blob: 4408644c6405f6c04e824d58495d3f971c0aca2f [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 Collet2ce49232016-02-02 14:36:49 +010063 U32 loadedDictEnd;
Yann Collet731ef162016-07-27 21:05:12 +020064 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +020065 U32 rep[ZSTD_REP_NUM];
66 U32 savedRep[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +020067 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +010068 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +010069 void* workSpace;
70 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +010071 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +020072 U64 frameContentSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +020073 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +020074 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +010075
Yann Collet712def92015-10-29 18:41:45 +010076 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +010077 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +010078 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +020079 U32* chainTable;
Yann Colletb923f652016-01-26 03:14:20 +010080 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +010081 U32 flagStaticTables;
Yann Collet731ef162016-07-27 21:05:12 +020082 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
83 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
84 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Collete928f7e2016-12-01 16:13:35 -080085 unsigned tmpCounters[1024];
Yann Colletf3eca252015-10-22 15:31:46 +010086};
87
Yann Collet5be2dd22015-11-11 13:43:58 +010088ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +010089{
inikep3763c772016-06-03 13:28:20 +020090 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +020091}
92
93ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
94{
Yann Collet69c2cdb2016-07-14 16:52:45 +020095 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +020096
Yann Collet23b6e052016-08-28 21:05:43 -070097 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
98 if (!customMem.customAlloc || !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +020099
Yann Collet23b6e052016-08-28 21:05:43 -0700100 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200101 if (!cctx) return NULL;
102 memset(cctx, 0, sizeof(ZSTD_CCtx));
Yann Colletedbcd9f2016-09-06 14:30:57 +0200103 memcpy(&(cctx->customMem), &customMem, sizeof(customMem));
Yann Collet69c2cdb2016-07-14 16:52:45 +0200104 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100105}
106
Yann Collet5be2dd22015-11-11 13:43:58 +0100107size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100108{
inikep36403962016-06-03 16:36:50 +0200109 if (cctx==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -0700110 ZSTD_free(cctx->workSpace, cctx->customMem);
111 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100112 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100113}
114
Yann Collet70e3b312016-08-23 01:18:06 +0200115size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200116{
Yann Colletd7c65892016-09-15 02:50:27 +0200117 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet3ae543c2016-07-11 03:12:17 +0200118 return sizeof(*cctx) + cctx->workSpaceSize;
119}
120
Yann Colletb44be742016-03-26 20:52:14 +0100121const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100122{
Yann Colletb44be742016-03-26 20:52:14 +0100123 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100124}
125
Yann Collet95162342016-10-25 16:19:52 -0700126static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx)
127{
128 return cctx->params;
129}
130
Yann Collet59d70632015-11-04 12:05:27 +0100131
Yann Collet21588e32016-03-30 16:50:44 +0200132/** ZSTD_checkParams() :
133 ensure param values remain within authorized range.
134 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200135size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200136{
Yann Colletac8bace2016-09-07 14:54:23 +0200137# define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
Yann Collet15354142016-04-04 04:22:53 +0200138 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200139 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200140 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
141 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Colletedbcd9f2016-09-06 14:30:57 +0200142 { 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 +0200143 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
144 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
145 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200146 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200147 return 0;
148}
149
150
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100151/** ZSTD_cycleLog() :
152 * condition for correct operation : hashLog > 1 */
153static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
154{
155 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
156 return hashLog - btScale;
157}
158
Yann Collet70d13012016-06-01 18:45:34 +0200159/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200160 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200161 mostly downsizing to reduce memory consumption and initialization.
162 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
163 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200164 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200165ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100166{
Yann Collet70d13012016-06-01 18:45:34 +0200167 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100168
Yann Collet70e45772016-03-19 18:08:32 +0100169 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200170 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
171 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200172 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200173 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200174 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200175 } }
Yann Collet70d13012016-06-01 18:45:34 +0200176 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100177 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
178 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
179 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100180
Yann Collet70d13012016-06-01 18:45:34 +0200181 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200182
183 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100184}
185
186
Yann Collet88472382016-07-14 17:05:38 +0200187size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100188{
Yann Collet731ef162016-07-27 21:05:12 +0200189 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
190 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
191 size_t const maxNbSeq = blockSize / divider;
192 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200193
Yann Collet731ef162016-07-27 21:05:12 +0200194 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
195 size_t const hSize = ((size_t)1) << cParams.hashLog;
196 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
197 size_t const h3Size = ((size_t)1) << hashLog3;
198 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200199
200 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
201 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
202 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200203 + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Collet3ae543c2016-07-11 03:12:17 +0200204
205 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100206}
207
Yann Colleta7737f62016-09-06 09:44:59 +0200208
209static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
210{
211 return (param1.cParams.hashLog == param2.cParams.hashLog)
212 & (param1.cParams.chainLog == param2.cParams.chainLog)
Yann Colletedbcd9f2016-09-06 14:30:57 +0200213 & (param1.cParams.strategy == param2.cParams.strategy)
214 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3));
Yann Colleta7737f62016-09-06 09:44:59 +0200215}
216
217/*! ZSTD_continueCCtx() :
218 reuse CCtx without reset (note : requires no dictionary) */
219static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
220{
221 U32 const end = (U32)(cctx->nextSrc - cctx->base);
222 cctx->params = params;
223 cctx->frameContentSize = frameContentSize;
224 cctx->lowLimit = end;
225 cctx->dictLimit = end;
226 cctx->nextToUpdate = end+1;
227 cctx->stage = ZSTDcs_init;
228 cctx->dictID = 0;
229 cctx->loadedDictEnd = 0;
230 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200231 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
232 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200233 return 0;
234}
235
236typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
237
Yann Collet27caf2a2016-04-01 15:48:48 +0200238/*! ZSTD_resetCCtx_advanced() :
Yann Colleta7737f62016-09-06 09:44:59 +0200239 note : 'params' must be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100240static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletea2ecdc2016-07-14 22:43:12 +0200241 ZSTD_parameters params, U64 frameContentSize,
Yann Collet4cb21292016-09-15 14:54:07 +0200242 ZSTD_compResetPolicy_e const crp)
Yann Colleta7737f62016-09-06 09:44:59 +0200243{
Yann Collet4cb21292016-09-15 14:54:07 +0200244 if (crp == ZSTDcrp_continue)
Yann Colleta7737f62016-09-06 09:44:59 +0200245 if (ZSTD_equivalentParams(params, zc->params))
246 return ZSTD_continueCCtx(zc, params, frameContentSize);
inikep87d4f3d2016-03-02 15:56:24 +0100247
Yann Colleta7737f62016-09-06 09:44:59 +0200248 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
249 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
250 size_t const maxNbSeq = blockSize / divider;
251 size_t const tokenSpace = blockSize + 11*maxNbSeq;
252 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
253 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
254 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
255 size_t const h3Size = ((size_t)1) << hashLog3;
256 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
257 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100258
Yann Colleta7737f62016-09-06 09:44:59 +0200259 /* Check if workSpace is large enough, alloc a new one if needed */
260 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
261 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
262 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200263 + (((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200264 if (zc->workSpaceSize < neededSpace) {
265 ZSTD_free(zc->workSpace, zc->customMem);
266 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
267 if (zc->workSpace == NULL) return ERROR(memory_allocation);
268 zc->workSpaceSize = neededSpace;
269 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100270
Yann Colleta7737f62016-09-06 09:44:59 +0200271 if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */
272 XXH64_reset(&zc->xxhState, 0);
273 zc->hashLog3 = hashLog3;
274 zc->hashTable = (U32*)(zc->workSpace);
275 zc->chainTable = zc->hashTable + hSize;
276 zc->hashTable3 = zc->chainTable + chainSize;
277 ptr = zc->hashTable3 + h3Size;
278 zc->hufTable = (HUF_CElt*)ptr;
279 zc->flagStaticTables = 0;
280 ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
Yann Collet70e8c382016-02-10 13:37:52 +0100281
Yann Colleta7737f62016-09-06 09:44:59 +0200282 zc->nextToUpdate = 1;
283 zc->nextSrc = NULL;
284 zc->base = NULL;
285 zc->dictBase = NULL;
286 zc->dictLimit = 0;
287 zc->lowLimit = 0;
288 zc->params = params;
289 zc->blockSize = blockSize;
290 zc->frameContentSize = frameContentSize;
291 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
292
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200293 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
Yann Colleta7737f62016-09-06 09:44:59 +0200294 zc->seqStore.litFreq = (U32*)ptr;
295 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
296 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
297 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
298 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
299 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
300 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
301 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
302 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
303 zc->seqStore.litLengthSum = 0;
304 }
305 zc->seqStore.sequencesStart = (seqDef*)ptr;
306 ptr = zc->seqStore.sequencesStart + maxNbSeq;
307 zc->seqStore.llCode = (BYTE*) ptr;
308 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
309 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
310 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
311
312 zc->stage = ZSTDcs_init;
313 zc->dictID = 0;
314 zc->loadedDictEnd = 0;
315
316 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100317 }
Yann Colletf3eca252015-10-22 15:31:46 +0100318}
319
Yann Collet083fcc82015-10-25 14:06:35 +0100320
Yann Collet370b08e2016-03-08 00:03:59 +0100321/*! ZSTD_copyCCtx() :
322* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet731ef162016-07-27 21:05:12 +0200323* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100324* @return : 0, or an error code */
Yann Collet97b378a2016-09-21 17:20:19 +0200325size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100326{
Yann Collet731ef162016-07-27 21:05:12 +0200327 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100328
inikep28669512016-06-02 13:04:18 +0200329 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Yann Collet97b378a2016-09-21 17:20:19 +0200330 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, pledgedSrcSize, ZSTDcrp_noMemset);
Yann Collet7b51a292016-01-26 15:58:49 +0100331
332 /* copy tables */
Yann Collet731ef162016-07-27 21:05:12 +0200333 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
334 size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
335 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
336 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100337 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
338 }
Yann Collet7b51a292016-01-26 15:58:49 +0100339
Yann Colletc46fb922016-05-29 05:01:04 +0200340 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100341 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
342 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
343 dstCCtx->nextSrc = srcCCtx->nextSrc;
344 dstCCtx->base = srcCCtx->base;
345 dstCCtx->dictBase = srcCCtx->dictBase;
346 dstCCtx->dictLimit = srcCCtx->dictLimit;
347 dstCCtx->lowLimit = srcCCtx->lowLimit;
348 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200349 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100350
Yann Colletfb810d62016-01-28 00:18:06 +0100351 /* copy entropy tables */
352 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100353 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100354 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100355 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
356 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
357 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
358 }
Yann Collet7b51a292016-01-26 15:58:49 +0100359
360 return 0;
361}
362
363
Yann Colletecabfe32016-03-20 16:20:06 +0100364/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100365* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100366static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100367{
Yann Colletecabfe32016-03-20 16:20:06 +0100368 U32 u;
369 for (u=0 ; u < size ; u++) {
370 if (table[u] < reducerValue) table[u] = 0;
371 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100372 }
373}
374
Yann Colletecabfe32016-03-20 16:20:06 +0100375/*! ZSTD_reduceIndex() :
376* rescale all indexes to avoid future overflow (indexes are U32) */
377static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
378{
Yann Collet731ef162016-07-27 21:05:12 +0200379 { U32 const hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100380 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
381
Yann Collet731ef162016-07-27 21:05:12 +0200382 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200383 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100384
Yann Collet731ef162016-07-27 21:05:12 +0200385 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100386 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
387}
388
Yann Collet89db5e02015-11-13 11:27:46 +0100389
Yann Collet863ec402016-01-28 17:56:33 +0100390/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100391* Block entropic compression
392*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100393
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200394/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100395
Yann Colletd1b26842016-03-15 01:24:33 +0100396size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100397{
Yann Colletd1b26842016-03-15 01:24:33 +0100398 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200399 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
400 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100401 return ZSTD_blockHeaderSize+srcSize;
402}
403
404
Yann Colletd1b26842016-03-15 01:24:33 +0100405static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100406{
407 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200408 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100409
Yann Colletd1b26842016-03-15 01:24:33 +0100410 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100411
Yann Collet59d1f792016-01-23 19:28:41 +0100412 switch(flSize)
413 {
414 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200415 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100416 break;
417 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200418 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100419 break;
420 default: /*note : should not be necessary : flSize is within {1,2,3} */
421 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200422 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100423 break;
424 }
425
426 memcpy(ostart + flSize, src, srcSize);
427 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100428}
429
Yann Colletd1b26842016-03-15 01:24:33 +0100430static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100431{
432 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200433 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100434
Yann Collet198e6aa2016-07-20 20:12:24 +0200435 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100436
437 switch(flSize)
438 {
439 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200440 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100441 break;
442 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200443 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100444 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100445 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100446 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200447 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100448 break;
449 }
450
451 ostart[flSize] = *(const BYTE*)src;
452 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100453}
454
Yann Collet59d1f792016-01-23 19:28:41 +0100455
Yann Colleta5c2c082016-03-20 01:09:18 +0100456static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100457
Yann Colletb923f652016-01-26 03:14:20 +0100458static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100459 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100460 const void* src, size_t srcSize)
461{
Yann Colleta910dc82016-03-18 12:37:45 +0100462 size_t const minGain = ZSTD_minGain(srcSize);
463 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200464 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100465 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200466 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100467 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100468
Yann Collet14983e72015-11-11 21:38:21 +0100469
Yann Colleta5c2c082016-03-20 01:09:18 +0100470 /* small ? don't even attempt compression (speed opt) */
471# define LITERAL_NOENTROPY 63
472 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
473 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
474 }
475
476 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100477 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200478 hType = set_repeat;
Yann Colletb923f652016-01-26 03:14:20 +0100479 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100480 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100481 } else {
Yann Colleta0d742b2016-12-01 17:47:30 -0800482 cLitSize = singleStream ? HUF_compress1X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters))
483 : HUF_compress4X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters));
Yann Colletb923f652016-01-26 03:14:20 +0100484 }
Yann Collet14983e72015-11-11 21:38:21 +0100485
Yann Collet98c88842016-07-15 16:12:38 +0200486 if ((cLitSize==0) | (cLitSize >= srcSize - minGain))
Yann Colleta910dc82016-03-18 12:37:45 +0100487 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
488 if (cLitSize==1)
489 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100490
491 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100492 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100493 {
Yann Collet59d1f792016-01-23 19:28:41 +0100494 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200495 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200496 MEM_writeLE24(ostart, lhc);
497 break;
498 }
Yann Collet59d1f792016-01-23 19:28:41 +0100499 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200500 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200501 MEM_writeLE32(ostart, lhc);
502 break;
503 }
Yann Colleta910dc82016-03-18 12:37:45 +0100504 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100505 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200506 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200507 MEM_writeLE32(ostart, lhc);
508 ostart[4] = (BYTE)(cLitSize >> 10);
509 break;
510 }
Yann Collet14983e72015-11-11 21:38:21 +0100511 }
Yann Colleta910dc82016-03-18 12:37:45 +0100512 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100513}
514
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200515static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
516 8, 9, 10, 11, 12, 13, 14, 15,
517 16, 16, 17, 17, 18, 18, 19, 19,
518 20, 20, 20, 20, 21, 21, 21, 21,
519 22, 22, 22, 22, 22, 22, 22, 22,
520 23, 23, 23, 23, 23, 23, 23, 23,
521 24, 24, 24, 24, 24, 24, 24, 24,
522 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100523
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200524static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
525 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
526 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
527 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
528 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
529 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
530 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
531 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200532
533
534void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100535{
Yann Colleted57d852016-07-29 21:22:17 +0200536 BYTE const LL_deltaCode = 19;
537 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200538 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200539 BYTE* const llCodeTable = seqStorePtr->llCode;
540 BYTE* const ofCodeTable = seqStorePtr->ofCode;
541 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200542 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200543 U32 u;
544 for (u=0; u<nbSeq; u++) {
545 U32 const llv = sequences[u].litLength;
546 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200547 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200548 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200549 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200550 }
Yann Colleted57d852016-07-29 21:22:17 +0200551 if (seqStorePtr->longLengthID==1)
552 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
553 if (seqStorePtr->longLengthID==2)
554 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100555}
556
557
Yann Colletb923f652016-01-26 03:14:20 +0100558size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100559 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100560 size_t srcSize)
561{
Yann Colletb923f652016-01-26 03:14:20 +0100562 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100563 U32 count[MaxSeq+1];
564 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100565 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
566 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
567 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100568 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200569 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200570 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
571 const BYTE* const llCodeTable = seqStorePtr->llCode;
572 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100573 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100574 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100575 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200576 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100577 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -0800578 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +0100579
Yann Collet14983e72015-11-11 21:38:21 +0100580 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100581 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100582 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100583 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100584 if (ZSTD_isError(cSize)) return cSize;
585 op += cSize;
586 }
587
588 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100589 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100590 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
591 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
592 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100593 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100594
Yann Colletbe391432016-03-22 23:19:28 +0100595 /* seqHead : flags for FSE encoding type */
596 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100597
Yann Colletfb810d62016-01-28 00:18:06 +0100598#define MIN_SEQ_FOR_DYNAMIC_FSE 64
599#define MAX_SEQ_FOR_STATIC_FSE 1000
600
Yann Colletb44be742016-03-26 20:52:14 +0100601 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +0200602 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +0100603
Yann Collet14983e72015-11-11 21:38:21 +0100604 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100605 { U32 max = MaxLL;
Yann Collete928f7e2016-12-01 16:13:35 -0800606 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100607 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
608 *op++ = llCodeTable[0];
609 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200610 LLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100611 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200612 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100613 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800614 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200615 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100616 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100617 size_t nbSeq_1 = nbSeq;
618 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
619 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
620 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100621 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
622 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
623 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800624 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200625 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100626 } }
Yann Collet14983e72015-11-11 21:38:21 +0100627
Yann Colletb44be742016-03-26 20:52:14 +0100628 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100629 { U32 max = MaxOff;
Yann Collete928f7e2016-12-01 16:13:35 -0800630 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100631 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100632 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100633 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200634 Offtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100635 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200636 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +0200637 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800638 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200639 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100640 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100641 size_t nbSeq_1 = nbSeq;
642 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100643 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100644 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100645 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
646 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
647 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800648 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200649 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100650 } }
651
Yann Collet14983e72015-11-11 21:38:21 +0100652 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100653 { U32 max = MaxML;
Yann Collete928f7e2016-12-01 16:13:35 -0800654 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100655 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100656 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100657 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200658 MLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100659 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200660 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100661 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800662 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200663 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100664 } else {
665 size_t nbSeq_1 = nbSeq;
666 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
667 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
668 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
669 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
670 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
671 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800672 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200673 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100674 } }
Yann Collet14983e72015-11-11 21:38:21 +0100675
Yann Colletbe391432016-03-22 23:19:28 +0100676 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100677 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100678
679 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100680 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100681 FSE_CState_t stateMatchLength;
682 FSE_CState_t stateOffsetBits;
683 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100684
Yann Collet95d07d72016-09-06 16:38:51 +0200685 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100686
Yann Collet597847a2016-03-20 19:14:22 +0100687 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100688 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100689 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100690 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +0200691 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100692 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200693 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100694 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200695 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100696 BIT_flushBits(&blockStream);
697
Yann Colletfadda6c2016-03-22 12:14:26 +0100698 { size_t n;
699 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +0200700 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200701 BYTE const ofCode = ofCodeTable[n];
702 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200703 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +0200704 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200705 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +0100706 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100707 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
708 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
709 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
710 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200711 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100712 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +0200713 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100714 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200715 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100716 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200717 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
Yann Colletb9151402016-03-26 17:18:11 +0100718 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100719 } }
Yann Collet14983e72015-11-11 21:38:21 +0100720
721 FSE_flushCState(&blockStream, &stateMatchLength);
722 FSE_flushCState(&blockStream, &stateOffsetBits);
723 FSE_flushCState(&blockStream, &stateLitLength);
724
Yann Colletb9151402016-03-26 17:18:11 +0100725 { size_t const streamSize = BIT_closeCStream(&blockStream);
726 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
727 op += streamSize;
728 } }
Yann Collet14983e72015-11-11 21:38:21 +0100729
730 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100731_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100732 { size_t const minGain = ZSTD_minGain(srcSize);
733 size_t const maxCSize = srcSize - minGain;
734 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100735
Yann Collet4266c0a2016-06-14 01:49:25 +0200736 /* confirm repcodes */
737 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->savedRep[i]; }
738
Yann Collet5054ee02015-11-23 13:34:21 +0100739 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100740}
741
742
Yann Collet95cd0c22016-03-08 18:24:21 +0100743/*! ZSTD_storeSeq() :
744 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
745 `offsetCode` : distance to match, or 0 == repCode.
746 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100747*/
Yann Colletd57dffb2016-07-03 01:48:26 +0200748MEM_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 +0100749{
Yann Collet45c03c52016-06-14 13:46:11 +0200750#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100751 static const BYTE* g_start = NULL;
Przemyslaw Skibinski3d180882016-11-17 18:04:41 +0100752 const U32 pos = (U32)((const BYTE*)literals - g_start);
753 if (g_start==NULL) g_start = (const BYTE*)literals;
Yann Collet4266c0a2016-06-14 01:49:25 +0200754 //if ((pos > 1) && (pos < 50000))
Yann Colletb9151402016-03-26 17:18:11 +0100755 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
Yann Collet433a5cc2016-03-25 11:43:48 +0100756 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100757#endif
Yann Collet14983e72015-11-11 21:38:21 +0100758 /* copy Literals */
759 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
760 seqStorePtr->lit += litLength;
761
762 /* literal Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200763 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
764 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100765
766 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200767 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100768
769 /* match Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200770 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
771 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +0200772
Yann Colletc0ce4f12016-07-30 00:55:13 +0200773 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +0100774}
775
776
Yann Collet7d360282016-02-12 00:07:30 +0100777/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100778* Match length counter
779***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100780static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100781{
Yann Collet863ec402016-01-28 17:56:33 +0100782 if (MEM_isLittleEndian()) {
783 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100784# if defined(_MSC_VER) && defined(_WIN64)
785 unsigned long r = 0;
786 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100787 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100788# elif defined(__GNUC__) && (__GNUC__ >= 3)
789 return (__builtin_ctzll((U64)val) >> 3);
790# else
791 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 };
792 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
793# endif
Yann Collet863ec402016-01-28 17:56:33 +0100794 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100795# if defined(_MSC_VER)
796 unsigned long r=0;
797 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100798 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100799# elif defined(__GNUC__) && (__GNUC__ >= 3)
800 return (__builtin_ctz((U32)val) >> 3);
801# else
802 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 };
803 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
804# endif
805 }
Yann Collet863ec402016-01-28 17:56:33 +0100806 } else { /* Big Endian CPU */
807 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100808# if defined(_MSC_VER) && defined(_WIN64)
809 unsigned long r = 0;
810 _BitScanReverse64( &r, val );
811 return (unsigned)(r>>3);
812# elif defined(__GNUC__) && (__GNUC__ >= 3)
813 return (__builtin_clzll(val) >> 3);
814# else
815 unsigned r;
816 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
817 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
818 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
819 r += (!val);
820 return r;
821# endif
Yann Collet863ec402016-01-28 17:56:33 +0100822 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100823# if defined(_MSC_VER)
824 unsigned long r = 0;
825 _BitScanReverse( &r, (unsigned long)val );
826 return (unsigned)(r>>3);
827# elif defined(__GNUC__) && (__GNUC__ >= 3)
828 return (__builtin_clz((U32)val) >> 3);
829# else
830 unsigned r;
831 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
832 r += (!val);
833 return r;
834# endif
Yann Collet863ec402016-01-28 17:56:33 +0100835 } }
Yann Collet14983e72015-11-11 21:38:21 +0100836}
837
838
Yann Colleta436a522016-06-20 23:34:04 +0200839static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100840{
841 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +0200842 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +0100843
Yann Colleta436a522016-06-20 23:34:04 +0200844 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +0200845 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100846 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
847 pIn += ZSTD_NbCommonBytes(diff);
848 return (size_t)(pIn - pStart);
849 }
Yann Collet14983e72015-11-11 21:38:21 +0100850 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
851 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
852 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
853 return (size_t)(pIn - pStart);
854}
855
Yann Collet04b12d82016-02-11 06:23:24 +0100856/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100857* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100858* convention : on reaching mEnd, match count continue starting from iStart
859*/
860static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
861{
Yann Collet7591a7f2016-05-20 11:44:43 +0200862 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +0200863 size_t const matchLength = ZSTD_count(ip, match, vEnd);
864 if (match + matchLength != mEnd) return matchLength;
865 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +0100866}
867
Yann Collet14983e72015-11-11 21:38:21 +0100868
Yann Collet863ec402016-01-28 17:56:33 +0100869/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100870* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100871***************************************/
inikepcc52a972016-02-19 10:09:35 +0100872static const U32 prime3bytes = 506832829U;
873static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Colletd4f4e582016-06-27 01:31:35 +0200874MEM_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 +0100875
Yann Collet4b100f42015-10-30 15:49:48 +0100876static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100877static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100878static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100879
Yann Collet4b100f42015-10-30 15:49:48 +0100880static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100881static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100882static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100883
884static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100885static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100886static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100887
Yann Collet14983e72015-11-11 21:38:21 +0100888static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100889static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100890static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100891
Yann Collet45dc3562016-07-12 09:47:31 +0200892static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
893static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
894static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
895
Yann Collet5be2dd22015-11-11 13:43:58 +0100896static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100897{
898 switch(mls)
899 {
900 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100901 case 4: return ZSTD_hash4Ptr(p, hBits);
902 case 5: return ZSTD_hash5Ptr(p, hBits);
903 case 6: return ZSTD_hash6Ptr(p, hBits);
904 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +0200905 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100906 }
907}
Yann Collet2acb5d32015-10-29 16:49:43 +0100908
Yann Collet863ec402016-01-28 17:56:33 +0100909
Yann Collet2ce49232016-02-02 14:36:49 +0100910/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100911* Fast Scan
912***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100913static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
914{
915 U32* const hashTable = zc->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200916 U32 const hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +0100917 const BYTE* const base = zc->base;
918 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +0200919 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +0100920 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +0100921
Yann Colletfb810d62016-01-28 00:18:06 +0100922 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100923 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +0100924 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +0100925 }
926}
927
928
Yann Collet1f44b3f2015-11-05 17:32:18 +0100929FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +0200930void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +0200931 const void* src, size_t srcSize,
932 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100933{
Yann Collet4266c0a2016-06-14 01:49:25 +0200934 U32* const hashTable = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200935 U32 const hBits = cctx->params.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +0200936 seqStore_t* seqStorePtr = &(cctx->seqStore);
937 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100938 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100939 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100940 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +0200941 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +0200942 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100943 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +0200944 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +0200945 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
946 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100947
Yann Collet1f44b3f2015-11-05 17:32:18 +0100948 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +0200949 ip += (ip==lowest);
950 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +0200951 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
952 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +0200953 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100954
955 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +0200956 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +0200957 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +0200958 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
959 U32 const current = (U32)(ip-base);
960 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +0100961 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +0100962 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100963
Yann Collet280f9a82016-08-08 00:44:00 +0200964 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +0200965 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +0100966 ip++;
Yann Colleta436a522016-06-20 23:34:04 +0200967 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
968 } else {
Yann Collet92d75662016-07-03 01:10:53 +0200969 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +0200970 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100971 ip += ((ip-anchor) >> g_searchStrength) + 1;
972 continue;
973 }
Yann Collet45dc3562016-07-12 09:47:31 +0200974 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +0200975 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +0200976 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +0100977 offset_2 = offset_1;
978 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +0100979
Yann Colleta436a522016-06-20 23:34:04 +0200980 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +0100981 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100982
Yann Collet402fdcf2015-11-20 12:46:08 +0100983 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +0200984 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +0100985 anchor = ip;
986
Yann Colletfb810d62016-01-28 00:18:06 +0100987 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100988 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +0100989 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 +0100990 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
991 /* check immediate repcode */
992 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +0200993 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +0200994 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100995 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +0200996 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +0200997 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +0100998 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +0200999 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1000 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001001 anchor = ip;
1002 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001003 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001004
Yann Collet4266c0a2016-06-14 01:49:25 +02001005 /* save reps for next block */
Yann Collet92d75662016-07-03 01:10:53 +02001006 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
1007 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001008
Yann Collet70e45772016-03-19 18:08:32 +01001009 /* Last Literals */
1010 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001011 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1012 seqStorePtr->lit += lastLLSize;
1013 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001014}
1015
1016
Yann Collet82260dd2016-02-11 07:14:25 +01001017static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001018 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001019{
Yann Collet3b719252016-03-30 19:48:05 +02001020 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001021 switch(mls)
1022 {
1023 default:
1024 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001025 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001026 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001027 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001028 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001029 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001030 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001031 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001032 }
1033}
Yann Colletf3eca252015-10-22 15:31:46 +01001034
Yann Colletf3eca252015-10-22 15:31:46 +01001035
Yann Collet82260dd2016-02-11 07:14:25 +01001036static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001037 const void* src, size_t srcSize,
1038 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001039{
1040 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001041 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001042 seqStore_t* seqStorePtr = &(ctx->seqStore);
1043 const BYTE* const base = ctx->base;
1044 const BYTE* const dictBase = ctx->dictBase;
1045 const BYTE* const istart = (const BYTE*)src;
1046 const BYTE* ip = istart;
1047 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001048 const U32 lowestIndex = ctx->lowLimit;
1049 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001050 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001051 const BYTE* const lowPrefixPtr = base + dictLimit;
1052 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001053 const BYTE* const iend = istart + srcSize;
1054 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001055 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001056
Yann Colleta436a522016-06-20 23:34:04 +02001057 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001058 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001059 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001060 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001061 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001062 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001063 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001064 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001065 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001066 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001067 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001068 hashTable[h] = current; /* update hash table */
1069
Yann Colleta436a522016-06-20 23:34:04 +02001070 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001071 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001072 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Colleta436a522016-06-20 23:34:04 +02001073 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001074 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001075 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001076 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001077 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001078 (MEM_read32(match) != MEM_read32(ip)) ) {
1079 ip += ((ip-anchor) >> g_searchStrength) + 1;
1080 continue;
1081 }
1082 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001083 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001084 U32 offset;
1085 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1086 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001087 offset = current - matchIndex;
1088 offset_2 = offset_1;
1089 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001090 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001091 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001092
Yann Collet5054ee02015-11-23 13:34:21 +01001093 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001094 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001095 anchor = ip;
1096
Yann Colletfb810d62016-01-28 00:18:06 +01001097 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001098 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001099 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001100 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1101 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001102 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001103 U32 const current2 = (U32)(ip-base);
1104 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001105 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001106 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1107 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001108 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001109 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001110 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001111 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001112 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001113 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001114 anchor = ip;
1115 continue;
1116 }
Yann Collet743402c2015-11-20 12:03:53 +01001117 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001118 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001119
Yann Collet4266c0a2016-06-14 01:49:25 +02001120 /* save reps for next block */
1121 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1122
Yann Collet89db5e02015-11-13 11:27:46 +01001123 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001124 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001125 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1126 seqStorePtr->lit += lastLLSize;
1127 }
Yann Collet89db5e02015-11-13 11:27:46 +01001128}
1129
1130
Yann Collet82260dd2016-02-11 07:14:25 +01001131static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001132 const void* src, size_t srcSize)
1133{
Yann Collet731ef162016-07-27 21:05:12 +02001134 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001135 switch(mls)
1136 {
1137 default:
1138 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001139 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001140 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001141 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001142 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001143 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001144 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001145 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001146 }
1147}
1148
1149
Yann Collet04b12d82016-02-11 06:23:24 +01001150/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001151* Double Fast
1152***************************************/
1153static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1154{
1155 U32* const hashLarge = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001156 U32 const hBitsL = cctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001157 U32* const hashSmall = cctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001158 U32 const hBitsS = cctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001159 const BYTE* const base = cctx->base;
1160 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001161 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001162 const size_t fastHashFillStep = 3;
1163
1164 while(ip <= iend) {
1165 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1166 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1167 ip += fastHashFillStep;
1168 }
1169}
1170
1171
1172FORCE_INLINE
1173void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1174 const void* src, size_t srcSize,
1175 const U32 mls)
1176{
1177 U32* const hashLong = cctx->hashTable;
1178 const U32 hBitsL = cctx->params.cParams.hashLog;
1179 U32* const hashSmall = cctx->chainTable;
1180 const U32 hBitsS = cctx->params.cParams.chainLog;
1181 seqStore_t* seqStorePtr = &(cctx->seqStore);
1182 const BYTE* const base = cctx->base;
1183 const BYTE* const istart = (const BYTE*)src;
1184 const BYTE* ip = istart;
1185 const BYTE* anchor = istart;
1186 const U32 lowestIndex = cctx->dictLimit;
1187 const BYTE* const lowest = base + lowestIndex;
1188 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001189 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001190 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1191 U32 offsetSaved = 0;
1192
1193 /* init */
1194 ip += (ip==lowest);
1195 { U32 const maxRep = (U32)(ip-lowest);
1196 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1197 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1198 }
1199
1200 /* Main Search Loop */
1201 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1202 size_t mLength;
1203 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1204 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1205 U32 const current = (U32)(ip-base);
1206 U32 const matchIndexL = hashLong[h2];
1207 U32 const matchIndexS = hashSmall[h];
1208 const BYTE* matchLong = base + matchIndexL;
1209 const BYTE* match = base + matchIndexS;
1210 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1211
1212 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1213 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1214 ip++;
1215 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1216 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001217 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001218 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1219 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001220 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001221 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1222 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Colletc54692f2016-08-24 01:10:42 +02001223 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1224 U32 const matchIndex3 = hashLong[h3];
1225 const BYTE* match3 = base + matchIndex3;
1226 hashLong[h3] = current + 1;
1227 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1228 mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
1229 ip++;
1230 offset = (U32)(ip-match3);
1231 while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1232 } else {
1233 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1234 offset = (U32)(ip-match);
1235 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1236 }
Yann Collet45dc3562016-07-12 09:47:31 +02001237 } else {
1238 ip += ((ip-anchor) >> g_searchStrength) + 1;
1239 continue;
1240 }
1241
1242 offset_2 = offset_1;
1243 offset_1 = offset;
1244
1245 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1246 }
1247
1248 /* match found */
1249 ip += mLength;
1250 anchor = ip;
1251
1252 if (ip <= ilimit) {
1253 /* Fill Table */
1254 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1255 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1256 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1257 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1258
1259 /* check immediate repcode */
1260 while ( (ip <= ilimit)
1261 && ( (offset_2>0)
1262 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1263 /* store sequence */
1264 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001265 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001266 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1267 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1268 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1269 ip += rLength;
1270 anchor = ip;
1271 continue; /* faster when present ... (?) */
1272 } } }
1273
1274 /* save reps for next block */
1275 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
1276 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
1277
1278 /* Last Literals */
1279 { size_t const lastLLSize = iend - anchor;
1280 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1281 seqStorePtr->lit += lastLLSize;
1282 }
1283}
1284
1285
1286static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1287{
1288 const U32 mls = ctx->params.cParams.searchLength;
1289 switch(mls)
1290 {
1291 default:
1292 case 4 :
1293 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1294 case 5 :
1295 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1296 case 6 :
1297 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1298 case 7 :
1299 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1300 }
1301}
1302
1303
1304static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1305 const void* src, size_t srcSize,
1306 const U32 mls)
1307{
1308 U32* const hashLong = ctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001309 U32 const hBitsL = ctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001310 U32* const hashSmall = ctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001311 U32 const hBitsS = ctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001312 seqStore_t* seqStorePtr = &(ctx->seqStore);
1313 const BYTE* const base = ctx->base;
1314 const BYTE* const dictBase = ctx->dictBase;
1315 const BYTE* const istart = (const BYTE*)src;
1316 const BYTE* ip = istart;
1317 const BYTE* anchor = istart;
1318 const U32 lowestIndex = ctx->lowLimit;
1319 const BYTE* const dictStart = dictBase + lowestIndex;
1320 const U32 dictLimit = ctx->dictLimit;
1321 const BYTE* const lowPrefixPtr = base + dictLimit;
1322 const BYTE* const dictEnd = dictBase + dictLimit;
1323 const BYTE* const iend = istart + srcSize;
1324 const BYTE* const ilimit = iend - 8;
1325 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1326
1327 /* Search Loop */
1328 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1329 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1330 const U32 matchIndex = hashSmall[hSmall];
1331 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1332 const BYTE* match = matchBase + matchIndex;
1333
1334 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1335 const U32 matchLongIndex = hashLong[hLong];
1336 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1337 const BYTE* matchLong = matchLongBase + matchLongIndex;
1338
1339 const U32 current = (U32)(ip-base);
1340 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1341 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1342 const BYTE* repMatch = repBase + repIndex;
1343 size_t mLength;
1344 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1345
1346 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1347 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1348 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1349 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1350 ip++;
1351 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1352 } else {
1353 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1354 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1355 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1356 U32 offset;
1357 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1358 offset = current - matchLongIndex;
1359 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1360 offset_2 = offset_1;
1361 offset_1 = offset;
1362 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001363
Yann Collet73d74a02016-07-12 13:03:48 +02001364 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001365 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1366 U32 const matchIndex3 = hashLong[h3];
1367 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1368 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001369 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001370 hashLong[h3] = current + 1;
1371 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1372 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1373 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1374 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1375 ip++;
1376 offset = current+1 - matchIndex3;
1377 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1378 } else {
1379 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1380 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1381 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1382 offset = current - matchIndex;
1383 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1384 }
Yann Collet45dc3562016-07-12 09:47:31 +02001385 offset_2 = offset_1;
1386 offset_1 = offset;
1387 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001388
Yann Collet45dc3562016-07-12 09:47:31 +02001389 } else {
1390 ip += ((ip-anchor) >> g_searchStrength) + 1;
1391 continue;
1392 } }
1393
1394 /* found a match : store it */
1395 ip += mLength;
1396 anchor = ip;
1397
1398 if (ip <= ilimit) {
1399 /* Fill Table */
1400 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1401 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1402 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1403 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1404 /* check immediate repcode */
1405 while (ip <= ilimit) {
1406 U32 const current2 = (U32)(ip-base);
1407 U32 const repIndex2 = current2 - offset_2;
1408 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1409 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1410 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1411 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1412 size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1413 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1414 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1415 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1416 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1417 ip += repLength2;
1418 anchor = ip;
1419 continue;
1420 }
1421 break;
1422 } } }
1423
1424 /* save reps for next block */
1425 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1426
1427 /* Last Literals */
1428 { size_t const lastLLSize = iend - anchor;
1429 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1430 seqStorePtr->lit += lastLLSize;
1431 }
1432}
1433
1434
1435static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1436 const void* src, size_t srcSize)
1437{
Yann Collet731ef162016-07-27 21:05:12 +02001438 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001439 switch(mls)
1440 {
1441 default:
1442 case 4 :
1443 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1444 case 5 :
1445 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1446 case 6 :
1447 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1448 case 7 :
1449 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1450 }
1451}
1452
1453
1454/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001455* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001456***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001457/** ZSTD_insertBt1() : add one or multiple positions to tree.
1458* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001459* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001460static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1461 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001462{
Yann Collet731ef162016-07-27 21:05:12 +02001463 U32* const hashTable = zc->hashTable;
1464 U32 const hashLog = zc->params.cParams.hashLog;
1465 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1466 U32* const bt = zc->chainTable;
1467 U32 const btLog = zc->params.cParams.chainLog - 1;
1468 U32 const btMask = (1 << btLog) - 1;
1469 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001470 size_t commonLengthSmaller=0, commonLengthLarger=0;
1471 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001472 const BYTE* const dictBase = zc->dictBase;
1473 const U32 dictLimit = zc->dictLimit;
1474 const BYTE* const dictEnd = dictBase + dictLimit;
1475 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001476 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001477 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001478 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001479 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001480 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001481 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001482 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001483 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001484 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001485#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001486 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1487 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1488 predictedSmall += (predictedSmall>0);
1489 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001490#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001491
Yann Collet6c3e2e72015-12-11 10:44:07 +01001492 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001493
Yann Colletfb810d62016-01-28 00:18:06 +01001494 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001495 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001496 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001497
Yann Colletc0932082016-06-30 14:07:30 +02001498#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001499 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001500 if (matchIndex == predictedSmall) {
1501 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001502 *smallerPtr = matchIndex;
1503 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1504 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1505 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001506 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001507 continue;
1508 }
Yann Colletfb810d62016-01-28 00:18:06 +01001509 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001510 *largerPtr = matchIndex;
1511 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1512 largerPtr = nextPtr;
1513 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001514 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001515 continue;
1516 }
Yann Collet04b12d82016-02-11 06:23:24 +01001517#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001518 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001519 match = base + matchIndex;
1520 if (match[matchLength] == ip[matchLength])
1521 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001522 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001523 match = dictBase + matchIndex;
1524 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1525 if (matchIndex+matchLength >= dictLimit)
1526 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1527 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001528
Yann Colletb8a6f682016-02-15 17:06:29 +01001529 if (matchLength > bestLength) {
1530 bestLength = matchLength;
1531 if (matchLength > matchEndIdx - matchIndex)
1532 matchEndIdx = matchIndex + (U32)matchLength;
1533 }
Yann Colletee3f4512015-12-29 22:26:09 +01001534
Yann Collet59d70632015-11-04 12:05:27 +01001535 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001536 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001537
Yann Colletfb810d62016-01-28 00:18:06 +01001538 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001539 /* match is smaller than current */
1540 *smallerPtr = matchIndex; /* update smaller idx */
1541 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001542 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001543 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001544 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001545 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001546 /* match is larger than current */
1547 *largerPtr = matchIndex;
1548 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001549 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001550 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001551 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001552 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001553
Yann Collet59d70632015-11-04 12:05:27 +01001554 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001555 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001556 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1557 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001558}
1559
1560
Yann Collet82260dd2016-02-11 07:14:25 +01001561static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001562 ZSTD_CCtx* zc,
1563 const BYTE* const ip, const BYTE* const iend,
1564 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001565 U32 nbCompares, const U32 mls,
1566 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001567{
Yann Collet731ef162016-07-27 21:05:12 +02001568 U32* const hashTable = zc->hashTable;
1569 U32 const hashLog = zc->params.cParams.hashLog;
1570 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1571 U32* const bt = zc->chainTable;
1572 U32 const btLog = zc->params.cParams.chainLog - 1;
1573 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001574 U32 matchIndex = hashTable[h];
1575 size_t commonLengthSmaller=0, commonLengthLarger=0;
1576 const BYTE* const base = zc->base;
1577 const BYTE* const dictBase = zc->dictBase;
1578 const U32 dictLimit = zc->dictLimit;
1579 const BYTE* const dictEnd = dictBase + dictLimit;
1580 const BYTE* const prefixStart = base + dictLimit;
1581 const U32 current = (U32)(ip-base);
1582 const U32 btLow = btMask >= current ? 0 : current - btMask;
1583 const U32 windowLow = zc->lowLimit;
1584 U32* smallerPtr = bt + 2*(current&btMask);
1585 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001586 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001587 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001588 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001589
Yann Collet6c3e2e72015-12-11 10:44:07 +01001590 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001591
Yann Colletfb810d62016-01-28 00:18:06 +01001592 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001593 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01001594 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1595 const BYTE* match;
1596
Yann Colletfb810d62016-01-28 00:18:06 +01001597 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001598 match = base + matchIndex;
1599 if (match[matchLength] == ip[matchLength])
1600 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001601 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001602 match = dictBase + matchIndex;
1603 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001604 if (matchIndex+matchLength >= dictLimit)
1605 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001606 }
1607
Yann Colletfb810d62016-01-28 00:18:06 +01001608 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001609 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001610 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001611 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001612 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001613 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1614 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1615 }
1616
Yann Colletfb810d62016-01-28 00:18:06 +01001617 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001618 /* match is smaller than current */
1619 *smallerPtr = matchIndex; /* update smaller idx */
1620 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1621 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1622 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1623 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001624 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001625 /* match is larger than current */
1626 *largerPtr = matchIndex;
1627 commonLengthLarger = matchLength;
1628 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1629 largerPtr = nextPtr;
1630 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001631 } }
Yann Collet03526e12015-11-23 15:29:15 +01001632
1633 *smallerPtr = *largerPtr = 0;
1634
Yann Collet72e84cf2015-12-31 19:08:44 +01001635 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001636 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001637}
1638
Yann Collet2cc12cb2016-01-01 07:47:58 +01001639
Yann Colletb8a6f682016-02-15 17:06:29 +01001640static 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 +01001641{
1642 const BYTE* const base = zc->base;
1643 const U32 target = (U32)(ip - base);
1644 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001645
1646 while(idx < target)
1647 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001648}
1649
Yann Collet52447382016-03-20 16:00:00 +01001650/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001651static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001652 ZSTD_CCtx* zc,
1653 const BYTE* const ip, const BYTE* const iLimit,
1654 size_t* offsetPtr,
1655 const U32 maxNbAttempts, const U32 mls)
1656{
1657 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001658 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001659 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1660}
1661
1662
Yann Collet768c6bc2016-02-10 14:01:49 +01001663static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001664 ZSTD_CCtx* zc, /* Index table will be updated */
1665 const BYTE* ip, const BYTE* const iLimit,
1666 size_t* offsetPtr,
1667 const U32 maxNbAttempts, const U32 matchLengthSearch)
1668{
1669 switch(matchLengthSearch)
1670 {
1671 default :
1672 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1673 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1674 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1675 }
1676}
1677
1678
Yann Colletb8a6f682016-02-15 17:06:29 +01001679static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1680{
1681 const BYTE* const base = zc->base;
1682 const U32 target = (U32)(ip - base);
1683 U32 idx = zc->nextToUpdate;
1684
1685 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1686}
1687
inikep64d7bcb2016-04-07 19:14:09 +02001688
Yann Collet03526e12015-11-23 15:29:15 +01001689/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001690static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001691 ZSTD_CCtx* zc,
1692 const BYTE* const ip, const BYTE* const iLimit,
1693 size_t* offsetPtr,
1694 const U32 maxNbAttempts, const U32 mls)
1695{
Yann Colletee3f4512015-12-29 22:26:09 +01001696 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001697 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001698 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001699}
1700
1701
Yann Collet82260dd2016-02-11 07:14:25 +01001702static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001703 ZSTD_CCtx* zc, /* Index table will be updated */
1704 const BYTE* ip, const BYTE* const iLimit,
1705 size_t* offsetPtr,
1706 const U32 maxNbAttempts, const U32 matchLengthSearch)
1707{
1708 switch(matchLengthSearch)
1709 {
1710 default :
1711 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1712 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1713 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1714 }
1715}
1716
1717
Yann Collet5106a762015-11-05 15:00:24 +01001718
Yann Collet731ef162016-07-27 21:05:12 +02001719/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02001720* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02001721***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02001722#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1723
1724/* Update chains up to ip (excluded)
1725 Assumption : always within prefix (ie. not within extDict) */
1726FORCE_INLINE
1727U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1728{
1729 U32* const hashTable = zc->hashTable;
1730 const U32 hashLog = zc->params.cParams.hashLog;
1731 U32* const chainTable = zc->chainTable;
1732 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1733 const BYTE* const base = zc->base;
1734 const U32 target = (U32)(ip - base);
1735 U32 idx = zc->nextToUpdate;
1736
Yann Collet22d76322016-06-21 08:01:51 +02001737 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001738 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1739 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1740 hashTable[h] = idx;
1741 idx++;
1742 }
1743
1744 zc->nextToUpdate = target;
1745 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1746}
1747
1748
1749
1750FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1751size_t ZSTD_HcFindBestMatch_generic (
1752 ZSTD_CCtx* zc, /* Index table will be updated */
1753 const BYTE* const ip, const BYTE* const iLimit,
1754 size_t* offsetPtr,
1755 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1756{
1757 U32* const chainTable = zc->chainTable;
1758 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1759 const U32 chainMask = chainSize-1;
1760 const BYTE* const base = zc->base;
1761 const BYTE* const dictBase = zc->dictBase;
1762 const U32 dictLimit = zc->dictLimit;
1763 const BYTE* const prefixStart = base + dictLimit;
1764 const BYTE* const dictEnd = dictBase + dictLimit;
1765 const U32 lowLimit = zc->lowLimit;
1766 const U32 current = (U32)(ip-base);
1767 const U32 minChain = current > chainSize ? current - chainSize : 0;
1768 int nbAttempts=maxNbAttempts;
1769 size_t ml=EQUAL_READ32-1;
1770
1771 /* HC4 match finder */
1772 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1773
Yann Collet22d76322016-06-21 08:01:51 +02001774 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001775 const BYTE* match;
1776 size_t currentMl=0;
1777 if ((!extDict) || matchIndex >= dictLimit) {
1778 match = base + matchIndex;
1779 if (match[ml] == ip[ml]) /* potentially better */
1780 currentMl = ZSTD_count(ip, match, iLimit);
1781 } else {
1782 match = dictBase + matchIndex;
1783 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1784 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1785 }
1786
1787 /* save best solution */
Yann Collet22d76322016-06-21 08:01:51 +02001788 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 +02001789
1790 if (matchIndex <= minChain) break;
1791 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1792 }
1793
1794 return ml;
1795}
1796
1797
1798FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1799 ZSTD_CCtx* zc,
1800 const BYTE* ip, const BYTE* const iLimit,
1801 size_t* offsetPtr,
1802 const U32 maxNbAttempts, const U32 matchLengthSearch)
1803{
1804 switch(matchLengthSearch)
1805 {
1806 default :
1807 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1808 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1809 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1810 }
1811}
1812
1813
1814FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1815 ZSTD_CCtx* zc,
1816 const BYTE* ip, const BYTE* const iLimit,
1817 size_t* offsetPtr,
1818 const U32 maxNbAttempts, const U32 matchLengthSearch)
1819{
1820 switch(matchLengthSearch)
1821 {
1822 default :
1823 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1824 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1825 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1826 }
1827}
1828
inikep64d7bcb2016-04-07 19:14:09 +02001829
Yann Collet287b7d92015-11-22 13:24:05 +01001830/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001831* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001832*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001833FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001834void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1835 const void* src, size_t srcSize,
1836 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001837{
inikepfaa8d8a2016-04-05 19:01:10 +02001838 seqStore_t* seqStorePtr = &(ctx->seqStore);
1839 const BYTE* const istart = (const BYTE*)src;
1840 const BYTE* ip = istart;
1841 const BYTE* anchor = istart;
1842 const BYTE* const iend = istart + srcSize;
1843 const BYTE* const ilimit = iend - 8;
1844 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001845
Yann Collet793c6492016-04-09 20:32:00 +02001846 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1847 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001848
inikep64d7bcb2016-04-07 19:14:09 +02001849 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1850 size_t* offsetPtr,
1851 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02001852 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02001853 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02001854
inikepfaa8d8a2016-04-05 19:01:10 +02001855 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001856 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02001857 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02001858 { U32 const maxRep = (U32)(ip-base);
1859 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1860 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1861 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001862
inikepfaa8d8a2016-04-05 19:01:10 +02001863 /* Match Loop */
1864 while (ip < ilimit) {
1865 size_t matchLength=0;
1866 size_t offset=0;
1867 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001868
inikepfaa8d8a2016-04-05 19:01:10 +02001869 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02001870 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02001871 /* repcode : we take it */
Yann Collet9634f672016-07-03 01:23:58 +02001872 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001873 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001874 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001875
inikepfaa8d8a2016-04-05 19:01:10 +02001876 /* first search (depth 0) */
1877 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001878 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001879 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001880 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001881 }
Yann Collet5106a762015-11-05 15:00:24 +01001882
inikep7bc19b62016-04-06 09:46:01 +02001883 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001884 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1885 continue;
1886 }
1887
inikep64d7bcb2016-04-07 19:14:09 +02001888 /* let's try to find a better solution */
1889 if (depth>=1)
1890 while (ip<ilimit) {
1891 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001892 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1893 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001894 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001895 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001896 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1897 matchLength = mlRep, offset = 0, start = ip;
1898 }
1899 { size_t offset2=99999999;
1900 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001901 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1902 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001903 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1904 matchLength = ml2, offset = offset2, start = ip;
1905 continue; /* search a better one */
1906 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001907
inikep64d7bcb2016-04-07 19:14:09 +02001908 /* let's find an even better one */
1909 if ((depth==2) && (ip<ilimit)) {
1910 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001911 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1912 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001913 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001914 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001915 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1916 matchLength = ml2, offset = 0, start = ip;
1917 }
1918 { size_t offset2=99999999;
1919 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001920 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1921 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001922 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1923 matchLength = ml2, offset = offset2, start = ip;
1924 continue;
1925 } } }
1926 break; /* nothing found : store previous solution */
1927 }
1928
1929 /* catch up */
1930 if (offset) {
1931 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1932 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02001933 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02001934 }
1935
inikepfaa8d8a2016-04-05 19:01:10 +02001936 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001937_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001938 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02001939 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02001940 anchor = ip = start + matchLength;
1941 }
Yann Collet48537162016-04-07 15:24:29 +02001942
inikepfaa8d8a2016-04-05 19:01:10 +02001943 /* check immediate repcode */
1944 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02001945 && ((offset_2>0)
1946 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02001947 /* store sequence */
Yann Collet9634f672016-07-03 01:23:58 +02001948 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
1949 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001950 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1951 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001952 anchor = ip;
1953 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02001954 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001955
Yann Collet4266c0a2016-06-14 01:49:25 +02001956 /* Save reps for next block */
Yann Collet9634f672016-07-03 01:23:58 +02001957 ctx->savedRep[0] = offset_1 ? offset_1 : savedOffset;
1958 ctx->savedRep[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02001959
inikepfaa8d8a2016-04-05 19:01:10 +02001960 /* Last Literals */
1961 { size_t const lastLLSize = iend - anchor;
1962 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1963 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01001964 }
Yann Collet5106a762015-11-05 15:00:24 +01001965}
1966
Yann Collet5be2dd22015-11-11 13:43:58 +01001967
inikep64d7bcb2016-04-07 19:14:09 +02001968static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1969{
1970 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
1971}
1972
1973static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1974{
1975 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
1976}
1977
1978static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1979{
1980 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
1981}
1982
1983static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1984{
1985 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
1986}
1987
1988
inikepfaa8d8a2016-04-05 19:01:10 +02001989FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001990void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1991 const void* src, size_t srcSize,
1992 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01001993{
inikepfaa8d8a2016-04-05 19:01:10 +02001994 seqStore_t* seqStorePtr = &(ctx->seqStore);
1995 const BYTE* const istart = (const BYTE*)src;
1996 const BYTE* ip = istart;
1997 const BYTE* anchor = istart;
1998 const BYTE* const iend = istart + srcSize;
1999 const BYTE* const ilimit = iend - 8;
2000 const BYTE* const base = ctx->base;
2001 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002002 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002003 const BYTE* const prefixStart = base + dictLimit;
2004 const BYTE* const dictBase = ctx->dictBase;
2005 const BYTE* const dictEnd = dictBase + dictLimit;
2006 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2007
2008 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2009 const U32 mls = ctx->params.cParams.searchLength;
2010
inikep64d7bcb2016-04-07 19:14:09 +02002011 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2012 size_t* offsetPtr,
2013 U32 maxNbAttempts, U32 matchLengthSearch);
2014 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2015
Yann Collet302ff032016-07-03 01:28:16 +02002016 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002017
Yann Collet302ff032016-07-03 01:28:16 +02002018 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002019 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002020 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002021
2022 /* Match Loop */
2023 while (ip < ilimit) {
2024 size_t matchLength=0;
2025 size_t offset=0;
2026 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002027 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002028
2029 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002030 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002031 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2032 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002033 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002034 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002035 /* repcode detected we should take it */
2036 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02002037 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2038 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002039 } }
2040
2041 /* first search (depth 0) */
2042 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002043 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002044 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002045 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002046 }
2047
inikep7bc19b62016-04-06 09:46:01 +02002048 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02002049 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2050 continue;
2051 }
2052
inikep64d7bcb2016-04-07 19:14:09 +02002053 /* let's try to find a better solution */
2054 if (depth>=1)
2055 while (ip<ilimit) {
2056 ip ++;
2057 current++;
2058 /* check repCode */
2059 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002060 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +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) == MEM_read32(repMatch)) {
2065 /* repcode detected */
2066 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2067 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2068 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002069 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002070 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2071 matchLength = repLength, offset = 0, start = ip;
2072 } }
2073
2074 /* search match, depth 1 */
2075 { size_t offset2=99999999;
2076 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002077 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2078 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02002079 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2080 matchLength = ml2, offset = offset2, start = ip;
2081 continue; /* search a better one */
2082 } }
2083
2084 /* let's find an even better one */
2085 if ((depth==2) && (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 repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2098 int gain2 = (int)(repLength * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002099 int gain1 = (int)(matchLength*4 - 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 2 */
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) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02002109 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2110 matchLength = ml2, offset = offset2, start = ip;
2111 continue;
2112 } } }
2113 break; /* nothing found : store previous solution */
2114 }
2115
inikepfaa8d8a2016-04-05 19:01:10 +02002116 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002117 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002118 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002119 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2120 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002121 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002122 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002123 }
inikepfaa8d8a2016-04-05 19:01:10 +02002124
inikepfaa8d8a2016-04-05 19:01:10 +02002125 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002126_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002127 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002128 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002129 anchor = ip = start + matchLength;
2130 }
2131
2132 /* check immediate repcode */
2133 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002134 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002135 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2136 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002137 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002138 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2139 /* repcode detected we should take it */
2140 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02002141 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
Yann Collet302ff032016-07-03 01:28:16 +02002142 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002143 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2144 ip += matchLength;
2145 anchor = ip;
2146 continue; /* faster when present ... (?) */
2147 }
2148 break;
2149 } }
2150
Yann Collet4266c0a2016-06-14 01:49:25 +02002151 /* Save reps for next block */
Yann Collet302ff032016-07-03 01:28:16 +02002152 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002153
inikepfaa8d8a2016-04-05 19:01:10 +02002154 /* Last Literals */
2155 { size_t const lastLLSize = iend - anchor;
2156 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2157 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002158 }
2159}
2160
2161
Yann Collet59d1f792016-01-23 19:28:41 +01002162void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002163{
inikep64d7bcb2016-04-07 19:14:09 +02002164 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002165}
2166
Yann Collet59d1f792016-01-23 19:28:41 +01002167static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002168{
Yann Colleta1249dc2016-01-25 04:22:03 +01002169 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002170}
Yann Collet9a24e592015-11-22 02:53:43 +01002171
Yann Collet59d1f792016-01-23 19:28:41 +01002172static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002173{
Yann Colleta1249dc2016-01-25 04:22:03 +01002174 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002175}
2176
Yann Collet59d1f792016-01-23 19:28:41 +01002177static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002178{
Yann Colleta1249dc2016-01-25 04:22:03 +01002179 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002180}
2181
inikepef519412016-04-21 11:08:43 +02002182
inikepef519412016-04-21 11:08:43 +02002183/* The optimal parser */
2184#include "zstd_opt.h"
2185
2186static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2187{
Yann Colletd4f4e582016-06-27 01:31:35 +02002188#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002189 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2190#else
2191 (void)ctx; (void)src; (void)srcSize;
2192 return;
2193#endif
2194}
2195
2196static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2197{
2198#ifdef ZSTD_OPT_H_91842398743
2199 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002200#else
2201 (void)ctx; (void)src; (void)srcSize;
2202 return;
2203#endif
inikepef519412016-04-21 11:08:43 +02002204}
2205
inikepd3b8d7a2016-02-22 10:06:17 +01002206static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002207{
Yann Colletd4f4e582016-06-27 01:31:35 +02002208#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002209 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2210#else
2211 (void)ctx; (void)src; (void)srcSize;
2212 return;
2213#endif
2214}
2215
2216static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2217{
2218#ifdef ZSTD_OPT_H_91842398743
2219 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002220#else
2221 (void)ctx; (void)src; (void)srcSize;
2222 return;
2223#endif
inikepe2bfe242016-01-31 11:25:48 +01002224}
2225
Yann Collet7a231792015-11-21 15:27:35 +01002226
Yann Collet59d1f792016-01-23 19:28:41 +01002227typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002228
Yann Colletb923f652016-01-26 03:14:20 +01002229static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002230{
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002231 static const ZSTD_blockCompressor blockCompressor[2][8] = {
2232 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 },
2233 { 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 +01002234 };
2235
2236 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002237}
2238
2239
Yann Colletd1b26842016-03-15 01:24:33 +01002240static 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 +01002241{
Yann Collet19cab462016-06-17 12:54:52 +02002242 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002243 const BYTE* const base = zc->base;
2244 const BYTE* const istart = (const BYTE*)src;
2245 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002246 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 +02002247 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002248 if (current > zc->nextToUpdate + 384)
2249 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 +01002250 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002251 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002252}
2253
2254
Yann Colletc991cc12016-07-28 00:55:43 +02002255/*! ZSTD_compress_generic() :
2256* Compress a chunk of data into one or multiple blocks.
2257* All blocks will be terminated, all input will be consumed.
2258* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2259* Frame is supposed already started (header already produced)
2260* @return : compressed size, or an error code
2261*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002262static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2263 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002264 const void* src, size_t srcSize,
2265 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002266{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002267 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002268 size_t remaining = srcSize;
2269 const BYTE* ip = (const BYTE*)src;
2270 BYTE* const ostart = (BYTE*)dst;
2271 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002272 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002273
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002274 if (cctx->params.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002275 XXH64_update(&cctx->xxhState, src, srcSize);
2276
Yann Collet2ce49232016-02-02 14:36:49 +01002277 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002278 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002279 size_t cSize;
2280
inikepfb5df612016-05-24 15:36:37 +02002281 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 +01002282 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002283
Yann Collet346efcc2016-08-02 14:26:00 +02002284 /* preemptive overflow correction */
Yann Colletc261f712016-12-12 00:25:07 +01002285 if (cctx->lowLimit > (2U<<30)) {
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002286 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002287 U32 const current = (U32)(ip - cctx->base);
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002288 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002289 U32 const correction = current - newCurrent;
2290 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002291 ZSTD_reduceIndex(cctx, correction);
2292 cctx->base += correction;
2293 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002294 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002295 cctx->dictLimit -= correction;
2296 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2297 else cctx->nextToUpdate -= correction;
2298 }
2299
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002300 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002301 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002302 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2303 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2304 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002305 }
Yann Collet89db5e02015-11-13 11:27:46 +01002306
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002307 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002308 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002309
Yann Collet2ce49232016-02-02 14:36:49 +01002310 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002311 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2312 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2313 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2314 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2315 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002316 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002317 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002318 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002319 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002320 }
2321
2322 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002323 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002324 ip += blockSize;
2325 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002326 }
2327
Yann Collet62470b42016-07-28 15:29:08 +02002328 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002329 return op-ostart;
2330}
2331
2332
Yann Collet6236eba2016-04-12 15:52:33 +02002333static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002334 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002335{ BYTE* const op = (BYTE*)dst;
Yann Collet731ef162016-07-27 21:05:12 +02002336 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2337 U32 const checksumFlag = params.fParams.checksumFlag>0;
2338 U32 const windowSize = 1U << params.cParams.windowLog;
2339 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize > (pledgedSrcSize-1));
2340 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2341 U32 const fcsCode = params.fParams.contentSizeFlag ?
Yann Collet673f0d72016-06-06 00:26:38 +02002342 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2343 0;
Yann Collet731ef162016-07-27 21:05:12 +02002344 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002345 size_t pos;
2346
2347 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002348
2349 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002350 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002351 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002352 switch(dictIDSizeCode)
2353 {
2354 default: /* impossible */
2355 case 0 : break;
2356 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002357 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002358 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2359 }
Yann Collet673f0d72016-06-06 00:26:38 +02002360 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002361 {
2362 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002363 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002364 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2365 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002366 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002367 }
Yann Colletc46fb922016-05-29 05:01:04 +02002368 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002369}
2370
2371
Yann Collet346efcc2016-08-02 14:26:00 +02002372static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002373 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002374 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002375 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002376{
Yann Collet2acb5d32015-10-29 16:49:43 +01002377 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002378 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002379
Yann Collet346efcc2016-08-02 14:26:00 +02002380 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002381
Yann Collet346efcc2016-08-02 14:26:00 +02002382 if (frame && (cctx->stage==ZSTDcs_init)) {
2383 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002384 if (ZSTD_isError(fhSize)) return fhSize;
2385 dstCapacity -= fhSize;
2386 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002387 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002388 }
Yann Colletf3eca252015-10-22 15:31:46 +01002389
Yann Collet417890c2015-12-04 17:16:37 +01002390 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002391 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002392 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002393 ptrdiff_t const delta = cctx->nextSrc - ip;
2394 cctx->lowLimit = cctx->dictLimit;
2395 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2396 cctx->dictBase = cctx->base;
2397 cctx->base -= delta;
2398 cctx->nextToUpdate = cctx->dictLimit;
2399 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002400 }
2401
Yann Collet346efcc2016-08-02 14:26:00 +02002402 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2403 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2404 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2405 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2406 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002407 }
2408
Yann Collet346efcc2016-08-02 14:26:00 +02002409 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002410
Yann Collet70e45772016-03-19 18:08:32 +01002411 { size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002412 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2413 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002414 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002415 return cSize + fhSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002416 }
Yann Colletf3eca252015-10-22 15:31:46 +01002417}
2418
Yann Colletbf42c8e2016-01-09 01:08:23 +01002419
Yann Collet5b567392016-07-28 01:17:22 +02002420size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002421 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002422 const void* src, size_t srcSize)
2423{
Yann Collet5b567392016-07-28 01:17:22 +02002424 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
2425}
2426
2427
Yann Colletcf05b9d2016-07-18 16:52:10 +02002428size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002429{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002430 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2431}
2432
2433size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2434{
2435 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002436 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Colletc991cc12016-07-28 00:55:43 +02002437 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002438}
2439
2440
Yann Colletb923f652016-01-26 03:14:20 +01002441static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002442{
2443 const BYTE* const ip = (const BYTE*) src;
2444 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002445
Yann Collet417890c2015-12-04 17:16:37 +01002446 /* input becomes current prefix */
2447 zc->lowLimit = zc->dictLimit;
2448 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2449 zc->dictBase = zc->base;
2450 zc->base += ip - zc->nextSrc;
2451 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002452 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002453
2454 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002455 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002456
Yann Collet3b719252016-03-30 19:48:05 +02002457 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002458 {
2459 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002460 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002461 break;
2462
Yann Collet45dc3562016-07-12 09:47:31 +02002463 case ZSTD_dfast:
2464 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2465 break;
2466
Yann Collet417890c2015-12-04 17:16:37 +01002467 case ZSTD_greedy:
2468 case ZSTD_lazy:
2469 case ZSTD_lazy2:
Yann Collet731ef162016-07-27 21:05:12 +02002470 ZSTD_insertAndFindFirstIndex (zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002471 break;
2472
2473 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002474 case ZSTD_btopt:
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002475 case ZSTD_btopt2:
Yann Collet731ef162016-07-27 21:05:12 +02002476 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002477 break;
2478
2479 default:
2480 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2481 }
2482
Yann Collet2ce49232016-02-02 14:36:49 +01002483 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002484 return 0;
2485}
2486
2487
Nick Terrellf9c9af32016-10-19 17:22:08 -07002488/* Dictionaries that assign zero probability to symbols that show up causes problems
2489 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2490 that we may encounter during compression.
2491 NOTE: This behavior is not standard and could be improved in the future. */
2492static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2493 U32 s;
2494 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2495 for (s = 0; s <= maxSymbolValue; ++s) {
2496 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2497 }
2498 return 0;
2499}
2500
2501
Yann Colletb923f652016-01-26 03:14:20 +01002502/* Dictionary format :
Yann Colletee5b7252016-10-27 14:20:55 -07002503 Magic == ZSTD_DICT_MAGIC (4 bytes)
2504 HUF_writeCTable(256)
2505 FSE_writeNCount(off)
2506 FSE_writeNCount(ml)
2507 FSE_writeNCount(ll)
2508 RepOffsets
2509 Dictionary content
Yann Colletb923f652016-01-26 03:14:20 +01002510*/
Yann Colletfb797352016-03-13 11:08:40 +01002511/*! ZSTD_loadDictEntropyStats() :
Yann Collet736d4192016-06-15 18:48:51 +02002512 @return : size read from dictionary
2513 note : magic number supposed already checked */
2514static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002515{
Yann Collet52a06222016-06-15 13:53:34 +02002516 const BYTE* dictPtr = (const BYTE*)dict;
2517 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07002518 short offcodeNCount[MaxOff+1];
2519 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08002520 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01002521
Yann Collet736d4192016-06-15 18:48:51 +02002522 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002523 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002524 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002525 }
Yann Colletfb810d62016-01-28 00:18:06 +01002526
Nick Terrellf9c9af32016-10-19 17:22:08 -07002527 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02002528 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002529 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002530 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002531 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Collet643d9a22016-12-01 16:24:04 -08002532 CHECK_E (FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002533 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002534 }
Yann Colletfb810d62016-01-28 00:18:06 +01002535
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002536 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002537 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002538 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002539 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002540 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002541 /* Every match length code must have non-zero probability */
2542 CHECK_F (ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
Yann Collet643d9a22016-12-01 16:24:04 -08002543 CHECK_E (FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002544 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002545 }
Yann Colletfb810d62016-01-28 00:18:06 +01002546
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002547 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002548 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002549 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002550 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002551 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002552 /* Every literal length code must have non-zero probability */
2553 CHECK_F (ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
Yann Collet643d9a22016-12-01 16:24:04 -08002554 CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002555 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002556 }
Yann Colletfb810d62016-01-28 00:18:06 +01002557
Yann Collet52a06222016-06-15 13:53:34 +02002558 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Nick Terrell8157a4c2016-12-20 10:47:52 -08002559 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] == 0 || cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2560 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] == 0 || cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2561 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 +02002562 dictPtr += 12;
2563
Nick Terrellb2c39a22016-10-24 14:11:27 -07002564 { U32 offcodeMax = MaxOff;
2565 if ((size_t)(dictEnd - dictPtr) <= ((U32)-1) - 128 KB) {
2566 U32 const maxOffset = (U32)(dictEnd - dictPtr) + 128 KB; /* The maximum offset that must be supported */
2567 /* Calculate minimum offset code required to represent maxOffset */
2568 offcodeMax = ZSTD_highbit32(maxOffset);
2569 }
Nick Terrellf9c9af32016-10-19 17:22:08 -07002570 /* Every possible supported offset <= dictContentSize + 128 KB must be representable */
2571 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
2572 }
2573
Yann Collet736d4192016-06-15 18:48:51 +02002574 cctx->flagStaticTables = 1;
Yann Collet52a06222016-06-15 13:53:34 +02002575 return dictPtr - (const BYTE*)dict;
Yann Colletb923f652016-01-26 03:14:20 +01002576}
2577
Yann Colletd1b26842016-03-15 01:24:33 +01002578/** ZSTD_compress_insertDictionary() :
2579* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002580static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002581{
Yann Colletc46fb922016-05-29 05:01:04 +02002582 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002583
Yann Colletd1b26842016-03-15 01:24:33 +01002584 /* default : dict is pure content */
2585 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletc46fb922016-05-29 05:01:04 +02002586 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
Yann Colletd1b26842016-03-15 01:24:33 +01002587
2588 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet3e21ec52016-09-06 15:36:19 +02002589 { size_t const loadError = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8);
2590 size_t const eSize = loadError + 8;
2591 if (ZSTD_isError(loadError)) return loadError;
Yann Collet21588e32016-03-30 16:50:44 +02002592 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002593 }
Yann Colletecd651b2016-01-07 15:35:18 +01002594}
2595
Yann Collet0085cd32016-04-12 14:14:10 +02002596
Yann Collet27caf2a2016-04-01 15:48:48 +02002597/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002598* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002599static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002600 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002601 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002602{
Yann Colleta7737f62016-09-06 09:44:59 +02002603 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
Yann Collet3e21ec52016-09-06 15:36:19 +02002604 CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp));
Yann Colleta7737f62016-09-06 09:44:59 +02002605 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002606}
2607
2608
Yann Collet27caf2a2016-04-01 15:48:48 +02002609/*! ZSTD_compressBegin_advanced() :
2610* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002611size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002612 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002613 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002614{
2615 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02002616 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet81e13ef2016-06-07 00:51:51 +02002617 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002618}
2619
2620
Yann Collet81e13ef2016-06-07 00:51:51 +02002621size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002622{
Yann Collet6c6e1752016-06-27 15:28:45 +02002623 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002624 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002625}
Yann Collet083fcc82015-10-25 14:06:35 +01002626
inikep19bd48f2016-04-04 12:10:00 +02002627
Yann Collet1c8e1942016-01-26 16:31:22 +01002628size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002629{
Yann Collet3b719252016-03-30 19:48:05 +02002630 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002631}
2632
2633
Yann Collet62470b42016-07-28 15:29:08 +02002634/*! ZSTD_writeEpilogue() :
2635* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002636* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002637static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002638{
Yann Colletc991cc12016-07-28 00:55:43 +02002639 BYTE* const ostart = (BYTE*)dst;
2640 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002641 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002642
Yann Collet87c18b22016-08-26 01:43:47 +02002643 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002644
2645 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002646 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002647 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002648 if (ZSTD_isError(fhSize)) return fhSize;
2649 dstCapacity -= fhSize;
2650 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002651 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002652 }
2653
Yann Colletc991cc12016-07-28 00:55:43 +02002654 if (cctx->stage != ZSTDcs_ending) {
2655 /* write one last empty block, make it the "last" block */
2656 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2657 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2658 MEM_writeLE32(op, cBlockHeader24);
2659 op += ZSTD_blockHeaderSize;
2660 dstCapacity -= ZSTD_blockHeaderSize;
2661 }
2662
2663 if (cctx->params.fParams.checksumFlag) {
2664 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2665 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2666 MEM_writeLE32(op, checksum);
2667 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002668 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002669
Yann Collet731ef162016-07-27 21:05:12 +02002670 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002671 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002672}
2673
Yann Colletfd416f12016-01-30 03:14:15 +01002674
Yann Collet62470b42016-07-28 15:29:08 +02002675size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2676 void* dst, size_t dstCapacity,
2677 const void* src, size_t srcSize)
2678{
2679 size_t endResult;
2680 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
2681 if (ZSTD_isError(cSize)) return cSize;
2682 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2683 if (ZSTD_isError(endResult)) return endResult;
2684 return cSize + endResult;
2685}
2686
2687
Yann Collet19c10022016-07-28 01:25:46 +02002688static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002689 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002690 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002691 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002692 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002693{
Yann Collet3e21ec52016-09-06 15:36:19 +02002694 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
Yann Collet62470b42016-07-28 15:29:08 +02002695 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002696}
2697
Yann Collet21588e32016-03-30 16:50:44 +02002698size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2699 void* dst, size_t dstCapacity,
2700 const void* src, size_t srcSize,
2701 const void* dict,size_t dictSize,
2702 ZSTD_parameters params)
2703{
Yann Colletcf409a72016-09-26 16:41:05 +02002704 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02002705 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2706}
2707
Yann Colletd1b26842016-03-15 01:24:33 +01002708size_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 +01002709{
Yann Collet407a11f2016-11-03 15:52:01 -07002710 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02002711 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002712 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002713}
2714
Yann Colletd1b26842016-03-15 01:24:33 +01002715size_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 +01002716{
Yann Collet21588e32016-03-30 16:50:44 +02002717 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002718}
2719
Yann Colletd1b26842016-03-15 01:24:33 +01002720size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002721{
Yann Collet44fe9912015-10-29 22:02:40 +01002722 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002723 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002724 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002725 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002726 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002727 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 +01002728 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002729}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002730
Yann Colletfd416f12016-01-30 03:14:15 +01002731
Yann Collet81e13ef2016-06-07 00:51:51 +02002732/* ===== Dictionary API ===== */
2733
2734struct ZSTD_CDict_s {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002735 void* dictBuffer;
2736 const void* dictContent;
Yann Collet81e13ef2016-06-07 00:51:51 +02002737 size_t dictContentSize;
2738 ZSTD_CCtx* refContext;
David Lamda9d3b72016-08-29 09:03:12 -07002739}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
Yann Collet81e13ef2016-06-07 00:51:51 +02002740
Yann Colletd7c65892016-09-15 02:50:27 +02002741size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2742{
2743 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01002744 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02002745}
2746
Yann Collet1f57c2e2016-12-21 16:20:11 +01002747ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
2748 ZSTD_parameters params, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02002749{
Yann Collet23b6e052016-08-28 21:05:43 -07002750 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2751 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02002752
Yann Collet23b6e052016-08-28 21:05:43 -07002753 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002754 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2755
Yann Collet1f57c2e2016-12-21 16:20:11 +01002756 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07002757 ZSTD_free(cdict, customMem);
2758 ZSTD_free(cctx, customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002759 return NULL;
2760 }
2761
Yann Collet1f57c2e2016-12-21 16:20:11 +01002762 if ((byReference) || (!dictBuffer) || (!dictSize)) {
2763 cdict->dictBuffer = NULL;
2764 cdict->dictContent = dictBuffer;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002765 } else {
2766 void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
Yann Collet4e5eea62016-12-21 16:44:35 +01002767 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002768 memcpy(internalBuffer, dictBuffer, dictSize);
2769 cdict->dictBuffer = internalBuffer;
2770 cdict->dictContent = internalBuffer;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002771 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002772
2773 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
Yann Collet81e13ef2016-06-07 00:51:51 +02002774 if (ZSTD_isError(errorCode)) {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002775 ZSTD_free(cdict->dictBuffer, customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002776 ZSTD_free(cctx, customMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01002777 ZSTD_free(cdict, customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002778 return NULL;
2779 } }
2780
Yann Collet81e13ef2016-06-07 00:51:51 +02002781 cdict->refContext = cctx;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002782 cdict->dictContentSize = dictSize;
Yann Collet81e13ef2016-06-07 00:51:51 +02002783 return cdict;
2784 }
2785}
2786
2787ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2788{
2789 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet07639052016-08-03 01:57:57 +02002790 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002791 params.fParams.contentSizeFlag = 1;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002792 return ZSTD_createCDict_advanced(dict, dictSize, 0, params, allocator);
2793}
2794
2795ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
2796{
2797 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2798 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
2799 params.fParams.contentSizeFlag = 1;
2800 return ZSTD_createCDict_advanced(dict, dictSize, 1, params, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02002801}
2802
2803size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2804{
Yann Collet23b6e052016-08-28 21:05:43 -07002805 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02002806 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07002807 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01002808 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002809 ZSTD_free(cdict, cMem);
2810 return 0;
2811 }
Yann Collet81e13ef2016-06-07 00:51:51 +02002812}
2813
Yann Collet95162342016-10-25 16:19:52 -07002814static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
2815 return ZSTD_getParamsFromCCtx(cdict->refContext);
2816}
2817
Yann Collet4cb21292016-09-15 14:54:07 +02002818size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, U64 pledgedSrcSize)
2819{
Yann Collet97b378a2016-09-21 17:20:19 +02002820 if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
Yann Collet4cb21292016-09-15 14:54:07 +02002821 else CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, pledgedSrcSize));
2822 return 0;
2823}
2824
Yann Collet07639052016-08-03 01:57:57 +02002825/*! ZSTD_compress_usingCDict() :
2826* Compression using a digested Dictionary.
2827* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2828* Note that compression level is decided during dictionary creation */
Yann Collet4cb21292016-09-15 14:54:07 +02002829size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2830 void* dst, size_t dstCapacity,
2831 const void* src, size_t srcSize,
2832 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02002833{
Yann Collet4cb21292016-09-15 14:54:07 +02002834 CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize));
Yann Collet07639052016-08-03 01:57:57 +02002835
2836 if (cdict->refContext->params.fParams.contentSizeFlag==1) {
2837 cctx->params.fParams.contentSizeFlag = 1;
2838 cctx->frameContentSize = srcSize;
2839 }
2840
2841 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002842}
2843
2844
2845
Yann Collet104e5b02016-08-12 13:04:27 +02002846/* ******************************************************************
2847* Streaming
2848********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002849
2850typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
2851
2852struct ZSTD_CStream_s {
Yann Colletfa0c0972016-09-15 14:11:01 +02002853 ZSTD_CCtx* cctx;
Yann Collet95162342016-10-25 16:19:52 -07002854 ZSTD_CDict* cdictLocal;
2855 const ZSTD_CDict* cdict;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002856 char* inBuff;
2857 size_t inBuffSize;
2858 size_t inToCompress;
2859 size_t inBuffPos;
2860 size_t inBuffTarget;
2861 size_t blockSize;
2862 char* outBuff;
2863 size_t outBuffSize;
2864 size_t outBuffContentSize;
2865 size_t outBuffFlushedSize;
2866 ZSTD_cStreamStage stage;
2867 U32 checksum;
2868 U32 frameEnded;
Yann Collete795c8a2016-12-13 16:39:36 +01002869 U64 pledgedSrcSize;
2870 U64 inputProcessed;
Yann Colletee5b7252016-10-27 14:20:55 -07002871 ZSTD_parameters params;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002872 ZSTD_customMem customMem;
2873}; /* typedef'd to ZSTD_CStream within "zstd.h" */
2874
2875ZSTD_CStream* ZSTD_createCStream(void)
2876{
2877 return ZSTD_createCStream_advanced(defaultCustomMem);
2878}
2879
2880ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
2881{
2882 ZSTD_CStream* zcs;
2883
Yann Collet23b6e052016-08-28 21:05:43 -07002884 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2885 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002886
Yann Collet23b6e052016-08-28 21:05:43 -07002887 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002888 if (zcs==NULL) return NULL;
2889 memset(zcs, 0, sizeof(ZSTD_CStream));
2890 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
Yann Colletfa0c0972016-09-15 14:11:01 +02002891 zcs->cctx = ZSTD_createCCtx_advanced(customMem);
2892 if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002893 return zcs;
2894}
2895
2896size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2897{
2898 if (zcs==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -07002899 { ZSTD_customMem const cMem = zcs->customMem;
Yann Colletfa0c0972016-09-15 14:11:01 +02002900 ZSTD_freeCCtx(zcs->cctx);
Yann Collet95162342016-10-25 16:19:52 -07002901 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet23b6e052016-08-28 21:05:43 -07002902 ZSTD_free(zcs->inBuff, cMem);
2903 ZSTD_free(zcs->outBuff, cMem);
2904 ZSTD_free(zcs, cMem);
2905 return 0;
2906 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002907}
2908
2909
Yann Collet104e5b02016-08-12 13:04:27 +02002910/*====== Initialization ======*/
2911
2912size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
2913size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002914
Yann Collet644a8da2016-09-15 16:16:21 +02002915size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002916{
Yann Colletd564faa2016-12-18 21:39:15 +01002917 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 -07002918
2919 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
2920 else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
Yann Collet4cb21292016-09-15 14:54:07 +02002921
2922 zcs->inToCompress = 0;
2923 zcs->inBuffPos = 0;
2924 zcs->inBuffTarget = zcs->blockSize;
2925 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
2926 zcs->stage = zcss_load;
2927 zcs->frameEnded = 0;
Yann Collete795c8a2016-12-13 16:39:36 +01002928 zcs->pledgedSrcSize = pledgedSrcSize;
2929 zcs->inputProcessed = 0;
Yann Collet4cb21292016-09-15 14:54:07 +02002930 return 0; /* ready to go */
2931}
2932
Yann Collet5a0c8e22016-08-12 01:20:36 +02002933size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
2934 const void* dict, size_t dictSize,
2935 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2936{
2937 /* allocate buffers */
2938 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
2939 if (zcs->inBuffSize < neededInBuffSize) {
2940 zcs->inBuffSize = neededInBuffSize;
Yann Colletcf409a72016-09-26 16:41:05 +02002941 ZSTD_free(zcs->inBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002942 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002943 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
2944 }
2945 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
2946 }
2947 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
2948 zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
Yann Colletcf409a72016-09-26 16:41:05 +02002949 ZSTD_free(zcs->outBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002950 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002951 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
2952 }
2953
Yann Colletee5b7252016-10-27 14:20:55 -07002954 if (dict) {
2955 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet1f57c2e2016-12-21 16:20:11 +01002956 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0, params, zcs->customMem);
Yann Colletee5b7252016-10-27 14:20:55 -07002957 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
2958 zcs->cdict = zcs->cdictLocal;
2959 } else zcs->cdict = NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002960
Yann Collet5a0c8e22016-08-12 01:20:36 +02002961 zcs->checksum = params.fParams.checksumFlag > 0;
Yann Colletee5b7252016-10-27 14:20:55 -07002962 zcs->params = params;
Yann Collet4cb21292016-09-15 14:54:07 +02002963
2964 return ZSTD_resetCStream(zcs, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002965}
2966
Yann Collet95162342016-10-25 16:19:52 -07002967/* note : cdict must outlive compression session */
2968size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
2969{
2970 ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
2971 size_t const initError = ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0);
2972 zcs->cdict = cdict;
Gregory Szorc7d6f4782017-01-14 17:44:54 -08002973 zcs->cctx->dictID = params.fParams.noDictIDFlag ? 0 : cdict->refContext->dictID;
Yann Collet95162342016-10-25 16:19:52 -07002974 return initError;
2975}
2976
Yann Collet5a0c8e22016-08-12 01:20:36 +02002977size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
2978{
2979 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
2980 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);
2981}
2982
Yann Collete795c8a2016-12-13 16:39:36 +01002983size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
2984{
Yann Colletd564faa2016-12-18 21:39:15 +01002985 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
2986 if (pledgedSrcSize) params.fParams.contentSizeFlag = 1;
Yann Collete795c8a2016-12-13 16:39:36 +01002987 return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);
2988}
2989
Yann Collet5a0c8e22016-08-12 01:20:36 +02002990size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
2991{
2992 return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel);
2993}
2994
Yann Collet70e3b312016-08-23 01:18:06 +02002995size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02002996{
Yann Colletd7c65892016-09-15 02:50:27 +02002997 if (zcs==NULL) return 0; /* support sizeof on NULL */
Yann Collet335ad5d2016-10-25 17:47:02 -07002998 return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize;
Yann Colletcb327632016-08-23 00:30:31 +02002999}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003000
Yann Collet104e5b02016-08-12 13:04:27 +02003001/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003002
3003typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
3004
3005MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3006{
3007 size_t const length = MIN(dstCapacity, srcSize);
3008 memcpy(dst, src, length);
3009 return length;
3010}
3011
3012static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3013 void* dst, size_t* dstCapacityPtr,
3014 const void* src, size_t* srcSizePtr,
3015 ZSTD_flush_e const flush)
3016{
3017 U32 someMoreWork = 1;
3018 const char* const istart = (const char*)src;
3019 const char* const iend = istart + *srcSizePtr;
3020 const char* ip = istart;
3021 char* const ostart = (char*)dst;
3022 char* const oend = ostart + *dstCapacityPtr;
3023 char* op = ostart;
3024
3025 while (someMoreWork) {
3026 switch(zcs->stage)
3027 {
3028 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
3029
3030 case zcss_load:
3031 /* complete inBuffer */
3032 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3033 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
3034 zcs->inBuffPos += loaded;
3035 ip += loaded;
3036 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
3037 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
3038 } }
3039 /* compress current block (note : this stage cannot be stopped in the middle) */
3040 { void* cDst;
3041 size_t cSize;
3042 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3043 size_t oSize = oend-op;
3044 if (oSize >= ZSTD_compressBound(iSize))
3045 cDst = op; /* compress directly into output buffer (avoid flush stage) */
3046 else
3047 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3048 cSize = (flush == zsf_end) ?
Yann Colletfa0c0972016-09-15 14:11:01 +02003049 ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
3050 ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003051 if (ZSTD_isError(cSize)) return cSize;
3052 if (flush == zsf_end) zcs->frameEnded = 1;
3053 /* prepare next block */
3054 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3055 if (zcs->inBuffTarget > zcs->inBuffSize)
3056 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
3057 zcs->inToCompress = zcs->inBuffPos;
3058 if (cDst == op) { op += cSize; break; } /* no need to flush */
3059 zcs->outBuffContentSize = cSize;
3060 zcs->outBuffFlushedSize = 0;
3061 zcs->stage = zcss_flush; /* pass-through to flush stage */
3062 }
3063
3064 case zcss_flush:
3065 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3066 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3067 op += flushed;
3068 zcs->outBuffFlushedSize += flushed;
3069 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
3070 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3071 zcs->stage = zcss_load;
3072 break;
3073 }
3074
3075 case zcss_final:
3076 someMoreWork = 0; /* do nothing */
3077 break;
3078
3079 default:
3080 return ERROR(GENERIC); /* impossible */
3081 }
3082 }
3083
3084 *srcSizePtr = ip - istart;
3085 *dstCapacityPtr = op - ostart;
Yann Collete795c8a2016-12-13 16:39:36 +01003086 zcs->inputProcessed += *srcSizePtr;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003087 if (zcs->frameEnded) return 0;
3088 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3089 if (hintInSize==0) hintInSize = zcs->blockSize;
3090 return hintInSize;
3091 }
3092}
3093
Yann Collet53e17fb2016-08-17 01:39:22 +02003094size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003095{
Yann Collet53e17fb2016-08-17 01:39:22 +02003096 size_t sizeRead = input->size - input->pos;
3097 size_t sizeWritten = output->size - output->pos;
3098 size_t const result = ZSTD_compressStream_generic(zcs,
3099 (char*)(output->dst) + output->pos, &sizeWritten,
3100 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3101 input->pos += sizeRead;
3102 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003103 return result;
3104}
3105
3106
Yann Collet104e5b02016-08-12 13:04:27 +02003107/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003108
3109/*! ZSTD_flushStream() :
3110* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003111size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003112{
3113 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003114 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02003115 size_t const result = ZSTD_compressStream_generic(zcs,
Yann Collet95d07d72016-09-06 16:38:51 +02003116 (char*)(output->dst) + output->pos, &sizeWritten,
3117 &srcSize, &srcSize, /* use a valid src address instead of NULL */
Yann Colletc4119022016-08-17 01:50:54 +02003118 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003119 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003120 if (ZSTD_isError(result)) return result;
3121 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3122}
3123
3124
Yann Collet53e17fb2016-08-17 01:39:22 +02003125size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003126{
Yann Collet53e17fb2016-08-17 01:39:22 +02003127 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3128 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003129 BYTE* op = ostart;
3130
Yann Collete795c8a2016-12-13 16:39:36 +01003131 if ((zcs->pledgedSrcSize) && (zcs->inputProcessed != zcs->pledgedSrcSize))
3132 return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */
3133
Yann Collet5a0c8e22016-08-12 01:20:36 +02003134 if (zcs->stage != zcss_final) {
3135 /* flush whatever remains */
3136 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003137 size_t sizeWritten = output->size - output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003138 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
3139 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3140 op += sizeWritten;
3141 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003142 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003143 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3144 }
3145 /* create epilogue */
3146 zcs->stage = zcss_final;
3147 zcs->outBuffContentSize = !notEnded ? 0 :
Yann Colletfa0c0972016-09-15 14:11:01 +02003148 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 +02003149 }
3150
3151 /* flush epilogue */
3152 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3153 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3154 op += flushed;
3155 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003156 output->pos += op-ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003157 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3158 return toFlush - flushed;
3159 }
3160}
3161
3162
3163
Yann Collet70e8c382016-02-10 13:37:52 +01003164/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003165
Yann Collet236d94f2016-05-18 12:06:33 +02003166#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003167#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003168int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003169
Yann Collet3b719252016-03-30 19:48:05 +02003170static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003171{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003172 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003173 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003174 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3175 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003176 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3177 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003178 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3179 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3180 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003181 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003182 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3183 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3184 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3185 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3186 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3187 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3188 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3189 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003190 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
3191 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
3192 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003193 { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */
3194 { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */
3195 { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003196},
3197{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003198 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003199 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003200 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003201 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3202 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3203 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3204 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3205 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3206 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3207 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3208 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3209 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3210 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3211 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3212 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003213 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003214 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3215 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3216 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003217 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3218 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003219 { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/
3220 { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/
3221 { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003222},
3223{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003224 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003225 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3226 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3227 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3228 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3229 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3230 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3231 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3232 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3233 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3234 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3235 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3236 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3237 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3238 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003239 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3240 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3241 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3242 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3243 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3244 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003245 { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/
3246 { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/
3247 { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003248},
3249{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003250 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003251 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003252 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003253 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3254 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3255 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3256 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3257 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3258 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3259 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3260 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003261 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3262 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3263 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3264 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3265 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3266 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3267 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3268 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3269 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3270 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003271 { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/
3272 { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/
3273 { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003274},
3275};
3276
Yann Collet236d94f2016-05-18 12:06:33 +02003277/*! ZSTD_getCParams() :
3278* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3279* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003280ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003281{
Yann Collet15354142016-04-04 04:22:53 +02003282 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003283 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003284 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003285 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003286 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003287 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003288 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003289 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3290 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003291 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003292 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3293 }
Yann Collet70d13012016-06-01 18:45:34 +02003294 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003295 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003296}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003297
3298/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003299* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003300* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003301ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003302 ZSTD_parameters params;
3303 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3304 memset(&params, 0, sizeof(params));
3305 params.cParams = cParams;
3306 return params;
3307}