blob: 538cb685cdd5077b384c30b84673331f3f9fa9ca [file] [log] [blame]
Yann Collet4ded9e52016-08-30 10:04:33 -07001/**
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
Yann Colletf3eca252015-10-22 15:31:46 +01009
Yann Colletf3eca252015-10-22 15:31:46 +010010
Yann Collet7d360282016-02-12 00:07:30 +010011/*-*************************************
Yann Colletae7aa062016-02-03 02:46:46 +010012* Dependencies
Yann Colletf3eca252015-10-22 15:31:46 +010013***************************************/
Yann Colletd3b7f8d2016-06-04 19:47:02 +020014#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010015#include "mem.h"
Yann Colletf2a3b6e2016-05-31 18:13:56 +020016#define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
Yann Collet7ae67bb2016-09-06 06:28:05 +020017#include "xxhash.h" /* XXH_reset, update, digest */
Yann Collet5a0c8e22016-08-12 01:20:36 +020018#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
Yann Colletd0e2cd12016-06-05 00:58:01 +020019#include "fse.h"
Yann Collet130fe112016-06-05 00:42:28 +020020#define HUF_STATIC_LINKING_ONLY
21#include "huf.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020022#include "zstd_internal.h" /* includes zstd.h */
Yann Colletf3eca252015-10-22 15:31:46 +010023
24
Yann Collet7d360282016-02-12 00:07:30 +010025/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010026* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010027***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010028static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Collet731ef162016-07-27 21:05:12 +020029#define HASH_READ_SIZE 8
30typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010031
Yann Colletf3eca252015-10-22 15:31:46 +010032
Yann Collet7d360282016-02-12 00:07:30 +010033/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010034* Helper functions
35***************************************/
Yann Colletc261f712016-12-12 00:25:07 +010036#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }
Yann Collet59d1f792016-01-23 19:28:41 +010037size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
38
39
Yann Collet7d360282016-02-12 00:07:30 +010040/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010041* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010042***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010043static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
44{
Yann Collet14983e72015-11-11 21:38:21 +010045 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020046 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020047 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010048}
49
50
Yann Collet7d360282016-02-12 00:07:30 +010051/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010052* Context memory management
53***************************************/
Yann Colletaca113f2016-12-23 22:25:03 +010054struct ZSTD_CCtx_s {
Yann Collet89db5e02015-11-13 11:27:46 +010055 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010056 const BYTE* base; /* All regular indexes relative to this position */
57 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010058 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010059 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010060 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010061 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +010062 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Colletbb002742017-01-25 16:25:38 -080063 U32 loadedDictEnd; /* index of end of dictionary */
64 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
Yann Collet14312d82017-02-23 23:42:12 -080065 U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */
Yann Collet731ef162016-07-27 21:05:12 +020066 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +020067 U32 rep[ZSTD_REP_NUM];
Yann Colletb459aad2017-01-19 17:33:37 -080068 U32 repToConfirm[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +020069 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +010070 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +010071 void* workSpace;
72 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +010073 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +020074 U64 frameContentSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +020075 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +020076 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +010077
Yann Collet712def92015-10-29 18:41:45 +010078 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +010079 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +010080 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +020081 U32* chainTable;
Yann Colletb923f652016-01-26 03:14:20 +010082 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +010083 U32 flagStaticTables;
Nick Terrella4197772017-03-01 17:51:56 -080084 HUF_repeat flagStaticHufTable;
Yann Collet731ef162016-07-27 21:05:12 +020085 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
86 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
87 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Collete928f7e2016-12-01 16:13:35 -080088 unsigned tmpCounters[1024];
Yann Colletf3eca252015-10-22 15:31:46 +010089};
90
Yann Collet5be2dd22015-11-11 13:43:58 +010091ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +010092{
inikep3763c772016-06-03 13:28:20 +020093 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +020094}
95
96ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
97{
Yann Collet69c2cdb2016-07-14 16:52:45 +020098 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +020099
Yann Collet23b6e052016-08-28 21:05:43 -0700100 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
101 if (!customMem.customAlloc || !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200102
Yann Collet23b6e052016-08-28 21:05:43 -0700103 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200104 if (!cctx) return NULL;
105 memset(cctx, 0, sizeof(ZSTD_CCtx));
Yann Colletbb002742017-01-25 16:25:38 -0800106 cctx->customMem = customMem;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200107 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100108}
109
Yann Collet5be2dd22015-11-11 13:43:58 +0100110size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100111{
inikep36403962016-06-03 16:36:50 +0200112 if (cctx==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -0700113 ZSTD_free(cctx->workSpace, cctx->customMem);
114 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100115 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100116}
117
Yann Collet70e3b312016-08-23 01:18:06 +0200118size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200119{
Yann Colletd7c65892016-09-15 02:50:27 +0200120 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet3ae543c2016-07-11 03:12:17 +0200121 return sizeof(*cctx) + cctx->workSpaceSize;
122}
123
Yann Colletbb002742017-01-25 16:25:38 -0800124size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
125{
126 switch(param)
127 {
Yann Collet06e76972017-01-25 16:39:03 -0800128 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet14312d82017-02-23 23:42:12 -0800129 case ZSTD_p_forceRawDict : cctx->forceRawDict = value>0; return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800130 default: return ERROR(parameter_unknown);
131 }
132}
133
Yann Colletb44be742016-03-26 20:52:14 +0100134const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100135{
Yann Colletb44be742016-03-26 20:52:14 +0100136 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100137}
138
Yann Collet95162342016-10-25 16:19:52 -0700139static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx)
140{
141 return cctx->params;
142}
143
Yann Collet59d70632015-11-04 12:05:27 +0100144
Yann Collet21588e32016-03-30 16:50:44 +0200145/** ZSTD_checkParams() :
146 ensure param values remain within authorized range.
147 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200148size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200149{
Yann Colletac8bace2016-09-07 14:54:23 +0200150# define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
Yann Collet15354142016-04-04 04:22:53 +0200151 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200152 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200153 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
154 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Colletedbcd9f2016-09-06 14:30:57 +0200155 { U32 const searchLengthMin = ((cParams.strategy == ZSTD_fast) | (cParams.strategy == ZSTD_greedy)) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN;
Yann Collet3b719252016-03-30 19:48:05 +0200156 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
157 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
158 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200159 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200160 return 0;
161}
162
163
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100164/** ZSTD_cycleLog() :
165 * condition for correct operation : hashLog > 1 */
166static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
167{
168 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
169 return hashLog - btScale;
170}
171
Yann Collet70d13012016-06-01 18:45:34 +0200172/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200173 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200174 mostly downsizing to reduce memory consumption and initialization.
175 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
176 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200177 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200178ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100179{
Yann Collet70d13012016-06-01 18:45:34 +0200180 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100181
Yann Collet70e45772016-03-19 18:08:32 +0100182 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200183 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
184 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200185 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200186 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200187 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200188 } }
Yann Collet70d13012016-06-01 18:45:34 +0200189 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100190 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
191 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
192 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100193
Yann Collet70d13012016-06-01 18:45:34 +0200194 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200195
196 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100197}
198
199
Yann Collet88472382016-07-14 17:05:38 +0200200size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100201{
Yann Collet731ef162016-07-27 21:05:12 +0200202 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
203 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
204 size_t const maxNbSeq = blockSize / divider;
205 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200206
Yann Collet731ef162016-07-27 21:05:12 +0200207 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
208 size_t const hSize = ((size_t)1) << cParams.hashLog;
209 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
210 size_t const h3Size = ((size_t)1) << hashLog3;
211 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200212
213 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
214 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
215 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200216 + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Collet3ae543c2016-07-11 03:12:17 +0200217
218 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100219}
220
Yann Colleta7737f62016-09-06 09:44:59 +0200221
222static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
223{
224 return (param1.cParams.hashLog == param2.cParams.hashLog)
225 & (param1.cParams.chainLog == param2.cParams.chainLog)
Yann Colletedbcd9f2016-09-06 14:30:57 +0200226 & (param1.cParams.strategy == param2.cParams.strategy)
227 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3));
Yann Colleta7737f62016-09-06 09:44:59 +0200228}
229
230/*! ZSTD_continueCCtx() :
231 reuse CCtx without reset (note : requires no dictionary) */
232static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
233{
234 U32 const end = (U32)(cctx->nextSrc - cctx->base);
235 cctx->params = params;
236 cctx->frameContentSize = frameContentSize;
237 cctx->lowLimit = end;
238 cctx->dictLimit = end;
239 cctx->nextToUpdate = end+1;
240 cctx->stage = ZSTDcs_init;
241 cctx->dictID = 0;
242 cctx->loadedDictEnd = 0;
243 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200244 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
245 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200246 return 0;
247}
248
249typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
250
Yann Collet27caf2a2016-04-01 15:48:48 +0200251/*! ZSTD_resetCCtx_advanced() :
Yann Colletdccd6b62017-02-27 15:57:50 -0800252 note : @params must be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100253static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletea2ecdc2016-07-14 22:43:12 +0200254 ZSTD_parameters params, U64 frameContentSize,
Yann Collet4cb21292016-09-15 14:54:07 +0200255 ZSTD_compResetPolicy_e const crp)
Yann Colleta7737f62016-09-06 09:44:59 +0200256{
Yann Collet4cb21292016-09-15 14:54:07 +0200257 if (crp == ZSTDcrp_continue)
Nick Terrella4197772017-03-01 17:51:56 -0800258 if (ZSTD_equivalentParams(params, zc->params)) {
259 zc->flagStaticTables = 0;
260 zc->flagStaticHufTable = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200261 return ZSTD_continueCCtx(zc, params, frameContentSize);
Nick Terrella4197772017-03-01 17:51:56 -0800262 }
inikep87d4f3d2016-03-02 15:56:24 +0100263
Yann Colleta7737f62016-09-06 09:44:59 +0200264 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
265 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
266 size_t const maxNbSeq = blockSize / divider;
267 size_t const tokenSpace = blockSize + 11*maxNbSeq;
268 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
269 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
270 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
271 size_t const h3Size = ((size_t)1) << hashLog3;
272 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
273 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100274
Yann Colleta7737f62016-09-06 09:44:59 +0200275 /* Check if workSpace is large enough, alloc a new one if needed */
276 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
277 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
278 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200279 + (((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200280 if (zc->workSpaceSize < neededSpace) {
281 ZSTD_free(zc->workSpace, zc->customMem);
282 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
283 if (zc->workSpace == NULL) return ERROR(memory_allocation);
284 zc->workSpaceSize = neededSpace;
285 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100286
Yann Colleta7737f62016-09-06 09:44:59 +0200287 if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */
288 XXH64_reset(&zc->xxhState, 0);
289 zc->hashLog3 = hashLog3;
290 zc->hashTable = (U32*)(zc->workSpace);
291 zc->chainTable = zc->hashTable + hSize;
292 zc->hashTable3 = zc->chainTable + chainSize;
293 ptr = zc->hashTable3 + h3Size;
294 zc->hufTable = (HUF_CElt*)ptr;
295 zc->flagStaticTables = 0;
Nick Terrella4197772017-03-01 17:51:56 -0800296 zc->flagStaticHufTable = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200297 ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
Yann Collet70e8c382016-02-10 13:37:52 +0100298
Yann Colleta7737f62016-09-06 09:44:59 +0200299 zc->nextToUpdate = 1;
300 zc->nextSrc = NULL;
301 zc->base = NULL;
302 zc->dictBase = NULL;
303 zc->dictLimit = 0;
304 zc->lowLimit = 0;
305 zc->params = params;
306 zc->blockSize = blockSize;
307 zc->frameContentSize = frameContentSize;
308 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
309
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200310 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
Yann Colleta7737f62016-09-06 09:44:59 +0200311 zc->seqStore.litFreq = (U32*)ptr;
312 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
313 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
314 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
315 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
316 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
317 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
318 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
319 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
320 zc->seqStore.litLengthSum = 0;
321 }
322 zc->seqStore.sequencesStart = (seqDef*)ptr;
323 ptr = zc->seqStore.sequencesStart + maxNbSeq;
324 zc->seqStore.llCode = (BYTE*) ptr;
325 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
326 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
327 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
328
329 zc->stage = ZSTDcs_init;
330 zc->dictID = 0;
331 zc->loadedDictEnd = 0;
332
333 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100334 }
Yann Colletf3eca252015-10-22 15:31:46 +0100335}
336
Yann Collet32dfae62017-01-19 10:32:55 -0800337/* ZSTD_invalidateRepCodes() :
338 * ensures next compression will not use repcodes from previous block.
339 * Note : only works with regular variant;
340 * do not use with extDict variant ! */
341void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
342 int i;
343 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
344}
Yann Collet083fcc82015-10-25 14:06:35 +0100345
Yann Collet370b08e2016-03-08 00:03:59 +0100346/*! ZSTD_copyCCtx() :
347* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet731ef162016-07-27 21:05:12 +0200348* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100349* @return : 0, or an error code */
Yann Collet97b378a2016-09-21 17:20:19 +0200350size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100351{
Yann Collet731ef162016-07-27 21:05:12 +0200352 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100353
Sean Purcell2db72492017-02-09 10:50:43 -0800354
inikep28669512016-06-02 13:04:18 +0200355 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Sean Purcell2db72492017-02-09 10:50:43 -0800356 { ZSTD_parameters params = srcCCtx->params;
357 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
358 ZSTD_resetCCtx_advanced(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset);
359 }
Yann Collet7b51a292016-01-26 15:58:49 +0100360
361 /* copy tables */
Yann Collet731ef162016-07-27 21:05:12 +0200362 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
363 size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
364 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
365 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100366 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
367 }
Yann Collet7b51a292016-01-26 15:58:49 +0100368
Yann Colletc46fb922016-05-29 05:01:04 +0200369 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100370 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
371 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
372 dstCCtx->nextSrc = srcCCtx->nextSrc;
373 dstCCtx->base = srcCCtx->base;
374 dstCCtx->dictBase = srcCCtx->dictBase;
375 dstCCtx->dictLimit = srcCCtx->dictLimit;
376 dstCCtx->lowLimit = srcCCtx->lowLimit;
377 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200378 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100379
Yann Colletfb810d62016-01-28 00:18:06 +0100380 /* copy entropy tables */
381 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Nick Terrella4197772017-03-01 17:51:56 -0800382 dstCCtx->flagStaticHufTable = srcCCtx->flagStaticHufTable;
Yann Collet863ec402016-01-28 17:56:33 +0100383 if (srcCCtx->flagStaticTables) {
Yann Colletfb810d62016-01-28 00:18:06 +0100384 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
385 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
386 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
387 }
Nick Terrella4197772017-03-01 17:51:56 -0800388 if (srcCCtx->flagStaticHufTable) {
389 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
390 }
Yann Collet7b51a292016-01-26 15:58:49 +0100391
392 return 0;
393}
394
395
Yann Colletecabfe32016-03-20 16:20:06 +0100396/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100397* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100398static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100399{
Yann Colletecabfe32016-03-20 16:20:06 +0100400 U32 u;
401 for (u=0 ; u < size ; u++) {
402 if (table[u] < reducerValue) table[u] = 0;
403 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100404 }
405}
406
Yann Colletecabfe32016-03-20 16:20:06 +0100407/*! ZSTD_reduceIndex() :
408* rescale all indexes to avoid future overflow (indexes are U32) */
409static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
410{
Yann Collet731ef162016-07-27 21:05:12 +0200411 { U32 const hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100412 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
413
Yann Collet731ef162016-07-27 21:05:12 +0200414 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200415 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100416
Yann Collet731ef162016-07-27 21:05:12 +0200417 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100418 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
419}
420
Yann Collet89db5e02015-11-13 11:27:46 +0100421
Yann Collet863ec402016-01-28 17:56:33 +0100422/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100423* Block entropic compression
424*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100425
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200426/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100427
Yann Colletd1b26842016-03-15 01:24:33 +0100428size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100429{
Yann Colletd1b26842016-03-15 01:24:33 +0100430 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200431 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
432 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100433 return ZSTD_blockHeaderSize+srcSize;
434}
435
436
Yann Colletd1b26842016-03-15 01:24:33 +0100437static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100438{
439 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200440 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100441
Yann Colletd1b26842016-03-15 01:24:33 +0100442 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100443
Yann Collet59d1f792016-01-23 19:28:41 +0100444 switch(flSize)
445 {
446 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200447 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100448 break;
449 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200450 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100451 break;
452 default: /*note : should not be necessary : flSize is within {1,2,3} */
453 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200454 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100455 break;
456 }
457
458 memcpy(ostart + flSize, src, srcSize);
459 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100460}
461
Yann Colletd1b26842016-03-15 01:24:33 +0100462static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100463{
464 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200465 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100466
Yann Collet198e6aa2016-07-20 20:12:24 +0200467 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100468
469 switch(flSize)
470 {
471 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200472 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100473 break;
474 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200475 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100476 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100477 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100478 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200479 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100480 break;
481 }
482
483 ostart[flSize] = *(const BYTE*)src;
484 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100485}
486
Yann Collet59d1f792016-01-23 19:28:41 +0100487
Yann Colleta5c2c082016-03-20 01:09:18 +0100488static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100489
Yann Colletb923f652016-01-26 03:14:20 +0100490static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100491 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100492 const void* src, size_t srcSize)
493{
Yann Colleta910dc82016-03-18 12:37:45 +0100494 size_t const minGain = ZSTD_minGain(srcSize);
495 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200496 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100497 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200498 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100499 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100500
Yann Collet14983e72015-11-11 21:38:21 +0100501
Yann Colleta5c2c082016-03-20 01:09:18 +0100502 /* small ? don't even attempt compression (speed opt) */
503# define LITERAL_NOENTROPY 63
Nick Terrella4197772017-03-01 17:51:56 -0800504 { size_t const minLitSize = zc->flagStaticHufTable == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
Yann Colleta5c2c082016-03-20 01:09:18 +0100505 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
506 }
507
508 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Nick Terrella4197772017-03-01 17:51:56 -0800509 { HUF_repeat repeat = zc->flagStaticHufTable;
510 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
511 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters), zc->hufTable, &repeat)
512 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters), zc->hufTable, &repeat);
513 if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
514 else { zc->flagStaticHufTable = HUF_repeat_check; } /* now have a table to reuse */
Yann Colletb923f652016-01-26 03:14:20 +0100515 }
Yann Collet14983e72015-11-11 21:38:21 +0100516
Nick Terrella4197772017-03-01 17:51:56 -0800517 if ((cLitSize==0) | (cLitSize >= srcSize - minGain)) {
518 zc->flagStaticHufTable = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100519 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800520 }
521 if (cLitSize==1) {
522 zc->flagStaticHufTable = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100523 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800524 }
Yann Collet14983e72015-11-11 21:38:21 +0100525
526 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100527 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100528 {
Yann Collet59d1f792016-01-23 19:28:41 +0100529 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200530 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200531 MEM_writeLE24(ostart, lhc);
532 break;
533 }
Yann Collet59d1f792016-01-23 19:28:41 +0100534 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200535 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200536 MEM_writeLE32(ostart, lhc);
537 break;
538 }
Yann Colleta910dc82016-03-18 12:37:45 +0100539 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100540 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200541 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200542 MEM_writeLE32(ostart, lhc);
543 ostart[4] = (BYTE)(cLitSize >> 10);
544 break;
545 }
Yann Collet14983e72015-11-11 21:38:21 +0100546 }
Yann Colleta910dc82016-03-18 12:37:45 +0100547 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100548}
549
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200550static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
551 8, 9, 10, 11, 12, 13, 14, 15,
552 16, 16, 17, 17, 18, 18, 19, 19,
553 20, 20, 20, 20, 21, 21, 21, 21,
554 22, 22, 22, 22, 22, 22, 22, 22,
555 23, 23, 23, 23, 23, 23, 23, 23,
556 24, 24, 24, 24, 24, 24, 24, 24,
557 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100558
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200559static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
560 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
561 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
562 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
563 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
564 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
565 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
566 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200567
568
569void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100570{
Yann Colleted57d852016-07-29 21:22:17 +0200571 BYTE const LL_deltaCode = 19;
572 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200573 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200574 BYTE* const llCodeTable = seqStorePtr->llCode;
575 BYTE* const ofCodeTable = seqStorePtr->ofCode;
576 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200577 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200578 U32 u;
579 for (u=0; u<nbSeq; u++) {
580 U32 const llv = sequences[u].litLength;
581 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200582 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200583 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200584 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200585 }
Yann Colleted57d852016-07-29 21:22:17 +0200586 if (seqStorePtr->longLengthID==1)
587 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
588 if (seqStorePtr->longLengthID==2)
589 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100590}
591
592
Yann Colletb923f652016-01-26 03:14:20 +0100593size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100594 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100595 size_t srcSize)
596{
Yann Colletb923f652016-01-26 03:14:20 +0100597 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100598 U32 count[MaxSeq+1];
599 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100600 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
601 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
602 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100603 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200604 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200605 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
606 const BYTE* const llCodeTable = seqStorePtr->llCode;
607 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100608 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100609 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100610 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200611 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100612 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -0800613 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +0100614
Yann Collet14983e72015-11-11 21:38:21 +0100615 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100616 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100617 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100618 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100619 if (ZSTD_isError(cSize)) return cSize;
620 op += cSize;
621 }
622
623 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100624 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100625 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
626 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
627 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100628 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100629
Yann Colletbe391432016-03-22 23:19:28 +0100630 /* seqHead : flags for FSE encoding type */
631 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100632
Yann Colletfb810d62016-01-28 00:18:06 +0100633#define MIN_SEQ_FOR_DYNAMIC_FSE 64
634#define MAX_SEQ_FOR_STATIC_FSE 1000
635
Yann Colletb44be742016-03-26 20:52:14 +0100636 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +0200637 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +0100638
Yann Collet14983e72015-11-11 21:38:21 +0100639 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100640 { U32 max = MaxLL;
Yann Collete928f7e2016-12-01 16:13:35 -0800641 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100642 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
643 *op++ = llCodeTable[0];
644 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200645 LLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100646 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200647 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100648 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800649 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200650 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100651 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100652 size_t nbSeq_1 = nbSeq;
653 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
654 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
655 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100656 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
657 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
658 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800659 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200660 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100661 } }
Yann Collet14983e72015-11-11 21:38:21 +0100662
Yann Colletb44be742016-03-26 20:52:14 +0100663 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100664 { U32 max = MaxOff;
Yann Collete928f7e2016-12-01 16:13:35 -0800665 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100666 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100667 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100668 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200669 Offtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100670 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200671 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +0200672 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800673 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200674 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100675 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100676 size_t nbSeq_1 = nbSeq;
677 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100678 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100679 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100680 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
681 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
682 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800683 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200684 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100685 } }
686
Yann Collet14983e72015-11-11 21:38:21 +0100687 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100688 { U32 max = MaxML;
Yann Collete928f7e2016-12-01 16:13:35 -0800689 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100690 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100691 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100692 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200693 MLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100694 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200695 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100696 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800697 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200698 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100699 } else {
700 size_t nbSeq_1 = nbSeq;
701 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
702 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
703 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
704 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
705 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
706 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800707 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200708 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100709 } }
Yann Collet14983e72015-11-11 21:38:21 +0100710
Yann Colletbe391432016-03-22 23:19:28 +0100711 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100712 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100713
714 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100715 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100716 FSE_CState_t stateMatchLength;
717 FSE_CState_t stateOffsetBits;
718 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100719
Yann Collet95d07d72016-09-06 16:38:51 +0200720 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100721
Yann Collet597847a2016-03-20 19:14:22 +0100722 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100723 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100724 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100725 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +0200726 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100727 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200728 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100729 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200730 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100731 BIT_flushBits(&blockStream);
732
Yann Colletfadda6c2016-03-22 12:14:26 +0100733 { size_t n;
734 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +0200735 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200736 BYTE const ofCode = ofCodeTable[n];
737 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200738 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +0200739 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200740 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +0100741 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100742 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
743 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
744 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
745 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200746 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100747 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +0200748 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100749 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200750 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100751 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200752 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
Yann Colletb9151402016-03-26 17:18:11 +0100753 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100754 } }
Yann Collet14983e72015-11-11 21:38:21 +0100755
756 FSE_flushCState(&blockStream, &stateMatchLength);
757 FSE_flushCState(&blockStream, &stateOffsetBits);
758 FSE_flushCState(&blockStream, &stateLitLength);
759
Yann Colletb9151402016-03-26 17:18:11 +0100760 { size_t const streamSize = BIT_closeCStream(&blockStream);
761 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
762 op += streamSize;
763 } }
Yann Collet14983e72015-11-11 21:38:21 +0100764
765 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100766_check_compressibility:
Nick Terrella4197772017-03-01 17:51:56 -0800767 { size_t const minGain = ZSTD_minGain(srcSize);
768 size_t const maxCSize = srcSize - minGain;
769 if ((size_t)(op-ostart) >= maxCSize) {
770 zc->flagStaticHufTable = HUF_repeat_none;
771 return 0;
772 } }
Yann Collet14983e72015-11-11 21:38:21 +0100773
Yann Collet4266c0a2016-06-14 01:49:25 +0200774 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -0800775 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +0200776
Yann Collet5054ee02015-11-23 13:34:21 +0100777 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100778}
779
780
Yann Colletbb002742017-01-25 16:25:38 -0800781#if 0 /* for debug */
782# define STORESEQ_DEBUG
783#include <stdio.h> /* fprintf */
784U32 g_startDebug = 0;
785const BYTE* g_start = NULL;
786#endif
787
Yann Collet95cd0c22016-03-08 18:24:21 +0100788/*! ZSTD_storeSeq() :
789 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
790 `offsetCode` : distance to match, or 0 == repCode.
791 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100792*/
Yann Colletd57dffb2016-07-03 01:48:26 +0200793MEM_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 +0100794{
Yann Colletbb002742017-01-25 16:25:38 -0800795#ifdef STORESEQ_DEBUG
796 if (g_startDebug) {
797 const U32 pos = (U32)((const BYTE*)literals - g_start);
798 if (g_start==NULL) g_start = (const BYTE*)literals;
799 if ((pos > 1895000) && (pos < 1895300))
800 fprintf(stderr, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
801 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
802 }
Yann Collet14983e72015-11-11 21:38:21 +0100803#endif
Yann Collet14983e72015-11-11 21:38:21 +0100804 /* copy Literals */
805 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
806 seqStorePtr->lit += litLength;
807
808 /* literal Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200809 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
810 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100811
812 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200813 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100814
815 /* match Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200816 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
817 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +0200818
Yann Colletc0ce4f12016-07-30 00:55:13 +0200819 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +0100820}
821
822
Yann Collet7d360282016-02-12 00:07:30 +0100823/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100824* Match length counter
825***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100826static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100827{
Yann Collet863ec402016-01-28 17:56:33 +0100828 if (MEM_isLittleEndian()) {
829 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100830# if defined(_MSC_VER) && defined(_WIN64)
831 unsigned long r = 0;
832 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100833 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100834# elif defined(__GNUC__) && (__GNUC__ >= 3)
835 return (__builtin_ctzll((U64)val) >> 3);
836# else
837 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 };
838 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
839# endif
Yann Collet863ec402016-01-28 17:56:33 +0100840 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100841# if defined(_MSC_VER)
842 unsigned long r=0;
843 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100844 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100845# elif defined(__GNUC__) && (__GNUC__ >= 3)
846 return (__builtin_ctz((U32)val) >> 3);
847# else
848 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 };
849 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
850# endif
851 }
Yann Collet863ec402016-01-28 17:56:33 +0100852 } else { /* Big Endian CPU */
853 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100854# if defined(_MSC_VER) && defined(_WIN64)
855 unsigned long r = 0;
856 _BitScanReverse64( &r, val );
857 return (unsigned)(r>>3);
858# elif defined(__GNUC__) && (__GNUC__ >= 3)
859 return (__builtin_clzll(val) >> 3);
860# else
861 unsigned r;
862 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
863 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
864 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
865 r += (!val);
866 return r;
867# endif
Yann Collet863ec402016-01-28 17:56:33 +0100868 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100869# if defined(_MSC_VER)
870 unsigned long r = 0;
871 _BitScanReverse( &r, (unsigned long)val );
872 return (unsigned)(r>>3);
873# elif defined(__GNUC__) && (__GNUC__ >= 3)
874 return (__builtin_clz((U32)val) >> 3);
875# else
876 unsigned r;
877 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
878 r += (!val);
879 return r;
880# endif
Yann Collet863ec402016-01-28 17:56:33 +0100881 } }
Yann Collet14983e72015-11-11 21:38:21 +0100882}
883
884
Yann Colleta436a522016-06-20 23:34:04 +0200885static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100886{
887 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +0200888 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +0100889
Yann Colleta436a522016-06-20 23:34:04 +0200890 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +0200891 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100892 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
893 pIn += ZSTD_NbCommonBytes(diff);
894 return (size_t)(pIn - pStart);
895 }
Yann Collet14983e72015-11-11 21:38:21 +0100896 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
897 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
898 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
899 return (size_t)(pIn - pStart);
900}
901
Yann Collet04b12d82016-02-11 06:23:24 +0100902/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100903* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100904* convention : on reaching mEnd, match count continue starting from iStart
905*/
906static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
907{
Yann Collet7591a7f2016-05-20 11:44:43 +0200908 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +0200909 size_t const matchLength = ZSTD_count(ip, match, vEnd);
910 if (match + matchLength != mEnd) return matchLength;
911 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +0100912}
913
Yann Collet14983e72015-11-11 21:38:21 +0100914
Yann Collet863ec402016-01-28 17:56:33 +0100915/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100916* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100917***************************************/
inikepcc52a972016-02-19 10:09:35 +0100918static const U32 prime3bytes = 506832829U;
919static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Colletd4f4e582016-06-27 01:31:35 +0200920MEM_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 +0100921
Yann Collet4b100f42015-10-30 15:49:48 +0100922static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100923static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100924static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100925
Yann Collet4b100f42015-10-30 15:49:48 +0100926static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100927static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100928static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100929
930static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100931static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100932static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100933
Yann Collet14983e72015-11-11 21:38:21 +0100934static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100935static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100936static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100937
Yann Collet45dc3562016-07-12 09:47:31 +0200938static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
939static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
940static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
941
Yann Collet5be2dd22015-11-11 13:43:58 +0100942static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100943{
944 switch(mls)
945 {
946 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100947 case 4: return ZSTD_hash4Ptr(p, hBits);
948 case 5: return ZSTD_hash5Ptr(p, hBits);
949 case 6: return ZSTD_hash6Ptr(p, hBits);
950 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +0200951 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100952 }
953}
Yann Collet2acb5d32015-10-29 16:49:43 +0100954
Yann Collet863ec402016-01-28 17:56:33 +0100955
Yann Collet2ce49232016-02-02 14:36:49 +0100956/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100957* Fast Scan
958***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100959static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
960{
961 U32* const hashTable = zc->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200962 U32 const hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +0100963 const BYTE* const base = zc->base;
964 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +0200965 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +0100966 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +0100967
Yann Colletfb810d62016-01-28 00:18:06 +0100968 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100969 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +0100970 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +0100971 }
972}
973
974
Yann Collet1f44b3f2015-11-05 17:32:18 +0100975FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +0200976void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +0200977 const void* src, size_t srcSize,
978 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100979{
Yann Collet4266c0a2016-06-14 01:49:25 +0200980 U32* const hashTable = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200981 U32 const hBits = cctx->params.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +0200982 seqStore_t* seqStorePtr = &(cctx->seqStore);
983 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100984 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100985 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100986 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +0200987 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +0200988 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100989 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +0200990 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +0200991 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
992 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100993
Yann Collet1f44b3f2015-11-05 17:32:18 +0100994 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +0200995 ip += (ip==lowest);
996 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +0200997 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
998 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +0200999 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001000
1001 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001002 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001003 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001004 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1005 U32 const current = (U32)(ip-base);
1006 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001007 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001008 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001009
Yann Collet280f9a82016-08-08 00:44:00 +02001010 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +02001011 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +01001012 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001013 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1014 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001015 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001016 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001017 ip += ((ip-anchor) >> g_searchStrength) + 1;
1018 continue;
1019 }
Yann Collet45dc3562016-07-12 09:47:31 +02001020 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001021 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001022 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001023 offset_2 = offset_1;
1024 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001025
Yann Colleta436a522016-06-20 23:34:04 +02001026 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001027 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001028
Yann Collet402fdcf2015-11-20 12:46:08 +01001029 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001030 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001031 anchor = ip;
1032
Yann Colletfb810d62016-01-28 00:18:06 +01001033 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001034 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001035 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 +01001036 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1037 /* check immediate repcode */
1038 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001039 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001040 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001041 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001042 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001043 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001044 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001045 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1046 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001047 anchor = ip;
1048 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001049 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001050
Yann Collet4266c0a2016-06-14 01:49:25 +02001051 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001052 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1053 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001054
Yann Collet70e45772016-03-19 18:08:32 +01001055 /* Last Literals */
1056 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001057 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1058 seqStorePtr->lit += lastLLSize;
1059 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001060}
1061
1062
Yann Collet82260dd2016-02-11 07:14:25 +01001063static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001064 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001065{
Yann Collet3b719252016-03-30 19:48:05 +02001066 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001067 switch(mls)
1068 {
1069 default:
1070 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001071 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001072 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001073 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001074 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001075 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001076 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001077 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001078 }
1079}
Yann Colletf3eca252015-10-22 15:31:46 +01001080
Yann Colletf3eca252015-10-22 15:31:46 +01001081
Yann Collet82260dd2016-02-11 07:14:25 +01001082static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001083 const void* src, size_t srcSize,
1084 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001085{
1086 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001087 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001088 seqStore_t* seqStorePtr = &(ctx->seqStore);
1089 const BYTE* const base = ctx->base;
1090 const BYTE* const dictBase = ctx->dictBase;
1091 const BYTE* const istart = (const BYTE*)src;
1092 const BYTE* ip = istart;
1093 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001094 const U32 lowestIndex = ctx->lowLimit;
1095 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001096 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001097 const BYTE* const lowPrefixPtr = base + dictLimit;
1098 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001099 const BYTE* const iend = istart + srcSize;
1100 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001101 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001102
Yann Colleta436a522016-06-20 23:34:04 +02001103 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001104 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001105 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001106 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001107 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001108 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001109 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001110 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001111 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001112 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001113 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001114 hashTable[h] = current; /* update hash table */
1115
Yann Colleta436a522016-06-20 23:34:04 +02001116 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001117 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001118 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Colleta436a522016-06-20 23:34:04 +02001119 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001120 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001121 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001122 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001123 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001124 (MEM_read32(match) != MEM_read32(ip)) ) {
1125 ip += ((ip-anchor) >> g_searchStrength) + 1;
1126 continue;
1127 }
1128 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001129 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001130 U32 offset;
1131 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1132 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001133 offset = current - matchIndex;
1134 offset_2 = offset_1;
1135 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001136 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001137 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001138
Yann Collet5054ee02015-11-23 13:34:21 +01001139 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001140 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001141 anchor = ip;
1142
Yann Colletfb810d62016-01-28 00:18:06 +01001143 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001144 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001145 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001146 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1147 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001148 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001149 U32 const current2 = (U32)(ip-base);
1150 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001151 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001152 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1153 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001154 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001155 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001156 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001157 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001158 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001159 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001160 anchor = ip;
1161 continue;
1162 }
Yann Collet743402c2015-11-20 12:03:53 +01001163 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001164 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001165
Yann Collet4266c0a2016-06-14 01:49:25 +02001166 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001167 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001168
Yann Collet89db5e02015-11-13 11:27:46 +01001169 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001170 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001171 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1172 seqStorePtr->lit += lastLLSize;
1173 }
Yann Collet89db5e02015-11-13 11:27:46 +01001174}
1175
1176
Yann Collet82260dd2016-02-11 07:14:25 +01001177static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001178 const void* src, size_t srcSize)
1179{
Yann Collet731ef162016-07-27 21:05:12 +02001180 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001181 switch(mls)
1182 {
1183 default:
1184 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001185 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001186 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001187 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001188 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001189 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001190 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001191 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001192 }
1193}
1194
1195
Yann Collet04b12d82016-02-11 06:23:24 +01001196/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001197* Double Fast
1198***************************************/
1199static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1200{
1201 U32* const hashLarge = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001202 U32 const hBitsL = cctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001203 U32* const hashSmall = cctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001204 U32 const hBitsS = cctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001205 const BYTE* const base = cctx->base;
1206 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001207 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001208 const size_t fastHashFillStep = 3;
1209
1210 while(ip <= iend) {
1211 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1212 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1213 ip += fastHashFillStep;
1214 }
1215}
1216
1217
1218FORCE_INLINE
1219void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1220 const void* src, size_t srcSize,
1221 const U32 mls)
1222{
1223 U32* const hashLong = cctx->hashTable;
1224 const U32 hBitsL = cctx->params.cParams.hashLog;
1225 U32* const hashSmall = cctx->chainTable;
1226 const U32 hBitsS = cctx->params.cParams.chainLog;
1227 seqStore_t* seqStorePtr = &(cctx->seqStore);
1228 const BYTE* const base = cctx->base;
1229 const BYTE* const istart = (const BYTE*)src;
1230 const BYTE* ip = istart;
1231 const BYTE* anchor = istart;
1232 const U32 lowestIndex = cctx->dictLimit;
1233 const BYTE* const lowest = base + lowestIndex;
1234 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001235 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001236 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1237 U32 offsetSaved = 0;
1238
1239 /* init */
1240 ip += (ip==lowest);
1241 { U32 const maxRep = (U32)(ip-lowest);
1242 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1243 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1244 }
1245
1246 /* Main Search Loop */
1247 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1248 size_t mLength;
1249 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1250 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1251 U32 const current = (U32)(ip-base);
1252 U32 const matchIndexL = hashLong[h2];
1253 U32 const matchIndexS = hashSmall[h];
1254 const BYTE* matchLong = base + matchIndexL;
1255 const BYTE* match = base + matchIndexS;
1256 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1257
1258 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1259 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1260 ip++;
1261 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1262 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001263 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001264 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1265 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001266 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001267 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1268 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Colletc54692f2016-08-24 01:10:42 +02001269 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1270 U32 const matchIndex3 = hashLong[h3];
1271 const BYTE* match3 = base + matchIndex3;
1272 hashLong[h3] = current + 1;
1273 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1274 mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
1275 ip++;
1276 offset = (U32)(ip-match3);
1277 while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1278 } else {
1279 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1280 offset = (U32)(ip-match);
1281 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1282 }
Yann Collet45dc3562016-07-12 09:47:31 +02001283 } else {
1284 ip += ((ip-anchor) >> g_searchStrength) + 1;
1285 continue;
1286 }
1287
1288 offset_2 = offset_1;
1289 offset_1 = offset;
1290
1291 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1292 }
1293
1294 /* match found */
1295 ip += mLength;
1296 anchor = ip;
1297
1298 if (ip <= ilimit) {
1299 /* Fill Table */
1300 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1301 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1302 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1303 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1304
1305 /* check immediate repcode */
1306 while ( (ip <= ilimit)
1307 && ( (offset_2>0)
1308 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1309 /* store sequence */
1310 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001311 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001312 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1313 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1314 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1315 ip += rLength;
1316 anchor = ip;
1317 continue; /* faster when present ... (?) */
1318 } } }
1319
1320 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001321 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1322 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001323
1324 /* Last Literals */
1325 { size_t const lastLLSize = iend - anchor;
1326 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1327 seqStorePtr->lit += lastLLSize;
1328 }
1329}
1330
1331
1332static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1333{
1334 const U32 mls = ctx->params.cParams.searchLength;
1335 switch(mls)
1336 {
1337 default:
1338 case 4 :
1339 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1340 case 5 :
1341 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1342 case 6 :
1343 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1344 case 7 :
1345 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1346 }
1347}
1348
1349
1350static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1351 const void* src, size_t srcSize,
1352 const U32 mls)
1353{
1354 U32* const hashLong = ctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001355 U32 const hBitsL = ctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001356 U32* const hashSmall = ctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001357 U32 const hBitsS = ctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001358 seqStore_t* seqStorePtr = &(ctx->seqStore);
1359 const BYTE* const base = ctx->base;
1360 const BYTE* const dictBase = ctx->dictBase;
1361 const BYTE* const istart = (const BYTE*)src;
1362 const BYTE* ip = istart;
1363 const BYTE* anchor = istart;
1364 const U32 lowestIndex = ctx->lowLimit;
1365 const BYTE* const dictStart = dictBase + lowestIndex;
1366 const U32 dictLimit = ctx->dictLimit;
1367 const BYTE* const lowPrefixPtr = base + dictLimit;
1368 const BYTE* const dictEnd = dictBase + dictLimit;
1369 const BYTE* const iend = istart + srcSize;
1370 const BYTE* const ilimit = iend - 8;
1371 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1372
1373 /* Search Loop */
1374 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1375 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1376 const U32 matchIndex = hashSmall[hSmall];
1377 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1378 const BYTE* match = matchBase + matchIndex;
1379
1380 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1381 const U32 matchLongIndex = hashLong[hLong];
1382 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1383 const BYTE* matchLong = matchLongBase + matchLongIndex;
1384
1385 const U32 current = (U32)(ip-base);
1386 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1387 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1388 const BYTE* repMatch = repBase + repIndex;
1389 size_t mLength;
1390 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1391
1392 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1393 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1394 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1395 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1396 ip++;
1397 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1398 } else {
1399 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1400 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1401 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1402 U32 offset;
1403 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1404 offset = current - matchLongIndex;
1405 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1406 offset_2 = offset_1;
1407 offset_1 = offset;
1408 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001409
Yann Collet73d74a02016-07-12 13:03:48 +02001410 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001411 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1412 U32 const matchIndex3 = hashLong[h3];
1413 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1414 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001415 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001416 hashLong[h3] = current + 1;
1417 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1418 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1419 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1420 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1421 ip++;
1422 offset = current+1 - matchIndex3;
1423 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1424 } else {
1425 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1426 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1427 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1428 offset = current - matchIndex;
1429 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1430 }
Yann Collet45dc3562016-07-12 09:47:31 +02001431 offset_2 = offset_1;
1432 offset_1 = offset;
1433 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001434
Yann Collet45dc3562016-07-12 09:47:31 +02001435 } else {
1436 ip += ((ip-anchor) >> g_searchStrength) + 1;
1437 continue;
1438 } }
1439
1440 /* found a match : store it */
1441 ip += mLength;
1442 anchor = ip;
1443
1444 if (ip <= ilimit) {
1445 /* Fill Table */
1446 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1447 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1448 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1449 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1450 /* check immediate repcode */
1451 while (ip <= ilimit) {
1452 U32 const current2 = (U32)(ip-base);
1453 U32 const repIndex2 = current2 - offset_2;
1454 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1455 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1456 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1457 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1458 size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1459 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1460 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1461 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1462 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1463 ip += repLength2;
1464 anchor = ip;
1465 continue;
1466 }
1467 break;
1468 } } }
1469
1470 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001471 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001472
1473 /* Last Literals */
1474 { size_t const lastLLSize = iend - anchor;
1475 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1476 seqStorePtr->lit += lastLLSize;
1477 }
1478}
1479
1480
1481static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1482 const void* src, size_t srcSize)
1483{
Yann Collet731ef162016-07-27 21:05:12 +02001484 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001485 switch(mls)
1486 {
1487 default:
1488 case 4 :
1489 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1490 case 5 :
1491 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1492 case 6 :
1493 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1494 case 7 :
1495 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1496 }
1497}
1498
1499
1500/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001501* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001502***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001503/** ZSTD_insertBt1() : add one or multiple positions to tree.
1504* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001505* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001506static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1507 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001508{
Yann Collet731ef162016-07-27 21:05:12 +02001509 U32* const hashTable = zc->hashTable;
1510 U32 const hashLog = zc->params.cParams.hashLog;
1511 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1512 U32* const bt = zc->chainTable;
1513 U32 const btLog = zc->params.cParams.chainLog - 1;
1514 U32 const btMask = (1 << btLog) - 1;
1515 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001516 size_t commonLengthSmaller=0, commonLengthLarger=0;
1517 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001518 const BYTE* const dictBase = zc->dictBase;
1519 const U32 dictLimit = zc->dictLimit;
1520 const BYTE* const dictEnd = dictBase + dictLimit;
1521 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001522 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001523 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001524 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001525 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001526 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001527 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001528 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001529 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001530 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001531#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001532 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1533 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1534 predictedSmall += (predictedSmall>0);
1535 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001536#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001537
Yann Collet6c3e2e72015-12-11 10:44:07 +01001538 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001539
Yann Colletfb810d62016-01-28 00:18:06 +01001540 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001541 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001542 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001543
Yann Colletc0932082016-06-30 14:07:30 +02001544#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001545 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001546 if (matchIndex == predictedSmall) {
1547 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001548 *smallerPtr = matchIndex;
1549 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1550 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1551 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001552 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001553 continue;
1554 }
Yann Colletfb810d62016-01-28 00:18:06 +01001555 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001556 *largerPtr = matchIndex;
1557 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1558 largerPtr = nextPtr;
1559 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001560 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001561 continue;
1562 }
Yann Collet04b12d82016-02-11 06:23:24 +01001563#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001564 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001565 match = base + matchIndex;
1566 if (match[matchLength] == ip[matchLength])
1567 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001568 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001569 match = dictBase + matchIndex;
1570 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1571 if (matchIndex+matchLength >= dictLimit)
1572 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1573 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001574
Yann Colletb8a6f682016-02-15 17:06:29 +01001575 if (matchLength > bestLength) {
1576 bestLength = matchLength;
1577 if (matchLength > matchEndIdx - matchIndex)
1578 matchEndIdx = matchIndex + (U32)matchLength;
1579 }
Yann Colletee3f4512015-12-29 22:26:09 +01001580
Yann Collet59d70632015-11-04 12:05:27 +01001581 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001582 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001583
Yann Colletfb810d62016-01-28 00:18:06 +01001584 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001585 /* match is smaller than current */
1586 *smallerPtr = matchIndex; /* update smaller idx */
1587 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001588 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001589 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001590 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001591 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001592 /* match is larger than current */
1593 *largerPtr = matchIndex;
1594 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001595 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001596 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001597 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001598 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001599
Yann Collet59d70632015-11-04 12:05:27 +01001600 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001601 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001602 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1603 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001604}
1605
1606
Yann Collet82260dd2016-02-11 07:14:25 +01001607static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001608 ZSTD_CCtx* zc,
1609 const BYTE* const ip, const BYTE* const iend,
1610 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001611 U32 nbCompares, const U32 mls,
1612 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001613{
Yann Collet731ef162016-07-27 21:05:12 +02001614 U32* const hashTable = zc->hashTable;
1615 U32 const hashLog = zc->params.cParams.hashLog;
1616 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1617 U32* const bt = zc->chainTable;
1618 U32 const btLog = zc->params.cParams.chainLog - 1;
1619 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001620 U32 matchIndex = hashTable[h];
1621 size_t commonLengthSmaller=0, commonLengthLarger=0;
1622 const BYTE* const base = zc->base;
1623 const BYTE* const dictBase = zc->dictBase;
1624 const U32 dictLimit = zc->dictLimit;
1625 const BYTE* const dictEnd = dictBase + dictLimit;
1626 const BYTE* const prefixStart = base + dictLimit;
1627 const U32 current = (U32)(ip-base);
1628 const U32 btLow = btMask >= current ? 0 : current - btMask;
1629 const U32 windowLow = zc->lowLimit;
1630 U32* smallerPtr = bt + 2*(current&btMask);
1631 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001632 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001633 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001634 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001635
Yann Collet6c3e2e72015-12-11 10:44:07 +01001636 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001637
Yann Colletfb810d62016-01-28 00:18:06 +01001638 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001639 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01001640 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1641 const BYTE* match;
1642
Yann Colletfb810d62016-01-28 00:18:06 +01001643 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001644 match = base + matchIndex;
1645 if (match[matchLength] == ip[matchLength])
1646 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001647 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001648 match = dictBase + matchIndex;
1649 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001650 if (matchIndex+matchLength >= dictLimit)
1651 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001652 }
1653
Yann Colletfb810d62016-01-28 00:18:06 +01001654 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001655 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001656 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001657 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001658 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001659 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1660 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1661 }
1662
Yann Colletfb810d62016-01-28 00:18:06 +01001663 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001664 /* match is smaller than current */
1665 *smallerPtr = matchIndex; /* update smaller idx */
1666 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1667 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1668 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1669 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001670 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001671 /* match is larger than current */
1672 *largerPtr = matchIndex;
1673 commonLengthLarger = matchLength;
1674 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1675 largerPtr = nextPtr;
1676 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001677 } }
Yann Collet03526e12015-11-23 15:29:15 +01001678
1679 *smallerPtr = *largerPtr = 0;
1680
Yann Collet72e84cf2015-12-31 19:08:44 +01001681 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001682 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001683}
1684
Yann Collet2cc12cb2016-01-01 07:47:58 +01001685
Yann Colletb8a6f682016-02-15 17:06:29 +01001686static 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 +01001687{
1688 const BYTE* const base = zc->base;
1689 const U32 target = (U32)(ip - base);
1690 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001691
1692 while(idx < target)
1693 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001694}
1695
Yann Collet52447382016-03-20 16:00:00 +01001696/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001697static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001698 ZSTD_CCtx* zc,
1699 const BYTE* const ip, const BYTE* const iLimit,
1700 size_t* offsetPtr,
1701 const U32 maxNbAttempts, const U32 mls)
1702{
1703 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001704 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001705 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1706}
1707
1708
Yann Collet768c6bc2016-02-10 14:01:49 +01001709static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001710 ZSTD_CCtx* zc, /* Index table will be updated */
1711 const BYTE* ip, const BYTE* const iLimit,
1712 size_t* offsetPtr,
1713 const U32 maxNbAttempts, const U32 matchLengthSearch)
1714{
1715 switch(matchLengthSearch)
1716 {
1717 default :
1718 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1719 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1720 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1721 }
1722}
1723
1724
Yann Colletb8a6f682016-02-15 17:06:29 +01001725static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1726{
1727 const BYTE* const base = zc->base;
1728 const U32 target = (U32)(ip - base);
1729 U32 idx = zc->nextToUpdate;
1730
1731 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1732}
1733
inikep64d7bcb2016-04-07 19:14:09 +02001734
Yann Collet03526e12015-11-23 15:29:15 +01001735/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001736static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001737 ZSTD_CCtx* zc,
1738 const BYTE* const ip, const BYTE* const iLimit,
1739 size_t* offsetPtr,
1740 const U32 maxNbAttempts, const U32 mls)
1741{
Yann Colletee3f4512015-12-29 22:26:09 +01001742 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001743 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001744 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001745}
1746
1747
Yann Collet82260dd2016-02-11 07:14:25 +01001748static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001749 ZSTD_CCtx* zc, /* Index table will be updated */
1750 const BYTE* ip, const BYTE* const iLimit,
1751 size_t* offsetPtr,
1752 const U32 maxNbAttempts, const U32 matchLengthSearch)
1753{
1754 switch(matchLengthSearch)
1755 {
1756 default :
1757 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1758 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1759 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1760 }
1761}
1762
1763
Yann Collet5106a762015-11-05 15:00:24 +01001764
Yann Collet731ef162016-07-27 21:05:12 +02001765/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02001766* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02001767***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02001768#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1769
1770/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08001771 Assumption : always within prefix (i.e. not within extDict) */
inikep64d7bcb2016-04-07 19:14:09 +02001772FORCE_INLINE
1773U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1774{
1775 U32* const hashTable = zc->hashTable;
1776 const U32 hashLog = zc->params.cParams.hashLog;
1777 U32* const chainTable = zc->chainTable;
1778 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1779 const BYTE* const base = zc->base;
1780 const U32 target = (U32)(ip - base);
1781 U32 idx = zc->nextToUpdate;
1782
Yann Collet22d76322016-06-21 08:01:51 +02001783 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001784 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1785 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1786 hashTable[h] = idx;
1787 idx++;
1788 }
1789
1790 zc->nextToUpdate = target;
1791 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1792}
1793
1794
1795
1796FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1797size_t ZSTD_HcFindBestMatch_generic (
1798 ZSTD_CCtx* zc, /* Index table will be updated */
1799 const BYTE* const ip, const BYTE* const iLimit,
1800 size_t* offsetPtr,
1801 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1802{
1803 U32* const chainTable = zc->chainTable;
1804 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1805 const U32 chainMask = chainSize-1;
1806 const BYTE* const base = zc->base;
1807 const BYTE* const dictBase = zc->dictBase;
1808 const U32 dictLimit = zc->dictLimit;
1809 const BYTE* const prefixStart = base + dictLimit;
1810 const BYTE* const dictEnd = dictBase + dictLimit;
1811 const U32 lowLimit = zc->lowLimit;
1812 const U32 current = (U32)(ip-base);
1813 const U32 minChain = current > chainSize ? current - chainSize : 0;
1814 int nbAttempts=maxNbAttempts;
1815 size_t ml=EQUAL_READ32-1;
1816
1817 /* HC4 match finder */
1818 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1819
Yann Collet22d76322016-06-21 08:01:51 +02001820 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001821 const BYTE* match;
1822 size_t currentMl=0;
1823 if ((!extDict) || matchIndex >= dictLimit) {
1824 match = base + matchIndex;
1825 if (match[ml] == ip[ml]) /* potentially better */
1826 currentMl = ZSTD_count(ip, match, iLimit);
1827 } else {
1828 match = dictBase + matchIndex;
1829 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1830 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1831 }
1832
1833 /* save best solution */
Yann Collet22d76322016-06-21 08:01:51 +02001834 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 +02001835
1836 if (matchIndex <= minChain) break;
1837 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1838 }
1839
1840 return ml;
1841}
1842
1843
1844FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1845 ZSTD_CCtx* zc,
1846 const BYTE* ip, const BYTE* const iLimit,
1847 size_t* offsetPtr,
1848 const U32 maxNbAttempts, const U32 matchLengthSearch)
1849{
1850 switch(matchLengthSearch)
1851 {
1852 default :
1853 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1854 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1855 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1856 }
1857}
1858
1859
1860FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1861 ZSTD_CCtx* zc,
1862 const BYTE* ip, const BYTE* const iLimit,
1863 size_t* offsetPtr,
1864 const U32 maxNbAttempts, const U32 matchLengthSearch)
1865{
1866 switch(matchLengthSearch)
1867 {
1868 default :
1869 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1870 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1871 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1872 }
1873}
1874
inikep64d7bcb2016-04-07 19:14:09 +02001875
Yann Collet287b7d92015-11-22 13:24:05 +01001876/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001877* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001878*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001879FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001880void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1881 const void* src, size_t srcSize,
1882 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001883{
inikepfaa8d8a2016-04-05 19:01:10 +02001884 seqStore_t* seqStorePtr = &(ctx->seqStore);
1885 const BYTE* const istart = (const BYTE*)src;
1886 const BYTE* ip = istart;
1887 const BYTE* anchor = istart;
1888 const BYTE* const iend = istart + srcSize;
1889 const BYTE* const ilimit = iend - 8;
1890 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001891
Yann Collet793c6492016-04-09 20:32:00 +02001892 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1893 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001894
inikep64d7bcb2016-04-07 19:14:09 +02001895 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1896 size_t* offsetPtr,
1897 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02001898 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02001899 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02001900
inikepfaa8d8a2016-04-05 19:01:10 +02001901 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001902 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02001903 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02001904 { U32 const maxRep = (U32)(ip-base);
1905 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1906 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1907 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001908
inikepfaa8d8a2016-04-05 19:01:10 +02001909 /* Match Loop */
1910 while (ip < ilimit) {
1911 size_t matchLength=0;
1912 size_t offset=0;
1913 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001914
inikepfaa8d8a2016-04-05 19:01:10 +02001915 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02001916 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02001917 /* repcode : we take it */
Yann Collet9634f672016-07-03 01:23:58 +02001918 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001919 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001920 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001921
inikepfaa8d8a2016-04-05 19:01:10 +02001922 /* first search (depth 0) */
1923 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001924 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001925 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001926 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001927 }
Yann Collet5106a762015-11-05 15:00:24 +01001928
inikep7bc19b62016-04-06 09:46:01 +02001929 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001930 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1931 continue;
1932 }
1933
inikep64d7bcb2016-04-07 19:14:09 +02001934 /* let's try to find a better solution */
1935 if (depth>=1)
1936 while (ip<ilimit) {
1937 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001938 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1939 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001940 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001941 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001942 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1943 matchLength = mlRep, offset = 0, start = ip;
1944 }
1945 { size_t offset2=99999999;
1946 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001947 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1948 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001949 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1950 matchLength = ml2, offset = offset2, start = ip;
1951 continue; /* search a better one */
1952 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001953
inikep64d7bcb2016-04-07 19:14:09 +02001954 /* let's find an even better one */
1955 if ((depth==2) && (ip<ilimit)) {
1956 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001957 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1958 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001959 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001960 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001961 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1962 matchLength = ml2, offset = 0, start = ip;
1963 }
1964 { size_t offset2=99999999;
1965 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001966 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1967 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001968 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1969 matchLength = ml2, offset = offset2, start = ip;
1970 continue;
1971 } } }
1972 break; /* nothing found : store previous solution */
1973 }
1974
1975 /* catch up */
1976 if (offset) {
1977 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1978 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02001979 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02001980 }
1981
inikepfaa8d8a2016-04-05 19:01:10 +02001982 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001983_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001984 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02001985 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02001986 anchor = ip = start + matchLength;
1987 }
Yann Collet48537162016-04-07 15:24:29 +02001988
inikepfaa8d8a2016-04-05 19:01:10 +02001989 /* check immediate repcode */
1990 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02001991 && ((offset_2>0)
1992 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02001993 /* store sequence */
Yann Collet9634f672016-07-03 01:23:58 +02001994 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
1995 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001996 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1997 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001998 anchor = ip;
1999 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002000 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002001
Yann Collet4266c0a2016-06-14 01:49:25 +02002002 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002003 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2004 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002005
inikepfaa8d8a2016-04-05 19:01:10 +02002006 /* Last Literals */
2007 { size_t const lastLLSize = iend - anchor;
2008 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2009 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002010 }
Yann Collet5106a762015-11-05 15:00:24 +01002011}
2012
Yann Collet5be2dd22015-11-11 13:43:58 +01002013
inikep64d7bcb2016-04-07 19:14:09 +02002014static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2015{
2016 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2017}
2018
2019static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2020{
2021 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2022}
2023
2024static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2025{
2026 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2027}
2028
2029static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2030{
2031 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2032}
2033
2034
inikepfaa8d8a2016-04-05 19:01:10 +02002035FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002036void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2037 const void* src, size_t srcSize,
2038 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002039{
inikepfaa8d8a2016-04-05 19:01:10 +02002040 seqStore_t* seqStorePtr = &(ctx->seqStore);
2041 const BYTE* const istart = (const BYTE*)src;
2042 const BYTE* ip = istart;
2043 const BYTE* anchor = istart;
2044 const BYTE* const iend = istart + srcSize;
2045 const BYTE* const ilimit = iend - 8;
2046 const BYTE* const base = ctx->base;
2047 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002048 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002049 const BYTE* const prefixStart = base + dictLimit;
2050 const BYTE* const dictBase = ctx->dictBase;
2051 const BYTE* const dictEnd = dictBase + dictLimit;
2052 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2053
2054 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2055 const U32 mls = ctx->params.cParams.searchLength;
2056
inikep64d7bcb2016-04-07 19:14:09 +02002057 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2058 size_t* offsetPtr,
2059 U32 maxNbAttempts, U32 matchLengthSearch);
2060 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2061
Yann Collet302ff032016-07-03 01:28:16 +02002062 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002063
Yann Collet302ff032016-07-03 01:28:16 +02002064 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002065 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002066 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002067
2068 /* Match Loop */
2069 while (ip < ilimit) {
2070 size_t matchLength=0;
2071 size_t offset=0;
2072 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002073 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002074
2075 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002076 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002077 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2078 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002079 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002080 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002081 /* repcode detected we should take it */
2082 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02002083 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2084 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002085 } }
2086
2087 /* first search (depth 0) */
2088 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002089 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002090 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002091 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002092 }
2093
inikep7bc19b62016-04-06 09:46:01 +02002094 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02002095 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2096 continue;
2097 }
2098
inikep64d7bcb2016-04-07 19:14:09 +02002099 /* let's try to find a better solution */
2100 if (depth>=1)
2101 while (ip<ilimit) {
2102 ip ++;
2103 current++;
2104 /* check repCode */
2105 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002106 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002107 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2108 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002109 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002110 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2111 /* repcode detected */
2112 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2113 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2114 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002115 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002116 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2117 matchLength = repLength, offset = 0, start = ip;
2118 } }
2119
2120 /* search match, depth 1 */
2121 { size_t offset2=99999999;
2122 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002123 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2124 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02002125 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2126 matchLength = ml2, offset = offset2, start = ip;
2127 continue; /* search a better one */
2128 } }
2129
2130 /* let's find an even better one */
2131 if ((depth==2) && (ip<ilimit)) {
2132 ip ++;
2133 current++;
2134 /* check repCode */
2135 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002136 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002137 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2138 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002139 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002140 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2141 /* repcode detected */
2142 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2143 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2144 int gain2 = (int)(repLength * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002145 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002146 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2147 matchLength = repLength, offset = 0, start = ip;
2148 } }
2149
2150 /* search match, depth 2 */
2151 { size_t offset2=99999999;
2152 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002153 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2154 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02002155 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2156 matchLength = ml2, offset = offset2, start = ip;
2157 continue;
2158 } } }
2159 break; /* nothing found : store previous solution */
2160 }
2161
inikepfaa8d8a2016-04-05 19:01:10 +02002162 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002163 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002164 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002165 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2166 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002167 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002168 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002169 }
inikepfaa8d8a2016-04-05 19:01:10 +02002170
inikepfaa8d8a2016-04-05 19:01:10 +02002171 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002172_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002173 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002174 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002175 anchor = ip = start + matchLength;
2176 }
2177
2178 /* check immediate repcode */
2179 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002180 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002181 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2182 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002183 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002184 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2185 /* repcode detected we should take it */
2186 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02002187 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
Yann Collet302ff032016-07-03 01:28:16 +02002188 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002189 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2190 ip += matchLength;
2191 anchor = ip;
2192 continue; /* faster when present ... (?) */
2193 }
2194 break;
2195 } }
2196
Yann Collet4266c0a2016-06-14 01:49:25 +02002197 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002198 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002199
inikepfaa8d8a2016-04-05 19:01:10 +02002200 /* Last Literals */
2201 { size_t const lastLLSize = iend - anchor;
2202 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2203 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002204 }
2205}
2206
2207
Yann Collet59d1f792016-01-23 19:28:41 +01002208void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002209{
inikep64d7bcb2016-04-07 19:14:09 +02002210 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002211}
2212
Yann Collet59d1f792016-01-23 19:28:41 +01002213static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002214{
Yann Colleta1249dc2016-01-25 04:22:03 +01002215 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002216}
Yann Collet9a24e592015-11-22 02:53:43 +01002217
Yann Collet59d1f792016-01-23 19:28:41 +01002218static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002219{
Yann Colleta1249dc2016-01-25 04:22:03 +01002220 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002221}
2222
Yann Collet59d1f792016-01-23 19:28:41 +01002223static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002224{
Yann Colleta1249dc2016-01-25 04:22:03 +01002225 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002226}
2227
inikepef519412016-04-21 11:08:43 +02002228
inikepef519412016-04-21 11:08:43 +02002229/* The optimal parser */
2230#include "zstd_opt.h"
2231
2232static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2233{
Yann Colletd4f4e582016-06-27 01:31:35 +02002234#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002235 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2236#else
2237 (void)ctx; (void)src; (void)srcSize;
2238 return;
2239#endif
2240}
2241
2242static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2243{
2244#ifdef ZSTD_OPT_H_91842398743
2245 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002246#else
2247 (void)ctx; (void)src; (void)srcSize;
2248 return;
2249#endif
inikepef519412016-04-21 11:08:43 +02002250}
2251
inikepd3b8d7a2016-02-22 10:06:17 +01002252static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002253{
Yann Colletd4f4e582016-06-27 01:31:35 +02002254#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002255 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2256#else
2257 (void)ctx; (void)src; (void)srcSize;
2258 return;
2259#endif
2260}
2261
2262static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2263{
2264#ifdef ZSTD_OPT_H_91842398743
2265 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002266#else
2267 (void)ctx; (void)src; (void)srcSize;
2268 return;
2269#endif
inikepe2bfe242016-01-31 11:25:48 +01002270}
2271
Yann Collet7a231792015-11-21 15:27:35 +01002272
Yann Collet59d1f792016-01-23 19:28:41 +01002273typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002274
Yann Colletb923f652016-01-26 03:14:20 +01002275static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002276{
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002277 static const ZSTD_blockCompressor blockCompressor[2][8] = {
2278 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 },
2279 { 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 +01002280 };
2281
2282 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002283}
2284
2285
Yann Colletd1b26842016-03-15 01:24:33 +01002286static 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 +01002287{
Yann Collet19cab462016-06-17 12:54:52 +02002288 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002289 const BYTE* const base = zc->base;
2290 const BYTE* const istart = (const BYTE*)src;
2291 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002292 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 +02002293 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002294 if (current > zc->nextToUpdate + 384)
2295 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 +01002296 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002297 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002298}
2299
2300
Yann Colletc991cc12016-07-28 00:55:43 +02002301/*! ZSTD_compress_generic() :
2302* Compress a chunk of data into one or multiple blocks.
2303* All blocks will be terminated, all input will be consumed.
2304* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2305* Frame is supposed already started (header already produced)
2306* @return : compressed size, or an error code
2307*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002308static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2309 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002310 const void* src, size_t srcSize,
2311 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002312{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002313 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002314 size_t remaining = srcSize;
2315 const BYTE* ip = (const BYTE*)src;
2316 BYTE* const ostart = (BYTE*)dst;
2317 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002318 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002319
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002320 if (cctx->params.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002321 XXH64_update(&cctx->xxhState, src, srcSize);
2322
Yann Collet2ce49232016-02-02 14:36:49 +01002323 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002324 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002325 size_t cSize;
2326
inikepfb5df612016-05-24 15:36:37 +02002327 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 +01002328 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002329
Yann Collet346efcc2016-08-02 14:26:00 +02002330 /* preemptive overflow correction */
Yann Colletc261f712016-12-12 00:25:07 +01002331 if (cctx->lowLimit > (2U<<30)) {
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002332 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002333 U32 const current = (U32)(ip - cctx->base);
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002334 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002335 U32 const correction = current - newCurrent;
2336 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002337 ZSTD_reduceIndex(cctx, correction);
2338 cctx->base += correction;
2339 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002340 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002341 cctx->dictLimit -= correction;
2342 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2343 else cctx->nextToUpdate -= correction;
2344 }
2345
Yann Collet06e76972017-01-25 16:39:03 -08002346 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002347 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002348 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2349 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2350 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002351 }
Yann Collet89db5e02015-11-13 11:27:46 +01002352
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002353 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002354 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002355
Yann Collet2ce49232016-02-02 14:36:49 +01002356 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002357 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2358 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2359 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2360 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2361 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002362 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002363 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002364 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002365 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002366 }
2367
2368 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002369 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002370 ip += blockSize;
2371 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002372 }
2373
Yann Collet62470b42016-07-28 15:29:08 +02002374 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002375 return op-ostart;
2376}
2377
2378
Yann Collet6236eba2016-04-12 15:52:33 +02002379static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002380 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002381{ BYTE* const op = (BYTE*)dst;
Yann Collet731ef162016-07-27 21:05:12 +02002382 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2383 U32 const checksumFlag = params.fParams.checksumFlag>0;
2384 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002385 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002386 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2387 U32 const fcsCode = params.fParams.contentSizeFlag ?
Yann Collet673f0d72016-06-06 00:26:38 +02002388 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2389 0;
Yann Collet731ef162016-07-27 21:05:12 +02002390 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002391 size_t pos;
2392
2393 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002394
2395 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002396 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002397 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002398 switch(dictIDSizeCode)
2399 {
2400 default: /* impossible */
2401 case 0 : break;
2402 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002403 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002404 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2405 }
Yann Collet673f0d72016-06-06 00:26:38 +02002406 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002407 {
2408 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002409 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002410 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2411 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002412 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002413 }
Yann Colletc46fb922016-05-29 05:01:04 +02002414 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002415}
2416
2417
Yann Collet346efcc2016-08-02 14:26:00 +02002418static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002419 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002420 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002421 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002422{
Yann Collet2acb5d32015-10-29 16:49:43 +01002423 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002424 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002425
Yann Collet346efcc2016-08-02 14:26:00 +02002426 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002427
Yann Collet346efcc2016-08-02 14:26:00 +02002428 if (frame && (cctx->stage==ZSTDcs_init)) {
2429 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002430 if (ZSTD_isError(fhSize)) return fhSize;
2431 dstCapacity -= fhSize;
2432 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002433 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002434 }
Yann Colletf3eca252015-10-22 15:31:46 +01002435
Yann Collet417890c2015-12-04 17:16:37 +01002436 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002437 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002438 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002439 ptrdiff_t const delta = cctx->nextSrc - ip;
2440 cctx->lowLimit = cctx->dictLimit;
2441 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2442 cctx->dictBase = cctx->base;
2443 cctx->base -= delta;
2444 cctx->nextToUpdate = cctx->dictLimit;
2445 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002446 }
2447
Yann Collet346efcc2016-08-02 14:26:00 +02002448 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2449 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2450 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2451 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2452 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002453 }
2454
Yann Collet346efcc2016-08-02 14:26:00 +02002455 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002456
Yann Collet5eb749e2017-01-11 18:21:25 +01002457 if (srcSize) {
2458 size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002459 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2460 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002461 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002462 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002463 } else
2464 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002465}
2466
Yann Colletbf42c8e2016-01-09 01:08:23 +01002467
Yann Collet5b567392016-07-28 01:17:22 +02002468size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002469 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002470 const void* src, size_t srcSize)
2471{
Yann Collet5b567392016-07-28 01:17:22 +02002472 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
2473}
2474
2475
Yann Colletcf05b9d2016-07-18 16:52:10 +02002476size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002477{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002478 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2479}
2480
2481size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2482{
2483 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002484 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Colletc991cc12016-07-28 00:55:43 +02002485 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002486}
2487
2488
Yann Colletb923f652016-01-26 03:14:20 +01002489static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002490{
2491 const BYTE* const ip = (const BYTE*) src;
2492 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002493
Yann Collet417890c2015-12-04 17:16:37 +01002494 /* input becomes current prefix */
2495 zc->lowLimit = zc->dictLimit;
2496 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2497 zc->dictBase = zc->base;
2498 zc->base += ip - zc->nextSrc;
2499 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002500 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002501
2502 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002503 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002504
Yann Collet3b719252016-03-30 19:48:05 +02002505 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002506 {
2507 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002508 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002509 break;
2510
Yann Collet45dc3562016-07-12 09:47:31 +02002511 case ZSTD_dfast:
2512 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2513 break;
2514
Yann Collet417890c2015-12-04 17:16:37 +01002515 case ZSTD_greedy:
2516 case ZSTD_lazy:
2517 case ZSTD_lazy2:
Yann Collet731ef162016-07-27 21:05:12 +02002518 ZSTD_insertAndFindFirstIndex (zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002519 break;
2520
2521 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002522 case ZSTD_btopt:
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002523 case ZSTD_btopt2:
Yann Collet731ef162016-07-27 21:05:12 +02002524 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002525 break;
2526
2527 default:
2528 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2529 }
2530
Nick Terrellecf90ca2017-02-13 18:27:34 -08002531 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002532 return 0;
2533}
2534
2535
Nick Terrellf9c9af32016-10-19 17:22:08 -07002536/* Dictionaries that assign zero probability to symbols that show up causes problems
2537 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2538 that we may encounter during compression.
2539 NOTE: This behavior is not standard and could be improved in the future. */
2540static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2541 U32 s;
2542 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2543 for (s = 0; s <= maxSymbolValue; ++s) {
2544 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2545 }
2546 return 0;
2547}
2548
2549
Yann Colletb923f652016-01-26 03:14:20 +01002550/* Dictionary format :
Yann Colletee5b7252016-10-27 14:20:55 -07002551 Magic == ZSTD_DICT_MAGIC (4 bytes)
2552 HUF_writeCTable(256)
2553 FSE_writeNCount(off)
2554 FSE_writeNCount(ml)
2555 FSE_writeNCount(ll)
2556 RepOffsets
2557 Dictionary content
Yann Colletb923f652016-01-26 03:14:20 +01002558*/
Yann Colletfb797352016-03-13 11:08:40 +01002559/*! ZSTD_loadDictEntropyStats() :
Yann Collet736d4192016-06-15 18:48:51 +02002560 @return : size read from dictionary
2561 note : magic number supposed already checked */
2562static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002563{
Yann Collet52a06222016-06-15 13:53:34 +02002564 const BYTE* dictPtr = (const BYTE*)dict;
2565 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07002566 short offcodeNCount[MaxOff+1];
2567 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08002568 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01002569
Yann Collet736d4192016-06-15 18:48:51 +02002570 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002571 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002572 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002573 }
Yann Colletfb810d62016-01-28 00:18:06 +01002574
Nick Terrellf9c9af32016-10-19 17:22:08 -07002575 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02002576 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002577 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002578 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002579 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Collet643d9a22016-12-01 16:24:04 -08002580 CHECK_E (FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002581 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002582 }
Yann Colletfb810d62016-01-28 00:18:06 +01002583
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002584 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002585 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002586 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002587 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002588 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002589 /* Every match length code must have non-zero probability */
2590 CHECK_F (ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
Yann Collet643d9a22016-12-01 16:24:04 -08002591 CHECK_E (FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002592 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002593 }
Yann Colletfb810d62016-01-28 00:18:06 +01002594
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002595 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002596 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002597 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002598 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002599 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002600 /* Every literal length code must have non-zero probability */
2601 CHECK_F (ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
Yann Collet643d9a22016-12-01 16:24:04 -08002602 CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002603 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002604 }
Yann Colletfb810d62016-01-28 00:18:06 +01002605
Yann Collet52a06222016-06-15 13:53:34 +02002606 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Nick Terrell8157a4c2016-12-20 10:47:52 -08002607 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] == 0 || cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2608 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] == 0 || cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2609 cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] == 0 || cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002610 dictPtr += 12;
2611
Nick Terrellb2c39a22016-10-24 14:11:27 -07002612 { U32 offcodeMax = MaxOff;
2613 if ((size_t)(dictEnd - dictPtr) <= ((U32)-1) - 128 KB) {
2614 U32 const maxOffset = (U32)(dictEnd - dictPtr) + 128 KB; /* The maximum offset that must be supported */
2615 /* Calculate minimum offset code required to represent maxOffset */
2616 offcodeMax = ZSTD_highbit32(maxOffset);
2617 }
Nick Terrellf9c9af32016-10-19 17:22:08 -07002618 /* Every possible supported offset <= dictContentSize + 128 KB must be representable */
2619 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
2620 }
2621
Yann Collet736d4192016-06-15 18:48:51 +02002622 cctx->flagStaticTables = 1;
Nick Terrella4197772017-03-01 17:51:56 -08002623 cctx->flagStaticHufTable = HUF_repeat_valid;
Yann Collet52a06222016-06-15 13:53:34 +02002624 return dictPtr - (const BYTE*)dict;
Yann Colletb923f652016-01-26 03:14:20 +01002625}
2626
Yann Colletd1b26842016-03-15 01:24:33 +01002627/** ZSTD_compress_insertDictionary() :
2628* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002629static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002630{
Yann Colletc46fb922016-05-29 05:01:04 +02002631 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002632
Yann Collet14312d82017-02-23 23:42:12 -08002633 /* dict as pure content */
2634 if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (zc->forceRawDict))
2635 return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletc46fb922016-05-29 05:01:04 +02002636 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
Yann Colletd1b26842016-03-15 01:24:33 +01002637
2638 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet3e21ec52016-09-06 15:36:19 +02002639 { size_t const loadError = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8);
2640 size_t const eSize = loadError + 8;
2641 if (ZSTD_isError(loadError)) return loadError;
Yann Collet21588e32016-03-30 16:50:44 +02002642 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002643 }
Yann Colletecd651b2016-01-07 15:35:18 +01002644}
2645
Yann Collet27caf2a2016-04-01 15:48:48 +02002646/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002647* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002648static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002649 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002650 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002651{
Yann Colleta7737f62016-09-06 09:44:59 +02002652 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
Yann Collet3e21ec52016-09-06 15:36:19 +02002653 CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp));
Yann Colleta7737f62016-09-06 09:44:59 +02002654 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002655}
2656
2657
Yann Collet27caf2a2016-04-01 15:48:48 +02002658/*! ZSTD_compressBegin_advanced() :
2659* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002660size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002661 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002662 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002663{
2664 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02002665 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet81e13ef2016-06-07 00:51:51 +02002666 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002667}
2668
2669
Yann Collet81e13ef2016-06-07 00:51:51 +02002670size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002671{
Yann Collet6c6e1752016-06-27 15:28:45 +02002672 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002673 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002674}
Yann Collet083fcc82015-10-25 14:06:35 +01002675
inikep19bd48f2016-04-04 12:10:00 +02002676
Yann Colletb05c4822017-01-12 02:01:28 +01002677size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002678{
Yann Colletb05c4822017-01-12 02:01:28 +01002679 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002680}
2681
2682
Yann Collet62470b42016-07-28 15:29:08 +02002683/*! ZSTD_writeEpilogue() :
2684* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002685* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002686static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002687{
Yann Colletc991cc12016-07-28 00:55:43 +02002688 BYTE* const ostart = (BYTE*)dst;
2689 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002690 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002691
Yann Collet87c18b22016-08-26 01:43:47 +02002692 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002693
2694 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002695 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002696 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002697 if (ZSTD_isError(fhSize)) return fhSize;
2698 dstCapacity -= fhSize;
2699 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002700 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002701 }
2702
Yann Colletc991cc12016-07-28 00:55:43 +02002703 if (cctx->stage != ZSTDcs_ending) {
2704 /* write one last empty block, make it the "last" block */
2705 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2706 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2707 MEM_writeLE32(op, cBlockHeader24);
2708 op += ZSTD_blockHeaderSize;
2709 dstCapacity -= ZSTD_blockHeaderSize;
2710 }
2711
2712 if (cctx->params.fParams.checksumFlag) {
2713 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2714 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2715 MEM_writeLE32(op, checksum);
2716 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002717 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002718
Yann Collet731ef162016-07-27 21:05:12 +02002719 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002720 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002721}
2722
Yann Colletfd416f12016-01-30 03:14:15 +01002723
Yann Collet62470b42016-07-28 15:29:08 +02002724size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2725 void* dst, size_t dstCapacity,
2726 const void* src, size_t srcSize)
2727{
2728 size_t endResult;
2729 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
2730 if (ZSTD_isError(cSize)) return cSize;
2731 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2732 if (ZSTD_isError(endResult)) return endResult;
2733 return cSize + endResult;
2734}
2735
2736
Yann Collet19c10022016-07-28 01:25:46 +02002737static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002738 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002739 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002740 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002741 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002742{
Yann Collet3e21ec52016-09-06 15:36:19 +02002743 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
Yann Collet62470b42016-07-28 15:29:08 +02002744 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002745}
2746
Yann Collet21588e32016-03-30 16:50:44 +02002747size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2748 void* dst, size_t dstCapacity,
2749 const void* src, size_t srcSize,
2750 const void* dict,size_t dictSize,
2751 ZSTD_parameters params)
2752{
Yann Colletcf409a72016-09-26 16:41:05 +02002753 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02002754 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2755}
2756
Yann Colletd1b26842016-03-15 01:24:33 +01002757size_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 +01002758{
Yann Collet407a11f2016-11-03 15:52:01 -07002759 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02002760 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002761 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002762}
2763
Yann Colletd1b26842016-03-15 01:24:33 +01002764size_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 +01002765{
Yann Collet21588e32016-03-30 16:50:44 +02002766 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002767}
2768
Yann Colletd1b26842016-03-15 01:24:33 +01002769size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002770{
Yann Collet44fe9912015-10-29 22:02:40 +01002771 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002772 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002773 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002774 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002775 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002776 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 +01002777 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002778}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002779
Yann Colletfd416f12016-01-30 03:14:15 +01002780
Yann Collet81e13ef2016-06-07 00:51:51 +02002781/* ===== Dictionary API ===== */
2782
2783struct ZSTD_CDict_s {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002784 void* dictBuffer;
2785 const void* dictContent;
Yann Collet81e13ef2016-06-07 00:51:51 +02002786 size_t dictContentSize;
2787 ZSTD_CCtx* refContext;
David Lamda9d3b72016-08-29 09:03:12 -07002788}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
Yann Collet81e13ef2016-06-07 00:51:51 +02002789
Yann Colletd7c65892016-09-15 02:50:27 +02002790size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2791{
2792 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01002793 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02002794}
2795
Yann Collet1f57c2e2016-12-21 16:20:11 +01002796ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
2797 ZSTD_parameters params, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02002798{
Yann Collet23b6e052016-08-28 21:05:43 -07002799 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2800 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02002801
Yann Collet23b6e052016-08-28 21:05:43 -07002802 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002803 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2804
Yann Collet1f57c2e2016-12-21 16:20:11 +01002805 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07002806 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002807 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002808 return NULL;
2809 }
2810
Yann Collet1f57c2e2016-12-21 16:20:11 +01002811 if ((byReference) || (!dictBuffer) || (!dictSize)) {
2812 cdict->dictBuffer = NULL;
2813 cdict->dictContent = dictBuffer;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002814 } else {
2815 void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
Yann Collet4e5eea62016-12-21 16:44:35 +01002816 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002817 memcpy(internalBuffer, dictBuffer, dictSize);
2818 cdict->dictBuffer = internalBuffer;
2819 cdict->dictContent = internalBuffer;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002820 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002821
2822 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
Yann Collet81e13ef2016-06-07 00:51:51 +02002823 if (ZSTD_isError(errorCode)) {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002824 ZSTD_free(cdict->dictBuffer, customMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01002825 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002826 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002827 return NULL;
2828 } }
2829
Yann Collet81e13ef2016-06-07 00:51:51 +02002830 cdict->refContext = cctx;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002831 cdict->dictContentSize = dictSize;
Yann Collet81e13ef2016-06-07 00:51:51 +02002832 return cdict;
2833 }
2834}
2835
2836ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2837{
2838 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet07639052016-08-03 01:57:57 +02002839 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002840 params.fParams.contentSizeFlag = 1;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002841 return ZSTD_createCDict_advanced(dict, dictSize, 0, params, allocator);
2842}
2843
2844ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
2845{
2846 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2847 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
2848 params.fParams.contentSizeFlag = 1;
2849 return ZSTD_createCDict_advanced(dict, dictSize, 1, params, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02002850}
2851
2852size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2853{
Yann Collet23b6e052016-08-28 21:05:43 -07002854 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02002855 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07002856 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01002857 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002858 ZSTD_free(cdict, cMem);
2859 return 0;
2860 }
Yann Collet81e13ef2016-06-07 00:51:51 +02002861}
2862
Yann Collet95162342016-10-25 16:19:52 -07002863static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
2864 return ZSTD_getParamsFromCCtx(cdict->refContext);
2865}
2866
Yann Colletc5933482017-01-22 16:40:06 -08002867size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002868{
Yann Collet97b378a2016-09-21 17:20:19 +02002869 if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
Sean Purcell2db72492017-02-09 10:50:43 -08002870 else {
2871 ZSTD_parameters params = cdict->refContext->params;
2872 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
2873 CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, params, pledgedSrcSize));
2874 }
Yann Collet4cb21292016-09-15 14:54:07 +02002875 return 0;
2876}
2877
Yann Collet07639052016-08-03 01:57:57 +02002878/*! ZSTD_compress_usingCDict() :
2879* Compression using a digested Dictionary.
2880* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2881* Note that compression level is decided during dictionary creation */
Yann Collet4cb21292016-09-15 14:54:07 +02002882size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2883 void* dst, size_t dstCapacity,
2884 const void* src, size_t srcSize,
2885 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02002886{
Yann Collet4cb21292016-09-15 14:54:07 +02002887 CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize));
Yann Collet07639052016-08-03 01:57:57 +02002888
2889 if (cdict->refContext->params.fParams.contentSizeFlag==1) {
2890 cctx->params.fParams.contentSizeFlag = 1;
2891 cctx->frameContentSize = srcSize;
2892 }
2893
2894 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002895}
2896
2897
2898
Yann Collet104e5b02016-08-12 13:04:27 +02002899/* ******************************************************************
2900* Streaming
2901********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002902
2903typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
2904
2905struct ZSTD_CStream_s {
Yann Colletfa0c0972016-09-15 14:11:01 +02002906 ZSTD_CCtx* cctx;
Yann Collet95162342016-10-25 16:19:52 -07002907 ZSTD_CDict* cdictLocal;
2908 const ZSTD_CDict* cdict;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002909 char* inBuff;
2910 size_t inBuffSize;
2911 size_t inToCompress;
2912 size_t inBuffPos;
2913 size_t inBuffTarget;
2914 size_t blockSize;
2915 char* outBuff;
2916 size_t outBuffSize;
2917 size_t outBuffContentSize;
2918 size_t outBuffFlushedSize;
2919 ZSTD_cStreamStage stage;
2920 U32 checksum;
2921 U32 frameEnded;
Yann Collete795c8a2016-12-13 16:39:36 +01002922 U64 pledgedSrcSize;
2923 U64 inputProcessed;
Yann Colletee5b7252016-10-27 14:20:55 -07002924 ZSTD_parameters params;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002925 ZSTD_customMem customMem;
2926}; /* typedef'd to ZSTD_CStream within "zstd.h" */
2927
2928ZSTD_CStream* ZSTD_createCStream(void)
2929{
2930 return ZSTD_createCStream_advanced(defaultCustomMem);
2931}
2932
2933ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
2934{
2935 ZSTD_CStream* zcs;
2936
Yann Collet23b6e052016-08-28 21:05:43 -07002937 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2938 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002939
Yann Collet23b6e052016-08-28 21:05:43 -07002940 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002941 if (zcs==NULL) return NULL;
2942 memset(zcs, 0, sizeof(ZSTD_CStream));
2943 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
Yann Colletfa0c0972016-09-15 14:11:01 +02002944 zcs->cctx = ZSTD_createCCtx_advanced(customMem);
2945 if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002946 return zcs;
2947}
2948
2949size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2950{
2951 if (zcs==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -07002952 { ZSTD_customMem const cMem = zcs->customMem;
Yann Colletfa0c0972016-09-15 14:11:01 +02002953 ZSTD_freeCCtx(zcs->cctx);
Yann Collet95162342016-10-25 16:19:52 -07002954 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet23b6e052016-08-28 21:05:43 -07002955 ZSTD_free(zcs->inBuff, cMem);
2956 ZSTD_free(zcs->outBuff, cMem);
2957 ZSTD_free(zcs, cMem);
2958 return 0;
2959 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002960}
2961
2962
Yann Collet104e5b02016-08-12 13:04:27 +02002963/*====== Initialization ======*/
2964
2965size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
2966size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002967
Sean Purcell2db72492017-02-09 10:50:43 -08002968static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002969{
Yann Colletd564faa2016-12-18 21:39:15 +01002970 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 -07002971
2972 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
2973 else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
Yann Collet4cb21292016-09-15 14:54:07 +02002974
2975 zcs->inToCompress = 0;
2976 zcs->inBuffPos = 0;
2977 zcs->inBuffTarget = zcs->blockSize;
2978 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
2979 zcs->stage = zcss_load;
2980 zcs->frameEnded = 0;
Yann Collete795c8a2016-12-13 16:39:36 +01002981 zcs->pledgedSrcSize = pledgedSrcSize;
2982 zcs->inputProcessed = 0;
Yann Collet4cb21292016-09-15 14:54:07 +02002983 return 0; /* ready to go */
2984}
2985
Sean Purcell2db72492017-02-09 10:50:43 -08002986size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
2987{
2988
2989 zcs->params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
2990
2991 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
2992}
2993
Yann Collet5a0c8e22016-08-12 01:20:36 +02002994size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
2995 const void* dict, size_t dictSize,
2996 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2997{
2998 /* allocate buffers */
2999 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
3000 if (zcs->inBuffSize < neededInBuffSize) {
3001 zcs->inBuffSize = neededInBuffSize;
Yann Colletcf409a72016-09-26 16:41:05 +02003002 ZSTD_free(zcs->inBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003003 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003004 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
3005 }
3006 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
3007 }
3008 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
3009 zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
Yann Colletcf409a72016-09-26 16:41:05 +02003010 ZSTD_free(zcs->outBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003011 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003012 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
3013 }
3014
Sean Purcell57d423c2017-01-17 11:04:08 -08003015 if (dict && dictSize >= 8) {
Yann Colletee5b7252016-10-27 14:20:55 -07003016 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003017 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0, params, zcs->customMem);
Yann Colletee5b7252016-10-27 14:20:55 -07003018 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3019 zcs->cdict = zcs->cdictLocal;
3020 } else zcs->cdict = NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003021
Yann Collet5a0c8e22016-08-12 01:20:36 +02003022 zcs->checksum = params.fParams.checksumFlag > 0;
Yann Colletee5b7252016-10-27 14:20:55 -07003023 zcs->params = params;
Yann Collet4cb21292016-09-15 14:54:07 +02003024
Sean Purcell2db72492017-02-09 10:50:43 -08003025 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003026}
3027
Yann Collet95162342016-10-25 16:19:52 -07003028/* note : cdict must outlive compression session */
3029size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3030{
3031 ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
3032 size_t const initError = ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0);
3033 zcs->cdict = cdict;
Gregory Szorc7d6f4782017-01-14 17:44:54 -08003034 zcs->cctx->dictID = params.fParams.noDictIDFlag ? 0 : cdict->refContext->dictID;
Yann Collet95162342016-10-25 16:19:52 -07003035 return initError;
3036}
3037
Yann Collet5a0c8e22016-08-12 01:20:36 +02003038size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3039{
3040 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
3041 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);
3042}
3043
Yann Collete795c8a2016-12-13 16:39:36 +01003044size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3045{
Yann Colletd564faa2016-12-18 21:39:15 +01003046 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
3047 if (pledgedSrcSize) params.fParams.contentSizeFlag = 1;
Yann Collete795c8a2016-12-13 16:39:36 +01003048 return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);
3049}
3050
Yann Collet5a0c8e22016-08-12 01:20:36 +02003051size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3052{
3053 return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel);
3054}
3055
Yann Collet70e3b312016-08-23 01:18:06 +02003056size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02003057{
Yann Colletd7c65892016-09-15 02:50:27 +02003058 if (zcs==NULL) return 0; /* support sizeof on NULL */
Yann Collet335ad5d2016-10-25 17:47:02 -07003059 return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize;
Yann Colletcb327632016-08-23 00:30:31 +02003060}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003061
Yann Collet104e5b02016-08-12 13:04:27 +02003062/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003063
3064typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
3065
3066MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3067{
3068 size_t const length = MIN(dstCapacity, srcSize);
3069 memcpy(dst, src, length);
3070 return length;
3071}
3072
3073static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3074 void* dst, size_t* dstCapacityPtr,
3075 const void* src, size_t* srcSizePtr,
3076 ZSTD_flush_e const flush)
3077{
3078 U32 someMoreWork = 1;
3079 const char* const istart = (const char*)src;
3080 const char* const iend = istart + *srcSizePtr;
3081 const char* ip = istart;
3082 char* const ostart = (char*)dst;
3083 char* const oend = ostart + *dstCapacityPtr;
3084 char* op = ostart;
3085
3086 while (someMoreWork) {
3087 switch(zcs->stage)
3088 {
3089 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
3090
3091 case zcss_load:
3092 /* complete inBuffer */
3093 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3094 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
3095 zcs->inBuffPos += loaded;
3096 ip += loaded;
3097 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
3098 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
3099 } }
3100 /* compress current block (note : this stage cannot be stopped in the middle) */
3101 { void* cDst;
3102 size_t cSize;
3103 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3104 size_t oSize = oend-op;
3105 if (oSize >= ZSTD_compressBound(iSize))
3106 cDst = op; /* compress directly into output buffer (avoid flush stage) */
3107 else
3108 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3109 cSize = (flush == zsf_end) ?
Yann Colletfa0c0972016-09-15 14:11:01 +02003110 ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
3111 ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003112 if (ZSTD_isError(cSize)) return cSize;
3113 if (flush == zsf_end) zcs->frameEnded = 1;
3114 /* prepare next block */
3115 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3116 if (zcs->inBuffTarget > zcs->inBuffSize)
3117 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
3118 zcs->inToCompress = zcs->inBuffPos;
3119 if (cDst == op) { op += cSize; break; } /* no need to flush */
3120 zcs->outBuffContentSize = cSize;
3121 zcs->outBuffFlushedSize = 0;
3122 zcs->stage = zcss_flush; /* pass-through to flush stage */
3123 }
3124
3125 case zcss_flush:
3126 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3127 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3128 op += flushed;
3129 zcs->outBuffFlushedSize += flushed;
3130 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
3131 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3132 zcs->stage = zcss_load;
3133 break;
3134 }
3135
3136 case zcss_final:
3137 someMoreWork = 0; /* do nothing */
3138 break;
3139
3140 default:
3141 return ERROR(GENERIC); /* impossible */
3142 }
3143 }
3144
3145 *srcSizePtr = ip - istart;
3146 *dstCapacityPtr = op - ostart;
Yann Collete795c8a2016-12-13 16:39:36 +01003147 zcs->inputProcessed += *srcSizePtr;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003148 if (zcs->frameEnded) return 0;
3149 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3150 if (hintInSize==0) hintInSize = zcs->blockSize;
3151 return hintInSize;
3152 }
3153}
3154
Yann Collet53e17fb2016-08-17 01:39:22 +02003155size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003156{
Yann Collet53e17fb2016-08-17 01:39:22 +02003157 size_t sizeRead = input->size - input->pos;
3158 size_t sizeWritten = output->size - output->pos;
3159 size_t const result = ZSTD_compressStream_generic(zcs,
3160 (char*)(output->dst) + output->pos, &sizeWritten,
3161 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3162 input->pos += sizeRead;
3163 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003164 return result;
3165}
3166
3167
Yann Collet104e5b02016-08-12 13:04:27 +02003168/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003169
3170/*! ZSTD_flushStream() :
3171* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003172size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003173{
3174 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003175 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02003176 size_t const result = ZSTD_compressStream_generic(zcs,
Yann Collet95d07d72016-09-06 16:38:51 +02003177 (char*)(output->dst) + output->pos, &sizeWritten,
3178 &srcSize, &srcSize, /* use a valid src address instead of NULL */
Yann Colletc4119022016-08-17 01:50:54 +02003179 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003180 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003181 if (ZSTD_isError(result)) return result;
3182 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3183}
3184
3185
Yann Collet53e17fb2016-08-17 01:39:22 +02003186size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003187{
Yann Collet53e17fb2016-08-17 01:39:22 +02003188 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3189 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003190 BYTE* op = ostart;
3191
Yann Collete795c8a2016-12-13 16:39:36 +01003192 if ((zcs->pledgedSrcSize) && (zcs->inputProcessed != zcs->pledgedSrcSize))
3193 return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */
3194
Yann Collet5a0c8e22016-08-12 01:20:36 +02003195 if (zcs->stage != zcss_final) {
3196 /* flush whatever remains */
3197 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003198 size_t sizeWritten = output->size - output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003199 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
3200 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3201 op += sizeWritten;
3202 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003203 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003204 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3205 }
3206 /* create epilogue */
3207 zcs->stage = zcss_final;
3208 zcs->outBuffContentSize = !notEnded ? 0 :
Yann Colletfa0c0972016-09-15 14:11:01 +02003209 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 +02003210 }
3211
3212 /* flush epilogue */
3213 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3214 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3215 op += flushed;
3216 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003217 output->pos += op-ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003218 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3219 return toFlush - flushed;
3220 }
3221}
3222
3223
3224
Yann Collet70e8c382016-02-10 13:37:52 +01003225/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003226
Yann Collet236d94f2016-05-18 12:06:33 +02003227#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003228#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003229int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003230
Yann Collet3b719252016-03-30 19:48:05 +02003231static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003232{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003233 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003234 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003235 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3236 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003237 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3238 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003239 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3240 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3241 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003242 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003243 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3244 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3245 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3246 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3247 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3248 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3249 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3250 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003251 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
3252 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
3253 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003254 { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */
3255 { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */
3256 { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003257},
3258{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003259 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003260 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003261 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003262 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3263 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3264 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3265 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3266 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3267 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3268 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3269 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3270 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3271 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3272 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3273 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003274 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003275 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3276 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3277 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003278 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3279 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003280 { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/
3281 { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/
3282 { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003283},
3284{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003285 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003286 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3287 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3288 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3289 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3290 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3291 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3292 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3293 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3294 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3295 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3296 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3297 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3298 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3299 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003300 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3301 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3302 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3303 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3304 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3305 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003306 { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/
3307 { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/
3308 { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003309},
3310{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003311 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003312 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003313 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003314 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3315 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3316 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3317 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3318 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3319 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3320 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3321 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003322 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3323 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3324 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3325 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3326 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3327 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3328 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3329 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3330 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3331 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003332 { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/
3333 { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/
3334 { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003335},
3336};
3337
Yann Collet236d94f2016-05-18 12:06:33 +02003338/*! ZSTD_getCParams() :
3339* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3340* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003341ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003342{
Yann Collet15354142016-04-04 04:22:53 +02003343 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003344 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003345 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003346 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003347 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003348 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003349 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003350 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3351 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003352 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003353 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3354 }
Yann Collet70d13012016-06-01 18:45:34 +02003355 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003356 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003357}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003358
3359/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003360* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003361* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003362ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003363 ZSTD_parameters params;
3364 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3365 memset(&params, 0, sizeof(params));
3366 params.cParams = cParams;
3367 return params;
3368}