blob: 27b11b8efe7fbb2b7a71dd3f2e2abd3378f315fc [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;
Nick Terrella4197772017-03-01 17:51:56 -080082 HUF_repeat flagStaticHufTable;
Yann Collet731ef162016-07-27 21:05:12 +020083 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
84 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
85 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Nick Terrelld051cd52017-03-02 16:38:07 -080086 unsigned tmpCounters[HUF_WORKSPACE_SIZE_U32];
Yann Colletf3eca252015-10-22 15:31:46 +010087};
88
Yann Collet5be2dd22015-11-11 13:43:58 +010089ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +010090{
inikep3763c772016-06-03 13:28:20 +020091 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +020092}
93
94ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
95{
Yann Collet69c2cdb2016-07-14 16:52:45 +020096 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +020097
Yann Collet23b6e052016-08-28 21:05:43 -070098 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
99 if (!customMem.customAlloc || !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200100
Yann Collet23b6e052016-08-28 21:05:43 -0700101 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200102 if (!cctx) return NULL;
103 memset(cctx, 0, sizeof(ZSTD_CCtx));
Yann Colletbb002742017-01-25 16:25:38 -0800104 cctx->customMem = customMem;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200105 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100106}
107
Yann Collet5be2dd22015-11-11 13:43:58 +0100108size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100109{
inikep36403962016-06-03 16:36:50 +0200110 if (cctx==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -0700111 ZSTD_free(cctx->workSpace, cctx->customMem);
112 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100113 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100114}
115
Yann Collet70e3b312016-08-23 01:18:06 +0200116size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200117{
Yann Colletd7c65892016-09-15 02:50:27 +0200118 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet3ae543c2016-07-11 03:12:17 +0200119 return sizeof(*cctx) + cctx->workSpaceSize;
120}
121
Yann Colletbb002742017-01-25 16:25:38 -0800122size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
123{
124 switch(param)
125 {
Yann Collet06e76972017-01-25 16:39:03 -0800126 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet14312d82017-02-23 23:42:12 -0800127 case ZSTD_p_forceRawDict : cctx->forceRawDict = value>0; return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800128 default: return ERROR(parameter_unknown);
129 }
130}
131
Yann Colletb44be742016-03-26 20:52:14 +0100132const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100133{
Yann Colletb44be742016-03-26 20:52:14 +0100134 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100135}
136
Yann Collet95162342016-10-25 16:19:52 -0700137static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx)
138{
139 return cctx->params;
140}
141
Yann Collet59d70632015-11-04 12:05:27 +0100142
Yann Collet21588e32016-03-30 16:50:44 +0200143/** ZSTD_checkParams() :
144 ensure param values remain within authorized range.
145 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200146size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200147{
Yann Colletac8bace2016-09-07 14:54:23 +0200148# define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
Yann Collet15354142016-04-04 04:22:53 +0200149 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200150 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200151 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
152 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Collet2e2e78d2017-03-29 16:02:47 -0700153 CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200154 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200155 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200156 return 0;
157}
158
159
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100160/** ZSTD_cycleLog() :
161 * condition for correct operation : hashLog > 1 */
162static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
163{
164 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
165 return hashLog - btScale;
166}
167
Yann Collet70d13012016-06-01 18:45:34 +0200168/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200169 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200170 mostly downsizing to reduce memory consumption and initialization.
171 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
172 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200173 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200174ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100175{
Yann Collet70d13012016-06-01 18:45:34 +0200176 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100177
Yann Collet70e45772016-03-19 18:08:32 +0100178 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200179 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
180 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200181 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200182 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200183 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200184 } }
Yann Collet70d13012016-06-01 18:45:34 +0200185 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100186 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
187 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
188 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100189
Yann Collet70d13012016-06-01 18:45:34 +0200190 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200191
192 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100193}
194
195
Yann Collet88472382016-07-14 17:05:38 +0200196size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100197{
Yann Collet731ef162016-07-27 21:05:12 +0200198 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
199 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
200 size_t const maxNbSeq = blockSize / divider;
201 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200202
Yann Collet731ef162016-07-27 21:05:12 +0200203 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
204 size_t const hSize = ((size_t)1) << cParams.hashLog;
205 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
206 size_t const h3Size = ((size_t)1) << hashLog3;
207 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200208
209 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
210 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
211 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200212 + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Collet3ae543c2016-07-11 03:12:17 +0200213
214 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100215}
216
Yann Colleta7737f62016-09-06 09:44:59 +0200217
218static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
219{
220 return (param1.cParams.hashLog == param2.cParams.hashLog)
221 & (param1.cParams.chainLog == param2.cParams.chainLog)
Yann Colletedbcd9f2016-09-06 14:30:57 +0200222 & (param1.cParams.strategy == param2.cParams.strategy)
223 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3));
Yann Colleta7737f62016-09-06 09:44:59 +0200224}
225
226/*! ZSTD_continueCCtx() :
227 reuse CCtx without reset (note : requires no dictionary) */
228static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
229{
230 U32 const end = (U32)(cctx->nextSrc - cctx->base);
231 cctx->params = params;
232 cctx->frameContentSize = frameContentSize;
233 cctx->lowLimit = end;
234 cctx->dictLimit = end;
235 cctx->nextToUpdate = end+1;
236 cctx->stage = ZSTDcs_init;
237 cctx->dictID = 0;
238 cctx->loadedDictEnd = 0;
239 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200240 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
241 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200242 return 0;
243}
244
245typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
246
Yann Collet27caf2a2016-04-01 15:48:48 +0200247/*! ZSTD_resetCCtx_advanced() :
Sean Purcell3437bf22017-03-01 16:10:26 -0800248 note : `params` must be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100249static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletea2ecdc2016-07-14 22:43:12 +0200250 ZSTD_parameters params, U64 frameContentSize,
Yann Collet4cb21292016-09-15 14:54:07 +0200251 ZSTD_compResetPolicy_e const crp)
Yann Colleta7737f62016-09-06 09:44:59 +0200252{
Yann Collet4cb21292016-09-15 14:54:07 +0200253 if (crp == ZSTDcrp_continue)
Nick Terrella4197772017-03-01 17:51:56 -0800254 if (ZSTD_equivalentParams(params, zc->params)) {
255 zc->flagStaticTables = 0;
256 zc->flagStaticHufTable = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200257 return ZSTD_continueCCtx(zc, params, frameContentSize);
Nick Terrella4197772017-03-01 17:51:56 -0800258 }
inikep87d4f3d2016-03-02 15:56:24 +0100259
Yann Colleta7737f62016-09-06 09:44:59 +0200260 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
261 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
262 size_t const maxNbSeq = blockSize / divider;
263 size_t const tokenSpace = blockSize + 11*maxNbSeq;
264 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
265 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
266 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
267 size_t const h3Size = ((size_t)1) << hashLog3;
268 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
269 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100270
Yann Colleta7737f62016-09-06 09:44:59 +0200271 /* Check if workSpace is large enough, alloc a new one if needed */
272 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
273 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
274 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200275 + (((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200276 if (zc->workSpaceSize < neededSpace) {
277 ZSTD_free(zc->workSpace, zc->customMem);
278 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
279 if (zc->workSpace == NULL) return ERROR(memory_allocation);
280 zc->workSpaceSize = neededSpace;
281 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100282
Yann Colleta7737f62016-09-06 09:44:59 +0200283 if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */
284 XXH64_reset(&zc->xxhState, 0);
285 zc->hashLog3 = hashLog3;
286 zc->hashTable = (U32*)(zc->workSpace);
287 zc->chainTable = zc->hashTable + hSize;
288 zc->hashTable3 = zc->chainTable + chainSize;
289 ptr = zc->hashTable3 + h3Size;
290 zc->hufTable = (HUF_CElt*)ptr;
291 zc->flagStaticTables = 0;
Nick Terrella4197772017-03-01 17:51:56 -0800292 zc->flagStaticHufTable = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200293 ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
Yann Collet70e8c382016-02-10 13:37:52 +0100294
Yann Colleta7737f62016-09-06 09:44:59 +0200295 zc->nextToUpdate = 1;
296 zc->nextSrc = NULL;
297 zc->base = NULL;
298 zc->dictBase = NULL;
299 zc->dictLimit = 0;
300 zc->lowLimit = 0;
301 zc->params = params;
302 zc->blockSize = blockSize;
303 zc->frameContentSize = frameContentSize;
304 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
305
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200306 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
Yann Colleta7737f62016-09-06 09:44:59 +0200307 zc->seqStore.litFreq = (U32*)ptr;
308 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
309 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
310 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
311 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
312 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
313 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
314 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
315 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
316 zc->seqStore.litLengthSum = 0;
317 }
318 zc->seqStore.sequencesStart = (seqDef*)ptr;
319 ptr = zc->seqStore.sequencesStart + maxNbSeq;
320 zc->seqStore.llCode = (BYTE*) ptr;
321 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
322 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
323 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
324
325 zc->stage = ZSTDcs_init;
326 zc->dictID = 0;
327 zc->loadedDictEnd = 0;
328
329 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100330 }
Yann Colletf3eca252015-10-22 15:31:46 +0100331}
332
Yann Collet32dfae62017-01-19 10:32:55 -0800333/* ZSTD_invalidateRepCodes() :
334 * ensures next compression will not use repcodes from previous block.
335 * Note : only works with regular variant;
336 * do not use with extDict variant ! */
337void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
338 int i;
339 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
340}
Yann Collet083fcc82015-10-25 14:06:35 +0100341
Yann Collet370b08e2016-03-08 00:03:59 +0100342/*! ZSTD_copyCCtx() :
343* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet731ef162016-07-27 21:05:12 +0200344* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100345* @return : 0, or an error code */
Yann Collet97b378a2016-09-21 17:20:19 +0200346size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100347{
Yann Collet731ef162016-07-27 21:05:12 +0200348 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100349
Sean Purcell2db72492017-02-09 10:50:43 -0800350
inikep28669512016-06-02 13:04:18 +0200351 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Sean Purcell2db72492017-02-09 10:50:43 -0800352 { ZSTD_parameters params = srcCCtx->params;
353 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
354 ZSTD_resetCCtx_advanced(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset);
355 }
Yann Collet7b51a292016-01-26 15:58:49 +0100356
357 /* copy tables */
Yann Collet731ef162016-07-27 21:05:12 +0200358 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
359 size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
360 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
361 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100362 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
363 }
Yann Collet7b51a292016-01-26 15:58:49 +0100364
Yann Colletc46fb922016-05-29 05:01:04 +0200365 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100366 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
367 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
368 dstCCtx->nextSrc = srcCCtx->nextSrc;
369 dstCCtx->base = srcCCtx->base;
370 dstCCtx->dictBase = srcCCtx->dictBase;
371 dstCCtx->dictLimit = srcCCtx->dictLimit;
372 dstCCtx->lowLimit = srcCCtx->lowLimit;
373 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200374 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100375
Yann Colletfb810d62016-01-28 00:18:06 +0100376 /* copy entropy tables */
377 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Nick Terrella4197772017-03-01 17:51:56 -0800378 dstCCtx->flagStaticHufTable = srcCCtx->flagStaticHufTable;
Yann Collet863ec402016-01-28 17:56:33 +0100379 if (srcCCtx->flagStaticTables) {
Yann Colletfb810d62016-01-28 00:18:06 +0100380 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
381 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
382 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
383 }
Nick Terrella4197772017-03-01 17:51:56 -0800384 if (srcCCtx->flagStaticHufTable) {
385 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
386 }
Yann Collet7b51a292016-01-26 15:58:49 +0100387
388 return 0;
389}
390
391
Yann Colletecabfe32016-03-20 16:20:06 +0100392/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100393* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100394static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100395{
Yann Colletecabfe32016-03-20 16:20:06 +0100396 U32 u;
397 for (u=0 ; u < size ; u++) {
398 if (table[u] < reducerValue) table[u] = 0;
399 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100400 }
401}
402
Yann Colletecabfe32016-03-20 16:20:06 +0100403/*! ZSTD_reduceIndex() :
404* rescale all indexes to avoid future overflow (indexes are U32) */
405static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
406{
Yann Collet731ef162016-07-27 21:05:12 +0200407 { U32 const hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100408 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
409
Yann Collet731ef162016-07-27 21:05:12 +0200410 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200411 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100412
Yann Collet731ef162016-07-27 21:05:12 +0200413 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100414 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
415}
416
Yann Collet89db5e02015-11-13 11:27:46 +0100417
Yann Collet863ec402016-01-28 17:56:33 +0100418/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100419* Block entropic compression
420*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100421
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200422/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100423
Yann Colletd1b26842016-03-15 01:24:33 +0100424size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100425{
Yann Colletd1b26842016-03-15 01:24:33 +0100426 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200427 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
428 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100429 return ZSTD_blockHeaderSize+srcSize;
430}
431
432
Yann Colletd1b26842016-03-15 01:24:33 +0100433static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100434{
435 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200436 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100437
Yann Colletd1b26842016-03-15 01:24:33 +0100438 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100439
Yann Collet59d1f792016-01-23 19:28:41 +0100440 switch(flSize)
441 {
442 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200443 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100444 break;
445 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200446 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100447 break;
448 default: /*note : should not be necessary : flSize is within {1,2,3} */
449 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200450 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100451 break;
452 }
453
454 memcpy(ostart + flSize, src, srcSize);
455 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100456}
457
Yann Colletd1b26842016-03-15 01:24:33 +0100458static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100459{
460 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200461 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100462
Yann Collet198e6aa2016-07-20 20:12:24 +0200463 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100464
465 switch(flSize)
466 {
467 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200468 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100469 break;
470 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200471 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100472 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100473 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100474 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200475 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100476 break;
477 }
478
479 ostart[flSize] = *(const BYTE*)src;
480 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100481}
482
Yann Collet59d1f792016-01-23 19:28:41 +0100483
Yann Colleta5c2c082016-03-20 01:09:18 +0100484static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100485
Yann Colletb923f652016-01-26 03:14:20 +0100486static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100487 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100488 const void* src, size_t srcSize)
489{
Yann Colleta910dc82016-03-18 12:37:45 +0100490 size_t const minGain = ZSTD_minGain(srcSize);
491 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200492 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100493 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200494 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100495 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100496
Yann Collet14983e72015-11-11 21:38:21 +0100497
Yann Colleta5c2c082016-03-20 01:09:18 +0100498 /* small ? don't even attempt compression (speed opt) */
499# define LITERAL_NOENTROPY 63
Nick Terrella4197772017-03-01 17:51:56 -0800500 { size_t const minLitSize = zc->flagStaticHufTable == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
Yann Colleta5c2c082016-03-20 01:09:18 +0100501 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
502 }
503
504 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Nick Terrella4197772017-03-01 17:51:56 -0800505 { HUF_repeat repeat = zc->flagStaticHufTable;
Nick Terrell54c4bab2017-03-03 12:30:24 -0800506 int const preferRepeat = zc->params.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
Nick Terrella4197772017-03-01 17:51:56 -0800507 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
Nick Terrell54c4bab2017-03-03 12:30:24 -0800508 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters), zc->hufTable, &repeat, preferRepeat)
509 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters), zc->hufTable, &repeat, preferRepeat);
Nick Terrella4197772017-03-01 17:51:56 -0800510 if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
511 else { zc->flagStaticHufTable = HUF_repeat_check; } /* now have a table to reuse */
Yann Colletb923f652016-01-26 03:14:20 +0100512 }
Yann Collet14983e72015-11-11 21:38:21 +0100513
Nick Terrella4197772017-03-01 17:51:56 -0800514 if ((cLitSize==0) | (cLitSize >= srcSize - minGain)) {
515 zc->flagStaticHufTable = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100516 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800517 }
518 if (cLitSize==1) {
519 zc->flagStaticHufTable = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100520 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800521 }
Yann Collet14983e72015-11-11 21:38:21 +0100522
523 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100524 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100525 {
Yann Collet59d1f792016-01-23 19:28:41 +0100526 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200527 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200528 MEM_writeLE24(ostart, lhc);
529 break;
530 }
Yann Collet59d1f792016-01-23 19:28:41 +0100531 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200532 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200533 MEM_writeLE32(ostart, lhc);
534 break;
535 }
Yann Colleta910dc82016-03-18 12:37:45 +0100536 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100537 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200538 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200539 MEM_writeLE32(ostart, lhc);
540 ostart[4] = (BYTE)(cLitSize >> 10);
541 break;
542 }
Yann Collet14983e72015-11-11 21:38:21 +0100543 }
Yann Colleta910dc82016-03-18 12:37:45 +0100544 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100545}
546
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200547static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
548 8, 9, 10, 11, 12, 13, 14, 15,
549 16, 16, 17, 17, 18, 18, 19, 19,
550 20, 20, 20, 20, 21, 21, 21, 21,
551 22, 22, 22, 22, 22, 22, 22, 22,
552 23, 23, 23, 23, 23, 23, 23, 23,
553 24, 24, 24, 24, 24, 24, 24, 24,
554 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100555
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200556static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
557 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
558 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
559 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
560 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
561 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
562 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
563 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200564
565
566void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100567{
Yann Colleted57d852016-07-29 21:22:17 +0200568 BYTE const LL_deltaCode = 19;
569 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200570 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200571 BYTE* const llCodeTable = seqStorePtr->llCode;
572 BYTE* const ofCodeTable = seqStorePtr->ofCode;
573 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200574 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200575 U32 u;
576 for (u=0; u<nbSeq; u++) {
577 U32 const llv = sequences[u].litLength;
578 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200579 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200580 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200581 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200582 }
Yann Colleted57d852016-07-29 21:22:17 +0200583 if (seqStorePtr->longLengthID==1)
584 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
585 if (seqStorePtr->longLengthID==2)
586 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100587}
588
Sean Purcell553f67e2017-03-02 15:15:31 -0800589MEM_STATIC size_t ZSTD_compressSequences (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100590 void* dst, size_t dstCapacity,
Sean Purcell553f67e2017-03-02 15:15:31 -0800591 size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100592{
Sean Purcell553f67e2017-03-02 15:15:31 -0800593 const int longOffsets = zc->params.cParams.windowLog > STREAM_ACCUMULATOR_MIN;
Yann Colletb923f652016-01-26 03:14:20 +0100594 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100595 U32 count[MaxSeq+1];
596 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100597 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
598 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
599 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100600 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200601 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200602 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
603 const BYTE* const llCodeTable = seqStorePtr->llCode;
604 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100605 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100606 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100607 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200608 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100609 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -0800610 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +0100611
Yann Collet14983e72015-11-11 21:38:21 +0100612 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100613 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100614 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100615 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100616 if (ZSTD_isError(cSize)) return cSize;
617 op += cSize;
618 }
619
620 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100621 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100622 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
623 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
624 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100625 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100626
Yann Colletbe391432016-03-22 23:19:28 +0100627 /* seqHead : flags for FSE encoding type */
628 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100629
Yann Colletfb810d62016-01-28 00:18:06 +0100630#define MIN_SEQ_FOR_DYNAMIC_FSE 64
631#define MAX_SEQ_FOR_STATIC_FSE 1000
632
Yann Colletb44be742016-03-26 20:52:14 +0100633 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +0200634 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +0100635
Yann Collet14983e72015-11-11 21:38:21 +0100636 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100637 { U32 max = MaxLL;
Yann Collete928f7e2016-12-01 16:13:35 -0800638 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100639 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
640 *op++ = llCodeTable[0];
641 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200642 LLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100643 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200644 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100645 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800646 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200647 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100648 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100649 size_t nbSeq_1 = nbSeq;
650 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
651 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
652 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100653 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -0700654 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +0100655 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800656 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200657 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100658 } }
Yann Collet14983e72015-11-11 21:38:21 +0100659
Yann Colletb44be742016-03-26 20:52:14 +0100660 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100661 { U32 max = MaxOff;
Yann Collete928f7e2016-12-01 16:13:35 -0800662 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100663 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100664 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100665 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200666 Offtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100667 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200668 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +0200669 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800670 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200671 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100672 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100673 size_t nbSeq_1 = nbSeq;
674 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100675 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100676 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100677 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -0700678 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +0100679 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800680 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200681 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100682 } }
683
Yann Collet14983e72015-11-11 21:38:21 +0100684 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100685 { U32 max = MaxML;
Yann Collete928f7e2016-12-01 16:13:35 -0800686 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100687 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100688 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100689 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200690 MLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100691 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200692 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100693 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800694 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200695 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100696 } else {
697 size_t nbSeq_1 = nbSeq;
698 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
699 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
700 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
701 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -0700702 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletfadda6c2016-03-22 12:14:26 +0100703 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800704 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200705 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100706 } }
Yann Collet14983e72015-11-11 21:38:21 +0100707
Yann Colletbe391432016-03-22 23:19:28 +0100708 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100709 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100710
711 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100712 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100713 FSE_CState_t stateMatchLength;
714 FSE_CState_t stateOffsetBits;
715 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100716
Yann Collet95d07d72016-09-06 16:38:51 +0200717 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100718
Yann Collet597847a2016-03-20 19:14:22 +0100719 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100720 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100721 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100722 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +0200723 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100724 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200725 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100726 if (MEM_32bits()) BIT_flushBits(&blockStream);
Sean Purcelld44703d2017-03-01 14:36:25 -0800727 if (longOffsets) {
728 U32 const ofBits = ofCodeTable[nbSeq-1];
729 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
730 if (extraBits) {
731 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
732 BIT_flushBits(&blockStream);
733 }
734 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
735 ofBits - extraBits);
736 } else {
737 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
738 }
Yann Collet597847a2016-03-20 19:14:22 +0100739 BIT_flushBits(&blockStream);
740
Yann Colletfadda6c2016-03-22 12:14:26 +0100741 { size_t n;
742 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +0200743 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200744 BYTE const ofCode = ofCodeTable[n];
745 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200746 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +0200747 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200748 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +0100749 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100750 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
751 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
752 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
753 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200754 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100755 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +0200756 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100757 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200758 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100759 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Sean Purcelld44703d2017-03-01 14:36:25 -0800760 if (longOffsets) {
761 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
762 if (extraBits) {
763 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
764 BIT_flushBits(&blockStream); /* (7)*/
765 }
766 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
767 ofBits - extraBits); /* 31 */
768 } else {
769 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
770 }
Yann Colletb9151402016-03-26 17:18:11 +0100771 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100772 } }
Yann Collet14983e72015-11-11 21:38:21 +0100773
774 FSE_flushCState(&blockStream, &stateMatchLength);
775 FSE_flushCState(&blockStream, &stateOffsetBits);
776 FSE_flushCState(&blockStream, &stateLitLength);
777
Yann Colletb9151402016-03-26 17:18:11 +0100778 { size_t const streamSize = BIT_closeCStream(&blockStream);
779 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
780 op += streamSize;
781 } }
Yann Collet14983e72015-11-11 21:38:21 +0100782
783 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100784_check_compressibility:
Nick Terrella4197772017-03-01 17:51:56 -0800785 { size_t const minGain = ZSTD_minGain(srcSize);
786 size_t const maxCSize = srcSize - minGain;
787 if ((size_t)(op-ostart) >= maxCSize) {
788 zc->flagStaticHufTable = HUF_repeat_none;
789 return 0;
790 } }
Yann Collet14983e72015-11-11 21:38:21 +0100791
Yann Collet4266c0a2016-06-14 01:49:25 +0200792 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -0800793 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +0200794
Yann Collet5054ee02015-11-23 13:34:21 +0100795 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100796}
797
Yann Colletbb002742017-01-25 16:25:38 -0800798#if 0 /* for debug */
799# define STORESEQ_DEBUG
800#include <stdio.h> /* fprintf */
801U32 g_startDebug = 0;
802const BYTE* g_start = NULL;
803#endif
804
Yann Collet95cd0c22016-03-08 18:24:21 +0100805/*! ZSTD_storeSeq() :
806 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
807 `offsetCode` : distance to match, or 0 == repCode.
808 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100809*/
Yann Colletd57dffb2016-07-03 01:48:26 +0200810MEM_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 +0100811{
Yann Colletbb002742017-01-25 16:25:38 -0800812#ifdef STORESEQ_DEBUG
813 if (g_startDebug) {
814 const U32 pos = (U32)((const BYTE*)literals - g_start);
815 if (g_start==NULL) g_start = (const BYTE*)literals;
816 if ((pos > 1895000) && (pos < 1895300))
817 fprintf(stderr, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
818 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
819 }
Yann Collet14983e72015-11-11 21:38:21 +0100820#endif
Yann Collet14983e72015-11-11 21:38:21 +0100821 /* copy Literals */
822 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
823 seqStorePtr->lit += litLength;
824
825 /* literal Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200826 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
827 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100828
829 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200830 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100831
832 /* match Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200833 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
834 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +0200835
Yann Colletc0ce4f12016-07-30 00:55:13 +0200836 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +0100837}
838
839
Yann Collet7d360282016-02-12 00:07:30 +0100840/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100841* Match length counter
842***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100843static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100844{
Yann Collet863ec402016-01-28 17:56:33 +0100845 if (MEM_isLittleEndian()) {
846 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100847# if defined(_MSC_VER) && defined(_WIN64)
848 unsigned long r = 0;
849 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100850 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100851# elif defined(__GNUC__) && (__GNUC__ >= 3)
852 return (__builtin_ctzll((U64)val) >> 3);
853# else
854 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 };
855 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
856# endif
Yann Collet863ec402016-01-28 17:56:33 +0100857 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100858# if defined(_MSC_VER)
859 unsigned long r=0;
860 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100861 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100862# elif defined(__GNUC__) && (__GNUC__ >= 3)
863 return (__builtin_ctz((U32)val) >> 3);
864# else
865 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 };
866 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
867# endif
868 }
Yann Collet863ec402016-01-28 17:56:33 +0100869 } else { /* Big Endian CPU */
870 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100871# if defined(_MSC_VER) && defined(_WIN64)
872 unsigned long r = 0;
873 _BitScanReverse64( &r, val );
874 return (unsigned)(r>>3);
875# elif defined(__GNUC__) && (__GNUC__ >= 3)
876 return (__builtin_clzll(val) >> 3);
877# else
878 unsigned r;
879 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
880 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
881 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
882 r += (!val);
883 return r;
884# endif
Yann Collet863ec402016-01-28 17:56:33 +0100885 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100886# if defined(_MSC_VER)
887 unsigned long r = 0;
888 _BitScanReverse( &r, (unsigned long)val );
889 return (unsigned)(r>>3);
890# elif defined(__GNUC__) && (__GNUC__ >= 3)
891 return (__builtin_clz((U32)val) >> 3);
892# else
893 unsigned r;
894 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
895 r += (!val);
896 return r;
897# endif
Yann Collet863ec402016-01-28 17:56:33 +0100898 } }
Yann Collet14983e72015-11-11 21:38:21 +0100899}
900
901
Yann Colleta436a522016-06-20 23:34:04 +0200902static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100903{
904 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +0200905 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +0100906
Yann Colleta436a522016-06-20 23:34:04 +0200907 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +0200908 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100909 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
910 pIn += ZSTD_NbCommonBytes(diff);
911 return (size_t)(pIn - pStart);
912 }
Yann Collet14983e72015-11-11 21:38:21 +0100913 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
914 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
915 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
916 return (size_t)(pIn - pStart);
917}
918
Yann Collet04b12d82016-02-11 06:23:24 +0100919/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100920* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100921* convention : on reaching mEnd, match count continue starting from iStart
922*/
923static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
924{
Yann Collet7591a7f2016-05-20 11:44:43 +0200925 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +0200926 size_t const matchLength = ZSTD_count(ip, match, vEnd);
927 if (match + matchLength != mEnd) return matchLength;
928 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +0100929}
930
Yann Collet14983e72015-11-11 21:38:21 +0100931
Yann Collet863ec402016-01-28 17:56:33 +0100932/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100933* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100934***************************************/
inikepcc52a972016-02-19 10:09:35 +0100935static const U32 prime3bytes = 506832829U;
936static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Colletd4f4e582016-06-27 01:31:35 +0200937MEM_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 +0100938
Yann Collet4b100f42015-10-30 15:49:48 +0100939static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100940static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100941static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100942
Yann Collet4b100f42015-10-30 15:49:48 +0100943static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100944static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100945static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100946
947static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100948static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100949static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100950
Yann Collet14983e72015-11-11 21:38:21 +0100951static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100952static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100953static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100954
Yann Collet45dc3562016-07-12 09:47:31 +0200955static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
956static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
957static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
958
Yann Collet5be2dd22015-11-11 13:43:58 +0100959static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100960{
961 switch(mls)
962 {
Yann Collet2e2e78d2017-03-29 16:02:47 -0700963 //case 3: return ZSTD_hash3Ptr(p, hBits);
964 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100965 case 4: return ZSTD_hash4Ptr(p, hBits);
966 case 5: return ZSTD_hash5Ptr(p, hBits);
967 case 6: return ZSTD_hash6Ptr(p, hBits);
968 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +0200969 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100970 }
971}
Yann Collet2acb5d32015-10-29 16:49:43 +0100972
Yann Collet863ec402016-01-28 17:56:33 +0100973
Yann Collet2ce49232016-02-02 14:36:49 +0100974/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100975* Fast Scan
976***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100977static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
978{
979 U32* const hashTable = zc->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200980 U32 const hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +0100981 const BYTE* const base = zc->base;
982 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +0200983 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +0100984 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +0100985
Yann Colletfb810d62016-01-28 00:18:06 +0100986 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100987 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +0100988 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +0100989 }
990}
991
992
Yann Collet1f44b3f2015-11-05 17:32:18 +0100993FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +0200994void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +0200995 const void* src, size_t srcSize,
996 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100997{
Yann Collet4266c0a2016-06-14 01:49:25 +0200998 U32* const hashTable = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200999 U32 const hBits = cctx->params.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +02001000 seqStore_t* seqStorePtr = &(cctx->seqStore);
1001 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001002 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001003 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001004 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +02001005 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +02001006 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001007 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001008 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +02001009 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1010 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001011
Yann Collet1f44b3f2015-11-05 17:32:18 +01001012 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001013 ip += (ip==lowest);
1014 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +02001015 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1016 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +02001017 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001018
1019 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001020 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001021 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001022 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1023 U32 const current = (U32)(ip-base);
1024 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001025 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001026 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001027
Yann Collet280f9a82016-08-08 00:44:00 +02001028 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +02001029 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +01001030 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001031 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1032 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001033 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001034 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001035 ip += ((ip-anchor) >> g_searchStrength) + 1;
1036 continue;
1037 }
Yann Collet45dc3562016-07-12 09:47:31 +02001038 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001039 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001040 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001041 offset_2 = offset_1;
1042 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001043
Yann Colleta436a522016-06-20 23:34:04 +02001044 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001045 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001046
Yann Collet402fdcf2015-11-20 12:46:08 +01001047 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001048 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001049 anchor = ip;
1050
Yann Colletfb810d62016-01-28 00:18:06 +01001051 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001052 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001053 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 +01001054 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1055 /* check immediate repcode */
1056 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001057 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001058 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001059 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001060 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001061 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001062 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001063 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1064 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001065 anchor = ip;
1066 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001067 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001068
Yann Collet4266c0a2016-06-14 01:49:25 +02001069 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001070 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1071 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001072
Yann Collet70e45772016-03-19 18:08:32 +01001073 /* Last Literals */
1074 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001075 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1076 seqStorePtr->lit += lastLLSize;
1077 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001078}
1079
1080
Yann Collet82260dd2016-02-11 07:14:25 +01001081static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001082 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001083{
Yann Collet3b719252016-03-30 19:48:05 +02001084 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001085 switch(mls)
1086 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001087 default: /* includes case 3 */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001088 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001089 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001090 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001091 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001092 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001093 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001094 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001095 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001096 }
1097}
Yann Colletf3eca252015-10-22 15:31:46 +01001098
Yann Colletf3eca252015-10-22 15:31:46 +01001099
Yann Collet82260dd2016-02-11 07:14:25 +01001100static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001101 const void* src, size_t srcSize,
1102 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001103{
1104 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001105 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001106 seqStore_t* seqStorePtr = &(ctx->seqStore);
1107 const BYTE* const base = ctx->base;
1108 const BYTE* const dictBase = ctx->dictBase;
1109 const BYTE* const istart = (const BYTE*)src;
1110 const BYTE* ip = istart;
1111 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001112 const U32 lowestIndex = ctx->lowLimit;
1113 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001114 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001115 const BYTE* const lowPrefixPtr = base + dictLimit;
1116 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001117 const BYTE* const iend = istart + srcSize;
1118 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001119 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001120
Yann Colleta436a522016-06-20 23:34:04 +02001121 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001122 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001123 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001124 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001125 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001126 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001127 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001128 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001129 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001130 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001131 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001132 hashTable[h] = current; /* update hash table */
1133
Yann Colleta436a522016-06-20 23:34:04 +02001134 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001135 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001136 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Colleta436a522016-06-20 23:34:04 +02001137 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001138 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001139 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001140 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001141 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001142 (MEM_read32(match) != MEM_read32(ip)) ) {
1143 ip += ((ip-anchor) >> g_searchStrength) + 1;
1144 continue;
1145 }
1146 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001147 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001148 U32 offset;
1149 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1150 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001151 offset = current - matchIndex;
1152 offset_2 = offset_1;
1153 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001154 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001155 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001156
Yann Collet5054ee02015-11-23 13:34:21 +01001157 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001158 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001159 anchor = ip;
1160
Yann Colletfb810d62016-01-28 00:18:06 +01001161 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001162 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001163 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001164 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1165 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001166 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001167 U32 const current2 = (U32)(ip-base);
1168 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001169 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001170 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1171 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001172 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001173 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001174 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001175 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001176 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001177 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001178 anchor = ip;
1179 continue;
1180 }
Yann Collet743402c2015-11-20 12:03:53 +01001181 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001182 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001183
Yann Collet4266c0a2016-06-14 01:49:25 +02001184 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001185 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001186
Yann Collet89db5e02015-11-13 11:27:46 +01001187 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001188 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001189 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1190 seqStorePtr->lit += lastLLSize;
1191 }
Yann Collet89db5e02015-11-13 11:27:46 +01001192}
1193
1194
Yann Collet82260dd2016-02-11 07:14:25 +01001195static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001196 const void* src, size_t srcSize)
1197{
Yann Collet731ef162016-07-27 21:05:12 +02001198 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001199 switch(mls)
1200 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001201 default: /* includes case 3 */
Yann Collet89db5e02015-11-13 11:27:46 +01001202 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001203 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001204 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001205 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001206 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001207 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001208 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001209 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001210 }
1211}
1212
1213
Yann Collet04b12d82016-02-11 06:23:24 +01001214/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001215* Double Fast
1216***************************************/
1217static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1218{
1219 U32* const hashLarge = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001220 U32 const hBitsL = cctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001221 U32* const hashSmall = cctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001222 U32 const hBitsS = cctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001223 const BYTE* const base = cctx->base;
1224 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001225 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001226 const size_t fastHashFillStep = 3;
1227
1228 while(ip <= iend) {
1229 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1230 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1231 ip += fastHashFillStep;
1232 }
1233}
1234
1235
1236FORCE_INLINE
1237void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1238 const void* src, size_t srcSize,
1239 const U32 mls)
1240{
1241 U32* const hashLong = cctx->hashTable;
1242 const U32 hBitsL = cctx->params.cParams.hashLog;
1243 U32* const hashSmall = cctx->chainTable;
1244 const U32 hBitsS = cctx->params.cParams.chainLog;
1245 seqStore_t* seqStorePtr = &(cctx->seqStore);
1246 const BYTE* const base = cctx->base;
1247 const BYTE* const istart = (const BYTE*)src;
1248 const BYTE* ip = istart;
1249 const BYTE* anchor = istart;
1250 const U32 lowestIndex = cctx->dictLimit;
1251 const BYTE* const lowest = base + lowestIndex;
1252 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001253 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001254 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1255 U32 offsetSaved = 0;
1256
1257 /* init */
1258 ip += (ip==lowest);
1259 { U32 const maxRep = (U32)(ip-lowest);
1260 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1261 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1262 }
1263
1264 /* Main Search Loop */
1265 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1266 size_t mLength;
1267 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1268 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1269 U32 const current = (U32)(ip-base);
1270 U32 const matchIndexL = hashLong[h2];
1271 U32 const matchIndexS = hashSmall[h];
1272 const BYTE* matchLong = base + matchIndexL;
1273 const BYTE* match = base + matchIndexS;
1274 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1275
1276 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1277 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1278 ip++;
1279 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1280 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001281 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001282 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1283 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001284 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001285 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1286 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Colletc54692f2016-08-24 01:10:42 +02001287 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1288 U32 const matchIndex3 = hashLong[h3];
1289 const BYTE* match3 = base + matchIndex3;
1290 hashLong[h3] = current + 1;
1291 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1292 mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
1293 ip++;
1294 offset = (U32)(ip-match3);
1295 while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1296 } else {
1297 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1298 offset = (U32)(ip-match);
1299 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1300 }
Yann Collet45dc3562016-07-12 09:47:31 +02001301 } else {
1302 ip += ((ip-anchor) >> g_searchStrength) + 1;
1303 continue;
1304 }
1305
1306 offset_2 = offset_1;
1307 offset_1 = offset;
1308
1309 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1310 }
1311
1312 /* match found */
1313 ip += mLength;
1314 anchor = ip;
1315
1316 if (ip <= ilimit) {
1317 /* Fill Table */
1318 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1319 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1320 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1321 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1322
1323 /* check immediate repcode */
1324 while ( (ip <= ilimit)
1325 && ( (offset_2>0)
1326 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1327 /* store sequence */
1328 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001329 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001330 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1331 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1332 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1333 ip += rLength;
1334 anchor = ip;
1335 continue; /* faster when present ... (?) */
1336 } } }
1337
1338 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001339 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1340 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001341
1342 /* Last Literals */
1343 { size_t const lastLLSize = iend - anchor;
1344 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1345 seqStorePtr->lit += lastLLSize;
1346 }
1347}
1348
1349
1350static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1351{
1352 const U32 mls = ctx->params.cParams.searchLength;
1353 switch(mls)
1354 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001355 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001356 case 4 :
1357 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1358 case 5 :
1359 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1360 case 6 :
1361 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1362 case 7 :
1363 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1364 }
1365}
1366
1367
1368static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1369 const void* src, size_t srcSize,
1370 const U32 mls)
1371{
1372 U32* const hashLong = ctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001373 U32 const hBitsL = ctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001374 U32* const hashSmall = ctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001375 U32 const hBitsS = ctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001376 seqStore_t* seqStorePtr = &(ctx->seqStore);
1377 const BYTE* const base = ctx->base;
1378 const BYTE* const dictBase = ctx->dictBase;
1379 const BYTE* const istart = (const BYTE*)src;
1380 const BYTE* ip = istart;
1381 const BYTE* anchor = istart;
1382 const U32 lowestIndex = ctx->lowLimit;
1383 const BYTE* const dictStart = dictBase + lowestIndex;
1384 const U32 dictLimit = ctx->dictLimit;
1385 const BYTE* const lowPrefixPtr = base + dictLimit;
1386 const BYTE* const dictEnd = dictBase + dictLimit;
1387 const BYTE* const iend = istart + srcSize;
1388 const BYTE* const ilimit = iend - 8;
1389 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1390
1391 /* Search Loop */
1392 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1393 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1394 const U32 matchIndex = hashSmall[hSmall];
1395 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1396 const BYTE* match = matchBase + matchIndex;
1397
1398 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1399 const U32 matchLongIndex = hashLong[hLong];
1400 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1401 const BYTE* matchLong = matchLongBase + matchLongIndex;
1402
1403 const U32 current = (U32)(ip-base);
1404 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1405 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1406 const BYTE* repMatch = repBase + repIndex;
1407 size_t mLength;
1408 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1409
1410 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1411 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1412 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1413 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1414 ip++;
1415 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1416 } else {
1417 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1418 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1419 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1420 U32 offset;
1421 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1422 offset = current - matchLongIndex;
1423 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1424 offset_2 = offset_1;
1425 offset_1 = offset;
1426 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001427
Yann Collet73d74a02016-07-12 13:03:48 +02001428 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001429 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1430 U32 const matchIndex3 = hashLong[h3];
1431 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1432 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001433 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001434 hashLong[h3] = current + 1;
1435 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1436 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1437 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1438 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1439 ip++;
1440 offset = current+1 - matchIndex3;
1441 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1442 } else {
1443 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1444 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1445 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1446 offset = current - matchIndex;
1447 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1448 }
Yann Collet45dc3562016-07-12 09:47:31 +02001449 offset_2 = offset_1;
1450 offset_1 = offset;
1451 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001452
Yann Collet45dc3562016-07-12 09:47:31 +02001453 } else {
1454 ip += ((ip-anchor) >> g_searchStrength) + 1;
1455 continue;
1456 } }
1457
1458 /* found a match : store it */
1459 ip += mLength;
1460 anchor = ip;
1461
1462 if (ip <= ilimit) {
1463 /* Fill Table */
1464 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1465 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1466 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1467 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1468 /* check immediate repcode */
1469 while (ip <= ilimit) {
1470 U32 const current2 = (U32)(ip-base);
1471 U32 const repIndex2 = current2 - offset_2;
1472 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1473 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1474 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1475 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1476 size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1477 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1478 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1479 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1480 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1481 ip += repLength2;
1482 anchor = ip;
1483 continue;
1484 }
1485 break;
1486 } } }
1487
1488 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001489 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001490
1491 /* Last Literals */
1492 { size_t const lastLLSize = iend - anchor;
1493 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1494 seqStorePtr->lit += lastLLSize;
1495 }
1496}
1497
1498
1499static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1500 const void* src, size_t srcSize)
1501{
Yann Collet731ef162016-07-27 21:05:12 +02001502 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001503 switch(mls)
1504 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001505 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001506 case 4 :
1507 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1508 case 5 :
1509 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1510 case 6 :
1511 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1512 case 7 :
1513 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1514 }
1515}
1516
1517
1518/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001519* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001520***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001521/** ZSTD_insertBt1() : add one or multiple positions to tree.
1522* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001523* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001524static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1525 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001526{
Yann Collet731ef162016-07-27 21:05:12 +02001527 U32* const hashTable = zc->hashTable;
1528 U32 const hashLog = zc->params.cParams.hashLog;
1529 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1530 U32* const bt = zc->chainTable;
1531 U32 const btLog = zc->params.cParams.chainLog - 1;
1532 U32 const btMask = (1 << btLog) - 1;
1533 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001534 size_t commonLengthSmaller=0, commonLengthLarger=0;
1535 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001536 const BYTE* const dictBase = zc->dictBase;
1537 const U32 dictLimit = zc->dictLimit;
1538 const BYTE* const dictEnd = dictBase + dictLimit;
1539 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001540 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001541 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001542 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001543 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001544 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001545 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001546 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001547 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001548 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001549#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001550 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1551 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1552 predictedSmall += (predictedSmall>0);
1553 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001554#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001555
Yann Collet6c3e2e72015-12-11 10:44:07 +01001556 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001557
Yann Colletfb810d62016-01-28 00:18:06 +01001558 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001559 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001560 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001561
Yann Colletc0932082016-06-30 14:07:30 +02001562#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001563 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001564 if (matchIndex == predictedSmall) {
1565 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001566 *smallerPtr = matchIndex;
1567 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1568 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1569 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001570 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001571 continue;
1572 }
Yann Colletfb810d62016-01-28 00:18:06 +01001573 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001574 *largerPtr = matchIndex;
1575 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1576 largerPtr = nextPtr;
1577 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001578 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001579 continue;
1580 }
Yann Collet04b12d82016-02-11 06:23:24 +01001581#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001582 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001583 match = base + matchIndex;
1584 if (match[matchLength] == ip[matchLength])
1585 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001586 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001587 match = dictBase + matchIndex;
1588 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1589 if (matchIndex+matchLength >= dictLimit)
1590 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1591 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001592
Yann Colletb8a6f682016-02-15 17:06:29 +01001593 if (matchLength > bestLength) {
1594 bestLength = matchLength;
1595 if (matchLength > matchEndIdx - matchIndex)
1596 matchEndIdx = matchIndex + (U32)matchLength;
1597 }
Yann Colletee3f4512015-12-29 22:26:09 +01001598
Yann Collet59d70632015-11-04 12:05:27 +01001599 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001600 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001601
Yann Colletfb810d62016-01-28 00:18:06 +01001602 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001603 /* match is smaller than current */
1604 *smallerPtr = matchIndex; /* update smaller idx */
1605 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001606 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001607 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001608 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001609 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001610 /* match is larger than current */
1611 *largerPtr = matchIndex;
1612 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001613 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001614 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001615 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001616 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001617
Yann Collet59d70632015-11-04 12:05:27 +01001618 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001619 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001620 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1621 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001622}
1623
1624
Yann Collet82260dd2016-02-11 07:14:25 +01001625static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001626 ZSTD_CCtx* zc,
1627 const BYTE* const ip, const BYTE* const iend,
1628 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001629 U32 nbCompares, const U32 mls,
1630 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001631{
Yann Collet731ef162016-07-27 21:05:12 +02001632 U32* const hashTable = zc->hashTable;
1633 U32 const hashLog = zc->params.cParams.hashLog;
1634 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1635 U32* const bt = zc->chainTable;
1636 U32 const btLog = zc->params.cParams.chainLog - 1;
1637 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001638 U32 matchIndex = hashTable[h];
1639 size_t commonLengthSmaller=0, commonLengthLarger=0;
1640 const BYTE* const base = zc->base;
1641 const BYTE* const dictBase = zc->dictBase;
1642 const U32 dictLimit = zc->dictLimit;
1643 const BYTE* const dictEnd = dictBase + dictLimit;
1644 const BYTE* const prefixStart = base + dictLimit;
1645 const U32 current = (U32)(ip-base);
1646 const U32 btLow = btMask >= current ? 0 : current - btMask;
1647 const U32 windowLow = zc->lowLimit;
1648 U32* smallerPtr = bt + 2*(current&btMask);
1649 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001650 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001651 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001652 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001653
Yann Collet6c3e2e72015-12-11 10:44:07 +01001654 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001655
Yann Colletfb810d62016-01-28 00:18:06 +01001656 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001657 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01001658 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1659 const BYTE* match;
1660
Yann Colletfb810d62016-01-28 00:18:06 +01001661 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001662 match = base + matchIndex;
1663 if (match[matchLength] == ip[matchLength])
1664 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001665 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001666 match = dictBase + matchIndex;
1667 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001668 if (matchIndex+matchLength >= dictLimit)
1669 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001670 }
1671
Yann Colletfb810d62016-01-28 00:18:06 +01001672 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001673 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001674 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001675 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001676 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001677 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1678 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1679 }
1680
Yann Colletfb810d62016-01-28 00:18:06 +01001681 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001682 /* match is smaller than current */
1683 *smallerPtr = matchIndex; /* update smaller idx */
1684 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1685 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1686 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1687 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001688 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001689 /* match is larger than current */
1690 *largerPtr = matchIndex;
1691 commonLengthLarger = matchLength;
1692 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1693 largerPtr = nextPtr;
1694 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001695 } }
Yann Collet03526e12015-11-23 15:29:15 +01001696
1697 *smallerPtr = *largerPtr = 0;
1698
Yann Collet72e84cf2015-12-31 19:08:44 +01001699 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001700 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001701}
1702
Yann Collet2cc12cb2016-01-01 07:47:58 +01001703
Yann Colletb8a6f682016-02-15 17:06:29 +01001704static 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 +01001705{
1706 const BYTE* const base = zc->base;
1707 const U32 target = (U32)(ip - base);
1708 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001709
1710 while(idx < target)
1711 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001712}
1713
Yann Collet52447382016-03-20 16:00:00 +01001714/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001715static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001716 ZSTD_CCtx* zc,
1717 const BYTE* const ip, const BYTE* const iLimit,
1718 size_t* offsetPtr,
1719 const U32 maxNbAttempts, const U32 mls)
1720{
1721 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001722 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001723 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1724}
1725
1726
Yann Collet768c6bc2016-02-10 14:01:49 +01001727static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001728 ZSTD_CCtx* zc, /* Index table will be updated */
1729 const BYTE* ip, const BYTE* const iLimit,
1730 size_t* offsetPtr,
1731 const U32 maxNbAttempts, const U32 matchLengthSearch)
1732{
1733 switch(matchLengthSearch)
1734 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001735 default : /* includes case 3 */
Yann Collet2cc12cb2016-01-01 07:47:58 +01001736 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1737 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07001738 case 7 :
Yann Collet2cc12cb2016-01-01 07:47:58 +01001739 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1740 }
1741}
1742
1743
Yann Colletb8a6f682016-02-15 17:06:29 +01001744static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1745{
1746 const BYTE* const base = zc->base;
1747 const U32 target = (U32)(ip - base);
1748 U32 idx = zc->nextToUpdate;
1749
1750 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1751}
1752
inikep64d7bcb2016-04-07 19:14:09 +02001753
Yann Collet03526e12015-11-23 15:29:15 +01001754/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001755static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001756 ZSTD_CCtx* zc,
1757 const BYTE* const ip, const BYTE* const iLimit,
1758 size_t* offsetPtr,
1759 const U32 maxNbAttempts, const U32 mls)
1760{
Yann Colletee3f4512015-12-29 22:26:09 +01001761 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001762 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001763 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001764}
1765
1766
Yann Collet82260dd2016-02-11 07:14:25 +01001767static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001768 ZSTD_CCtx* zc, /* Index table will be updated */
1769 const BYTE* ip, const BYTE* const iLimit,
1770 size_t* offsetPtr,
1771 const U32 maxNbAttempts, const U32 matchLengthSearch)
1772{
1773 switch(matchLengthSearch)
1774 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001775 default : /* includes case 3 */
Yann Collet03526e12015-11-23 15:29:15 +01001776 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1777 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07001778 case 7 :
Yann Collet03526e12015-11-23 15:29:15 +01001779 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1780 }
1781}
1782
1783
Yann Collet5106a762015-11-05 15:00:24 +01001784
Yann Collet731ef162016-07-27 21:05:12 +02001785/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02001786* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02001787***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02001788#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1789
1790/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08001791 Assumption : always within prefix (i.e. not within extDict) */
inikep64d7bcb2016-04-07 19:14:09 +02001792FORCE_INLINE
1793U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1794{
1795 U32* const hashTable = zc->hashTable;
1796 const U32 hashLog = zc->params.cParams.hashLog;
1797 U32* const chainTable = zc->chainTable;
1798 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1799 const BYTE* const base = zc->base;
1800 const U32 target = (U32)(ip - base);
1801 U32 idx = zc->nextToUpdate;
1802
Yann Collet22d76322016-06-21 08:01:51 +02001803 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001804 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1805 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1806 hashTable[h] = idx;
1807 idx++;
1808 }
1809
1810 zc->nextToUpdate = target;
1811 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1812}
1813
1814
1815
1816FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1817size_t ZSTD_HcFindBestMatch_generic (
1818 ZSTD_CCtx* zc, /* Index table will be updated */
1819 const BYTE* const ip, const BYTE* const iLimit,
1820 size_t* offsetPtr,
1821 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1822{
1823 U32* const chainTable = zc->chainTable;
1824 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1825 const U32 chainMask = chainSize-1;
1826 const BYTE* const base = zc->base;
1827 const BYTE* const dictBase = zc->dictBase;
1828 const U32 dictLimit = zc->dictLimit;
1829 const BYTE* const prefixStart = base + dictLimit;
1830 const BYTE* const dictEnd = dictBase + dictLimit;
1831 const U32 lowLimit = zc->lowLimit;
1832 const U32 current = (U32)(ip-base);
1833 const U32 minChain = current > chainSize ? current - chainSize : 0;
1834 int nbAttempts=maxNbAttempts;
1835 size_t ml=EQUAL_READ32-1;
1836
1837 /* HC4 match finder */
1838 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1839
Yann Collet22d76322016-06-21 08:01:51 +02001840 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001841 const BYTE* match;
1842 size_t currentMl=0;
1843 if ((!extDict) || matchIndex >= dictLimit) {
1844 match = base + matchIndex;
1845 if (match[ml] == ip[ml]) /* potentially better */
1846 currentMl = ZSTD_count(ip, match, iLimit);
1847 } else {
1848 match = dictBase + matchIndex;
1849 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1850 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1851 }
1852
1853 /* save best solution */
Yann Collet22d76322016-06-21 08:01:51 +02001854 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 +02001855
1856 if (matchIndex <= minChain) break;
1857 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1858 }
1859
1860 return ml;
1861}
1862
1863
1864FORCE_INLINE size_t ZSTD_HcFindBestMatch_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 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001872 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02001873 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1874 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
Yann Collet933ce4a2017-03-29 14:32:15 -07001875 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02001876 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1877 }
1878}
1879
1880
1881FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1882 ZSTD_CCtx* zc,
1883 const BYTE* ip, const BYTE* const iLimit,
1884 size_t* offsetPtr,
1885 const U32 maxNbAttempts, const U32 matchLengthSearch)
1886{
1887 switch(matchLengthSearch)
1888 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001889 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02001890 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1891 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
Yann Collet933ce4a2017-03-29 14:32:15 -07001892 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02001893 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1894 }
1895}
1896
inikep64d7bcb2016-04-07 19:14:09 +02001897
Yann Collet287b7d92015-11-22 13:24:05 +01001898/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001899* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001900*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001901FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001902void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1903 const void* src, size_t srcSize,
1904 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001905{
inikepfaa8d8a2016-04-05 19:01:10 +02001906 seqStore_t* seqStorePtr = &(ctx->seqStore);
1907 const BYTE* const istart = (const BYTE*)src;
1908 const BYTE* ip = istart;
1909 const BYTE* anchor = istart;
1910 const BYTE* const iend = istart + srcSize;
1911 const BYTE* const ilimit = iend - 8;
1912 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001913
Yann Collet793c6492016-04-09 20:32:00 +02001914 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1915 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001916
inikep64d7bcb2016-04-07 19:14:09 +02001917 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1918 size_t* offsetPtr,
1919 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02001920 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02001921 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02001922
inikepfaa8d8a2016-04-05 19:01:10 +02001923 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001924 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02001925 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02001926 { U32 const maxRep = (U32)(ip-base);
1927 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1928 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1929 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001930
inikepfaa8d8a2016-04-05 19:01:10 +02001931 /* Match Loop */
1932 while (ip < ilimit) {
1933 size_t matchLength=0;
1934 size_t offset=0;
1935 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001936
inikepfaa8d8a2016-04-05 19:01:10 +02001937 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02001938 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02001939 /* repcode : we take it */
Yann Collet9634f672016-07-03 01:23:58 +02001940 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001941 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001942 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001943
inikepfaa8d8a2016-04-05 19:01:10 +02001944 /* first search (depth 0) */
1945 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001946 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001947 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001948 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001949 }
Yann Collet5106a762015-11-05 15:00:24 +01001950
inikep7bc19b62016-04-06 09:46:01 +02001951 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001952 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1953 continue;
1954 }
1955
inikep64d7bcb2016-04-07 19:14:09 +02001956 /* let's try to find a better solution */
1957 if (depth>=1)
1958 while (ip<ilimit) {
1959 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001960 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1961 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001962 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001963 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001964 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1965 matchLength = mlRep, offset = 0, start = ip;
1966 }
1967 { size_t offset2=99999999;
1968 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001969 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1970 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001971 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1972 matchLength = ml2, offset = offset2, start = ip;
1973 continue; /* search a better one */
1974 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001975
inikep64d7bcb2016-04-07 19:14:09 +02001976 /* let's find an even better one */
1977 if ((depth==2) && (ip<ilimit)) {
1978 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001979 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1980 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001981 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001982 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001983 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1984 matchLength = ml2, offset = 0, start = ip;
1985 }
1986 { size_t offset2=99999999;
1987 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001988 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1989 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001990 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1991 matchLength = ml2, offset = offset2, start = ip;
1992 continue;
1993 } } }
1994 break; /* nothing found : store previous solution */
1995 }
1996
1997 /* catch up */
1998 if (offset) {
1999 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
2000 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02002001 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02002002 }
2003
inikepfaa8d8a2016-04-05 19:01:10 +02002004 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002005_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002006 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002007 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002008 anchor = ip = start + matchLength;
2009 }
Yann Collet48537162016-04-07 15:24:29 +02002010
inikepfaa8d8a2016-04-05 19:01:10 +02002011 /* check immediate repcode */
2012 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02002013 && ((offset_2>0)
2014 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02002015 /* store sequence */
Yann Collet9634f672016-07-03 01:23:58 +02002016 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
2017 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02002018 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2019 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002020 anchor = ip;
2021 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002022 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002023
Yann Collet4266c0a2016-06-14 01:49:25 +02002024 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002025 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2026 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002027
inikepfaa8d8a2016-04-05 19:01:10 +02002028 /* Last Literals */
2029 { size_t const lastLLSize = iend - anchor;
2030 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2031 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002032 }
Yann Collet5106a762015-11-05 15:00:24 +01002033}
2034
Yann Collet5be2dd22015-11-11 13:43:58 +01002035
inikep64d7bcb2016-04-07 19:14:09 +02002036static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2037{
2038 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2039}
2040
2041static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2042{
2043 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2044}
2045
2046static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2047{
2048 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2049}
2050
2051static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2052{
2053 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2054}
2055
2056
inikepfaa8d8a2016-04-05 19:01:10 +02002057FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002058void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2059 const void* src, size_t srcSize,
2060 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002061{
inikepfaa8d8a2016-04-05 19:01:10 +02002062 seqStore_t* seqStorePtr = &(ctx->seqStore);
2063 const BYTE* const istart = (const BYTE*)src;
2064 const BYTE* ip = istart;
2065 const BYTE* anchor = istart;
2066 const BYTE* const iend = istart + srcSize;
2067 const BYTE* const ilimit = iend - 8;
2068 const BYTE* const base = ctx->base;
2069 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002070 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002071 const BYTE* const prefixStart = base + dictLimit;
2072 const BYTE* const dictBase = ctx->dictBase;
2073 const BYTE* const dictEnd = dictBase + dictLimit;
2074 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2075
2076 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2077 const U32 mls = ctx->params.cParams.searchLength;
2078
inikep64d7bcb2016-04-07 19:14:09 +02002079 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2080 size_t* offsetPtr,
2081 U32 maxNbAttempts, U32 matchLengthSearch);
2082 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2083
Yann Collet302ff032016-07-03 01:28:16 +02002084 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002085
Yann Collet302ff032016-07-03 01:28:16 +02002086 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002087 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002088 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002089
2090 /* Match Loop */
2091 while (ip < ilimit) {
2092 size_t matchLength=0;
2093 size_t offset=0;
2094 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002095 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002096
2097 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002098 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002099 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2100 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002101 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002102 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002103 /* repcode detected we should take it */
2104 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02002105 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2106 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002107 } }
2108
2109 /* first search (depth 0) */
2110 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002111 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002112 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002113 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002114 }
2115
inikep7bc19b62016-04-06 09:46:01 +02002116 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02002117 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2118 continue;
2119 }
2120
inikep64d7bcb2016-04-07 19:14:09 +02002121 /* let's try to find a better solution */
2122 if (depth>=1)
2123 while (ip<ilimit) {
2124 ip ++;
2125 current++;
2126 /* check repCode */
2127 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002128 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002129 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2130 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002131 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002132 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2133 /* repcode detected */
2134 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2135 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2136 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002137 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002138 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2139 matchLength = repLength, offset = 0, start = ip;
2140 } }
2141
2142 /* search match, depth 1 */
2143 { size_t offset2=99999999;
2144 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002145 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2146 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02002147 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2148 matchLength = ml2, offset = offset2, start = ip;
2149 continue; /* search a better one */
2150 } }
2151
2152 /* let's find an even better one */
2153 if ((depth==2) && (ip<ilimit)) {
2154 ip ++;
2155 current++;
2156 /* check repCode */
2157 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002158 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002159 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2160 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002161 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002162 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2163 /* repcode detected */
2164 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2165 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2166 int gain2 = (int)(repLength * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002167 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002168 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2169 matchLength = repLength, offset = 0, start = ip;
2170 } }
2171
2172 /* search match, depth 2 */
2173 { size_t offset2=99999999;
2174 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002175 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2176 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02002177 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2178 matchLength = ml2, offset = offset2, start = ip;
2179 continue;
2180 } } }
2181 break; /* nothing found : store previous solution */
2182 }
2183
inikepfaa8d8a2016-04-05 19:01:10 +02002184 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002185 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002186 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002187 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2188 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002189 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002190 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002191 }
inikepfaa8d8a2016-04-05 19:01:10 +02002192
inikepfaa8d8a2016-04-05 19:01:10 +02002193 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002194_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002195 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002196 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002197 anchor = ip = start + matchLength;
2198 }
2199
2200 /* check immediate repcode */
2201 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002202 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002203 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2204 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002205 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002206 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2207 /* repcode detected we should take it */
2208 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02002209 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
Yann Collet302ff032016-07-03 01:28:16 +02002210 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002211 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2212 ip += matchLength;
2213 anchor = ip;
2214 continue; /* faster when present ... (?) */
2215 }
2216 break;
2217 } }
2218
Yann Collet4266c0a2016-06-14 01:49:25 +02002219 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002220 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002221
inikepfaa8d8a2016-04-05 19:01:10 +02002222 /* Last Literals */
2223 { size_t const lastLLSize = iend - anchor;
2224 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2225 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002226 }
2227}
2228
2229
Yann Collet59d1f792016-01-23 19:28:41 +01002230void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002231{
inikep64d7bcb2016-04-07 19:14:09 +02002232 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002233}
2234
Yann Collet59d1f792016-01-23 19:28:41 +01002235static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002236{
Yann Colleta1249dc2016-01-25 04:22:03 +01002237 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002238}
Yann Collet9a24e592015-11-22 02:53:43 +01002239
Yann Collet59d1f792016-01-23 19:28:41 +01002240static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002241{
Yann Colleta1249dc2016-01-25 04:22:03 +01002242 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002243}
2244
Yann Collet59d1f792016-01-23 19:28:41 +01002245static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002246{
Yann Colleta1249dc2016-01-25 04:22:03 +01002247 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002248}
2249
inikepef519412016-04-21 11:08:43 +02002250
inikepef519412016-04-21 11:08:43 +02002251/* The optimal parser */
2252#include "zstd_opt.h"
2253
2254static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2255{
Yann Colletd4f4e582016-06-27 01:31:35 +02002256#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002257 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2258#else
2259 (void)ctx; (void)src; (void)srcSize;
2260 return;
2261#endif
2262}
2263
2264static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2265{
2266#ifdef ZSTD_OPT_H_91842398743
2267 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002268#else
2269 (void)ctx; (void)src; (void)srcSize;
2270 return;
2271#endif
inikepef519412016-04-21 11:08:43 +02002272}
2273
inikepd3b8d7a2016-02-22 10:06:17 +01002274static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002275{
Yann Colletd4f4e582016-06-27 01:31:35 +02002276#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002277 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2278#else
2279 (void)ctx; (void)src; (void)srcSize;
2280 return;
2281#endif
2282}
2283
2284static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2285{
2286#ifdef ZSTD_OPT_H_91842398743
2287 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002288#else
2289 (void)ctx; (void)src; (void)srcSize;
2290 return;
2291#endif
inikepe2bfe242016-01-31 11:25:48 +01002292}
2293
Yann Collet7a231792015-11-21 15:27:35 +01002294
Yann Collet59d1f792016-01-23 19:28:41 +01002295typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002296
Yann Colletb923f652016-01-26 03:14:20 +01002297static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002298{
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002299 static const ZSTD_blockCompressor blockCompressor[2][8] = {
2300 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 },
2301 { 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 +01002302 };
2303
2304 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002305}
2306
2307
Yann Colletd1b26842016-03-15 01:24:33 +01002308static 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 +01002309{
Yann Collet19cab462016-06-17 12:54:52 +02002310 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002311 const BYTE* const base = zc->base;
2312 const BYTE* const istart = (const BYTE*)src;
2313 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002314 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 +02002315 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002316 if (current > zc->nextToUpdate + 384)
2317 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 +01002318 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002319 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002320}
2321
2322
Yann Colletc991cc12016-07-28 00:55:43 +02002323/*! ZSTD_compress_generic() :
2324* Compress a chunk of data into one or multiple blocks.
2325* All blocks will be terminated, all input will be consumed.
2326* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2327* Frame is supposed already started (header already produced)
2328* @return : compressed size, or an error code
2329*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002330static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2331 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002332 const void* src, size_t srcSize,
2333 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002334{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002335 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002336 size_t remaining = srcSize;
2337 const BYTE* ip = (const BYTE*)src;
2338 BYTE* const ostart = (BYTE*)dst;
2339 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002340 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002341
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002342 if (cctx->params.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002343 XXH64_update(&cctx->xxhState, src, srcSize);
2344
Yann Collet2ce49232016-02-02 14:36:49 +01002345 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002346 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002347 size_t cSize;
2348
inikepfb5df612016-05-24 15:36:37 +02002349 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 +01002350 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002351
Yann Collet346efcc2016-08-02 14:26:00 +02002352 /* preemptive overflow correction */
Sean Purcell881abe42017-03-07 16:52:23 -08002353 if (cctx->lowLimit > (3U<<29)) {
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002354 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002355 U32 const current = (U32)(ip - cctx->base);
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002356 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002357 U32 const correction = current - newCurrent;
2358 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002359 ZSTD_reduceIndex(cctx, correction);
2360 cctx->base += correction;
2361 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002362 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002363 cctx->dictLimit -= correction;
2364 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2365 else cctx->nextToUpdate -= correction;
2366 }
2367
Yann Collet06e76972017-01-25 16:39:03 -08002368 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002369 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002370 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2371 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2372 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002373 }
Yann Collet89db5e02015-11-13 11:27:46 +01002374
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002375 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002376 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002377
Yann Collet2ce49232016-02-02 14:36:49 +01002378 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002379 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2380 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2381 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2382 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2383 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002384 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002385 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002386 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002387 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002388 }
2389
2390 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002391 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002392 ip += blockSize;
2393 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002394 }
2395
Yann Collet62470b42016-07-28 15:29:08 +02002396 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002397 return op-ostart;
2398}
2399
2400
Yann Collet6236eba2016-04-12 15:52:33 +02002401static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002402 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002403{ BYTE* const op = (BYTE*)dst;
Yann Collet731ef162016-07-27 21:05:12 +02002404 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2405 U32 const checksumFlag = params.fParams.checksumFlag>0;
2406 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002407 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002408 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2409 U32 const fcsCode = params.fParams.contentSizeFlag ?
Yann Collet673f0d72016-06-06 00:26:38 +02002410 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2411 0;
Yann Collet731ef162016-07-27 21:05:12 +02002412 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002413 size_t pos;
2414
2415 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002416
2417 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002418 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002419 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002420 switch(dictIDSizeCode)
2421 {
2422 default: /* impossible */
2423 case 0 : break;
2424 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002425 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002426 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2427 }
Yann Collet673f0d72016-06-06 00:26:38 +02002428 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002429 {
2430 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002431 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002432 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2433 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002434 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002435 }
Yann Colletc46fb922016-05-29 05:01:04 +02002436 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002437}
2438
2439
Yann Collet346efcc2016-08-02 14:26:00 +02002440static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002441 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002442 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002443 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002444{
Yann Collet2acb5d32015-10-29 16:49:43 +01002445 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002446 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002447
Yann Collet346efcc2016-08-02 14:26:00 +02002448 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002449
Yann Collet346efcc2016-08-02 14:26:00 +02002450 if (frame && (cctx->stage==ZSTDcs_init)) {
2451 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002452 if (ZSTD_isError(fhSize)) return fhSize;
2453 dstCapacity -= fhSize;
2454 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002455 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002456 }
Yann Colletf3eca252015-10-22 15:31:46 +01002457
Yann Collet417890c2015-12-04 17:16:37 +01002458 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002459 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002460 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002461 ptrdiff_t const delta = cctx->nextSrc - ip;
2462 cctx->lowLimit = cctx->dictLimit;
2463 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2464 cctx->dictBase = cctx->base;
2465 cctx->base -= delta;
2466 cctx->nextToUpdate = cctx->dictLimit;
2467 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002468 }
2469
Yann Collet346efcc2016-08-02 14:26:00 +02002470 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2471 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2472 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2473 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2474 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002475 }
2476
Yann Collet346efcc2016-08-02 14:26:00 +02002477 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002478
Yann Collet5eb749e2017-01-11 18:21:25 +01002479 if (srcSize) {
2480 size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002481 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2482 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002483 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002484 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002485 } else
2486 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002487}
2488
Yann Colletbf42c8e2016-01-09 01:08:23 +01002489
Yann Collet5b567392016-07-28 01:17:22 +02002490size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002491 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002492 const void* src, size_t srcSize)
2493{
Yann Collet5b567392016-07-28 01:17:22 +02002494 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
2495}
2496
2497
Yann Colletcf05b9d2016-07-18 16:52:10 +02002498size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002499{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002500 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2501}
2502
2503size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2504{
2505 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002506 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Colletc991cc12016-07-28 00:55:43 +02002507 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002508}
2509
Yann Collet16a0b102017-03-24 12:46:46 -07002510/*! ZSTD_loadDictionaryContent() :
2511 * @return : 0, or an error code
2512 */
Yann Colletb923f652016-01-26 03:14:20 +01002513static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002514{
2515 const BYTE* const ip = (const BYTE*) src;
2516 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002517
Yann Collet417890c2015-12-04 17:16:37 +01002518 /* input becomes current prefix */
2519 zc->lowLimit = zc->dictLimit;
2520 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2521 zc->dictBase = zc->base;
2522 zc->base += ip - zc->nextSrc;
2523 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002524 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002525
2526 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002527 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002528
Yann Collet3b719252016-03-30 19:48:05 +02002529 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002530 {
2531 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002532 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002533 break;
2534
Yann Collet45dc3562016-07-12 09:47:31 +02002535 case ZSTD_dfast:
2536 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2537 break;
2538
Yann Collet417890c2015-12-04 17:16:37 +01002539 case ZSTD_greedy:
2540 case ZSTD_lazy:
2541 case ZSTD_lazy2:
Yann Collet16a0b102017-03-24 12:46:46 -07002542 if (srcSize >= HASH_READ_SIZE)
2543 ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002544 break;
2545
2546 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002547 case ZSTD_btopt:
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002548 case ZSTD_btopt2:
Yann Collet16a0b102017-03-24 12:46:46 -07002549 if (srcSize >= HASH_READ_SIZE)
2550 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002551 break;
2552
2553 default:
2554 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2555 }
2556
Nick Terrellecf90ca2017-02-13 18:27:34 -08002557 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002558 return 0;
2559}
2560
2561
Nick Terrellf9c9af32016-10-19 17:22:08 -07002562/* Dictionaries that assign zero probability to symbols that show up causes problems
2563 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2564 that we may encounter during compression.
2565 NOTE: This behavior is not standard and could be improved in the future. */
2566static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2567 U32 s;
2568 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2569 for (s = 0; s <= maxSymbolValue; ++s) {
2570 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2571 }
2572 return 0;
2573}
2574
2575
Yann Colletb923f652016-01-26 03:14:20 +01002576/* Dictionary format :
Yann Colletbea78e82017-03-22 18:09:11 -07002577 * See :
2578 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
2579 */
Yann Collet16a0b102017-03-24 12:46:46 -07002580/*! ZSTD_loadZstdDictionary() :
2581 * @return : 0, or an error code
2582 * assumptions : magic number supposed already checked
2583 * dictSize supposed > 8
Yann Colletbea78e82017-03-22 18:09:11 -07002584 */
Yann Collet16a0b102017-03-24 12:46:46 -07002585static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002586{
Yann Collet52a06222016-06-15 13:53:34 +02002587 const BYTE* dictPtr = (const BYTE*)dict;
2588 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07002589 short offcodeNCount[MaxOff+1];
2590 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08002591 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01002592
Yann Colletbea78e82017-03-22 18:09:11 -07002593 dictPtr += 4; /* skip magic number */
2594 cctx->dictID = cctx->params.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
2595 dictPtr += 4;
2596
2597 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002598 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002599 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002600 }
Yann Colletfb810d62016-01-28 00:18:06 +01002601
Nick Terrellf9c9af32016-10-19 17:22:08 -07002602 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02002603 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002604 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002605 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002606 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Collet643d9a22016-12-01 16:24:04 -08002607 CHECK_E (FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002608 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002609 }
Yann Colletfb810d62016-01-28 00:18:06 +01002610
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002611 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002612 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002613 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002614 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002615 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002616 /* Every match length code must have non-zero probability */
2617 CHECK_F (ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
Yann Collet643d9a22016-12-01 16:24:04 -08002618 CHECK_E (FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002619 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002620 }
Yann Colletfb810d62016-01-28 00:18:06 +01002621
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002622 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002623 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002624 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002625 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002626 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002627 /* Every literal length code must have non-zero probability */
2628 CHECK_F (ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
Yann Collet643d9a22016-12-01 16:24:04 -08002629 CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002630 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002631 }
Yann Colletfb810d62016-01-28 00:18:06 +01002632
Yann Collet52a06222016-06-15 13:53:34 +02002633 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07002634 cctx->rep[0] = MEM_readLE32(dictPtr+0);
2635 cctx->rep[1] = MEM_readLE32(dictPtr+4);
2636 cctx->rep[2] = MEM_readLE32(dictPtr+8);
Yann Collet52a06222016-06-15 13:53:34 +02002637 dictPtr += 12;
2638
Yann Colletbea78e82017-03-22 18:09:11 -07002639 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
2640 U32 offcodeMax = MaxOff;
2641 if (dictContentSize <= ((U32)-1) - 128 KB) {
2642 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
2643 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
Nick Terrellb2c39a22016-10-24 14:11:27 -07002644 }
Yann Colletbea78e82017-03-22 18:09:11 -07002645 /* All offset values <= dictContentSize + 128 KB must be representable */
Nick Terrellf9c9af32016-10-19 17:22:08 -07002646 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
Yann Colletbea78e82017-03-22 18:09:11 -07002647 /* All repCodes must be <= dictContentSize and != 0*/
2648 { U32 u;
2649 for (u=0; u<3; u++) {
2650 if (cctx->rep[u] == 0) return ERROR(dictionary_corrupted);
2651 if (cctx->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07002652 } }
Nick Terrellf9c9af32016-10-19 17:22:08 -07002653
Yann Collet16a0b102017-03-24 12:46:46 -07002654 cctx->flagStaticTables = 1;
2655 cctx->flagStaticHufTable = HUF_repeat_valid;
2656 return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
2657 }
Yann Colletb923f652016-01-26 03:14:20 +01002658}
2659
Yann Colletd1b26842016-03-15 01:24:33 +01002660/** ZSTD_compress_insertDictionary() :
2661* @return : 0, or an error code */
Yann Collet16a0b102017-03-24 12:46:46 -07002662static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002663{
Yann Colletc46fb922016-05-29 05:01:04 +02002664 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002665
Yann Collet14312d82017-02-23 23:42:12 -08002666 /* dict as pure content */
Yann Collet16a0b102017-03-24 12:46:46 -07002667 if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict))
2668 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002669
Yann Colletbea78e82017-03-22 18:09:11 -07002670 /* dict as zstd dictionary */
Yann Collet16a0b102017-03-24 12:46:46 -07002671 return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002672}
2673
Yann Collet27caf2a2016-04-01 15:48:48 +02002674/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002675* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002676static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002677 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002678 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002679{
Yann Colleta7737f62016-09-06 09:44:59 +02002680 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
Yann Collet3e21ec52016-09-06 15:36:19 +02002681 CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp));
Yann Colleta7737f62016-09-06 09:44:59 +02002682 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002683}
2684
2685
Yann Collet27caf2a2016-04-01 15:48:48 +02002686/*! ZSTD_compressBegin_advanced() :
2687* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002688size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002689 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002690 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002691{
2692 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02002693 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet81e13ef2016-06-07 00:51:51 +02002694 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002695}
2696
2697
Yann Collet81e13ef2016-06-07 00:51:51 +02002698size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002699{
Yann Collet6c6e1752016-06-27 15:28:45 +02002700 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002701 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002702}
Yann Collet083fcc82015-10-25 14:06:35 +01002703
inikep19bd48f2016-04-04 12:10:00 +02002704
Yann Colletb05c4822017-01-12 02:01:28 +01002705size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002706{
Yann Colletb05c4822017-01-12 02:01:28 +01002707 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002708}
2709
2710
Yann Collet62470b42016-07-28 15:29:08 +02002711/*! ZSTD_writeEpilogue() :
2712* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002713* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002714static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002715{
Yann Colletc991cc12016-07-28 00:55:43 +02002716 BYTE* const ostart = (BYTE*)dst;
2717 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002718 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002719
Yann Collet87c18b22016-08-26 01:43:47 +02002720 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002721
2722 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002723 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002724 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002725 if (ZSTD_isError(fhSize)) return fhSize;
2726 dstCapacity -= fhSize;
2727 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002728 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002729 }
2730
Yann Colletc991cc12016-07-28 00:55:43 +02002731 if (cctx->stage != ZSTDcs_ending) {
2732 /* write one last empty block, make it the "last" block */
2733 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2734 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2735 MEM_writeLE32(op, cBlockHeader24);
2736 op += ZSTD_blockHeaderSize;
2737 dstCapacity -= ZSTD_blockHeaderSize;
2738 }
2739
2740 if (cctx->params.fParams.checksumFlag) {
2741 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2742 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2743 MEM_writeLE32(op, checksum);
2744 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002745 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002746
Yann Collet731ef162016-07-27 21:05:12 +02002747 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002748 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002749}
2750
Yann Colletfd416f12016-01-30 03:14:15 +01002751
Yann Collet62470b42016-07-28 15:29:08 +02002752size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2753 void* dst, size_t dstCapacity,
2754 const void* src, size_t srcSize)
2755{
2756 size_t endResult;
2757 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
2758 if (ZSTD_isError(cSize)) return cSize;
2759 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2760 if (ZSTD_isError(endResult)) return endResult;
2761 return cSize + endResult;
2762}
2763
2764
Yann Collet19c10022016-07-28 01:25:46 +02002765static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002766 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002767 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002768 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002769 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002770{
Yann Collet3e21ec52016-09-06 15:36:19 +02002771 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
Yann Collet62470b42016-07-28 15:29:08 +02002772 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002773}
2774
Yann Collet21588e32016-03-30 16:50:44 +02002775size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2776 void* dst, size_t dstCapacity,
2777 const void* src, size_t srcSize,
2778 const void* dict,size_t dictSize,
2779 ZSTD_parameters params)
2780{
Yann Colletcf409a72016-09-26 16:41:05 +02002781 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02002782 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2783}
2784
Yann Colletd1b26842016-03-15 01:24:33 +01002785size_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 +01002786{
Yann Collet407a11f2016-11-03 15:52:01 -07002787 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02002788 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002789 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002790}
2791
Yann Colletd1b26842016-03-15 01:24:33 +01002792size_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 +01002793{
Yann Collet21588e32016-03-30 16:50:44 +02002794 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002795}
2796
Yann Colletd1b26842016-03-15 01:24:33 +01002797size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002798{
Yann Collet44fe9912015-10-29 22:02:40 +01002799 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002800 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002801 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002802 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002803 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002804 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 +01002805 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002806}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002807
Yann Colletfd416f12016-01-30 03:14:15 +01002808
Yann Collet81e13ef2016-06-07 00:51:51 +02002809/* ===== Dictionary API ===== */
2810
2811struct ZSTD_CDict_s {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002812 void* dictBuffer;
2813 const void* dictContent;
Yann Collet81e13ef2016-06-07 00:51:51 +02002814 size_t dictContentSize;
2815 ZSTD_CCtx* refContext;
David Lamda9d3b72016-08-29 09:03:12 -07002816}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
Yann Collet81e13ef2016-06-07 00:51:51 +02002817
Yann Colletd7c65892016-09-15 02:50:27 +02002818size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2819{
2820 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01002821 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02002822}
2823
Yann Collet1f57c2e2016-12-21 16:20:11 +01002824ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
2825 ZSTD_parameters params, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02002826{
Yann Collet23b6e052016-08-28 21:05:43 -07002827 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2828 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02002829
Yann Collet23b6e052016-08-28 21:05:43 -07002830 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002831 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2832
Yann Collet1f57c2e2016-12-21 16:20:11 +01002833 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07002834 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002835 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002836 return NULL;
2837 }
2838
Yann Collet1f57c2e2016-12-21 16:20:11 +01002839 if ((byReference) || (!dictBuffer) || (!dictSize)) {
2840 cdict->dictBuffer = NULL;
2841 cdict->dictContent = dictBuffer;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002842 } else {
2843 void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
Yann Collet4e5eea62016-12-21 16:44:35 +01002844 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002845 memcpy(internalBuffer, dictBuffer, dictSize);
2846 cdict->dictBuffer = internalBuffer;
2847 cdict->dictContent = internalBuffer;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002848 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002849
2850 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
Yann Collet81e13ef2016-06-07 00:51:51 +02002851 if (ZSTD_isError(errorCode)) {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002852 ZSTD_free(cdict->dictBuffer, customMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01002853 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002854 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002855 return NULL;
2856 } }
2857
Yann Collet81e13ef2016-06-07 00:51:51 +02002858 cdict->refContext = cctx;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002859 cdict->dictContentSize = dictSize;
Yann Collet81e13ef2016-06-07 00:51:51 +02002860 return cdict;
2861 }
2862}
2863
2864ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2865{
2866 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet07639052016-08-03 01:57:57 +02002867 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002868 params.fParams.contentSizeFlag = 1;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002869 return ZSTD_createCDict_advanced(dict, dictSize, 0, params, allocator);
2870}
2871
2872ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
2873{
2874 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2875 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
2876 params.fParams.contentSizeFlag = 1;
2877 return ZSTD_createCDict_advanced(dict, dictSize, 1, params, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02002878}
2879
2880size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2881{
Yann Collet23b6e052016-08-28 21:05:43 -07002882 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02002883 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07002884 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01002885 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002886 ZSTD_free(cdict, cMem);
2887 return 0;
2888 }
Yann Collet81e13ef2016-06-07 00:51:51 +02002889}
2890
Yann Collet95162342016-10-25 16:19:52 -07002891static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
2892 return ZSTD_getParamsFromCCtx(cdict->refContext);
2893}
2894
Yann Colletc5933482017-01-22 16:40:06 -08002895size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002896{
Yann Collet97b378a2016-09-21 17:20:19 +02002897 if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
Sean Purcell2db72492017-02-09 10:50:43 -08002898 else {
2899 ZSTD_parameters params = cdict->refContext->params;
2900 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
2901 CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, params, pledgedSrcSize));
2902 }
Yann Collet4cb21292016-09-15 14:54:07 +02002903 return 0;
2904}
2905
Yann Collet07639052016-08-03 01:57:57 +02002906/*! ZSTD_compress_usingCDict() :
2907* Compression using a digested Dictionary.
2908* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2909* Note that compression level is decided during dictionary creation */
Yann Collet4cb21292016-09-15 14:54:07 +02002910size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2911 void* dst, size_t dstCapacity,
2912 const void* src, size_t srcSize,
2913 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02002914{
Yann Collet4cb21292016-09-15 14:54:07 +02002915 CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize));
Yann Collet07639052016-08-03 01:57:57 +02002916
2917 if (cdict->refContext->params.fParams.contentSizeFlag==1) {
2918 cctx->params.fParams.contentSizeFlag = 1;
2919 cctx->frameContentSize = srcSize;
2920 }
2921
2922 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002923}
2924
2925
2926
Yann Collet104e5b02016-08-12 13:04:27 +02002927/* ******************************************************************
2928* Streaming
2929********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002930
2931typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
2932
2933struct ZSTD_CStream_s {
Yann Colletfa0c0972016-09-15 14:11:01 +02002934 ZSTD_CCtx* cctx;
Yann Collet95162342016-10-25 16:19:52 -07002935 ZSTD_CDict* cdictLocal;
2936 const ZSTD_CDict* cdict;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002937 char* inBuff;
2938 size_t inBuffSize;
2939 size_t inToCompress;
2940 size_t inBuffPos;
2941 size_t inBuffTarget;
2942 size_t blockSize;
2943 char* outBuff;
2944 size_t outBuffSize;
2945 size_t outBuffContentSize;
2946 size_t outBuffFlushedSize;
2947 ZSTD_cStreamStage stage;
2948 U32 checksum;
2949 U32 frameEnded;
Yann Collete795c8a2016-12-13 16:39:36 +01002950 U64 pledgedSrcSize;
2951 U64 inputProcessed;
Yann Colletee5b7252016-10-27 14:20:55 -07002952 ZSTD_parameters params;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002953 ZSTD_customMem customMem;
2954}; /* typedef'd to ZSTD_CStream within "zstd.h" */
2955
2956ZSTD_CStream* ZSTD_createCStream(void)
2957{
2958 return ZSTD_createCStream_advanced(defaultCustomMem);
2959}
2960
2961ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
2962{
2963 ZSTD_CStream* zcs;
2964
Yann Collet23b6e052016-08-28 21:05:43 -07002965 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2966 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002967
Yann Collet23b6e052016-08-28 21:05:43 -07002968 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002969 if (zcs==NULL) return NULL;
2970 memset(zcs, 0, sizeof(ZSTD_CStream));
2971 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
Yann Colletfa0c0972016-09-15 14:11:01 +02002972 zcs->cctx = ZSTD_createCCtx_advanced(customMem);
2973 if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002974 return zcs;
2975}
2976
2977size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2978{
2979 if (zcs==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -07002980 { ZSTD_customMem const cMem = zcs->customMem;
Yann Colletfa0c0972016-09-15 14:11:01 +02002981 ZSTD_freeCCtx(zcs->cctx);
Nick Terrelleaf69b02017-03-21 13:20:59 -07002982 zcs->cctx = NULL;
Yann Collet95162342016-10-25 16:19:52 -07002983 ZSTD_freeCDict(zcs->cdictLocal);
Nick Terrelleaf69b02017-03-21 13:20:59 -07002984 zcs->cdictLocal = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -07002985 ZSTD_free(zcs->inBuff, cMem);
Nick Terrelleaf69b02017-03-21 13:20:59 -07002986 zcs->inBuff = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -07002987 ZSTD_free(zcs->outBuff, cMem);
Nick Terrelleaf69b02017-03-21 13:20:59 -07002988 zcs->outBuff = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -07002989 ZSTD_free(zcs, cMem);
2990 return 0;
2991 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002992}
2993
2994
Yann Collet104e5b02016-08-12 13:04:27 +02002995/*====== Initialization ======*/
2996
2997size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
2998size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002999
Sean Purcell2db72492017-02-09 10:50:43 -08003000static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003001{
Yann Colletd564faa2016-12-18 21:39:15 +01003002 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 -07003003
3004 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
3005 else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
Yann Collet4cb21292016-09-15 14:54:07 +02003006
3007 zcs->inToCompress = 0;
3008 zcs->inBuffPos = 0;
3009 zcs->inBuffTarget = zcs->blockSize;
3010 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3011 zcs->stage = zcss_load;
3012 zcs->frameEnded = 0;
Yann Collete795c8a2016-12-13 16:39:36 +01003013 zcs->pledgedSrcSize = pledgedSrcSize;
3014 zcs->inputProcessed = 0;
Yann Collet4cb21292016-09-15 14:54:07 +02003015 return 0; /* ready to go */
3016}
3017
Sean Purcell2db72492017-02-09 10:50:43 -08003018size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
3019{
3020
3021 zcs->params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
3022
3023 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
3024}
3025
Yann Collet5a0c8e22016-08-12 01:20:36 +02003026size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3027 const void* dict, size_t dictSize,
3028 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3029{
3030 /* allocate buffers */
3031 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
3032 if (zcs->inBuffSize < neededInBuffSize) {
3033 zcs->inBuffSize = neededInBuffSize;
Yann Colletcf409a72016-09-26 16:41:05 +02003034 ZSTD_free(zcs->inBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003035 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003036 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
3037 }
3038 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
3039 }
3040 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
3041 zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
Yann Colletcf409a72016-09-26 16:41:05 +02003042 ZSTD_free(zcs->outBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003043 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003044 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
3045 }
3046
Sean Purcell57d423c2017-01-17 11:04:08 -08003047 if (dict && dictSize >= 8) {
Yann Colletee5b7252016-10-27 14:20:55 -07003048 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003049 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0, params, zcs->customMem);
Yann Colletee5b7252016-10-27 14:20:55 -07003050 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3051 zcs->cdict = zcs->cdictLocal;
3052 } else zcs->cdict = NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003053
Yann Collet5a0c8e22016-08-12 01:20:36 +02003054 zcs->checksum = params.fParams.checksumFlag > 0;
Yann Colletee5b7252016-10-27 14:20:55 -07003055 zcs->params = params;
Yann Collet4cb21292016-09-15 14:54:07 +02003056
Sean Purcell2db72492017-02-09 10:50:43 -08003057 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003058}
3059
Yann Collet95162342016-10-25 16:19:52 -07003060/* note : cdict must outlive compression session */
3061size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3062{
3063 ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
3064 size_t const initError = ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0);
3065 zcs->cdict = cdict;
Gregory Szorc7d6f4782017-01-14 17:44:54 -08003066 zcs->cctx->dictID = params.fParams.noDictIDFlag ? 0 : cdict->refContext->dictID;
Yann Collet95162342016-10-25 16:19:52 -07003067 return initError;
3068}
3069
Yann Collet5a0c8e22016-08-12 01:20:36 +02003070size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3071{
3072 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
3073 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);
3074}
3075
Yann Collete795c8a2016-12-13 16:39:36 +01003076size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3077{
Yann Colletd564faa2016-12-18 21:39:15 +01003078 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
3079 if (pledgedSrcSize) params.fParams.contentSizeFlag = 1;
Yann Collete795c8a2016-12-13 16:39:36 +01003080 return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);
3081}
3082
Yann Collet5a0c8e22016-08-12 01:20:36 +02003083size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3084{
3085 return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel);
3086}
3087
Yann Collet70e3b312016-08-23 01:18:06 +02003088size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02003089{
Yann Colletd7c65892016-09-15 02:50:27 +02003090 if (zcs==NULL) return 0; /* support sizeof on NULL */
Nick Terrelle06c3032017-03-08 13:45:10 -08003091 return sizeof(*zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize;
Yann Colletcb327632016-08-23 00:30:31 +02003092}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003093
Yann Collet104e5b02016-08-12 13:04:27 +02003094/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003095
3096typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
3097
3098MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3099{
3100 size_t const length = MIN(dstCapacity, srcSize);
3101 memcpy(dst, src, length);
3102 return length;
3103}
3104
3105static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3106 void* dst, size_t* dstCapacityPtr,
3107 const void* src, size_t* srcSizePtr,
3108 ZSTD_flush_e const flush)
3109{
3110 U32 someMoreWork = 1;
3111 const char* const istart = (const char*)src;
3112 const char* const iend = istart + *srcSizePtr;
3113 const char* ip = istart;
3114 char* const ostart = (char*)dst;
3115 char* const oend = ostart + *dstCapacityPtr;
3116 char* op = ostart;
3117
3118 while (someMoreWork) {
3119 switch(zcs->stage)
3120 {
3121 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
3122
3123 case zcss_load:
3124 /* complete inBuffer */
3125 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3126 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
3127 zcs->inBuffPos += loaded;
3128 ip += loaded;
3129 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
3130 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
3131 } }
3132 /* compress current block (note : this stage cannot be stopped in the middle) */
3133 { void* cDst;
3134 size_t cSize;
3135 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3136 size_t oSize = oend-op;
3137 if (oSize >= ZSTD_compressBound(iSize))
3138 cDst = op; /* compress directly into output buffer (avoid flush stage) */
3139 else
3140 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3141 cSize = (flush == zsf_end) ?
Yann Colletfa0c0972016-09-15 14:11:01 +02003142 ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
3143 ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003144 if (ZSTD_isError(cSize)) return cSize;
3145 if (flush == zsf_end) zcs->frameEnded = 1;
3146 /* prepare next block */
3147 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3148 if (zcs->inBuffTarget > zcs->inBuffSize)
3149 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
3150 zcs->inToCompress = zcs->inBuffPos;
3151 if (cDst == op) { op += cSize; break; } /* no need to flush */
3152 zcs->outBuffContentSize = cSize;
3153 zcs->outBuffFlushedSize = 0;
3154 zcs->stage = zcss_flush; /* pass-through to flush stage */
3155 }
3156
3157 case zcss_flush:
3158 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3159 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3160 op += flushed;
3161 zcs->outBuffFlushedSize += flushed;
3162 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
3163 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3164 zcs->stage = zcss_load;
3165 break;
3166 }
3167
3168 case zcss_final:
3169 someMoreWork = 0; /* do nothing */
3170 break;
3171
3172 default:
3173 return ERROR(GENERIC); /* impossible */
3174 }
3175 }
3176
3177 *srcSizePtr = ip - istart;
3178 *dstCapacityPtr = op - ostart;
Yann Collete795c8a2016-12-13 16:39:36 +01003179 zcs->inputProcessed += *srcSizePtr;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003180 if (zcs->frameEnded) return 0;
3181 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3182 if (hintInSize==0) hintInSize = zcs->blockSize;
3183 return hintInSize;
3184 }
3185}
3186
Yann Collet53e17fb2016-08-17 01:39:22 +02003187size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003188{
Yann Collet53e17fb2016-08-17 01:39:22 +02003189 size_t sizeRead = input->size - input->pos;
3190 size_t sizeWritten = output->size - output->pos;
3191 size_t const result = ZSTD_compressStream_generic(zcs,
3192 (char*)(output->dst) + output->pos, &sizeWritten,
3193 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3194 input->pos += sizeRead;
3195 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003196 return result;
3197}
3198
3199
Yann Collet104e5b02016-08-12 13:04:27 +02003200/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003201
3202/*! ZSTD_flushStream() :
3203* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003204size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003205{
3206 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003207 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02003208 size_t const result = ZSTD_compressStream_generic(zcs,
Yann Collet95d07d72016-09-06 16:38:51 +02003209 (char*)(output->dst) + output->pos, &sizeWritten,
3210 &srcSize, &srcSize, /* use a valid src address instead of NULL */
Yann Colletc4119022016-08-17 01:50:54 +02003211 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003212 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003213 if (ZSTD_isError(result)) return result;
3214 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3215}
3216
3217
Yann Collet53e17fb2016-08-17 01:39:22 +02003218size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003219{
Yann Collet53e17fb2016-08-17 01:39:22 +02003220 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3221 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003222 BYTE* op = ostart;
3223
Yann Collete795c8a2016-12-13 16:39:36 +01003224 if ((zcs->pledgedSrcSize) && (zcs->inputProcessed != zcs->pledgedSrcSize))
3225 return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */
3226
Yann Collet5a0c8e22016-08-12 01:20:36 +02003227 if (zcs->stage != zcss_final) {
3228 /* flush whatever remains */
3229 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003230 size_t sizeWritten = output->size - output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003231 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
3232 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3233 op += sizeWritten;
3234 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003235 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003236 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3237 }
3238 /* create epilogue */
3239 zcs->stage = zcss_final;
3240 zcs->outBuffContentSize = !notEnded ? 0 :
Yann Colletfa0c0972016-09-15 14:11:01 +02003241 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 +02003242 }
3243
3244 /* flush epilogue */
3245 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3246 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3247 op += flushed;
3248 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003249 output->pos += op-ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003250 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3251 return toFlush - flushed;
3252 }
3253}
3254
3255
3256
Yann Collet70e8c382016-02-10 13:37:52 +01003257/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003258
Yann Collet236d94f2016-05-18 12:06:33 +02003259#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003260#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003261int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003262
Yann Collet3b719252016-03-30 19:48:05 +02003263static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003264{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003265 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003266 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003267 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3268 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003269 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3270 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003271 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3272 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3273 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003274 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003275 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3276 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3277 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3278 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3279 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3280 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3281 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3282 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003283 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
3284 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
3285 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003286 { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */
3287 { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */
3288 { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003289},
3290{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003291 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003292 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003293 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003294 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3295 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3296 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3297 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3298 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3299 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3300 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3301 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3302 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3303 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3304 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3305 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003306 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003307 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3308 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3309 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003310 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3311 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003312 { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/
3313 { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/
3314 { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003315},
3316{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003317 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003318 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3319 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3320 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3321 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3322 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3323 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3324 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3325 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3326 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3327 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3328 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3329 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3330 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3331 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003332 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3333 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3334 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3335 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3336 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3337 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003338 { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/
3339 { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/
3340 { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003341},
3342{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003343 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003344 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003345 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003346 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3347 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3348 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3349 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3350 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3351 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3352 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3353 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003354 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3355 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3356 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3357 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3358 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3359 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3360 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3361 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3362 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3363 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003364 { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/
3365 { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/
3366 { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003367},
3368};
3369
Yann Collet236d94f2016-05-18 12:06:33 +02003370/*! ZSTD_getCParams() :
3371* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3372* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003373ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003374{
Yann Collet15354142016-04-04 04:22:53 +02003375 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003376 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003377 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003378 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003379 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003380 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003381 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003382 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3383 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003384 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003385 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3386 }
Yann Collet70d13012016-06-01 18:45:34 +02003387 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003388 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003389}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003390
3391/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003392* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003393* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003394ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003395 ZSTD_parameters params;
3396 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3397 memset(&params, 0, sizeof(params));
3398 params.cParams = cParams;
3399 return params;
3400}