blob: 188b8e717a7a15314ceff68edb23e0466287158d [file] [log] [blame]
Yann Collet32fb4072017-08-18 16:52:05 -07001/*
Yann Collet4ded9e52016-08-30 10:04:33 -07002 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
Yann Collet32fb4072017-08-18 16:52:05 -07005 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
Yann Collet3128e032017-09-08 00:09:23 -07008 * You may select, at your option, one of the above-listed licenses.
Yann Collet4ded9e52016-08-30 10:04:33 -07009 */
Yann Colletf3eca252015-10-22 15:31:46 +010010
Yann Colletf3eca252015-10-22 15:31:46 +010011
Yann Collet7d360282016-02-12 00:07:30 +010012/*-*************************************
Yann Colletb0edb7f2017-05-12 15:31:53 -070013* Tuning parameters
14***************************************/
Yann Collet6d4fef32017-05-17 18:36:15 -070015#ifndef ZSTD_CLEVEL_DEFAULT
16# define ZSTD_CLEVEL_DEFAULT 3
Yann Colletb0edb7f2017-05-12 15:31:53 -070017#endif
18
Yann Colletbf991502017-06-19 12:56:25 -070019
Yann Colletb0edb7f2017-05-12 15:31:53 -070020/*-*************************************
Yann Colletae7aa062016-02-03 02:46:46 +010021* Dependencies
Yann Colletf3eca252015-10-22 15:31:46 +010022***************************************/
Yann Colletd3b7f8d2016-06-04 19:47:02 +020023#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010024#include "mem.h"
Yann Collet5a0c8e22016-08-12 01:20:36 +020025#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
Yann Colletd0e2cd12016-06-05 00:58:01 +020026#include "fse.h"
Yann Collet130fe112016-06-05 00:42:28 +020027#define HUF_STATIC_LINKING_ONLY
28#include "huf.h"
Nick Terrell721726d2017-09-01 18:28:35 -070029#include "zstd_compress.h"
30#include "zstd_fast.h"
31#include "zstd_double_fast.h"
32#include "zstd_lazy.h"
33#include "zstd_opt.h"
Stella Lau360428c2017-09-06 17:56:01 -070034#include "zstd_ldm.h"
Yann Collet31533ba2017-04-27 00:29:04 -070035
Yann Colletf3eca252015-10-22 15:31:46 +010036
Yann Collet7d360282016-02-12 00:07:30 +010037/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010038* Helper functions
39***************************************/
Yann Collet3f75d522017-03-31 17:11:38 -070040size_t ZSTD_compressBound(size_t srcSize) {
Yann Collet5b103452017-09-29 23:17:41 -070041 return ZSTD_COMPRESSBOUND(srcSize);
Yann Collet3f75d522017-03-31 17:11:38 -070042}
Yann Collet59d1f792016-01-23 19:28:41 +010043
44
Yann Collet7d360282016-02-12 00:07:30 +010045/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010046* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010047***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010048static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
49{
Yann Collet14983e72015-11-11 21:38:21 +010050 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020051 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020052 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010053}
54
55
Yann Collet7d360282016-02-12 00:07:30 +010056/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010057* Context memory management
58***************************************/
Yann Collet18803372017-05-22 18:21:51 -070059struct ZSTD_CDict_s {
60 void* dictBuffer;
61 const void* dictContent;
62 size_t dictContentSize;
63 ZSTD_CCtx* refContext;
Yann Collet8c910d22017-06-03 01:15:02 -070064}; /* typedef'd to ZSTD_CDict within "zstd.h" */
Yann Collet0be6fd32017-05-08 16:08:01 -070065
Yann Collet5be2dd22015-11-11 13:43:58 +010066ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +010067{
Yann Colletae728a42017-05-30 17:11:39 -070068 return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
inikep50e82c02016-05-23 15:49:09 +020069}
70
71ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
72{
Yann Collet69c2cdb2016-07-14 16:52:45 +020073 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +020074
Yann Colletae728a42017-05-30 17:11:39 -070075 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +020076
Yann Colletc4f46b92017-05-30 17:45:37 -070077 cctx = (ZSTD_CCtx*) ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +020078 if (!cctx) return NULL;
Yann Colletbb002742017-01-25 16:25:38 -080079 cctx->customMem = customMem;
Stella Lau97e27af2017-08-18 11:20:08 -070080 cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;
Yann Colleta0ba8492017-06-16 13:29:17 -070081 ZSTD_STATIC_ASSERT(zcss_init==0);
Yann Colletd3de3d52017-06-16 16:51:33 -070082 ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
Yann Collet69c2cdb2016-07-14 16:52:45 +020083 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +010084}
85
Yann Colletc7fe2622017-05-23 13:16:00 -070086ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
87{
Yann Collet335780c2017-09-13 16:35:29 -070088 ZSTD_CCtx* const cctx = (ZSTD_CCtx*) workspace;
Yann Colletc7fe2622017-05-23 13:16:00 -070089 if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
90 if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
Yann Collet7bd1a292017-06-21 11:50:33 -070091 memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */
Yann Colletc7fe2622017-05-23 13:16:00 -070092 cctx->staticSize = workspaceSize;
93 cctx->workSpace = (void*)(cctx+1);
94 cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
95
96 /* entropy space (never moves) */
Nick Terrellde0414b2017-07-12 19:08:24 -070097 if (cctx->workSpaceSize < sizeof(ZSTD_entropyCTables_t)) return NULL;
Yann Collet335780c2017-09-13 16:35:29 -070098 assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
Nick Terrellde0414b2017-07-12 19:08:24 -070099 cctx->entropy = (ZSTD_entropyCTables_t*)cctx->workSpace;
Yann Colletc7fe2622017-05-23 13:16:00 -0700100
Yann Colletf3eca252015-10-22 15:31:46 +0100101 return cctx;
102}
103
Yann Collet5be2dd22015-11-11 13:43:58 +0100104size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100105{
inikep36403962016-06-03 16:36:50 +0200106 if (cctx==NULL) return 0; /* support free on NULL */
Yann Colletc4a5a212017-06-01 17:56:14 -0700107 if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
Yann Collet23b6e052016-08-28 21:05:43 -0700108 ZSTD_free(cctx->workSpace, cctx->customMem);
Yann Collet78553662017-05-08 17:15:00 -0700109 cctx->workSpace = NULL;
110 ZSTD_freeCDict(cctx->cdictLocal);
111 cctx->cdictLocal = NULL;
Yann Collet0d6ecc72017-09-11 14:09:34 -0700112#ifdef ZSTD_MULTITHREAD
Yann Colletc4a5a212017-06-01 17:56:14 -0700113 ZSTDMT_freeCCtx(cctx->mtctx);
114 cctx->mtctx = NULL;
Yann Collet0d6ecc72017-09-11 14:09:34 -0700115#endif
Yann Collet23b6e052016-08-28 21:05:43 -0700116 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100117 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100118}
119
Yann Collet0d6ecc72017-09-11 14:09:34 -0700120
121static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
122{
123#ifdef ZSTD_MULTITHREAD
124 return ZSTDMT_sizeof_CCtx(cctx->mtctx);
125#else
126 (void) cctx;
127 return 0;
128#endif
129}
130
131
Yann Collet70e3b312016-08-23 01:18:06 +0200132size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200133{
Yann Colletd7c65892016-09-15 02:50:27 +0200134 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet7d1ff382017-09-18 14:47:34 -0700135 DEBUGLOG(3, "sizeof(*cctx) : %u", (U32)sizeof(*cctx));
136 DEBUGLOG(3, "workSpaceSize (including streaming buffers): %u", (U32)cctx->workSpaceSize);
137 DEBUGLOG(3, "inner cdict : %u", (U32)ZSTD_sizeof_CDict(cctx->cdictLocal));
138 DEBUGLOG(3, "inner MTCTX : %u", (U32)ZSTD_sizeof_mtctx(cctx));
Yann Collet791d7442017-05-08 16:17:30 -0700139 return sizeof(*cctx) + cctx->workSpaceSize
140 + ZSTD_sizeof_CDict(cctx->cdictLocal)
Yann Collet0d6ecc72017-09-11 14:09:34 -0700141 + ZSTD_sizeof_mtctx(cctx);
Yann Collet3ae543c2016-07-11 03:12:17 +0200142}
143
Yann Collet009d6042017-05-19 10:17:59 -0700144size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
145{
146 return ZSTD_sizeof_CCtx(zcs); /* same object */
147}
148
Yann Colletb0edb7f2017-05-12 15:31:53 -0700149/* private API call, for dictBuilder only */
150const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
151
Yann Collet6d4fef32017-05-17 18:36:15 -0700152#define ZSTD_CLEVEL_CUSTOM 999
Yann Collet083fcc82015-10-25 14:06:35 +0100153
Stella Lau0e56a842017-08-28 19:25:17 -0700154static ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
155 ZSTD_CCtx_params params, U64 srcSizeHint, size_t dictSize)
Yann Collet083fcc82015-10-25 14:06:35 +0100156{
Stella Lau0e56a842017-08-28 19:25:17 -0700157 return (params.compressionLevel == ZSTD_CLEVEL_CUSTOM ?
158 params.cParams :
159 ZSTD_getCParams(params.compressionLevel, srcSizeHint, dictSize));
Yann Colletbb002742017-01-25 16:25:38 -0800160}
161
Stella Lau1c81f722017-08-23 15:47:15 -0700162static void ZSTD_cLevelToCCtxParams_srcSize(ZSTD_CCtx_params* params, U64 srcSize)
Stella Lau5bc2c1e2017-08-23 12:03:30 -0700163{
Stella Lau0e56a842017-08-28 19:25:17 -0700164 params->cParams = ZSTD_getCParamsFromCCtxParams(*params, srcSize, 0);
Stella Lau5bc2c1e2017-08-23 12:03:30 -0700165 params->compressionLevel = ZSTD_CLEVEL_CUSTOM;
166}
Yann Collet083fcc82015-10-25 14:06:35 +0100167
Yann Colletadd66f82017-05-12 15:59:48 -0700168static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
Yann Collet7d360282016-02-12 00:07:30 +0100169{
Stella Lau5bc2c1e2017-08-23 12:03:30 -0700170 ZSTD_cLevelToCCtxParams_srcSize(
171 &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1);
172}
173
174static void ZSTD_cLevelToCCtxParams(ZSTD_CCtx_params* params)
175{
176 ZSTD_cLevelToCCtxParams_srcSize(params, 0);
Yann Collet7d360282016-02-12 00:07:30 +0100177}
178
Stella Lau91b30db2017-08-21 10:09:06 -0700179static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
180 ZSTD_compressionParameters cParams)
181{
182 ZSTD_CCtx_params cctxParams;
Stella Lau90a31bf2017-08-30 14:36:54 -0700183 memset(&cctxParams, 0, sizeof(cctxParams));
Stella Lau91b30db2017-08-21 10:09:06 -0700184 cctxParams.cParams = cParams;
185 cctxParams.compressionLevel = ZSTD_CLEVEL_CUSTOM;
186 return cctxParams;
187}
188
Stella Lau5bc2c1e2017-08-23 12:03:30 -0700189static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
190 ZSTD_customMem customMem)
Stella Lauc0221122017-08-17 19:30:22 -0700191{
Stella Lau5bc2c1e2017-08-23 12:03:30 -0700192 ZSTD_CCtx_params* params;
193 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
194 params = (ZSTD_CCtx_params*)ZSTD_calloc(
195 sizeof(ZSTD_CCtx_params), customMem);
Stella Lauc0221122017-08-17 19:30:22 -0700196 if (!params) { return NULL; }
Stella Lau5bc2c1e2017-08-23 12:03:30 -0700197 params->customMem = customMem;
Stella Lauc0221122017-08-17 19:30:22 -0700198 params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
199 return params;
200}
201
Stella Lau5bc2c1e2017-08-23 12:03:30 -0700202ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
203{
204 return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);
205}
206
207size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
208{
209 if (params == NULL) { return 0; }
210 ZSTD_free(params, params->customMem);
211 return 0;
212}
213
Stella Lau023b24e2017-08-20 22:55:07 -0700214size_t ZSTD_resetCCtxParams(ZSTD_CCtx_params* params)
215{
Stella Lau0e56a842017-08-28 19:25:17 -0700216 return ZSTD_initCCtxParams(params, ZSTD_CLEVEL_DEFAULT);
Stella Lau023b24e2017-08-20 22:55:07 -0700217}
218
Stella Lau07445922017-08-25 13:23:16 -0700219size_t ZSTD_initCCtxParams(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
Stella Lau0e56a842017-08-28 19:25:17 -0700220 if (!cctxParams) { return ERROR(GENERIC); }
Stella Lau90a31bf2017-08-30 14:36:54 -0700221 memset(cctxParams, 0, sizeof(*cctxParams));
Stella Lau0e56a842017-08-28 19:25:17 -0700222 cctxParams->compressionLevel = compressionLevel;
223 return 0;
Stella Lau07445922017-08-25 13:23:16 -0700224}
225
226size_t ZSTD_initCCtxParams_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
Stella Lauc0221122017-08-17 19:30:22 -0700227{
Stella Lau560b34f2017-08-21 11:44:58 -0700228 if (!cctxParams) { return ERROR(GENERIC); }
Stella Laufd8a2572017-08-21 13:23:35 -0700229 CHECK_F( ZSTD_checkCParams(params.cParams) );
Stella Lau90a31bf2017-08-30 14:36:54 -0700230 memset(cctxParams, 0, sizeof(*cctxParams));
Stella Lauf181f332017-08-21 01:59:08 -0700231 cctxParams->cParams = params.cParams;
232 cctxParams->fParams = params.fParams;
233 cctxParams->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Stella Lauc0221122017-08-17 19:30:22 -0700234 return 0;
235}
236
Stella Lau11303772017-08-22 14:53:13 -0700237static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
238 ZSTD_CCtx_params cctxParams, ZSTD_parameters params)
239{
240 ZSTD_CCtx_params ret = cctxParams;
241 ret.cParams = params.cParams;
242 ret.fParams = params.fParams;
Nick Terrell86e83e92017-10-02 13:43:30 -0700243 ret.compressionLevel = ZSTD_CLEVEL_CUSTOM;
Stella Lau11303772017-08-22 14:53:13 -0700244 return ret;
Yann Collet083fcc82015-10-25 14:06:35 +0100245}
246
Yann Collet2bd64402017-07-13 17:12:16 -0700247#define CLAMPCHECK(val,min,max) { \
248 if (((val)<(min)) | ((val)>(max))) { \
249 return ERROR(parameter_outOfBound); \
Yann Colletc3bce242017-06-20 16:09:11 -0700250} }
251
Yann Colletb0edb7f2017-05-12 15:31:53 -0700252size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
Yann Collet95162342016-10-25 16:19:52 -0700253{
Yann Collet24de7b02017-05-22 13:05:45 -0700254 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700255
256 switch(param)
257 {
Yann Collet7c3dea42017-09-24 15:57:29 -0700258 case ZSTD_p_format :
259 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
260
Stella Lau023b24e2017-08-20 22:55:07 -0700261 case ZSTD_p_compressionLevel:
Yann Colletcd2892f2017-06-01 09:44:54 -0700262 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700263 if (cctx->cdict) return ERROR(stage_wrong);
Stella Lauf181f332017-08-21 01:59:08 -0700264 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700265
Stella Lau023b24e2017-08-20 22:55:07 -0700266 case ZSTD_p_windowLog:
267 case ZSTD_p_hashLog:
268 case ZSTD_p_chainLog:
269 case ZSTD_p_searchLog:
270 case ZSTD_p_minMatch:
271 case ZSTD_p_targetLength:
272 case ZSTD_p_compressionStrategy:
Yann Colletcd2892f2017-06-01 09:44:54 -0700273 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700274 if (cctx->cdict) return ERROR(stage_wrong);
Stella Lau91b30db2017-08-21 10:09:06 -0700275 ZSTD_cLevelToCParams(cctx); /* Can optimize if srcSize is known */
Stella Lau023b24e2017-08-20 22:55:07 -0700276 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700277
Stella Lau023b24e2017-08-20 22:55:07 -0700278 case ZSTD_p_contentSizeFlag:
279 case ZSTD_p_checksumFlag:
280 case ZSTD_p_dictIDFlag:
281 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
Yann Colletfecc7212017-06-27 11:46:39 -0700282
Yann Colletb0edb7f2017-05-12 15:31:53 -0700283 case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize,
284 * even when referencing into Dictionary content
285 * default : 0 when using a CDict, 1 when using a Prefix */
Yann Colletc35e5352017-06-01 18:44:06 -0700286 cctx->loadedDictEnd = 0;
Stella Lau5bc2c1e2017-08-23 12:03:30 -0700287 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
Yann Colletc35e5352017-06-01 18:44:06 -0700288
289 case ZSTD_p_nbThreads:
290 if (value==0) return 0;
Yann Collet33873f02017-06-16 12:04:21 -0700291 DEBUGLOG(5, " setting nbThreads : %u", value);
Stella Lau4e835722017-08-29 16:18:21 -0700292 if (value > 1 && cctx->staticSize) {
293 return ERROR(parameter_unsupported); /* MT not compatible with static alloc */
Yann Collet33873f02017-06-16 12:04:21 -0700294 }
Stella Lau4e835722017-08-29 16:18:21 -0700295 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
Yann Colletc35e5352017-06-01 18:44:06 -0700296
Yann Collet559ee822017-06-16 11:58:21 -0700297 case ZSTD_p_jobSize:
Stella Lau99111532017-08-25 13:14:51 -0700298 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
Yann Colletc35e5352017-06-01 18:44:06 -0700299
Yann Collet559ee822017-06-16 11:58:21 -0700300 case ZSTD_p_overlapSizeLog:
Stella Lau81d89d82017-08-18 12:08:57 -0700301 DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->requestedParams.nbThreads);
Stella Lau99111532017-08-25 13:14:51 -0700302 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700303
Stella Lau67d4a612017-09-02 21:10:36 -0700304 case ZSTD_p_enableLongDistanceMatching:
Stella Lau6a546ef2017-07-28 15:51:33 -0700305 if (cctx->cdict) return ERROR(stage_wrong);
Stella Lau6a546ef2017-07-28 15:51:33 -0700306 if (value != 0) {
307 ZSTD_cLevelToCParams(cctx);
Stella Lau6a546ef2017-07-28 15:51:33 -0700308 }
Stella Lau8081bec2017-08-31 15:40:16 -0700309 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
Stella Lau6a546ef2017-07-28 15:51:33 -0700310
Stella Lau767a0b32017-09-01 12:24:59 -0700311 case ZSTD_p_ldmHashLog:
312 case ZSTD_p_ldmMinMatch:
313 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
314 if (cctx->cdict) return ERROR(stage_wrong);
315 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
316
Stella Lau67d4a612017-09-02 21:10:36 -0700317 case ZSTD_p_ldmBucketSizeLog:
Stella Laua1f04d52017-09-01 14:52:51 -0700318 case ZSTD_p_ldmHashEveryLog:
319 if (cctx->cdict) return ERROR(stage_wrong);
320 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
321
Yann Collet2bd64402017-07-13 17:12:16 -0700322 default: return ERROR(parameter_unsupported);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700323 }
Yann Collet95162342016-10-25 16:19:52 -0700324}
325
Stella Lauc0221122017-08-17 19:30:22 -0700326size_t ZSTD_CCtxParam_setParameter(
327 ZSTD_CCtx_params* params, ZSTD_cParameter param, unsigned value)
328{
329 switch(param)
330 {
Yann Collet7c3dea42017-09-24 15:57:29 -0700331 case ZSTD_p_format :
Yann Colletc9949322017-09-27 12:22:22 -0700332 if (value > (unsigned)ZSTD_f_zstd1_magicless)
Yann Collet7c3dea42017-09-24 15:57:29 -0700333 return ERROR(parameter_unsupported);
334 params->format = (ZSTD_format_e)value;
335 return 0;
336
Stella Lauc0221122017-08-17 19:30:22 -0700337 case ZSTD_p_compressionLevel :
338 if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel();
339 if (value == 0) return 0;
340 params->compressionLevel = value;
341 return 0;
342
343 case ZSTD_p_windowLog :
344 if (value == 0) return 0;
345 CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
346 ZSTD_cLevelToCCtxParams(params);
347 params->cParams.windowLog = value;
348 return 0;
349
350 case ZSTD_p_hashLog :
351 if (value == 0) return 0;
352 CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
353 ZSTD_cLevelToCCtxParams(params);
354 params->cParams.hashLog = value;
355 return 0;
356
357 case ZSTD_p_chainLog :
358 if (value == 0) return 0;
359 CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
360 ZSTD_cLevelToCCtxParams(params);
361 params->cParams.chainLog = value;
362 return 0;
363
364 case ZSTD_p_searchLog :
365 if (value == 0) return 0;
366 CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
367 ZSTD_cLevelToCCtxParams(params);
368 params->cParams.searchLog = value;
369 return 0;
370
371 case ZSTD_p_minMatch :
372 if (value == 0) return 0;
373 CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
374 ZSTD_cLevelToCCtxParams(params);
375 params->cParams.searchLength = value;
376 return 0;
377
378 case ZSTD_p_targetLength :
379 if (value == 0) return 0;
380 CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
381 ZSTD_cLevelToCCtxParams(params);
382 params->cParams.targetLength = value;
383 return 0;
384
385 case ZSTD_p_compressionStrategy :
386 if (value == 0) return 0;
387 CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
388 ZSTD_cLevelToCCtxParams(params);
389 params->cParams.strategy = (ZSTD_strategy)value;
390 return 0;
391
392 case ZSTD_p_contentSizeFlag :
Stella Lau023b24e2017-08-20 22:55:07 -0700393 /* Content size written in frame header _when known_ (default:1) */
394 DEBUGLOG(5, "set content size flag = %u", (value>0));
Stella Lauc0221122017-08-17 19:30:22 -0700395 params->fParams.contentSizeFlag = value > 0;
396 return 0;
397
398 case ZSTD_p_checksumFlag :
Stella Lau023b24e2017-08-20 22:55:07 -0700399 /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
Stella Lauc0221122017-08-17 19:30:22 -0700400 params->fParams.checksumFlag = value > 0;
401 return 0;
402
Stella Lauf181f332017-08-21 01:59:08 -0700403 case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
Stella Lau023b24e2017-08-20 22:55:07 -0700404 DEBUGLOG(5, "set dictIDFlag = %u", (value>0));
Stella Lauc0221122017-08-17 19:30:22 -0700405 params->fParams.noDictIDFlag = (value == 0);
406 return 0;
407
Stella Lauc0221122017-08-17 19:30:22 -0700408 case ZSTD_p_forceMaxWindow :
Stella Laub6cb2ed2017-08-18 11:43:31 -0700409 params->forceWindow = value > 0;
Stella Lauc0221122017-08-17 19:30:22 -0700410 return 0;
411
412 case ZSTD_p_nbThreads :
Stella Lau4e835722017-08-29 16:18:21 -0700413 if (value == 0) return 0;
Stella Lau81d89d82017-08-18 12:08:57 -0700414#ifndef ZSTD_MULTITHREAD
415 if (value > 1) return ERROR(parameter_unsupported);
Yann Colletf325ee42017-09-11 14:37:03 -0700416 return 0;
Yann Collet0d6ecc72017-09-11 14:09:34 -0700417#else
Stella Lau99111532017-08-25 13:14:51 -0700418 return ZSTDMT_initializeCCtxParameters(params, value);
Yann Collet0d6ecc72017-09-11 14:09:34 -0700419#endif
Stella Lauc0221122017-08-17 19:30:22 -0700420
421 case ZSTD_p_jobSize :
Yann Collet0d6ecc72017-09-11 14:09:34 -0700422#ifndef ZSTD_MULTITHREAD
423 return ERROR(parameter_unsupported);
424#else
Stella Lau1c0dbe82017-08-21 13:18:00 -0700425 if (params->nbThreads <= 1) return ERROR(parameter_unsupported);
Stella Lau99111532017-08-25 13:14:51 -0700426 return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_sectionSize, value);
Yann Collet0d6ecc72017-09-11 14:09:34 -0700427#endif
Stella Lauc0221122017-08-17 19:30:22 -0700428
429 case ZSTD_p_overlapSizeLog :
Yann Collet0d6ecc72017-09-11 14:09:34 -0700430#ifndef ZSTD_MULTITHREAD
431 return ERROR(parameter_unsupported);
432#else
Stella Lau1c0dbe82017-08-21 13:18:00 -0700433 if (params->nbThreads <= 1) return ERROR(parameter_unsupported);
Stella Lau99111532017-08-25 13:14:51 -0700434 return ZSTDMT_CCtxParam_setMTCtxParameter(params, ZSTDMT_p_overlapSectionLog, value);
Yann Collet0d6ecc72017-09-11 14:09:34 -0700435#endif
Stella Lau023b24e2017-08-20 22:55:07 -0700436
Stella Lau67d4a612017-09-02 21:10:36 -0700437 case ZSTD_p_enableLongDistanceMatching :
Stella Lau8081bec2017-08-31 15:40:16 -0700438 if (value != 0) {
439 ZSTD_cLevelToCCtxParams(params);
Nick Terrellc233bdb2017-09-22 14:04:39 -0700440 params->cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
Stella Lau8081bec2017-08-31 15:40:16 -0700441 }
Stella Lau767a0b32017-09-01 12:24:59 -0700442 return ZSTD_ldm_initializeParameters(&params->ldmParams, value);
443
444 case ZSTD_p_ldmHashLog :
445 if (value == 0) return 0;
446 CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
447 params->ldmParams.hashLog = value;
448 return 0;
449
450 case ZSTD_p_ldmMinMatch :
451 if (value == 0) return 0;
Stella Lau9e406022017-09-06 08:39:46 -0700452 CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX);
Stella Lau767a0b32017-09-01 12:24:59 -0700453 params->ldmParams.minMatchLength = value;
Stella Lau8081bec2017-08-31 15:40:16 -0700454 return 0;
Stella Lau6a546ef2017-07-28 15:51:33 -0700455
Stella Lau67d4a612017-09-02 21:10:36 -0700456 case ZSTD_p_ldmBucketSizeLog :
457 if (value > ZSTD_LDM_BUCKETSIZELOG_MAX) {
458 return ERROR(parameter_outOfBound);
459 }
460 params->ldmParams.bucketSizeLog = value;
461 return 0;
462
Stella Laua1f04d52017-09-01 14:52:51 -0700463 case ZSTD_p_ldmHashEveryLog :
464 if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) {
465 return ERROR(parameter_outOfBound);
466 }
467 params->ldmParams.hashEveryLog = value;
468 return 0;
469
Stella Lauc0221122017-08-17 19:30:22 -0700470 default: return ERROR(parameter_unsupported);
471 }
472}
473
Stella Lauf181f332017-08-21 01:59:08 -0700474/**
475 * This function should be updated whenever ZSTD_CCtx_params is updated.
476 * Parameters are copied manually before the dictionary is loaded.
477 * The multithreading parameters jobSize and overlapSizeLog are set only if
Stella Lau024098a2017-08-25 17:58:28 -0700478 * nbThreads > 1.
Stella Lau91b30db2017-08-21 10:09:06 -0700479 *
480 * Pledged srcSize is treated as unknown.
Stella Lauf181f332017-08-21 01:59:08 -0700481 */
Stella Lau82d636b2017-08-29 18:03:06 -0700482size_t ZSTD_CCtx_setParametersUsingCCtxParams(
483 ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
Stella Lau97e27af2017-08-18 11:20:08 -0700484{
Stella Lau4e835722017-08-29 16:18:21 -0700485 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
486 if (cctx->cdict) return ERROR(stage_wrong);
Stella Lau399ae012017-08-18 13:01:55 -0700487
488 /* Assume the compression and frame parameters are validated */
489 cctx->requestedParams.cParams = params->cParams;
490 cctx->requestedParams.fParams = params->fParams;
491 cctx->requestedParams.compressionLevel = params->compressionLevel;
492
Stella Lau399ae012017-08-18 13:01:55 -0700493 /* Set force window explicitly since it sets cctx->loadedDictEnd */
494 CHECK_F( ZSTD_CCtx_setParameter(
495 cctx, ZSTD_p_forceMaxWindow, params->forceWindow) );
496
497 /* Set multithreading parameters explicitly */
498 CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_nbThreads, params->nbThreads) );
Stella Lau023b24e2017-08-20 22:55:07 -0700499 if (params->nbThreads > 1) {
500 CHECK_F( ZSTD_CCtx_setParameter(cctx, ZSTD_p_jobSize, params->jobSize) );
501 CHECK_F( ZSTD_CCtx_setParameter(
Stella Lau399ae012017-08-18 13:01:55 -0700502 cctx, ZSTD_p_overlapSizeLog, params->overlapSizeLog) );
Stella Lau023b24e2017-08-20 22:55:07 -0700503 }
Stella Lau5bc2c1e2017-08-23 12:03:30 -0700504
Stella Laua1f04d52017-09-01 14:52:51 -0700505 /* Copy long distance matching parameters */
Stella Lau767a0b32017-09-01 12:24:59 -0700506 cctx->requestedParams.ldmParams = params->ldmParams;
Stella Lau8081bec2017-08-31 15:40:16 -0700507
Stella Lau5bc2c1e2017-08-23 12:03:30 -0700508 /* customMem is used only for create/free params and can be ignored */
Stella Lau97e27af2017-08-18 11:20:08 -0700509 return 0;
510}
511
Yann Colletb0edb7f2017-05-12 15:31:53 -0700512ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
Yann Collet083fcc82015-10-25 14:06:35 +0100513{
Yann Colletfbd5ab72017-09-29 19:40:27 -0700514 DEBUGLOG(4, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize);
Yann Collet24de7b02017-05-22 13:05:45 -0700515 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colleta0ba8492017-06-16 13:29:17 -0700516 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700517 return 0;
518}
Yann Collet59d70632015-11-04 12:05:27 +0100519
Stella Lauc7a18b72017-08-29 15:10:42 -0700520size_t ZSTD_CCtx_loadDictionary_advanced(
521 ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
522 ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictMode_e dictMode)
Yann Collet6d4fef32017-05-17 18:36:15 -0700523{
Yann Collet24de7b02017-05-22 13:05:45 -0700524 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletc7fe2622017-05-23 13:16:00 -0700525 if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
Yann Colletfbd5ab72017-09-29 19:40:27 -0700526 DEBUGLOG(4, "load dictionary of size %u", (U32)dictSize);
Yann Collet6d4fef32017-05-17 18:36:15 -0700527 ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */
528 if (dict==NULL || dictSize==0) { /* no dictionary mode */
529 cctx->cdictLocal = NULL;
530 cctx->cdict = NULL;
531 } else {
Yann Collet8b21ec42017-05-19 19:46:15 -0700532 ZSTD_compressionParameters const cParams =
Stella Lau0e56a842017-08-28 19:25:17 -0700533 ZSTD_getCParamsFromCCtxParams(cctx->requestedParams, 0, dictSize);
Yann Collet6d4fef32017-05-17 18:36:15 -0700534 cctx->cdictLocal = ZSTD_createCDict_advanced(
535 dict, dictSize,
Stella Lauee657012017-08-29 20:27:35 -0700536 dictLoadMethod, dictMode,
Yann Collet8b21ec42017-05-19 19:46:15 -0700537 cParams, cctx->customMem);
Yann Collet6d4fef32017-05-17 18:36:15 -0700538 cctx->cdict = cctx->cdictLocal;
539 if (cctx->cdictLocal == NULL)
540 return ERROR(memory_allocation);
541 }
542 return 0;
543}
544
Stella Laueb7bbab2017-08-25 10:48:07 -0700545ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
546 ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
547{
Stella Lauc7a18b72017-08-29 15:10:42 -0700548 return ZSTD_CCtx_loadDictionary_advanced(
549 cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dm_auto);
Stella Laueb7bbab2017-08-25 10:48:07 -0700550}
551
552ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
553{
Stella Lauc7a18b72017-08-29 15:10:42 -0700554 return ZSTD_CCtx_loadDictionary_advanced(
555 cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dm_auto);
Stella Laueb7bbab2017-08-25 10:48:07 -0700556}
557
558
Yann Colletbd18c882017-06-16 10:17:50 -0700559size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Colletb0edb7f2017-05-12 15:31:53 -0700560{
Yann Collet24de7b02017-05-22 13:05:45 -0700561 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
562 cctx->cdict = cdict;
Stella Lau90a31bf2017-08-30 14:36:54 -0700563 memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* exclusive */
Yann Colletb7372932017-06-27 15:49:12 -0700564 return 0;
565}
566
567size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
568{
Stella Lauc7a18b72017-08-29 15:10:42 -0700569 return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dm_rawContent);
570}
571
572size_t ZSTD_CCtx_refPrefix_advanced(
573 ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictMode_e dictMode)
574{
Yann Colletb7372932017-06-27 15:49:12 -0700575 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
576 cctx->cdict = NULL; /* prefix discards any prior cdict */
Stella Lauc7a18b72017-08-29 15:10:42 -0700577 cctx->prefixDict.dict = prefix;
578 cctx->prefixDict.dictSize = prefixSize;
579 cctx->prefixDict.dictMode = dictMode;
Yann Colletb7372932017-06-27 15:49:12 -0700580 return 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100581}
582
Yann Colletb26728c2017-06-16 14:00:46 -0700583static void ZSTD_startNewCompression(ZSTD_CCtx* cctx)
Yann Colletbd18c882017-06-16 10:17:50 -0700584{
585 cctx->streamStage = zcss_init;
Yann Colleta0ba8492017-06-16 13:29:17 -0700586 cctx->pledgedSrcSizePlusOne = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700587}
588
589/*! ZSTD_CCtx_reset() :
590 * Also dumps dictionary */
591void ZSTD_CCtx_reset(ZSTD_CCtx* cctx)
592{
593 ZSTD_startNewCompression(cctx);
Yann Colletbd18c882017-06-16 10:17:50 -0700594 cctx->cdict = NULL;
595}
596
Yann Collet381e66c2017-06-16 17:29:35 -0700597/** ZSTD_checkCParams() :
598 control CParam values remain within authorized range.
Yann Collet21588e32016-03-30 16:50:44 +0200599 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200600size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200601{
Yann Collet15354142016-04-04 04:22:53 +0200602 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200603 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200604 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
605 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Collet2e2e78d2017-03-29 16:02:47 -0700606 CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200607 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet2bd64402017-07-13 17:12:16 -0700608 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra)
609 return ERROR(parameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200610 return 0;
611}
612
Yann Collet381e66c2017-06-16 17:29:35 -0700613/** ZSTD_clampCParams() :
614 * make CParam values within valid range.
615 * @return : valid CParams */
616static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters cParams)
617{
618# define CLAMP(val,min,max) { \
619 if (val<min) val=min; \
620 else if (val>max) val=max; \
621 }
622 CLAMP(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
623 CLAMP(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
624 CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
625 CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
626 CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
627 CLAMP(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
628 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) cParams.strategy = ZSTD_btultra;
629 return cParams;
630}
Yann Collet21588e32016-03-30 16:50:44 +0200631
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100632/** ZSTD_cycleLog() :
633 * condition for correct operation : hashLog > 1 */
634static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
635{
636 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
637 return hashLog - btScale;
638}
639
Yann Collet381e66c2017-06-16 17:29:35 -0700640/** ZSTD_adjustCParams_internal() :
Yann Colletcf409a72016-09-26 16:41:05 +0200641 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet86b4fe52017-09-28 18:14:28 -0700642 mostly downsizing to reduce memory consumption and initialization latency.
643 Both `srcSize` and `dictSize` are optional (use 0 if unknown).
Yann Collet9b5b47a2017-09-28 01:25:40 -0700644 Note : cPar is considered validated at this stage. Use ZSTD_checkCParams() to ensure that condition. */
Yann Collet381e66c2017-06-16 17:29:35 -0700645ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100646{
Yann Collet86b4fe52017-09-28 18:14:28 -0700647 static const U64 minSrcSize = 513; /* (1<<9) + 1 */
648 static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
Yann Collet381e66c2017-06-16 17:29:35 -0700649 assert(ZSTD_checkCParams(cPar)==0);
Yann Collet59d70632015-11-04 12:05:27 +0100650
Yann Collet86b4fe52017-09-28 18:14:28 -0700651 if (dictSize && (srcSize+1<2) /* srcSize unknown */ )
652 srcSize = minSrcSize; /* presumed small when there is a dictionary */
Nick Terrellc5d6dde2017-09-30 14:17:32 -0700653 else if (srcSize == 0)
Yann Colletdc404112017-09-30 15:02:40 -0700654 srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */
Yann Collet86b4fe52017-09-28 18:14:28 -0700655
656 /* resize windowLog if input is small enough, to use less memory */
657 if ( (srcSize < maxWindowResize)
658 && (dictSize < maxWindowResize) ) {
659 U32 const tSize = (U32)(srcSize + dictSize);
660 static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN;
661 U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN :
662 ZSTD_highbit32(tSize-1) + 1;
663 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
664 }
Yann Collet70d13012016-06-01 18:45:34 +0200665 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100666 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
Yann Collet9b5b47a2017-09-28 01:25:40 -0700667 if (cycleLog > cPar.windowLog)
668 cPar.chainLog -= (cycleLog - cPar.windowLog);
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100669 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100670
Yann Collet9b5b47a2017-09-28 01:25:40 -0700671 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
672 cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200673
674 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100675}
676
Yann Collet381e66c2017-06-16 17:29:35 -0700677ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
678{
679 cPar = ZSTD_clampCParams(cPar);
680 return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
681}
682
Yann Collet96f0cde2017-09-24 16:47:02 -0700683size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
Yann Collete74215e2016-03-19 16:09:09 +0100684{
Stella Lau15fdeb92017-08-24 16:28:49 -0700685 /* Estimate CCtx size is supported for single-threaded compression only. */
Stella Lau90a31bf2017-08-30 14:36:54 -0700686 if (params->nbThreads > 1) { return ERROR(GENERIC); }
Stella Lau0e56a842017-08-28 19:25:17 -0700687 { ZSTD_compressionParameters const cParams =
688 ZSTD_getCParamsFromCCtxParams(*params, 0, 0);
Stella Lau15fdeb92017-08-24 16:28:49 -0700689 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
690 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
691 size_t const maxNbSeq = blockSize / divider;
692 size_t const tokenSpace = blockSize + 11*maxNbSeq;
693 size_t const chainSize =
Nick Terrelld6abb282017-09-21 16:18:34 -0700694 (cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams.chainLog);
Stella Lau15fdeb92017-08-24 16:28:49 -0700695 size_t const hSize = ((size_t)1) << cParams.hashLog;
696 U32 const hashLog3 = (cParams.searchLength>3) ?
697 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
698 size_t const h3Size = ((size_t)1) << hashLog3;
699 size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
700 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200701
Stella Lau15fdeb92017-08-24 16:28:49 -0700702 size_t const optBudget =
703 ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
704 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
705 size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
Stella Lau6a546ef2017-07-28 15:51:33 -0700706
Stella Lau767a0b32017-09-01 12:24:59 -0700707 size_t const ldmSpace = params->ldmParams.enableLdm ?
708 ZSTD_ldm_getTableSize(params->ldmParams.hashLog,
Stella Lau67d4a612017-09-02 21:10:36 -0700709 params->ldmParams.bucketSizeLog) : 0;
Stella Lau8081bec2017-08-31 15:40:16 -0700710
Stella Lau6a546ef2017-07-28 15:51:33 -0700711 size_t const neededSpace = entropySpace + tableSpace + tokenSpace +
712 optSpace + ldmSpace;
Yann Collet3ae543c2016-07-11 03:12:17 +0200713
Stella Lau15fdeb92017-08-24 16:28:49 -0700714 DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
715 DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
716 return sizeof(ZSTD_CCtx) + neededSpace;
717 }
Stella Lauade95b82017-08-17 18:13:08 -0700718}
Yann Collet3ae543c2016-07-11 03:12:17 +0200719
Yann Collet96f0cde2017-09-24 16:47:02 -0700720size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
Yann Collet3ae543c2016-07-11 03:12:17 +0200721{
Stella Lau939f9542017-08-21 12:57:18 -0700722 ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
Yann Collet96f0cde2017-09-24 16:47:02 -0700723 return ZSTD_estimateCCtxSize_usingCCtxParams(&params);
Yann Collet2e91dde2016-03-08 12:22:11 +0100724}
725
Yann Collet31af8292017-06-26 15:52:39 -0700726size_t ZSTD_estimateCCtxSize(int compressionLevel)
727{
728 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
Yann Collet96f0cde2017-09-24 16:47:02 -0700729 return ZSTD_estimateCCtxSize_usingCParams(cParams);
Yann Collet31af8292017-06-26 15:52:39 -0700730}
731
Yann Collet96f0cde2017-09-24 16:47:02 -0700732size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
Yann Colleta7737f62016-09-06 09:44:59 +0200733{
Stella Lau90a31bf2017-08-30 14:36:54 -0700734 if (params->nbThreads > 1) { return ERROR(GENERIC); }
Yann Collet96f0cde2017-09-24 16:47:02 -0700735 { size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
Stella Lau15fdeb92017-08-24 16:28:49 -0700736 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog);
737 size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize;
738 size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
739 size_t const streamingSize = inBuffSize + outBuffSize;
Yann Colletc7fe2622017-05-23 13:16:00 -0700740
Stella Lau15fdeb92017-08-24 16:28:49 -0700741 return CCtxSize + streamingSize;
742 }
Stella Lauade95b82017-08-17 18:13:08 -0700743}
744
Yann Collet96f0cde2017-09-24 16:47:02 -0700745size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
Yann Colleta7737f62016-09-06 09:44:59 +0200746{
Stella Lau939f9542017-08-21 12:57:18 -0700747 ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
Yann Collet96f0cde2017-09-24 16:47:02 -0700748 return ZSTD_estimateCStreamSize_usingCCtxParams(&params);
Yann Colletc7fe2622017-05-23 13:16:00 -0700749}
750
Yann Collet0c9a9152017-06-26 16:02:25 -0700751size_t ZSTD_estimateCStreamSize(int compressionLevel) {
752 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
Yann Collet96f0cde2017-09-24 16:47:02 -0700753 return ZSTD_estimateCStreamSize_usingCParams(cParams);
Yann Collet0c9a9152017-06-26 16:02:25 -0700754}
755
Stella Laud7755192017-08-18 17:37:58 -0700756static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
757 ZSTD_compressionParameters cParams2)
Yann Colleta7737f62016-09-06 09:44:59 +0200758{
Yann Colletfa3671e2017-05-19 10:51:30 -0700759 U32 bslog1 = MIN(cParams1.windowLog, ZSTD_BLOCKSIZELOG_MAX);
760 U32 bslog2 = MIN(cParams2.windowLog, ZSTD_BLOCKSIZELOG_MAX);
Yann Collet009d6042017-05-19 10:17:59 -0700761 return (bslog1 == bslog2) /* same block size */
762 & (cParams1.hashLog == cParams2.hashLog)
763 & (cParams1.chainLog == cParams2.chainLog)
764 & (cParams1.strategy == cParams2.strategy) /* opt parser space */
765 & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */
Yann Colleta7737f62016-09-06 09:44:59 +0200766}
767
Stella Lau767a0b32017-09-01 12:24:59 -0700768/** The parameters are equivalent if ldm is not enabled in both sets or
769 * all the parameters are equivalent. */
770static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
771 ldmParams_t ldmParams2)
772{
773 return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) ||
774 (ldmParams1.enableLdm == ldmParams2.enableLdm &&
775 ldmParams1.hashLog == ldmParams2.hashLog &&
Stella Lau67d4a612017-09-02 21:10:36 -0700776 ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog &&
Stella Laua1f04d52017-09-01 14:52:51 -0700777 ldmParams1.minMatchLength == ldmParams2.minMatchLength &&
778 ldmParams1.hashEveryLog == ldmParams2.hashEveryLog);
Stella Lau767a0b32017-09-01 12:24:59 -0700779}
780
Stella Laud7755192017-08-18 17:37:58 -0700781/** Equivalence for resetCCtx purposes */
782static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
783 ZSTD_CCtx_params params2)
784{
Stella Lau8081bec2017-08-31 15:40:16 -0700785 return ZSTD_equivalentCParams(params1.cParams, params2.cParams) &&
Stella Lau767a0b32017-09-01 12:24:59 -0700786 ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams);
Stella Laud7755192017-08-18 17:37:58 -0700787}
788
Yann Colleta7737f62016-09-06 09:44:59 +0200789/*! ZSTD_continueCCtx() :
Yann Colletc08e6492017-06-19 18:25:35 -0700790 * reuse CCtx without reset (note : requires no dictionary) */
Stella Lau97e27af2017-08-18 11:20:08 -0700791static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
Yann Colleta7737f62016-09-06 09:44:59 +0200792{
793 U32 const end = (U32)(cctx->nextSrc - cctx->base);
Yann Colletfbd5ab72017-09-29 19:40:27 -0700794 DEBUGLOG(4, "continue mode");
Yann Collet1ad7c822017-05-22 17:06:04 -0700795 cctx->appliedParams = params;
Yann Colletb26728c2017-06-16 14:00:46 -0700796 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
Yann Collet20d5e032017-04-11 18:34:02 -0700797 cctx->consumedSrcSize = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700798 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
Yann Collet2cf77552017-06-16 12:34:41 -0700799 cctx->appliedParams.fParams.contentSizeFlag = 0;
Yann Colletfbd5ab72017-09-29 19:40:27 -0700800 DEBUGLOG(4, "pledged content size : %u ; flag : %u",
Yann Colletb26728c2017-06-16 14:00:46 -0700801 (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
Yann Colleta7737f62016-09-06 09:44:59 +0200802 cctx->lowLimit = end;
803 cctx->dictLimit = end;
804 cctx->nextToUpdate = end+1;
805 cctx->stage = ZSTDcs_init;
806 cctx->dictID = 0;
807 cctx->loadedDictEnd = 0;
Nick Terrelle1982302017-07-17 12:27:24 -0700808 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->seqStore.rep[i] = repStartValue[i]; }
Nick Terrell7a28b9e2017-07-17 15:29:11 -0700809 cctx->optState.litLengthSum = 0; /* force reset of btopt stats */
Yann Colletb6249222016-09-06 09:54:22 +0200810 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200811 return 0;
812}
813
Yann Colletb0739bc2017-05-22 17:45:15 -0700814typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
Yann Collet5a773612017-07-03 15:21:24 -0700815typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
Yann Colleta7737f62016-09-06 09:44:59 +0200816
Yann Collet30fb4992017-04-18 14:08:50 -0700817/*! ZSTD_resetCCtx_internal() :
Yann Collet5ac72b42017-05-23 11:18:24 -0700818 note : `params` are assumed fully validated at this stage */
819static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
Stella Lau97e27af2017-08-18 11:20:08 -0700820 ZSTD_CCtx_params params, U64 pledgedSrcSize,
Yann Collet5ac72b42017-05-23 11:18:24 -0700821 ZSTD_compResetPolicy_e const crp,
822 ZSTD_buffered_policy_e const zbuff)
Yann Colleta7737f62016-09-06 09:44:59 +0200823{
Yann Colletdb1668a2017-09-29 18:05:18 -0700824 DEBUGLOG(4, "ZSTD_resetCCtx_internal");
Yann Collet5ac72b42017-05-23 11:18:24 -0700825 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Colletdb1668a2017-09-29 18:05:18 -0700826 DEBUGLOG(4, "pledgedSrcSize: %u", (U32)pledgedSrcSize);
Yann Collet0be6fd32017-05-08 16:08:01 -0700827
Yann Colletb0739bc2017-05-22 17:45:15 -0700828 if (crp == ZSTDcrp_continue) {
Stella Laud7755192017-08-18 17:37:58 -0700829 if (ZSTD_equivalentParams(params, zc->appliedParams)) {
Yann Colletdb1668a2017-09-29 18:05:18 -0700830 DEBUGLOG(4, "ZSTD_equivalentParams()==1");
Stella Laua1f04d52017-09-01 14:52:51 -0700831 assert(!(params.ldmParams.enableLdm &&
Stella Lau360428c2017-09-06 17:56:01 -0700832 params.ldmParams.hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET));
Nick Terrellde0414b2017-07-12 19:08:24 -0700833 zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
Nick Terrell830ef412017-07-13 12:45:39 -0700834 zc->entropy->offcode_repeatMode = FSE_repeat_none;
835 zc->entropy->matchlength_repeatMode = FSE_repeat_none;
836 zc->entropy->litlength_repeatMode = FSE_repeat_none;
Yann Colleta0ba8492017-06-16 13:29:17 -0700837 return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
Yann Colletb0739bc2017-05-22 17:45:15 -0700838 } }
inikep87d4f3d2016-03-02 15:56:24 +0100839
Stella Lau767a0b32017-09-01 12:24:59 -0700840 if (params.ldmParams.enableLdm) {
Stella Lau67d4a612017-09-02 21:10:36 -0700841 /* Adjust long distance matching parameters */
Stella Lau360428c2017-09-06 17:56:01 -0700842 ZSTD_ldm_adjustParameters(&params.ldmParams, params.cParams.windowLog);
843 assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
Stella Lauf902bf92017-09-11 14:55:29 -0700844 assert(params.ldmParams.hashEveryLog < 32);
Stella Lau767a0b32017-09-01 12:24:59 -0700845 zc->ldmState.hashPower =
846 ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
Stella Lau6a546ef2017-07-28 15:51:33 -0700847 }
848
Yann Colletfa3671e2017-05-19 10:51:30 -0700849 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200850 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
851 size_t const maxNbSeq = blockSize / divider;
852 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700853 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ?
Nick Terrelld6abb282017-09-21 16:18:34 -0700854 0 : ((size_t)1 << params.cParams.chainLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200855 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
Yann Collet5ac72b42017-05-23 11:18:24 -0700856 U32 const hashLog3 = (params.cParams.searchLength>3) ?
857 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200858 size_t const h3Size = ((size_t)1) << hashLog3;
859 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet7bd1a292017-06-21 11:50:33 -0700860 size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
861 size_t const buffInSize = (zbuff==ZSTDb_buffered) ? ((size_t)1 << params.cParams.windowLog) + blockSize : 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200862 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100863
Yann Colleta7737f62016-09-06 09:44:59 +0200864 /* Check if workSpace is large enough, alloc a new one if needed */
Nick Terrellde0414b2017-07-12 19:08:24 -0700865 { size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
Yann Collet71ddeb62017-04-20 22:54:54 -0700866 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
Yann Collete6fa70a2017-04-20 17:28:31 -0700867 + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
Yann Collet5ac72b42017-05-23 11:18:24 -0700868 size_t const optSpace = ( (params.cParams.strategy == ZSTD_btopt)
869 || (params.cParams.strategy == ZSTD_btultra)) ?
870 optPotentialSpace : 0;
Yann Collet7bd1a292017-06-21 11:50:33 -0700871 size_t const bufferSpace = buffInSize + buffOutSize;
Stella Lau9e406022017-09-06 08:39:46 -0700872 size_t const ldmSpace = params.ldmParams.enableLdm
873 ? ZSTD_ldm_getTableSize(params.ldmParams.hashLog, params.ldmParams.bucketSizeLog)
874 : 0;
Stella Lau6a546ef2017-07-28 15:51:33 -0700875 size_t const neededSpace = entropySpace + optSpace + ldmSpace +
876 tableSpace + tokenSpace + bufferSpace;
Yann Colletc7fe2622017-05-23 13:16:00 -0700877
Stella Lau6a546ef2017-07-28 15:51:33 -0700878 if (zc->workSpaceSize < neededSpace) { /* too small : resize */
Yann Collet0be6fd32017-05-08 16:08:01 -0700879 DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n",
Yann Colletc7fe2622017-05-23 13:16:00 -0700880 (unsigned)zc->workSpaceSize>>10,
881 (unsigned)neededSpace>>10);
882 /* static cctx : no resize, error out */
883 if (zc->staticSize) return ERROR(memory_allocation);
884
Yann Collet0181fef2017-04-06 01:25:26 -0700885 zc->workSpaceSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200886 ZSTD_free(zc->workSpace, zc->customMem);
887 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
888 if (zc->workSpace == NULL) return ERROR(memory_allocation);
889 zc->workSpaceSize = neededSpace;
Yann Collet7bb60b12017-04-20 17:38:56 -0700890 ptr = zc->workSpace;
891
892 /* entropy space */
Nick Terrellde0414b2017-07-12 19:08:24 -0700893 assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */
894 assert(zc->workSpaceSize >= sizeof(ZSTD_entropyCTables_t));
895 zc->entropy = (ZSTD_entropyCTables_t*)zc->workSpace;
Yann Colleta7737f62016-09-06 09:44:59 +0200896 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100897
Yann Collete6fa70a2017-04-20 17:28:31 -0700898 /* init params */
Yann Collet1ad7c822017-05-22 17:06:04 -0700899 zc->appliedParams = params;
Yann Colleta0ba8492017-06-16 13:29:17 -0700900 zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
Yann Collete6fa70a2017-04-20 17:28:31 -0700901 zc->consumedSrcSize = 0;
Yann Colleta0ba8492017-06-16 13:29:17 -0700902 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
Yann Colletcc9f9b72017-06-15 18:17:10 -0700903 zc->appliedParams.fParams.contentSizeFlag = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700904 DEBUGLOG(5, "pledged content size : %u ; flag : %u",
905 (U32)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
Yann Colletcc9f9b72017-06-15 18:17:10 -0700906 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100907
Yann Collet083fcc82015-10-25 14:06:35 +0100908 XXH64_reset(&zc->xxhState, 0);
Yann Collete6fa70a2017-04-20 17:28:31 -0700909 zc->stage = ZSTDcs_init;
910 zc->dictID = 0;
911 zc->loadedDictEnd = 0;
Nick Terrellde0414b2017-07-12 19:08:24 -0700912 zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
Nick Terrell830ef412017-07-13 12:45:39 -0700913 zc->entropy->offcode_repeatMode = FSE_repeat_none;
914 zc->entropy->matchlength_repeatMode = FSE_repeat_none;
915 zc->entropy->litlength_repeatMode = FSE_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200916 zc->nextToUpdate = 1;
917 zc->nextSrc = NULL;
918 zc->base = NULL;
919 zc->dictBase = NULL;
920 zc->dictLimit = 0;
921 zc->lowLimit = 0;
Nick Terrelle1982302017-07-17 12:27:24 -0700922 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->seqStore.rep[i] = repStartValue[i]; }
Yann Collete6fa70a2017-04-20 17:28:31 -0700923 zc->hashLog3 = hashLog3;
Nick Terrell7a28b9e2017-07-17 15:29:11 -0700924 zc->optState.litLengthSum = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200925
Nick Terrellde0414b2017-07-12 19:08:24 -0700926 ptr = zc->entropy + 1;
Yann Collete6fa70a2017-04-20 17:28:31 -0700927
928 /* opt parser space */
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800929 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) {
Yann Collet009d6042017-05-19 10:17:59 -0700930 DEBUGLOG(5, "reserving optimal parser space");
Yann Collete6fa70a2017-04-20 17:28:31 -0700931 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
Nick Terrell7a28b9e2017-07-17 15:29:11 -0700932 zc->optState.litFreq = (U32*)ptr;
933 zc->optState.litLengthFreq = zc->optState.litFreq + (1<<Litbits);
934 zc->optState.matchLengthFreq = zc->optState.litLengthFreq + (MaxLL+1);
935 zc->optState.offCodeFreq = zc->optState.matchLengthFreq + (MaxML+1);
936 ptr = zc->optState.offCodeFreq + (MaxOff+1);
937 zc->optState.matchTable = (ZSTD_match_t*)ptr;
938 ptr = zc->optState.matchTable + ZSTD_OPT_NUM+1;
939 zc->optState.priceTable = (ZSTD_optimal_t*)ptr;
940 ptr = zc->optState.priceTable + ZSTD_OPT_NUM+1;
Yann Colleta7737f62016-09-06 09:44:59 +0200941 }
Yann Collete6fa70a2017-04-20 17:28:31 -0700942
Stella Lau9e406022017-09-06 08:39:46 -0700943 /* ldm hash table */
944 /* initialize bucketOffsets table later for pointer alignment */
Stella Lau767a0b32017-09-01 12:24:59 -0700945 if (params.ldmParams.enableLdm) {
946 size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
Stella Lau9e406022017-09-06 08:39:46 -0700947 memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t));
Stella Lau6a546ef2017-07-28 15:51:33 -0700948 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
949 zc->ldmState.hashTable = (ldmEntry_t*)ptr;
950 ptr = zc->ldmState.hashTable + ldmHSize;
Stella Lau6a546ef2017-07-28 15:51:33 -0700951 }
952
Yann Collete6fa70a2017-04-20 17:28:31 -0700953 /* table Space */
954 if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
955 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
956 zc->hashTable = (U32*)(ptr);
957 zc->chainTable = zc->hashTable + hSize;
958 zc->hashTable3 = zc->chainTable + chainSize;
959 ptr = zc->hashTable3 + h3Size;
960
961 /* sequences storage */
Yann Colleta7737f62016-09-06 09:44:59 +0200962 zc->seqStore.sequencesStart = (seqDef*)ptr;
963 ptr = zc->seqStore.sequencesStart + maxNbSeq;
964 zc->seqStore.llCode = (BYTE*) ptr;
965 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
966 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
967 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700968 ptr = zc->seqStore.litStart + blockSize;
969
Stella Lau9e406022017-09-06 08:39:46 -0700970 /* ldm bucketOffsets table */
971 if (params.ldmParams.enableLdm) {
972 size_t const ldmBucketSize =
973 ((size_t)1) << (params.ldmParams.hashLog -
974 params.ldmParams.bucketSizeLog);
Stella Lau9e406022017-09-06 08:39:46 -0700975 memset(ptr, 0, ldmBucketSize);
976 zc->ldmState.bucketOffsets = (BYTE*)ptr;
977 ptr = zc->ldmState.bucketOffsets + ldmBucketSize;
978 }
979
Yann Collet5ac72b42017-05-23 11:18:24 -0700980 /* buffers */
981 zc->inBuffSize = buffInSize;
982 zc->inBuff = (char*)ptr;
983 zc->outBuffSize = buffOutSize;
984 zc->outBuff = zc->inBuff + buffInSize;
Yann Colleta7737f62016-09-06 09:44:59 +0200985
Yann Colleta7737f62016-09-06 09:44:59 +0200986 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100987 }
Yann Colletf3eca252015-10-22 15:31:46 +0100988}
989
Yann Collet32dfae62017-01-19 10:32:55 -0800990/* ZSTD_invalidateRepCodes() :
991 * ensures next compression will not use repcodes from previous block.
992 * Note : only works with regular variant;
993 * do not use with extDict variant ! */
994void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
995 int i;
Nick Terrelle1982302017-07-17 12:27:24 -0700996 for (i=0; i<ZSTD_REP_NUM; i++) cctx->seqStore.rep[i] = 0;
Yann Collet32dfae62017-01-19 10:32:55 -0800997}
Yann Collet083fcc82015-10-25 14:06:35 +0100998
Yann Collet7b51a292016-01-26 15:58:49 +0100999
Yann Colleta4cab802017-04-18 14:54:54 -07001000/*! ZSTD_copyCCtx_internal() :
1001 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Stella Laufd0071d2017-09-05 15:34:17 -07001002 * The "context", in this case, refers to the hash and chain tables, entropy
1003 * tables, and dictionary offsets.
Yann Colleta4cab802017-04-18 14:54:54 -07001004 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
1005 * pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
1006 * @return : 0, or an error code */
Yann Collet1ad7c822017-05-22 17:06:04 -07001007static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1008 const ZSTD_CCtx* srcCCtx,
1009 ZSTD_frameParameters fParams,
Yann Collet204b6b72017-06-21 15:13:00 -07001010 unsigned long long pledgedSrcSize,
1011 ZSTD_buffered_policy_e zbuff)
Yann Collet7b51a292016-01-26 15:58:49 +01001012{
Yann Collet009d6042017-05-19 10:17:59 -07001013 DEBUGLOG(5, "ZSTD_copyCCtx_internal");
Yann Collet7b51a292016-01-26 15:58:49 +01001014 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Sean Purcell2db72492017-02-09 10:50:43 -08001015
inikep28669512016-06-02 13:04:18 +02001016 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Stella Laufd0071d2017-09-05 15:34:17 -07001017 { ZSTD_CCtx_params params = dstCCtx->requestedParams;
1018 /* Copy only compression parameters related to tables. */
1019 params.cParams = srcCCtx->appliedParams.cParams;
Yann Colleta4cab802017-04-18 14:54:54 -07001020 params.fParams = fParams;
Yann Collet5ac72b42017-05-23 11:18:24 -07001021 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
1022 ZSTDcrp_noMemset, zbuff);
Sean Purcell2db72492017-02-09 10:50:43 -08001023 }
Yann Collet7b51a292016-01-26 15:58:49 +01001024
1025 /* copy tables */
Nick Terrelld6abb282017-09-21 16:18:34 -07001026 { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
Yann Collet1ad7c822017-05-22 17:06:04 -07001027 size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02001028 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
1029 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collete6fa70a2017-04-20 17:28:31 -07001030 assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
1031 assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
1032 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
Yann Colletc6eea2b2016-03-19 17:18:00 +01001033 }
Yann Collet7b51a292016-01-26 15:58:49 +01001034
Yann Colletc46fb922016-05-29 05:01:04 +02001035 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +01001036 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
1037 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
1038 dstCCtx->nextSrc = srcCCtx->nextSrc;
1039 dstCCtx->base = srcCCtx->base;
1040 dstCCtx->dictBase = srcCCtx->dictBase;
1041 dstCCtx->dictLimit = srcCCtx->dictLimit;
1042 dstCCtx->lowLimit = srcCCtx->lowLimit;
1043 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +02001044 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +01001045
Yann Colletfb810d62016-01-28 00:18:06 +01001046 /* copy entropy tables */
Nick Terrellde0414b2017-07-12 19:08:24 -07001047 memcpy(dstCCtx->entropy, srcCCtx->entropy, sizeof(ZSTD_entropyCTables_t));
Yann Collet7b51a292016-01-26 15:58:49 +01001048
1049 return 0;
1050}
1051
Yann Colleta4cab802017-04-18 14:54:54 -07001052/*! ZSTD_copyCCtx() :
1053 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
1054 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
1055 * pledgedSrcSize==0 means "unknown".
1056* @return : 0, or an error code */
1057size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
1058{
1059 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet204b6b72017-06-21 15:13:00 -07001060 ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
1061 ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
Yann Colleta4cab802017-04-18 14:54:54 -07001062 fParams.contentSizeFlag = pledgedSrcSize>0;
1063
Yann Collet204b6b72017-06-21 15:13:00 -07001064 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize, zbuff);
Yann Colleta4cab802017-04-18 14:54:54 -07001065}
1066
Yann Collet7b51a292016-01-26 15:58:49 +01001067
Yann Colletecabfe32016-03-20 16:20:06 +01001068/*! ZSTD_reduceTable() :
Yann Colleta4cab802017-04-18 14:54:54 -07001069 * reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +01001070static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +01001071{
Yann Colletecabfe32016-03-20 16:20:06 +01001072 U32 u;
1073 for (u=0 ; u < size ; u++) {
1074 if (table[u] < reducerValue) table[u] = 0;
1075 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +01001076 }
1077}
1078
Stella Lau6a546ef2017-07-28 15:51:33 -07001079/*! ZSTD_ldm_reduceTable() :
1080 * reduce table indexes by `reducerValue` */
1081static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
Stella Lau8081bec2017-08-31 15:40:16 -07001082 U32 const reducerValue)
Stella Lau6a546ef2017-07-28 15:51:33 -07001083{
1084 U32 u;
1085 for (u = 0; u < size; u++) {
1086 if (table[u].offset < reducerValue) table[u].offset = 0;
1087 else table[u].offset -= reducerValue;
1088 }
1089}
1090
Yann Colletecabfe32016-03-20 16:20:06 +01001091/*! ZSTD_reduceIndex() :
1092* rescale all indexes to avoid future overflow (indexes are U32) */
1093static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
1094{
Stella Lau0d1b54d2017-09-11 13:02:09 -07001095 { U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +01001096 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
1097
Stella Lau0d1b54d2017-09-11 13:02:09 -07001098 { U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((U32)1 << zc->appliedParams.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +02001099 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +01001100
Stella Lau0d1b54d2017-09-11 13:02:09 -07001101 { U32 const h3Size = (zc->hashLog3) ? (U32)1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +01001102 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
Stella Lau6a546ef2017-07-28 15:51:33 -07001103
Stella Lau767a0b32017-09-01 12:24:59 -07001104 { if (zc->appliedParams.ldmParams.enableLdm) {
Stella Lau0d1b54d2017-09-11 13:02:09 -07001105 U32 const ldmHSize = (U32)1 << zc->appliedParams.ldmParams.hashLog;
Stella Lau6a546ef2017-07-28 15:51:33 -07001106 ZSTD_ldm_reduceTable(zc->ldmState.hashTable, ldmHSize, reducerValue);
1107 }
1108 }
Yann Colletecabfe32016-03-20 16:20:06 +01001109}
1110
Yann Collet89db5e02015-11-13 11:27:46 +01001111
Yann Collet863ec402016-01-28 17:56:33 +01001112/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +01001113* Block entropic compression
1114*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +01001115
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +02001116/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +01001117
Yann Colletd1b26842016-03-15 01:24:33 +01001118size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +01001119{
Yann Colletd1b26842016-03-15 01:24:33 +01001120 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +02001121 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
1122 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +01001123 return ZSTD_blockHeaderSize+srcSize;
1124}
1125
1126
Yann Colletd1b26842016-03-15 01:24:33 +01001127static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +01001128{
1129 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +02001130 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +01001131
Yann Colletd1b26842016-03-15 01:24:33 +01001132 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +01001133
Yann Collet59d1f792016-01-23 19:28:41 +01001134 switch(flSize)
1135 {
1136 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +02001137 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +01001138 break;
1139 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +02001140 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +01001141 break;
Yann Collet59d1f792016-01-23 19:28:41 +01001142 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +02001143 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +01001144 break;
Yann Colletcd2892f2017-06-01 09:44:54 -07001145 default: /* not necessary : flSize is {1,2,3} */
1146 assert(0);
Yann Collet59d1f792016-01-23 19:28:41 +01001147 }
1148
1149 memcpy(ostart + flSize, src, srcSize);
1150 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +01001151}
1152
Yann Colletd1b26842016-03-15 01:24:33 +01001153static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +01001154{
1155 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +02001156 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +01001157
Yann Collet198e6aa2016-07-20 20:12:24 +02001158 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +01001159
1160 switch(flSize)
1161 {
1162 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +02001163 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +01001164 break;
1165 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +02001166 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +01001167 break;
Yann Collet59d1f792016-01-23 19:28:41 +01001168 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +02001169 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +01001170 break;
Yann Colletcd2892f2017-06-01 09:44:54 -07001171 default: /* not necessary : flSize is {1,2,3} */
1172 assert(0);
Yann Collet59d1f792016-01-23 19:28:41 +01001173 }
1174
1175 ostart[flSize] = *(const BYTE*)src;
1176 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +01001177}
1178
Yann Collet59d1f792016-01-23 19:28:41 +01001179
Yann Colleta5c2c082016-03-20 01:09:18 +01001180static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +01001181
Nick Terrelle1982302017-07-17 12:27:24 -07001182static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
1183 ZSTD_strategy strategy,
Yann Colletd1b26842016-03-15 01:24:33 +01001184 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +01001185 const void* src, size_t srcSize)
1186{
Yann Colleta910dc82016-03-18 12:37:45 +01001187 size_t const minGain = ZSTD_minGain(srcSize);
1188 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +02001189 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +01001190 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +02001191 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +01001192 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +01001193
Yann Collet14983e72015-11-11 21:38:21 +01001194
Yann Colleta5c2c082016-03-20 01:09:18 +01001195 /* small ? don't even attempt compression (speed opt) */
1196# define LITERAL_NOENTROPY 63
Nick Terrelle1982302017-07-17 12:27:24 -07001197 { size_t const minLitSize = entropy->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
Yann Colleta5c2c082016-03-20 01:09:18 +01001198 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
1199 }
1200
1201 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Nick Terrelle1982302017-07-17 12:27:24 -07001202 { HUF_repeat repeat = entropy->hufCTable_repeatMode;
1203 int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
Nick Terrella4197772017-03-01 17:51:56 -08001204 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
Yann Collete348dad2017-04-20 11:14:13 -07001205 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Nick Terrelle1982302017-07-17 12:27:24 -07001206 entropy->workspace, sizeof(entropy->workspace), (HUF_CElt*)entropy->hufCTable, &repeat, preferRepeat)
Yann Collete348dad2017-04-20 11:14:13 -07001207 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Nick Terrelle1982302017-07-17 12:27:24 -07001208 entropy->workspace, sizeof(entropy->workspace), (HUF_CElt*)entropy->hufCTable, &repeat, preferRepeat);
Nick Terrella4197772017-03-01 17:51:56 -08001209 if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
Nick Terrelle1982302017-07-17 12:27:24 -07001210 else { entropy->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
Yann Colletb923f652016-01-26 03:14:20 +01001211 }
Yann Collet14983e72015-11-11 21:38:21 +01001212
Nick Terrell308047e2017-08-03 14:05:01 -07001213 if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
Nick Terrelle1982302017-07-17 12:27:24 -07001214 entropy->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +01001215 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -08001216 }
1217 if (cLitSize==1) {
Nick Terrelle1982302017-07-17 12:27:24 -07001218 entropy->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +01001219 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -08001220 }
Yann Collet14983e72015-11-11 21:38:21 +01001221
1222 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +01001223 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +01001224 {
Yann Collet59d1f792016-01-23 19:28:41 +01001225 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +02001226 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +02001227 MEM_writeLE24(ostart, lhc);
1228 break;
1229 }
Yann Collet59d1f792016-01-23 19:28:41 +01001230 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +02001231 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +02001232 MEM_writeLE32(ostart, lhc);
1233 break;
1234 }
Yann Collet59d1f792016-01-23 19:28:41 +01001235 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +02001236 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +02001237 MEM_writeLE32(ostart, lhc);
1238 ostart[4] = (BYTE)(cLitSize >> 10);
1239 break;
1240 }
Yann Colleta9e57052017-10-13 02:36:16 -07001241 default: /* not possible : lhSize is {3,4,5} */
Yann Colletcd2892f2017-06-01 09:44:54 -07001242 assert(0);
Yann Collet14983e72015-11-11 21:38:21 +01001243 }
Yann Colleta910dc82016-03-18 12:37:45 +01001244 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +01001245}
1246
Yann Colleted57d852016-07-29 21:22:17 +02001247
1248void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +01001249{
Yann Colleted57d852016-07-29 21:22:17 +02001250 BYTE const LL_deltaCode = 19;
1251 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +02001252 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +02001253 BYTE* const llCodeTable = seqStorePtr->llCode;
1254 BYTE* const ofCodeTable = seqStorePtr->ofCode;
1255 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +02001256 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +02001257 U32 u;
1258 for (u=0; u<nbSeq; u++) {
1259 U32 const llv = sequences[u].litLength;
1260 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +02001261 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +02001262 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +02001263 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +02001264 }
Yann Colleted57d852016-07-29 21:22:17 +02001265 if (seqStorePtr->longLengthID==1)
1266 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
1267 if (seqStorePtr->longLengthID==2)
1268 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +01001269}
1270
Nick Terrellbbe77212017-09-18 16:54:53 -07001271typedef enum {
1272 ZSTD_defaultDisallowed = 0,
1273 ZSTD_defaultAllowed = 1
1274} ZSTD_defaultPolicy_e;
1275
Yann Colleta9e57052017-10-13 02:36:16 -07001276MEM_STATIC
1277symbolEncodingType_e ZSTD_selectEncodingType(
Nick Terrellbbe77212017-09-18 16:54:53 -07001278 FSE_repeat* repeatMode, size_t const mostFrequent, size_t nbSeq,
1279 U32 defaultNormLog, ZSTD_defaultPolicy_e const isDefaultAllowed)
Nick Terrell634f0122017-07-14 19:11:58 -07001280{
1281#define MIN_SEQ_FOR_DYNAMIC_FSE 64
1282#define MAX_SEQ_FOR_STATIC_FSE 1000
Nick Terrellbbe77212017-09-18 16:54:53 -07001283 ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
1284 if ((mostFrequent == nbSeq) && (!isDefaultAllowed || nbSeq > 2)) {
Nick Terrellced6e612017-10-13 14:09:17 -07001285 DEBUGLOG(5, "Selected set_rle");
Nick Terrellbbe77212017-09-18 16:54:53 -07001286 /* Prefer set_basic over set_rle when there are 2 or less symbols,
1287 * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
1288 * If basic encoding isn't possible, always choose RLE.
1289 */
Nick Terrell634f0122017-07-14 19:11:58 -07001290 *repeatMode = FSE_repeat_check;
1291 return set_rle;
1292 }
Yann Colleta9e57052017-10-13 02:36:16 -07001293 if ( isDefaultAllowed
1294 && (*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Nick Terrellced6e612017-10-13 14:09:17 -07001295 DEBUGLOG(5, "Selected set_repeat");
Nick Terrell634f0122017-07-14 19:11:58 -07001296 return set_repeat;
1297 }
Yann Colleta9e57052017-10-13 02:36:16 -07001298 if ( isDefaultAllowed
1299 && ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1)))) ) {
Nick Terrellced6e612017-10-13 14:09:17 -07001300 DEBUGLOG(5, "Selected set_basic");
Nick Terrell634f0122017-07-14 19:11:58 -07001301 *repeatMode = FSE_repeat_valid;
1302 return set_basic;
1303 }
Nick Terrellced6e612017-10-13 14:09:17 -07001304 DEBUGLOG(5, "Selected set_compressed");
Nick Terrell634f0122017-07-14 19:11:58 -07001305 *repeatMode = FSE_repeat_check;
1306 return set_compressed;
1307}
1308
Yann Colleta9e57052017-10-13 02:36:16 -07001309MEM_STATIC
1310size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
Nick Terrell634f0122017-07-14 19:11:58 -07001311 FSE_CTable* CTable, U32 FSELog, symbolEncodingType_e type,
1312 U32* count, U32 max,
1313 BYTE const* codeTable, size_t nbSeq,
1314 S16 const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
1315 void* workspace, size_t workspaceSize)
1316{
1317 BYTE* op = (BYTE*)dst;
1318 BYTE const* const oend = op + dstCapacity;
1319
1320 switch (type) {
1321 case set_rle:
1322 *op = codeTable[0];
1323 CHECK_F(FSE_buildCTable_rle(CTable, (BYTE)max));
1324 return 1;
1325 case set_repeat:
1326 return 0;
1327 case set_basic:
Yann Colleta9e57052017-10-13 02:36:16 -07001328 CHECK_F(FSE_buildCTable_wksp(CTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */
Nick Terrell634f0122017-07-14 19:11:58 -07001329 return 0;
1330 case set_compressed: {
1331 S16 norm[MaxSeq + 1];
1332 size_t nbSeq_1 = nbSeq;
1333 const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
1334 if (count[codeTable[nbSeq-1]] > 1) {
1335 count[codeTable[nbSeq-1]]--;
1336 nbSeq_1--;
1337 }
Nick Terrellbbe77212017-09-18 16:54:53 -07001338 assert(nbSeq_1 > 1);
Nick Terrell634f0122017-07-14 19:11:58 -07001339 CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
1340 { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
1341 if (FSE_isError(NCountSize)) return NCountSize;
1342 CHECK_F(FSE_buildCTable_wksp(CTable, norm, max, tableLog, workspace, workspaceSize));
1343 return NCountSize;
1344 }
1345 }
1346 default: return assert(0), ERROR(GENERIC);
1347 }
1348}
1349
Yann Colleta9e57052017-10-13 02:36:16 -07001350MEM_STATIC
1351size_t ZSTD_encodeSequences(
1352 void* dst, size_t dstCapacity,
1353 FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
1354 FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
1355 FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
1356 seqDef const* sequences, size_t nbSeq, int longOffsets)
Nick Terrell634f0122017-07-14 19:11:58 -07001357{
1358 BIT_CStream_t blockStream;
1359 FSE_CState_t stateMatchLength;
1360 FSE_CState_t stateOffsetBits;
1361 FSE_CState_t stateLitLength;
1362
1363 CHECK_E(BIT_initCStream(&blockStream, dst, dstCapacity), dstSize_tooSmall); /* not enough space remaining */
1364
1365 /* first symbols */
1366 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
1367 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
1368 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
1369 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
1370 if (MEM_32bits()) BIT_flushBits(&blockStream);
1371 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
1372 if (MEM_32bits()) BIT_flushBits(&blockStream);
1373 if (longOffsets) {
1374 U32 const ofBits = ofCodeTable[nbSeq-1];
1375 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1376 if (extraBits) {
1377 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
1378 BIT_flushBits(&blockStream);
1379 }
1380 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
1381 ofBits - extraBits);
1382 } else {
1383 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
1384 }
1385 BIT_flushBits(&blockStream);
1386
1387 { size_t n;
1388 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
1389 BYTE const llCode = llCodeTable[n];
1390 BYTE const ofCode = ofCodeTable[n];
1391 BYTE const mlCode = mlCodeTable[n];
1392 U32 const llBits = LL_bits[llCode];
Yann Colleta9e57052017-10-13 02:36:16 -07001393 U32 const ofBits = ofCode;
Nick Terrell634f0122017-07-14 19:11:58 -07001394 U32 const mlBits = ML_bits[mlCode];
Yann Colleta9e57052017-10-13 02:36:16 -07001395 DEBUGLOG(6, "encoding: litlen:%u - matchlen:%u - offCode:%u",
1396 sequences[n].litLength,
1397 sequences[n].matchLength + MINMATCH,
1398 sequences[n].offset); /* 32b*/ /* 64b*/
Nick Terrell634f0122017-07-14 19:11:58 -07001399 /* (7)*/ /* (7)*/
1400 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
1401 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
1402 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
1403 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
1404 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
1405 BIT_flushBits(&blockStream); /* (7)*/
1406 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
1407 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
1408 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Collet6b2b6a92017-08-22 12:08:39 -07001409 if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream);
Nick Terrell634f0122017-07-14 19:11:58 -07001410 if (longOffsets) {
1411 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1412 if (extraBits) {
1413 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
1414 BIT_flushBits(&blockStream); /* (7)*/
1415 }
1416 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
1417 ofBits - extraBits); /* 31 */
1418 } else {
1419 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
1420 }
1421 BIT_flushBits(&blockStream); /* (7)*/
1422 } }
1423
1424 FSE_flushCState(&blockStream, &stateMatchLength);
1425 FSE_flushCState(&blockStream, &stateOffsetBits);
1426 FSE_flushCState(&blockStream, &stateLitLength);
1427
1428 { size_t const streamSize = BIT_closeCStream(&blockStream);
1429 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
1430 return streamSize;
1431 }
1432}
1433
Nick Terrell308047e2017-08-03 14:05:01 -07001434MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
Nick Terrelle1982302017-07-17 12:27:24 -07001435 ZSTD_entropyCTables_t* entropy,
1436 ZSTD_compressionParameters const* cParams,
Nick Terrell308047e2017-08-03 14:05:01 -07001437 void* dst, size_t dstCapacity)
Yann Collet14983e72015-11-11 21:38:21 +01001438{
Nick Terrelle1982302017-07-17 12:27:24 -07001439 const int longOffsets = cParams->windowLog > STREAM_ACCUMULATOR_MIN;
Yann Collet14983e72015-11-11 21:38:21 +01001440 U32 count[MaxSeq+1];
Nick Terrelle1982302017-07-17 12:27:24 -07001441 FSE_CTable* CTable_LitLength = entropy->litlengthCTable;
1442 FSE_CTable* CTable_OffsetBits = entropy->offcodeCTable;
1443 FSE_CTable* CTable_MatchLength = entropy->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +01001444 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +02001445 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +02001446 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
1447 const BYTE* const llCodeTable = seqStorePtr->llCode;
1448 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +01001449 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +01001450 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +01001451 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +02001452 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +01001453 BYTE* seqHead;
Nick Terrell634f0122017-07-14 19:11:58 -07001454
Nick Terrelle1982302017-07-17 12:27:24 -07001455 ZSTD_STATIC_ASSERT(sizeof(entropy->workspace) >= (1<<MAX(MLFSELog,LLFSELog)));
Yann Collet14983e72015-11-11 21:38:21 +01001456
Yann Collet14983e72015-11-11 21:38:21 +01001457 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +01001458 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +01001459 size_t const litSize = seqStorePtr->lit - literals;
Nick Terrelle1982302017-07-17 12:27:24 -07001460 size_t const cSize = ZSTD_compressLiterals(
1461 entropy, cParams->strategy, op, dstCapacity, literals, litSize);
1462 if (ZSTD_isError(cSize))
1463 return cSize;
Yann Collet14983e72015-11-11 21:38:21 +01001464 op += cSize;
1465 }
1466
1467 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +01001468 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +01001469 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
1470 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
1471 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Nick Terrell308047e2017-08-03 14:05:01 -07001472 if (nbSeq==0) return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +01001473
Yann Colletbe391432016-03-22 23:19:28 +01001474 /* seqHead : flags for FSE encoding type */
1475 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +01001476
Yann Colletb44be742016-03-26 20:52:14 +01001477 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +02001478 ZSTD_seqToCodes(seqStorePtr);
Yann Colleta9e57052017-10-13 02:36:16 -07001479 /* build CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001480 { U32 max = MaxLL;
Nick Terrelle1982302017-07-17 12:27:24 -07001481 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, entropy->workspace);
Nick Terrellced6e612017-10-13 14:09:17 -07001482 DEBUGLOG(5, "Building LL table");
Nick Terrellbbe77212017-09-18 16:54:53 -07001483 LLtype = ZSTD_selectEncodingType(&entropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed);
Nick Terrell634f0122017-07-14 19:11:58 -07001484 { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
1485 count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
Nick Terrelle1982302017-07-17 12:27:24 -07001486 entropy->workspace, sizeof(entropy->workspace));
Nick Terrell634f0122017-07-14 19:11:58 -07001487 if (ZSTD_isError(countSize)) return countSize;
1488 op += countSize;
Yann Colletfadda6c2016-03-22 12:14:26 +01001489 } }
Yann Colleta9e57052017-10-13 02:36:16 -07001490 /* build CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +01001491 { U32 max = MaxOff;
Nick Terrelle1982302017-07-17 12:27:24 -07001492 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, entropy->workspace);
Nick Terrellbbe77212017-09-18 16:54:53 -07001493 /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
Yann Colleta9e57052017-10-13 02:36:16 -07001494 ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
Nick Terrellced6e612017-10-13 14:09:17 -07001495 DEBUGLOG(5, "Building OF table");
Nick Terrellbbe77212017-09-18 16:54:53 -07001496 Offtype = ZSTD_selectEncodingType(&entropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy);
Nick Terrell634f0122017-07-14 19:11:58 -07001497 { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
Nick Terrellbbe77212017-09-18 16:54:53 -07001498 count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
Nick Terrelle1982302017-07-17 12:27:24 -07001499 entropy->workspace, sizeof(entropy->workspace));
Nick Terrell634f0122017-07-14 19:11:58 -07001500 if (ZSTD_isError(countSize)) return countSize;
1501 op += countSize;
Yann Colletfadda6c2016-03-22 12:14:26 +01001502 } }
Yann Colleta9e57052017-10-13 02:36:16 -07001503 /* build CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001504 { U32 max = MaxML;
Nick Terrelle1982302017-07-17 12:27:24 -07001505 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, entropy->workspace);
Nick Terrellced6e612017-10-13 14:09:17 -07001506 DEBUGLOG(5, "Building ML table");
Nick Terrellbbe77212017-09-18 16:54:53 -07001507 MLtype = ZSTD_selectEncodingType(&entropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed);
Nick Terrell634f0122017-07-14 19:11:58 -07001508 { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
1509 count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
Nick Terrelle1982302017-07-17 12:27:24 -07001510 entropy->workspace, sizeof(entropy->workspace));
Nick Terrell634f0122017-07-14 19:11:58 -07001511 if (ZSTD_isError(countSize)) return countSize;
1512 op += countSize;
Yann Colletfadda6c2016-03-22 12:14:26 +01001513 } }
Yann Collet14983e72015-11-11 21:38:21 +01001514
Yann Colletbe391432016-03-22 23:19:28 +01001515 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Collet14983e72015-11-11 21:38:21 +01001516
Yann Colleta9e57052017-10-13 02:36:16 -07001517 { size_t const bitstreamSize = ZSTD_encodeSequences(
1518 op, oend - op,
1519 CTable_MatchLength, mlCodeTable,
1520 CTable_OffsetBits, ofCodeTable,
1521 CTable_LitLength, llCodeTable,
1522 sequences, nbSeq,
1523 longOffsets);
1524 if (ZSTD_isError(bitstreamSize)) return bitstreamSize;
1525 op += bitstreamSize;
Nick Terrell634f0122017-07-14 19:11:58 -07001526 }
Yann Collet14983e72015-11-11 21:38:21 +01001527
Nick Terrell308047e2017-08-03 14:05:01 -07001528 return op - ostart;
1529}
Yann Collet14983e72015-11-11 21:38:21 +01001530
Nick Terrell308047e2017-08-03 14:05:01 -07001531MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
1532 ZSTD_entropyCTables_t* entropy,
1533 ZSTD_compressionParameters const* cParams,
1534 void* dst, size_t dstCapacity,
1535 size_t srcSize)
1536{
1537 size_t const cSize = ZSTD_compressSequences_internal(seqStorePtr, entropy, cParams,
1538 dst, dstCapacity);
Nick Terrell308047e2017-08-03 14:05:01 -07001539 /* If the srcSize <= dstCapacity, then there is enough space to write a
1540 * raw uncompressed block. Since we ran out of space, the block must not
1541 * be compressible, so fall back to a raw uncompressed block.
1542 */
Yann Colleta9e57052017-10-13 02:36:16 -07001543 int const uncompressibleError = (cSize == ERROR(dstSize_tooSmall)) && (srcSize <= dstCapacity);
Nick Terrell308047e2017-08-03 14:05:01 -07001544 if (ZSTD_isError(cSize) && !uncompressibleError)
1545 return cSize;
Nick Terrell24ac2db2017-10-13 12:47:00 -07001546 /* We check that dictionaries have offset codes available for the first
1547 * block. After the first block, the offcode table might not have large
1548 * enough codes to represent the offsets in the data.
1549 */
1550 if (entropy->offcode_repeatMode == FSE_repeat_valid)
1551 entropy->offcode_repeatMode = FSE_repeat_check;
Yann Colleta9e57052017-10-13 02:36:16 -07001552
Nick Terrell308047e2017-08-03 14:05:01 -07001553 /* Check compressibility */
Yann Colleta9e57052017-10-13 02:36:16 -07001554 { size_t const minGain = ZSTD_minGain(srcSize); /* note : fixed formula, maybe should depend on compression level, or strategy */
1555 size_t const maxCSize = srcSize - minGain;
1556 if (cSize >= maxCSize || uncompressibleError) {
1557 entropy->hufCTable_repeatMode = HUF_repeat_none;
1558 entropy->offcode_repeatMode = FSE_repeat_none;
1559 entropy->matchlength_repeatMode = FSE_repeat_none;
1560 entropy->litlength_repeatMode = FSE_repeat_none;
1561 return 0; /* block not compressed */
1562 } }
Nick Terrell308047e2017-08-03 14:05:01 -07001563 assert(!ZSTD_isError(cSize));
Yann Collet14983e72015-11-11 21:38:21 +01001564
Yann Colleta9e57052017-10-13 02:36:16 -07001565 /* block is compressed => confirm repcodes in history */
Nick Terrelle1982302017-07-17 12:27:24 -07001566 { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->rep[i] = seqStorePtr->repToConfirm[i]; }
Nick Terrell308047e2017-08-03 14:05:01 -07001567 return cSize;
Yann Collet14983e72015-11-11 21:38:21 +01001568}
1569
Yann Colletb44ab822017-06-20 14:11:49 -07001570/* ZSTD_selectBlockCompressor() :
Stella Lau360428c2017-09-06 17:56:01 -07001571 * Not static, but internal use only (used by long distance matcher)
Yann Colletb44ab822017-06-20 14:11:49 -07001572 * assumption : strat is a valid strategy */
Stella Lau6a546ef2017-07-28 15:51:33 -07001573typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Stella Lau360428c2017-09-06 17:56:01 -07001574ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001575{
Yann Colleta5ffe3d2017-05-12 16:29:19 -07001576 static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
Yann Colletb44ab822017-06-20 14:11:49 -07001577 { ZSTD_compressBlock_fast /* default for 0 */,
Yann Colleta5ffe3d2017-05-12 16:29:19 -07001578 ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
Yann Colletc17e0202017-04-20 12:50:02 -07001579 ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
Nick Terrell5f2c7212017-05-10 16:49:58 -07001580 ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra },
Yann Colletb44ab822017-06-20 14:11:49 -07001581 { ZSTD_compressBlock_fast_extDict /* default for 0 */,
Yann Colleta5ffe3d2017-05-12 16:29:19 -07001582 ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
Yann Colletc17e0202017-04-20 12:50:02 -07001583 ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
Nick Terrell5f2c7212017-05-10 16:49:58 -07001584 ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01001585 };
Yann Colleta5ffe3d2017-05-12 16:29:19 -07001586 ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
Yann Colleta9e57052017-10-13 02:36:16 -07001587
Yann Colletb44ab822017-06-20 14:11:49 -07001588 assert((U32)strat >= (U32)ZSTD_fast);
1589 assert((U32)strat <= (U32)ZSTD_btultra);
Yann Colletb44ab822017-06-20 14:11:49 -07001590 return blockCompressor[extDict!=0][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001591}
1592
Stella Lau6a546ef2017-07-28 15:51:33 -07001593static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
1594 const BYTE* anchor, size_t lastLLSize)
1595{
1596 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1597 seqStorePtr->lit += lastLLSize;
1598}
Yann Collet59d70632015-11-04 12:05:27 +01001599
Yann Colletd1b26842016-03-15 01:24:33 +01001600static 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 +01001601{
Yann Colleta9e57052017-10-13 02:36:16 -07001602 if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1)
1603 return 0; /* don't even attempt compression below a certain srcSize */
Yann Collet19cab462016-06-17 12:54:52 +02001604 ZSTD_resetSeqStore(&(zc->seqStore));
Stella Lau6a546ef2017-07-28 15:51:33 -07001605
Yann Colleta9e57052017-10-13 02:36:16 -07001606 /* limited update after a very long match */
1607 { const BYTE* const base = zc->base;
1608 const BYTE* const istart = (const BYTE*)src;
1609 const U32 current = (U32)(istart-base);
1610 if (current > zc->nextToUpdate + 384)
1611 zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384));
1612 }
1613 /* find and store sequences */
1614 { U32 const extDict = zc->lowLimit < zc->dictLimit;
1615 const ZSTD_blockCompressor blockCompressor =
1616 zc->appliedParams.ldmParams.enableLdm
1617 ? (extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm)
1618 : ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
1619 size_t const lastLLSize = blockCompressor(zc, src, srcSize);
1620 const BYTE* const anchor = (const BYTE*)src + srcSize - lastLLSize;
1621 ZSTD_storeLastLiterals(&zc->seqStore, anchor, lastLLSize);
1622 }
1623 /* encode */
Nick Terrelle1982302017-07-17 12:27:24 -07001624 return ZSTD_compressSequences(&zc->seqStore, zc->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001625}
1626
1627
Yann Colletdb8e21d2017-05-12 13:46:49 -07001628/*! ZSTD_compress_frameChunk() :
Yann Colletc991cc12016-07-28 00:55:43 +02001629* Compress a chunk of data into one or multiple blocks.
1630* All blocks will be terminated, all input will be consumed.
1631* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
1632* Frame is supposed already started (header already produced)
1633* @return : compressed size, or an error code
1634*/
Yann Colletdb8e21d2017-05-12 13:46:49 -07001635static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001636 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02001637 const void* src, size_t srcSize,
1638 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01001639{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001640 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001641 size_t remaining = srcSize;
1642 const BYTE* ip = (const BYTE*)src;
1643 BYTE* const ostart = (BYTE*)dst;
1644 BYTE* op = ostart;
Nick Terrellc233bdb2017-09-22 14:04:39 -07001645 U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog;
Yann Colleta9e57052017-10-13 02:36:16 -07001646 assert(cctx->appliedParams.cParams.windowLog <= 31);
Yann Collet9b11b462015-11-01 12:40:22 +01001647
Yann Collet1ad7c822017-05-22 17:06:04 -07001648 if (cctx->appliedParams.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001649 XXH64_update(&cctx->xxhState, src, srcSize);
1650
Yann Collet2ce49232016-02-02 14:36:49 +01001651 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02001652 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01001653
Yann Colletc17e0202017-04-20 12:50:02 -07001654 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
1655 return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01001656 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01001657
Nick Terrelld6abb282017-09-21 16:18:34 -07001658 /* preemptive overflow correction:
1659 * 1. correction is large enough:
1660 * lowLimit > (3<<29) ==> current > 3<<29 + 1<<windowLog - blockSize
1661 * 1<<windowLog <= newCurrent < 1<<chainLog + 1<<windowLog
1662 *
1663 * current - newCurrent
1664 * > (3<<29 + 1<<windowLog - blockSize) - (1<<windowLog + 1<<chainLog)
1665 * > (3<<29 - blockSize) - (1<<chainLog)
1666 * > (3<<29 - blockSize) - (1<<30) (NOTE: chainLog <= 30)
1667 * > 1<<29 - 1<<17
1668 *
1669 * 2. (ip+blockSize - cctx->base) doesn't overflow:
1670 * In 32 bit mode we limit windowLog to 30 so we don't get
1671 * differences larger than 1<<31-1.
1672 * 3. cctx->lowLimit < 1<<32:
1673 * windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
1674 */
Sean Purcell881abe42017-03-07 16:52:23 -08001675 if (cctx->lowLimit > (3U<<29)) {
Nick Terrellc233bdb2017-09-22 14:04:39 -07001676 U32 const cycleMask = ((U32)1 << ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01001677 U32 const current = (U32)(ip - cctx->base);
Nick Terrellc233bdb2017-09-22 14:04:39 -07001678 U32 const newCurrent = (current & cycleMask) + ((U32)1 << cctx->appliedParams.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01001679 U32 const correction = current - newCurrent;
Nick Terrelld6abb282017-09-21 16:18:34 -07001680 ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
1681 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
1682 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
1683 assert(current > newCurrent);
1684 assert(correction > 1<<28); /* Loose bound, should be about 1<<29 */
Yann Collet346efcc2016-08-02 14:26:00 +02001685 ZSTD_reduceIndex(cctx, correction);
1686 cctx->base += correction;
1687 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01001688 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02001689 cctx->dictLimit -= correction;
1690 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
1691 else cctx->nextToUpdate -= correction;
Nick Terrelld6abb282017-09-21 16:18:34 -07001692 DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x\n", correction, cctx->lowLimit);
Yann Collet346efcc2016-08-02 14:26:00 +02001693 }
Yann Colleta9e57052017-10-13 02:36:16 -07001694 /* enforce maxDist */
Yann Collet06e76972017-01-25 16:39:03 -08001695 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001696 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
1697 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
1698 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001699 }
Yann Collet89db5e02015-11-13 11:27:46 +01001700
Yann Colleta9e57052017-10-13 02:36:16 -07001701 { size_t cSize = ZSTD_compressBlock_internal(cctx,
1702 op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
1703 ip, blockSize);
1704 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001705
Yann Colleta9e57052017-10-13 02:36:16 -07001706 if (cSize == 0) { /* block is not compressible */
1707 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
1708 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
1709 MEM_writeLE32(op, cBlockHeader24); /* 4th byte will be overwritten */
1710 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
1711 cSize = ZSTD_blockHeaderSize + blockSize;
1712 } else {
1713 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
1714 MEM_writeLE24(op, cBlockHeader24);
1715 cSize += ZSTD_blockHeaderSize;
1716 }
Yann Colletf3eca252015-10-22 15:31:46 +01001717
Yann Colleta9e57052017-10-13 02:36:16 -07001718 ip += blockSize;
1719 assert(remaining >= blockSize);
1720 remaining -= blockSize;
1721 op += cSize;
1722 assert(dstCapacity >= cSize);
1723 dstCapacity -= cSize;
1724 } }
Yann Colletf3eca252015-10-22 15:31:46 +01001725
Yann Collet62470b42016-07-28 15:29:08 +02001726 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01001727 return op-ostart;
1728}
1729
1730
Yann Collet6236eba2016-04-12 15:52:33 +02001731static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Stella Lau97e27af2017-08-18 11:20:08 -07001732 ZSTD_CCtx_params params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02001733{ BYTE* const op = (BYTE*)dst;
Yann Collet31533ba2017-04-27 00:29:04 -07001734 U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
1735 U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02001736 U32 const checksumFlag = params.fParams.checksumFlag>0;
Nick Terrellc233bdb2017-09-22 14:04:39 -07001737 U32 const windowSize = (U32)1 << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08001738 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02001739 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
1740 U32 const fcsCode = params.fParams.contentSizeFlag ?
Nick Terrell55fc1f92017-05-24 13:50:10 -07001741 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02001742 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Collet62568c92017-09-25 14:26:26 -07001743 size_t pos=0;
Yann Colletc46fb922016-05-29 05:01:04 +02001744
1745 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet62568c92017-09-25 14:26:26 -07001746 DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
Yann Collet0be6fd32017-05-08 16:08:01 -07001747 !params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
Yann Collet6236eba2016-04-12 15:52:33 +02001748
Yann Collet62568c92017-09-25 14:26:26 -07001749 if (params.format == ZSTD_f_zstd1) {
1750 DEBUGLOG(4, "writing zstd magic number");
1751 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
1752 pos = 4;
1753 }
1754 op[pos++] = frameHeaderDecriptionByte;
Eric Biggerse4d02652016-07-26 10:42:19 -07001755 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02001756 switch(dictIDSizeCode)
1757 {
Yann Colletcd2892f2017-06-01 09:44:54 -07001758 default: assert(0); /* impossible */
Yann Colletc46fb922016-05-29 05:01:04 +02001759 case 0 : break;
1760 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02001761 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02001762 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
1763 }
Yann Collet673f0d72016-06-06 00:26:38 +02001764 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02001765 {
Yann Colletcd2892f2017-06-01 09:44:54 -07001766 default: assert(0); /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07001767 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02001768 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
1769 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02001770 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02001771 }
Yann Colletc46fb922016-05-29 05:01:04 +02001772 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02001773}
1774
1775
Yann Collet346efcc2016-08-02 14:26:00 +02001776static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01001777 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01001778 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02001779 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01001780{
Yann Collet2acb5d32015-10-29 16:49:43 +01001781 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02001782 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01001783
Yann Colleta3d99262017-06-29 14:44:49 -07001784 DEBUGLOG(5, "ZSTD_compressContinue_internal");
1785 DEBUGLOG(5, "stage: %u", cctx->stage);
Yann Collet346efcc2016-08-02 14:26:00 +02001786 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02001787
Yann Collet346efcc2016-08-02 14:26:00 +02001788 if (frame && (cctx->stage==ZSTDcs_init)) {
Yann Colleta0ba8492017-06-16 13:29:17 -07001789 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams,
Stella Lau6f1a21c2017-08-23 10:24:19 -07001790 cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02001791 if (ZSTD_isError(fhSize)) return fhSize;
1792 dstCapacity -= fhSize;
1793 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02001794 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01001795 }
Yann Colletf3eca252015-10-22 15:31:46 +01001796
Yann Collet417890c2015-12-04 17:16:37 +01001797 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02001798 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01001799 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02001800 ptrdiff_t const delta = cctx->nextSrc - ip;
1801 cctx->lowLimit = cctx->dictLimit;
1802 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
1803 cctx->dictBase = cctx->base;
1804 cctx->base -= delta;
1805 cctx->nextToUpdate = cctx->dictLimit;
1806 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01001807 }
1808
Yann Collet346efcc2016-08-02 14:26:00 +02001809 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
1810 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
1811 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
1812 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
1813 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01001814 }
1815
Yann Collet346efcc2016-08-02 14:26:00 +02001816 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01001817
Yann Collet5eb749e2017-01-11 18:21:25 +01001818 if (srcSize) {
1819 size_t const cSize = frame ?
Yann Colletdb8e21d2017-05-12 13:46:49 -07001820 ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
Yann Collet346efcc2016-08-02 14:26:00 +02001821 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01001822 if (ZSTD_isError(cSize)) return cSize;
Yann Collet20d5e032017-04-11 18:34:02 -07001823 cctx->consumedSrcSize += srcSize;
Yann Collet6236eba2016-04-12 15:52:33 +02001824 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01001825 } else
1826 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001827}
1828
Yann Collet5b567392016-07-28 01:17:22 +02001829size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01001830 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01001831 const void* src, size_t srcSize)
1832{
Yann Collet20d5e032017-04-11 18:34:02 -07001833 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
Yann Collet5b567392016-07-28 01:17:22 +02001834}
1835
1836
Yann Colletfa3671e2017-05-19 10:51:30 -07001837size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01001838{
Stella Lau90a31bf2017-08-30 14:36:54 -07001839 ZSTD_compressionParameters const cParams =
Stella Lau0e56a842017-08-28 19:25:17 -07001840 ZSTD_getCParamsFromCCtxParams(cctx->appliedParams, 0, 0);
Nick Terrellc233bdb2017-09-22 14:04:39 -07001841 return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
Yann Colletcf05b9d2016-07-18 16:52:10 +02001842}
1843
1844size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
1845{
Yann Colletfa3671e2017-05-19 10:51:30 -07001846 size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02001847 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07001848 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
Yann Colletbf42c8e2016-01-09 01:08:23 +01001849}
1850
Yann Collet16a0b102017-03-24 12:46:46 -07001851/*! ZSTD_loadDictionaryContent() :
1852 * @return : 0, or an error code
1853 */
Yann Colletb923f652016-01-26 03:14:20 +01001854static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01001855{
1856 const BYTE* const ip = (const BYTE*) src;
1857 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001858
Yann Collet417890c2015-12-04 17:16:37 +01001859 /* input becomes current prefix */
1860 zc->lowLimit = zc->dictLimit;
1861 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
1862 zc->dictBase = zc->base;
1863 zc->base += ip - zc->nextSrc;
1864 zc->nextToUpdate = zc->dictLimit;
Stella Laub6cb2ed2017-08-18 11:43:31 -07001865 zc->loadedDictEnd = zc->appliedParams.forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01001866
1867 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02001868 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01001869
Yann Collet1ad7c822017-05-22 17:06:04 -07001870 switch(zc->appliedParams.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01001871 {
1872 case ZSTD_fast:
Yann Collet1ad7c822017-05-22 17:06:04 -07001873 ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01001874 break;
Yann Collet45dc3562016-07-12 09:47:31 +02001875 case ZSTD_dfast:
Yann Collet1ad7c822017-05-22 17:06:04 -07001876 ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet45dc3562016-07-12 09:47:31 +02001877 break;
1878
Yann Collet417890c2015-12-04 17:16:37 +01001879 case ZSTD_greedy:
1880 case ZSTD_lazy:
1881 case ZSTD_lazy2:
Yann Collet16a0b102017-03-24 12:46:46 -07001882 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07001883 ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01001884 break;
1885
1886 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01001887 case ZSTD_btopt:
Nick Terrelleeb31ee2017-03-09 11:44:25 -08001888 case ZSTD_btultra:
Yann Collet16a0b102017-03-24 12:46:46 -07001889 if (srcSize >= HASH_READ_SIZE)
Nick Terrellc233bdb2017-09-22 14:04:39 -07001890 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, (U32)1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01001891 break;
1892
1893 default:
Yann Colletcd2892f2017-06-01 09:44:54 -07001894 assert(0); /* not possible : not a valid strategy id */
Yann Collet417890c2015-12-04 17:16:37 +01001895 }
1896
Nick Terrellecf90ca2017-02-13 18:27:34 -08001897 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01001898 return 0;
1899}
1900
1901
Nick Terrellf9c9af32016-10-19 17:22:08 -07001902/* Dictionaries that assign zero probability to symbols that show up causes problems
1903 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
1904 that we may encounter during compression.
1905 NOTE: This behavior is not standard and could be improved in the future. */
1906static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
1907 U32 s;
1908 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
1909 for (s = 0; s <= maxSymbolValue; ++s) {
1910 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
1911 }
1912 return 0;
1913}
1914
1915
Yann Colletb923f652016-01-26 03:14:20 +01001916/* Dictionary format :
Yann Colletbea78e82017-03-22 18:09:11 -07001917 * See :
1918 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
1919 */
Yann Collet16a0b102017-03-24 12:46:46 -07001920/*! ZSTD_loadZstdDictionary() :
1921 * @return : 0, or an error code
1922 * assumptions : magic number supposed already checked
1923 * dictSize supposed > 8
Yann Colletbea78e82017-03-22 18:09:11 -07001924 */
Yann Collet16a0b102017-03-24 12:46:46 -07001925static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01001926{
Yann Collet52a06222016-06-15 13:53:34 +02001927 const BYTE* dictPtr = (const BYTE*)dict;
1928 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07001929 short offcodeNCount[MaxOff+1];
1930 unsigned offcodeMaxValue = MaxOff;
Nick Terrellde0414b2017-07-12 19:08:24 -07001931
1932 ZSTD_STATIC_ASSERT(sizeof(cctx->entropy->workspace) >= (1<<MAX(MLFSELog,LLFSELog)));
Yann Colletfb810d62016-01-28 00:18:06 +01001933
Yann Colletbea78e82017-03-22 18:09:11 -07001934 dictPtr += 4; /* skip magic number */
Yann Collet1ad7c822017-05-22 17:06:04 -07001935 cctx->dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
Yann Colletbea78e82017-03-22 18:09:11 -07001936 dictPtr += 4;
1937
Nick Terrella86a7092017-10-03 13:22:13 -07001938 { unsigned maxSymbolValue = 255;
1939 size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)cctx->entropy->hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001940 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrella86a7092017-10-03 13:22:13 -07001941 if (maxSymbolValue < 255) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02001942 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001943 }
Yann Colletfb810d62016-01-28 00:18:06 +01001944
Nick Terrellf9c9af32016-10-19 17:22:08 -07001945 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02001946 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001947 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07001948 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07001949 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Nick Terrellde0414b2017-07-12 19:08:24 -07001950 CHECK_E( FSE_buildCTable_wksp(cctx->entropy->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
Yann Colletc17e0202017-04-20 12:50:02 -07001951 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02001952 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001953 }
Yann Colletfb810d62016-01-28 00:18:06 +01001954
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001955 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07001956 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02001957 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001958 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07001959 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07001960 /* Every match length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07001961 CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
Nick Terrellde0414b2017-07-12 19:08:24 -07001962 CHECK_E( FSE_buildCTable_wksp(cctx->entropy->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
Yann Colletc17e0202017-04-20 12:50:02 -07001963 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02001964 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001965 }
Yann Colletfb810d62016-01-28 00:18:06 +01001966
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001967 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07001968 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02001969 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001970 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07001971 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07001972 /* Every literal length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07001973 CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
Nick Terrellde0414b2017-07-12 19:08:24 -07001974 CHECK_E( FSE_buildCTable_wksp(cctx->entropy->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
Yann Colletc17e0202017-04-20 12:50:02 -07001975 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02001976 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001977 }
Yann Colletfb810d62016-01-28 00:18:06 +01001978
Yann Collet52a06222016-06-15 13:53:34 +02001979 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Nick Terrelle1982302017-07-17 12:27:24 -07001980 cctx->seqStore.rep[0] = MEM_readLE32(dictPtr+0);
1981 cctx->seqStore.rep[1] = MEM_readLE32(dictPtr+4);
1982 cctx->seqStore.rep[2] = MEM_readLE32(dictPtr+8);
Yann Collet52a06222016-06-15 13:53:34 +02001983 dictPtr += 12;
1984
Yann Colletbea78e82017-03-22 18:09:11 -07001985 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
1986 U32 offcodeMax = MaxOff;
1987 if (dictContentSize <= ((U32)-1) - 128 KB) {
1988 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
1989 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
Nick Terrellb2c39a22016-10-24 14:11:27 -07001990 }
Yann Colletbea78e82017-03-22 18:09:11 -07001991 /* All offset values <= dictContentSize + 128 KB must be representable */
Nick Terrellf9c9af32016-10-19 17:22:08 -07001992 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
Yann Colletbea78e82017-03-22 18:09:11 -07001993 /* All repCodes must be <= dictContentSize and != 0*/
1994 { U32 u;
1995 for (u=0; u<3; u++) {
Nick Terrelle1982302017-07-17 12:27:24 -07001996 if (cctx->seqStore.rep[u] == 0) return ERROR(dictionary_corrupted);
1997 if (cctx->seqStore.rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07001998 } }
Nick Terrellf9c9af32016-10-19 17:22:08 -07001999
Nick Terrellde0414b2017-07-12 19:08:24 -07002000 cctx->entropy->hufCTable_repeatMode = HUF_repeat_valid;
Nick Terrell830ef412017-07-13 12:45:39 -07002001 cctx->entropy->offcode_repeatMode = FSE_repeat_valid;
2002 cctx->entropy->matchlength_repeatMode = FSE_repeat_valid;
2003 cctx->entropy->litlength_repeatMode = FSE_repeat_valid;
Yann Collet16a0b102017-03-24 12:46:46 -07002004 return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
2005 }
Yann Colletb923f652016-01-26 03:14:20 +01002006}
2007
Yann Colletd1b26842016-03-15 01:24:33 +01002008/** ZSTD_compress_insertDictionary() :
2009* @return : 0, or an error code */
Yann Collet7bd1a292017-06-21 11:50:33 -07002010static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
2011 const void* dict, size_t dictSize,
2012 ZSTD_dictMode_e dictMode)
Yann Colletb923f652016-01-26 03:14:20 +01002013{
Yann Collet204b6b72017-06-21 15:13:00 -07002014 DEBUGLOG(5, "ZSTD_compress_insertDictionary");
Yann Colletc46fb922016-05-29 05:01:04 +02002015 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002016
Yann Collet7bd1a292017-06-21 11:50:33 -07002017 /* dict restricted modes */
2018 if (dictMode==ZSTD_dm_rawContent)
Yann Collet16a0b102017-03-24 12:46:46 -07002019 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002020
Yann Collet7d381612017-06-27 13:50:34 -07002021 if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
Yann Collet204b6b72017-06-21 15:13:00 -07002022 if (dictMode == ZSTD_dm_auto) {
2023 DEBUGLOG(5, "raw content dictionary detected");
Yann Collet7bd1a292017-06-21 11:50:33 -07002024 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Collet204b6b72017-06-21 15:13:00 -07002025 }
Yann Collet7bd1a292017-06-21 11:50:33 -07002026 if (dictMode == ZSTD_dm_fullDict)
2027 return ERROR(dictionary_wrong);
2028 assert(0); /* impossible */
2029 }
2030
2031 /* dict as full zstd dictionary */
Yann Collet16a0b102017-03-24 12:46:46 -07002032 return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002033}
2034
Yann Collet27caf2a2016-04-01 15:48:48 +02002035/*! ZSTD_compressBegin_internal() :
Yann Colletc3bce242017-06-20 16:09:11 -07002036 * @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002037static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002038 const void* dict, size_t dictSize,
Yann Collet7bd1a292017-06-21 11:50:33 -07002039 ZSTD_dictMode_e dictMode,
Yann Collet18803372017-05-22 18:21:51 -07002040 const ZSTD_CDict* cdict,
Stella Lau97e27af2017-08-18 11:20:08 -07002041 ZSTD_CCtx_params params, U64 pledgedSrcSize,
Yann Collet5ac72b42017-05-23 11:18:24 -07002042 ZSTD_buffered_policy_e zbuff)
Yann Colletf3eca252015-10-22 15:31:46 +01002043{
Yann Colleta3d99262017-06-29 14:44:49 -07002044 DEBUGLOG(4, "ZSTD_compressBegin_internal");
Yann Collet5ac72b42017-05-23 11:18:24 -07002045 /* params are supposed to be fully validated at this point */
Yann Colletab9162e2017-04-11 10:46:20 -07002046 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet18803372017-05-22 18:21:51 -07002047 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
2048
Yann Collet204b6b72017-06-21 15:13:00 -07002049 if (cdict && cdict->dictContentSize>0) {
Yann Collet5ac72b42017-05-23 11:18:24 -07002050 return ZSTD_copyCCtx_internal(cctx, cdict->refContext,
Yann Collet204b6b72017-06-21 15:13:00 -07002051 params.fParams, pledgedSrcSize,
2052 zbuff);
2053 }
Yann Collet18803372017-05-22 18:21:51 -07002054
Yann Collet204b6b72017-06-21 15:13:00 -07002055 CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
2056 ZSTDcrp_continue, zbuff) );
Yann Collet7bd1a292017-06-21 11:50:33 -07002057 return ZSTD_compress_insertDictionary(cctx, dict, dictSize, dictMode);
Yann Collet88fcd292015-11-25 14:42:45 +01002058}
2059
Stella Lau23fc0e42017-08-22 14:24:47 -07002060size_t ZSTD_compressBegin_advanced_internal(
Stella Lau023b24e2017-08-20 22:55:07 -07002061 ZSTD_CCtx* cctx,
Stella Lau63b8c982017-08-18 16:17:24 -07002062 const void* dict, size_t dictSize,
Stella Lauc7a18b72017-08-29 15:10:42 -07002063 ZSTD_dictMode_e dictMode,
Stella Lau63b8c982017-08-18 16:17:24 -07002064 ZSTD_CCtx_params params,
2065 unsigned long long pledgedSrcSize)
2066{
2067 /* compression parameters verification and optimization */
2068 CHECK_F( ZSTD_checkCParams(params.cParams) );
Stella Lauc7a18b72017-08-29 15:10:42 -07002069 return ZSTD_compressBegin_internal(cctx, dict, dictSize, dictMode, NULL,
Stella Lau63b8c982017-08-18 16:17:24 -07002070 params, pledgedSrcSize,
2071 ZSTDb_not_buffered);
2072}
Yann Collet88fcd292015-11-25 14:42:45 +01002073
Yann Collet27caf2a2016-04-01 15:48:48 +02002074/*! ZSTD_compressBegin_advanced() :
2075* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002076size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002077 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002078 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002079{
Stella Lau90a31bf2017-08-30 14:36:54 -07002080 ZSTD_CCtx_params const cctxParams =
Stella Lau11303772017-08-22 14:53:13 -07002081 ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
Stella Lauc7a18b72017-08-29 15:10:42 -07002082 return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, ZSTD_dm_auto,
2083 cctxParams,
Stella Lau23fc0e42017-08-22 14:24:47 -07002084 pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002085}
2086
Yann Collet81e13ef2016-06-07 00:51:51 +02002087size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002088{
Yann Collet6c6e1752016-06-27 15:28:45 +02002089 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Stella Lau90a31bf2017-08-30 14:36:54 -07002090 ZSTD_CCtx_params const cctxParams =
Stella Lau64ce4942017-08-23 12:30:47 -07002091 ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
Yann Collet7bd1a292017-06-21 11:50:33 -07002092 return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
Stella Lau64ce4942017-08-23 12:30:47 -07002093 cctxParams, 0, ZSTDb_not_buffered);
Yann Collet1c8e1942016-01-26 16:31:22 +01002094}
Yann Collet083fcc82015-10-25 14:06:35 +01002095
Yann Colletb05c4822017-01-12 02:01:28 +01002096size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002097{
Yann Colletb05c4822017-01-12 02:01:28 +01002098 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002099}
2100
2101
Yann Collet62470b42016-07-28 15:29:08 +02002102/*! ZSTD_writeEpilogue() :
2103* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002104* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002105static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002106{
Yann Colletc991cc12016-07-28 00:55:43 +02002107 BYTE* const ostart = (BYTE*)dst;
2108 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002109 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002110
Yann Collet009d6042017-05-19 10:17:59 -07002111 DEBUGLOG(5, "ZSTD_writeEpilogue");
Yann Collet87c18b22016-08-26 01:43:47 +02002112 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002113
2114 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002115 if (cctx->stage == ZSTDcs_init) {
Yann Collet1ad7c822017-05-22 17:06:04 -07002116 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002117 if (ZSTD_isError(fhSize)) return fhSize;
2118 dstCapacity -= fhSize;
2119 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002120 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002121 }
2122
Yann Colletc991cc12016-07-28 00:55:43 +02002123 if (cctx->stage != ZSTDcs_ending) {
2124 /* write one last empty block, make it the "last" block */
2125 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2126 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2127 MEM_writeLE32(op, cBlockHeader24);
2128 op += ZSTD_blockHeaderSize;
2129 dstCapacity -= ZSTD_blockHeaderSize;
2130 }
2131
Yann Collet1ad7c822017-05-22 17:06:04 -07002132 if (cctx->appliedParams.fParams.checksumFlag) {
Yann Colletc991cc12016-07-28 00:55:43 +02002133 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2134 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2135 MEM_writeLE32(op, checksum);
2136 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002137 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002138
Yann Collet731ef162016-07-27 21:05:12 +02002139 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002140 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002141}
2142
Yann Colletfd416f12016-01-30 03:14:15 +01002143
Yann Collet62470b42016-07-28 15:29:08 +02002144size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2145 void* dst, size_t dstCapacity,
2146 const void* src, size_t srcSize)
2147{
2148 size_t endResult;
Yann Collet009d6042017-05-19 10:17:59 -07002149 size_t const cSize = ZSTD_compressContinue_internal(cctx,
2150 dst, dstCapacity, src, srcSize,
2151 1 /* frame mode */, 1 /* last chunk */);
Yann Collet62470b42016-07-28 15:29:08 +02002152 if (ZSTD_isError(cSize)) return cSize;
2153 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2154 if (ZSTD_isError(endResult)) return endResult;
Yann Collet1ad7c822017-05-22 17:06:04 -07002155 if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
Yann Colletfbd5ab72017-09-29 19:40:27 -07002156 DEBUGLOG(4, "end of frame : controlling src size");
Yann Colleta0ba8492017-06-16 13:29:17 -07002157 if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) {
Yann Colletfbd5ab72017-09-29 19:40:27 -07002158 DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize = %u",
Yann Colletaee916e2017-06-16 17:01:46 -07002159 (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize);
Yann Collet0be6fd32017-05-08 16:08:01 -07002160 return ERROR(srcSize_wrong);
Yann Collet9e73f2f2017-06-16 12:24:01 -07002161 } }
Yann Collet62470b42016-07-28 15:29:08 +02002162 return cSize + endResult;
2163}
2164
2165
Yann Collet19c10022016-07-28 01:25:46 +02002166static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002167 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002168 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002169 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002170 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002171{
Stella Lau90a31bf2017-08-30 14:36:54 -07002172 ZSTD_CCtx_params const cctxParams =
Stella Lau11303772017-08-22 14:53:13 -07002173 ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
Stella Lau23fc0e42017-08-22 14:24:47 -07002174 return ZSTD_compress_advanced_internal(cctx,
2175 dst, dstCapacity,
2176 src, srcSize,
2177 dict, dictSize,
2178 cctxParams);
Yann Colletf3eca252015-10-22 15:31:46 +01002179}
2180
Yann Collet21588e32016-03-30 16:50:44 +02002181size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2182 void* dst, size_t dstCapacity,
2183 const void* src, size_t srcSize,
2184 const void* dict,size_t dictSize,
2185 ZSTD_parameters params)
2186{
Yann Colletcf409a72016-09-26 16:41:05 +02002187 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02002188 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2189}
2190
Stella Lau63b8c982017-08-18 16:17:24 -07002191/* Internal */
Stella Lau23fc0e42017-08-22 14:24:47 -07002192size_t ZSTD_compress_advanced_internal(
Stella Lau023b24e2017-08-20 22:55:07 -07002193 ZSTD_CCtx* cctx,
2194 void* dst, size_t dstCapacity,
2195 const void* src, size_t srcSize,
2196 const void* dict,size_t dictSize,
2197 ZSTD_CCtx_params params)
Stella Lau63b8c982017-08-18 16:17:24 -07002198{
Stella Lauc7a18b72017-08-29 15:10:42 -07002199 CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
Stella Lau63b8c982017-08-18 16:17:24 -07002200 params, srcSize, ZSTDb_not_buffered) );
2201 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
2202}
2203
Yann Colletc17e0202017-04-20 12:50:02 -07002204size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
2205 const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01002206{
Yann Collet407a11f2016-11-03 15:52:01 -07002207 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02002208 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002209 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002210}
2211
Yann Colletd1b26842016-03-15 01:24:33 +01002212size_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 +01002213{
Yann Collet21588e32016-03-30 16:50:44 +02002214 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002215}
2216
Yann Colletd1b26842016-03-15 01:24:33 +01002217size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002218{
Yann Collet44fe9912015-10-29 22:02:40 +01002219 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002220 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002221 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Colletae728a42017-05-30 17:11:39 -07002222 ctxBody.customMem = ZSTD_defaultCMem;
Yann Colletd1b26842016-03-15 01:24:33 +01002223 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Colletae728a42017-05-30 17:11:39 -07002224 ZSTD_free(ctxBody.workSpace, ZSTD_defaultCMem); /* can't free ctxBody itself, as it's on stack; free only heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002225 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002226}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002227
Yann Colletfd416f12016-01-30 03:14:15 +01002228
Yann Collet81e13ef2016-06-07 00:51:51 +02002229/* ===== Dictionary API ===== */
2230
Yann Collet09ae03a2017-06-26 16:47:32 -07002231/*! ZSTD_estimateCDictSize_advanced() :
Yann Colleta1d67042017-05-08 17:51:49 -07002232 * Estimate amount of memory that will be needed to create a dictionary with following arguments */
Stella Lauc88fb922017-08-29 11:55:02 -07002233size_t ZSTD_estimateCDictSize_advanced(
2234 size_t dictSize, ZSTD_compressionParameters cParams,
2235 ZSTD_dictLoadMethod_e dictLoadMethod)
Yann Colleta1d67042017-05-08 17:51:49 -07002236{
Yann Collet7bd1a292017-06-21 11:50:33 -07002237 DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict));
Stella Laub5b92752017-08-29 10:49:29 -07002238 DEBUGLOG(5, "CCtx estimate : %u",
Yann Collet96f0cde2017-09-24 16:47:02 -07002239 (U32)ZSTD_estimateCCtxSize_usingCParams(cParams));
2240 return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_usingCParams(cParams)
Stella Lauc88fb922017-08-29 11:55:02 -07002241 + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
Yann Colleta1d67042017-05-08 17:51:49 -07002242}
2243
Yann Collet09ae03a2017-06-26 16:47:32 -07002244size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
2245{
2246 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
Stella Lauee657012017-08-29 20:27:35 -07002247 return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
Yann Collet09ae03a2017-06-26 16:47:32 -07002248}
2249
Yann Colletd7c65892016-09-15 02:50:27 +02002250size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2251{
2252 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Collet7bd1a292017-06-21 11:50:33 -07002253 DEBUGLOG(5, "sizeof(*cdict) : %u", (U32)sizeof(*cdict));
2254 DEBUGLOG(5, "ZSTD_sizeof_CCtx : %u", (U32)ZSTD_sizeof_CCtx(cdict->refContext));
Yann Colletaca113f2016-12-23 22:25:03 +01002255 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02002256}
2257
Yann Colletcdf7e822017-05-25 18:05:49 -07002258static size_t ZSTD_initCDict_internal(
2259 ZSTD_CDict* cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07002260 const void* dictBuffer, size_t dictSize,
Stella Lauc88fb922017-08-29 11:55:02 -07002261 ZSTD_dictLoadMethod_e dictLoadMethod,
2262 ZSTD_dictMode_e dictMode,
Yann Colletcdf7e822017-05-25 18:05:49 -07002263 ZSTD_compressionParameters cParams)
2264{
Yann Collet204b6b72017-06-21 15:13:00 -07002265 DEBUGLOG(5, "ZSTD_initCDict_internal, mode %u", (U32)dictMode);
Stella Lauc88fb922017-08-29 11:55:02 -07002266 if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
Yann Colletcdf7e822017-05-25 18:05:49 -07002267 cdict->dictBuffer = NULL;
2268 cdict->dictContent = dictBuffer;
2269 } else {
2270 void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem);
Yann Colletcdf7e822017-05-25 18:05:49 -07002271 cdict->dictBuffer = internalBuffer;
2272 cdict->dictContent = internalBuffer;
Yann Colletc3bce242017-06-20 16:09:11 -07002273 if (!internalBuffer) return ERROR(memory_allocation);
2274 memcpy(internalBuffer, dictBuffer, dictSize);
Yann Colletcdf7e822017-05-25 18:05:49 -07002275 }
2276 cdict->dictContentSize = dictSize;
2277
Stella Lau90a31bf2017-08-30 14:36:54 -07002278 { ZSTD_CCtx_params cctxParams = cdict->refContext->requestedParams;
Stella Lau5b956f42017-08-21 14:49:16 -07002279 cctxParams.cParams = cParams;
Yann Collet7bd1a292017-06-21 11:50:33 -07002280 CHECK_F( ZSTD_compressBegin_internal(cdict->refContext,
2281 cdict->dictContent, dictSize, dictMode,
2282 NULL,
Stella Lau5b956f42017-08-21 14:49:16 -07002283 cctxParams, ZSTD_CONTENTSIZE_UNKNOWN,
Yann Collet7bd1a292017-06-21 11:50:33 -07002284 ZSTDb_not_buffered) );
Yann Colletcdf7e822017-05-25 18:05:49 -07002285 }
2286
2287 return 0;
2288}
2289
Yann Collet7bd1a292017-06-21 11:50:33 -07002290ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
Stella Lauc88fb922017-08-29 11:55:02 -07002291 ZSTD_dictLoadMethod_e dictLoadMethod,
2292 ZSTD_dictMode_e dictMode,
Yann Collet31533ba2017-04-27 00:29:04 -07002293 ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02002294{
Yann Collet204b6b72017-06-21 15:13:00 -07002295 DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode);
Yann Colletae728a42017-05-30 17:11:39 -07002296 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02002297
Yann Collet466f92e2017-06-20 16:25:29 -07002298 { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002299 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2300
Yann Collet1f57c2e2016-12-21 16:20:11 +01002301 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07002302 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002303 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002304 return NULL;
2305 }
Yann Colletcdf7e822017-05-25 18:05:49 -07002306 cdict->refContext = cctx;
Yann Colletcdf7e822017-05-25 18:05:49 -07002307 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07002308 dictBuffer, dictSize,
Stella Lauc88fb922017-08-29 11:55:02 -07002309 dictLoadMethod, dictMode,
Yann Colletcdf7e822017-05-25 18:05:49 -07002310 cParams) )) {
2311 ZSTD_freeCDict(cdict);
2312 return NULL;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002313 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002314
Yann Collet81e13ef2016-06-07 00:51:51 +02002315 return cdict;
2316 }
2317}
2318
2319ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2320{
Yann Collet31533ba2017-04-27 00:29:04 -07002321 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
Yann Collet7bd1a292017-06-21 11:50:33 -07002322 return ZSTD_createCDict_advanced(dict, dictSize,
Stella Lauc88fb922017-08-29 11:55:02 -07002323 ZSTD_dlm_byCopy, ZSTD_dm_auto,
Yann Collet7bd1a292017-06-21 11:50:33 -07002324 cParams, ZSTD_defaultCMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01002325}
2326
2327ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
2328{
Yann Collet31533ba2017-04-27 00:29:04 -07002329 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
Yann Collet7bd1a292017-06-21 11:50:33 -07002330 return ZSTD_createCDict_advanced(dict, dictSize,
Stella Lauc88fb922017-08-29 11:55:02 -07002331 ZSTD_dlm_byRef, ZSTD_dm_auto,
Yann Collet7bd1a292017-06-21 11:50:33 -07002332 cParams, ZSTD_defaultCMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002333}
2334
2335size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2336{
Yann Collet23b6e052016-08-28 21:05:43 -07002337 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02002338 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07002339 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01002340 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002341 ZSTD_free(cdict, cMem);
2342 return 0;
2343 }
Yann Collet81e13ef2016-06-07 00:51:51 +02002344}
2345
Yann Colletcdf7e822017-05-25 18:05:49 -07002346/*! ZSTD_initStaticCDict_advanced() :
2347 * Generate a digested dictionary in provided memory area.
2348 * workspace: The memory area to emplace the dictionary into.
2349 * Provided pointer must 8-bytes aligned.
2350 * It must outlive dictionary usage.
2351 * workspaceSize: Use ZSTD_estimateCDictSize()
2352 * to determine how large workspace must be.
2353 * cParams : use ZSTD_getCParams() to transform a compression level
2354 * into its relevants cParams.
2355 * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
2356 * Note : there is no corresponding "free" function.
2357 * Since workspace was allocated externally, it must be freed externally.
2358 */
2359ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
Yann Collet7bd1a292017-06-21 11:50:33 -07002360 const void* dict, size_t dictSize,
Stella Lauc88fb922017-08-29 11:55:02 -07002361 ZSTD_dictLoadMethod_e dictLoadMethod,
2362 ZSTD_dictMode_e dictMode,
Yann Colletcdf7e822017-05-25 18:05:49 -07002363 ZSTD_compressionParameters cParams)
2364{
Yann Collet96f0cde2017-09-24 16:47:02 -07002365 size_t const cctxSize = ZSTD_estimateCCtxSize_usingCParams(cParams);
Stella Lauc88fb922017-08-29 11:55:02 -07002366 size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize)
Yann Colletcdf7e822017-05-25 18:05:49 -07002367 + cctxSize;
2368 ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
2369 void* ptr;
Yann Collet2cf77552017-06-16 12:34:41 -07002370 DEBUGLOG(5, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7);
Yann Colletcdf7e822017-05-25 18:05:49 -07002371 if ((size_t)workspace & 7) return NULL; /* 8-aligned */
Yann Collet2cf77552017-06-16 12:34:41 -07002372 DEBUGLOG(5, "(workspaceSize < neededSize) : (%u < %u) => %u",
Yann Colletcdf7e822017-05-25 18:05:49 -07002373 (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
2374 if (workspaceSize < neededSize) return NULL;
2375
Stella Lauc88fb922017-08-29 11:55:02 -07002376 if (dictLoadMethod == ZSTD_dlm_byCopy) {
Yann Colletcdf7e822017-05-25 18:05:49 -07002377 memcpy(cdict+1, dict, dictSize);
2378 dict = cdict+1;
2379 ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize;
2380 } else {
2381 ptr = cdict+1;
2382 }
2383 cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize);
2384
2385 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07002386 dict, dictSize,
Stella Lauc88fb922017-08-29 11:55:02 -07002387 ZSTD_dlm_byRef, dictMode,
Yann Collet7bd1a292017-06-21 11:50:33 -07002388 cParams) ))
Yann Colletcdf7e822017-05-25 18:05:49 -07002389 return NULL;
2390
2391 return cdict;
2392}
2393
Stella Lau024098a2017-08-25 17:58:28 -07002394ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) {
2395 return cdict->refContext->appliedParams.cParams;
Yann Collet95162342016-10-25 16:19:52 -07002396}
2397
Yann Collet715b9aa2017-04-18 13:55:53 -07002398/* ZSTD_compressBegin_usingCDict_advanced() :
Yann Collet4f818182017-04-17 17:57:35 -07002399 * cdict must be != NULL */
Yann Collet715b9aa2017-04-18 13:55:53 -07002400size_t ZSTD_compressBegin_usingCDict_advanced(
Yann Collet4f818182017-04-17 17:57:35 -07002401 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
2402 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002403{
Yann Collet5ac72b42017-05-23 11:18:24 -07002404 if (cdict==NULL) return ERROR(dictionary_wrong);
Stella Lau024098a2017-08-25 17:58:28 -07002405 { ZSTD_CCtx_params params = cctx->requestedParams;
2406 params.cParams = ZSTD_getCParamsFromCDict(cdict);
Yann Collet4f818182017-04-17 17:57:35 -07002407 params.fParams = fParams;
Yann Collet18803372017-05-22 18:21:51 -07002408 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced");
Yann Collet7bd1a292017-06-21 11:50:33 -07002409 return ZSTD_compressBegin_internal(cctx,
2410 NULL, 0, ZSTD_dm_auto,
2411 cdict,
2412 params, pledgedSrcSize,
2413 ZSTDb_not_buffered);
Sean Purcell2db72492017-02-09 10:50:43 -08002414 }
Yann Collet4cb21292016-09-15 14:54:07 +02002415}
2416
Yann Collet4f818182017-04-17 17:57:35 -07002417/* ZSTD_compressBegin_usingCDict() :
2418 * pledgedSrcSize=0 means "unknown"
2419 * if pledgedSrcSize>0, it will enable contentSizeFlag */
Yann Collet768df122017-04-26 15:42:10 -07002420size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Collet4f818182017-04-17 17:57:35 -07002421{
Yann Collet768df122017-04-26 15:42:10 -07002422 ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet009d6042017-05-19 10:17:59 -07002423 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
Yann Collet768df122017-04-26 15:42:10 -07002424 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
Yann Collet4f818182017-04-17 17:57:35 -07002425}
2426
Yann Colletf4bd8572017-04-27 11:31:55 -07002427size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
2428 void* dst, size_t dstCapacity,
2429 const void* src, size_t srcSize,
2430 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
2431{
2432 CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
2433 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002434}
2435
Yann Collet07639052016-08-03 01:57:57 +02002436/*! ZSTD_compress_usingCDict() :
Yann Collet4f818182017-04-17 17:57:35 -07002437 * Compression using a digested Dictionary.
2438 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2439 * Note that compression parameters are decided at CDict creation time
2440 * while frame parameters are hardcoded */
Yann Collet4cb21292016-09-15 14:54:07 +02002441size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2442 void* dst, size_t dstCapacity,
2443 const void* src, size_t srcSize,
2444 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02002445{
Yann Collet4f818182017-04-17 17:57:35 -07002446 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Colletf4bd8572017-04-27 11:31:55 -07002447 return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
Yann Collet81e13ef2016-06-07 00:51:51 +02002448}
2449
2450
2451
Yann Collet104e5b02016-08-12 13:04:27 +02002452/* ******************************************************************
2453* Streaming
2454********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002455
Yann Collet5a0c8e22016-08-12 01:20:36 +02002456ZSTD_CStream* ZSTD_createCStream(void)
2457{
Yann Colletae728a42017-05-30 17:11:39 -07002458 return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002459}
2460
Yann Colletdde10b22017-06-26 17:44:26 -07002461ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize)
2462{
2463 return ZSTD_initStaticCCtx(workspace, workspaceSize);
2464}
2465
Yann Collet5a0c8e22016-08-12 01:20:36 +02002466ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
Yann Colletae728a42017-05-30 17:11:39 -07002467{ /* CStream and CCtx are now same object */
Yann Collet6fb2f242017-05-10 11:06:06 -07002468 return ZSTD_createCCtx_advanced(customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002469}
2470
2471size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2472{
Yann Collet78553662017-05-08 17:15:00 -07002473 return ZSTD_freeCCtx(zcs); /* same object */
Yann Collet5a0c8e22016-08-12 01:20:36 +02002474}
2475
Yann Collet5a0c8e22016-08-12 01:20:36 +02002476
2477
Yann Collet104e5b02016-08-12 13:04:27 +02002478/*====== Initialization ======*/
2479
Yann Colletfa3671e2017-05-19 10:51:30 -07002480size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002481
Yann Colletc17e0202017-04-20 12:50:02 -07002482size_t ZSTD_CStreamOutSize(void)
2483{
Yann Colletfa3671e2017-05-19 10:51:30 -07002484 return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
Yann Colletc17e0202017-04-20 12:50:02 -07002485}
Yann Collet5a0c8e22016-08-12 01:20:36 +02002486
Yann Collet1ad7c822017-05-22 17:06:04 -07002487static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
Yann Collet2e427422017-06-27 17:09:12 -07002488 const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode,
2489 const ZSTD_CDict* cdict,
Stella Lauee657012017-08-29 20:27:35 -07002490 const ZSTD_CCtx_params params, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002491{
Yann Colleta3d99262017-06-29 14:44:49 -07002492 DEBUGLOG(4, "ZSTD_resetCStream_internal");
Yann Colletb7372932017-06-27 15:49:12 -07002493 /* params are supposed to be fully validated at this point */
2494 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
2495 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
Yann Colletee5b7252016-10-27 14:20:55 -07002496
Yann Collet7bd1a292017-06-21 11:50:33 -07002497 CHECK_F( ZSTD_compressBegin_internal(zcs,
Yann Collet2e427422017-06-27 17:09:12 -07002498 dict, dictSize, dictMode,
Yann Colletb7372932017-06-27 15:49:12 -07002499 cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07002500 params, pledgedSrcSize,
2501 ZSTDb_buffered) );
Yann Collet4cb21292016-09-15 14:54:07 +02002502
2503 zcs->inToCompress = 0;
2504 zcs->inBuffPos = 0;
2505 zcs->inBuffTarget = zcs->blockSize;
2506 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07002507 zcs->streamStage = zcss_load;
Yann Collet4cb21292016-09-15 14:54:07 +02002508 zcs->frameEnded = 0;
2509 return 0; /* ready to go */
2510}
2511
Sean Purcell2db72492017-02-09 10:50:43 -08002512size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
2513{
Stella Laud7755192017-08-18 17:37:58 -07002514 ZSTD_CCtx_params params = zcs->requestedParams;
Yann Collet0be6fd32017-05-08 16:08:01 -07002515 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
Stella Lau0e56a842017-08-28 19:25:17 -07002516 params.cParams = ZSTD_getCParamsFromCCtxParams(params, pledgedSrcSize, 0);
Yann Colletdb1668a2017-09-29 18:05:18 -07002517 DEBUGLOG(4, "ZSTD_resetCStream");
Stella Lauc7a18b72017-08-29 15:10:42 -07002518 return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize);
Sean Purcell2db72492017-02-09 10:50:43 -08002519}
Sean Purcell2db72492017-02-09 10:50:43 -08002520
Yann Collet204b6b72017-06-21 15:13:00 -07002521/*! ZSTD_initCStream_internal() :
Yann Colletb7372932017-06-27 15:49:12 -07002522 * Note : not static, but hidden (not exposed). Used by zstdmt_compress.c
Yann Collet204b6b72017-06-21 15:13:00 -07002523 * Assumption 1 : params are valid
2524 * Assumption 2 : either dict, or cdict, is defined, not both */
Yann Collet8c910d22017-06-03 01:15:02 -07002525size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
2526 const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
Stella Lauee657012017-08-29 20:27:35 -07002527 ZSTD_CCtx_params params, unsigned long long pledgedSrcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02002528{
Yann Colletdb1668a2017-09-29 18:05:18 -07002529 DEBUGLOG(4, "ZSTD_initCStream_internal");
Yann Collet4b987ad2017-04-10 17:50:44 -07002530 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet8c910d22017-06-03 01:15:02 -07002531 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
Yann Collete88034f2017-04-10 22:24:02 -07002532
Yann Collete88034f2017-04-10 22:24:02 -07002533 if (dict && dictSize >= 8) {
Yann Collet204b6b72017-06-21 15:13:00 -07002534 DEBUGLOG(5, "loading dictionary of size %u", (U32)dictSize);
Yann Colletc7fe2622017-05-23 13:16:00 -07002535 if (zcs->staticSize) { /* static CCtx : never uses malloc */
2536 /* incompatible with internal cdict creation */
2537 return ERROR(memory_allocation);
Yann Collet02d37aa2017-04-05 14:53:51 -07002538 }
Yann Collete88034f2017-04-10 22:24:02 -07002539 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet7bd1a292017-06-21 11:50:33 -07002540 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
Stella Lauc7a18b72017-08-29 15:10:42 -07002541 ZSTD_dlm_byCopy, ZSTD_dm_auto,
Yann Collet204b6b72017-06-21 15:13:00 -07002542 params.cParams, zcs->customMem);
Yann Collete88034f2017-04-10 22:24:02 -07002543 zcs->cdict = zcs->cdictLocal;
Yann Collet466f92e2017-06-20 16:25:29 -07002544 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
Yann Collet8c910d22017-06-03 01:15:02 -07002545 } else {
2546 if (cdict) {
Stella Lau024098a2017-08-25 17:58:28 -07002547 params.cParams = ZSTD_getCParamsFromCDict(cdict); /* cParams are enforced from cdict */
Yann Collet8c910d22017-06-03 01:15:02 -07002548 }
Yann Collet466f92e2017-06-20 16:25:29 -07002549 ZSTD_freeCDict(zcs->cdictLocal);
2550 zcs->cdictLocal = NULL;
Yann Collet8c910d22017-06-03 01:15:02 -07002551 zcs->cdict = cdict;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002552 }
Sean Purcell57d423c2017-01-17 11:04:08 -08002553
Stella Lau64ce4942017-08-23 12:30:47 -07002554 params.compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collet8c910d22017-06-03 01:15:02 -07002555 zcs->requestedParams = params;
Stella Laub6cb2ed2017-08-18 11:43:31 -07002556
Stella Lauc7a18b72017-08-29 15:10:42 -07002557 return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dm_auto, zcs->cdict, params, pledgedSrcSize);
Yann Colletee5b7252016-10-27 14:20:55 -07002558}
2559
2560/* ZSTD_initCStream_usingCDict_advanced() :
Yann Collet5a0c8e22016-08-12 01:20:36 +02002561 * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
Yann Collet8c910d22017-06-03 01:15:02 -07002562size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
2563 const ZSTD_CDict* cdict,
2564 ZSTD_frameParameters fParams,
2565 unsigned long long pledgedSrcSize)
2566{ /* cannot handle NULL cdict (does not know what to do) */
2567 if (!cdict) return ERROR(dictionary_wrong);
Stella Lau024098a2017-08-25 17:58:28 -07002568 { ZSTD_CCtx_params params = zcs->requestedParams;
2569 params.cParams = ZSTD_getCParamsFromCDict(cdict);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002570 params.fParams = fParams;
Yann Collet8c910d22017-06-03 01:15:02 -07002571 return ZSTD_initCStream_internal(zcs,
2572 NULL, 0, cdict,
2573 params, pledgedSrcSize);
Yann Collete88034f2017-04-10 22:24:02 -07002574 }
2575}
2576
2577/* note : cdict must outlive compression session */
2578size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
2579{
Yann Collet8c910d22017-06-03 01:15:02 -07002580 ZSTD_frameParameters const fParams = { 0 /* contentSize */, 0 /* checksum */, 0 /* hideDictID */ };
2581 return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, 0); /* note : will check that cdict != NULL */
Yann Collet5a0c8e22016-08-12 01:20:36 +02002582}
2583
Yann Collet95162342016-10-25 16:19:52 -07002584size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
2585 const void* dict, size_t dictSize,
2586 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2587{
Stella Lau90a31bf2017-08-30 14:36:54 -07002588 ZSTD_CCtx_params const cctxParams =
Stella Lau11303772017-08-22 14:53:13 -07002589 ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
Yann Collet4b987ad2017-04-10 17:50:44 -07002590 CHECK_F( ZSTD_checkCParams(params.cParams) );
Stella Lau8fd16362017-08-21 18:10:44 -07002591 return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, pledgedSrcSize);
Yann Collet95162342016-10-25 16:19:52 -07002592}
2593
Yann Collet5a0c8e22016-08-12 01:20:36 +02002594size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
2595{
2596 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Stella Lau90a31bf2017-08-30 14:36:54 -07002597 ZSTD_CCtx_params const cctxParams =
Stella Lau11303772017-08-22 14:53:13 -07002598 ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
Stella Lau8fd16362017-08-21 18:10:44 -07002599 return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002600}
2601
Yann Collete795c8a2016-12-13 16:39:36 +01002602size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
2603{
Stella Lau64ce4942017-08-23 12:30:47 -07002604 ZSTD_CCtx_params cctxParams;
Stella Lau90a31bf2017-08-30 14:36:54 -07002605 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
Stella Lau64ce4942017-08-23 12:30:47 -07002606 cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
Stella Lau90a31bf2017-08-30 14:36:54 -07002607 cctxParams.fParams.contentSizeFlag = (pledgedSrcSize>0);
Stella Lau64ce4942017-08-23 12:30:47 -07002608 return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, pledgedSrcSize);
Yann Collete795c8a2016-12-13 16:39:36 +01002609}
2610
Yann Collet5a0c8e22016-08-12 01:20:36 +02002611size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
2612{
Stella Laud7755192017-08-18 17:37:58 -07002613 return ZSTD_initCStream_srcSize(zcs, compressionLevel, 0);
Yann Colletcb327632016-08-23 00:30:31 +02002614}
Yann Collet5a0c8e22016-08-12 01:20:36 +02002615
Yann Collet104e5b02016-08-12 13:04:27 +02002616/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002617
Yann Collet01b15492017-05-30 18:10:26 -07002618MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
2619 const void* src, size_t srcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02002620{
2621 size_t const length = MIN(dstCapacity, srcSize);
Yann Collet18ab5af2017-05-31 09:59:22 -07002622 if (length) memcpy(dst, src, length);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002623 return length;
2624}
2625
Yann Colleta3d99262017-06-29 14:44:49 -07002626/** ZSTD_compressStream_generic():
2627 * internal function for all *compressStream*() variants and *compress_generic()
Yann Collet6ee05a02017-09-25 15:41:48 -07002628 * non-static, because can be called from zstdmt.c
Yann Colleta3d99262017-06-29 14:44:49 -07002629 * @return : hint size for next input */
Yann Colletd5c046c2017-06-30 14:51:01 -07002630size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
2631 ZSTD_outBuffer* output,
2632 ZSTD_inBuffer* input,
2633 ZSTD_EndDirective const flushMode)
Yann Collet5a0c8e22016-08-12 01:20:36 +02002634{
Yann Collet01b15492017-05-30 18:10:26 -07002635 const char* const istart = (const char*)input->src;
2636 const char* const iend = istart + input->size;
2637 const char* ip = istart + input->pos;
2638 char* const ostart = (char*)output->dst;
2639 char* const oend = ostart + output->size;
2640 char* op = ostart + output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002641 U32 someMoreWork = 1;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002642
Yann Collet58e8d792017-06-02 18:20:48 -07002643 /* check expectations */
Yann Collet2cb97742017-07-04 12:39:26 -07002644 DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (U32)flushMode);
Yann Collet6d4fef32017-05-17 18:36:15 -07002645 assert(zcs->inBuff != NULL);
Yann Colletecb0f462017-06-21 17:25:01 -07002646 assert(zcs->inBuffSize>0);
Yann Collet6d4fef32017-05-17 18:36:15 -07002647 assert(zcs->outBuff!= NULL);
Yann Colletecb0f462017-06-21 17:25:01 -07002648 assert(zcs->outBuffSize>0);
Yann Collet58e8d792017-06-02 18:20:48 -07002649 assert(output->pos <= output->size);
2650 assert(input->pos <= input->size);
Yann Collet009d6042017-05-19 10:17:59 -07002651
Yann Collet5a0c8e22016-08-12 01:20:36 +02002652 while (someMoreWork) {
Yann Collet0be6fd32017-05-08 16:08:01 -07002653 switch(zcs->streamStage)
Yann Collet5a0c8e22016-08-12 01:20:36 +02002654 {
Yann Collet1ad7c822017-05-22 17:06:04 -07002655 case zcss_init:
2656 /* call ZSTD_initCStream() first ! */
2657 return ERROR(init_missing);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002658
2659 case zcss_load:
Yann Colleta3d99262017-06-29 14:44:49 -07002660 if ( (flushMode == ZSTD_e_end)
Yann Collet2084b042017-07-03 15:52:19 -07002661 && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */
Yann Colleta3d99262017-06-29 14:44:49 -07002662 && (zcs->inBuffPos == 0) ) {
2663 /* shortcut to compression pass directly into output buffer */
2664 size_t const cSize = ZSTD_compressEnd(zcs,
2665 op, oend-op, ip, iend-ip);
2666 DEBUGLOG(4, "ZSTD_compressEnd : %u", (U32)cSize);
2667 if (ZSTD_isError(cSize)) return cSize;
2668 ip = iend;
2669 op += cSize;
2670 zcs->frameEnded = 1;
2671 ZSTD_startNewCompression(zcs);
2672 someMoreWork = 0; break;
Yann Collet2084b042017-07-03 15:52:19 -07002673 }
2674 /* complete loading into inBuffer */
Yann Collet5a0c8e22016-08-12 01:20:36 +02002675 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
Yann Collet06589fe2017-05-31 10:03:20 -07002676 size_t const loaded = ZSTD_limitCopy(
2677 zcs->inBuff + zcs->inBuffPos, toLoad,
2678 ip, iend-ip);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002679 zcs->inBuffPos += loaded;
2680 ip += loaded;
Yann Collet009d6042017-05-19 10:17:59 -07002681 if ( (flushMode == ZSTD_e_continue)
2682 && (zcs->inBuffPos < zcs->inBuffTarget) ) {
2683 /* not enough input to fill full block : stop here */
2684 someMoreWork = 0; break;
2685 }
2686 if ( (flushMode == ZSTD_e_flush)
2687 && (zcs->inBuffPos == zcs->inToCompress) ) {
2688 /* empty */
2689 someMoreWork = 0; break;
Yann Collet559ee822017-06-16 11:58:21 -07002690 }
2691 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002692 /* compress current block (note : this stage cannot be stopped in the middle) */
Yann Collet009d6042017-05-19 10:17:59 -07002693 DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002694 { void* cDst;
2695 size_t cSize;
2696 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
2697 size_t oSize = oend-op;
Yann Collet009d6042017-05-19 10:17:59 -07002698 unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002699 if (oSize >= ZSTD_compressBound(iSize))
Yann Collet559ee822017-06-16 11:58:21 -07002700 cDst = op; /* compress into output buffer, to skip flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02002701 else
2702 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
Yann Collet009d6042017-05-19 10:17:59 -07002703 cSize = lastBlock ?
2704 ZSTD_compressEnd(zcs, cDst, oSize,
2705 zcs->inBuff + zcs->inToCompress, iSize) :
2706 ZSTD_compressContinue(zcs, cDst, oSize,
2707 zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002708 if (ZSTD_isError(cSize)) return cSize;
Yann Collet009d6042017-05-19 10:17:59 -07002709 zcs->frameEnded = lastBlock;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002710 /* prepare next block */
2711 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
2712 if (zcs->inBuffTarget > zcs->inBuffSize)
Yann Collet009d6042017-05-19 10:17:59 -07002713 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
Yann Collet8b21ec42017-05-19 19:46:15 -07002714 DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
2715 (U32)zcs->inBuffTarget, (U32)zcs->inBuffSize);
2716 if (!lastBlock)
2717 assert(zcs->inBuffTarget <= zcs->inBuffSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002718 zcs->inToCompress = zcs->inBuffPos;
Yann Collet009d6042017-05-19 10:17:59 -07002719 if (cDst == op) { /* no need to flush */
2720 op += cSize;
2721 if (zcs->frameEnded) {
Yann Collet559ee822017-06-16 11:58:21 -07002722 DEBUGLOG(5, "Frame completed directly in outBuffer");
Yann Collet009d6042017-05-19 10:17:59 -07002723 someMoreWork = 0;
Yann Colletb26728c2017-06-16 14:00:46 -07002724 ZSTD_startNewCompression(zcs);
Yann Collet009d6042017-05-19 10:17:59 -07002725 }
2726 break;
2727 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002728 zcs->outBuffContentSize = cSize;
2729 zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07002730 zcs->streamStage = zcss_flush; /* pass-through to flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02002731 }
Jos Collin7cd7a752017-05-11 13:17:20 +05302732 /* fall-through */
Yann Collet5a0c8e22016-08-12 01:20:36 +02002733 case zcss_flush:
Yann Collet009d6042017-05-19 10:17:59 -07002734 DEBUGLOG(5, "flush stage");
Yann Collet5a0c8e22016-08-12 01:20:36 +02002735 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
Yann Collet01b15492017-05-30 18:10:26 -07002736 size_t const flushed = ZSTD_limitCopy(op, oend-op,
2737 zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
Yann Collet2cb97742017-07-04 12:39:26 -07002738 DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u",
2739 (U32)toFlush, (U32)(oend-op), (U32)flushed);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002740 op += flushed;
2741 zcs->outBuffFlushedSize += flushed;
Yann Collet01b15492017-05-30 18:10:26 -07002742 if (toFlush!=flushed) {
Yann Collet2cb97742017-07-04 12:39:26 -07002743 /* flush not fully completed, presumably because dst is too small */
2744 assert(op==oend);
Yann Collet01b15492017-05-30 18:10:26 -07002745 someMoreWork = 0;
2746 break;
2747 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002748 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07002749 if (zcs->frameEnded) {
Yann Collet559ee822017-06-16 11:58:21 -07002750 DEBUGLOG(5, "Frame completed on flush");
Yann Collet009d6042017-05-19 10:17:59 -07002751 someMoreWork = 0;
Yann Colletb26728c2017-06-16 14:00:46 -07002752 ZSTD_startNewCompression(zcs);
Yann Collet009d6042017-05-19 10:17:59 -07002753 break;
2754 }
Yann Collet0be6fd32017-05-08 16:08:01 -07002755 zcs->streamStage = zcss_load;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002756 break;
2757 }
2758
Yann Colletcd2892f2017-06-01 09:44:54 -07002759 default: /* impossible */
2760 assert(0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002761 }
2762 }
2763
Yann Collet01b15492017-05-30 18:10:26 -07002764 input->pos = ip - istart;
2765 output->pos = op - ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002766 if (zcs->frameEnded) return 0;
2767 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
2768 if (hintInSize==0) hintInSize = zcs->blockSize;
2769 return hintInSize;
2770 }
2771}
2772
Yann Collet53e17fb2016-08-17 01:39:22 +02002773size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02002774{
Yann Collet01b15492017-05-30 18:10:26 -07002775 /* check conditions */
2776 if (output->pos > output->size) return ERROR(GENERIC);
2777 if (input->pos > input->size) return ERROR(GENERIC);
2778
2779 return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002780}
2781
Yann Colletf35e2de2017-06-05 18:32:48 -07002782
Yann Colletdeee6e52017-05-30 17:42:00 -07002783size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2784 ZSTD_outBuffer* output,
2785 ZSTD_inBuffer* input,
2786 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07002787{
Yann Collet8afb1512017-09-29 22:14:37 -07002788 DEBUGLOG(5, "ZSTD_compress_generic");
Yann Collet6d4fef32017-05-17 18:36:15 -07002789 /* check conditions */
Yann Colletdeee6e52017-05-30 17:42:00 -07002790 if (output->pos > output->size) return ERROR(GENERIC);
2791 if (input->pos > input->size) return ERROR(GENERIC);
Yann Collet6d4fef32017-05-17 18:36:15 -07002792 assert(cctx!=NULL);
Yann Collet01b15492017-05-30 18:10:26 -07002793
Yann Colleta3d99262017-06-29 14:44:49 -07002794 /* transparent initialization stage */
Yann Collet6d4fef32017-05-17 18:36:15 -07002795 if (cctx->streamStage == zcss_init) {
Stella Lauc7a18b72017-08-29 15:10:42 -07002796 ZSTD_prefixDict const prefixDict = cctx->prefixDict;
Stella Laud7755192017-08-18 17:37:58 -07002797 ZSTD_CCtx_params params = cctx->requestedParams;
Stella Lau0e56a842017-08-28 19:25:17 -07002798 params.cParams = ZSTD_getCParamsFromCCtxParams(
2799 cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
Stella Lau90a31bf2017-08-30 14:36:54 -07002800 memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
Stella Lauc7a18b72017-08-29 15:10:42 -07002801 assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
Yann Colletdb1668a2017-09-29 18:05:18 -07002802 DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage");
Yann Colletf129fd32017-06-11 18:46:09 -07002803
2804#ifdef ZSTD_MULTITHREAD
Stella Laud7755192017-08-18 17:37:58 -07002805 if (params.nbThreads > 1) {
Stella Lau4e835722017-08-29 16:18:21 -07002806 if (cctx->mtctx == NULL || cctx->appliedParams.nbThreads != params.nbThreads) {
2807 ZSTDMT_freeCCtx(cctx->mtctx);
2808 cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbThreads, cctx->customMem);
2809 if (cctx->mtctx == NULL) return ERROR(memory_allocation);
2810 }
Stella Laud7755192017-08-18 17:37:58 -07002811 DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", params.nbThreads);
Stella Lauc7a18b72017-08-29 15:10:42 -07002812 CHECK_F( ZSTDMT_initCStream_internal(
Stella Lau90a31bf2017-08-30 14:36:54 -07002813 cctx->mtctx,
2814 prefixDict.dict, prefixDict.dictSize, ZSTD_dm_rawContent,
Stella Lauc7a18b72017-08-29 15:10:42 -07002815 cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
Yann Collet23aace92017-06-11 18:32:36 -07002816 cctx->streamStage = zcss_load;
Stella Lau4e835722017-08-29 16:18:21 -07002817 cctx->appliedParams.nbThreads = params.nbThreads;
Yann Colletf129fd32017-06-11 18:46:09 -07002818 } else
2819#endif
2820 {
Stella Lauc7a18b72017-08-29 15:10:42 -07002821 CHECK_F( ZSTD_resetCStream_internal(
2822 cctx, prefixDict.dict, prefixDict.dictSize,
2823 prefixDict.dictMode, cctx->cdict, params,
2824 cctx->pledgedSrcSizePlusOne-1) );
Yann Colletf35e2de2017-06-05 18:32:48 -07002825 } }
2826
Yann Colleta3d99262017-06-29 14:44:49 -07002827 /* compression stage */
Yann Colletf129fd32017-06-11 18:46:09 -07002828#ifdef ZSTD_MULTITHREAD
Stella Lau4e835722017-08-29 16:18:21 -07002829 if (cctx->appliedParams.nbThreads > 1) {
Yann Collet23aace92017-06-11 18:32:36 -07002830 size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
Yann Collet8afb1512017-09-29 22:14:37 -07002831 DEBUGLOG(5, "ZSTDMT_compressStream_generic result : %u", (U32)flushMin);
Yann Colletb26728c2017-06-16 14:00:46 -07002832 if ( ZSTD_isError(flushMin)
2833 || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
2834 ZSTD_startNewCompression(cctx);
Yann Collet9e73f2f2017-06-16 12:24:01 -07002835 }
Yann Collet23aace92017-06-11 18:32:36 -07002836 return flushMin;
Yann Collet6d4fef32017-05-17 18:36:15 -07002837 }
Yann Colletf129fd32017-06-11 18:46:09 -07002838#endif
Yann Collet01b15492017-05-30 18:10:26 -07002839 CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
Yann Collet559ee822017-06-16 11:58:21 -07002840 DEBUGLOG(5, "completed ZSTD_compress_generic");
Yann Colletdeee6e52017-05-30 17:42:00 -07002841 return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
Yann Collet6d4fef32017-05-17 18:36:15 -07002842}
2843
Yann Colletdeee6e52017-05-30 17:42:00 -07002844size_t ZSTD_compress_generic_simpleArgs (
2845 ZSTD_CCtx* cctx,
2846 void* dst, size_t dstCapacity, size_t* dstPos,
2847 const void* src, size_t srcSize, size_t* srcPos,
2848 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07002849{
Yann Colletdeee6e52017-05-30 17:42:00 -07002850 ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
2851 ZSTD_inBuffer input = { src, srcSize, *srcPos };
Yann Collet01b15492017-05-30 18:10:26 -07002852 /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
Yann Collet58e8d792017-06-02 18:20:48 -07002853 size_t const cErr = ZSTD_compress_generic(cctx, &output, &input, endOp);
Yann Colletdeee6e52017-05-30 17:42:00 -07002854 *dstPos = output.pos;
2855 *srcPos = input.pos;
Yann Collet58e8d792017-06-02 18:20:48 -07002856 return cErr;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002857}
2858
2859
Yann Collet104e5b02016-08-12 13:04:27 +02002860/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002861
2862/*! ZSTD_flushStream() :
2863* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02002864size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02002865{
Yann Collet18ab5af2017-05-31 09:59:22 -07002866 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07002867 if (output->pos > output->size) return ERROR(GENERIC);
2868 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_flush) );
2869 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
Yann Collet5a0c8e22016-08-12 01:20:36 +02002870}
2871
2872
Yann Collet53e17fb2016-08-17 01:39:22 +02002873size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02002874{
Yann Collet18ab5af2017-05-31 09:59:22 -07002875 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07002876 if (output->pos > output->size) return ERROR(GENERIC);
2877 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_end) );
Yann Collet2cb97742017-07-04 12:39:26 -07002878 { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
2879 size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4;
2880 size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize + lastBlockSize + checksumSize;
2881 DEBUGLOG(5, "ZSTD_endStream : remaining to flush : %u",
2882 (unsigned)toFlush);
2883 return toFlush;
2884 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002885}
2886
2887
Yann Collet70e8c382016-02-10 13:37:52 +01002888/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002889
inikep2c5eeea2016-04-15 13:44:46 +02002890#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02002891int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01002892
Yann Collet3b719252016-03-30 19:48:05 +02002893static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletadbe74a2017-06-28 13:22:37 -07002894{ /* "default" - guarantees a monotonically increasing memory budget */
Yann Collet793c6492016-04-09 20:32:00 +02002895 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02002896 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02002897 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
2898 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Colletadbe74a2017-06-28 13:22:37 -07002899 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3 */
2900 { 20, 17, 18, 1, 5, 16, ZSTD_dfast }, /* level 4 */
2901 { 20, 17, 18, 2, 5, 16, ZSTD_greedy }, /* level 5 */
2902 { 21, 17, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
2903 { 21, 18, 19, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02002904 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Colletadbe74a2017-06-28 13:22:37 -07002905 { 21, 19, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
Yann Collet3c242e72016-07-13 14:56:24 +02002906 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
2907 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
2908 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
2909 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
2910 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
Yann Colletadbe74a2017-06-28 13:22:37 -07002911 { 22, 21, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
Yann Collet3c242e72016-07-13 14:56:24 +02002912 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Colletadbe74a2017-06-28 13:22:37 -07002913 { 23, 22, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
Yann Collet29297c62017-04-27 17:44:01 -07002914 { 23, 22, 22, 5, 4, 32, ZSTD_btopt }, /* level 18 */
Yann Collete19a9ef2016-08-26 20:02:49 +02002915 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Nick Terrell374f8682017-05-10 17:48:42 -07002916 { 25, 25, 23, 7, 3, 64, ZSTD_btultra }, /* level 20 */
Yann Colletadbe74a2017-06-28 13:22:37 -07002917 { 26, 26, 24, 7, 3,256, ZSTD_btultra }, /* level 21 */
Nick Terrell374f8682017-05-10 17:48:42 -07002918 { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01002919},
2920{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002921 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02002922 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02002923 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02002924 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
2925 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
2926 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
2927 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
2928 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
2929 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
2930 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
2931 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
2932 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
2933 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
2934 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
2935 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02002936 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02002937 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
2938 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
2939 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02002940 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
2941 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07002942 { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/
2943 { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/
2944 { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002945},
2946{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002947 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02002948 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
2949 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
2950 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
2951 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
2952 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
2953 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
2954 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
2955 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
2956 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
2957 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
2958 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
2959 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
2960 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
2961 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02002962 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
2963 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
2964 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
2965 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
2966 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
2967 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07002968 { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/
2969 { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/
2970 { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002971},
2972{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002973 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02002974 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02002975 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02002976 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
2977 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
2978 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
2979 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
2980 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
2981 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
2982 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
2983 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02002984 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
2985 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
2986 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
2987 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
2988 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
2989 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
2990 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
2991 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
2992 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
2993 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07002994 { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/
2995 { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/
2996 { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002997},
2998};
2999
Yann Collet03746622017-06-28 20:17:22 -07003000#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
Yann Collet81353512017-06-28 15:34:56 -07003001/* This function just controls
3002 * the monotonic memory budget increase of ZSTD_defaultCParameters[0].
Yann Collet2cb97742017-07-04 12:39:26 -07003003 * Run once, on first ZSTD_getCParams() usage, if ZSTD_DEBUG is enabled
Yann Collet81353512017-06-28 15:34:56 -07003004 */
3005MEM_STATIC void ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget(void)
3006{
Yann Collet03746622017-06-28 20:17:22 -07003007 int level;
3008 for (level=1; level<ZSTD_maxCLevel(); level++) {
3009 ZSTD_compressionParameters const c1 = ZSTD_defaultCParameters[0][level];
3010 ZSTD_compressionParameters const c2 = ZSTD_defaultCParameters[0][level+1];
Yann Collet03746622017-06-28 20:17:22 -07003011 assert(c1.windowLog <= c2.windowLog);
3012# define ZSTD_TABLECOST(h,c) ((1<<(h)) + (1<<(c)))
3013 assert(ZSTD_TABLECOST(c1.hashLog, c1.chainLog) <= ZSTD_TABLECOST(c2.hashLog, c2.chainLog));
Yann Collet81353512017-06-28 15:34:56 -07003014 }
Yann Collet81353512017-06-28 15:34:56 -07003015}
Yann Collet03746622017-06-28 20:17:22 -07003016#endif
Yann Collet81353512017-06-28 15:34:56 -07003017
Yann Collet236d94f2016-05-18 12:06:33 +02003018/*! ZSTD_getCParams() :
3019* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3020* Size values are optional, provide 0 if not known or unused */
Yann Collet009d6042017-05-19 10:17:59 -07003021ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003022{
Yann Collet009d6042017-05-19 10:17:59 -07003023 size_t const addedSize = srcSizeHint ? 0 : 500;
3024 U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003025 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet81353512017-06-28 15:34:56 -07003026
3027#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
3028 static int g_monotonicTest = 1;
3029 if (g_monotonicTest) {
3030 ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget();
3031 g_monotonicTest=0;
3032 }
3033#endif
3034
Yann Collet6d4fef32017-05-17 18:36:15 -07003035 if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003036 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collete51d51b2017-06-20 17:44:55 -07003037 { ZSTD_compressionParameters const cp = ZSTD_defaultCParameters[tableID][compressionLevel];
3038 return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); }
Stella Lau0e56a842017-08-28 19:25:17 -07003039
Yann Colletfd416f12016-01-30 03:14:15 +01003040}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003041
3042/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003043* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003044* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet009d6042017-05-19 10:17:59 -07003045ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003046 ZSTD_parameters params;
Yann Collet009d6042017-05-19 10:17:59 -07003047 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003048 memset(&params, 0, sizeof(params));
3049 params.cParams = cParams;
3050 return params;
3051}