blob: 91e81d9c236512e622cb92a6ebaa9378205ee4c2 [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 Collet731ef162016-07-27 21:05:12 +020065 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +020066 U32 rep[ZSTD_REP_NUM];
Yann Colletb459aad2017-01-19 17:33:37 -080067 U32 repToConfirm[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +020068 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +010069 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +010070 void* workSpace;
71 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +010072 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +020073 U64 frameContentSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +020074 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +020075 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +010076
Yann Collet712def92015-10-29 18:41:45 +010077 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +010078 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +010079 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +020080 U32* chainTable;
Yann Colletb923f652016-01-26 03:14:20 +010081 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +010082 U32 flagStaticTables;
Yann Collet731ef162016-07-27 21:05:12 +020083 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
84 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
85 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Collete928f7e2016-12-01 16:13:35 -080086 unsigned tmpCounters[1024];
Yann Colletf3eca252015-10-22 15:31:46 +010087};
88
Yann Collet5be2dd22015-11-11 13:43:58 +010089ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +010090{
inikep3763c772016-06-03 13:28:20 +020091 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +020092}
93
94ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
95{
Yann Collet69c2cdb2016-07-14 16:52:45 +020096 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +020097
Yann Collet23b6e052016-08-28 21:05:43 -070098 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
99 if (!customMem.customAlloc || !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200100
Yann Collet23b6e052016-08-28 21:05:43 -0700101 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200102 if (!cctx) return NULL;
103 memset(cctx, 0, sizeof(ZSTD_CCtx));
Yann Colletbb002742017-01-25 16:25:38 -0800104 cctx->customMem = customMem;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200105 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100106}
107
Yann Collet5be2dd22015-11-11 13:43:58 +0100108size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100109{
inikep36403962016-06-03 16:36:50 +0200110 if (cctx==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -0700111 ZSTD_free(cctx->workSpace, cctx->customMem);
112 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100113 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100114}
115
Yann Collet70e3b312016-08-23 01:18:06 +0200116size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200117{
Yann Colletd7c65892016-09-15 02:50:27 +0200118 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet3ae543c2016-07-11 03:12:17 +0200119 return sizeof(*cctx) + cctx->workSpaceSize;
120}
121
Yann Colletbb002742017-01-25 16:25:38 -0800122size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
123{
124 switch(param)
125 {
Yann Collet06e76972017-01-25 16:39:03 -0800126 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800127 default: return ERROR(parameter_unknown);
128 }
129}
130
Yann Colletb44be742016-03-26 20:52:14 +0100131const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100132{
Yann Colletb44be742016-03-26 20:52:14 +0100133 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100134}
135
Yann Collet95162342016-10-25 16:19:52 -0700136static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx)
137{
138 return cctx->params;
139}
140
Yann Collet59d70632015-11-04 12:05:27 +0100141
Yann Collet21588e32016-03-30 16:50:44 +0200142/** ZSTD_checkParams() :
143 ensure param values remain within authorized range.
144 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200145size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200146{
Yann Colletac8bace2016-09-07 14:54:23 +0200147# define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
Yann Collet15354142016-04-04 04:22:53 +0200148 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200149 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200150 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
151 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Colletedbcd9f2016-09-06 14:30:57 +0200152 { U32 const searchLengthMin = ((cParams.strategy == ZSTD_fast) | (cParams.strategy == ZSTD_greedy)) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN;
Yann Collet3b719252016-03-30 19:48:05 +0200153 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
154 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
155 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200156 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200157 return 0;
158}
159
160
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100161/** ZSTD_cycleLog() :
162 * condition for correct operation : hashLog > 1 */
163static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
164{
165 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
166 return hashLog - btScale;
167}
168
Yann Collet70d13012016-06-01 18:45:34 +0200169/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200170 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200171 mostly downsizing to reduce memory consumption and initialization.
172 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
173 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200174 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200175ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100176{
Yann Collet70d13012016-06-01 18:45:34 +0200177 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100178
Yann Collet70e45772016-03-19 18:08:32 +0100179 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200180 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
181 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200182 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200183 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200184 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200185 } }
Yann Collet70d13012016-06-01 18:45:34 +0200186 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100187 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
188 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
189 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100190
Yann Collet70d13012016-06-01 18:45:34 +0200191 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200192
193 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100194}
195
196
Yann Collet88472382016-07-14 17:05:38 +0200197size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100198{
Yann Collet731ef162016-07-27 21:05:12 +0200199 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
200 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
201 size_t const maxNbSeq = blockSize / divider;
202 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200203
Yann Collet731ef162016-07-27 21:05:12 +0200204 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
205 size_t const hSize = ((size_t)1) << cParams.hashLog;
206 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
207 size_t const h3Size = ((size_t)1) << hashLog3;
208 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200209
210 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
211 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
212 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200213 + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Collet3ae543c2016-07-11 03:12:17 +0200214
215 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100216}
217
Yann Colleta7737f62016-09-06 09:44:59 +0200218
219static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
220{
221 return (param1.cParams.hashLog == param2.cParams.hashLog)
222 & (param1.cParams.chainLog == param2.cParams.chainLog)
Yann Colletedbcd9f2016-09-06 14:30:57 +0200223 & (param1.cParams.strategy == param2.cParams.strategy)
224 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3));
Yann Colleta7737f62016-09-06 09:44:59 +0200225}
226
227/*! ZSTD_continueCCtx() :
228 reuse CCtx without reset (note : requires no dictionary) */
229static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
230{
231 U32 const end = (U32)(cctx->nextSrc - cctx->base);
232 cctx->params = params;
233 cctx->frameContentSize = frameContentSize;
234 cctx->lowLimit = end;
235 cctx->dictLimit = end;
236 cctx->nextToUpdate = end+1;
237 cctx->stage = ZSTDcs_init;
238 cctx->dictID = 0;
239 cctx->loadedDictEnd = 0;
240 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200241 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
242 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200243 return 0;
244}
245
246typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
247
Yann Collet27caf2a2016-04-01 15:48:48 +0200248/*! ZSTD_resetCCtx_advanced() :
Yann Colleta7737f62016-09-06 09:44:59 +0200249 note : 'params' must be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100250static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletea2ecdc2016-07-14 22:43:12 +0200251 ZSTD_parameters params, U64 frameContentSize,
Yann Collet4cb21292016-09-15 14:54:07 +0200252 ZSTD_compResetPolicy_e const crp)
Yann Colleta7737f62016-09-06 09:44:59 +0200253{
Yann Collet4cb21292016-09-15 14:54:07 +0200254 if (crp == ZSTDcrp_continue)
Yann Colleta7737f62016-09-06 09:44:59 +0200255 if (ZSTD_equivalentParams(params, zc->params))
256 return ZSTD_continueCCtx(zc, params, frameContentSize);
inikep87d4f3d2016-03-02 15:56:24 +0100257
Yann Colleta7737f62016-09-06 09:44:59 +0200258 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
259 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
260 size_t const maxNbSeq = blockSize / divider;
261 size_t const tokenSpace = blockSize + 11*maxNbSeq;
262 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
263 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
264 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
265 size_t const h3Size = ((size_t)1) << hashLog3;
266 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
267 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100268
Yann Colleta7737f62016-09-06 09:44:59 +0200269 /* Check if workSpace is large enough, alloc a new one if needed */
270 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
271 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
272 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200273 + (((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200274 if (zc->workSpaceSize < neededSpace) {
275 ZSTD_free(zc->workSpace, zc->customMem);
276 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
277 if (zc->workSpace == NULL) return ERROR(memory_allocation);
278 zc->workSpaceSize = neededSpace;
279 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100280
Yann Colleta7737f62016-09-06 09:44:59 +0200281 if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */
282 XXH64_reset(&zc->xxhState, 0);
283 zc->hashLog3 = hashLog3;
284 zc->hashTable = (U32*)(zc->workSpace);
285 zc->chainTable = zc->hashTable + hSize;
286 zc->hashTable3 = zc->chainTable + chainSize;
287 ptr = zc->hashTable3 + h3Size;
288 zc->hufTable = (HUF_CElt*)ptr;
289 zc->flagStaticTables = 0;
290 ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
Yann Collet70e8c382016-02-10 13:37:52 +0100291
Yann Colleta7737f62016-09-06 09:44:59 +0200292 zc->nextToUpdate = 1;
293 zc->nextSrc = NULL;
294 zc->base = NULL;
295 zc->dictBase = NULL;
296 zc->dictLimit = 0;
297 zc->lowLimit = 0;
298 zc->params = params;
299 zc->blockSize = blockSize;
300 zc->frameContentSize = frameContentSize;
301 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
302
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200303 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
Yann Colleta7737f62016-09-06 09:44:59 +0200304 zc->seqStore.litFreq = (U32*)ptr;
305 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
306 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
307 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
308 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
309 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
310 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
311 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
312 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
313 zc->seqStore.litLengthSum = 0;
314 }
315 zc->seqStore.sequencesStart = (seqDef*)ptr;
316 ptr = zc->seqStore.sequencesStart + maxNbSeq;
317 zc->seqStore.llCode = (BYTE*) ptr;
318 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
319 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
320 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
321
322 zc->stage = ZSTDcs_init;
323 zc->dictID = 0;
324 zc->loadedDictEnd = 0;
325
326 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100327 }
Yann Colletf3eca252015-10-22 15:31:46 +0100328}
329
Yann Collet32dfae62017-01-19 10:32:55 -0800330/* ZSTD_invalidateRepCodes() :
331 * ensures next compression will not use repcodes from previous block.
332 * Note : only works with regular variant;
333 * do not use with extDict variant ! */
334void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
335 int i;
336 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
337}
Yann Collet083fcc82015-10-25 14:06:35 +0100338
Yann Collet370b08e2016-03-08 00:03:59 +0100339/*! ZSTD_copyCCtx() :
340* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet731ef162016-07-27 21:05:12 +0200341* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100342* @return : 0, or an error code */
Yann Collet97b378a2016-09-21 17:20:19 +0200343size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100344{
Yann Collet731ef162016-07-27 21:05:12 +0200345 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100346
Sean Purcell2db72492017-02-09 10:50:43 -0800347
inikep28669512016-06-02 13:04:18 +0200348 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Sean Purcell2db72492017-02-09 10:50:43 -0800349 { ZSTD_parameters params = srcCCtx->params;
350 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
351 ZSTD_resetCCtx_advanced(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset);
352 }
Yann Collet7b51a292016-01-26 15:58:49 +0100353
354 /* copy tables */
Yann Collet731ef162016-07-27 21:05:12 +0200355 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
356 size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
357 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
358 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100359 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
360 }
Yann Collet7b51a292016-01-26 15:58:49 +0100361
Yann Colletc46fb922016-05-29 05:01:04 +0200362 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100363 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
364 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
365 dstCCtx->nextSrc = srcCCtx->nextSrc;
366 dstCCtx->base = srcCCtx->base;
367 dstCCtx->dictBase = srcCCtx->dictBase;
368 dstCCtx->dictLimit = srcCCtx->dictLimit;
369 dstCCtx->lowLimit = srcCCtx->lowLimit;
370 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200371 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100372
Yann Colletfb810d62016-01-28 00:18:06 +0100373 /* copy entropy tables */
374 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100375 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100376 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100377 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
378 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
379 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
380 }
Yann Collet7b51a292016-01-26 15:58:49 +0100381
382 return 0;
383}
384
385
Yann Colletecabfe32016-03-20 16:20:06 +0100386/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100387* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100388static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100389{
Yann Colletecabfe32016-03-20 16:20:06 +0100390 U32 u;
391 for (u=0 ; u < size ; u++) {
392 if (table[u] < reducerValue) table[u] = 0;
393 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100394 }
395}
396
Yann Colletecabfe32016-03-20 16:20:06 +0100397/*! ZSTD_reduceIndex() :
398* rescale all indexes to avoid future overflow (indexes are U32) */
399static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
400{
Yann Collet731ef162016-07-27 21:05:12 +0200401 { U32 const hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100402 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
403
Yann Collet731ef162016-07-27 21:05:12 +0200404 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200405 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100406
Yann Collet731ef162016-07-27 21:05:12 +0200407 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100408 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
409}
410
Yann Collet89db5e02015-11-13 11:27:46 +0100411
Yann Collet863ec402016-01-28 17:56:33 +0100412/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100413* Block entropic compression
414*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100415
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200416/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100417
Yann Colletd1b26842016-03-15 01:24:33 +0100418size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100419{
Yann Colletd1b26842016-03-15 01:24:33 +0100420 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200421 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
422 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100423 return ZSTD_blockHeaderSize+srcSize;
424}
425
426
Yann Colletd1b26842016-03-15 01:24:33 +0100427static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100428{
429 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200430 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100431
Yann Colletd1b26842016-03-15 01:24:33 +0100432 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100433
Yann Collet59d1f792016-01-23 19:28:41 +0100434 switch(flSize)
435 {
436 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200437 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100438 break;
439 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200440 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100441 break;
442 default: /*note : should not be necessary : flSize is within {1,2,3} */
443 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200444 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100445 break;
446 }
447
448 memcpy(ostart + flSize, src, srcSize);
449 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100450}
451
Yann Colletd1b26842016-03-15 01:24:33 +0100452static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100453{
454 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200455 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100456
Yann Collet198e6aa2016-07-20 20:12:24 +0200457 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100458
459 switch(flSize)
460 {
461 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200462 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100463 break;
464 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200465 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100466 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100467 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100468 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200469 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100470 break;
471 }
472
473 ostart[flSize] = *(const BYTE*)src;
474 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100475}
476
Yann Collet59d1f792016-01-23 19:28:41 +0100477
Yann Colleta5c2c082016-03-20 01:09:18 +0100478static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100479
Yann Colletb923f652016-01-26 03:14:20 +0100480static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100481 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100482 const void* src, size_t srcSize)
483{
Yann Colleta910dc82016-03-18 12:37:45 +0100484 size_t const minGain = ZSTD_minGain(srcSize);
485 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200486 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100487 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200488 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100489 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100490
Yann Collet14983e72015-11-11 21:38:21 +0100491
Yann Colleta5c2c082016-03-20 01:09:18 +0100492 /* small ? don't even attempt compression (speed opt) */
493# define LITERAL_NOENTROPY 63
494 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
495 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
496 }
497
498 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100499 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200500 hType = set_repeat;
Yann Colletb923f652016-01-26 03:14:20 +0100501 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100502 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100503 } else {
Yann Colleta0d742b2016-12-01 17:47:30 -0800504 cLitSize = singleStream ? HUF_compress1X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters))
505 : HUF_compress4X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters));
Yann Colletb923f652016-01-26 03:14:20 +0100506 }
Yann Collet14983e72015-11-11 21:38:21 +0100507
Yann Collet98c88842016-07-15 16:12:38 +0200508 if ((cLitSize==0) | (cLitSize >= srcSize - minGain))
Yann Colleta910dc82016-03-18 12:37:45 +0100509 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
510 if (cLitSize==1)
511 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100512
513 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100514 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100515 {
Yann Collet59d1f792016-01-23 19:28:41 +0100516 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200517 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200518 MEM_writeLE24(ostart, lhc);
519 break;
520 }
Yann Collet59d1f792016-01-23 19:28:41 +0100521 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200522 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200523 MEM_writeLE32(ostart, lhc);
524 break;
525 }
Yann Colleta910dc82016-03-18 12:37:45 +0100526 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100527 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200528 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200529 MEM_writeLE32(ostart, lhc);
530 ostart[4] = (BYTE)(cLitSize >> 10);
531 break;
532 }
Yann Collet14983e72015-11-11 21:38:21 +0100533 }
Yann Colleta910dc82016-03-18 12:37:45 +0100534 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100535}
536
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200537static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
538 8, 9, 10, 11, 12, 13, 14, 15,
539 16, 16, 17, 17, 18, 18, 19, 19,
540 20, 20, 20, 20, 21, 21, 21, 21,
541 22, 22, 22, 22, 22, 22, 22, 22,
542 23, 23, 23, 23, 23, 23, 23, 23,
543 24, 24, 24, 24, 24, 24, 24, 24,
544 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100545
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200546static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
547 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
548 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
549 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
550 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
551 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
552 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
553 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200554
555
556void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100557{
Yann Colleted57d852016-07-29 21:22:17 +0200558 BYTE const LL_deltaCode = 19;
559 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200560 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200561 BYTE* const llCodeTable = seqStorePtr->llCode;
562 BYTE* const ofCodeTable = seqStorePtr->ofCode;
563 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200564 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200565 U32 u;
566 for (u=0; u<nbSeq; u++) {
567 U32 const llv = sequences[u].litLength;
568 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200569 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200570 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200571 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200572 }
Yann Colleted57d852016-07-29 21:22:17 +0200573 if (seqStorePtr->longLengthID==1)
574 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
575 if (seqStorePtr->longLengthID==2)
576 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100577}
578
579
Yann Colletb923f652016-01-26 03:14:20 +0100580size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100581 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100582 size_t srcSize)
583{
Yann Colletb923f652016-01-26 03:14:20 +0100584 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100585 U32 count[MaxSeq+1];
586 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100587 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
588 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
589 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100590 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200591 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200592 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
593 const BYTE* const llCodeTable = seqStorePtr->llCode;
594 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100595 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100596 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100597 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200598 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100599 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -0800600 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +0100601
Yann Collet14983e72015-11-11 21:38:21 +0100602 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100603 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100604 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100605 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100606 if (ZSTD_isError(cSize)) return cSize;
607 op += cSize;
608 }
609
610 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100611 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100612 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
613 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
614 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100615 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100616
Yann Colletbe391432016-03-22 23:19:28 +0100617 /* seqHead : flags for FSE encoding type */
618 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100619
Yann Colletfb810d62016-01-28 00:18:06 +0100620#define MIN_SEQ_FOR_DYNAMIC_FSE 64
621#define MAX_SEQ_FOR_STATIC_FSE 1000
622
Yann Colletb44be742016-03-26 20:52:14 +0100623 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +0200624 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +0100625
Yann Collet14983e72015-11-11 21:38:21 +0100626 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100627 { U32 max = MaxLL;
Yann Collete928f7e2016-12-01 16:13:35 -0800628 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100629 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
630 *op++ = llCodeTable[0];
631 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200632 LLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100633 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200634 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100635 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800636 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200637 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100638 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100639 size_t nbSeq_1 = nbSeq;
640 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
641 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
642 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100643 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
644 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
645 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800646 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200647 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100648 } }
Yann Collet14983e72015-11-11 21:38:21 +0100649
Yann Colletb44be742016-03-26 20:52:14 +0100650 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100651 { U32 max = MaxOff;
Yann Collete928f7e2016-12-01 16:13:35 -0800652 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100653 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100654 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100655 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200656 Offtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100657 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200658 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +0200659 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800660 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200661 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100662 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100663 size_t nbSeq_1 = nbSeq;
664 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100665 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100666 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100667 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
668 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
669 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800670 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200671 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100672 } }
673
Yann Collet14983e72015-11-11 21:38:21 +0100674 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100675 { U32 max = MaxML;
Yann Collete928f7e2016-12-01 16:13:35 -0800676 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100677 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100678 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100679 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200680 MLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100681 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200682 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100683 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800684 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200685 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100686 } else {
687 size_t nbSeq_1 = nbSeq;
688 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
689 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
690 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
691 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
692 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
693 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800694 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200695 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100696 } }
Yann Collet14983e72015-11-11 21:38:21 +0100697
Yann Colletbe391432016-03-22 23:19:28 +0100698 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100699 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100700
701 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100702 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100703 FSE_CState_t stateMatchLength;
704 FSE_CState_t stateOffsetBits;
705 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100706
Yann Collet95d07d72016-09-06 16:38:51 +0200707 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100708
Yann Collet597847a2016-03-20 19:14:22 +0100709 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100710 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100711 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100712 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +0200713 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100714 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200715 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100716 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200717 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100718 BIT_flushBits(&blockStream);
719
Yann Colletfadda6c2016-03-22 12:14:26 +0100720 { size_t n;
721 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +0200722 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200723 BYTE const ofCode = ofCodeTable[n];
724 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200725 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +0200726 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200727 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +0100728 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100729 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
730 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
731 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
732 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200733 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100734 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +0200735 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100736 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200737 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100738 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200739 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
Yann Colletb9151402016-03-26 17:18:11 +0100740 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100741 } }
Yann Collet14983e72015-11-11 21:38:21 +0100742
743 FSE_flushCState(&blockStream, &stateMatchLength);
744 FSE_flushCState(&blockStream, &stateOffsetBits);
745 FSE_flushCState(&blockStream, &stateLitLength);
746
Yann Colletb9151402016-03-26 17:18:11 +0100747 { size_t const streamSize = BIT_closeCStream(&blockStream);
748 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
749 op += streamSize;
750 } }
Yann Collet14983e72015-11-11 21:38:21 +0100751
752 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100753_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100754 { size_t const minGain = ZSTD_minGain(srcSize);
755 size_t const maxCSize = srcSize - minGain;
756 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100757
Yann Collet4266c0a2016-06-14 01:49:25 +0200758 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -0800759 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +0200760
Yann Collet5054ee02015-11-23 13:34:21 +0100761 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100762}
763
764
Yann Colletbb002742017-01-25 16:25:38 -0800765#if 0 /* for debug */
766# define STORESEQ_DEBUG
767#include <stdio.h> /* fprintf */
768U32 g_startDebug = 0;
769const BYTE* g_start = NULL;
770#endif
771
Yann Collet95cd0c22016-03-08 18:24:21 +0100772/*! ZSTD_storeSeq() :
773 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
774 `offsetCode` : distance to match, or 0 == repCode.
775 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100776*/
Yann Colletd57dffb2016-07-03 01:48:26 +0200777MEM_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 +0100778{
Yann Colletbb002742017-01-25 16:25:38 -0800779#ifdef STORESEQ_DEBUG
780 if (g_startDebug) {
781 const U32 pos = (U32)((const BYTE*)literals - g_start);
782 if (g_start==NULL) g_start = (const BYTE*)literals;
783 if ((pos > 1895000) && (pos < 1895300))
784 fprintf(stderr, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
785 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
786 }
Yann Collet14983e72015-11-11 21:38:21 +0100787#endif
Yann Collet14983e72015-11-11 21:38:21 +0100788 /* copy Literals */
789 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
790 seqStorePtr->lit += litLength;
791
792 /* literal Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200793 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
794 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100795
796 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200797 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100798
799 /* match Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200800 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
801 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +0200802
Yann Colletc0ce4f12016-07-30 00:55:13 +0200803 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +0100804}
805
806
Yann Collet7d360282016-02-12 00:07:30 +0100807/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100808* Match length counter
809***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100810static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100811{
Yann Collet863ec402016-01-28 17:56:33 +0100812 if (MEM_isLittleEndian()) {
813 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100814# if defined(_MSC_VER) && defined(_WIN64)
815 unsigned long r = 0;
816 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100817 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100818# elif defined(__GNUC__) && (__GNUC__ >= 3)
819 return (__builtin_ctzll((U64)val) >> 3);
820# else
821 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 };
822 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
823# endif
Yann Collet863ec402016-01-28 17:56:33 +0100824 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100825# if defined(_MSC_VER)
826 unsigned long r=0;
827 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100828 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100829# elif defined(__GNUC__) && (__GNUC__ >= 3)
830 return (__builtin_ctz((U32)val) >> 3);
831# else
832 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 };
833 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
834# endif
835 }
Yann Collet863ec402016-01-28 17:56:33 +0100836 } else { /* Big Endian CPU */
837 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100838# if defined(_MSC_VER) && defined(_WIN64)
839 unsigned long r = 0;
840 _BitScanReverse64( &r, val );
841 return (unsigned)(r>>3);
842# elif defined(__GNUC__) && (__GNUC__ >= 3)
843 return (__builtin_clzll(val) >> 3);
844# else
845 unsigned r;
846 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
847 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
848 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
849 r += (!val);
850 return r;
851# endif
Yann Collet863ec402016-01-28 17:56:33 +0100852 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100853# if defined(_MSC_VER)
854 unsigned long r = 0;
855 _BitScanReverse( &r, (unsigned long)val );
856 return (unsigned)(r>>3);
857# elif defined(__GNUC__) && (__GNUC__ >= 3)
858 return (__builtin_clz((U32)val) >> 3);
859# else
860 unsigned r;
861 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
862 r += (!val);
863 return r;
864# endif
Yann Collet863ec402016-01-28 17:56:33 +0100865 } }
Yann Collet14983e72015-11-11 21:38:21 +0100866}
867
868
Yann Colleta436a522016-06-20 23:34:04 +0200869static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100870{
871 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +0200872 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +0100873
Yann Colleta436a522016-06-20 23:34:04 +0200874 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +0200875 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100876 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
877 pIn += ZSTD_NbCommonBytes(diff);
878 return (size_t)(pIn - pStart);
879 }
Yann Collet14983e72015-11-11 21:38:21 +0100880 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
881 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
882 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
883 return (size_t)(pIn - pStart);
884}
885
Yann Collet04b12d82016-02-11 06:23:24 +0100886/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100887* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100888* convention : on reaching mEnd, match count continue starting from iStart
889*/
890static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
891{
Yann Collet7591a7f2016-05-20 11:44:43 +0200892 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +0200893 size_t const matchLength = ZSTD_count(ip, match, vEnd);
894 if (match + matchLength != mEnd) return matchLength;
895 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +0100896}
897
Yann Collet14983e72015-11-11 21:38:21 +0100898
Yann Collet863ec402016-01-28 17:56:33 +0100899/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100900* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100901***************************************/
inikepcc52a972016-02-19 10:09:35 +0100902static const U32 prime3bytes = 506832829U;
903static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Colletd4f4e582016-06-27 01:31:35 +0200904MEM_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 +0100905
Yann Collet4b100f42015-10-30 15:49:48 +0100906static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100907static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100908static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100909
Yann Collet4b100f42015-10-30 15:49:48 +0100910static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100911static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100912static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100913
914static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100915static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100916static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100917
Yann Collet14983e72015-11-11 21:38:21 +0100918static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100919static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100920static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100921
Yann Collet45dc3562016-07-12 09:47:31 +0200922static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
923static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
924static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
925
Yann Collet5be2dd22015-11-11 13:43:58 +0100926static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100927{
928 switch(mls)
929 {
930 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100931 case 4: return ZSTD_hash4Ptr(p, hBits);
932 case 5: return ZSTD_hash5Ptr(p, hBits);
933 case 6: return ZSTD_hash6Ptr(p, hBits);
934 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +0200935 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100936 }
937}
Yann Collet2acb5d32015-10-29 16:49:43 +0100938
Yann Collet863ec402016-01-28 17:56:33 +0100939
Yann Collet2ce49232016-02-02 14:36:49 +0100940/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100941* Fast Scan
942***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100943static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
944{
945 U32* const hashTable = zc->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200946 U32 const hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +0100947 const BYTE* const base = zc->base;
948 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +0200949 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +0100950 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +0100951
Yann Colletfb810d62016-01-28 00:18:06 +0100952 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100953 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +0100954 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +0100955 }
956}
957
958
Yann Collet1f44b3f2015-11-05 17:32:18 +0100959FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +0200960void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +0200961 const void* src, size_t srcSize,
962 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100963{
Yann Collet4266c0a2016-06-14 01:49:25 +0200964 U32* const hashTable = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200965 U32 const hBits = cctx->params.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +0200966 seqStore_t* seqStorePtr = &(cctx->seqStore);
967 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100968 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100969 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100970 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +0200971 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +0200972 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100973 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +0200974 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +0200975 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
976 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100977
Yann Collet1f44b3f2015-11-05 17:32:18 +0100978 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +0200979 ip += (ip==lowest);
980 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +0200981 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
982 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +0200983 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100984
985 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +0200986 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +0200987 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +0200988 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
989 U32 const current = (U32)(ip-base);
990 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +0100991 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +0100992 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100993
Yann Collet280f9a82016-08-08 00:44:00 +0200994 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +0200995 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +0100996 ip++;
Yann Colleta436a522016-06-20 23:34:04 +0200997 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
998 } else {
Yann Collet92d75662016-07-03 01:10:53 +0200999 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001000 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001001 ip += ((ip-anchor) >> g_searchStrength) + 1;
1002 continue;
1003 }
Yann Collet45dc3562016-07-12 09:47:31 +02001004 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001005 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001006 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001007 offset_2 = offset_1;
1008 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001009
Yann Colleta436a522016-06-20 23:34:04 +02001010 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001011 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001012
Yann Collet402fdcf2015-11-20 12:46:08 +01001013 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001014 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001015 anchor = ip;
1016
Yann Colletfb810d62016-01-28 00:18:06 +01001017 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001018 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001019 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 +01001020 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1021 /* check immediate repcode */
1022 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001023 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001024 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001025 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001026 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001027 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001028 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001029 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1030 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001031 anchor = ip;
1032 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001033 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001034
Yann Collet4266c0a2016-06-14 01:49:25 +02001035 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001036 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1037 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001038
Yann Collet70e45772016-03-19 18:08:32 +01001039 /* Last Literals */
1040 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001041 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1042 seqStorePtr->lit += lastLLSize;
1043 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001044}
1045
1046
Yann Collet82260dd2016-02-11 07:14:25 +01001047static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001048 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001049{
Yann Collet3b719252016-03-30 19:48:05 +02001050 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001051 switch(mls)
1052 {
1053 default:
1054 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001055 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001056 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001057 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001058 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001059 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001060 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001061 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001062 }
1063}
Yann Colletf3eca252015-10-22 15:31:46 +01001064
Yann Colletf3eca252015-10-22 15:31:46 +01001065
Yann Collet82260dd2016-02-11 07:14:25 +01001066static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001067 const void* src, size_t srcSize,
1068 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001069{
1070 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001071 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001072 seqStore_t* seqStorePtr = &(ctx->seqStore);
1073 const BYTE* const base = ctx->base;
1074 const BYTE* const dictBase = ctx->dictBase;
1075 const BYTE* const istart = (const BYTE*)src;
1076 const BYTE* ip = istart;
1077 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001078 const U32 lowestIndex = ctx->lowLimit;
1079 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001080 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001081 const BYTE* const lowPrefixPtr = base + dictLimit;
1082 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001083 const BYTE* const iend = istart + srcSize;
1084 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001085 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001086
Yann Colleta436a522016-06-20 23:34:04 +02001087 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001088 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001089 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001090 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001091 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001092 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001093 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001094 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001095 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001096 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001097 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001098 hashTable[h] = current; /* update hash table */
1099
Yann Colleta436a522016-06-20 23:34:04 +02001100 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001101 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001102 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Colleta436a522016-06-20 23:34:04 +02001103 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001104 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001105 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001106 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001107 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001108 (MEM_read32(match) != MEM_read32(ip)) ) {
1109 ip += ((ip-anchor) >> g_searchStrength) + 1;
1110 continue;
1111 }
1112 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001113 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001114 U32 offset;
1115 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1116 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001117 offset = current - matchIndex;
1118 offset_2 = offset_1;
1119 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001120 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001121 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001122
Yann Collet5054ee02015-11-23 13:34:21 +01001123 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001124 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001125 anchor = ip;
1126
Yann Colletfb810d62016-01-28 00:18:06 +01001127 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001128 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001129 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001130 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1131 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001132 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001133 U32 const current2 = (U32)(ip-base);
1134 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001135 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001136 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1137 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001138 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001139 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001140 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001141 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001142 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001143 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001144 anchor = ip;
1145 continue;
1146 }
Yann Collet743402c2015-11-20 12:03:53 +01001147 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001148 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001149
Yann Collet4266c0a2016-06-14 01:49:25 +02001150 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001151 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001152
Yann Collet89db5e02015-11-13 11:27:46 +01001153 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001154 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001155 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1156 seqStorePtr->lit += lastLLSize;
1157 }
Yann Collet89db5e02015-11-13 11:27:46 +01001158}
1159
1160
Yann Collet82260dd2016-02-11 07:14:25 +01001161static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001162 const void* src, size_t srcSize)
1163{
Yann Collet731ef162016-07-27 21:05:12 +02001164 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001165 switch(mls)
1166 {
1167 default:
1168 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001169 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001170 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001171 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001172 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001173 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001174 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001175 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001176 }
1177}
1178
1179
Yann Collet04b12d82016-02-11 06:23:24 +01001180/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001181* Double Fast
1182***************************************/
1183static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1184{
1185 U32* const hashLarge = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001186 U32 const hBitsL = cctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001187 U32* const hashSmall = cctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001188 U32 const hBitsS = cctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001189 const BYTE* const base = cctx->base;
1190 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001191 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001192 const size_t fastHashFillStep = 3;
1193
1194 while(ip <= iend) {
1195 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1196 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1197 ip += fastHashFillStep;
1198 }
1199}
1200
1201
1202FORCE_INLINE
1203void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1204 const void* src, size_t srcSize,
1205 const U32 mls)
1206{
1207 U32* const hashLong = cctx->hashTable;
1208 const U32 hBitsL = cctx->params.cParams.hashLog;
1209 U32* const hashSmall = cctx->chainTable;
1210 const U32 hBitsS = cctx->params.cParams.chainLog;
1211 seqStore_t* seqStorePtr = &(cctx->seqStore);
1212 const BYTE* const base = cctx->base;
1213 const BYTE* const istart = (const BYTE*)src;
1214 const BYTE* ip = istart;
1215 const BYTE* anchor = istart;
1216 const U32 lowestIndex = cctx->dictLimit;
1217 const BYTE* const lowest = base + lowestIndex;
1218 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001219 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001220 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1221 U32 offsetSaved = 0;
1222
1223 /* init */
1224 ip += (ip==lowest);
1225 { U32 const maxRep = (U32)(ip-lowest);
1226 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1227 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1228 }
1229
1230 /* Main Search Loop */
1231 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1232 size_t mLength;
1233 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1234 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1235 U32 const current = (U32)(ip-base);
1236 U32 const matchIndexL = hashLong[h2];
1237 U32 const matchIndexS = hashSmall[h];
1238 const BYTE* matchLong = base + matchIndexL;
1239 const BYTE* match = base + matchIndexS;
1240 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1241
1242 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1243 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1244 ip++;
1245 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1246 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001247 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001248 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1249 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001250 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001251 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1252 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Colletc54692f2016-08-24 01:10:42 +02001253 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1254 U32 const matchIndex3 = hashLong[h3];
1255 const BYTE* match3 = base + matchIndex3;
1256 hashLong[h3] = current + 1;
1257 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1258 mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
1259 ip++;
1260 offset = (U32)(ip-match3);
1261 while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1262 } else {
1263 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1264 offset = (U32)(ip-match);
1265 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1266 }
Yann Collet45dc3562016-07-12 09:47:31 +02001267 } else {
1268 ip += ((ip-anchor) >> g_searchStrength) + 1;
1269 continue;
1270 }
1271
1272 offset_2 = offset_1;
1273 offset_1 = offset;
1274
1275 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1276 }
1277
1278 /* match found */
1279 ip += mLength;
1280 anchor = ip;
1281
1282 if (ip <= ilimit) {
1283 /* Fill Table */
1284 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1285 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1286 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1287 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1288
1289 /* check immediate repcode */
1290 while ( (ip <= ilimit)
1291 && ( (offset_2>0)
1292 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1293 /* store sequence */
1294 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001295 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001296 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1297 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1298 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1299 ip += rLength;
1300 anchor = ip;
1301 continue; /* faster when present ... (?) */
1302 } } }
1303
1304 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001305 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1306 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001307
1308 /* Last Literals */
1309 { size_t const lastLLSize = iend - anchor;
1310 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1311 seqStorePtr->lit += lastLLSize;
1312 }
1313}
1314
1315
1316static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1317{
1318 const U32 mls = ctx->params.cParams.searchLength;
1319 switch(mls)
1320 {
1321 default:
1322 case 4 :
1323 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1324 case 5 :
1325 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1326 case 6 :
1327 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1328 case 7 :
1329 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1330 }
1331}
1332
1333
1334static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1335 const void* src, size_t srcSize,
1336 const U32 mls)
1337{
1338 U32* const hashLong = ctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001339 U32 const hBitsL = ctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001340 U32* const hashSmall = ctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001341 U32 const hBitsS = ctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001342 seqStore_t* seqStorePtr = &(ctx->seqStore);
1343 const BYTE* const base = ctx->base;
1344 const BYTE* const dictBase = ctx->dictBase;
1345 const BYTE* const istart = (const BYTE*)src;
1346 const BYTE* ip = istart;
1347 const BYTE* anchor = istart;
1348 const U32 lowestIndex = ctx->lowLimit;
1349 const BYTE* const dictStart = dictBase + lowestIndex;
1350 const U32 dictLimit = ctx->dictLimit;
1351 const BYTE* const lowPrefixPtr = base + dictLimit;
1352 const BYTE* const dictEnd = dictBase + dictLimit;
1353 const BYTE* const iend = istart + srcSize;
1354 const BYTE* const ilimit = iend - 8;
1355 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1356
1357 /* Search Loop */
1358 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1359 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1360 const U32 matchIndex = hashSmall[hSmall];
1361 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1362 const BYTE* match = matchBase + matchIndex;
1363
1364 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1365 const U32 matchLongIndex = hashLong[hLong];
1366 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1367 const BYTE* matchLong = matchLongBase + matchLongIndex;
1368
1369 const U32 current = (U32)(ip-base);
1370 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1371 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1372 const BYTE* repMatch = repBase + repIndex;
1373 size_t mLength;
1374 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1375
1376 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1377 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1378 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1379 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1380 ip++;
1381 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1382 } else {
1383 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1384 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1385 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1386 U32 offset;
1387 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1388 offset = current - matchLongIndex;
1389 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1390 offset_2 = offset_1;
1391 offset_1 = offset;
1392 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001393
Yann Collet73d74a02016-07-12 13:03:48 +02001394 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001395 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1396 U32 const matchIndex3 = hashLong[h3];
1397 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1398 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001399 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001400 hashLong[h3] = current + 1;
1401 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1402 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1403 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1404 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1405 ip++;
1406 offset = current+1 - matchIndex3;
1407 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1408 } else {
1409 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1410 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1411 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1412 offset = current - matchIndex;
1413 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1414 }
Yann Collet45dc3562016-07-12 09:47:31 +02001415 offset_2 = offset_1;
1416 offset_1 = offset;
1417 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001418
Yann Collet45dc3562016-07-12 09:47:31 +02001419 } else {
1420 ip += ((ip-anchor) >> g_searchStrength) + 1;
1421 continue;
1422 } }
1423
1424 /* found a match : store it */
1425 ip += mLength;
1426 anchor = ip;
1427
1428 if (ip <= ilimit) {
1429 /* Fill Table */
1430 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1431 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1432 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1433 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1434 /* check immediate repcode */
1435 while (ip <= ilimit) {
1436 U32 const current2 = (U32)(ip-base);
1437 U32 const repIndex2 = current2 - offset_2;
1438 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1439 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1440 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1441 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1442 size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1443 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1444 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1445 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1446 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1447 ip += repLength2;
1448 anchor = ip;
1449 continue;
1450 }
1451 break;
1452 } } }
1453
1454 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001455 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001456
1457 /* Last Literals */
1458 { size_t const lastLLSize = iend - anchor;
1459 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1460 seqStorePtr->lit += lastLLSize;
1461 }
1462}
1463
1464
1465static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1466 const void* src, size_t srcSize)
1467{
Yann Collet731ef162016-07-27 21:05:12 +02001468 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001469 switch(mls)
1470 {
1471 default:
1472 case 4 :
1473 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1474 case 5 :
1475 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1476 case 6 :
1477 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1478 case 7 :
1479 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1480 }
1481}
1482
1483
1484/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001485* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001486***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001487/** ZSTD_insertBt1() : add one or multiple positions to tree.
1488* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001489* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001490static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1491 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001492{
Yann Collet731ef162016-07-27 21:05:12 +02001493 U32* const hashTable = zc->hashTable;
1494 U32 const hashLog = zc->params.cParams.hashLog;
1495 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1496 U32* const bt = zc->chainTable;
1497 U32 const btLog = zc->params.cParams.chainLog - 1;
1498 U32 const btMask = (1 << btLog) - 1;
1499 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001500 size_t commonLengthSmaller=0, commonLengthLarger=0;
1501 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001502 const BYTE* const dictBase = zc->dictBase;
1503 const U32 dictLimit = zc->dictLimit;
1504 const BYTE* const dictEnd = dictBase + dictLimit;
1505 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001506 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001507 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001508 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001509 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001510 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001511 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001512 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001513 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001514 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001515#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001516 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1517 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1518 predictedSmall += (predictedSmall>0);
1519 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001520#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001521
Yann Collet6c3e2e72015-12-11 10:44:07 +01001522 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001523
Yann Colletfb810d62016-01-28 00:18:06 +01001524 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001525 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001526 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001527
Yann Colletc0932082016-06-30 14:07:30 +02001528#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001529 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001530 if (matchIndex == predictedSmall) {
1531 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001532 *smallerPtr = matchIndex;
1533 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1534 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1535 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001536 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001537 continue;
1538 }
Yann Colletfb810d62016-01-28 00:18:06 +01001539 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001540 *largerPtr = matchIndex;
1541 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1542 largerPtr = nextPtr;
1543 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001544 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001545 continue;
1546 }
Yann Collet04b12d82016-02-11 06:23:24 +01001547#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001548 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001549 match = base + matchIndex;
1550 if (match[matchLength] == ip[matchLength])
1551 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001552 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001553 match = dictBase + matchIndex;
1554 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1555 if (matchIndex+matchLength >= dictLimit)
1556 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1557 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001558
Yann Colletb8a6f682016-02-15 17:06:29 +01001559 if (matchLength > bestLength) {
1560 bestLength = matchLength;
1561 if (matchLength > matchEndIdx - matchIndex)
1562 matchEndIdx = matchIndex + (U32)matchLength;
1563 }
Yann Colletee3f4512015-12-29 22:26:09 +01001564
Yann Collet59d70632015-11-04 12:05:27 +01001565 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001566 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001567
Yann Colletfb810d62016-01-28 00:18:06 +01001568 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001569 /* match is smaller than current */
1570 *smallerPtr = matchIndex; /* update smaller idx */
1571 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001572 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001573 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001574 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001575 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001576 /* match is larger than current */
1577 *largerPtr = matchIndex;
1578 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001579 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001580 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001581 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001582 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001583
Yann Collet59d70632015-11-04 12:05:27 +01001584 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001585 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001586 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1587 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001588}
1589
1590
Yann Collet82260dd2016-02-11 07:14:25 +01001591static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001592 ZSTD_CCtx* zc,
1593 const BYTE* const ip, const BYTE* const iend,
1594 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001595 U32 nbCompares, const U32 mls,
1596 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001597{
Yann Collet731ef162016-07-27 21:05:12 +02001598 U32* const hashTable = zc->hashTable;
1599 U32 const hashLog = zc->params.cParams.hashLog;
1600 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1601 U32* const bt = zc->chainTable;
1602 U32 const btLog = zc->params.cParams.chainLog - 1;
1603 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001604 U32 matchIndex = hashTable[h];
1605 size_t commonLengthSmaller=0, commonLengthLarger=0;
1606 const BYTE* const base = zc->base;
1607 const BYTE* const dictBase = zc->dictBase;
1608 const U32 dictLimit = zc->dictLimit;
1609 const BYTE* const dictEnd = dictBase + dictLimit;
1610 const BYTE* const prefixStart = base + dictLimit;
1611 const U32 current = (U32)(ip-base);
1612 const U32 btLow = btMask >= current ? 0 : current - btMask;
1613 const U32 windowLow = zc->lowLimit;
1614 U32* smallerPtr = bt + 2*(current&btMask);
1615 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001616 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001617 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001618 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001619
Yann Collet6c3e2e72015-12-11 10:44:07 +01001620 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001621
Yann Colletfb810d62016-01-28 00:18:06 +01001622 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001623 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01001624 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1625 const BYTE* match;
1626
Yann Colletfb810d62016-01-28 00:18:06 +01001627 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001628 match = base + matchIndex;
1629 if (match[matchLength] == ip[matchLength])
1630 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001631 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001632 match = dictBase + matchIndex;
1633 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001634 if (matchIndex+matchLength >= dictLimit)
1635 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001636 }
1637
Yann Colletfb810d62016-01-28 00:18:06 +01001638 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001639 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001640 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001641 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001642 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001643 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1644 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1645 }
1646
Yann Colletfb810d62016-01-28 00:18:06 +01001647 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001648 /* match is smaller than current */
1649 *smallerPtr = matchIndex; /* update smaller idx */
1650 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1651 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1652 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1653 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001654 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001655 /* match is larger than current */
1656 *largerPtr = matchIndex;
1657 commonLengthLarger = matchLength;
1658 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1659 largerPtr = nextPtr;
1660 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001661 } }
Yann Collet03526e12015-11-23 15:29:15 +01001662
1663 *smallerPtr = *largerPtr = 0;
1664
Yann Collet72e84cf2015-12-31 19:08:44 +01001665 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001666 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001667}
1668
Yann Collet2cc12cb2016-01-01 07:47:58 +01001669
Yann Colletb8a6f682016-02-15 17:06:29 +01001670static 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 +01001671{
1672 const BYTE* const base = zc->base;
1673 const U32 target = (U32)(ip - base);
1674 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001675
1676 while(idx < target)
1677 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001678}
1679
Yann Collet52447382016-03-20 16:00:00 +01001680/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001681static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001682 ZSTD_CCtx* zc,
1683 const BYTE* const ip, const BYTE* const iLimit,
1684 size_t* offsetPtr,
1685 const U32 maxNbAttempts, const U32 mls)
1686{
1687 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001688 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001689 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1690}
1691
1692
Yann Collet768c6bc2016-02-10 14:01:49 +01001693static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001694 ZSTD_CCtx* zc, /* Index table will be updated */
1695 const BYTE* ip, const BYTE* const iLimit,
1696 size_t* offsetPtr,
1697 const U32 maxNbAttempts, const U32 matchLengthSearch)
1698{
1699 switch(matchLengthSearch)
1700 {
1701 default :
1702 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1703 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1704 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1705 }
1706}
1707
1708
Yann Colletb8a6f682016-02-15 17:06:29 +01001709static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1710{
1711 const BYTE* const base = zc->base;
1712 const U32 target = (U32)(ip - base);
1713 U32 idx = zc->nextToUpdate;
1714
1715 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1716}
1717
inikep64d7bcb2016-04-07 19:14:09 +02001718
Yann Collet03526e12015-11-23 15:29:15 +01001719/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001720static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001721 ZSTD_CCtx* zc,
1722 const BYTE* const ip, const BYTE* const iLimit,
1723 size_t* offsetPtr,
1724 const U32 maxNbAttempts, const U32 mls)
1725{
Yann Colletee3f4512015-12-29 22:26:09 +01001726 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001727 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001728 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001729}
1730
1731
Yann Collet82260dd2016-02-11 07:14:25 +01001732static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001733 ZSTD_CCtx* zc, /* Index table will be updated */
1734 const BYTE* ip, const BYTE* const iLimit,
1735 size_t* offsetPtr,
1736 const U32 maxNbAttempts, const U32 matchLengthSearch)
1737{
1738 switch(matchLengthSearch)
1739 {
1740 default :
1741 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1742 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1743 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1744 }
1745}
1746
1747
Yann Collet5106a762015-11-05 15:00:24 +01001748
Yann Collet731ef162016-07-27 21:05:12 +02001749/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02001750* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02001751***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02001752#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1753
1754/* Update chains up to ip (excluded)
1755 Assumption : always within prefix (ie. not within extDict) */
1756FORCE_INLINE
1757U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1758{
1759 U32* const hashTable = zc->hashTable;
1760 const U32 hashLog = zc->params.cParams.hashLog;
1761 U32* const chainTable = zc->chainTable;
1762 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1763 const BYTE* const base = zc->base;
1764 const U32 target = (U32)(ip - base);
1765 U32 idx = zc->nextToUpdate;
1766
Yann Collet22d76322016-06-21 08:01:51 +02001767 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001768 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1769 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1770 hashTable[h] = idx;
1771 idx++;
1772 }
1773
1774 zc->nextToUpdate = target;
1775 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1776}
1777
1778
1779
1780FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1781size_t ZSTD_HcFindBestMatch_generic (
1782 ZSTD_CCtx* zc, /* Index table will be updated */
1783 const BYTE* const ip, const BYTE* const iLimit,
1784 size_t* offsetPtr,
1785 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1786{
1787 U32* const chainTable = zc->chainTable;
1788 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1789 const U32 chainMask = chainSize-1;
1790 const BYTE* const base = zc->base;
1791 const BYTE* const dictBase = zc->dictBase;
1792 const U32 dictLimit = zc->dictLimit;
1793 const BYTE* const prefixStart = base + dictLimit;
1794 const BYTE* const dictEnd = dictBase + dictLimit;
1795 const U32 lowLimit = zc->lowLimit;
1796 const U32 current = (U32)(ip-base);
1797 const U32 minChain = current > chainSize ? current - chainSize : 0;
1798 int nbAttempts=maxNbAttempts;
1799 size_t ml=EQUAL_READ32-1;
1800
1801 /* HC4 match finder */
1802 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1803
Yann Collet22d76322016-06-21 08:01:51 +02001804 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001805 const BYTE* match;
1806 size_t currentMl=0;
1807 if ((!extDict) || matchIndex >= dictLimit) {
1808 match = base + matchIndex;
1809 if (match[ml] == ip[ml]) /* potentially better */
1810 currentMl = ZSTD_count(ip, match, iLimit);
1811 } else {
1812 match = dictBase + matchIndex;
1813 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1814 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1815 }
1816
1817 /* save best solution */
Yann Collet22d76322016-06-21 08:01:51 +02001818 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 +02001819
1820 if (matchIndex <= minChain) break;
1821 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1822 }
1823
1824 return ml;
1825}
1826
1827
1828FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1829 ZSTD_CCtx* zc,
1830 const BYTE* ip, const BYTE* const iLimit,
1831 size_t* offsetPtr,
1832 const U32 maxNbAttempts, const U32 matchLengthSearch)
1833{
1834 switch(matchLengthSearch)
1835 {
1836 default :
1837 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1838 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1839 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1840 }
1841}
1842
1843
1844FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_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, 1);
1854 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1855 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1856 }
1857}
1858
inikep64d7bcb2016-04-07 19:14:09 +02001859
Yann Collet287b7d92015-11-22 13:24:05 +01001860/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001861* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001862*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001863FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001864void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1865 const void* src, size_t srcSize,
1866 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001867{
inikepfaa8d8a2016-04-05 19:01:10 +02001868 seqStore_t* seqStorePtr = &(ctx->seqStore);
1869 const BYTE* const istart = (const BYTE*)src;
1870 const BYTE* ip = istart;
1871 const BYTE* anchor = istart;
1872 const BYTE* const iend = istart + srcSize;
1873 const BYTE* const ilimit = iend - 8;
1874 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001875
Yann Collet793c6492016-04-09 20:32:00 +02001876 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1877 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001878
inikep64d7bcb2016-04-07 19:14:09 +02001879 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1880 size_t* offsetPtr,
1881 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02001882 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02001883 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02001884
inikepfaa8d8a2016-04-05 19:01:10 +02001885 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001886 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02001887 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02001888 { U32 const maxRep = (U32)(ip-base);
1889 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1890 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1891 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001892
inikepfaa8d8a2016-04-05 19:01:10 +02001893 /* Match Loop */
1894 while (ip < ilimit) {
1895 size_t matchLength=0;
1896 size_t offset=0;
1897 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001898
inikepfaa8d8a2016-04-05 19:01:10 +02001899 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02001900 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02001901 /* repcode : we take it */
Yann Collet9634f672016-07-03 01:23:58 +02001902 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001903 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001904 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001905
inikepfaa8d8a2016-04-05 19:01:10 +02001906 /* first search (depth 0) */
1907 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001908 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001909 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001910 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001911 }
Yann Collet5106a762015-11-05 15:00:24 +01001912
inikep7bc19b62016-04-06 09:46:01 +02001913 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001914 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1915 continue;
1916 }
1917
inikep64d7bcb2016-04-07 19:14:09 +02001918 /* let's try to find a better solution */
1919 if (depth>=1)
1920 while (ip<ilimit) {
1921 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001922 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1923 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001924 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001925 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001926 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1927 matchLength = mlRep, offset = 0, start = ip;
1928 }
1929 { size_t offset2=99999999;
1930 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001931 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1932 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001933 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1934 matchLength = ml2, offset = offset2, start = ip;
1935 continue; /* search a better one */
1936 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001937
inikep64d7bcb2016-04-07 19:14:09 +02001938 /* let's find an even better one */
1939 if ((depth==2) && (ip<ilimit)) {
1940 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001941 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1942 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001943 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001944 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001945 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1946 matchLength = ml2, offset = 0, start = ip;
1947 }
1948 { size_t offset2=99999999;
1949 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001950 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1951 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001952 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1953 matchLength = ml2, offset = offset2, start = ip;
1954 continue;
1955 } } }
1956 break; /* nothing found : store previous solution */
1957 }
1958
1959 /* catch up */
1960 if (offset) {
1961 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1962 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02001963 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02001964 }
1965
inikepfaa8d8a2016-04-05 19:01:10 +02001966 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001967_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001968 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02001969 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02001970 anchor = ip = start + matchLength;
1971 }
Yann Collet48537162016-04-07 15:24:29 +02001972
inikepfaa8d8a2016-04-05 19:01:10 +02001973 /* check immediate repcode */
1974 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02001975 && ((offset_2>0)
1976 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02001977 /* store sequence */
Yann Collet9634f672016-07-03 01:23:58 +02001978 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
1979 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001980 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1981 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001982 anchor = ip;
1983 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02001984 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001985
Yann Collet4266c0a2016-06-14 01:49:25 +02001986 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001987 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
1988 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02001989
inikepfaa8d8a2016-04-05 19:01:10 +02001990 /* Last Literals */
1991 { size_t const lastLLSize = iend - anchor;
1992 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1993 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01001994 }
Yann Collet5106a762015-11-05 15:00:24 +01001995}
1996
Yann Collet5be2dd22015-11-11 13:43:58 +01001997
inikep64d7bcb2016-04-07 19:14:09 +02001998static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1999{
2000 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2001}
2002
2003static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2004{
2005 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2006}
2007
2008static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2009{
2010 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2011}
2012
2013static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2014{
2015 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2016}
2017
2018
inikepfaa8d8a2016-04-05 19:01:10 +02002019FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002020void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2021 const void* src, size_t srcSize,
2022 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002023{
inikepfaa8d8a2016-04-05 19:01:10 +02002024 seqStore_t* seqStorePtr = &(ctx->seqStore);
2025 const BYTE* const istart = (const BYTE*)src;
2026 const BYTE* ip = istart;
2027 const BYTE* anchor = istart;
2028 const BYTE* const iend = istart + srcSize;
2029 const BYTE* const ilimit = iend - 8;
2030 const BYTE* const base = ctx->base;
2031 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002032 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002033 const BYTE* const prefixStart = base + dictLimit;
2034 const BYTE* const dictBase = ctx->dictBase;
2035 const BYTE* const dictEnd = dictBase + dictLimit;
2036 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2037
2038 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2039 const U32 mls = ctx->params.cParams.searchLength;
2040
inikep64d7bcb2016-04-07 19:14:09 +02002041 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2042 size_t* offsetPtr,
2043 U32 maxNbAttempts, U32 matchLengthSearch);
2044 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2045
Yann Collet302ff032016-07-03 01:28:16 +02002046 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002047
Yann Collet302ff032016-07-03 01:28:16 +02002048 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002049 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002050 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002051
2052 /* Match Loop */
2053 while (ip < ilimit) {
2054 size_t matchLength=0;
2055 size_t offset=0;
2056 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002057 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002058
2059 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002060 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002061 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2062 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002063 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002064 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002065 /* repcode detected we should take it */
2066 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02002067 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2068 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002069 } }
2070
2071 /* first search (depth 0) */
2072 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002073 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002074 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002075 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002076 }
2077
inikep7bc19b62016-04-06 09:46:01 +02002078 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02002079 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2080 continue;
2081 }
2082
inikep64d7bcb2016-04-07 19:14:09 +02002083 /* let's try to find a better solution */
2084 if (depth>=1)
2085 while (ip<ilimit) {
2086 ip ++;
2087 current++;
2088 /* check repCode */
2089 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002090 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002091 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2092 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002093 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002094 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2095 /* repcode detected */
2096 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2097 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2098 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002099 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002100 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2101 matchLength = repLength, offset = 0, start = ip;
2102 } }
2103
2104 /* search match, depth 1 */
2105 { size_t offset2=99999999;
2106 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002107 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2108 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02002109 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2110 matchLength = ml2, offset = offset2, start = ip;
2111 continue; /* search a better one */
2112 } }
2113
2114 /* let's find an even better one */
2115 if ((depth==2) && (ip<ilimit)) {
2116 ip ++;
2117 current++;
2118 /* check repCode */
2119 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002120 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002121 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2122 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002123 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002124 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2125 /* repcode detected */
2126 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2127 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2128 int gain2 = (int)(repLength * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002129 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002130 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2131 matchLength = repLength, offset = 0, start = ip;
2132 } }
2133
2134 /* search match, depth 2 */
2135 { size_t offset2=99999999;
2136 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002137 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2138 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02002139 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2140 matchLength = ml2, offset = offset2, start = ip;
2141 continue;
2142 } } }
2143 break; /* nothing found : store previous solution */
2144 }
2145
inikepfaa8d8a2016-04-05 19:01:10 +02002146 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002147 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002148 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002149 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2150 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002151 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002152 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002153 }
inikepfaa8d8a2016-04-05 19:01:10 +02002154
inikepfaa8d8a2016-04-05 19:01:10 +02002155 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002156_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002157 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002158 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002159 anchor = ip = start + matchLength;
2160 }
2161
2162 /* check immediate repcode */
2163 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002164 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002165 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2166 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002167 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002168 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2169 /* repcode detected we should take it */
2170 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02002171 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
Yann Collet302ff032016-07-03 01:28:16 +02002172 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002173 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2174 ip += matchLength;
2175 anchor = ip;
2176 continue; /* faster when present ... (?) */
2177 }
2178 break;
2179 } }
2180
Yann Collet4266c0a2016-06-14 01:49:25 +02002181 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002182 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002183
inikepfaa8d8a2016-04-05 19:01:10 +02002184 /* Last Literals */
2185 { size_t const lastLLSize = iend - anchor;
2186 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2187 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002188 }
2189}
2190
2191
Yann Collet59d1f792016-01-23 19:28:41 +01002192void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002193{
inikep64d7bcb2016-04-07 19:14:09 +02002194 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002195}
2196
Yann Collet59d1f792016-01-23 19:28:41 +01002197static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002198{
Yann Colleta1249dc2016-01-25 04:22:03 +01002199 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002200}
Yann Collet9a24e592015-11-22 02:53:43 +01002201
Yann Collet59d1f792016-01-23 19:28:41 +01002202static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002203{
Yann Colleta1249dc2016-01-25 04:22:03 +01002204 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002205}
2206
Yann Collet59d1f792016-01-23 19:28:41 +01002207static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002208{
Yann Colleta1249dc2016-01-25 04:22:03 +01002209 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002210}
2211
inikepef519412016-04-21 11:08:43 +02002212
inikepef519412016-04-21 11:08:43 +02002213/* The optimal parser */
2214#include "zstd_opt.h"
2215
2216static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2217{
Yann Colletd4f4e582016-06-27 01:31:35 +02002218#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002219 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2220#else
2221 (void)ctx; (void)src; (void)srcSize;
2222 return;
2223#endif
2224}
2225
2226static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2227{
2228#ifdef ZSTD_OPT_H_91842398743
2229 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002230#else
2231 (void)ctx; (void)src; (void)srcSize;
2232 return;
2233#endif
inikepef519412016-04-21 11:08:43 +02002234}
2235
inikepd3b8d7a2016-02-22 10:06:17 +01002236static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002237{
Yann Colletd4f4e582016-06-27 01:31:35 +02002238#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002239 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2240#else
2241 (void)ctx; (void)src; (void)srcSize;
2242 return;
2243#endif
2244}
2245
2246static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2247{
2248#ifdef ZSTD_OPT_H_91842398743
2249 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002250#else
2251 (void)ctx; (void)src; (void)srcSize;
2252 return;
2253#endif
inikepe2bfe242016-01-31 11:25:48 +01002254}
2255
Yann Collet7a231792015-11-21 15:27:35 +01002256
Yann Collet59d1f792016-01-23 19:28:41 +01002257typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002258
Yann Colletb923f652016-01-26 03:14:20 +01002259static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002260{
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002261 static const ZSTD_blockCompressor blockCompressor[2][8] = {
2262 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 },
2263 { 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 +01002264 };
2265
2266 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002267}
2268
2269
Yann Colletd1b26842016-03-15 01:24:33 +01002270static 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 +01002271{
Yann Collet19cab462016-06-17 12:54:52 +02002272 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002273 const BYTE* const base = zc->base;
2274 const BYTE* const istart = (const BYTE*)src;
2275 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002276 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 +02002277 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002278 if (current > zc->nextToUpdate + 384)
2279 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 +01002280 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002281 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002282}
2283
2284
Yann Colletc991cc12016-07-28 00:55:43 +02002285/*! ZSTD_compress_generic() :
2286* Compress a chunk of data into one or multiple blocks.
2287* All blocks will be terminated, all input will be consumed.
2288* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2289* Frame is supposed already started (header already produced)
2290* @return : compressed size, or an error code
2291*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002292static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2293 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002294 const void* src, size_t srcSize,
2295 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002296{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002297 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002298 size_t remaining = srcSize;
2299 const BYTE* ip = (const BYTE*)src;
2300 BYTE* const ostart = (BYTE*)dst;
2301 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002302 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002303
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002304 if (cctx->params.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002305 XXH64_update(&cctx->xxhState, src, srcSize);
2306
Yann Collet2ce49232016-02-02 14:36:49 +01002307 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002308 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002309 size_t cSize;
2310
inikepfb5df612016-05-24 15:36:37 +02002311 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 +01002312 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002313
Yann Collet346efcc2016-08-02 14:26:00 +02002314 /* preemptive overflow correction */
Yann Colletc261f712016-12-12 00:25:07 +01002315 if (cctx->lowLimit > (2U<<30)) {
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002316 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002317 U32 const current = (U32)(ip - cctx->base);
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002318 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002319 U32 const correction = current - newCurrent;
2320 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002321 ZSTD_reduceIndex(cctx, correction);
2322 cctx->base += correction;
2323 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002324 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002325 cctx->dictLimit -= correction;
2326 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2327 else cctx->nextToUpdate -= correction;
2328 }
2329
Yann Collet06e76972017-01-25 16:39:03 -08002330 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002331 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002332 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2333 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2334 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002335 }
Yann Collet89db5e02015-11-13 11:27:46 +01002336
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002337 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002338 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002339
Yann Collet2ce49232016-02-02 14:36:49 +01002340 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002341 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2342 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2343 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2344 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2345 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002346 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002347 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002348 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002349 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002350 }
2351
2352 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002353 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002354 ip += blockSize;
2355 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002356 }
2357
Yann Collet62470b42016-07-28 15:29:08 +02002358 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002359 return op-ostart;
2360}
2361
2362
Yann Collet6236eba2016-04-12 15:52:33 +02002363static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002364 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002365{ BYTE* const op = (BYTE*)dst;
Yann Collet731ef162016-07-27 21:05:12 +02002366 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2367 U32 const checksumFlag = params.fParams.checksumFlag>0;
2368 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002369 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002370 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2371 U32 const fcsCode = params.fParams.contentSizeFlag ?
Yann Collet673f0d72016-06-06 00:26:38 +02002372 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2373 0;
Yann Collet731ef162016-07-27 21:05:12 +02002374 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002375 size_t pos;
2376
2377 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002378
2379 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002380 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002381 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002382 switch(dictIDSizeCode)
2383 {
2384 default: /* impossible */
2385 case 0 : break;
2386 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002387 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002388 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2389 }
Yann Collet673f0d72016-06-06 00:26:38 +02002390 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002391 {
2392 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002393 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002394 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2395 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002396 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002397 }
Yann Colletc46fb922016-05-29 05:01:04 +02002398 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002399}
2400
2401
Yann Collet346efcc2016-08-02 14:26:00 +02002402static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002403 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002404 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002405 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002406{
Yann Collet2acb5d32015-10-29 16:49:43 +01002407 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002408 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002409
Yann Collet346efcc2016-08-02 14:26:00 +02002410 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002411
Yann Collet346efcc2016-08-02 14:26:00 +02002412 if (frame && (cctx->stage==ZSTDcs_init)) {
2413 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002414 if (ZSTD_isError(fhSize)) return fhSize;
2415 dstCapacity -= fhSize;
2416 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002417 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002418 }
Yann Colletf3eca252015-10-22 15:31:46 +01002419
Yann Collet417890c2015-12-04 17:16:37 +01002420 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002421 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002422 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002423 ptrdiff_t const delta = cctx->nextSrc - ip;
2424 cctx->lowLimit = cctx->dictLimit;
2425 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2426 cctx->dictBase = cctx->base;
2427 cctx->base -= delta;
2428 cctx->nextToUpdate = cctx->dictLimit;
2429 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002430 }
2431
Yann Collet346efcc2016-08-02 14:26:00 +02002432 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2433 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2434 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2435 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2436 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002437 }
2438
Yann Collet346efcc2016-08-02 14:26:00 +02002439 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002440
Yann Collet5eb749e2017-01-11 18:21:25 +01002441 if (srcSize) {
2442 size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002443 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2444 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002445 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002446 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002447 } else
2448 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002449}
2450
Yann Colletbf42c8e2016-01-09 01:08:23 +01002451
Yann Collet5b567392016-07-28 01:17:22 +02002452size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002453 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002454 const void* src, size_t srcSize)
2455{
Yann Collet5b567392016-07-28 01:17:22 +02002456 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
2457}
2458
2459
Yann Colletcf05b9d2016-07-18 16:52:10 +02002460size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002461{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002462 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2463}
2464
2465size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2466{
2467 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002468 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Colletc991cc12016-07-28 00:55:43 +02002469 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002470}
2471
2472
Yann Colletb923f652016-01-26 03:14:20 +01002473static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002474{
2475 const BYTE* const ip = (const BYTE*) src;
2476 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002477
Yann Collet417890c2015-12-04 17:16:37 +01002478 /* input becomes current prefix */
2479 zc->lowLimit = zc->dictLimit;
2480 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2481 zc->dictBase = zc->base;
2482 zc->base += ip - zc->nextSrc;
2483 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002484 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002485
2486 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002487 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002488
Yann Collet3b719252016-03-30 19:48:05 +02002489 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002490 {
2491 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002492 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002493 break;
2494
Yann Collet45dc3562016-07-12 09:47:31 +02002495 case ZSTD_dfast:
2496 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2497 break;
2498
Yann Collet417890c2015-12-04 17:16:37 +01002499 case ZSTD_greedy:
2500 case ZSTD_lazy:
2501 case ZSTD_lazy2:
Yann Collet731ef162016-07-27 21:05:12 +02002502 ZSTD_insertAndFindFirstIndex (zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002503 break;
2504
2505 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002506 case ZSTD_btopt:
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002507 case ZSTD_btopt2:
Yann Collet731ef162016-07-27 21:05:12 +02002508 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002509 break;
2510
2511 default:
2512 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2513 }
2514
Nick Terrellecf90ca2017-02-13 18:27:34 -08002515 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002516 return 0;
2517}
2518
2519
Nick Terrellf9c9af32016-10-19 17:22:08 -07002520/* Dictionaries that assign zero probability to symbols that show up causes problems
2521 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2522 that we may encounter during compression.
2523 NOTE: This behavior is not standard and could be improved in the future. */
2524static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2525 U32 s;
2526 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2527 for (s = 0; s <= maxSymbolValue; ++s) {
2528 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2529 }
2530 return 0;
2531}
2532
2533
Yann Colletb923f652016-01-26 03:14:20 +01002534/* Dictionary format :
Yann Colletee5b7252016-10-27 14:20:55 -07002535 Magic == ZSTD_DICT_MAGIC (4 bytes)
2536 HUF_writeCTable(256)
2537 FSE_writeNCount(off)
2538 FSE_writeNCount(ml)
2539 FSE_writeNCount(ll)
2540 RepOffsets
2541 Dictionary content
Yann Colletb923f652016-01-26 03:14:20 +01002542*/
Yann Colletfb797352016-03-13 11:08:40 +01002543/*! ZSTD_loadDictEntropyStats() :
Yann Collet736d4192016-06-15 18:48:51 +02002544 @return : size read from dictionary
2545 note : magic number supposed already checked */
2546static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002547{
Yann Collet52a06222016-06-15 13:53:34 +02002548 const BYTE* dictPtr = (const BYTE*)dict;
2549 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07002550 short offcodeNCount[MaxOff+1];
2551 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08002552 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01002553
Yann Collet736d4192016-06-15 18:48:51 +02002554 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002555 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002556 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002557 }
Yann Colletfb810d62016-01-28 00:18:06 +01002558
Nick Terrellf9c9af32016-10-19 17:22:08 -07002559 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02002560 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002561 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002562 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002563 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Collet643d9a22016-12-01 16:24:04 -08002564 CHECK_E (FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002565 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002566 }
Yann Colletfb810d62016-01-28 00:18:06 +01002567
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002568 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002569 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002570 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002571 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002572 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002573 /* Every match length code must have non-zero probability */
2574 CHECK_F (ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
Yann Collet643d9a22016-12-01 16:24:04 -08002575 CHECK_E (FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002576 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002577 }
Yann Colletfb810d62016-01-28 00:18:06 +01002578
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002579 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002580 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002581 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002582 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002583 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002584 /* Every literal length code must have non-zero probability */
2585 CHECK_F (ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
Yann Collet643d9a22016-12-01 16:24:04 -08002586 CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002587 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002588 }
Yann Colletfb810d62016-01-28 00:18:06 +01002589
Yann Collet52a06222016-06-15 13:53:34 +02002590 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Nick Terrell8157a4c2016-12-20 10:47:52 -08002591 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] == 0 || cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2592 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] == 0 || cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2593 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 +02002594 dictPtr += 12;
2595
Nick Terrellb2c39a22016-10-24 14:11:27 -07002596 { U32 offcodeMax = MaxOff;
2597 if ((size_t)(dictEnd - dictPtr) <= ((U32)-1) - 128 KB) {
2598 U32 const maxOffset = (U32)(dictEnd - dictPtr) + 128 KB; /* The maximum offset that must be supported */
2599 /* Calculate minimum offset code required to represent maxOffset */
2600 offcodeMax = ZSTD_highbit32(maxOffset);
2601 }
Nick Terrellf9c9af32016-10-19 17:22:08 -07002602 /* Every possible supported offset <= dictContentSize + 128 KB must be representable */
2603 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
2604 }
2605
Yann Collet736d4192016-06-15 18:48:51 +02002606 cctx->flagStaticTables = 1;
Yann Collet52a06222016-06-15 13:53:34 +02002607 return dictPtr - (const BYTE*)dict;
Yann Colletb923f652016-01-26 03:14:20 +01002608}
2609
Yann Colletd1b26842016-03-15 01:24:33 +01002610/** ZSTD_compress_insertDictionary() :
2611* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002612static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002613{
Yann Colletc46fb922016-05-29 05:01:04 +02002614 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002615
Yann Colletd1b26842016-03-15 01:24:33 +01002616 /* default : dict is pure content */
2617 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletc46fb922016-05-29 05:01:04 +02002618 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
Yann Colletd1b26842016-03-15 01:24:33 +01002619
2620 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet3e21ec52016-09-06 15:36:19 +02002621 { size_t const loadError = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8);
2622 size_t const eSize = loadError + 8;
2623 if (ZSTD_isError(loadError)) return loadError;
Yann Collet21588e32016-03-30 16:50:44 +02002624 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002625 }
Yann Colletecd651b2016-01-07 15:35:18 +01002626}
2627
Yann Collet27caf2a2016-04-01 15:48:48 +02002628/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002629* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002630static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002631 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002632 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002633{
Yann Colleta7737f62016-09-06 09:44:59 +02002634 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
Yann Collet3e21ec52016-09-06 15:36:19 +02002635 CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp));
Yann Colleta7737f62016-09-06 09:44:59 +02002636 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002637}
2638
2639
Yann Collet27caf2a2016-04-01 15:48:48 +02002640/*! ZSTD_compressBegin_advanced() :
2641* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002642size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002643 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002644 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002645{
2646 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02002647 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet81e13ef2016-06-07 00:51:51 +02002648 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002649}
2650
2651
Yann Collet81e13ef2016-06-07 00:51:51 +02002652size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002653{
Yann Collet6c6e1752016-06-27 15:28:45 +02002654 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002655 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002656}
Yann Collet083fcc82015-10-25 14:06:35 +01002657
inikep19bd48f2016-04-04 12:10:00 +02002658
Yann Colletb05c4822017-01-12 02:01:28 +01002659size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002660{
Yann Colletb05c4822017-01-12 02:01:28 +01002661 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002662}
2663
2664
Yann Collet62470b42016-07-28 15:29:08 +02002665/*! ZSTD_writeEpilogue() :
2666* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002667* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002668static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002669{
Yann Colletc991cc12016-07-28 00:55:43 +02002670 BYTE* const ostart = (BYTE*)dst;
2671 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002672 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002673
Yann Collet87c18b22016-08-26 01:43:47 +02002674 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002675
2676 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002677 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002678 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002679 if (ZSTD_isError(fhSize)) return fhSize;
2680 dstCapacity -= fhSize;
2681 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002682 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002683 }
2684
Yann Colletc991cc12016-07-28 00:55:43 +02002685 if (cctx->stage != ZSTDcs_ending) {
2686 /* write one last empty block, make it the "last" block */
2687 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2688 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2689 MEM_writeLE32(op, cBlockHeader24);
2690 op += ZSTD_blockHeaderSize;
2691 dstCapacity -= ZSTD_blockHeaderSize;
2692 }
2693
2694 if (cctx->params.fParams.checksumFlag) {
2695 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2696 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2697 MEM_writeLE32(op, checksum);
2698 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002699 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002700
Yann Collet731ef162016-07-27 21:05:12 +02002701 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002702 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002703}
2704
Yann Colletfd416f12016-01-30 03:14:15 +01002705
Yann Collet62470b42016-07-28 15:29:08 +02002706size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2707 void* dst, size_t dstCapacity,
2708 const void* src, size_t srcSize)
2709{
2710 size_t endResult;
2711 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
2712 if (ZSTD_isError(cSize)) return cSize;
2713 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2714 if (ZSTD_isError(endResult)) return endResult;
2715 return cSize + endResult;
2716}
2717
2718
Yann Collet19c10022016-07-28 01:25:46 +02002719static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002720 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002721 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002722 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002723 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002724{
Yann Collet3e21ec52016-09-06 15:36:19 +02002725 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
Yann Collet62470b42016-07-28 15:29:08 +02002726 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002727}
2728
Yann Collet21588e32016-03-30 16:50:44 +02002729size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2730 void* dst, size_t dstCapacity,
2731 const void* src, size_t srcSize,
2732 const void* dict,size_t dictSize,
2733 ZSTD_parameters params)
2734{
Yann Colletcf409a72016-09-26 16:41:05 +02002735 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02002736 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2737}
2738
Yann Colletd1b26842016-03-15 01:24:33 +01002739size_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 +01002740{
Yann Collet407a11f2016-11-03 15:52:01 -07002741 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02002742 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002743 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002744}
2745
Yann Colletd1b26842016-03-15 01:24:33 +01002746size_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 +01002747{
Yann Collet21588e32016-03-30 16:50:44 +02002748 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002749}
2750
Yann Colletd1b26842016-03-15 01:24:33 +01002751size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002752{
Yann Collet44fe9912015-10-29 22:02:40 +01002753 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002754 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002755 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002756 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002757 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002758 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 +01002759 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002760}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002761
Yann Colletfd416f12016-01-30 03:14:15 +01002762
Yann Collet81e13ef2016-06-07 00:51:51 +02002763/* ===== Dictionary API ===== */
2764
2765struct ZSTD_CDict_s {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002766 void* dictBuffer;
2767 const void* dictContent;
Yann Collet81e13ef2016-06-07 00:51:51 +02002768 size_t dictContentSize;
2769 ZSTD_CCtx* refContext;
David Lamda9d3b72016-08-29 09:03:12 -07002770}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
Yann Collet81e13ef2016-06-07 00:51:51 +02002771
Yann Colletd7c65892016-09-15 02:50:27 +02002772size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2773{
2774 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01002775 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02002776}
2777
Yann Collet1f57c2e2016-12-21 16:20:11 +01002778ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
2779 ZSTD_parameters params, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02002780{
Yann Collet23b6e052016-08-28 21:05:43 -07002781 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2782 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02002783
Yann Collet23b6e052016-08-28 21:05:43 -07002784 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002785 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2786
Yann Collet1f57c2e2016-12-21 16:20:11 +01002787 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07002788 ZSTD_free(cdict, customMem);
2789 ZSTD_free(cctx, customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002790 return NULL;
2791 }
2792
Yann Collet1f57c2e2016-12-21 16:20:11 +01002793 if ((byReference) || (!dictBuffer) || (!dictSize)) {
2794 cdict->dictBuffer = NULL;
2795 cdict->dictContent = dictBuffer;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002796 } else {
2797 void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
Yann Collet4e5eea62016-12-21 16:44:35 +01002798 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002799 memcpy(internalBuffer, dictBuffer, dictSize);
2800 cdict->dictBuffer = internalBuffer;
2801 cdict->dictContent = internalBuffer;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002802 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002803
2804 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
Yann Collet81e13ef2016-06-07 00:51:51 +02002805 if (ZSTD_isError(errorCode)) {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002806 ZSTD_free(cdict->dictBuffer, customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002807 ZSTD_free(cctx, customMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01002808 ZSTD_free(cdict, customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002809 return NULL;
2810 } }
2811
Yann Collet81e13ef2016-06-07 00:51:51 +02002812 cdict->refContext = cctx;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002813 cdict->dictContentSize = dictSize;
Yann Collet81e13ef2016-06-07 00:51:51 +02002814 return cdict;
2815 }
2816}
2817
2818ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2819{
2820 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet07639052016-08-03 01:57:57 +02002821 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002822 params.fParams.contentSizeFlag = 1;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002823 return ZSTD_createCDict_advanced(dict, dictSize, 0, params, allocator);
2824}
2825
2826ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
2827{
2828 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2829 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
2830 params.fParams.contentSizeFlag = 1;
2831 return ZSTD_createCDict_advanced(dict, dictSize, 1, params, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02002832}
2833
2834size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2835{
Yann Collet23b6e052016-08-28 21:05:43 -07002836 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02002837 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07002838 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01002839 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002840 ZSTD_free(cdict, cMem);
2841 return 0;
2842 }
Yann Collet81e13ef2016-06-07 00:51:51 +02002843}
2844
Yann Collet95162342016-10-25 16:19:52 -07002845static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
2846 return ZSTD_getParamsFromCCtx(cdict->refContext);
2847}
2848
Yann Colletc5933482017-01-22 16:40:06 -08002849size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002850{
Yann Collet97b378a2016-09-21 17:20:19 +02002851 if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
Sean Purcell2db72492017-02-09 10:50:43 -08002852 else {
2853 ZSTD_parameters params = cdict->refContext->params;
2854 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
2855 CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, params, pledgedSrcSize));
2856 }
Yann Collet4cb21292016-09-15 14:54:07 +02002857 return 0;
2858}
2859
Yann Collet07639052016-08-03 01:57:57 +02002860/*! ZSTD_compress_usingCDict() :
2861* Compression using a digested Dictionary.
2862* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2863* Note that compression level is decided during dictionary creation */
Yann Collet4cb21292016-09-15 14:54:07 +02002864size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2865 void* dst, size_t dstCapacity,
2866 const void* src, size_t srcSize,
2867 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02002868{
Yann Collet4cb21292016-09-15 14:54:07 +02002869 CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize));
Yann Collet07639052016-08-03 01:57:57 +02002870
2871 if (cdict->refContext->params.fParams.contentSizeFlag==1) {
2872 cctx->params.fParams.contentSizeFlag = 1;
2873 cctx->frameContentSize = srcSize;
2874 }
2875
2876 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002877}
2878
2879
2880
Yann Collet104e5b02016-08-12 13:04:27 +02002881/* ******************************************************************
2882* Streaming
2883********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002884
2885typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
2886
2887struct ZSTD_CStream_s {
Yann Colletfa0c0972016-09-15 14:11:01 +02002888 ZSTD_CCtx* cctx;
Yann Collet95162342016-10-25 16:19:52 -07002889 ZSTD_CDict* cdictLocal;
2890 const ZSTD_CDict* cdict;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002891 char* inBuff;
2892 size_t inBuffSize;
2893 size_t inToCompress;
2894 size_t inBuffPos;
2895 size_t inBuffTarget;
2896 size_t blockSize;
2897 char* outBuff;
2898 size_t outBuffSize;
2899 size_t outBuffContentSize;
2900 size_t outBuffFlushedSize;
2901 ZSTD_cStreamStage stage;
2902 U32 checksum;
2903 U32 frameEnded;
Yann Collete795c8a2016-12-13 16:39:36 +01002904 U64 pledgedSrcSize;
2905 U64 inputProcessed;
Yann Colletee5b7252016-10-27 14:20:55 -07002906 ZSTD_parameters params;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002907 ZSTD_customMem customMem;
2908}; /* typedef'd to ZSTD_CStream within "zstd.h" */
2909
2910ZSTD_CStream* ZSTD_createCStream(void)
2911{
2912 return ZSTD_createCStream_advanced(defaultCustomMem);
2913}
2914
2915ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
2916{
2917 ZSTD_CStream* zcs;
2918
Yann Collet23b6e052016-08-28 21:05:43 -07002919 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2920 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002921
Yann Collet23b6e052016-08-28 21:05:43 -07002922 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002923 if (zcs==NULL) return NULL;
2924 memset(zcs, 0, sizeof(ZSTD_CStream));
2925 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
Yann Colletfa0c0972016-09-15 14:11:01 +02002926 zcs->cctx = ZSTD_createCCtx_advanced(customMem);
2927 if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002928 return zcs;
2929}
2930
2931size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2932{
2933 if (zcs==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -07002934 { ZSTD_customMem const cMem = zcs->customMem;
Yann Colletfa0c0972016-09-15 14:11:01 +02002935 ZSTD_freeCCtx(zcs->cctx);
Yann Collet95162342016-10-25 16:19:52 -07002936 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet23b6e052016-08-28 21:05:43 -07002937 ZSTD_free(zcs->inBuff, cMem);
2938 ZSTD_free(zcs->outBuff, cMem);
2939 ZSTD_free(zcs, cMem);
2940 return 0;
2941 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002942}
2943
2944
Yann Collet104e5b02016-08-12 13:04:27 +02002945/*====== Initialization ======*/
2946
2947size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
2948size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002949
Sean Purcell2db72492017-02-09 10:50:43 -08002950static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002951{
Yann Colletd564faa2016-12-18 21:39:15 +01002952 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 -07002953
2954 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
2955 else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
Yann Collet4cb21292016-09-15 14:54:07 +02002956
2957 zcs->inToCompress = 0;
2958 zcs->inBuffPos = 0;
2959 zcs->inBuffTarget = zcs->blockSize;
2960 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
2961 zcs->stage = zcss_load;
2962 zcs->frameEnded = 0;
Yann Collete795c8a2016-12-13 16:39:36 +01002963 zcs->pledgedSrcSize = pledgedSrcSize;
2964 zcs->inputProcessed = 0;
Yann Collet4cb21292016-09-15 14:54:07 +02002965 return 0; /* ready to go */
2966}
2967
Sean Purcell2db72492017-02-09 10:50:43 -08002968size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
2969{
2970
2971 zcs->params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
2972
2973 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
2974}
2975
Yann Collet5a0c8e22016-08-12 01:20:36 +02002976size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
2977 const void* dict, size_t dictSize,
2978 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2979{
2980 /* allocate buffers */
2981 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
2982 if (zcs->inBuffSize < neededInBuffSize) {
2983 zcs->inBuffSize = neededInBuffSize;
Yann Colletcf409a72016-09-26 16:41:05 +02002984 ZSTD_free(zcs->inBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002985 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002986 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
2987 }
2988 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
2989 }
2990 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
2991 zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
Yann Colletcf409a72016-09-26 16:41:05 +02002992 ZSTD_free(zcs->outBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002993 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002994 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
2995 }
2996
Sean Purcell57d423c2017-01-17 11:04:08 -08002997 if (dict && dictSize >= 8) {
Yann Colletee5b7252016-10-27 14:20:55 -07002998 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet1f57c2e2016-12-21 16:20:11 +01002999 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0, params, zcs->customMem);
Yann Colletee5b7252016-10-27 14:20:55 -07003000 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3001 zcs->cdict = zcs->cdictLocal;
3002 } else zcs->cdict = NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003003
Yann Collet5a0c8e22016-08-12 01:20:36 +02003004 zcs->checksum = params.fParams.checksumFlag > 0;
Yann Colletee5b7252016-10-27 14:20:55 -07003005 zcs->params = params;
Yann Collet4cb21292016-09-15 14:54:07 +02003006
Sean Purcell2db72492017-02-09 10:50:43 -08003007 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003008}
3009
Yann Collet95162342016-10-25 16:19:52 -07003010/* note : cdict must outlive compression session */
3011size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3012{
3013 ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
3014 size_t const initError = ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0);
3015 zcs->cdict = cdict;
Gregory Szorc7d6f4782017-01-14 17:44:54 -08003016 zcs->cctx->dictID = params.fParams.noDictIDFlag ? 0 : cdict->refContext->dictID;
Yann Collet95162342016-10-25 16:19:52 -07003017 return initError;
3018}
3019
Yann Collet5a0c8e22016-08-12 01:20:36 +02003020size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3021{
3022 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
3023 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);
3024}
3025
Yann Collete795c8a2016-12-13 16:39:36 +01003026size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3027{
Yann Colletd564faa2016-12-18 21:39:15 +01003028 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
3029 if (pledgedSrcSize) params.fParams.contentSizeFlag = 1;
Yann Collete795c8a2016-12-13 16:39:36 +01003030 return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);
3031}
3032
Yann Collet5a0c8e22016-08-12 01:20:36 +02003033size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3034{
3035 return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel);
3036}
3037
Yann Collet70e3b312016-08-23 01:18:06 +02003038size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02003039{
Yann Colletd7c65892016-09-15 02:50:27 +02003040 if (zcs==NULL) return 0; /* support sizeof on NULL */
Yann Collet335ad5d2016-10-25 17:47:02 -07003041 return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize;
Yann Colletcb327632016-08-23 00:30:31 +02003042}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003043
Yann Collet104e5b02016-08-12 13:04:27 +02003044/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003045
3046typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
3047
3048MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3049{
3050 size_t const length = MIN(dstCapacity, srcSize);
3051 memcpy(dst, src, length);
3052 return length;
3053}
3054
3055static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3056 void* dst, size_t* dstCapacityPtr,
3057 const void* src, size_t* srcSizePtr,
3058 ZSTD_flush_e const flush)
3059{
3060 U32 someMoreWork = 1;
3061 const char* const istart = (const char*)src;
3062 const char* const iend = istart + *srcSizePtr;
3063 const char* ip = istart;
3064 char* const ostart = (char*)dst;
3065 char* const oend = ostart + *dstCapacityPtr;
3066 char* op = ostart;
3067
3068 while (someMoreWork) {
3069 switch(zcs->stage)
3070 {
3071 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
3072
3073 case zcss_load:
3074 /* complete inBuffer */
3075 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3076 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
3077 zcs->inBuffPos += loaded;
3078 ip += loaded;
3079 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
3080 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
3081 } }
3082 /* compress current block (note : this stage cannot be stopped in the middle) */
3083 { void* cDst;
3084 size_t cSize;
3085 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3086 size_t oSize = oend-op;
3087 if (oSize >= ZSTD_compressBound(iSize))
3088 cDst = op; /* compress directly into output buffer (avoid flush stage) */
3089 else
3090 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3091 cSize = (flush == zsf_end) ?
Yann Colletfa0c0972016-09-15 14:11:01 +02003092 ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
3093 ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003094 if (ZSTD_isError(cSize)) return cSize;
3095 if (flush == zsf_end) zcs->frameEnded = 1;
3096 /* prepare next block */
3097 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3098 if (zcs->inBuffTarget > zcs->inBuffSize)
3099 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
3100 zcs->inToCompress = zcs->inBuffPos;
3101 if (cDst == op) { op += cSize; break; } /* no need to flush */
3102 zcs->outBuffContentSize = cSize;
3103 zcs->outBuffFlushedSize = 0;
3104 zcs->stage = zcss_flush; /* pass-through to flush stage */
3105 }
3106
3107 case zcss_flush:
3108 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3109 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3110 op += flushed;
3111 zcs->outBuffFlushedSize += flushed;
3112 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
3113 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3114 zcs->stage = zcss_load;
3115 break;
3116 }
3117
3118 case zcss_final:
3119 someMoreWork = 0; /* do nothing */
3120 break;
3121
3122 default:
3123 return ERROR(GENERIC); /* impossible */
3124 }
3125 }
3126
3127 *srcSizePtr = ip - istart;
3128 *dstCapacityPtr = op - ostart;
Yann Collete795c8a2016-12-13 16:39:36 +01003129 zcs->inputProcessed += *srcSizePtr;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003130 if (zcs->frameEnded) return 0;
3131 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3132 if (hintInSize==0) hintInSize = zcs->blockSize;
3133 return hintInSize;
3134 }
3135}
3136
Yann Collet53e17fb2016-08-17 01:39:22 +02003137size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003138{
Yann Collet53e17fb2016-08-17 01:39:22 +02003139 size_t sizeRead = input->size - input->pos;
3140 size_t sizeWritten = output->size - output->pos;
3141 size_t const result = ZSTD_compressStream_generic(zcs,
3142 (char*)(output->dst) + output->pos, &sizeWritten,
3143 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3144 input->pos += sizeRead;
3145 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003146 return result;
3147}
3148
3149
Yann Collet104e5b02016-08-12 13:04:27 +02003150/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003151
3152/*! ZSTD_flushStream() :
3153* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003154size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003155{
3156 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003157 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02003158 size_t const result = ZSTD_compressStream_generic(zcs,
Yann Collet95d07d72016-09-06 16:38:51 +02003159 (char*)(output->dst) + output->pos, &sizeWritten,
3160 &srcSize, &srcSize, /* use a valid src address instead of NULL */
Yann Colletc4119022016-08-17 01:50:54 +02003161 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003162 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003163 if (ZSTD_isError(result)) return result;
3164 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3165}
3166
3167
Yann Collet53e17fb2016-08-17 01:39:22 +02003168size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003169{
Yann Collet53e17fb2016-08-17 01:39:22 +02003170 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3171 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003172 BYTE* op = ostart;
3173
Yann Collete795c8a2016-12-13 16:39:36 +01003174 if ((zcs->pledgedSrcSize) && (zcs->inputProcessed != zcs->pledgedSrcSize))
3175 return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */
3176
Yann Collet5a0c8e22016-08-12 01:20:36 +02003177 if (zcs->stage != zcss_final) {
3178 /* flush whatever remains */
3179 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003180 size_t sizeWritten = output->size - output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003181 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
3182 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3183 op += sizeWritten;
3184 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003185 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003186 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3187 }
3188 /* create epilogue */
3189 zcs->stage = zcss_final;
3190 zcs->outBuffContentSize = !notEnded ? 0 :
Yann Colletfa0c0972016-09-15 14:11:01 +02003191 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 +02003192 }
3193
3194 /* flush epilogue */
3195 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3196 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3197 op += flushed;
3198 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003199 output->pos += op-ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003200 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3201 return toFlush - flushed;
3202 }
3203}
3204
3205
3206
Yann Collet70e8c382016-02-10 13:37:52 +01003207/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003208
Yann Collet236d94f2016-05-18 12:06:33 +02003209#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003210#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003211int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003212
Yann Collet3b719252016-03-30 19:48:05 +02003213static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003214{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003215 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003216 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003217 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3218 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003219 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3220 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003221 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3222 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3223 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003224 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003225 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3226 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3227 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3228 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3229 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3230 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3231 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3232 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003233 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
3234 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
3235 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003236 { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */
3237 { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */
3238 { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003239},
3240{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003241 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003242 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003243 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003244 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3245 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3246 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3247 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3248 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3249 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3250 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3251 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3252 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3253 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3254 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3255 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003256 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003257 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3258 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3259 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003260 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3261 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003262 { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/
3263 { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/
3264 { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003265},
3266{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003267 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003268 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3269 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3270 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3271 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3272 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3273 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3274 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3275 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3276 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3277 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3278 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3279 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3280 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3281 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003282 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3283 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3284 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3285 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3286 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3287 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003288 { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/
3289 { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/
3290 { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003291},
3292{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003293 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003294 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003295 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003296 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3297 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3298 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3299 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3300 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3301 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3302 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3303 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003304 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3305 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3306 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3307 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3308 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3309 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3310 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3311 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3312 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3313 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003314 { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/
3315 { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/
3316 { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003317},
3318};
3319
Yann Collet236d94f2016-05-18 12:06:33 +02003320/*! ZSTD_getCParams() :
3321* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3322* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003323ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003324{
Yann Collet15354142016-04-04 04:22:53 +02003325 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003326 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003327 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003328 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003329 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003330 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003331 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003332 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3333 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003334 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003335 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3336 }
Yann Collet70d13012016-06-01 18:45:34 +02003337 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003338 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003339}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003340
3341/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003342* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003343* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003344ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003345 ZSTD_parameters params;
3346 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3347 memset(&params, 0, sizeof(params));
3348 params.cParams = cParams;
3349 return params;
3350}