blob: 6b804720646904f84cbce83462cb7919ebb54df9 [file] [log] [blame]
Yann Collet4ded9e52016-08-30 10:04:33 -07001/**
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
Yann Colletf3eca252015-10-22 15:31:46 +01009
Yann Colletf3eca252015-10-22 15:31:46 +010010
Yann Collet7d360282016-02-12 00:07:30 +010011/*-*************************************
Yann Colletae7aa062016-02-03 02:46:46 +010012* Dependencies
Yann Colletf3eca252015-10-22 15:31:46 +010013***************************************/
Yann Colletd3b7f8d2016-06-04 19:47:02 +020014#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010015#include "mem.h"
Yann Collet5a0c8e22016-08-12 01:20:36 +020016#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
Yann Colletd0e2cd12016-06-05 00:58:01 +020017#include "fse.h"
Yann Collet130fe112016-06-05 00:42:28 +020018#define HUF_STATIC_LINKING_ONLY
19#include "huf.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020020#include "zstd_internal.h" /* includes zstd.h */
Yann Colletf3eca252015-10-22 15:31:46 +010021
22
Yann Collet7d360282016-02-12 00:07:30 +010023/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010024* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010025***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010026static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Collet731ef162016-07-27 21:05:12 +020027#define HASH_READ_SIZE 8
28typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010029
Yann Colletf3eca252015-10-22 15:31:46 +010030
Yann Collet7d360282016-02-12 00:07:30 +010031/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010032* Helper functions
33***************************************/
Yann Colletc261f712016-12-12 00:25:07 +010034#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }
Yann Collet59d1f792016-01-23 19:28:41 +010035size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
36
37
Yann Collet7d360282016-02-12 00:07:30 +010038/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010039* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010040***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010041static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
42{
Yann Collet14983e72015-11-11 21:38:21 +010043 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020044 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020045 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010046}
47
48
Yann Collet7d360282016-02-12 00:07:30 +010049/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010050* Context memory management
51***************************************/
Yann Colletaca113f2016-12-23 22:25:03 +010052struct ZSTD_CCtx_s {
Yann Collet89db5e02015-11-13 11:27:46 +010053 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010054 const BYTE* base; /* All regular indexes relative to this position */
55 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010056 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010057 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010058 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010059 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +010060 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Colletbb002742017-01-25 16:25:38 -080061 U32 loadedDictEnd; /* index of end of dictionary */
62 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
Yann Collet14312d82017-02-23 23:42:12 -080063 U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */
Yann Collet731ef162016-07-27 21:05:12 +020064 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +020065 U32 rep[ZSTD_REP_NUM];
Yann Colletb459aad2017-01-19 17:33:37 -080066 U32 repToConfirm[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +020067 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +010068 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +010069 void* workSpace;
70 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +010071 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +020072 U64 frameContentSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +020073 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +020074 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +010075
Yann Collet712def92015-10-29 18:41:45 +010076 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +010077 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +010078 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +020079 U32* chainTable;
Yann Colletb923f652016-01-26 03:14:20 +010080 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +010081 U32 flagStaticTables;
Yann Collet731ef162016-07-27 21:05:12 +020082 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
83 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
84 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Collete928f7e2016-12-01 16:13:35 -080085 unsigned tmpCounters[1024];
Yann Colletf3eca252015-10-22 15:31:46 +010086};
87
Yann Collet5be2dd22015-11-11 13:43:58 +010088ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +010089{
inikep3763c772016-06-03 13:28:20 +020090 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +020091}
92
93ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
94{
Yann Collet69c2cdb2016-07-14 16:52:45 +020095 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +020096
Yann Collet23b6e052016-08-28 21:05:43 -070097 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
98 if (!customMem.customAlloc || !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +020099
Yann Collet23b6e052016-08-28 21:05:43 -0700100 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200101 if (!cctx) return NULL;
102 memset(cctx, 0, sizeof(ZSTD_CCtx));
Yann Colletbb002742017-01-25 16:25:38 -0800103 cctx->customMem = customMem;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200104 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100105}
106
Yann Collet5be2dd22015-11-11 13:43:58 +0100107size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100108{
inikep36403962016-06-03 16:36:50 +0200109 if (cctx==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -0700110 ZSTD_free(cctx->workSpace, cctx->customMem);
111 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100112 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100113}
114
Yann Collet70e3b312016-08-23 01:18:06 +0200115size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200116{
Yann Colletd7c65892016-09-15 02:50:27 +0200117 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet3ae543c2016-07-11 03:12:17 +0200118 return sizeof(*cctx) + cctx->workSpaceSize;
119}
120
Yann Colletbb002742017-01-25 16:25:38 -0800121size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
122{
123 switch(param)
124 {
Yann Collet06e76972017-01-25 16:39:03 -0800125 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet14312d82017-02-23 23:42:12 -0800126 case ZSTD_p_forceRawDict : cctx->forceRawDict = value>0; return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800127 default: return ERROR(parameter_unknown);
128 }
129}
130
Yann Colletb44be742016-03-26 20:52:14 +0100131const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100132{
Yann Colletb44be742016-03-26 20:52:14 +0100133 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100134}
135
Yann Collet95162342016-10-25 16:19:52 -0700136static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx)
137{
138 return cctx->params;
139}
140
Yann Collet59d70632015-11-04 12:05:27 +0100141
Yann Collet21588e32016-03-30 16:50:44 +0200142/** ZSTD_checkParams() :
143 ensure param values remain within authorized range.
144 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200145size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200146{
Yann Colletac8bace2016-09-07 14:54:23 +0200147# define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
Yann Collet15354142016-04-04 04:22:53 +0200148 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200149 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200150 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
151 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Colletedbcd9f2016-09-06 14:30:57 +0200152 { 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 +0200153 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
154 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
155 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200156 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200157 return 0;
158}
159
160
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100161/** ZSTD_cycleLog() :
162 * condition for correct operation : hashLog > 1 */
163static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
164{
165 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
166 return hashLog - btScale;
167}
168
Yann Collet70d13012016-06-01 18:45:34 +0200169/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200170 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200171 mostly downsizing to reduce memory consumption and initialization.
172 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
173 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200174 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200175ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100176{
Yann Collet70d13012016-06-01 18:45:34 +0200177 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100178
Yann Collet70e45772016-03-19 18:08:32 +0100179 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200180 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
181 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200182 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200183 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200184 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200185 } }
Yann Collet70d13012016-06-01 18:45:34 +0200186 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100187 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
188 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
189 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100190
Yann Collet70d13012016-06-01 18:45:34 +0200191 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200192
193 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100194}
195
196
Yann Collet88472382016-07-14 17:05:38 +0200197size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100198{
Yann Collet731ef162016-07-27 21:05:12 +0200199 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
200 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
201 size_t const maxNbSeq = blockSize / divider;
202 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200203
Yann Collet731ef162016-07-27 21:05:12 +0200204 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
205 size_t const hSize = ((size_t)1) << cParams.hashLog;
206 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
207 size_t const h3Size = ((size_t)1) << hashLog3;
208 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200209
210 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
211 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
212 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200213 + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Collet3ae543c2016-07-11 03:12:17 +0200214
215 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100216}
217
Yann Colleta7737f62016-09-06 09:44:59 +0200218
219static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
220{
221 return (param1.cParams.hashLog == param2.cParams.hashLog)
222 & (param1.cParams.chainLog == param2.cParams.chainLog)
Yann Colletedbcd9f2016-09-06 14:30:57 +0200223 & (param1.cParams.strategy == param2.cParams.strategy)
224 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3));
Yann Colleta7737f62016-09-06 09:44:59 +0200225}
226
227/*! ZSTD_continueCCtx() :
228 reuse CCtx without reset (note : requires no dictionary) */
229static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
230{
231 U32 const end = (U32)(cctx->nextSrc - cctx->base);
232 cctx->params = params;
233 cctx->frameContentSize = frameContentSize;
234 cctx->lowLimit = end;
235 cctx->dictLimit = end;
236 cctx->nextToUpdate = end+1;
237 cctx->stage = ZSTDcs_init;
238 cctx->dictID = 0;
239 cctx->loadedDictEnd = 0;
240 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200241 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
242 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200243 return 0;
244}
245
246typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
247
Yann Collet27caf2a2016-04-01 15:48:48 +0200248/*! ZSTD_resetCCtx_advanced() :
Yann Colletdccd6b62017-02-27 15:57:50 -0800249 note : @params must be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100250static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletea2ecdc2016-07-14 22:43:12 +0200251 ZSTD_parameters params, U64 frameContentSize,
Yann Collet4cb21292016-09-15 14:54:07 +0200252 ZSTD_compResetPolicy_e const crp)
Yann Colleta7737f62016-09-06 09:44:59 +0200253{
Yann Collet4cb21292016-09-15 14:54:07 +0200254 if (crp == ZSTDcrp_continue)
Yann Colleta7737f62016-09-06 09:44:59 +0200255 if (ZSTD_equivalentParams(params, zc->params))
256 return ZSTD_continueCCtx(zc, params, frameContentSize);
inikep87d4f3d2016-03-02 15:56:24 +0100257
Yann Colleta7737f62016-09-06 09:44:59 +0200258 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
259 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
260 size_t const maxNbSeq = blockSize / divider;
261 size_t const tokenSpace = blockSize + 11*maxNbSeq;
262 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
263 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
264 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
265 size_t const h3Size = ((size_t)1) << hashLog3;
266 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
267 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100268
Yann Colleta7737f62016-09-06 09:44:59 +0200269 /* Check if workSpace is large enough, alloc a new one if needed */
270 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
271 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
272 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200273 + (((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200274 if (zc->workSpaceSize < neededSpace) {
275 ZSTD_free(zc->workSpace, zc->customMem);
276 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
277 if (zc->workSpace == NULL) return ERROR(memory_allocation);
278 zc->workSpaceSize = neededSpace;
279 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100280
Yann Colleta7737f62016-09-06 09:44:59 +0200281 if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */
282 XXH64_reset(&zc->xxhState, 0);
283 zc->hashLog3 = hashLog3;
284 zc->hashTable = (U32*)(zc->workSpace);
285 zc->chainTable = zc->hashTable + hSize;
286 zc->hashTable3 = zc->chainTable + chainSize;
287 ptr = zc->hashTable3 + h3Size;
288 zc->hufTable = (HUF_CElt*)ptr;
289 zc->flagStaticTables = 0;
290 ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
Yann Collet70e8c382016-02-10 13:37:52 +0100291
Yann Colleta7737f62016-09-06 09:44:59 +0200292 zc->nextToUpdate = 1;
293 zc->nextSrc = NULL;
294 zc->base = NULL;
295 zc->dictBase = NULL;
296 zc->dictLimit = 0;
297 zc->lowLimit = 0;
298 zc->params = params;
299 zc->blockSize = blockSize;
300 zc->frameContentSize = frameContentSize;
301 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
302
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200303 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
Yann Colleta7737f62016-09-06 09:44:59 +0200304 zc->seqStore.litFreq = (U32*)ptr;
305 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
306 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
307 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
308 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
309 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
310 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
311 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
312 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
313 zc->seqStore.litLengthSum = 0;
314 }
315 zc->seqStore.sequencesStart = (seqDef*)ptr;
316 ptr = zc->seqStore.sequencesStart + maxNbSeq;
317 zc->seqStore.llCode = (BYTE*) ptr;
318 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
319 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
320 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
321
322 zc->stage = ZSTDcs_init;
323 zc->dictID = 0;
324 zc->loadedDictEnd = 0;
325
326 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100327 }
Yann Colletf3eca252015-10-22 15:31:46 +0100328}
329
Yann Collet32dfae62017-01-19 10:32:55 -0800330/* ZSTD_invalidateRepCodes() :
331 * ensures next compression will not use repcodes from previous block.
332 * Note : only works with regular variant;
333 * do not use with extDict variant ! */
334void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
335 int i;
336 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
337}
Yann Collet083fcc82015-10-25 14:06:35 +0100338
Yann Collet370b08e2016-03-08 00:03:59 +0100339/*! ZSTD_copyCCtx() :
340* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet731ef162016-07-27 21:05:12 +0200341* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100342* @return : 0, or an error code */
Yann Collet97b378a2016-09-21 17:20:19 +0200343size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100344{
Yann Collet731ef162016-07-27 21:05:12 +0200345 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100346
Sean Purcell2db72492017-02-09 10:50:43 -0800347
inikep28669512016-06-02 13:04:18 +0200348 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Sean Purcell2db72492017-02-09 10:50:43 -0800349 { ZSTD_parameters params = srcCCtx->params;
350 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
351 ZSTD_resetCCtx_advanced(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset);
352 }
Yann Collet7b51a292016-01-26 15:58:49 +0100353
354 /* copy tables */
Yann Collet731ef162016-07-27 21:05:12 +0200355 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
356 size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
357 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
358 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100359 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
360 }
Yann Collet7b51a292016-01-26 15:58:49 +0100361
Yann Colletc46fb922016-05-29 05:01:04 +0200362 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100363 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
364 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
365 dstCCtx->nextSrc = srcCCtx->nextSrc;
366 dstCCtx->base = srcCCtx->base;
367 dstCCtx->dictBase = srcCCtx->dictBase;
368 dstCCtx->dictLimit = srcCCtx->dictLimit;
369 dstCCtx->lowLimit = srcCCtx->lowLimit;
370 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200371 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100372
Yann Colletfb810d62016-01-28 00:18:06 +0100373 /* copy entropy tables */
374 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100375 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100376 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100377 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
378 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
379 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
380 }
Yann Collet7b51a292016-01-26 15:58:49 +0100381
382 return 0;
383}
384
385
Yann Colletecabfe32016-03-20 16:20:06 +0100386/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100387* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100388static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100389{
Yann Colletecabfe32016-03-20 16:20:06 +0100390 U32 u;
391 for (u=0 ; u < size ; u++) {
392 if (table[u] < reducerValue) table[u] = 0;
393 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100394 }
395}
396
Yann Colletecabfe32016-03-20 16:20:06 +0100397/*! ZSTD_reduceIndex() :
398* rescale all indexes to avoid future overflow (indexes are U32) */
399static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
400{
Yann Collet731ef162016-07-27 21:05:12 +0200401 { U32 const hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100402 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
403
Yann Collet731ef162016-07-27 21:05:12 +0200404 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200405 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100406
Yann Collet731ef162016-07-27 21:05:12 +0200407 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100408 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
409}
410
Yann Collet89db5e02015-11-13 11:27:46 +0100411
Yann Collet863ec402016-01-28 17:56:33 +0100412/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100413* Block entropic compression
414*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100415
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200416/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100417
Yann Colletd1b26842016-03-15 01:24:33 +0100418size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100419{
Yann Colletd1b26842016-03-15 01:24:33 +0100420 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200421 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
422 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100423 return ZSTD_blockHeaderSize+srcSize;
424}
425
426
Yann Colletd1b26842016-03-15 01:24:33 +0100427static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100428{
429 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200430 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100431
Yann Colletd1b26842016-03-15 01:24:33 +0100432 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100433
Yann Collet59d1f792016-01-23 19:28:41 +0100434 switch(flSize)
435 {
436 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200437 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100438 break;
439 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200440 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100441 break;
442 default: /*note : should not be necessary : flSize is within {1,2,3} */
443 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200444 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100445 break;
446 }
447
448 memcpy(ostart + flSize, src, srcSize);
449 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100450}
451
Yann Colletd1b26842016-03-15 01:24:33 +0100452static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100453{
454 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200455 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100456
Yann Collet198e6aa2016-07-20 20:12:24 +0200457 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100458
459 switch(flSize)
460 {
461 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200462 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100463 break;
464 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200465 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100466 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100467 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100468 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200469 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100470 break;
471 }
472
473 ostart[flSize] = *(const BYTE*)src;
474 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100475}
476
Yann Collet59d1f792016-01-23 19:28:41 +0100477
Yann Colleta5c2c082016-03-20 01:09:18 +0100478static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100479
Yann Colletb923f652016-01-26 03:14:20 +0100480static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100481 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100482 const void* src, size_t srcSize)
483{
Yann Colleta910dc82016-03-18 12:37:45 +0100484 size_t const minGain = ZSTD_minGain(srcSize);
485 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200486 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100487 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200488 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100489 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100490
Yann Collet14983e72015-11-11 21:38:21 +0100491
Yann Colleta5c2c082016-03-20 01:09:18 +0100492 /* small ? don't even attempt compression (speed opt) */
493# define LITERAL_NOENTROPY 63
494 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
495 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
496 }
497
498 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100499 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200500 hType = set_repeat;
Yann Colletb923f652016-01-26 03:14:20 +0100501 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100502 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100503 } else {
Yann Colleta0d742b2016-12-01 17:47:30 -0800504 cLitSize = singleStream ? HUF_compress1X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters))
505 : HUF_compress4X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters));
Yann Colletb923f652016-01-26 03:14:20 +0100506 }
Yann Collet14983e72015-11-11 21:38:21 +0100507
Yann Collet98c88842016-07-15 16:12:38 +0200508 if ((cLitSize==0) | (cLitSize >= srcSize - minGain))
Yann Colleta910dc82016-03-18 12:37:45 +0100509 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
510 if (cLitSize==1)
511 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100512
513 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100514 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100515 {
Yann Collet59d1f792016-01-23 19:28:41 +0100516 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200517 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200518 MEM_writeLE24(ostart, lhc);
519 break;
520 }
Yann Collet59d1f792016-01-23 19:28:41 +0100521 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200522 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200523 MEM_writeLE32(ostart, lhc);
524 break;
525 }
Yann Colleta910dc82016-03-18 12:37:45 +0100526 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100527 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200528 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200529 MEM_writeLE32(ostart, lhc);
530 ostart[4] = (BYTE)(cLitSize >> 10);
531 break;
532 }
Yann Collet14983e72015-11-11 21:38:21 +0100533 }
Yann Colleta910dc82016-03-18 12:37:45 +0100534 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100535}
536
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200537static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
538 8, 9, 10, 11, 12, 13, 14, 15,
539 16, 16, 17, 17, 18, 18, 19, 19,
540 20, 20, 20, 20, 21, 21, 21, 21,
541 22, 22, 22, 22, 22, 22, 22, 22,
542 23, 23, 23, 23, 23, 23, 23, 23,
543 24, 24, 24, 24, 24, 24, 24, 24,
544 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100545
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200546static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
547 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
548 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
549 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
550 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
551 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
552 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
553 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200554
555
556void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100557{
Yann Colleted57d852016-07-29 21:22:17 +0200558 BYTE const LL_deltaCode = 19;
559 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200560 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200561 BYTE* const llCodeTable = seqStorePtr->llCode;
562 BYTE* const ofCodeTable = seqStorePtr->ofCode;
563 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200564 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200565 U32 u;
566 for (u=0; u<nbSeq; u++) {
567 U32 const llv = sequences[u].litLength;
568 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200569 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200570 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200571 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200572 }
Yann Colleted57d852016-07-29 21:22:17 +0200573 if (seqStorePtr->longLengthID==1)
574 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
575 if (seqStorePtr->longLengthID==2)
576 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100577}
578
Sean Purcell553f67e2017-03-02 15:15:31 -0800579MEM_STATIC size_t ZSTD_compressSequences (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100580 void* dst, size_t dstCapacity,
Sean Purcell553f67e2017-03-02 15:15:31 -0800581 size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100582{
Sean Purcell553f67e2017-03-02 15:15:31 -0800583 const int longOffsets = zc->params.cParams.windowLog > STREAM_ACCUMULATOR_MIN;
Yann Colletb923f652016-01-26 03:14:20 +0100584 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100585 U32 count[MaxSeq+1];
586 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100587 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
588 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
589 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100590 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200591 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200592 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
593 const BYTE* const llCodeTable = seqStorePtr->llCode;
594 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100595 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100596 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100597 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200598 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100599 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -0800600 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +0100601
Yann Collet14983e72015-11-11 21:38:21 +0100602 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100603 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100604 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100605 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100606 if (ZSTD_isError(cSize)) return cSize;
607 op += cSize;
608 }
609
610 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100611 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100612 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
613 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
614 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100615 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100616
Yann Colletbe391432016-03-22 23:19:28 +0100617 /* seqHead : flags for FSE encoding type */
618 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100619
Yann Colletfb810d62016-01-28 00:18:06 +0100620#define MIN_SEQ_FOR_DYNAMIC_FSE 64
621#define MAX_SEQ_FOR_STATIC_FSE 1000
622
Yann Colletb44be742016-03-26 20:52:14 +0100623 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +0200624 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +0100625
Yann Collet14983e72015-11-11 21:38:21 +0100626 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100627 { U32 max = MaxLL;
Yann Collete928f7e2016-12-01 16:13:35 -0800628 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100629 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
630 *op++ = llCodeTable[0];
631 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200632 LLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100633 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200634 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100635 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800636 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200637 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100638 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100639 size_t nbSeq_1 = nbSeq;
640 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
641 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
642 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100643 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
644 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
645 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800646 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200647 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100648 } }
Yann Collet14983e72015-11-11 21:38:21 +0100649
Yann Colletb44be742016-03-26 20:52:14 +0100650 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100651 { U32 max = MaxOff;
Yann Collete928f7e2016-12-01 16:13:35 -0800652 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100653 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100654 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100655 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200656 Offtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100657 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200658 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +0200659 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800660 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200661 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100662 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100663 size_t nbSeq_1 = nbSeq;
664 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100665 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100666 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100667 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
668 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
669 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800670 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200671 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100672 } }
673
Yann Collet14983e72015-11-11 21:38:21 +0100674 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100675 { U32 max = MaxML;
Yann Collete928f7e2016-12-01 16:13:35 -0800676 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100677 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100678 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100679 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200680 MLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100681 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200682 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100683 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800684 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200685 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100686 } else {
687 size_t nbSeq_1 = nbSeq;
688 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
689 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
690 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
691 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
692 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
693 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800694 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200695 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100696 } }
Yann Collet14983e72015-11-11 21:38:21 +0100697
Yann Colletbe391432016-03-22 23:19:28 +0100698 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100699 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100700
701 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100702 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100703 FSE_CState_t stateMatchLength;
704 FSE_CState_t stateOffsetBits;
705 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100706
Yann Collet95d07d72016-09-06 16:38:51 +0200707 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100708
Yann Collet597847a2016-03-20 19:14:22 +0100709 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100710 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100711 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100712 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +0200713 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100714 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200715 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100716 if (MEM_32bits()) BIT_flushBits(&blockStream);
Sean Purcelld44703d2017-03-01 14:36:25 -0800717 if (longOffsets) {
718 U32 const ofBits = ofCodeTable[nbSeq-1];
719 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
720 if (extraBits) {
721 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
722 BIT_flushBits(&blockStream);
723 }
724 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
725 ofBits - extraBits);
726 } else {
727 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
728 }
Yann Collet597847a2016-03-20 19:14:22 +0100729 BIT_flushBits(&blockStream);
730
Yann Colletfadda6c2016-03-22 12:14:26 +0100731 { size_t n;
732 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +0200733 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200734 BYTE const ofCode = ofCodeTable[n];
735 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200736 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +0200737 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200738 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +0100739 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100740 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
741 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
742 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
743 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200744 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100745 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +0200746 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100747 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200748 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100749 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Sean Purcelld44703d2017-03-01 14:36:25 -0800750 if (longOffsets) {
751 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
752 if (extraBits) {
753 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
754 BIT_flushBits(&blockStream); /* (7)*/
755 }
756 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
757 ofBits - extraBits); /* 31 */
758 } else {
759 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
760 }
Yann Colletb9151402016-03-26 17:18:11 +0100761 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100762 } }
Yann Collet14983e72015-11-11 21:38:21 +0100763
764 FSE_flushCState(&blockStream, &stateMatchLength);
765 FSE_flushCState(&blockStream, &stateOffsetBits);
766 FSE_flushCState(&blockStream, &stateLitLength);
767
Yann Colletb9151402016-03-26 17:18:11 +0100768 { size_t const streamSize = BIT_closeCStream(&blockStream);
769 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
770 op += streamSize;
771 } }
Yann Collet14983e72015-11-11 21:38:21 +0100772
773 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100774_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100775 { size_t const minGain = ZSTD_minGain(srcSize);
776 size_t const maxCSize = srcSize - minGain;
777 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100778
Yann Collet4266c0a2016-06-14 01:49:25 +0200779 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -0800780 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +0200781
Yann Collet5054ee02015-11-23 13:34:21 +0100782 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100783}
784
Yann Colletbb002742017-01-25 16:25:38 -0800785#if 0 /* for debug */
786# define STORESEQ_DEBUG
787#include <stdio.h> /* fprintf */
788U32 g_startDebug = 0;
789const BYTE* g_start = NULL;
790#endif
791
Yann Collet95cd0c22016-03-08 18:24:21 +0100792/*! ZSTD_storeSeq() :
793 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
794 `offsetCode` : distance to match, or 0 == repCode.
795 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100796*/
Yann Colletd57dffb2016-07-03 01:48:26 +0200797MEM_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 +0100798{
Yann Colletbb002742017-01-25 16:25:38 -0800799#ifdef STORESEQ_DEBUG
800 if (g_startDebug) {
801 const U32 pos = (U32)((const BYTE*)literals - g_start);
802 if (g_start==NULL) g_start = (const BYTE*)literals;
803 if ((pos > 1895000) && (pos < 1895300))
804 fprintf(stderr, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
805 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
806 }
Yann Collet14983e72015-11-11 21:38:21 +0100807#endif
Yann Collet14983e72015-11-11 21:38:21 +0100808 /* copy Literals */
809 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
810 seqStorePtr->lit += litLength;
811
812 /* literal Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200813 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
814 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100815
816 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200817 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100818
819 /* match Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200820 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
821 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +0200822
Yann Colletc0ce4f12016-07-30 00:55:13 +0200823 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +0100824}
825
826
Yann Collet7d360282016-02-12 00:07:30 +0100827/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100828* Match length counter
829***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100830static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100831{
Yann Collet863ec402016-01-28 17:56:33 +0100832 if (MEM_isLittleEndian()) {
833 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100834# if defined(_MSC_VER) && defined(_WIN64)
835 unsigned long r = 0;
836 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100837 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100838# elif defined(__GNUC__) && (__GNUC__ >= 3)
839 return (__builtin_ctzll((U64)val) >> 3);
840# else
841 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 };
842 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
843# endif
Yann Collet863ec402016-01-28 17:56:33 +0100844 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100845# if defined(_MSC_VER)
846 unsigned long r=0;
847 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100848 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100849# elif defined(__GNUC__) && (__GNUC__ >= 3)
850 return (__builtin_ctz((U32)val) >> 3);
851# else
852 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 };
853 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
854# endif
855 }
Yann Collet863ec402016-01-28 17:56:33 +0100856 } else { /* Big Endian CPU */
857 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100858# if defined(_MSC_VER) && defined(_WIN64)
859 unsigned long r = 0;
860 _BitScanReverse64( &r, val );
861 return (unsigned)(r>>3);
862# elif defined(__GNUC__) && (__GNUC__ >= 3)
863 return (__builtin_clzll(val) >> 3);
864# else
865 unsigned r;
866 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
867 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
868 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
869 r += (!val);
870 return r;
871# endif
Yann Collet863ec402016-01-28 17:56:33 +0100872 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100873# if defined(_MSC_VER)
874 unsigned long r = 0;
875 _BitScanReverse( &r, (unsigned long)val );
876 return (unsigned)(r>>3);
877# elif defined(__GNUC__) && (__GNUC__ >= 3)
878 return (__builtin_clz((U32)val) >> 3);
879# else
880 unsigned r;
881 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
882 r += (!val);
883 return r;
884# endif
Yann Collet863ec402016-01-28 17:56:33 +0100885 } }
Yann Collet14983e72015-11-11 21:38:21 +0100886}
887
888
Yann Colleta436a522016-06-20 23:34:04 +0200889static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100890{
891 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +0200892 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +0100893
Yann Colleta436a522016-06-20 23:34:04 +0200894 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +0200895 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100896 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
897 pIn += ZSTD_NbCommonBytes(diff);
898 return (size_t)(pIn - pStart);
899 }
Yann Collet14983e72015-11-11 21:38:21 +0100900 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
901 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
902 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
903 return (size_t)(pIn - pStart);
904}
905
Yann Collet04b12d82016-02-11 06:23:24 +0100906/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100907* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100908* convention : on reaching mEnd, match count continue starting from iStart
909*/
910static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
911{
Yann Collet7591a7f2016-05-20 11:44:43 +0200912 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +0200913 size_t const matchLength = ZSTD_count(ip, match, vEnd);
914 if (match + matchLength != mEnd) return matchLength;
915 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +0100916}
917
Yann Collet14983e72015-11-11 21:38:21 +0100918
Yann Collet863ec402016-01-28 17:56:33 +0100919/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100920* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100921***************************************/
inikepcc52a972016-02-19 10:09:35 +0100922static const U32 prime3bytes = 506832829U;
923static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Colletd4f4e582016-06-27 01:31:35 +0200924MEM_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 +0100925
Yann Collet4b100f42015-10-30 15:49:48 +0100926static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100927static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100928static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100929
Yann Collet4b100f42015-10-30 15:49:48 +0100930static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100931static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100932static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100933
934static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100935static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100936static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100937
Yann Collet14983e72015-11-11 21:38:21 +0100938static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100939static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100940static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100941
Yann Collet45dc3562016-07-12 09:47:31 +0200942static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
943static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
944static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
945
Yann Collet5be2dd22015-11-11 13:43:58 +0100946static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100947{
948 switch(mls)
949 {
950 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100951 case 4: return ZSTD_hash4Ptr(p, hBits);
952 case 5: return ZSTD_hash5Ptr(p, hBits);
953 case 6: return ZSTD_hash6Ptr(p, hBits);
954 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +0200955 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100956 }
957}
Yann Collet2acb5d32015-10-29 16:49:43 +0100958
Yann Collet863ec402016-01-28 17:56:33 +0100959
Yann Collet2ce49232016-02-02 14:36:49 +0100960/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100961* Fast Scan
962***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100963static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
964{
965 U32* const hashTable = zc->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200966 U32 const hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +0100967 const BYTE* const base = zc->base;
968 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +0200969 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +0100970 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +0100971
Yann Colletfb810d62016-01-28 00:18:06 +0100972 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100973 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +0100974 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +0100975 }
976}
977
978
Yann Collet1f44b3f2015-11-05 17:32:18 +0100979FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +0200980void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +0200981 const void* src, size_t srcSize,
982 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100983{
Yann Collet4266c0a2016-06-14 01:49:25 +0200984 U32* const hashTable = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200985 U32 const hBits = cctx->params.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +0200986 seqStore_t* seqStorePtr = &(cctx->seqStore);
987 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100988 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100989 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100990 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +0200991 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +0200992 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100993 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +0200994 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +0200995 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
996 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100997
Yann Collet1f44b3f2015-11-05 17:32:18 +0100998 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +0200999 ip += (ip==lowest);
1000 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +02001001 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1002 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +02001003 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001004
1005 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001006 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001007 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001008 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1009 U32 const current = (U32)(ip-base);
1010 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001011 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001012 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001013
Yann Collet280f9a82016-08-08 00:44:00 +02001014 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +02001015 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +01001016 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001017 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1018 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001019 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001020 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001021 ip += ((ip-anchor) >> g_searchStrength) + 1;
1022 continue;
1023 }
Yann Collet45dc3562016-07-12 09:47:31 +02001024 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001025 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001026 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001027 offset_2 = offset_1;
1028 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001029
Yann Colleta436a522016-06-20 23:34:04 +02001030 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001031 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001032
Yann Collet402fdcf2015-11-20 12:46:08 +01001033 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001034 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001035 anchor = ip;
1036
Yann Colletfb810d62016-01-28 00:18:06 +01001037 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001038 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001039 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 +01001040 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1041 /* check immediate repcode */
1042 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001043 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001044 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001045 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001046 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001047 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001048 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001049 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1050 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001051 anchor = ip;
1052 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001053 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001054
Yann Collet4266c0a2016-06-14 01:49:25 +02001055 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001056 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1057 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001058
Yann Collet70e45772016-03-19 18:08:32 +01001059 /* Last Literals */
1060 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001061 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1062 seqStorePtr->lit += lastLLSize;
1063 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001064}
1065
1066
Yann Collet82260dd2016-02-11 07:14:25 +01001067static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001068 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001069{
Yann Collet3b719252016-03-30 19:48:05 +02001070 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001071 switch(mls)
1072 {
1073 default:
1074 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001075 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001076 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001077 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001078 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001079 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001080 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001081 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001082 }
1083}
Yann Colletf3eca252015-10-22 15:31:46 +01001084
Yann Colletf3eca252015-10-22 15:31:46 +01001085
Yann Collet82260dd2016-02-11 07:14:25 +01001086static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001087 const void* src, size_t srcSize,
1088 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001089{
1090 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001091 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001092 seqStore_t* seqStorePtr = &(ctx->seqStore);
1093 const BYTE* const base = ctx->base;
1094 const BYTE* const dictBase = ctx->dictBase;
1095 const BYTE* const istart = (const BYTE*)src;
1096 const BYTE* ip = istart;
1097 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001098 const U32 lowestIndex = ctx->lowLimit;
1099 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001100 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001101 const BYTE* const lowPrefixPtr = base + dictLimit;
1102 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001103 const BYTE* const iend = istart + srcSize;
1104 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001105 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001106
Yann Colleta436a522016-06-20 23:34:04 +02001107 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001108 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001109 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001110 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001111 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001112 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001113 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001114 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001115 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001116 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001117 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001118 hashTable[h] = current; /* update hash table */
1119
Yann Colleta436a522016-06-20 23:34:04 +02001120 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001121 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001122 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Colleta436a522016-06-20 23:34:04 +02001123 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001124 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001125 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001126 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001127 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001128 (MEM_read32(match) != MEM_read32(ip)) ) {
1129 ip += ((ip-anchor) >> g_searchStrength) + 1;
1130 continue;
1131 }
1132 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001133 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001134 U32 offset;
1135 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1136 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001137 offset = current - matchIndex;
1138 offset_2 = offset_1;
1139 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001140 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001141 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001142
Yann Collet5054ee02015-11-23 13:34:21 +01001143 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001144 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001145 anchor = ip;
1146
Yann Colletfb810d62016-01-28 00:18:06 +01001147 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001148 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001149 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001150 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1151 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001152 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001153 U32 const current2 = (U32)(ip-base);
1154 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001155 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001156 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1157 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001158 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001159 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001160 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001161 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001162 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001163 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001164 anchor = ip;
1165 continue;
1166 }
Yann Collet743402c2015-11-20 12:03:53 +01001167 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001168 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001169
Yann Collet4266c0a2016-06-14 01:49:25 +02001170 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001171 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001172
Yann Collet89db5e02015-11-13 11:27:46 +01001173 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001174 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001175 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1176 seqStorePtr->lit += lastLLSize;
1177 }
Yann Collet89db5e02015-11-13 11:27:46 +01001178}
1179
1180
Yann Collet82260dd2016-02-11 07:14:25 +01001181static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001182 const void* src, size_t srcSize)
1183{
Yann Collet731ef162016-07-27 21:05:12 +02001184 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001185 switch(mls)
1186 {
1187 default:
1188 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001189 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001190 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001191 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001192 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001193 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001194 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001195 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001196 }
1197}
1198
1199
Yann Collet04b12d82016-02-11 06:23:24 +01001200/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001201* Double Fast
1202***************************************/
1203static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1204{
1205 U32* const hashLarge = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001206 U32 const hBitsL = cctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001207 U32* const hashSmall = cctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001208 U32 const hBitsS = cctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001209 const BYTE* const base = cctx->base;
1210 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001211 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001212 const size_t fastHashFillStep = 3;
1213
1214 while(ip <= iend) {
1215 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1216 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1217 ip += fastHashFillStep;
1218 }
1219}
1220
1221
1222FORCE_INLINE
1223void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1224 const void* src, size_t srcSize,
1225 const U32 mls)
1226{
1227 U32* const hashLong = cctx->hashTable;
1228 const U32 hBitsL = cctx->params.cParams.hashLog;
1229 U32* const hashSmall = cctx->chainTable;
1230 const U32 hBitsS = cctx->params.cParams.chainLog;
1231 seqStore_t* seqStorePtr = &(cctx->seqStore);
1232 const BYTE* const base = cctx->base;
1233 const BYTE* const istart = (const BYTE*)src;
1234 const BYTE* ip = istart;
1235 const BYTE* anchor = istart;
1236 const U32 lowestIndex = cctx->dictLimit;
1237 const BYTE* const lowest = base + lowestIndex;
1238 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001239 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001240 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1241 U32 offsetSaved = 0;
1242
1243 /* init */
1244 ip += (ip==lowest);
1245 { U32 const maxRep = (U32)(ip-lowest);
1246 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1247 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1248 }
1249
1250 /* Main Search Loop */
1251 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1252 size_t mLength;
1253 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1254 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1255 U32 const current = (U32)(ip-base);
1256 U32 const matchIndexL = hashLong[h2];
1257 U32 const matchIndexS = hashSmall[h];
1258 const BYTE* matchLong = base + matchIndexL;
1259 const BYTE* match = base + matchIndexS;
1260 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1261
1262 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1263 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1264 ip++;
1265 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1266 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001267 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001268 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1269 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001270 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001271 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1272 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Colletc54692f2016-08-24 01:10:42 +02001273 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1274 U32 const matchIndex3 = hashLong[h3];
1275 const BYTE* match3 = base + matchIndex3;
1276 hashLong[h3] = current + 1;
1277 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1278 mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
1279 ip++;
1280 offset = (U32)(ip-match3);
1281 while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1282 } else {
1283 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1284 offset = (U32)(ip-match);
1285 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1286 }
Yann Collet45dc3562016-07-12 09:47:31 +02001287 } else {
1288 ip += ((ip-anchor) >> g_searchStrength) + 1;
1289 continue;
1290 }
1291
1292 offset_2 = offset_1;
1293 offset_1 = offset;
1294
1295 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1296 }
1297
1298 /* match found */
1299 ip += mLength;
1300 anchor = ip;
1301
1302 if (ip <= ilimit) {
1303 /* Fill Table */
1304 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1305 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1306 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1307 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1308
1309 /* check immediate repcode */
1310 while ( (ip <= ilimit)
1311 && ( (offset_2>0)
1312 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1313 /* store sequence */
1314 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001315 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001316 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1317 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1318 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1319 ip += rLength;
1320 anchor = ip;
1321 continue; /* faster when present ... (?) */
1322 } } }
1323
1324 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001325 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1326 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001327
1328 /* Last Literals */
1329 { size_t const lastLLSize = iend - anchor;
1330 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1331 seqStorePtr->lit += lastLLSize;
1332 }
1333}
1334
1335
1336static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1337{
1338 const U32 mls = ctx->params.cParams.searchLength;
1339 switch(mls)
1340 {
1341 default:
1342 case 4 :
1343 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1344 case 5 :
1345 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1346 case 6 :
1347 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1348 case 7 :
1349 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1350 }
1351}
1352
1353
1354static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1355 const void* src, size_t srcSize,
1356 const U32 mls)
1357{
1358 U32* const hashLong = ctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001359 U32 const hBitsL = ctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001360 U32* const hashSmall = ctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001361 U32 const hBitsS = ctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001362 seqStore_t* seqStorePtr = &(ctx->seqStore);
1363 const BYTE* const base = ctx->base;
1364 const BYTE* const dictBase = ctx->dictBase;
1365 const BYTE* const istart = (const BYTE*)src;
1366 const BYTE* ip = istart;
1367 const BYTE* anchor = istart;
1368 const U32 lowestIndex = ctx->lowLimit;
1369 const BYTE* const dictStart = dictBase + lowestIndex;
1370 const U32 dictLimit = ctx->dictLimit;
1371 const BYTE* const lowPrefixPtr = base + dictLimit;
1372 const BYTE* const dictEnd = dictBase + dictLimit;
1373 const BYTE* const iend = istart + srcSize;
1374 const BYTE* const ilimit = iend - 8;
1375 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1376
1377 /* Search Loop */
1378 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1379 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1380 const U32 matchIndex = hashSmall[hSmall];
1381 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1382 const BYTE* match = matchBase + matchIndex;
1383
1384 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1385 const U32 matchLongIndex = hashLong[hLong];
1386 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1387 const BYTE* matchLong = matchLongBase + matchLongIndex;
1388
1389 const U32 current = (U32)(ip-base);
1390 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1391 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1392 const BYTE* repMatch = repBase + repIndex;
1393 size_t mLength;
1394 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1395
1396 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1397 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1398 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1399 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1400 ip++;
1401 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1402 } else {
1403 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1404 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1405 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1406 U32 offset;
1407 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1408 offset = current - matchLongIndex;
1409 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1410 offset_2 = offset_1;
1411 offset_1 = offset;
1412 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001413
Yann Collet73d74a02016-07-12 13:03:48 +02001414 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001415 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1416 U32 const matchIndex3 = hashLong[h3];
1417 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1418 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001419 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001420 hashLong[h3] = current + 1;
1421 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1422 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1423 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1424 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1425 ip++;
1426 offset = current+1 - matchIndex3;
1427 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1428 } else {
1429 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1430 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1431 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1432 offset = current - matchIndex;
1433 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1434 }
Yann Collet45dc3562016-07-12 09:47:31 +02001435 offset_2 = offset_1;
1436 offset_1 = offset;
1437 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001438
Yann Collet45dc3562016-07-12 09:47:31 +02001439 } else {
1440 ip += ((ip-anchor) >> g_searchStrength) + 1;
1441 continue;
1442 } }
1443
1444 /* found a match : store it */
1445 ip += mLength;
1446 anchor = ip;
1447
1448 if (ip <= ilimit) {
1449 /* Fill Table */
1450 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1451 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1452 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1453 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1454 /* check immediate repcode */
1455 while (ip <= ilimit) {
1456 U32 const current2 = (U32)(ip-base);
1457 U32 const repIndex2 = current2 - offset_2;
1458 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1459 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1460 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1461 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1462 size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1463 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1464 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1465 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1466 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1467 ip += repLength2;
1468 anchor = ip;
1469 continue;
1470 }
1471 break;
1472 } } }
1473
1474 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001475 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001476
1477 /* Last Literals */
1478 { size_t const lastLLSize = iend - anchor;
1479 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1480 seqStorePtr->lit += lastLLSize;
1481 }
1482}
1483
1484
1485static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1486 const void* src, size_t srcSize)
1487{
Yann Collet731ef162016-07-27 21:05:12 +02001488 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001489 switch(mls)
1490 {
1491 default:
1492 case 4 :
1493 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1494 case 5 :
1495 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1496 case 6 :
1497 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1498 case 7 :
1499 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1500 }
1501}
1502
1503
1504/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001505* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001506***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001507/** ZSTD_insertBt1() : add one or multiple positions to tree.
1508* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001509* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001510static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1511 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001512{
Yann Collet731ef162016-07-27 21:05:12 +02001513 U32* const hashTable = zc->hashTable;
1514 U32 const hashLog = zc->params.cParams.hashLog;
1515 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1516 U32* const bt = zc->chainTable;
1517 U32 const btLog = zc->params.cParams.chainLog - 1;
1518 U32 const btMask = (1 << btLog) - 1;
1519 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001520 size_t commonLengthSmaller=0, commonLengthLarger=0;
1521 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001522 const BYTE* const dictBase = zc->dictBase;
1523 const U32 dictLimit = zc->dictLimit;
1524 const BYTE* const dictEnd = dictBase + dictLimit;
1525 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001526 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001527 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001528 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001529 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001530 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001531 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001532 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001533 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001534 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001535#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001536 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1537 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1538 predictedSmall += (predictedSmall>0);
1539 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001540#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001541
Yann Collet6c3e2e72015-12-11 10:44:07 +01001542 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001543
Yann Colletfb810d62016-01-28 00:18:06 +01001544 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001545 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001546 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001547
Yann Colletc0932082016-06-30 14:07:30 +02001548#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001549 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001550 if (matchIndex == predictedSmall) {
1551 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001552 *smallerPtr = matchIndex;
1553 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1554 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1555 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001556 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001557 continue;
1558 }
Yann Colletfb810d62016-01-28 00:18:06 +01001559 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001560 *largerPtr = matchIndex;
1561 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1562 largerPtr = nextPtr;
1563 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001564 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001565 continue;
1566 }
Yann Collet04b12d82016-02-11 06:23:24 +01001567#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001568 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001569 match = base + matchIndex;
1570 if (match[matchLength] == ip[matchLength])
1571 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001572 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001573 match = dictBase + matchIndex;
1574 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1575 if (matchIndex+matchLength >= dictLimit)
1576 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1577 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001578
Yann Colletb8a6f682016-02-15 17:06:29 +01001579 if (matchLength > bestLength) {
1580 bestLength = matchLength;
1581 if (matchLength > matchEndIdx - matchIndex)
1582 matchEndIdx = matchIndex + (U32)matchLength;
1583 }
Yann Colletee3f4512015-12-29 22:26:09 +01001584
Yann Collet59d70632015-11-04 12:05:27 +01001585 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001586 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001587
Yann Colletfb810d62016-01-28 00:18:06 +01001588 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001589 /* match is smaller than current */
1590 *smallerPtr = matchIndex; /* update smaller idx */
1591 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001592 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001593 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001594 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001595 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001596 /* match is larger than current */
1597 *largerPtr = matchIndex;
1598 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001599 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001600 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001601 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001602 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001603
Yann Collet59d70632015-11-04 12:05:27 +01001604 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001605 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001606 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1607 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001608}
1609
1610
Yann Collet82260dd2016-02-11 07:14:25 +01001611static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001612 ZSTD_CCtx* zc,
1613 const BYTE* const ip, const BYTE* const iend,
1614 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001615 U32 nbCompares, const U32 mls,
1616 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001617{
Yann Collet731ef162016-07-27 21:05:12 +02001618 U32* const hashTable = zc->hashTable;
1619 U32 const hashLog = zc->params.cParams.hashLog;
1620 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1621 U32* const bt = zc->chainTable;
1622 U32 const btLog = zc->params.cParams.chainLog - 1;
1623 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001624 U32 matchIndex = hashTable[h];
1625 size_t commonLengthSmaller=0, commonLengthLarger=0;
1626 const BYTE* const base = zc->base;
1627 const BYTE* const dictBase = zc->dictBase;
1628 const U32 dictLimit = zc->dictLimit;
1629 const BYTE* const dictEnd = dictBase + dictLimit;
1630 const BYTE* const prefixStart = base + dictLimit;
1631 const U32 current = (U32)(ip-base);
1632 const U32 btLow = btMask >= current ? 0 : current - btMask;
1633 const U32 windowLow = zc->lowLimit;
1634 U32* smallerPtr = bt + 2*(current&btMask);
1635 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001636 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001637 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001638 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001639
Yann Collet6c3e2e72015-12-11 10:44:07 +01001640 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001641
Yann Colletfb810d62016-01-28 00:18:06 +01001642 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001643 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01001644 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1645 const BYTE* match;
1646
Yann Colletfb810d62016-01-28 00:18:06 +01001647 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001648 match = base + matchIndex;
1649 if (match[matchLength] == ip[matchLength])
1650 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001651 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001652 match = dictBase + matchIndex;
1653 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001654 if (matchIndex+matchLength >= dictLimit)
1655 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001656 }
1657
Yann Colletfb810d62016-01-28 00:18:06 +01001658 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001659 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001660 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001661 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001662 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001663 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1664 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1665 }
1666
Yann Colletfb810d62016-01-28 00:18:06 +01001667 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001668 /* match is smaller than current */
1669 *smallerPtr = matchIndex; /* update smaller idx */
1670 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1671 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1672 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1673 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001674 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001675 /* match is larger than current */
1676 *largerPtr = matchIndex;
1677 commonLengthLarger = matchLength;
1678 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1679 largerPtr = nextPtr;
1680 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001681 } }
Yann Collet03526e12015-11-23 15:29:15 +01001682
1683 *smallerPtr = *largerPtr = 0;
1684
Yann Collet72e84cf2015-12-31 19:08:44 +01001685 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001686 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001687}
1688
Yann Collet2cc12cb2016-01-01 07:47:58 +01001689
Yann Colletb8a6f682016-02-15 17:06:29 +01001690static 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 +01001691{
1692 const BYTE* const base = zc->base;
1693 const U32 target = (U32)(ip - base);
1694 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001695
1696 while(idx < target)
1697 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001698}
1699
Yann Collet52447382016-03-20 16:00:00 +01001700/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001701static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001702 ZSTD_CCtx* zc,
1703 const BYTE* const ip, const BYTE* const iLimit,
1704 size_t* offsetPtr,
1705 const U32 maxNbAttempts, const U32 mls)
1706{
1707 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001708 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001709 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1710}
1711
1712
Yann Collet768c6bc2016-02-10 14:01:49 +01001713static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001714 ZSTD_CCtx* zc, /* Index table will be updated */
1715 const BYTE* ip, const BYTE* const iLimit,
1716 size_t* offsetPtr,
1717 const U32 maxNbAttempts, const U32 matchLengthSearch)
1718{
1719 switch(matchLengthSearch)
1720 {
1721 default :
1722 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1723 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1724 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1725 }
1726}
1727
1728
Yann Colletb8a6f682016-02-15 17:06:29 +01001729static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1730{
1731 const BYTE* const base = zc->base;
1732 const U32 target = (U32)(ip - base);
1733 U32 idx = zc->nextToUpdate;
1734
1735 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1736}
1737
inikep64d7bcb2016-04-07 19:14:09 +02001738
Yann Collet03526e12015-11-23 15:29:15 +01001739/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001740static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001741 ZSTD_CCtx* zc,
1742 const BYTE* const ip, const BYTE* const iLimit,
1743 size_t* offsetPtr,
1744 const U32 maxNbAttempts, const U32 mls)
1745{
Yann Colletee3f4512015-12-29 22:26:09 +01001746 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001747 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001748 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001749}
1750
1751
Yann Collet82260dd2016-02-11 07:14:25 +01001752static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001753 ZSTD_CCtx* zc, /* Index table will be updated */
1754 const BYTE* ip, const BYTE* const iLimit,
1755 size_t* offsetPtr,
1756 const U32 maxNbAttempts, const U32 matchLengthSearch)
1757{
1758 switch(matchLengthSearch)
1759 {
1760 default :
1761 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1762 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1763 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1764 }
1765}
1766
1767
Yann Collet5106a762015-11-05 15:00:24 +01001768
Yann Collet731ef162016-07-27 21:05:12 +02001769/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02001770* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02001771***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02001772#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1773
1774/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08001775 Assumption : always within prefix (i.e. not within extDict) */
inikep64d7bcb2016-04-07 19:14:09 +02001776FORCE_INLINE
1777U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1778{
1779 U32* const hashTable = zc->hashTable;
1780 const U32 hashLog = zc->params.cParams.hashLog;
1781 U32* const chainTable = zc->chainTable;
1782 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1783 const BYTE* const base = zc->base;
1784 const U32 target = (U32)(ip - base);
1785 U32 idx = zc->nextToUpdate;
1786
Yann Collet22d76322016-06-21 08:01:51 +02001787 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001788 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1789 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1790 hashTable[h] = idx;
1791 idx++;
1792 }
1793
1794 zc->nextToUpdate = target;
1795 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1796}
1797
1798
1799
1800FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1801size_t ZSTD_HcFindBestMatch_generic (
1802 ZSTD_CCtx* zc, /* Index table will be updated */
1803 const BYTE* const ip, const BYTE* const iLimit,
1804 size_t* offsetPtr,
1805 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1806{
1807 U32* const chainTable = zc->chainTable;
1808 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1809 const U32 chainMask = chainSize-1;
1810 const BYTE* const base = zc->base;
1811 const BYTE* const dictBase = zc->dictBase;
1812 const U32 dictLimit = zc->dictLimit;
1813 const BYTE* const prefixStart = base + dictLimit;
1814 const BYTE* const dictEnd = dictBase + dictLimit;
1815 const U32 lowLimit = zc->lowLimit;
1816 const U32 current = (U32)(ip-base);
1817 const U32 minChain = current > chainSize ? current - chainSize : 0;
1818 int nbAttempts=maxNbAttempts;
1819 size_t ml=EQUAL_READ32-1;
1820
1821 /* HC4 match finder */
1822 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1823
Yann Collet22d76322016-06-21 08:01:51 +02001824 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001825 const BYTE* match;
1826 size_t currentMl=0;
1827 if ((!extDict) || matchIndex >= dictLimit) {
1828 match = base + matchIndex;
1829 if (match[ml] == ip[ml]) /* potentially better */
1830 currentMl = ZSTD_count(ip, match, iLimit);
1831 } else {
1832 match = dictBase + matchIndex;
1833 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1834 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1835 }
1836
1837 /* save best solution */
Yann Collet22d76322016-06-21 08:01:51 +02001838 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 +02001839
1840 if (matchIndex <= minChain) break;
1841 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1842 }
1843
1844 return ml;
1845}
1846
1847
1848FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1849 ZSTD_CCtx* zc,
1850 const BYTE* ip, const BYTE* const iLimit,
1851 size_t* offsetPtr,
1852 const U32 maxNbAttempts, const U32 matchLengthSearch)
1853{
1854 switch(matchLengthSearch)
1855 {
1856 default :
1857 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1858 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1859 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1860 }
1861}
1862
1863
1864FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1865 ZSTD_CCtx* zc,
1866 const BYTE* ip, const BYTE* const iLimit,
1867 size_t* offsetPtr,
1868 const U32 maxNbAttempts, const U32 matchLengthSearch)
1869{
1870 switch(matchLengthSearch)
1871 {
1872 default :
1873 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1874 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1875 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1876 }
1877}
1878
inikep64d7bcb2016-04-07 19:14:09 +02001879
Yann Collet287b7d92015-11-22 13:24:05 +01001880/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001881* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001882*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001883FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001884void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1885 const void* src, size_t srcSize,
1886 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001887{
inikepfaa8d8a2016-04-05 19:01:10 +02001888 seqStore_t* seqStorePtr = &(ctx->seqStore);
1889 const BYTE* const istart = (const BYTE*)src;
1890 const BYTE* ip = istart;
1891 const BYTE* anchor = istart;
1892 const BYTE* const iend = istart + srcSize;
1893 const BYTE* const ilimit = iend - 8;
1894 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001895
Yann Collet793c6492016-04-09 20:32:00 +02001896 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1897 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001898
inikep64d7bcb2016-04-07 19:14:09 +02001899 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1900 size_t* offsetPtr,
1901 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02001902 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02001903 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02001904
inikepfaa8d8a2016-04-05 19:01:10 +02001905 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001906 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02001907 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02001908 { U32 const maxRep = (U32)(ip-base);
1909 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1910 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1911 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001912
inikepfaa8d8a2016-04-05 19:01:10 +02001913 /* Match Loop */
1914 while (ip < ilimit) {
1915 size_t matchLength=0;
1916 size_t offset=0;
1917 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001918
inikepfaa8d8a2016-04-05 19:01:10 +02001919 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02001920 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02001921 /* repcode : we take it */
Yann Collet9634f672016-07-03 01:23:58 +02001922 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001923 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001924 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001925
inikepfaa8d8a2016-04-05 19:01:10 +02001926 /* first search (depth 0) */
1927 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001928 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001929 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001930 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001931 }
Yann Collet5106a762015-11-05 15:00:24 +01001932
inikep7bc19b62016-04-06 09:46:01 +02001933 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001934 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1935 continue;
1936 }
1937
inikep64d7bcb2016-04-07 19:14:09 +02001938 /* let's try to find a better solution */
1939 if (depth>=1)
1940 while (ip<ilimit) {
1941 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001942 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1943 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001944 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001945 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001946 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1947 matchLength = mlRep, offset = 0, start = ip;
1948 }
1949 { size_t offset2=99999999;
1950 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001951 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1952 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001953 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1954 matchLength = ml2, offset = offset2, start = ip;
1955 continue; /* search a better one */
1956 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001957
inikep64d7bcb2016-04-07 19:14:09 +02001958 /* let's find an even better one */
1959 if ((depth==2) && (ip<ilimit)) {
1960 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001961 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1962 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001963 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001964 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001965 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1966 matchLength = ml2, offset = 0, start = ip;
1967 }
1968 { size_t offset2=99999999;
1969 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001970 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1971 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001972 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1973 matchLength = ml2, offset = offset2, start = ip;
1974 continue;
1975 } } }
1976 break; /* nothing found : store previous solution */
1977 }
1978
1979 /* catch up */
1980 if (offset) {
1981 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1982 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02001983 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02001984 }
1985
inikepfaa8d8a2016-04-05 19:01:10 +02001986 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001987_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001988 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02001989 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02001990 anchor = ip = start + matchLength;
1991 }
Yann Collet48537162016-04-07 15:24:29 +02001992
inikepfaa8d8a2016-04-05 19:01:10 +02001993 /* check immediate repcode */
1994 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02001995 && ((offset_2>0)
1996 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02001997 /* store sequence */
Yann Collet9634f672016-07-03 01:23:58 +02001998 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
1999 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02002000 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2001 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002002 anchor = ip;
2003 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002004 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002005
Yann Collet4266c0a2016-06-14 01:49:25 +02002006 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002007 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2008 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002009
inikepfaa8d8a2016-04-05 19:01:10 +02002010 /* Last Literals */
2011 { size_t const lastLLSize = iend - anchor;
2012 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2013 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002014 }
Yann Collet5106a762015-11-05 15:00:24 +01002015}
2016
Yann Collet5be2dd22015-11-11 13:43:58 +01002017
inikep64d7bcb2016-04-07 19:14:09 +02002018static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2019{
2020 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2021}
2022
2023static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2024{
2025 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2026}
2027
2028static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2029{
2030 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2031}
2032
2033static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2034{
2035 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2036}
2037
2038
inikepfaa8d8a2016-04-05 19:01:10 +02002039FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002040void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2041 const void* src, size_t srcSize,
2042 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002043{
inikepfaa8d8a2016-04-05 19:01:10 +02002044 seqStore_t* seqStorePtr = &(ctx->seqStore);
2045 const BYTE* const istart = (const BYTE*)src;
2046 const BYTE* ip = istart;
2047 const BYTE* anchor = istart;
2048 const BYTE* const iend = istart + srcSize;
2049 const BYTE* const ilimit = iend - 8;
2050 const BYTE* const base = ctx->base;
2051 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002052 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002053 const BYTE* const prefixStart = base + dictLimit;
2054 const BYTE* const dictBase = ctx->dictBase;
2055 const BYTE* const dictEnd = dictBase + dictLimit;
2056 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2057
2058 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2059 const U32 mls = ctx->params.cParams.searchLength;
2060
inikep64d7bcb2016-04-07 19:14:09 +02002061 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2062 size_t* offsetPtr,
2063 U32 maxNbAttempts, U32 matchLengthSearch);
2064 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2065
Yann Collet302ff032016-07-03 01:28:16 +02002066 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002067
Yann Collet302ff032016-07-03 01:28:16 +02002068 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002069 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002070 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002071
2072 /* Match Loop */
2073 while (ip < ilimit) {
2074 size_t matchLength=0;
2075 size_t offset=0;
2076 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002077 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002078
2079 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002080 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002081 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2082 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002083 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002084 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002085 /* repcode detected we should take it */
2086 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02002087 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2088 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002089 } }
2090
2091 /* first search (depth 0) */
2092 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002093 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002094 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002095 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002096 }
2097
inikep7bc19b62016-04-06 09:46:01 +02002098 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02002099 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2100 continue;
2101 }
2102
inikep64d7bcb2016-04-07 19:14:09 +02002103 /* let's try to find a better solution */
2104 if (depth>=1)
2105 while (ip<ilimit) {
2106 ip ++;
2107 current++;
2108 /* check repCode */
2109 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002110 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002111 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2112 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002113 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002114 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2115 /* repcode detected */
2116 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2117 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2118 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002119 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002120 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2121 matchLength = repLength, offset = 0, start = ip;
2122 } }
2123
2124 /* search match, depth 1 */
2125 { size_t offset2=99999999;
2126 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002127 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2128 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02002129 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2130 matchLength = ml2, offset = offset2, start = ip;
2131 continue; /* search a better one */
2132 } }
2133
2134 /* let's find an even better one */
2135 if ((depth==2) && (ip<ilimit)) {
2136 ip ++;
2137 current++;
2138 /* check repCode */
2139 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002140 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002141 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2142 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002143 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002144 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2145 /* repcode detected */
2146 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2147 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2148 int gain2 = (int)(repLength * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002149 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002150 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2151 matchLength = repLength, offset = 0, start = ip;
2152 } }
2153
2154 /* search match, depth 2 */
2155 { size_t offset2=99999999;
2156 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002157 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2158 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02002159 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2160 matchLength = ml2, offset = offset2, start = ip;
2161 continue;
2162 } } }
2163 break; /* nothing found : store previous solution */
2164 }
2165
inikepfaa8d8a2016-04-05 19:01:10 +02002166 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002167 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002168 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002169 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2170 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002171 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002172 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002173 }
inikepfaa8d8a2016-04-05 19:01:10 +02002174
inikepfaa8d8a2016-04-05 19:01:10 +02002175 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002176_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002177 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002178 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002179 anchor = ip = start + matchLength;
2180 }
2181
2182 /* check immediate repcode */
2183 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002184 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002185 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2186 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002187 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002188 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2189 /* repcode detected we should take it */
2190 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02002191 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
Yann Collet302ff032016-07-03 01:28:16 +02002192 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002193 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2194 ip += matchLength;
2195 anchor = ip;
2196 continue; /* faster when present ... (?) */
2197 }
2198 break;
2199 } }
2200
Yann Collet4266c0a2016-06-14 01:49:25 +02002201 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002202 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002203
inikepfaa8d8a2016-04-05 19:01:10 +02002204 /* Last Literals */
2205 { size_t const lastLLSize = iend - anchor;
2206 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2207 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002208 }
2209}
2210
2211
Yann Collet59d1f792016-01-23 19:28:41 +01002212void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002213{
inikep64d7bcb2016-04-07 19:14:09 +02002214 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002215}
2216
Yann Collet59d1f792016-01-23 19:28:41 +01002217static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002218{
Yann Colleta1249dc2016-01-25 04:22:03 +01002219 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002220}
Yann Collet9a24e592015-11-22 02:53:43 +01002221
Yann Collet59d1f792016-01-23 19:28:41 +01002222static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002223{
Yann Colleta1249dc2016-01-25 04:22:03 +01002224 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002225}
2226
Yann Collet59d1f792016-01-23 19:28:41 +01002227static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002228{
Yann Colleta1249dc2016-01-25 04:22:03 +01002229 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002230}
2231
inikepef519412016-04-21 11:08:43 +02002232
inikepef519412016-04-21 11:08:43 +02002233/* The optimal parser */
2234#include "zstd_opt.h"
2235
2236static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2237{
Yann Colletd4f4e582016-06-27 01:31:35 +02002238#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002239 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2240#else
2241 (void)ctx; (void)src; (void)srcSize;
2242 return;
2243#endif
2244}
2245
2246static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2247{
2248#ifdef ZSTD_OPT_H_91842398743
2249 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002250#else
2251 (void)ctx; (void)src; (void)srcSize;
2252 return;
2253#endif
inikepef519412016-04-21 11:08:43 +02002254}
2255
inikepd3b8d7a2016-02-22 10:06:17 +01002256static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002257{
Yann Colletd4f4e582016-06-27 01:31:35 +02002258#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002259 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2260#else
2261 (void)ctx; (void)src; (void)srcSize;
2262 return;
2263#endif
2264}
2265
2266static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2267{
2268#ifdef ZSTD_OPT_H_91842398743
2269 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002270#else
2271 (void)ctx; (void)src; (void)srcSize;
2272 return;
2273#endif
inikepe2bfe242016-01-31 11:25:48 +01002274}
2275
Yann Collet7a231792015-11-21 15:27:35 +01002276
Yann Collet59d1f792016-01-23 19:28:41 +01002277typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002278
Yann Colletb923f652016-01-26 03:14:20 +01002279static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002280{
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002281 static const ZSTD_blockCompressor blockCompressor[2][8] = {
2282 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 },
2283 { 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 +01002284 };
2285
2286 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002287}
2288
2289
Yann Colletd1b26842016-03-15 01:24:33 +01002290static 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 +01002291{
Yann Collet19cab462016-06-17 12:54:52 +02002292 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002293 const BYTE* const base = zc->base;
2294 const BYTE* const istart = (const BYTE*)src;
2295 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002296 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 +02002297 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002298 if (current > zc->nextToUpdate + 384)
2299 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 +01002300 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002301 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002302}
2303
2304
Yann Colletc991cc12016-07-28 00:55:43 +02002305/*! ZSTD_compress_generic() :
2306* Compress a chunk of data into one or multiple blocks.
2307* All blocks will be terminated, all input will be consumed.
2308* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2309* Frame is supposed already started (header already produced)
2310* @return : compressed size, or an error code
2311*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002312static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2313 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002314 const void* src, size_t srcSize,
2315 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002316{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002317 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002318 size_t remaining = srcSize;
2319 const BYTE* ip = (const BYTE*)src;
2320 BYTE* const ostart = (BYTE*)dst;
2321 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002322 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002323
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002324 if (cctx->params.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002325 XXH64_update(&cctx->xxhState, src, srcSize);
2326
Yann Collet2ce49232016-02-02 14:36:49 +01002327 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002328 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002329 size_t cSize;
2330
inikepfb5df612016-05-24 15:36:37 +02002331 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 +01002332 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002333
Yann Collet346efcc2016-08-02 14:26:00 +02002334 /* preemptive overflow correction */
Yann Colletc261f712016-12-12 00:25:07 +01002335 if (cctx->lowLimit > (2U<<30)) {
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002336 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002337 U32 const current = (U32)(ip - cctx->base);
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002338 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002339 U32 const correction = current - newCurrent;
2340 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002341 ZSTD_reduceIndex(cctx, correction);
2342 cctx->base += correction;
2343 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002344 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002345 cctx->dictLimit -= correction;
2346 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2347 else cctx->nextToUpdate -= correction;
2348 }
2349
Yann Collet06e76972017-01-25 16:39:03 -08002350 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002351 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002352 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2353 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2354 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002355 }
Yann Collet89db5e02015-11-13 11:27:46 +01002356
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002357 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002358 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002359
Yann Collet2ce49232016-02-02 14:36:49 +01002360 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002361 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2362 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2363 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2364 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2365 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002366 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002367 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002368 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002369 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002370 }
2371
2372 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002373 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002374 ip += blockSize;
2375 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002376 }
2377
Yann Collet62470b42016-07-28 15:29:08 +02002378 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002379 return op-ostart;
2380}
2381
2382
Yann Collet6236eba2016-04-12 15:52:33 +02002383static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002384 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002385{ BYTE* const op = (BYTE*)dst;
Yann Collet731ef162016-07-27 21:05:12 +02002386 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2387 U32 const checksumFlag = params.fParams.checksumFlag>0;
2388 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002389 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002390 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2391 U32 const fcsCode = params.fParams.contentSizeFlag ?
Yann Collet673f0d72016-06-06 00:26:38 +02002392 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2393 0;
Yann Collet731ef162016-07-27 21:05:12 +02002394 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002395 size_t pos;
2396
2397 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002398
2399 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002400 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002401 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002402 switch(dictIDSizeCode)
2403 {
2404 default: /* impossible */
2405 case 0 : break;
2406 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002407 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002408 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2409 }
Yann Collet673f0d72016-06-06 00:26:38 +02002410 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002411 {
2412 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002413 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002414 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2415 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002416 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002417 }
Yann Colletc46fb922016-05-29 05:01:04 +02002418 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002419}
2420
2421
Yann Collet346efcc2016-08-02 14:26:00 +02002422static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002423 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002424 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002425 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002426{
Yann Collet2acb5d32015-10-29 16:49:43 +01002427 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002428 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002429
Yann Collet346efcc2016-08-02 14:26:00 +02002430 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002431
Yann Collet346efcc2016-08-02 14:26:00 +02002432 if (frame && (cctx->stage==ZSTDcs_init)) {
2433 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002434 if (ZSTD_isError(fhSize)) return fhSize;
2435 dstCapacity -= fhSize;
2436 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002437 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002438 }
Yann Colletf3eca252015-10-22 15:31:46 +01002439
Yann Collet417890c2015-12-04 17:16:37 +01002440 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002441 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002442 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002443 ptrdiff_t const delta = cctx->nextSrc - ip;
2444 cctx->lowLimit = cctx->dictLimit;
2445 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2446 cctx->dictBase = cctx->base;
2447 cctx->base -= delta;
2448 cctx->nextToUpdate = cctx->dictLimit;
2449 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002450 }
2451
Yann Collet346efcc2016-08-02 14:26:00 +02002452 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2453 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2454 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2455 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2456 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002457 }
2458
Yann Collet346efcc2016-08-02 14:26:00 +02002459 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002460
Yann Collet5eb749e2017-01-11 18:21:25 +01002461 if (srcSize) {
2462 size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002463 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2464 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002465 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002466 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002467 } else
2468 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002469}
2470
Yann Colletbf42c8e2016-01-09 01:08:23 +01002471
Yann Collet5b567392016-07-28 01:17:22 +02002472size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002473 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002474 const void* src, size_t srcSize)
2475{
Yann Collet5b567392016-07-28 01:17:22 +02002476 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
2477}
2478
2479
Yann Colletcf05b9d2016-07-18 16:52:10 +02002480size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002481{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002482 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2483}
2484
2485size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2486{
2487 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002488 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Colletc991cc12016-07-28 00:55:43 +02002489 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002490}
2491
2492
Yann Colletb923f652016-01-26 03:14:20 +01002493static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002494{
2495 const BYTE* const ip = (const BYTE*) src;
2496 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002497
Yann Collet417890c2015-12-04 17:16:37 +01002498 /* input becomes current prefix */
2499 zc->lowLimit = zc->dictLimit;
2500 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2501 zc->dictBase = zc->base;
2502 zc->base += ip - zc->nextSrc;
2503 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002504 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002505
2506 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002507 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002508
Yann Collet3b719252016-03-30 19:48:05 +02002509 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002510 {
2511 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002512 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002513 break;
2514
Yann Collet45dc3562016-07-12 09:47:31 +02002515 case ZSTD_dfast:
2516 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2517 break;
2518
Yann Collet417890c2015-12-04 17:16:37 +01002519 case ZSTD_greedy:
2520 case ZSTD_lazy:
2521 case ZSTD_lazy2:
Yann Collet731ef162016-07-27 21:05:12 +02002522 ZSTD_insertAndFindFirstIndex (zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002523 break;
2524
2525 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002526 case ZSTD_btopt:
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002527 case ZSTD_btopt2:
Yann Collet731ef162016-07-27 21:05:12 +02002528 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002529 break;
2530
2531 default:
2532 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2533 }
2534
Nick Terrellecf90ca2017-02-13 18:27:34 -08002535 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002536 return 0;
2537}
2538
2539
Nick Terrellf9c9af32016-10-19 17:22:08 -07002540/* Dictionaries that assign zero probability to symbols that show up causes problems
2541 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2542 that we may encounter during compression.
2543 NOTE: This behavior is not standard and could be improved in the future. */
2544static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2545 U32 s;
2546 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2547 for (s = 0; s <= maxSymbolValue; ++s) {
2548 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2549 }
2550 return 0;
2551}
2552
2553
Yann Colletb923f652016-01-26 03:14:20 +01002554/* Dictionary format :
Yann Colletee5b7252016-10-27 14:20:55 -07002555 Magic == ZSTD_DICT_MAGIC (4 bytes)
2556 HUF_writeCTable(256)
2557 FSE_writeNCount(off)
2558 FSE_writeNCount(ml)
2559 FSE_writeNCount(ll)
2560 RepOffsets
2561 Dictionary content
Yann Colletb923f652016-01-26 03:14:20 +01002562*/
Yann Colletfb797352016-03-13 11:08:40 +01002563/*! ZSTD_loadDictEntropyStats() :
Yann Collet736d4192016-06-15 18:48:51 +02002564 @return : size read from dictionary
2565 note : magic number supposed already checked */
2566static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002567{
Yann Collet52a06222016-06-15 13:53:34 +02002568 const BYTE* dictPtr = (const BYTE*)dict;
2569 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07002570 short offcodeNCount[MaxOff+1];
2571 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08002572 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01002573
Yann Collet736d4192016-06-15 18:48:51 +02002574 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002575 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002576 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002577 }
Yann Colletfb810d62016-01-28 00:18:06 +01002578
Nick Terrellf9c9af32016-10-19 17:22:08 -07002579 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02002580 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002581 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002582 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002583 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Collet643d9a22016-12-01 16:24:04 -08002584 CHECK_E (FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002585 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002586 }
Yann Colletfb810d62016-01-28 00:18:06 +01002587
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002588 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002589 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002590 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002591 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002592 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002593 /* Every match length code must have non-zero probability */
2594 CHECK_F (ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
Yann Collet643d9a22016-12-01 16:24:04 -08002595 CHECK_E (FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002596 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002597 }
Yann Colletfb810d62016-01-28 00:18:06 +01002598
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002599 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002600 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002601 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002602 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002603 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002604 /* Every literal length code must have non-zero probability */
2605 CHECK_F (ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
Yann Collet643d9a22016-12-01 16:24:04 -08002606 CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002607 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002608 }
Yann Colletfb810d62016-01-28 00:18:06 +01002609
Yann Collet52a06222016-06-15 13:53:34 +02002610 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Nick Terrell8157a4c2016-12-20 10:47:52 -08002611 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] == 0 || cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2612 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] == 0 || cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2613 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 +02002614 dictPtr += 12;
2615
Nick Terrellb2c39a22016-10-24 14:11:27 -07002616 { U32 offcodeMax = MaxOff;
2617 if ((size_t)(dictEnd - dictPtr) <= ((U32)-1) - 128 KB) {
2618 U32 const maxOffset = (U32)(dictEnd - dictPtr) + 128 KB; /* The maximum offset that must be supported */
2619 /* Calculate minimum offset code required to represent maxOffset */
2620 offcodeMax = ZSTD_highbit32(maxOffset);
2621 }
Nick Terrellf9c9af32016-10-19 17:22:08 -07002622 /* Every possible supported offset <= dictContentSize + 128 KB must be representable */
2623 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
2624 }
2625
Yann Collet736d4192016-06-15 18:48:51 +02002626 cctx->flagStaticTables = 1;
Yann Collet52a06222016-06-15 13:53:34 +02002627 return dictPtr - (const BYTE*)dict;
Yann Colletb923f652016-01-26 03:14:20 +01002628}
2629
Yann Colletd1b26842016-03-15 01:24:33 +01002630/** ZSTD_compress_insertDictionary() :
2631* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002632static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002633{
Yann Colletc46fb922016-05-29 05:01:04 +02002634 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002635
Yann Collet14312d82017-02-23 23:42:12 -08002636 /* dict as pure content */
2637 if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (zc->forceRawDict))
2638 return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletc46fb922016-05-29 05:01:04 +02002639 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
Yann Colletd1b26842016-03-15 01:24:33 +01002640
2641 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet3e21ec52016-09-06 15:36:19 +02002642 { size_t const loadError = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8);
2643 size_t const eSize = loadError + 8;
2644 if (ZSTD_isError(loadError)) return loadError;
Yann Collet21588e32016-03-30 16:50:44 +02002645 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002646 }
Yann Colletecd651b2016-01-07 15:35:18 +01002647}
2648
Yann Collet27caf2a2016-04-01 15:48:48 +02002649/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002650* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002651static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002652 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002653 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002654{
Yann Colleta7737f62016-09-06 09:44:59 +02002655 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
Yann Collet3e21ec52016-09-06 15:36:19 +02002656 CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp));
Yann Colleta7737f62016-09-06 09:44:59 +02002657 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002658}
2659
2660
Yann Collet27caf2a2016-04-01 15:48:48 +02002661/*! ZSTD_compressBegin_advanced() :
2662* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002663size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002664 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002665 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002666{
2667 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02002668 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet81e13ef2016-06-07 00:51:51 +02002669 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002670}
2671
2672
Yann Collet81e13ef2016-06-07 00:51:51 +02002673size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002674{
Yann Collet6c6e1752016-06-27 15:28:45 +02002675 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002676 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002677}
Yann Collet083fcc82015-10-25 14:06:35 +01002678
inikep19bd48f2016-04-04 12:10:00 +02002679
Yann Colletb05c4822017-01-12 02:01:28 +01002680size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002681{
Yann Colletb05c4822017-01-12 02:01:28 +01002682 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002683}
2684
2685
Yann Collet62470b42016-07-28 15:29:08 +02002686/*! ZSTD_writeEpilogue() :
2687* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002688* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002689static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002690{
Yann Colletc991cc12016-07-28 00:55:43 +02002691 BYTE* const ostart = (BYTE*)dst;
2692 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002693 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002694
Yann Collet87c18b22016-08-26 01:43:47 +02002695 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002696
2697 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002698 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002699 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002700 if (ZSTD_isError(fhSize)) return fhSize;
2701 dstCapacity -= fhSize;
2702 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002703 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002704 }
2705
Yann Colletc991cc12016-07-28 00:55:43 +02002706 if (cctx->stage != ZSTDcs_ending) {
2707 /* write one last empty block, make it the "last" block */
2708 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2709 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2710 MEM_writeLE32(op, cBlockHeader24);
2711 op += ZSTD_blockHeaderSize;
2712 dstCapacity -= ZSTD_blockHeaderSize;
2713 }
2714
2715 if (cctx->params.fParams.checksumFlag) {
2716 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2717 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2718 MEM_writeLE32(op, checksum);
2719 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002720 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002721
Yann Collet731ef162016-07-27 21:05:12 +02002722 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002723 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002724}
2725
Yann Colletfd416f12016-01-30 03:14:15 +01002726
Yann Collet62470b42016-07-28 15:29:08 +02002727size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2728 void* dst, size_t dstCapacity,
2729 const void* src, size_t srcSize)
2730{
2731 size_t endResult;
2732 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
2733 if (ZSTD_isError(cSize)) return cSize;
2734 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2735 if (ZSTD_isError(endResult)) return endResult;
2736 return cSize + endResult;
2737}
2738
2739
Yann Collet19c10022016-07-28 01:25:46 +02002740static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002741 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002742 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002743 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002744 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002745{
Yann Collet3e21ec52016-09-06 15:36:19 +02002746 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
Yann Collet62470b42016-07-28 15:29:08 +02002747 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002748}
2749
Yann Collet21588e32016-03-30 16:50:44 +02002750size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2751 void* dst, size_t dstCapacity,
2752 const void* src, size_t srcSize,
2753 const void* dict,size_t dictSize,
2754 ZSTD_parameters params)
2755{
Yann Colletcf409a72016-09-26 16:41:05 +02002756 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02002757 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2758}
2759
Yann Colletd1b26842016-03-15 01:24:33 +01002760size_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 +01002761{
Yann Collet407a11f2016-11-03 15:52:01 -07002762 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02002763 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002764 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002765}
2766
Yann Colletd1b26842016-03-15 01:24:33 +01002767size_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 +01002768{
Yann Collet21588e32016-03-30 16:50:44 +02002769 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002770}
2771
Yann Colletd1b26842016-03-15 01:24:33 +01002772size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002773{
Yann Collet44fe9912015-10-29 22:02:40 +01002774 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002775 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002776 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002777 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002778 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002779 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 +01002780 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002781}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002782
Yann Colletfd416f12016-01-30 03:14:15 +01002783
Yann Collet81e13ef2016-06-07 00:51:51 +02002784/* ===== Dictionary API ===== */
2785
2786struct ZSTD_CDict_s {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002787 void* dictBuffer;
2788 const void* dictContent;
Yann Collet81e13ef2016-06-07 00:51:51 +02002789 size_t dictContentSize;
2790 ZSTD_CCtx* refContext;
David Lamda9d3b72016-08-29 09:03:12 -07002791}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
Yann Collet81e13ef2016-06-07 00:51:51 +02002792
Yann Colletd7c65892016-09-15 02:50:27 +02002793size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2794{
2795 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01002796 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02002797}
2798
Yann Collet1f57c2e2016-12-21 16:20:11 +01002799ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
2800 ZSTD_parameters params, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02002801{
Yann Collet23b6e052016-08-28 21:05:43 -07002802 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2803 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02002804
Yann Collet23b6e052016-08-28 21:05:43 -07002805 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002806 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2807
Yann Collet1f57c2e2016-12-21 16:20:11 +01002808 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07002809 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002810 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002811 return NULL;
2812 }
2813
Yann Collet1f57c2e2016-12-21 16:20:11 +01002814 if ((byReference) || (!dictBuffer) || (!dictSize)) {
2815 cdict->dictBuffer = NULL;
2816 cdict->dictContent = dictBuffer;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002817 } else {
2818 void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
Yann Collet4e5eea62016-12-21 16:44:35 +01002819 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002820 memcpy(internalBuffer, dictBuffer, dictSize);
2821 cdict->dictBuffer = internalBuffer;
2822 cdict->dictContent = internalBuffer;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002823 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002824
2825 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
Yann Collet81e13ef2016-06-07 00:51:51 +02002826 if (ZSTD_isError(errorCode)) {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002827 ZSTD_free(cdict->dictBuffer, customMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01002828 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002829 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002830 return NULL;
2831 } }
2832
Yann Collet81e13ef2016-06-07 00:51:51 +02002833 cdict->refContext = cctx;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002834 cdict->dictContentSize = dictSize;
Yann Collet81e13ef2016-06-07 00:51:51 +02002835 return cdict;
2836 }
2837}
2838
2839ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2840{
2841 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet07639052016-08-03 01:57:57 +02002842 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002843 params.fParams.contentSizeFlag = 1;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002844 return ZSTD_createCDict_advanced(dict, dictSize, 0, params, allocator);
2845}
2846
2847ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
2848{
2849 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2850 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
2851 params.fParams.contentSizeFlag = 1;
2852 return ZSTD_createCDict_advanced(dict, dictSize, 1, params, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02002853}
2854
2855size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2856{
Yann Collet23b6e052016-08-28 21:05:43 -07002857 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02002858 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07002859 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01002860 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002861 ZSTD_free(cdict, cMem);
2862 return 0;
2863 }
Yann Collet81e13ef2016-06-07 00:51:51 +02002864}
2865
Yann Collet95162342016-10-25 16:19:52 -07002866static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
2867 return ZSTD_getParamsFromCCtx(cdict->refContext);
2868}
2869
Yann Colletc5933482017-01-22 16:40:06 -08002870size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002871{
Yann Collet97b378a2016-09-21 17:20:19 +02002872 if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
Sean Purcell2db72492017-02-09 10:50:43 -08002873 else {
2874 ZSTD_parameters params = cdict->refContext->params;
2875 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
2876 CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, params, pledgedSrcSize));
2877 }
Yann Collet4cb21292016-09-15 14:54:07 +02002878 return 0;
2879}
2880
Yann Collet07639052016-08-03 01:57:57 +02002881/*! ZSTD_compress_usingCDict() :
2882* Compression using a digested Dictionary.
2883* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2884* Note that compression level is decided during dictionary creation */
Yann Collet4cb21292016-09-15 14:54:07 +02002885size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2886 void* dst, size_t dstCapacity,
2887 const void* src, size_t srcSize,
2888 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02002889{
Yann Collet4cb21292016-09-15 14:54:07 +02002890 CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize));
Yann Collet07639052016-08-03 01:57:57 +02002891
2892 if (cdict->refContext->params.fParams.contentSizeFlag==1) {
2893 cctx->params.fParams.contentSizeFlag = 1;
2894 cctx->frameContentSize = srcSize;
2895 }
2896
2897 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002898}
2899
2900
2901
Yann Collet104e5b02016-08-12 13:04:27 +02002902/* ******************************************************************
2903* Streaming
2904********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002905
2906typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
2907
2908struct ZSTD_CStream_s {
Yann Colletfa0c0972016-09-15 14:11:01 +02002909 ZSTD_CCtx* cctx;
Yann Collet95162342016-10-25 16:19:52 -07002910 ZSTD_CDict* cdictLocal;
2911 const ZSTD_CDict* cdict;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002912 char* inBuff;
2913 size_t inBuffSize;
2914 size_t inToCompress;
2915 size_t inBuffPos;
2916 size_t inBuffTarget;
2917 size_t blockSize;
2918 char* outBuff;
2919 size_t outBuffSize;
2920 size_t outBuffContentSize;
2921 size_t outBuffFlushedSize;
2922 ZSTD_cStreamStage stage;
2923 U32 checksum;
2924 U32 frameEnded;
Yann Collete795c8a2016-12-13 16:39:36 +01002925 U64 pledgedSrcSize;
2926 U64 inputProcessed;
Yann Colletee5b7252016-10-27 14:20:55 -07002927 ZSTD_parameters params;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002928 ZSTD_customMem customMem;
2929}; /* typedef'd to ZSTD_CStream within "zstd.h" */
2930
2931ZSTD_CStream* ZSTD_createCStream(void)
2932{
2933 return ZSTD_createCStream_advanced(defaultCustomMem);
2934}
2935
2936ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
2937{
2938 ZSTD_CStream* zcs;
2939
Yann Collet23b6e052016-08-28 21:05:43 -07002940 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2941 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002942
Yann Collet23b6e052016-08-28 21:05:43 -07002943 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002944 if (zcs==NULL) return NULL;
2945 memset(zcs, 0, sizeof(ZSTD_CStream));
2946 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
Yann Colletfa0c0972016-09-15 14:11:01 +02002947 zcs->cctx = ZSTD_createCCtx_advanced(customMem);
2948 if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002949 return zcs;
2950}
2951
2952size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2953{
2954 if (zcs==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -07002955 { ZSTD_customMem const cMem = zcs->customMem;
Yann Colletfa0c0972016-09-15 14:11:01 +02002956 ZSTD_freeCCtx(zcs->cctx);
Yann Collet95162342016-10-25 16:19:52 -07002957 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet23b6e052016-08-28 21:05:43 -07002958 ZSTD_free(zcs->inBuff, cMem);
2959 ZSTD_free(zcs->outBuff, cMem);
2960 ZSTD_free(zcs, cMem);
2961 return 0;
2962 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002963}
2964
2965
Yann Collet104e5b02016-08-12 13:04:27 +02002966/*====== Initialization ======*/
2967
2968size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
2969size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002970
Sean Purcell2db72492017-02-09 10:50:43 -08002971static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002972{
Yann Colletd564faa2016-12-18 21:39:15 +01002973 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 -07002974
2975 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
2976 else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
Yann Collet4cb21292016-09-15 14:54:07 +02002977
2978 zcs->inToCompress = 0;
2979 zcs->inBuffPos = 0;
2980 zcs->inBuffTarget = zcs->blockSize;
2981 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
2982 zcs->stage = zcss_load;
2983 zcs->frameEnded = 0;
Yann Collete795c8a2016-12-13 16:39:36 +01002984 zcs->pledgedSrcSize = pledgedSrcSize;
2985 zcs->inputProcessed = 0;
Yann Collet4cb21292016-09-15 14:54:07 +02002986 return 0; /* ready to go */
2987}
2988
Sean Purcell2db72492017-02-09 10:50:43 -08002989size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
2990{
2991
2992 zcs->params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
2993
2994 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
2995}
2996
Yann Collet5a0c8e22016-08-12 01:20:36 +02002997size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
2998 const void* dict, size_t dictSize,
2999 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3000{
3001 /* allocate buffers */
3002 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
3003 if (zcs->inBuffSize < neededInBuffSize) {
3004 zcs->inBuffSize = neededInBuffSize;
Yann Colletcf409a72016-09-26 16:41:05 +02003005 ZSTD_free(zcs->inBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003006 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003007 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
3008 }
3009 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
3010 }
3011 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
3012 zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
Yann Colletcf409a72016-09-26 16:41:05 +02003013 ZSTD_free(zcs->outBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003014 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003015 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
3016 }
3017
Sean Purcell57d423c2017-01-17 11:04:08 -08003018 if (dict && dictSize >= 8) {
Yann Colletee5b7252016-10-27 14:20:55 -07003019 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003020 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0, params, zcs->customMem);
Yann Colletee5b7252016-10-27 14:20:55 -07003021 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3022 zcs->cdict = zcs->cdictLocal;
3023 } else zcs->cdict = NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003024
Yann Collet5a0c8e22016-08-12 01:20:36 +02003025 zcs->checksum = params.fParams.checksumFlag > 0;
Yann Colletee5b7252016-10-27 14:20:55 -07003026 zcs->params = params;
Yann Collet4cb21292016-09-15 14:54:07 +02003027
Sean Purcell2db72492017-02-09 10:50:43 -08003028 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003029}
3030
Yann Collet95162342016-10-25 16:19:52 -07003031/* note : cdict must outlive compression session */
3032size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3033{
3034 ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
3035 size_t const initError = ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0);
3036 zcs->cdict = cdict;
Gregory Szorc7d6f4782017-01-14 17:44:54 -08003037 zcs->cctx->dictID = params.fParams.noDictIDFlag ? 0 : cdict->refContext->dictID;
Yann Collet95162342016-10-25 16:19:52 -07003038 return initError;
3039}
3040
Yann Collet5a0c8e22016-08-12 01:20:36 +02003041size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3042{
3043 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
3044 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);
3045}
3046
Yann Collete795c8a2016-12-13 16:39:36 +01003047size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3048{
Yann Colletd564faa2016-12-18 21:39:15 +01003049 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
3050 if (pledgedSrcSize) params.fParams.contentSizeFlag = 1;
Yann Collete795c8a2016-12-13 16:39:36 +01003051 return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);
3052}
3053
Yann Collet5a0c8e22016-08-12 01:20:36 +02003054size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3055{
3056 return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel);
3057}
3058
Yann Collet70e3b312016-08-23 01:18:06 +02003059size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02003060{
Yann Colletd7c65892016-09-15 02:50:27 +02003061 if (zcs==NULL) return 0; /* support sizeof on NULL */
Yann Collet335ad5d2016-10-25 17:47:02 -07003062 return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize;
Yann Colletcb327632016-08-23 00:30:31 +02003063}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003064
Yann Collet104e5b02016-08-12 13:04:27 +02003065/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003066
3067typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
3068
3069MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3070{
3071 size_t const length = MIN(dstCapacity, srcSize);
3072 memcpy(dst, src, length);
3073 return length;
3074}
3075
3076static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3077 void* dst, size_t* dstCapacityPtr,
3078 const void* src, size_t* srcSizePtr,
3079 ZSTD_flush_e const flush)
3080{
3081 U32 someMoreWork = 1;
3082 const char* const istart = (const char*)src;
3083 const char* const iend = istart + *srcSizePtr;
3084 const char* ip = istart;
3085 char* const ostart = (char*)dst;
3086 char* const oend = ostart + *dstCapacityPtr;
3087 char* op = ostart;
3088
3089 while (someMoreWork) {
3090 switch(zcs->stage)
3091 {
3092 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
3093
3094 case zcss_load:
3095 /* complete inBuffer */
3096 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3097 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
3098 zcs->inBuffPos += loaded;
3099 ip += loaded;
3100 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
3101 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
3102 } }
3103 /* compress current block (note : this stage cannot be stopped in the middle) */
3104 { void* cDst;
3105 size_t cSize;
3106 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3107 size_t oSize = oend-op;
3108 if (oSize >= ZSTD_compressBound(iSize))
3109 cDst = op; /* compress directly into output buffer (avoid flush stage) */
3110 else
3111 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3112 cSize = (flush == zsf_end) ?
Yann Colletfa0c0972016-09-15 14:11:01 +02003113 ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
3114 ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003115 if (ZSTD_isError(cSize)) return cSize;
3116 if (flush == zsf_end) zcs->frameEnded = 1;
3117 /* prepare next block */
3118 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3119 if (zcs->inBuffTarget > zcs->inBuffSize)
3120 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
3121 zcs->inToCompress = zcs->inBuffPos;
3122 if (cDst == op) { op += cSize; break; } /* no need to flush */
3123 zcs->outBuffContentSize = cSize;
3124 zcs->outBuffFlushedSize = 0;
3125 zcs->stage = zcss_flush; /* pass-through to flush stage */
3126 }
3127
3128 case zcss_flush:
3129 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3130 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3131 op += flushed;
3132 zcs->outBuffFlushedSize += flushed;
3133 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
3134 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3135 zcs->stage = zcss_load;
3136 break;
3137 }
3138
3139 case zcss_final:
3140 someMoreWork = 0; /* do nothing */
3141 break;
3142
3143 default:
3144 return ERROR(GENERIC); /* impossible */
3145 }
3146 }
3147
3148 *srcSizePtr = ip - istart;
3149 *dstCapacityPtr = op - ostart;
Yann Collete795c8a2016-12-13 16:39:36 +01003150 zcs->inputProcessed += *srcSizePtr;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003151 if (zcs->frameEnded) return 0;
3152 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3153 if (hintInSize==0) hintInSize = zcs->blockSize;
3154 return hintInSize;
3155 }
3156}
3157
Yann Collet53e17fb2016-08-17 01:39:22 +02003158size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003159{
Yann Collet53e17fb2016-08-17 01:39:22 +02003160 size_t sizeRead = input->size - input->pos;
3161 size_t sizeWritten = output->size - output->pos;
3162 size_t const result = ZSTD_compressStream_generic(zcs,
3163 (char*)(output->dst) + output->pos, &sizeWritten,
3164 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3165 input->pos += sizeRead;
3166 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003167 return result;
3168}
3169
3170
Yann Collet104e5b02016-08-12 13:04:27 +02003171/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003172
3173/*! ZSTD_flushStream() :
3174* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003175size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003176{
3177 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003178 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02003179 size_t const result = ZSTD_compressStream_generic(zcs,
Yann Collet95d07d72016-09-06 16:38:51 +02003180 (char*)(output->dst) + output->pos, &sizeWritten,
3181 &srcSize, &srcSize, /* use a valid src address instead of NULL */
Yann Colletc4119022016-08-17 01:50:54 +02003182 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003183 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003184 if (ZSTD_isError(result)) return result;
3185 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3186}
3187
3188
Yann Collet53e17fb2016-08-17 01:39:22 +02003189size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003190{
Yann Collet53e17fb2016-08-17 01:39:22 +02003191 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3192 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003193 BYTE* op = ostart;
3194
Yann Collete795c8a2016-12-13 16:39:36 +01003195 if ((zcs->pledgedSrcSize) && (zcs->inputProcessed != zcs->pledgedSrcSize))
3196 return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */
3197
Yann Collet5a0c8e22016-08-12 01:20:36 +02003198 if (zcs->stage != zcss_final) {
3199 /* flush whatever remains */
3200 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003201 size_t sizeWritten = output->size - output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003202 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
3203 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3204 op += sizeWritten;
3205 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003206 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003207 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3208 }
3209 /* create epilogue */
3210 zcs->stage = zcss_final;
3211 zcs->outBuffContentSize = !notEnded ? 0 :
Yann Colletfa0c0972016-09-15 14:11:01 +02003212 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 +02003213 }
3214
3215 /* flush epilogue */
3216 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3217 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3218 op += flushed;
3219 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003220 output->pos += op-ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003221 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3222 return toFlush - flushed;
3223 }
3224}
3225
3226
3227
Yann Collet70e8c382016-02-10 13:37:52 +01003228/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003229
Yann Collet236d94f2016-05-18 12:06:33 +02003230#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003231#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003232int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003233
Yann Collet3b719252016-03-30 19:48:05 +02003234static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003235{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003236 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003237 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003238 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3239 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003240 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3241 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003242 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3243 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3244 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003245 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003246 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3247 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3248 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3249 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3250 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3251 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3252 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3253 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003254 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
3255 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
3256 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003257 { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */
3258 { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */
3259 { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003260},
3261{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003262 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003263 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003264 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003265 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3266 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3267 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3268 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3269 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3270 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3271 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3272 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3273 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3274 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3275 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3276 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003277 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003278 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3279 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3280 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003281 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3282 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003283 { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/
3284 { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/
3285 { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003286},
3287{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003288 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003289 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3290 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3291 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3292 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3293 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3294 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3295 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3296 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3297 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3298 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3299 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3300 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3301 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3302 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003303 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3304 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3305 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3306 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3307 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3308 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003309 { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/
3310 { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/
3311 { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003312},
3313{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003314 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003315 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003316 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003317 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3318 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3319 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3320 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3321 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3322 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3323 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3324 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003325 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3326 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3327 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3328 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3329 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3330 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3331 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3332 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3333 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3334 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003335 { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/
3336 { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/
3337 { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003338},
3339};
3340
Yann Collet236d94f2016-05-18 12:06:33 +02003341/*! ZSTD_getCParams() :
3342* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3343* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003344ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003345{
Yann Collet15354142016-04-04 04:22:53 +02003346 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003347 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003348 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003349 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003350 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003351 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003352 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003353 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3354 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003355 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003356 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3357 }
Yann Collet70d13012016-06-01 18:45:34 +02003358 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003359 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003360}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003361
3362/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003363* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003364* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003365ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003366 ZSTD_parameters params;
3367 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3368 memset(&params, 0, sizeof(params));
3369 params.cParams = cParams;
3370 return params;
3371}