1*61145dc2SMartin Matuska // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only
2c03c5b1cSMartin Matuska /*
3c03c5b1cSMartin Matuska * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
4c03c5b1cSMartin Matuska * All rights reserved.
5c03c5b1cSMartin Matuska *
6c03c5b1cSMartin Matuska * This source code is licensed under both the BSD-style license (found in the
7c03c5b1cSMartin Matuska * LICENSE file in the root directory of this source tree) and the GPLv2 (found
8c03c5b1cSMartin Matuska * in the COPYING file in the root directory of this source tree).
9c03c5b1cSMartin Matuska * You may select, at your option, one of the above-listed licenses.
10c03c5b1cSMartin Matuska */
11c03c5b1cSMartin Matuska
12c03c5b1cSMartin Matuska /*-*************************************
13c03c5b1cSMartin Matuska * Dependencies
14c03c5b1cSMartin Matuska ***************************************/
15c03c5b1cSMartin Matuska #include <limits.h> /* INT_MAX */
16c03c5b1cSMartin Matuska #include <string.h> /* memset */
17c03c5b1cSMartin Matuska #include "../common/cpu.h"
18c03c5b1cSMartin Matuska #include "../common/mem.h"
19c03c5b1cSMartin Matuska #include "hist.h" /* HIST_countFast_wksp */
20c03c5b1cSMartin Matuska #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
21c03c5b1cSMartin Matuska #include "../common/fse.h"
22c03c5b1cSMartin Matuska #define HUF_STATIC_LINKING_ONLY
23c03c5b1cSMartin Matuska #include "../common/huf.h"
24c03c5b1cSMartin Matuska #include "zstd_compress_internal.h"
25c03c5b1cSMartin Matuska #include "zstd_compress_sequences.h"
26c03c5b1cSMartin Matuska #include "zstd_compress_literals.h"
27c03c5b1cSMartin Matuska #include "zstd_fast.h"
28c03c5b1cSMartin Matuska #include "zstd_double_fast.h"
29c03c5b1cSMartin Matuska #include "zstd_lazy.h"
30c03c5b1cSMartin Matuska #include "zstd_opt.h"
31c03c5b1cSMartin Matuska #include "zstd_ldm.h"
32c03c5b1cSMartin Matuska #include "zstd_compress_superblock.h"
33c03c5b1cSMartin Matuska
34c03c5b1cSMartin Matuska
35c03c5b1cSMartin Matuska /*-*************************************
36c03c5b1cSMartin Matuska * Helper functions
37c03c5b1cSMartin Matuska ***************************************/
38c03c5b1cSMartin Matuska /* ZSTD_compressBound()
39c03c5b1cSMartin Matuska * Note that the result from this function is only compatible with the "normal"
40c03c5b1cSMartin Matuska * full-block strategy.
41c03c5b1cSMartin Matuska * When there are a lot of small blocks due to frequent flush in streaming mode
42c03c5b1cSMartin Matuska * the overhead of headers can make the compressed data to be larger than the
43c03c5b1cSMartin Matuska * return value of ZSTD_compressBound().
44c03c5b1cSMartin Matuska */
ZSTD_compressBound(size_t srcSize)45c03c5b1cSMartin Matuska size_t ZSTD_compressBound(size_t srcSize) {
46c03c5b1cSMartin Matuska return ZSTD_COMPRESSBOUND(srcSize);
47c03c5b1cSMartin Matuska }
48c03c5b1cSMartin Matuska
49c03c5b1cSMartin Matuska
50c03c5b1cSMartin Matuska /*-*************************************
51c03c5b1cSMartin Matuska * Context memory management
52c03c5b1cSMartin Matuska ***************************************/
53c03c5b1cSMartin Matuska struct ZSTD_CDict_s {
54c03c5b1cSMartin Matuska const void* dictContent;
55c03c5b1cSMartin Matuska size_t dictContentSize;
56c03c5b1cSMartin Matuska U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
57c03c5b1cSMartin Matuska ZSTD_cwksp workspace;
58c03c5b1cSMartin Matuska ZSTD_matchState_t matchState;
59c03c5b1cSMartin Matuska ZSTD_compressedBlockState_t cBlockState;
60c03c5b1cSMartin Matuska ZSTD_customMem customMem;
61c03c5b1cSMartin Matuska U32 dictID;
62c03c5b1cSMartin Matuska int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */
63c03c5b1cSMartin Matuska }; /* typedef'd to ZSTD_CDict within "zstd.h" */
64c03c5b1cSMartin Matuska
ZSTD_createCCtx(void)65c03c5b1cSMartin Matuska ZSTD_CCtx* ZSTD_createCCtx(void)
66c03c5b1cSMartin Matuska {
67c03c5b1cSMartin Matuska return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
68c03c5b1cSMartin Matuska }
69c03c5b1cSMartin Matuska
ZSTD_initCCtx(ZSTD_CCtx * cctx,ZSTD_customMem memManager)70c03c5b1cSMartin Matuska static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
71c03c5b1cSMartin Matuska {
72c03c5b1cSMartin Matuska assert(cctx != NULL);
73c03c5b1cSMartin Matuska memset(cctx, 0, sizeof(*cctx));
74c03c5b1cSMartin Matuska cctx->customMem = memManager;
75c03c5b1cSMartin Matuska cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
76c03c5b1cSMartin Matuska { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
77c03c5b1cSMartin Matuska assert(!ZSTD_isError(err));
78c03c5b1cSMartin Matuska (void)err;
79c03c5b1cSMartin Matuska }
80c03c5b1cSMartin Matuska }
81c03c5b1cSMartin Matuska
ZSTD_createCCtx_advanced(ZSTD_customMem customMem)82c03c5b1cSMartin Matuska ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
83c03c5b1cSMartin Matuska {
84c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(zcss_init==0);
85c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
86c03c5b1cSMartin Matuska if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
87c03c5b1cSMartin Matuska { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
88c03c5b1cSMartin Matuska if (!cctx) return NULL;
89c03c5b1cSMartin Matuska ZSTD_initCCtx(cctx, customMem);
90c03c5b1cSMartin Matuska return cctx;
91c03c5b1cSMartin Matuska }
92c03c5b1cSMartin Matuska }
93c03c5b1cSMartin Matuska
ZSTD_initStaticCCtx(void * workspace,size_t workspaceSize)94c03c5b1cSMartin Matuska ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
95c03c5b1cSMartin Matuska {
96c03c5b1cSMartin Matuska ZSTD_cwksp ws;
97c03c5b1cSMartin Matuska ZSTD_CCtx* cctx;
98c03c5b1cSMartin Matuska if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
99c03c5b1cSMartin Matuska if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
100c03c5b1cSMartin Matuska ZSTD_cwksp_init(&ws, workspace, workspaceSize);
101c03c5b1cSMartin Matuska
102c03c5b1cSMartin Matuska cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx));
103c03c5b1cSMartin Matuska if (cctx == NULL) return NULL;
104c03c5b1cSMartin Matuska
105c03c5b1cSMartin Matuska memset(cctx, 0, sizeof(ZSTD_CCtx));
106c03c5b1cSMartin Matuska ZSTD_cwksp_move(&cctx->workspace, &ws);
107c03c5b1cSMartin Matuska cctx->staticSize = workspaceSize;
108c03c5b1cSMartin Matuska
109c03c5b1cSMartin Matuska /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
110c03c5b1cSMartin Matuska if (!ZSTD_cwksp_check_available(&cctx->workspace, HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL;
111c03c5b1cSMartin Matuska cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
112c03c5b1cSMartin Matuska cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
113c03c5b1cSMartin Matuska cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, HUF_WORKSPACE_SIZE);
114c03c5b1cSMartin Matuska cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
115c03c5b1cSMartin Matuska return cctx;
116c03c5b1cSMartin Matuska }
117c03c5b1cSMartin Matuska
118c03c5b1cSMartin Matuska /**
119c03c5b1cSMartin Matuska * Clears and frees all of the dictionaries in the CCtx.
120c03c5b1cSMartin Matuska */
ZSTD_clearAllDicts(ZSTD_CCtx * cctx)121c03c5b1cSMartin Matuska static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx)
122c03c5b1cSMartin Matuska {
123c03c5b1cSMartin Matuska ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem);
124c03c5b1cSMartin Matuska ZSTD_freeCDict(cctx->localDict.cdict);
125c03c5b1cSMartin Matuska memset(&cctx->localDict, 0, sizeof(cctx->localDict));
126c03c5b1cSMartin Matuska memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
127c03c5b1cSMartin Matuska cctx->cdict = NULL;
128c03c5b1cSMartin Matuska }
129c03c5b1cSMartin Matuska
ZSTD_sizeof_localDict(ZSTD_localDict dict)130c03c5b1cSMartin Matuska static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict)
131c03c5b1cSMartin Matuska {
132c03c5b1cSMartin Matuska size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0;
133c03c5b1cSMartin Matuska size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict);
134c03c5b1cSMartin Matuska return bufferSize + cdictSize;
135c03c5b1cSMartin Matuska }
136c03c5b1cSMartin Matuska
ZSTD_freeCCtxContent(ZSTD_CCtx * cctx)137c03c5b1cSMartin Matuska static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx)
138c03c5b1cSMartin Matuska {
139c03c5b1cSMartin Matuska assert(cctx != NULL);
140c03c5b1cSMartin Matuska assert(cctx->staticSize == 0);
141c03c5b1cSMartin Matuska ZSTD_clearAllDicts(cctx);
142c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
143c03c5b1cSMartin Matuska ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
144c03c5b1cSMartin Matuska #endif
145c03c5b1cSMartin Matuska ZSTD_cwksp_free(&cctx->workspace, cctx->customMem);
146c03c5b1cSMartin Matuska }
147c03c5b1cSMartin Matuska
ZSTD_freeCCtx(ZSTD_CCtx * cctx)148c03c5b1cSMartin Matuska size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
149c03c5b1cSMartin Matuska {
150c03c5b1cSMartin Matuska if (cctx==NULL) return 0; /* support free on NULL */
151c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
152c03c5b1cSMartin Matuska "not compatible with static CCtx");
153c03c5b1cSMartin Matuska {
154c03c5b1cSMartin Matuska int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx);
155c03c5b1cSMartin Matuska ZSTD_freeCCtxContent(cctx);
156c03c5b1cSMartin Matuska if (!cctxInWorkspace) {
157c03c5b1cSMartin Matuska ZSTD_free(cctx, cctx->customMem);
158c03c5b1cSMartin Matuska }
159c03c5b1cSMartin Matuska }
160c03c5b1cSMartin Matuska return 0;
161c03c5b1cSMartin Matuska }
162c03c5b1cSMartin Matuska
163c03c5b1cSMartin Matuska
ZSTD_sizeof_mtctx(const ZSTD_CCtx * cctx)164c03c5b1cSMartin Matuska static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
165c03c5b1cSMartin Matuska {
166c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
167c03c5b1cSMartin Matuska return ZSTDMT_sizeof_CCtx(cctx->mtctx);
168c03c5b1cSMartin Matuska #else
169c03c5b1cSMartin Matuska (void)cctx;
170c03c5b1cSMartin Matuska return 0;
171c03c5b1cSMartin Matuska #endif
172c03c5b1cSMartin Matuska }
173c03c5b1cSMartin Matuska
174c03c5b1cSMartin Matuska
ZSTD_sizeof_CCtx(const ZSTD_CCtx * cctx)175c03c5b1cSMartin Matuska size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
176c03c5b1cSMartin Matuska {
177c03c5b1cSMartin Matuska if (cctx==NULL) return 0; /* support sizeof on NULL */
178c03c5b1cSMartin Matuska /* cctx may be in the workspace */
179c03c5b1cSMartin Matuska return (cctx->workspace.workspace == cctx ? 0 : sizeof(*cctx))
180c03c5b1cSMartin Matuska + ZSTD_cwksp_sizeof(&cctx->workspace)
181c03c5b1cSMartin Matuska + ZSTD_sizeof_localDict(cctx->localDict)
182c03c5b1cSMartin Matuska + ZSTD_sizeof_mtctx(cctx);
183c03c5b1cSMartin Matuska }
184c03c5b1cSMartin Matuska
ZSTD_sizeof_CStream(const ZSTD_CStream * zcs)185c03c5b1cSMartin Matuska size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
186c03c5b1cSMartin Matuska {
187c03c5b1cSMartin Matuska return ZSTD_sizeof_CCtx(zcs); /* same object */
188c03c5b1cSMartin Matuska }
189c03c5b1cSMartin Matuska
190c03c5b1cSMartin Matuska /* private API call, for dictBuilder only */
ZSTD_getSeqStore(const ZSTD_CCtx * ctx)191c03c5b1cSMartin Matuska const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
192c03c5b1cSMartin Matuska
ZSTD_makeCCtxParamsFromCParams(ZSTD_compressionParameters cParams)193c03c5b1cSMartin Matuska static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
194c03c5b1cSMartin Matuska ZSTD_compressionParameters cParams)
195c03c5b1cSMartin Matuska {
196c03c5b1cSMartin Matuska ZSTD_CCtx_params cctxParams;
197c03c5b1cSMartin Matuska memset(&cctxParams, 0, sizeof(cctxParams));
198c03c5b1cSMartin Matuska cctxParams.cParams = cParams;
199c03c5b1cSMartin Matuska cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
200c03c5b1cSMartin Matuska assert(!ZSTD_checkCParams(cParams));
201c03c5b1cSMartin Matuska cctxParams.fParams.contentSizeFlag = 1;
202c03c5b1cSMartin Matuska return cctxParams;
203c03c5b1cSMartin Matuska }
204c03c5b1cSMartin Matuska
ZSTD_createCCtxParams_advanced(ZSTD_customMem customMem)205c03c5b1cSMartin Matuska static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
206c03c5b1cSMartin Matuska ZSTD_customMem customMem)
207c03c5b1cSMartin Matuska {
208c03c5b1cSMartin Matuska ZSTD_CCtx_params* params;
209c03c5b1cSMartin Matuska if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
210c03c5b1cSMartin Matuska params = (ZSTD_CCtx_params*)ZSTD_calloc(
211c03c5b1cSMartin Matuska sizeof(ZSTD_CCtx_params), customMem);
212c03c5b1cSMartin Matuska if (!params) { return NULL; }
213c03c5b1cSMartin Matuska params->customMem = customMem;
214c03c5b1cSMartin Matuska params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
215c03c5b1cSMartin Matuska params->fParams.contentSizeFlag = 1;
216c03c5b1cSMartin Matuska return params;
217c03c5b1cSMartin Matuska }
218c03c5b1cSMartin Matuska
ZSTD_createCCtxParams(void)219c03c5b1cSMartin Matuska ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
220c03c5b1cSMartin Matuska {
221c03c5b1cSMartin Matuska return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);
222c03c5b1cSMartin Matuska }
223c03c5b1cSMartin Matuska
ZSTD_freeCCtxParams(ZSTD_CCtx_params * params)224c03c5b1cSMartin Matuska size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
225c03c5b1cSMartin Matuska {
226c03c5b1cSMartin Matuska if (params == NULL) { return 0; }
227c03c5b1cSMartin Matuska ZSTD_free(params, params->customMem);
228c03c5b1cSMartin Matuska return 0;
229c03c5b1cSMartin Matuska }
230c03c5b1cSMartin Matuska
ZSTD_CCtxParams_reset(ZSTD_CCtx_params * params)231c03c5b1cSMartin Matuska size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
232c03c5b1cSMartin Matuska {
233c03c5b1cSMartin Matuska return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
234c03c5b1cSMartin Matuska }
235c03c5b1cSMartin Matuska
ZSTD_CCtxParams_init(ZSTD_CCtx_params * cctxParams,int compressionLevel)236c03c5b1cSMartin Matuska size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
237c03c5b1cSMartin Matuska RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
238c03c5b1cSMartin Matuska memset(cctxParams, 0, sizeof(*cctxParams));
239c03c5b1cSMartin Matuska cctxParams->compressionLevel = compressionLevel;
240c03c5b1cSMartin Matuska cctxParams->fParams.contentSizeFlag = 1;
241c03c5b1cSMartin Matuska return 0;
242c03c5b1cSMartin Matuska }
243c03c5b1cSMartin Matuska
ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params * cctxParams,ZSTD_parameters params)244c03c5b1cSMartin Matuska size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
245c03c5b1cSMartin Matuska {
246c03c5b1cSMartin Matuska RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
247c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
248c03c5b1cSMartin Matuska memset(cctxParams, 0, sizeof(*cctxParams));
249c03c5b1cSMartin Matuska assert(!ZSTD_checkCParams(params.cParams));
250c03c5b1cSMartin Matuska cctxParams->cParams = params.cParams;
251c03c5b1cSMartin Matuska cctxParams->fParams = params.fParams;
252c03c5b1cSMartin Matuska cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
253c03c5b1cSMartin Matuska return 0;
254c03c5b1cSMartin Matuska }
255c03c5b1cSMartin Matuska
256c03c5b1cSMartin Matuska /* ZSTD_assignParamsToCCtxParams() :
257c03c5b1cSMartin Matuska * params is presumed valid at this stage */
ZSTD_assignParamsToCCtxParams(const ZSTD_CCtx_params * cctxParams,const ZSTD_parameters * params)258c03c5b1cSMartin Matuska static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
259c03c5b1cSMartin Matuska const ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params)
260c03c5b1cSMartin Matuska {
261c03c5b1cSMartin Matuska ZSTD_CCtx_params ret = *cctxParams;
262c03c5b1cSMartin Matuska assert(!ZSTD_checkCParams(params->cParams));
263c03c5b1cSMartin Matuska ret.cParams = params->cParams;
264c03c5b1cSMartin Matuska ret.fParams = params->fParams;
265c03c5b1cSMartin Matuska ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
266c03c5b1cSMartin Matuska return ret;
267c03c5b1cSMartin Matuska }
268c03c5b1cSMartin Matuska
ZSTD_cParam_getBounds(ZSTD_cParameter param)269c03c5b1cSMartin Matuska ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
270c03c5b1cSMartin Matuska {
271c03c5b1cSMartin Matuska ZSTD_bounds bounds = { 0, 0, 0 };
272c03c5b1cSMartin Matuska
273c03c5b1cSMartin Matuska switch(param)
274c03c5b1cSMartin Matuska {
275c03c5b1cSMartin Matuska case ZSTD_c_compressionLevel:
276c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_minCLevel();
277c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_maxCLevel();
278c03c5b1cSMartin Matuska return bounds;
279c03c5b1cSMartin Matuska
280c03c5b1cSMartin Matuska case ZSTD_c_windowLog:
281c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_WINDOWLOG_MIN;
282c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_WINDOWLOG_MAX;
283c03c5b1cSMartin Matuska return bounds;
284c03c5b1cSMartin Matuska
285c03c5b1cSMartin Matuska case ZSTD_c_hashLog:
286c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_HASHLOG_MIN;
287c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_HASHLOG_MAX;
288c03c5b1cSMartin Matuska return bounds;
289c03c5b1cSMartin Matuska
290c03c5b1cSMartin Matuska case ZSTD_c_chainLog:
291c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_CHAINLOG_MIN;
292c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_CHAINLOG_MAX;
293c03c5b1cSMartin Matuska return bounds;
294c03c5b1cSMartin Matuska
295c03c5b1cSMartin Matuska case ZSTD_c_searchLog:
296c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_SEARCHLOG_MIN;
297c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_SEARCHLOG_MAX;
298c03c5b1cSMartin Matuska return bounds;
299c03c5b1cSMartin Matuska
300c03c5b1cSMartin Matuska case ZSTD_c_minMatch:
301c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_MINMATCH_MIN;
302c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_MINMATCH_MAX;
303c03c5b1cSMartin Matuska return bounds;
304c03c5b1cSMartin Matuska
305c03c5b1cSMartin Matuska case ZSTD_c_targetLength:
306c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_TARGETLENGTH_MIN;
307c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_TARGETLENGTH_MAX;
308c03c5b1cSMartin Matuska return bounds;
309c03c5b1cSMartin Matuska
310c03c5b1cSMartin Matuska case ZSTD_c_strategy:
311c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_STRATEGY_MIN;
312c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_STRATEGY_MAX;
313c03c5b1cSMartin Matuska return bounds;
314c03c5b1cSMartin Matuska
315c03c5b1cSMartin Matuska case ZSTD_c_contentSizeFlag:
316c03c5b1cSMartin Matuska bounds.lowerBound = 0;
317c03c5b1cSMartin Matuska bounds.upperBound = 1;
318c03c5b1cSMartin Matuska return bounds;
319c03c5b1cSMartin Matuska
320c03c5b1cSMartin Matuska case ZSTD_c_checksumFlag:
321c03c5b1cSMartin Matuska bounds.lowerBound = 0;
322c03c5b1cSMartin Matuska bounds.upperBound = 1;
323c03c5b1cSMartin Matuska return bounds;
324c03c5b1cSMartin Matuska
325c03c5b1cSMartin Matuska case ZSTD_c_dictIDFlag:
326c03c5b1cSMartin Matuska bounds.lowerBound = 0;
327c03c5b1cSMartin Matuska bounds.upperBound = 1;
328c03c5b1cSMartin Matuska return bounds;
329c03c5b1cSMartin Matuska
330c03c5b1cSMartin Matuska case ZSTD_c_nbWorkers:
331c03c5b1cSMartin Matuska bounds.lowerBound = 0;
332c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
333c03c5b1cSMartin Matuska bounds.upperBound = ZSTDMT_NBWORKERS_MAX;
334c03c5b1cSMartin Matuska #else
335c03c5b1cSMartin Matuska bounds.upperBound = 0;
336c03c5b1cSMartin Matuska #endif
337c03c5b1cSMartin Matuska return bounds;
338c03c5b1cSMartin Matuska
339c03c5b1cSMartin Matuska case ZSTD_c_jobSize:
340c03c5b1cSMartin Matuska bounds.lowerBound = 0;
341c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
342c03c5b1cSMartin Matuska bounds.upperBound = ZSTDMT_JOBSIZE_MAX;
343c03c5b1cSMartin Matuska #else
344c03c5b1cSMartin Matuska bounds.upperBound = 0;
345c03c5b1cSMartin Matuska #endif
346c03c5b1cSMartin Matuska return bounds;
347c03c5b1cSMartin Matuska
348c03c5b1cSMartin Matuska case ZSTD_c_overlapLog:
349c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
350c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_OVERLAPLOG_MIN;
351c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_OVERLAPLOG_MAX;
352c03c5b1cSMartin Matuska #else
353c03c5b1cSMartin Matuska bounds.lowerBound = 0;
354c03c5b1cSMartin Matuska bounds.upperBound = 0;
355c03c5b1cSMartin Matuska #endif
356c03c5b1cSMartin Matuska return bounds;
357c03c5b1cSMartin Matuska
358c03c5b1cSMartin Matuska case ZSTD_c_enableLongDistanceMatching:
359c03c5b1cSMartin Matuska bounds.lowerBound = 0;
360c03c5b1cSMartin Matuska bounds.upperBound = 1;
361c03c5b1cSMartin Matuska return bounds;
362c03c5b1cSMartin Matuska
363c03c5b1cSMartin Matuska case ZSTD_c_ldmHashLog:
364c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN;
365c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_LDM_HASHLOG_MAX;
366c03c5b1cSMartin Matuska return bounds;
367c03c5b1cSMartin Matuska
368c03c5b1cSMartin Matuska case ZSTD_c_ldmMinMatch:
369c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN;
370c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_LDM_MINMATCH_MAX;
371c03c5b1cSMartin Matuska return bounds;
372c03c5b1cSMartin Matuska
373c03c5b1cSMartin Matuska case ZSTD_c_ldmBucketSizeLog:
374c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN;
375c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX;
376c03c5b1cSMartin Matuska return bounds;
377c03c5b1cSMartin Matuska
378c03c5b1cSMartin Matuska case ZSTD_c_ldmHashRateLog:
379c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN;
380c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX;
381c03c5b1cSMartin Matuska return bounds;
382c03c5b1cSMartin Matuska
383c03c5b1cSMartin Matuska /* experimental parameters */
384c03c5b1cSMartin Matuska case ZSTD_c_rsyncable:
385c03c5b1cSMartin Matuska bounds.lowerBound = 0;
386c03c5b1cSMartin Matuska bounds.upperBound = 1;
387c03c5b1cSMartin Matuska return bounds;
388c03c5b1cSMartin Matuska
389c03c5b1cSMartin Matuska case ZSTD_c_forceMaxWindow :
390c03c5b1cSMartin Matuska bounds.lowerBound = 0;
391c03c5b1cSMartin Matuska bounds.upperBound = 1;
392c03c5b1cSMartin Matuska return bounds;
393c03c5b1cSMartin Matuska
394c03c5b1cSMartin Matuska case ZSTD_c_format:
395c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
396c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_f_zstd1;
397c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_f_zstd1_magicless; /* note : how to ensure at compile time that this is the highest value enum ? */
398c03c5b1cSMartin Matuska return bounds;
399c03c5b1cSMartin Matuska
400c03c5b1cSMartin Matuska case ZSTD_c_forceAttachDict:
401c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy);
402c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_dictDefaultAttach;
403c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */
404c03c5b1cSMartin Matuska return bounds;
405c03c5b1cSMartin Matuska
406c03c5b1cSMartin Matuska case ZSTD_c_literalCompressionMode:
407c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed);
408c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_lcm_auto;
409c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_lcm_uncompressed;
410c03c5b1cSMartin Matuska return bounds;
411c03c5b1cSMartin Matuska
412c03c5b1cSMartin Matuska case ZSTD_c_targetCBlockSize:
413c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_TARGETCBLOCKSIZE_MIN;
414c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_TARGETCBLOCKSIZE_MAX;
415c03c5b1cSMartin Matuska return bounds;
416c03c5b1cSMartin Matuska
417c03c5b1cSMartin Matuska case ZSTD_c_srcSizeHint:
418c03c5b1cSMartin Matuska bounds.lowerBound = ZSTD_SRCSIZEHINT_MIN;
419c03c5b1cSMartin Matuska bounds.upperBound = ZSTD_SRCSIZEHINT_MAX;
420c03c5b1cSMartin Matuska return bounds;
421c03c5b1cSMartin Matuska
422c03c5b1cSMartin Matuska default:
423c03c5b1cSMartin Matuska bounds.error = ERROR(parameter_unsupported);
424c03c5b1cSMartin Matuska return bounds;
425c03c5b1cSMartin Matuska }
426c03c5b1cSMartin Matuska }
427c03c5b1cSMartin Matuska
428c03c5b1cSMartin Matuska /* ZSTD_cParam_clampBounds:
429c03c5b1cSMartin Matuska * Clamps the value into the bounded range.
430c03c5b1cSMartin Matuska */
ZSTD_cParam_clampBounds(ZSTD_cParameter cParam,int * value)431c03c5b1cSMartin Matuska static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value)
432c03c5b1cSMartin Matuska {
433c03c5b1cSMartin Matuska ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
434c03c5b1cSMartin Matuska if (ZSTD_isError(bounds.error)) return bounds.error;
435c03c5b1cSMartin Matuska if (*value < bounds.lowerBound) *value = bounds.lowerBound;
436c03c5b1cSMartin Matuska if (*value > bounds.upperBound) *value = bounds.upperBound;
437c03c5b1cSMartin Matuska return 0;
438c03c5b1cSMartin Matuska }
439c03c5b1cSMartin Matuska
440c03c5b1cSMartin Matuska #define BOUNDCHECK(cParam, val) { \
441c03c5b1cSMartin Matuska RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \
442c03c5b1cSMartin Matuska parameter_outOfBound, "Param out of bounds"); \
443c03c5b1cSMartin Matuska }
444c03c5b1cSMartin Matuska
445c03c5b1cSMartin Matuska
ZSTD_isUpdateAuthorized(ZSTD_cParameter param)446c03c5b1cSMartin Matuska static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
447c03c5b1cSMartin Matuska {
448c03c5b1cSMartin Matuska switch(param)
449c03c5b1cSMartin Matuska {
450c03c5b1cSMartin Matuska case ZSTD_c_compressionLevel:
451c03c5b1cSMartin Matuska case ZSTD_c_hashLog:
452c03c5b1cSMartin Matuska case ZSTD_c_chainLog:
453c03c5b1cSMartin Matuska case ZSTD_c_searchLog:
454c03c5b1cSMartin Matuska case ZSTD_c_minMatch:
455c03c5b1cSMartin Matuska case ZSTD_c_targetLength:
456c03c5b1cSMartin Matuska case ZSTD_c_strategy:
457c03c5b1cSMartin Matuska return 1;
458c03c5b1cSMartin Matuska
459c03c5b1cSMartin Matuska case ZSTD_c_format:
460c03c5b1cSMartin Matuska case ZSTD_c_windowLog:
461c03c5b1cSMartin Matuska case ZSTD_c_contentSizeFlag:
462c03c5b1cSMartin Matuska case ZSTD_c_checksumFlag:
463c03c5b1cSMartin Matuska case ZSTD_c_dictIDFlag:
464c03c5b1cSMartin Matuska case ZSTD_c_forceMaxWindow :
465c03c5b1cSMartin Matuska case ZSTD_c_nbWorkers:
466c03c5b1cSMartin Matuska case ZSTD_c_jobSize:
467c03c5b1cSMartin Matuska case ZSTD_c_overlapLog:
468c03c5b1cSMartin Matuska case ZSTD_c_rsyncable:
469c03c5b1cSMartin Matuska case ZSTD_c_enableLongDistanceMatching:
470c03c5b1cSMartin Matuska case ZSTD_c_ldmHashLog:
471c03c5b1cSMartin Matuska case ZSTD_c_ldmMinMatch:
472c03c5b1cSMartin Matuska case ZSTD_c_ldmBucketSizeLog:
473c03c5b1cSMartin Matuska case ZSTD_c_ldmHashRateLog:
474c03c5b1cSMartin Matuska case ZSTD_c_forceAttachDict:
475c03c5b1cSMartin Matuska case ZSTD_c_literalCompressionMode:
476c03c5b1cSMartin Matuska case ZSTD_c_targetCBlockSize:
477c03c5b1cSMartin Matuska case ZSTD_c_srcSizeHint:
478c03c5b1cSMartin Matuska default:
479c03c5b1cSMartin Matuska return 0;
480c03c5b1cSMartin Matuska }
481c03c5b1cSMartin Matuska }
482c03c5b1cSMartin Matuska
ZSTD_CCtx_setParameter(ZSTD_CCtx * cctx,ZSTD_cParameter param,int value)483c03c5b1cSMartin Matuska size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
484c03c5b1cSMartin Matuska {
485c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value);
486c03c5b1cSMartin Matuska if (cctx->streamStage != zcss_init) {
487c03c5b1cSMartin Matuska if (ZSTD_isUpdateAuthorized(param)) {
488c03c5b1cSMartin Matuska cctx->cParamsChanged = 1;
489c03c5b1cSMartin Matuska } else {
490c03c5b1cSMartin Matuska RETURN_ERROR(stage_wrong, "can only set params in ctx init stage");
491c03c5b1cSMartin Matuska } }
492c03c5b1cSMartin Matuska
493c03c5b1cSMartin Matuska switch(param)
494c03c5b1cSMartin Matuska {
495c03c5b1cSMartin Matuska case ZSTD_c_nbWorkers:
496c03c5b1cSMartin Matuska RETURN_ERROR_IF((value!=0) && cctx->staticSize, parameter_unsupported,
497c03c5b1cSMartin Matuska "MT not compatible with static alloc");
498c03c5b1cSMartin Matuska break;
499c03c5b1cSMartin Matuska
500c03c5b1cSMartin Matuska case ZSTD_c_compressionLevel:
501c03c5b1cSMartin Matuska case ZSTD_c_windowLog:
502c03c5b1cSMartin Matuska case ZSTD_c_hashLog:
503c03c5b1cSMartin Matuska case ZSTD_c_chainLog:
504c03c5b1cSMartin Matuska case ZSTD_c_searchLog:
505c03c5b1cSMartin Matuska case ZSTD_c_minMatch:
506c03c5b1cSMartin Matuska case ZSTD_c_targetLength:
507c03c5b1cSMartin Matuska case ZSTD_c_strategy:
508c03c5b1cSMartin Matuska case ZSTD_c_ldmHashRateLog:
509c03c5b1cSMartin Matuska case ZSTD_c_format:
510c03c5b1cSMartin Matuska case ZSTD_c_contentSizeFlag:
511c03c5b1cSMartin Matuska case ZSTD_c_checksumFlag:
512c03c5b1cSMartin Matuska case ZSTD_c_dictIDFlag:
513c03c5b1cSMartin Matuska case ZSTD_c_forceMaxWindow:
514c03c5b1cSMartin Matuska case ZSTD_c_forceAttachDict:
515c03c5b1cSMartin Matuska case ZSTD_c_literalCompressionMode:
516c03c5b1cSMartin Matuska case ZSTD_c_jobSize:
517c03c5b1cSMartin Matuska case ZSTD_c_overlapLog:
518c03c5b1cSMartin Matuska case ZSTD_c_rsyncable:
519c03c5b1cSMartin Matuska case ZSTD_c_enableLongDistanceMatching:
520c03c5b1cSMartin Matuska case ZSTD_c_ldmHashLog:
521c03c5b1cSMartin Matuska case ZSTD_c_ldmMinMatch:
522c03c5b1cSMartin Matuska case ZSTD_c_ldmBucketSizeLog:
523c03c5b1cSMartin Matuska case ZSTD_c_targetCBlockSize:
524c03c5b1cSMartin Matuska case ZSTD_c_srcSizeHint:
525c03c5b1cSMartin Matuska break;
526c03c5b1cSMartin Matuska
527c03c5b1cSMartin Matuska default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
528c03c5b1cSMartin Matuska }
529c03c5b1cSMartin Matuska return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value);
530c03c5b1cSMartin Matuska }
531c03c5b1cSMartin Matuska
ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params * CCtxParams,ZSTD_cParameter param,int value)532c03c5b1cSMartin Matuska size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
533c03c5b1cSMartin Matuska ZSTD_cParameter param, int value)
534c03c5b1cSMartin Matuska {
535c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_CCtxParams_setParameter (%i, %i)", (int)param, value);
536c03c5b1cSMartin Matuska switch(param)
537c03c5b1cSMartin Matuska {
538c03c5b1cSMartin Matuska case ZSTD_c_format :
539c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_format, value);
540c03c5b1cSMartin Matuska CCtxParams->format = (ZSTD_format_e)value;
541c03c5b1cSMartin Matuska return (size_t)CCtxParams->format;
542c03c5b1cSMartin Matuska
543c03c5b1cSMartin Matuska case ZSTD_c_compressionLevel : {
544c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
545c03c5b1cSMartin Matuska if (value) { /* 0 : does not change current level */
546c03c5b1cSMartin Matuska CCtxParams->compressionLevel = value;
547c03c5b1cSMartin Matuska }
548c03c5b1cSMartin Matuska if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel;
549c03c5b1cSMartin Matuska return 0; /* return type (size_t) cannot represent negative values */
550c03c5b1cSMartin Matuska }
551c03c5b1cSMartin Matuska
552c03c5b1cSMartin Matuska case ZSTD_c_windowLog :
553c03c5b1cSMartin Matuska if (value!=0) /* 0 => use default */
554c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_windowLog, value);
555c03c5b1cSMartin Matuska CCtxParams->cParams.windowLog = (U32)value;
556c03c5b1cSMartin Matuska return CCtxParams->cParams.windowLog;
557c03c5b1cSMartin Matuska
558c03c5b1cSMartin Matuska case ZSTD_c_hashLog :
559c03c5b1cSMartin Matuska if (value!=0) /* 0 => use default */
560c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_hashLog, value);
561c03c5b1cSMartin Matuska CCtxParams->cParams.hashLog = (U32)value;
562c03c5b1cSMartin Matuska return CCtxParams->cParams.hashLog;
563c03c5b1cSMartin Matuska
564c03c5b1cSMartin Matuska case ZSTD_c_chainLog :
565c03c5b1cSMartin Matuska if (value!=0) /* 0 => use default */
566c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_chainLog, value);
567c03c5b1cSMartin Matuska CCtxParams->cParams.chainLog = (U32)value;
568c03c5b1cSMartin Matuska return CCtxParams->cParams.chainLog;
569c03c5b1cSMartin Matuska
570c03c5b1cSMartin Matuska case ZSTD_c_searchLog :
571c03c5b1cSMartin Matuska if (value!=0) /* 0 => use default */
572c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_searchLog, value);
573c03c5b1cSMartin Matuska CCtxParams->cParams.searchLog = (U32)value;
574c03c5b1cSMartin Matuska return (size_t)value;
575c03c5b1cSMartin Matuska
576c03c5b1cSMartin Matuska case ZSTD_c_minMatch :
577c03c5b1cSMartin Matuska if (value!=0) /* 0 => use default */
578c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_minMatch, value);
579c03c5b1cSMartin Matuska CCtxParams->cParams.minMatch = value;
580c03c5b1cSMartin Matuska return CCtxParams->cParams.minMatch;
581c03c5b1cSMartin Matuska
582c03c5b1cSMartin Matuska case ZSTD_c_targetLength :
583c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_targetLength, value);
584c03c5b1cSMartin Matuska CCtxParams->cParams.targetLength = value;
585c03c5b1cSMartin Matuska return CCtxParams->cParams.targetLength;
586c03c5b1cSMartin Matuska
587c03c5b1cSMartin Matuska case ZSTD_c_strategy :
588c03c5b1cSMartin Matuska if (value!=0) /* 0 => use default */
589c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_strategy, value);
590c03c5b1cSMartin Matuska CCtxParams->cParams.strategy = (ZSTD_strategy)value;
591c03c5b1cSMartin Matuska return (size_t)CCtxParams->cParams.strategy;
592c03c5b1cSMartin Matuska
593c03c5b1cSMartin Matuska case ZSTD_c_contentSizeFlag :
594c03c5b1cSMartin Matuska /* Content size written in frame header _when known_ (default:1) */
595c03c5b1cSMartin Matuska DEBUGLOG(4, "set content size flag = %u", (value!=0));
596c03c5b1cSMartin Matuska CCtxParams->fParams.contentSizeFlag = value != 0;
597c03c5b1cSMartin Matuska return CCtxParams->fParams.contentSizeFlag;
598c03c5b1cSMartin Matuska
599c03c5b1cSMartin Matuska case ZSTD_c_checksumFlag :
600c03c5b1cSMartin Matuska /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
601c03c5b1cSMartin Matuska CCtxParams->fParams.checksumFlag = value != 0;
602c03c5b1cSMartin Matuska return CCtxParams->fParams.checksumFlag;
603c03c5b1cSMartin Matuska
604c03c5b1cSMartin Matuska case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
605c03c5b1cSMartin Matuska DEBUGLOG(4, "set dictIDFlag = %u", (value!=0));
606c03c5b1cSMartin Matuska CCtxParams->fParams.noDictIDFlag = !value;
607c03c5b1cSMartin Matuska return !CCtxParams->fParams.noDictIDFlag;
608c03c5b1cSMartin Matuska
609c03c5b1cSMartin Matuska case ZSTD_c_forceMaxWindow :
610c03c5b1cSMartin Matuska CCtxParams->forceWindow = (value != 0);
611c03c5b1cSMartin Matuska return CCtxParams->forceWindow;
612c03c5b1cSMartin Matuska
613c03c5b1cSMartin Matuska case ZSTD_c_forceAttachDict : {
614c03c5b1cSMartin Matuska const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value;
615c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_forceAttachDict, pref);
616c03c5b1cSMartin Matuska CCtxParams->attachDictPref = pref;
617c03c5b1cSMartin Matuska return CCtxParams->attachDictPref;
618c03c5b1cSMartin Matuska }
619c03c5b1cSMartin Matuska
620c03c5b1cSMartin Matuska case ZSTD_c_literalCompressionMode : {
621c03c5b1cSMartin Matuska const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value;
622c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm);
623c03c5b1cSMartin Matuska CCtxParams->literalCompressionMode = lcm;
624c03c5b1cSMartin Matuska return CCtxParams->literalCompressionMode;
625c03c5b1cSMartin Matuska }
626c03c5b1cSMartin Matuska
627c03c5b1cSMartin Matuska case ZSTD_c_nbWorkers :
628c03c5b1cSMartin Matuska #ifndef ZSTD_MULTITHREAD
629c03c5b1cSMartin Matuska RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
630c03c5b1cSMartin Matuska return 0;
631c03c5b1cSMartin Matuska #else
632c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
633c03c5b1cSMartin Matuska CCtxParams->nbWorkers = value;
634c03c5b1cSMartin Matuska return CCtxParams->nbWorkers;
635c03c5b1cSMartin Matuska #endif
636c03c5b1cSMartin Matuska
637c03c5b1cSMartin Matuska case ZSTD_c_jobSize :
638c03c5b1cSMartin Matuska #ifndef ZSTD_MULTITHREAD
639c03c5b1cSMartin Matuska RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
640c03c5b1cSMartin Matuska return 0;
641c03c5b1cSMartin Matuska #else
642c03c5b1cSMartin Matuska /* Adjust to the minimum non-default value. */
643c03c5b1cSMartin Matuska if (value != 0 && value < ZSTDMT_JOBSIZE_MIN)
644c03c5b1cSMartin Matuska value = ZSTDMT_JOBSIZE_MIN;
645c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
646c03c5b1cSMartin Matuska assert(value >= 0);
647c03c5b1cSMartin Matuska CCtxParams->jobSize = value;
648c03c5b1cSMartin Matuska return CCtxParams->jobSize;
649c03c5b1cSMartin Matuska #endif
650c03c5b1cSMartin Matuska
651c03c5b1cSMartin Matuska case ZSTD_c_overlapLog :
652c03c5b1cSMartin Matuska #ifndef ZSTD_MULTITHREAD
653c03c5b1cSMartin Matuska RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
654c03c5b1cSMartin Matuska return 0;
655c03c5b1cSMartin Matuska #else
656c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), "");
657c03c5b1cSMartin Matuska CCtxParams->overlapLog = value;
658c03c5b1cSMartin Matuska return CCtxParams->overlapLog;
659c03c5b1cSMartin Matuska #endif
660c03c5b1cSMartin Matuska
661c03c5b1cSMartin Matuska case ZSTD_c_rsyncable :
662c03c5b1cSMartin Matuska #ifndef ZSTD_MULTITHREAD
663c03c5b1cSMartin Matuska RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
664c03c5b1cSMartin Matuska return 0;
665c03c5b1cSMartin Matuska #else
666c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), "");
667c03c5b1cSMartin Matuska CCtxParams->rsyncable = value;
668c03c5b1cSMartin Matuska return CCtxParams->rsyncable;
669c03c5b1cSMartin Matuska #endif
670c03c5b1cSMartin Matuska
671c03c5b1cSMartin Matuska case ZSTD_c_enableLongDistanceMatching :
672c03c5b1cSMartin Matuska CCtxParams->ldmParams.enableLdm = (value!=0);
673c03c5b1cSMartin Matuska return CCtxParams->ldmParams.enableLdm;
674c03c5b1cSMartin Matuska
675c03c5b1cSMartin Matuska case ZSTD_c_ldmHashLog :
676c03c5b1cSMartin Matuska if (value!=0) /* 0 ==> auto */
677c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_ldmHashLog, value);
678c03c5b1cSMartin Matuska CCtxParams->ldmParams.hashLog = value;
679c03c5b1cSMartin Matuska return CCtxParams->ldmParams.hashLog;
680c03c5b1cSMartin Matuska
681c03c5b1cSMartin Matuska case ZSTD_c_ldmMinMatch :
682c03c5b1cSMartin Matuska if (value!=0) /* 0 ==> default */
683c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_ldmMinMatch, value);
684c03c5b1cSMartin Matuska CCtxParams->ldmParams.minMatchLength = value;
685c03c5b1cSMartin Matuska return CCtxParams->ldmParams.minMatchLength;
686c03c5b1cSMartin Matuska
687c03c5b1cSMartin Matuska case ZSTD_c_ldmBucketSizeLog :
688c03c5b1cSMartin Matuska if (value!=0) /* 0 ==> default */
689c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value);
690c03c5b1cSMartin Matuska CCtxParams->ldmParams.bucketSizeLog = value;
691c03c5b1cSMartin Matuska return CCtxParams->ldmParams.bucketSizeLog;
692c03c5b1cSMartin Matuska
693c03c5b1cSMartin Matuska case ZSTD_c_ldmHashRateLog :
694c03c5b1cSMartin Matuska RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN,
695c03c5b1cSMartin Matuska parameter_outOfBound, "Param out of bounds!");
696c03c5b1cSMartin Matuska CCtxParams->ldmParams.hashRateLog = value;
697c03c5b1cSMartin Matuska return CCtxParams->ldmParams.hashRateLog;
698c03c5b1cSMartin Matuska
699c03c5b1cSMartin Matuska case ZSTD_c_targetCBlockSize :
700c03c5b1cSMartin Matuska if (value!=0) /* 0 ==> default */
701c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_targetCBlockSize, value);
702c03c5b1cSMartin Matuska CCtxParams->targetCBlockSize = value;
703c03c5b1cSMartin Matuska return CCtxParams->targetCBlockSize;
704c03c5b1cSMartin Matuska
705c03c5b1cSMartin Matuska case ZSTD_c_srcSizeHint :
706c03c5b1cSMartin Matuska if (value!=0) /* 0 ==> default */
707c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_srcSizeHint, value);
708c03c5b1cSMartin Matuska CCtxParams->srcSizeHint = value;
709c03c5b1cSMartin Matuska return CCtxParams->srcSizeHint;
710c03c5b1cSMartin Matuska
711c03c5b1cSMartin Matuska default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
712c03c5b1cSMartin Matuska }
713c03c5b1cSMartin Matuska }
714c03c5b1cSMartin Matuska
ZSTD_CCtx_getParameter(ZSTD_CCtx * cctx,ZSTD_cParameter param,int * value)715c03c5b1cSMartin Matuska size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value)
716c03c5b1cSMartin Matuska {
717c03c5b1cSMartin Matuska return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value);
718c03c5b1cSMartin Matuska }
719c03c5b1cSMartin Matuska
ZSTD_CCtxParams_getParameter(ZSTD_CCtx_params * CCtxParams,ZSTD_cParameter param,int * value)720c03c5b1cSMartin Matuska size_t ZSTD_CCtxParams_getParameter(
721c03c5b1cSMartin Matuska ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value)
722c03c5b1cSMartin Matuska {
723c03c5b1cSMartin Matuska switch(param)
724c03c5b1cSMartin Matuska {
725c03c5b1cSMartin Matuska case ZSTD_c_format :
726c03c5b1cSMartin Matuska *value = CCtxParams->format;
727c03c5b1cSMartin Matuska break;
728c03c5b1cSMartin Matuska case ZSTD_c_compressionLevel :
729c03c5b1cSMartin Matuska *value = CCtxParams->compressionLevel;
730c03c5b1cSMartin Matuska break;
731c03c5b1cSMartin Matuska case ZSTD_c_windowLog :
732c03c5b1cSMartin Matuska *value = (int)CCtxParams->cParams.windowLog;
733c03c5b1cSMartin Matuska break;
734c03c5b1cSMartin Matuska case ZSTD_c_hashLog :
735c03c5b1cSMartin Matuska *value = (int)CCtxParams->cParams.hashLog;
736c03c5b1cSMartin Matuska break;
737c03c5b1cSMartin Matuska case ZSTD_c_chainLog :
738c03c5b1cSMartin Matuska *value = (int)CCtxParams->cParams.chainLog;
739c03c5b1cSMartin Matuska break;
740c03c5b1cSMartin Matuska case ZSTD_c_searchLog :
741c03c5b1cSMartin Matuska *value = CCtxParams->cParams.searchLog;
742c03c5b1cSMartin Matuska break;
743c03c5b1cSMartin Matuska case ZSTD_c_minMatch :
744c03c5b1cSMartin Matuska *value = CCtxParams->cParams.minMatch;
745c03c5b1cSMartin Matuska break;
746c03c5b1cSMartin Matuska case ZSTD_c_targetLength :
747c03c5b1cSMartin Matuska *value = CCtxParams->cParams.targetLength;
748c03c5b1cSMartin Matuska break;
749c03c5b1cSMartin Matuska case ZSTD_c_strategy :
750c03c5b1cSMartin Matuska *value = (unsigned)CCtxParams->cParams.strategy;
751c03c5b1cSMartin Matuska break;
752c03c5b1cSMartin Matuska case ZSTD_c_contentSizeFlag :
753c03c5b1cSMartin Matuska *value = CCtxParams->fParams.contentSizeFlag;
754c03c5b1cSMartin Matuska break;
755c03c5b1cSMartin Matuska case ZSTD_c_checksumFlag :
756c03c5b1cSMartin Matuska *value = CCtxParams->fParams.checksumFlag;
757c03c5b1cSMartin Matuska break;
758c03c5b1cSMartin Matuska case ZSTD_c_dictIDFlag :
759c03c5b1cSMartin Matuska *value = !CCtxParams->fParams.noDictIDFlag;
760c03c5b1cSMartin Matuska break;
761c03c5b1cSMartin Matuska case ZSTD_c_forceMaxWindow :
762c03c5b1cSMartin Matuska *value = CCtxParams->forceWindow;
763c03c5b1cSMartin Matuska break;
764c03c5b1cSMartin Matuska case ZSTD_c_forceAttachDict :
765c03c5b1cSMartin Matuska *value = CCtxParams->attachDictPref;
766c03c5b1cSMartin Matuska break;
767c03c5b1cSMartin Matuska case ZSTD_c_literalCompressionMode :
768c03c5b1cSMartin Matuska *value = CCtxParams->literalCompressionMode;
769c03c5b1cSMartin Matuska break;
770c03c5b1cSMartin Matuska case ZSTD_c_nbWorkers :
771c03c5b1cSMartin Matuska #ifndef ZSTD_MULTITHREAD
772c03c5b1cSMartin Matuska assert(CCtxParams->nbWorkers == 0);
773c03c5b1cSMartin Matuska #endif
774c03c5b1cSMartin Matuska *value = CCtxParams->nbWorkers;
775c03c5b1cSMartin Matuska break;
776c03c5b1cSMartin Matuska case ZSTD_c_jobSize :
777c03c5b1cSMartin Matuska #ifndef ZSTD_MULTITHREAD
778c03c5b1cSMartin Matuska RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
779c03c5b1cSMartin Matuska #else
780c03c5b1cSMartin Matuska assert(CCtxParams->jobSize <= INT_MAX);
781c03c5b1cSMartin Matuska *value = (int)CCtxParams->jobSize;
782c03c5b1cSMartin Matuska break;
783c03c5b1cSMartin Matuska #endif
784c03c5b1cSMartin Matuska case ZSTD_c_overlapLog :
785c03c5b1cSMartin Matuska #ifndef ZSTD_MULTITHREAD
786c03c5b1cSMartin Matuska RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
787c03c5b1cSMartin Matuska #else
788c03c5b1cSMartin Matuska *value = CCtxParams->overlapLog;
789c03c5b1cSMartin Matuska break;
790c03c5b1cSMartin Matuska #endif
791c03c5b1cSMartin Matuska case ZSTD_c_rsyncable :
792c03c5b1cSMartin Matuska #ifndef ZSTD_MULTITHREAD
793c03c5b1cSMartin Matuska RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
794c03c5b1cSMartin Matuska #else
795c03c5b1cSMartin Matuska *value = CCtxParams->rsyncable;
796c03c5b1cSMartin Matuska break;
797c03c5b1cSMartin Matuska #endif
798c03c5b1cSMartin Matuska case ZSTD_c_enableLongDistanceMatching :
799c03c5b1cSMartin Matuska *value = CCtxParams->ldmParams.enableLdm;
800c03c5b1cSMartin Matuska break;
801c03c5b1cSMartin Matuska case ZSTD_c_ldmHashLog :
802c03c5b1cSMartin Matuska *value = CCtxParams->ldmParams.hashLog;
803c03c5b1cSMartin Matuska break;
804c03c5b1cSMartin Matuska case ZSTD_c_ldmMinMatch :
805c03c5b1cSMartin Matuska *value = CCtxParams->ldmParams.minMatchLength;
806c03c5b1cSMartin Matuska break;
807c03c5b1cSMartin Matuska case ZSTD_c_ldmBucketSizeLog :
808c03c5b1cSMartin Matuska *value = CCtxParams->ldmParams.bucketSizeLog;
809c03c5b1cSMartin Matuska break;
810c03c5b1cSMartin Matuska case ZSTD_c_ldmHashRateLog :
811c03c5b1cSMartin Matuska *value = CCtxParams->ldmParams.hashRateLog;
812c03c5b1cSMartin Matuska break;
813c03c5b1cSMartin Matuska case ZSTD_c_targetCBlockSize :
814c03c5b1cSMartin Matuska *value = (int)CCtxParams->targetCBlockSize;
815c03c5b1cSMartin Matuska break;
816c03c5b1cSMartin Matuska case ZSTD_c_srcSizeHint :
817c03c5b1cSMartin Matuska *value = (int)CCtxParams->srcSizeHint;
818c03c5b1cSMartin Matuska break;
819c03c5b1cSMartin Matuska default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
820c03c5b1cSMartin Matuska }
821c03c5b1cSMartin Matuska return 0;
822c03c5b1cSMartin Matuska }
823c03c5b1cSMartin Matuska
824c03c5b1cSMartin Matuska /** ZSTD_CCtx_setParametersUsingCCtxParams() :
825c03c5b1cSMartin Matuska * just applies `params` into `cctx`
826c03c5b1cSMartin Matuska * no action is performed, parameters are merely stored.
827c03c5b1cSMartin Matuska * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx.
828c03c5b1cSMartin Matuska * This is possible even if a compression is ongoing.
829c03c5b1cSMartin Matuska * In which case, new parameters will be applied on the fly, starting with next compression job.
830c03c5b1cSMartin Matuska */
ZSTD_CCtx_setParametersUsingCCtxParams(ZSTD_CCtx * cctx,const ZSTD_CCtx_params * params)831c03c5b1cSMartin Matuska size_t ZSTD_CCtx_setParametersUsingCCtxParams(
832c03c5b1cSMartin Matuska ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
833c03c5b1cSMartin Matuska {
834c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams");
835c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
836c03c5b1cSMartin Matuska "The context is in the wrong stage!");
837c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->cdict, stage_wrong,
838c03c5b1cSMartin Matuska "Can't override parameters with cdict attached (some must "
839c03c5b1cSMartin Matuska "be inherited from the cdict).");
840c03c5b1cSMartin Matuska
841c03c5b1cSMartin Matuska cctx->requestedParams = *params;
842c03c5b1cSMartin Matuska return 0;
843c03c5b1cSMartin Matuska }
844c03c5b1cSMartin Matuska
ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx * cctx,unsigned long long pledgedSrcSize)845c03c5b1cSMartin Matuska ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
846c03c5b1cSMartin Matuska {
847c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize);
848c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
849c03c5b1cSMartin Matuska "Can't set pledgedSrcSize when not in init stage.");
850c03c5b1cSMartin Matuska cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
851c03c5b1cSMartin Matuska return 0;
852c03c5b1cSMartin Matuska }
853c03c5b1cSMartin Matuska
854c03c5b1cSMartin Matuska /**
855c03c5b1cSMartin Matuska * Initializes the local dict using the requested parameters.
856c03c5b1cSMartin Matuska * NOTE: This does not use the pledged src size, because it may be used for more
857c03c5b1cSMartin Matuska * than one compression.
858c03c5b1cSMartin Matuska */
ZSTD_initLocalDict(ZSTD_CCtx * cctx)859c03c5b1cSMartin Matuska static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
860c03c5b1cSMartin Matuska {
861c03c5b1cSMartin Matuska ZSTD_localDict* const dl = &cctx->localDict;
862c03c5b1cSMartin Matuska ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(
863c03c5b1cSMartin Matuska &cctx->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN, dl->dictSize);
864c03c5b1cSMartin Matuska if (dl->dict == NULL) {
865c03c5b1cSMartin Matuska /* No local dictionary. */
866c03c5b1cSMartin Matuska assert(dl->dictBuffer == NULL);
867c03c5b1cSMartin Matuska assert(dl->cdict == NULL);
868c03c5b1cSMartin Matuska assert(dl->dictSize == 0);
869c03c5b1cSMartin Matuska return 0;
870c03c5b1cSMartin Matuska }
871c03c5b1cSMartin Matuska if (dl->cdict != NULL) {
872c03c5b1cSMartin Matuska assert(cctx->cdict == dl->cdict);
873c03c5b1cSMartin Matuska /* Local dictionary already initialized. */
874c03c5b1cSMartin Matuska return 0;
875c03c5b1cSMartin Matuska }
876c03c5b1cSMartin Matuska assert(dl->dictSize > 0);
877c03c5b1cSMartin Matuska assert(cctx->cdict == NULL);
878c03c5b1cSMartin Matuska assert(cctx->prefixDict.dict == NULL);
879c03c5b1cSMartin Matuska
880c03c5b1cSMartin Matuska dl->cdict = ZSTD_createCDict_advanced(
881c03c5b1cSMartin Matuska dl->dict,
882c03c5b1cSMartin Matuska dl->dictSize,
883c03c5b1cSMartin Matuska ZSTD_dlm_byRef,
884c03c5b1cSMartin Matuska dl->dictContentType,
885c03c5b1cSMartin Matuska cParams,
886c03c5b1cSMartin Matuska cctx->customMem);
887c03c5b1cSMartin Matuska RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed");
888c03c5b1cSMartin Matuska cctx->cdict = dl->cdict;
889c03c5b1cSMartin Matuska return 0;
890c03c5b1cSMartin Matuska }
891c03c5b1cSMartin Matuska
ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx * cctx,const void * dict,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType)892c03c5b1cSMartin Matuska size_t ZSTD_CCtx_loadDictionary_advanced(
893c03c5b1cSMartin Matuska ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
894c03c5b1cSMartin Matuska ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType)
895c03c5b1cSMartin Matuska {
896c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
897c03c5b1cSMartin Matuska "Can't load a dictionary when ctx is not in init stage.");
898c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
899c03c5b1cSMartin Matuska "no malloc for static CCtx");
900c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
901c03c5b1cSMartin Matuska ZSTD_clearAllDicts(cctx); /* in case one already exists */
902c03c5b1cSMartin Matuska if (dict == NULL || dictSize == 0) /* no dictionary mode */
903c03c5b1cSMartin Matuska return 0;
904c03c5b1cSMartin Matuska if (dictLoadMethod == ZSTD_dlm_byRef) {
905c03c5b1cSMartin Matuska cctx->localDict.dict = dict;
906c03c5b1cSMartin Matuska } else {
907c03c5b1cSMartin Matuska void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem);
908c03c5b1cSMartin Matuska RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!");
909c03c5b1cSMartin Matuska memcpy(dictBuffer, dict, dictSize);
910c03c5b1cSMartin Matuska cctx->localDict.dictBuffer = dictBuffer;
911c03c5b1cSMartin Matuska cctx->localDict.dict = dictBuffer;
912c03c5b1cSMartin Matuska }
913c03c5b1cSMartin Matuska cctx->localDict.dictSize = dictSize;
914c03c5b1cSMartin Matuska cctx->localDict.dictContentType = dictContentType;
915c03c5b1cSMartin Matuska return 0;
916c03c5b1cSMartin Matuska }
917c03c5b1cSMartin Matuska
ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx * cctx,const void * dict,size_t dictSize)918c03c5b1cSMartin Matuska ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
919c03c5b1cSMartin Matuska ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
920c03c5b1cSMartin Matuska {
921c03c5b1cSMartin Matuska return ZSTD_CCtx_loadDictionary_advanced(
922c03c5b1cSMartin Matuska cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
923c03c5b1cSMartin Matuska }
924c03c5b1cSMartin Matuska
ZSTD_CCtx_loadDictionary(ZSTD_CCtx * cctx,const void * dict,size_t dictSize)925c03c5b1cSMartin Matuska ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
926c03c5b1cSMartin Matuska {
927c03c5b1cSMartin Matuska return ZSTD_CCtx_loadDictionary_advanced(
928c03c5b1cSMartin Matuska cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
929c03c5b1cSMartin Matuska }
930c03c5b1cSMartin Matuska
931c03c5b1cSMartin Matuska
ZSTD_CCtx_refCDict(ZSTD_CCtx * cctx,const ZSTD_CDict * cdict)932c03c5b1cSMartin Matuska size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
933c03c5b1cSMartin Matuska {
934c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
935c03c5b1cSMartin Matuska "Can't ref a dict when ctx not in init stage.");
936c03c5b1cSMartin Matuska /* Free the existing local cdict (if any) to save memory. */
937c03c5b1cSMartin Matuska ZSTD_clearAllDicts(cctx);
938c03c5b1cSMartin Matuska cctx->cdict = cdict;
939c03c5b1cSMartin Matuska return 0;
940c03c5b1cSMartin Matuska }
941c03c5b1cSMartin Matuska
ZSTD_CCtx_refPrefix(ZSTD_CCtx * cctx,const void * prefix,size_t prefixSize)942c03c5b1cSMartin Matuska size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
943c03c5b1cSMartin Matuska {
944c03c5b1cSMartin Matuska return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
945c03c5b1cSMartin Matuska }
946c03c5b1cSMartin Matuska
ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx * cctx,const void * prefix,size_t prefixSize,ZSTD_dictContentType_e dictContentType)947c03c5b1cSMartin Matuska size_t ZSTD_CCtx_refPrefix_advanced(
948c03c5b1cSMartin Matuska ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
949c03c5b1cSMartin Matuska {
950c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
951c03c5b1cSMartin Matuska "Can't ref a prefix when ctx not in init stage.");
952c03c5b1cSMartin Matuska ZSTD_clearAllDicts(cctx);
953c03c5b1cSMartin Matuska if (prefix != NULL && prefixSize > 0) {
954c03c5b1cSMartin Matuska cctx->prefixDict.dict = prefix;
955c03c5b1cSMartin Matuska cctx->prefixDict.dictSize = prefixSize;
956c03c5b1cSMartin Matuska cctx->prefixDict.dictContentType = dictContentType;
957c03c5b1cSMartin Matuska }
958c03c5b1cSMartin Matuska return 0;
959c03c5b1cSMartin Matuska }
960c03c5b1cSMartin Matuska
961c03c5b1cSMartin Matuska /*! ZSTD_CCtx_reset() :
962c03c5b1cSMartin Matuska * Also dumps dictionary */
ZSTD_CCtx_reset(ZSTD_CCtx * cctx,ZSTD_ResetDirective reset)963c03c5b1cSMartin Matuska size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset)
964c03c5b1cSMartin Matuska {
965c03c5b1cSMartin Matuska if ( (reset == ZSTD_reset_session_only)
966c03c5b1cSMartin Matuska || (reset == ZSTD_reset_session_and_parameters) ) {
967c03c5b1cSMartin Matuska cctx->streamStage = zcss_init;
968c03c5b1cSMartin Matuska cctx->pledgedSrcSizePlusOne = 0;
969c03c5b1cSMartin Matuska }
970c03c5b1cSMartin Matuska if ( (reset == ZSTD_reset_parameters)
971c03c5b1cSMartin Matuska || (reset == ZSTD_reset_session_and_parameters) ) {
972c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
973c03c5b1cSMartin Matuska "Can't reset parameters only when not in init stage.");
974c03c5b1cSMartin Matuska ZSTD_clearAllDicts(cctx);
975c03c5b1cSMartin Matuska return ZSTD_CCtxParams_reset(&cctx->requestedParams);
976c03c5b1cSMartin Matuska }
977c03c5b1cSMartin Matuska return 0;
978c03c5b1cSMartin Matuska }
979c03c5b1cSMartin Matuska
980c03c5b1cSMartin Matuska
981c03c5b1cSMartin Matuska /** ZSTD_checkCParams() :
982c03c5b1cSMartin Matuska control CParam values remain within authorized range.
983c03c5b1cSMartin Matuska @return : 0, or an error code if one value is beyond authorized range */
ZSTD_checkCParams(ZSTD_compressionParameters cParams)984c03c5b1cSMartin Matuska size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
985c03c5b1cSMartin Matuska {
986c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog);
987c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_chainLog, (int)cParams.chainLog);
988c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_hashLog, (int)cParams.hashLog);
989c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog);
990c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_minMatch, (int)cParams.minMatch);
991c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_targetLength,(int)cParams.targetLength);
992c03c5b1cSMartin Matuska BOUNDCHECK(ZSTD_c_strategy, cParams.strategy);
993c03c5b1cSMartin Matuska return 0;
994c03c5b1cSMartin Matuska }
995c03c5b1cSMartin Matuska
996c03c5b1cSMartin Matuska /** ZSTD_clampCParams() :
997c03c5b1cSMartin Matuska * make CParam values within valid range.
998c03c5b1cSMartin Matuska * @return : valid CParams */
999c03c5b1cSMartin Matuska static ZSTD_compressionParameters
ZSTD_clampCParams(ZSTD_compressionParameters cParams)1000c03c5b1cSMartin Matuska ZSTD_clampCParams(ZSTD_compressionParameters cParams)
1001c03c5b1cSMartin Matuska {
1002c03c5b1cSMartin Matuska # define CLAMP_TYPE(cParam, val, type) { \
1003c03c5b1cSMartin Matuska ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \
1004c03c5b1cSMartin Matuska if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \
1005c03c5b1cSMartin Matuska else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \
1006c03c5b1cSMartin Matuska }
1007c03c5b1cSMartin Matuska # define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned)
1008c03c5b1cSMartin Matuska CLAMP(ZSTD_c_windowLog, cParams.windowLog);
1009c03c5b1cSMartin Matuska CLAMP(ZSTD_c_chainLog, cParams.chainLog);
1010c03c5b1cSMartin Matuska CLAMP(ZSTD_c_hashLog, cParams.hashLog);
1011c03c5b1cSMartin Matuska CLAMP(ZSTD_c_searchLog, cParams.searchLog);
1012c03c5b1cSMartin Matuska CLAMP(ZSTD_c_minMatch, cParams.minMatch);
1013c03c5b1cSMartin Matuska CLAMP(ZSTD_c_targetLength,cParams.targetLength);
1014c03c5b1cSMartin Matuska CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy);
1015c03c5b1cSMartin Matuska return cParams;
1016c03c5b1cSMartin Matuska }
1017c03c5b1cSMartin Matuska
1018c03c5b1cSMartin Matuska /** ZSTD_cycleLog() :
1019c03c5b1cSMartin Matuska * condition for correct operation : hashLog > 1 */
ZSTD_cycleLog(U32 hashLog,ZSTD_strategy strat)1020c03c5b1cSMartin Matuska U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
1021c03c5b1cSMartin Matuska {
1022c03c5b1cSMartin Matuska U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
1023c03c5b1cSMartin Matuska return hashLog - btScale;
1024c03c5b1cSMartin Matuska }
1025c03c5b1cSMartin Matuska
1026c03c5b1cSMartin Matuska /** ZSTD_adjustCParams_internal() :
1027c03c5b1cSMartin Matuska * optimize `cPar` for a specified input (`srcSize` and `dictSize`).
1028c03c5b1cSMartin Matuska * mostly downsize to reduce memory consumption and initialization latency.
1029c03c5b1cSMartin Matuska * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known.
1030c03c5b1cSMartin Matuska * note : `srcSize==0` means 0!
1031c03c5b1cSMartin Matuska * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */
1032c03c5b1cSMartin Matuska static ZSTD_compressionParameters
ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,unsigned long long srcSize,size_t dictSize)1033c03c5b1cSMartin Matuska ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
1034c03c5b1cSMartin Matuska unsigned long long srcSize,
1035c03c5b1cSMartin Matuska size_t dictSize)
1036c03c5b1cSMartin Matuska {
1037c03c5b1cSMartin Matuska static const U64 minSrcSize = 513; /* (1<<9) + 1 */
1038c03c5b1cSMartin Matuska static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
1039c03c5b1cSMartin Matuska assert(ZSTD_checkCParams(cPar)==0);
1040c03c5b1cSMartin Matuska
1041c03c5b1cSMartin Matuska if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
1042c03c5b1cSMartin Matuska srcSize = minSrcSize;
1043c03c5b1cSMartin Matuska
1044c03c5b1cSMartin Matuska /* resize windowLog if input is small enough, to use less memory */
1045c03c5b1cSMartin Matuska if ( (srcSize < maxWindowResize)
1046c03c5b1cSMartin Matuska && (dictSize < maxWindowResize) ) {
1047c03c5b1cSMartin Matuska U32 const tSize = (U32)(srcSize + dictSize);
1048c03c5b1cSMartin Matuska static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN;
1049c03c5b1cSMartin Matuska U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN :
1050c03c5b1cSMartin Matuska ZSTD_highbit32(tSize-1) + 1;
1051c03c5b1cSMartin Matuska if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
1052c03c5b1cSMartin Matuska }
1053c03c5b1cSMartin Matuska if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1;
1054c03c5b1cSMartin Matuska { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
1055c03c5b1cSMartin Matuska if (cycleLog > cPar.windowLog)
1056c03c5b1cSMartin Matuska cPar.chainLog -= (cycleLog - cPar.windowLog);
1057c03c5b1cSMartin Matuska }
1058c03c5b1cSMartin Matuska
1059c03c5b1cSMartin Matuska if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
1060c03c5b1cSMartin Matuska cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */
1061c03c5b1cSMartin Matuska
1062c03c5b1cSMartin Matuska return cPar;
1063c03c5b1cSMartin Matuska }
1064c03c5b1cSMartin Matuska
1065c03c5b1cSMartin Matuska ZSTD_compressionParameters
ZSTD_adjustCParams(ZSTD_compressionParameters cPar,unsigned long long srcSize,size_t dictSize)1066c03c5b1cSMartin Matuska ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
1067c03c5b1cSMartin Matuska unsigned long long srcSize,
1068c03c5b1cSMartin Matuska size_t dictSize)
1069c03c5b1cSMartin Matuska {
1070c03c5b1cSMartin Matuska cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */
1071c03c5b1cSMartin Matuska if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN;
1072c03c5b1cSMartin Matuska return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
1073c03c5b1cSMartin Matuska }
1074c03c5b1cSMartin Matuska
1075c03c5b1cSMartin Matuska static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize);
1076c03c5b1cSMartin Matuska static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize);
1077c03c5b1cSMartin Matuska
ZSTD_getCParamsFromCCtxParams(const ZSTD_CCtx_params * CCtxParams,U64 srcSizeHint,size_t dictSize)1078c03c5b1cSMartin Matuska ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
1079c03c5b1cSMartin Matuska const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
1080c03c5b1cSMartin Matuska {
1081c03c5b1cSMartin Matuska ZSTD_compressionParameters cParams;
1082c03c5b1cSMartin Matuska if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) {
1083c03c5b1cSMartin Matuska srcSizeHint = CCtxParams->srcSizeHint;
1084c03c5b1cSMartin Matuska }
1085c03c5b1cSMartin Matuska cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize);
1086c03c5b1cSMartin Matuska if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
1087c03c5b1cSMartin Matuska if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
1088c03c5b1cSMartin Matuska if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
1089c03c5b1cSMartin Matuska if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
1090c03c5b1cSMartin Matuska if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
1091c03c5b1cSMartin Matuska if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch;
1092c03c5b1cSMartin Matuska if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
1093c03c5b1cSMartin Matuska if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
1094c03c5b1cSMartin Matuska assert(!ZSTD_checkCParams(cParams));
1095c03c5b1cSMartin Matuska /* srcSizeHint == 0 means 0 */
1096c03c5b1cSMartin Matuska return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize);
1097c03c5b1cSMartin Matuska }
1098c03c5b1cSMartin Matuska
1099c03c5b1cSMartin Matuska static size_t
ZSTD_sizeof_matchState(const ZSTD_compressionParameters * const cParams,const U32 forCCtx)1100c03c5b1cSMartin Matuska ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
1101c03c5b1cSMartin Matuska const U32 forCCtx)
1102c03c5b1cSMartin Matuska {
1103c03c5b1cSMartin Matuska size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
1104c03c5b1cSMartin Matuska size_t const hSize = ((size_t)1) << cParams->hashLog;
1105c03c5b1cSMartin Matuska U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
1106c03c5b1cSMartin Matuska size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
1107c03c5b1cSMartin Matuska /* We don't use ZSTD_cwksp_alloc_size() here because the tables aren't
1108c03c5b1cSMartin Matuska * surrounded by redzones in ASAN. */
1109c03c5b1cSMartin Matuska size_t const tableSpace = chainSize * sizeof(U32)
1110c03c5b1cSMartin Matuska + hSize * sizeof(U32)
1111c03c5b1cSMartin Matuska + h3Size * sizeof(U32);
1112c03c5b1cSMartin Matuska size_t const optPotentialSpace =
1113c03c5b1cSMartin Matuska ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32))
1114c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32))
1115c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32))
1116c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size((1<<Litbits) * sizeof(U32))
1117c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
1118c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
1119c03c5b1cSMartin Matuska size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
1120c03c5b1cSMartin Matuska ? optPotentialSpace
1121c03c5b1cSMartin Matuska : 0;
1122c03c5b1cSMartin Matuska DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
1123c03c5b1cSMartin Matuska (U32)chainSize, (U32)hSize, (U32)h3Size);
1124c03c5b1cSMartin Matuska return tableSpace + optSpace;
1125c03c5b1cSMartin Matuska }
1126c03c5b1cSMartin Matuska
ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params * params)1127c03c5b1cSMartin Matuska size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1128c03c5b1cSMartin Matuska {
1129c03c5b1cSMartin Matuska RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
1130c03c5b1cSMartin Matuska { ZSTD_compressionParameters const cParams =
1131c03c5b1cSMartin Matuska ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
1132c03c5b1cSMartin Matuska size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
1133c03c5b1cSMartin Matuska U32 const divider = (cParams.minMatch==3) ? 3 : 4;
1134c03c5b1cSMartin Matuska size_t const maxNbSeq = blockSize / divider;
1135c03c5b1cSMartin Matuska size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
1136c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
1137c03c5b1cSMartin Matuska + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
1138c03c5b1cSMartin Matuska size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
1139c03c5b1cSMartin Matuska size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
1140c03c5b1cSMartin Matuska size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
1141c03c5b1cSMartin Matuska
1142c03c5b1cSMartin Matuska size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
1143c03c5b1cSMartin Matuska size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq));
1144c03c5b1cSMartin Matuska
1145c03c5b1cSMartin Matuska /* estimateCCtxSize is for one-shot compression. So no buffers should
1146c03c5b1cSMartin Matuska * be needed. However, we still allocate two 0-sized buffers, which can
1147c03c5b1cSMartin Matuska * take space under ASAN. */
1148c03c5b1cSMartin Matuska size_t const bufferSpace = ZSTD_cwksp_alloc_size(0)
1149c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size(0);
1150c03c5b1cSMartin Matuska
1151c03c5b1cSMartin Matuska size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx));
1152c03c5b1cSMartin Matuska
1153c03c5b1cSMartin Matuska size_t const neededSpace =
1154c03c5b1cSMartin Matuska cctxSpace +
1155c03c5b1cSMartin Matuska entropySpace +
1156c03c5b1cSMartin Matuska blockStateSpace +
1157c03c5b1cSMartin Matuska ldmSpace +
1158c03c5b1cSMartin Matuska ldmSeqSpace +
1159c03c5b1cSMartin Matuska matchStateSize +
1160c03c5b1cSMartin Matuska tokenSpace +
1161c03c5b1cSMartin Matuska bufferSpace;
1162c03c5b1cSMartin Matuska
1163c03c5b1cSMartin Matuska DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
1164c03c5b1cSMartin Matuska return neededSpace;
1165c03c5b1cSMartin Matuska }
1166c03c5b1cSMartin Matuska }
1167c03c5b1cSMartin Matuska
ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)1168c03c5b1cSMartin Matuska size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
1169c03c5b1cSMartin Matuska {
1170c03c5b1cSMartin Matuska ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
1171c03c5b1cSMartin Matuska return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms);
1172c03c5b1cSMartin Matuska }
1173c03c5b1cSMartin Matuska
ZSTD_estimateCCtxSize_internal(int compressionLevel)1174c03c5b1cSMartin Matuska static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
1175c03c5b1cSMartin Matuska {
1176c03c5b1cSMartin Matuska ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
1177c03c5b1cSMartin Matuska return ZSTD_estimateCCtxSize_usingCParams(cParams);
1178c03c5b1cSMartin Matuska }
1179c03c5b1cSMartin Matuska
ZSTD_estimateCCtxSize(int compressionLevel)1180c03c5b1cSMartin Matuska size_t ZSTD_estimateCCtxSize(int compressionLevel)
1181c03c5b1cSMartin Matuska {
1182c03c5b1cSMartin Matuska int level;
1183c03c5b1cSMartin Matuska size_t memBudget = 0;
1184c03c5b1cSMartin Matuska for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
1185c03c5b1cSMartin Matuska size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
1186c03c5b1cSMartin Matuska if (newMB > memBudget) memBudget = newMB;
1187c03c5b1cSMartin Matuska }
1188c03c5b1cSMartin Matuska return memBudget;
1189c03c5b1cSMartin Matuska }
1190c03c5b1cSMartin Matuska
ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params * params)1191c03c5b1cSMartin Matuska size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1192c03c5b1cSMartin Matuska {
1193c03c5b1cSMartin Matuska RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
1194c03c5b1cSMartin Matuska { ZSTD_compressionParameters const cParams =
1195c03c5b1cSMartin Matuska ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
1196c03c5b1cSMartin Matuska size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
1197c03c5b1cSMartin Matuska size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
1198c03c5b1cSMartin Matuska size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
1199c03c5b1cSMartin Matuska size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
1200c03c5b1cSMartin Matuska size_t const streamingSize = ZSTD_cwksp_alloc_size(inBuffSize)
1201c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size(outBuffSize);
1202c03c5b1cSMartin Matuska
1203c03c5b1cSMartin Matuska return CCtxSize + streamingSize;
1204c03c5b1cSMartin Matuska }
1205c03c5b1cSMartin Matuska }
1206c03c5b1cSMartin Matuska
ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)1207c03c5b1cSMartin Matuska size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
1208c03c5b1cSMartin Matuska {
1209c03c5b1cSMartin Matuska ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
1210c03c5b1cSMartin Matuska return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms);
1211c03c5b1cSMartin Matuska }
1212c03c5b1cSMartin Matuska
ZSTD_estimateCStreamSize_internal(int compressionLevel)1213c03c5b1cSMartin Matuska static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
1214c03c5b1cSMartin Matuska {
1215c03c5b1cSMartin Matuska ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
1216c03c5b1cSMartin Matuska return ZSTD_estimateCStreamSize_usingCParams(cParams);
1217c03c5b1cSMartin Matuska }
1218c03c5b1cSMartin Matuska
ZSTD_estimateCStreamSize(int compressionLevel)1219c03c5b1cSMartin Matuska size_t ZSTD_estimateCStreamSize(int compressionLevel)
1220c03c5b1cSMartin Matuska {
1221c03c5b1cSMartin Matuska int level;
1222c03c5b1cSMartin Matuska size_t memBudget = 0;
1223c03c5b1cSMartin Matuska for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
1224c03c5b1cSMartin Matuska size_t const newMB = ZSTD_estimateCStreamSize_internal(level);
1225c03c5b1cSMartin Matuska if (newMB > memBudget) memBudget = newMB;
1226c03c5b1cSMartin Matuska }
1227c03c5b1cSMartin Matuska return memBudget;
1228c03c5b1cSMartin Matuska }
1229c03c5b1cSMartin Matuska
1230c03c5b1cSMartin Matuska /* ZSTD_getFrameProgression():
1231c03c5b1cSMartin Matuska * tells how much data has been consumed (input) and produced (output) for current frame.
1232c03c5b1cSMartin Matuska * able to count progression inside worker threads (non-blocking mode).
1233c03c5b1cSMartin Matuska */
ZSTD_getFrameProgression(const ZSTD_CCtx * cctx)1234c03c5b1cSMartin Matuska ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
1235c03c5b1cSMartin Matuska {
1236c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
1237c03c5b1cSMartin Matuska if (cctx->appliedParams.nbWorkers > 0) {
1238c03c5b1cSMartin Matuska return ZSTDMT_getFrameProgression(cctx->mtctx);
1239c03c5b1cSMartin Matuska }
1240c03c5b1cSMartin Matuska #endif
1241c03c5b1cSMartin Matuska { ZSTD_frameProgression fp;
1242c03c5b1cSMartin Matuska size_t const buffered = (cctx->inBuff == NULL) ? 0 :
1243c03c5b1cSMartin Matuska cctx->inBuffPos - cctx->inToCompress;
1244c03c5b1cSMartin Matuska if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
1245c03c5b1cSMartin Matuska assert(buffered <= ZSTD_BLOCKSIZE_MAX);
1246c03c5b1cSMartin Matuska fp.ingested = cctx->consumedSrcSize + buffered;
1247c03c5b1cSMartin Matuska fp.consumed = cctx->consumedSrcSize;
1248c03c5b1cSMartin Matuska fp.produced = cctx->producedCSize;
1249c03c5b1cSMartin Matuska fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */
1250c03c5b1cSMartin Matuska fp.currentJobID = 0;
1251c03c5b1cSMartin Matuska fp.nbActiveWorkers = 0;
1252c03c5b1cSMartin Matuska return fp;
1253c03c5b1cSMartin Matuska } }
1254c03c5b1cSMartin Matuska
1255c03c5b1cSMartin Matuska /*! ZSTD_toFlushNow()
1256c03c5b1cSMartin Matuska * Only useful for multithreading scenarios currently (nbWorkers >= 1).
1257c03c5b1cSMartin Matuska */
ZSTD_toFlushNow(ZSTD_CCtx * cctx)1258c03c5b1cSMartin Matuska size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx)
1259c03c5b1cSMartin Matuska {
1260c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
1261c03c5b1cSMartin Matuska if (cctx->appliedParams.nbWorkers > 0) {
1262c03c5b1cSMartin Matuska return ZSTDMT_toFlushNow(cctx->mtctx);
1263c03c5b1cSMartin Matuska }
1264c03c5b1cSMartin Matuska #endif
1265c03c5b1cSMartin Matuska (void)cctx;
1266c03c5b1cSMartin Matuska return 0; /* over-simplification; could also check if context is currently running in streaming mode, and in which case, report how many bytes are left to be flushed within output buffer */
1267c03c5b1cSMartin Matuska }
1268c03c5b1cSMartin Matuska
ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1,ZSTD_compressionParameters cParams2)1269c03c5b1cSMartin Matuska static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1,
1270c03c5b1cSMartin Matuska ZSTD_compressionParameters cParams2)
1271c03c5b1cSMartin Matuska {
1272c03c5b1cSMartin Matuska (void)cParams1;
1273c03c5b1cSMartin Matuska (void)cParams2;
1274c03c5b1cSMartin Matuska assert(cParams1.windowLog == cParams2.windowLog);
1275c03c5b1cSMartin Matuska assert(cParams1.chainLog == cParams2.chainLog);
1276c03c5b1cSMartin Matuska assert(cParams1.hashLog == cParams2.hashLog);
1277c03c5b1cSMartin Matuska assert(cParams1.searchLog == cParams2.searchLog);
1278c03c5b1cSMartin Matuska assert(cParams1.minMatch == cParams2.minMatch);
1279c03c5b1cSMartin Matuska assert(cParams1.targetLength == cParams2.targetLength);
1280c03c5b1cSMartin Matuska assert(cParams1.strategy == cParams2.strategy);
1281c03c5b1cSMartin Matuska }
1282c03c5b1cSMartin Matuska
ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t * bs)1283c03c5b1cSMartin Matuska void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
1284c03c5b1cSMartin Matuska {
1285c03c5b1cSMartin Matuska int i;
1286c03c5b1cSMartin Matuska for (i = 0; i < ZSTD_REP_NUM; ++i)
1287c03c5b1cSMartin Matuska bs->rep[i] = repStartValue[i];
1288c03c5b1cSMartin Matuska bs->entropy.huf.repeatMode = HUF_repeat_none;
1289c03c5b1cSMartin Matuska bs->entropy.fse.offcode_repeatMode = FSE_repeat_none;
1290c03c5b1cSMartin Matuska bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none;
1291c03c5b1cSMartin Matuska bs->entropy.fse.litlength_repeatMode = FSE_repeat_none;
1292c03c5b1cSMartin Matuska }
1293c03c5b1cSMartin Matuska
1294c03c5b1cSMartin Matuska /*! ZSTD_invalidateMatchState()
1295c03c5b1cSMartin Matuska * Invalidate all the matches in the match finder tables.
1296c03c5b1cSMartin Matuska * Requires nextSrc and base to be set (can be NULL).
1297c03c5b1cSMartin Matuska */
ZSTD_invalidateMatchState(ZSTD_matchState_t * ms)1298c03c5b1cSMartin Matuska static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
1299c03c5b1cSMartin Matuska {
1300c03c5b1cSMartin Matuska ZSTD_window_clear(&ms->window);
1301c03c5b1cSMartin Matuska
1302c03c5b1cSMartin Matuska ms->nextToUpdate = ms->window.dictLimit;
1303c03c5b1cSMartin Matuska ms->loadedDictEnd = 0;
1304c03c5b1cSMartin Matuska ms->opt.litLengthSum = 0; /* force reset of btopt stats */
1305c03c5b1cSMartin Matuska ms->dictMatchState = NULL;
1306c03c5b1cSMartin Matuska }
1307c03c5b1cSMartin Matuska
1308c03c5b1cSMartin Matuska /**
1309c03c5b1cSMartin Matuska * Indicates whether this compression proceeds directly from user-provided
1310c03c5b1cSMartin Matuska * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or
1311c03c5b1cSMartin Matuska * whether the context needs to buffer the input/output (ZSTDb_buffered).
1312c03c5b1cSMartin Matuska */
1313c03c5b1cSMartin Matuska typedef enum {
1314c03c5b1cSMartin Matuska ZSTDb_not_buffered,
1315c03c5b1cSMartin Matuska ZSTDb_buffered
1316c03c5b1cSMartin Matuska } ZSTD_buffered_policy_e;
1317c03c5b1cSMartin Matuska
1318c03c5b1cSMartin Matuska /**
1319c03c5b1cSMartin Matuska * Controls, for this matchState reset, whether the tables need to be cleared /
1320c03c5b1cSMartin Matuska * prepared for the coming compression (ZSTDcrp_makeClean), or whether the
1321c03c5b1cSMartin Matuska * tables can be left unclean (ZSTDcrp_leaveDirty), because we know that a
1322c03c5b1cSMartin Matuska * subsequent operation will overwrite the table space anyways (e.g., copying
1323c03c5b1cSMartin Matuska * the matchState contents in from a CDict).
1324c03c5b1cSMartin Matuska */
1325c03c5b1cSMartin Matuska typedef enum {
1326c03c5b1cSMartin Matuska ZSTDcrp_makeClean,
1327c03c5b1cSMartin Matuska ZSTDcrp_leaveDirty
1328c03c5b1cSMartin Matuska } ZSTD_compResetPolicy_e;
1329c03c5b1cSMartin Matuska
1330c03c5b1cSMartin Matuska /**
1331c03c5b1cSMartin Matuska * Controls, for this matchState reset, whether indexing can continue where it
1332c03c5b1cSMartin Matuska * left off (ZSTDirp_continue), or whether it needs to be restarted from zero
1333c03c5b1cSMartin Matuska * (ZSTDirp_reset).
1334c03c5b1cSMartin Matuska */
1335c03c5b1cSMartin Matuska typedef enum {
1336c03c5b1cSMartin Matuska ZSTDirp_continue,
1337c03c5b1cSMartin Matuska ZSTDirp_reset
1338c03c5b1cSMartin Matuska } ZSTD_indexResetPolicy_e;
1339c03c5b1cSMartin Matuska
1340c03c5b1cSMartin Matuska typedef enum {
1341c03c5b1cSMartin Matuska ZSTD_resetTarget_CDict,
1342c03c5b1cSMartin Matuska ZSTD_resetTarget_CCtx
1343c03c5b1cSMartin Matuska } ZSTD_resetTarget_e;
1344c03c5b1cSMartin Matuska
1345c03c5b1cSMartin Matuska static size_t
ZSTD_reset_matchState(ZSTD_matchState_t * ms,ZSTD_cwksp * ws,const ZSTD_compressionParameters * cParams,const ZSTD_compResetPolicy_e crp,const ZSTD_indexResetPolicy_e forceResetIndex,const ZSTD_resetTarget_e forWho)1346c03c5b1cSMartin Matuska ZSTD_reset_matchState(ZSTD_matchState_t* ms,
1347c03c5b1cSMartin Matuska ZSTD_cwksp* ws,
1348c03c5b1cSMartin Matuska const ZSTD_compressionParameters* cParams,
1349c03c5b1cSMartin Matuska const ZSTD_compResetPolicy_e crp,
1350c03c5b1cSMartin Matuska const ZSTD_indexResetPolicy_e forceResetIndex,
1351c03c5b1cSMartin Matuska const ZSTD_resetTarget_e forWho)
1352c03c5b1cSMartin Matuska {
1353c03c5b1cSMartin Matuska size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
1354c03c5b1cSMartin Matuska size_t const hSize = ((size_t)1) << cParams->hashLog;
1355c03c5b1cSMartin Matuska U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
1356c03c5b1cSMartin Matuska size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
1357c03c5b1cSMartin Matuska
1358c03c5b1cSMartin Matuska DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset);
1359c03c5b1cSMartin Matuska if (forceResetIndex == ZSTDirp_reset) {
1360c03c5b1cSMartin Matuska ZSTD_window_init(&ms->window);
1361c03c5b1cSMartin Matuska ZSTD_cwksp_mark_tables_dirty(ws);
1362c03c5b1cSMartin Matuska }
1363c03c5b1cSMartin Matuska
1364c03c5b1cSMartin Matuska ms->hashLog3 = hashLog3;
1365c03c5b1cSMartin Matuska
1366c03c5b1cSMartin Matuska ZSTD_invalidateMatchState(ms);
1367c03c5b1cSMartin Matuska
1368c03c5b1cSMartin Matuska assert(!ZSTD_cwksp_reserve_failed(ws)); /* check that allocation hasn't already failed */
1369c03c5b1cSMartin Matuska
1370c03c5b1cSMartin Matuska ZSTD_cwksp_clear_tables(ws);
1371c03c5b1cSMartin Matuska
1372c03c5b1cSMartin Matuska DEBUGLOG(5, "reserving table space");
1373c03c5b1cSMartin Matuska /* table Space */
1374c03c5b1cSMartin Matuska ms->hashTable = (U32*)ZSTD_cwksp_reserve_table(ws, hSize * sizeof(U32));
1375c03c5b1cSMartin Matuska ms->chainTable = (U32*)ZSTD_cwksp_reserve_table(ws, chainSize * sizeof(U32));
1376c03c5b1cSMartin Matuska ms->hashTable3 = (U32*)ZSTD_cwksp_reserve_table(ws, h3Size * sizeof(U32));
1377c03c5b1cSMartin Matuska RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
1378c03c5b1cSMartin Matuska "failed a workspace allocation in ZSTD_reset_matchState");
1379c03c5b1cSMartin Matuska
1380c03c5b1cSMartin Matuska DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_leaveDirty);
1381c03c5b1cSMartin Matuska if (crp!=ZSTDcrp_leaveDirty) {
1382c03c5b1cSMartin Matuska /* reset tables only */
1383c03c5b1cSMartin Matuska ZSTD_cwksp_clean_tables(ws);
1384c03c5b1cSMartin Matuska }
1385c03c5b1cSMartin Matuska
1386c03c5b1cSMartin Matuska /* opt parser space */
1387c03c5b1cSMartin Matuska if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) {
1388c03c5b1cSMartin Matuska DEBUGLOG(4, "reserving optimal parser space");
1389c03c5b1cSMartin Matuska ms->opt.litFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (1<<Litbits) * sizeof(unsigned));
1390c03c5b1cSMartin Matuska ms->opt.litLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxLL+1) * sizeof(unsigned));
1391c03c5b1cSMartin Matuska ms->opt.matchLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxML+1) * sizeof(unsigned));
1392c03c5b1cSMartin Matuska ms->opt.offCodeFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxOff+1) * sizeof(unsigned));
1393c03c5b1cSMartin Matuska ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t));
1394c03c5b1cSMartin Matuska ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
1395c03c5b1cSMartin Matuska }
1396c03c5b1cSMartin Matuska
1397c03c5b1cSMartin Matuska ms->cParams = *cParams;
1398c03c5b1cSMartin Matuska
1399c03c5b1cSMartin Matuska RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
1400c03c5b1cSMartin Matuska "failed a workspace allocation in ZSTD_reset_matchState");
1401c03c5b1cSMartin Matuska
1402c03c5b1cSMartin Matuska return 0;
1403c03c5b1cSMartin Matuska }
1404c03c5b1cSMartin Matuska
1405c03c5b1cSMartin Matuska /* ZSTD_indexTooCloseToMax() :
1406c03c5b1cSMartin Matuska * minor optimization : prefer memset() rather than reduceIndex()
1407c03c5b1cSMartin Matuska * which is measurably slow in some circumstances (reported for Visual Studio).
1408c03c5b1cSMartin Matuska * Works when re-using a context for a lot of smallish inputs :
1409c03c5b1cSMartin Matuska * if all inputs are smaller than ZSTD_INDEXOVERFLOW_MARGIN,
1410c03c5b1cSMartin Matuska * memset() will be triggered before reduceIndex().
1411c03c5b1cSMartin Matuska */
1412c03c5b1cSMartin Matuska #define ZSTD_INDEXOVERFLOW_MARGIN (16 MB)
ZSTD_indexTooCloseToMax(ZSTD_window_t w)1413c03c5b1cSMartin Matuska static int ZSTD_indexTooCloseToMax(ZSTD_window_t w)
1414c03c5b1cSMartin Matuska {
1415c03c5b1cSMartin Matuska return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN);
1416c03c5b1cSMartin Matuska }
1417c03c5b1cSMartin Matuska
1418c03c5b1cSMartin Matuska /*! ZSTD_resetCCtx_internal() :
1419c03c5b1cSMartin Matuska note : `params` are assumed fully validated at this stage */
ZSTD_resetCCtx_internal(ZSTD_CCtx * zc,ZSTD_CCtx_params params,U64 const pledgedSrcSize,ZSTD_compResetPolicy_e const crp,ZSTD_buffered_policy_e const zbuff)1420c03c5b1cSMartin Matuska static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1421c03c5b1cSMartin Matuska ZSTD_CCtx_params params,
1422c03c5b1cSMartin Matuska U64 const pledgedSrcSize,
1423c03c5b1cSMartin Matuska ZSTD_compResetPolicy_e const crp,
1424c03c5b1cSMartin Matuska ZSTD_buffered_policy_e const zbuff)
1425c03c5b1cSMartin Matuska {
1426c03c5b1cSMartin Matuska ZSTD_cwksp* const ws = &zc->workspace;
1427c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
1428c03c5b1cSMartin Matuska (U32)pledgedSrcSize, params.cParams.windowLog);
1429c03c5b1cSMartin Matuska assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
1430c03c5b1cSMartin Matuska
1431c03c5b1cSMartin Matuska zc->isFirstBlock = 1;
1432c03c5b1cSMartin Matuska
1433c03c5b1cSMartin Matuska if (params.ldmParams.enableLdm) {
1434c03c5b1cSMartin Matuska /* Adjust long distance matching parameters */
1435c03c5b1cSMartin Matuska ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams);
1436c03c5b1cSMartin Matuska assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
1437c03c5b1cSMartin Matuska assert(params.ldmParams.hashRateLog < 32);
1438c03c5b1cSMartin Matuska zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
1439c03c5b1cSMartin Matuska }
1440c03c5b1cSMartin Matuska
1441c03c5b1cSMartin Matuska { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
1442c03c5b1cSMartin Matuska size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
1443c03c5b1cSMartin Matuska U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
1444c03c5b1cSMartin Matuska size_t const maxNbSeq = blockSize / divider;
1445c03c5b1cSMartin Matuska size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
1446c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
1447c03c5b1cSMartin Matuska + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
1448c03c5b1cSMartin Matuska size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
1449c03c5b1cSMartin Matuska size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
1450c03c5b1cSMartin Matuska size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1);
1451c03c5b1cSMartin Matuska size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
1452c03c5b1cSMartin Matuska
1453c03c5b1cSMartin Matuska ZSTD_indexResetPolicy_e needsIndexReset = zc->initialized ? ZSTDirp_continue : ZSTDirp_reset;
1454c03c5b1cSMartin Matuska
1455c03c5b1cSMartin Matuska if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) {
1456c03c5b1cSMartin Matuska needsIndexReset = ZSTDirp_reset;
1457c03c5b1cSMartin Matuska }
1458c03c5b1cSMartin Matuska
1459c03c5b1cSMartin Matuska if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
1460c03c5b1cSMartin Matuska
1461c03c5b1cSMartin Matuska /* Check if workspace is large enough, alloc a new one if needed */
1462c03c5b1cSMartin Matuska { size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
1463c03c5b1cSMartin Matuska size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
1464c03c5b1cSMartin Matuska size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
1465c03c5b1cSMartin Matuska size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize);
1466c03c5b1cSMartin Matuska size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
1467c03c5b1cSMartin Matuska size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq));
1468c03c5b1cSMartin Matuska
1469c03c5b1cSMartin Matuska size_t const neededSpace =
1470c03c5b1cSMartin Matuska cctxSpace +
1471c03c5b1cSMartin Matuska entropySpace +
1472c03c5b1cSMartin Matuska blockStateSpace +
1473c03c5b1cSMartin Matuska ldmSpace +
1474c03c5b1cSMartin Matuska ldmSeqSpace +
1475c03c5b1cSMartin Matuska matchStateSize +
1476c03c5b1cSMartin Matuska tokenSpace +
1477c03c5b1cSMartin Matuska bufferSpace;
1478c03c5b1cSMartin Matuska
1479c03c5b1cSMartin Matuska int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
1480c03c5b1cSMartin Matuska int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
1481c03c5b1cSMartin Matuska
1482c03c5b1cSMartin Matuska DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
1483c03c5b1cSMartin Matuska neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
1484c03c5b1cSMartin Matuska DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
1485c03c5b1cSMartin Matuska
1486c03c5b1cSMartin Matuska if (workspaceTooSmall || workspaceWasteful) {
1487c03c5b1cSMartin Matuska DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB",
1488c03c5b1cSMartin Matuska ZSTD_cwksp_sizeof(ws) >> 10,
1489c03c5b1cSMartin Matuska neededSpace >> 10);
1490c03c5b1cSMartin Matuska
1491c03c5b1cSMartin Matuska RETURN_ERROR_IF(zc->staticSize, memory_allocation, "static cctx : no resize");
1492c03c5b1cSMartin Matuska
1493c03c5b1cSMartin Matuska needsIndexReset = ZSTDirp_reset;
1494c03c5b1cSMartin Matuska
1495c03c5b1cSMartin Matuska ZSTD_cwksp_free(ws, zc->customMem);
1496c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem), "");
1497c03c5b1cSMartin Matuska
1498c03c5b1cSMartin Matuska DEBUGLOG(5, "reserving object space");
1499c03c5b1cSMartin Matuska /* Statically sized space.
1500c03c5b1cSMartin Matuska * entropyWorkspace never moves,
1501c03c5b1cSMartin Matuska * though prev/next block swap places */
1502c03c5b1cSMartin Matuska assert(ZSTD_cwksp_check_available(ws, 2 * sizeof(ZSTD_compressedBlockState_t)));
1503c03c5b1cSMartin Matuska zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
1504c03c5b1cSMartin Matuska RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock");
1505c03c5b1cSMartin Matuska zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
1506c03c5b1cSMartin Matuska RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock");
1507c03c5b1cSMartin Matuska zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, HUF_WORKSPACE_SIZE);
1508c03c5b1cSMartin Matuska RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace");
1509c03c5b1cSMartin Matuska } }
1510c03c5b1cSMartin Matuska
1511c03c5b1cSMartin Matuska ZSTD_cwksp_clear(ws);
1512c03c5b1cSMartin Matuska
1513c03c5b1cSMartin Matuska /* init params */
1514c03c5b1cSMartin Matuska zc->appliedParams = params;
1515c03c5b1cSMartin Matuska zc->blockState.matchState.cParams = params.cParams;
1516c03c5b1cSMartin Matuska zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
1517c03c5b1cSMartin Matuska zc->consumedSrcSize = 0;
1518c03c5b1cSMartin Matuska zc->producedCSize = 0;
1519c03c5b1cSMartin Matuska if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
1520c03c5b1cSMartin Matuska zc->appliedParams.fParams.contentSizeFlag = 0;
1521c03c5b1cSMartin Matuska DEBUGLOG(4, "pledged content size : %u ; flag : %u",
1522c03c5b1cSMartin Matuska (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
1523c03c5b1cSMartin Matuska zc->blockSize = blockSize;
1524c03c5b1cSMartin Matuska
1525c03c5b1cSMartin Matuska XXH64_reset(&zc->xxhState, 0);
1526c03c5b1cSMartin Matuska zc->stage = ZSTDcs_init;
1527c03c5b1cSMartin Matuska zc->dictID = 0;
1528c03c5b1cSMartin Matuska
1529c03c5b1cSMartin Matuska ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
1530c03c5b1cSMartin Matuska
1531c03c5b1cSMartin Matuska /* ZSTD_wildcopy() is used to copy into the literals buffer,
1532c03c5b1cSMartin Matuska * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes.
1533c03c5b1cSMartin Matuska */
1534c03c5b1cSMartin Matuska zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH);
1535c03c5b1cSMartin Matuska zc->seqStore.maxNbLit = blockSize;
1536c03c5b1cSMartin Matuska
1537c03c5b1cSMartin Matuska /* buffers */
1538c03c5b1cSMartin Matuska zc->inBuffSize = buffInSize;
1539c03c5b1cSMartin Matuska zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize);
1540c03c5b1cSMartin Matuska zc->outBuffSize = buffOutSize;
1541c03c5b1cSMartin Matuska zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize);
1542c03c5b1cSMartin Matuska
1543c03c5b1cSMartin Matuska /* ldm bucketOffsets table */
1544c03c5b1cSMartin Matuska if (params.ldmParams.enableLdm) {
1545c03c5b1cSMartin Matuska /* TODO: avoid memset? */
1546c03c5b1cSMartin Matuska size_t const ldmBucketSize =
1547c03c5b1cSMartin Matuska ((size_t)1) << (params.ldmParams.hashLog -
1548c03c5b1cSMartin Matuska params.ldmParams.bucketSizeLog);
1549c03c5b1cSMartin Matuska zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize);
1550c03c5b1cSMartin Matuska memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize);
1551c03c5b1cSMartin Matuska }
1552c03c5b1cSMartin Matuska
1553c03c5b1cSMartin Matuska /* sequences storage */
1554c03c5b1cSMartin Matuska ZSTD_referenceExternalSequences(zc, NULL, 0);
1555c03c5b1cSMartin Matuska zc->seqStore.maxNbSeq = maxNbSeq;
1556c03c5b1cSMartin Matuska zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
1557c03c5b1cSMartin Matuska zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
1558c03c5b1cSMartin Matuska zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
1559c03c5b1cSMartin Matuska zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef));
1560c03c5b1cSMartin Matuska
1561c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_reset_matchState(
1562c03c5b1cSMartin Matuska &zc->blockState.matchState,
1563c03c5b1cSMartin Matuska ws,
1564c03c5b1cSMartin Matuska ¶ms.cParams,
1565c03c5b1cSMartin Matuska crp,
1566c03c5b1cSMartin Matuska needsIndexReset,
1567c03c5b1cSMartin Matuska ZSTD_resetTarget_CCtx), "");
1568c03c5b1cSMartin Matuska
1569c03c5b1cSMartin Matuska /* ldm hash table */
1570c03c5b1cSMartin Matuska if (params.ldmParams.enableLdm) {
1571c03c5b1cSMartin Matuska /* TODO: avoid memset? */
1572c03c5b1cSMartin Matuska size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
1573c03c5b1cSMartin Matuska zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t));
1574c03c5b1cSMartin Matuska memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
1575c03c5b1cSMartin Matuska zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq));
1576c03c5b1cSMartin Matuska zc->maxNbLdmSequences = maxNbLdmSeq;
1577c03c5b1cSMartin Matuska
1578c03c5b1cSMartin Matuska ZSTD_window_init(&zc->ldmState.window);
1579c03c5b1cSMartin Matuska ZSTD_window_clear(&zc->ldmState.window);
1580c03c5b1cSMartin Matuska zc->ldmState.loadedDictEnd = 0;
1581c03c5b1cSMartin Matuska }
1582c03c5b1cSMartin Matuska
1583c03c5b1cSMartin Matuska DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws));
1584c03c5b1cSMartin Matuska zc->initialized = 1;
1585c03c5b1cSMartin Matuska
1586c03c5b1cSMartin Matuska return 0;
1587c03c5b1cSMartin Matuska }
1588c03c5b1cSMartin Matuska }
1589c03c5b1cSMartin Matuska
1590c03c5b1cSMartin Matuska /* ZSTD_invalidateRepCodes() :
1591c03c5b1cSMartin Matuska * ensures next compression will not use repcodes from previous block.
1592c03c5b1cSMartin Matuska * Note : only works with regular variant;
1593c03c5b1cSMartin Matuska * do not use with extDict variant ! */
ZSTD_invalidateRepCodes(ZSTD_CCtx * cctx)1594c03c5b1cSMartin Matuska void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
1595c03c5b1cSMartin Matuska int i;
1596c03c5b1cSMartin Matuska for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0;
1597c03c5b1cSMartin Matuska assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
1598c03c5b1cSMartin Matuska }
1599c03c5b1cSMartin Matuska
1600c03c5b1cSMartin Matuska /* These are the approximate sizes for each strategy past which copying the
1601c03c5b1cSMartin Matuska * dictionary tables into the working context is faster than using them
1602c03c5b1cSMartin Matuska * in-place.
1603c03c5b1cSMartin Matuska */
1604c03c5b1cSMartin Matuska static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = {
1605c03c5b1cSMartin Matuska 8 KB, /* unused */
1606c03c5b1cSMartin Matuska 8 KB, /* ZSTD_fast */
1607c03c5b1cSMartin Matuska 16 KB, /* ZSTD_dfast */
1608c03c5b1cSMartin Matuska 32 KB, /* ZSTD_greedy */
1609c03c5b1cSMartin Matuska 32 KB, /* ZSTD_lazy */
1610c03c5b1cSMartin Matuska 32 KB, /* ZSTD_lazy2 */
1611c03c5b1cSMartin Matuska 32 KB, /* ZSTD_btlazy2 */
1612c03c5b1cSMartin Matuska 32 KB, /* ZSTD_btopt */
1613c03c5b1cSMartin Matuska 8 KB, /* ZSTD_btultra */
1614c03c5b1cSMartin Matuska 8 KB /* ZSTD_btultra2 */
1615c03c5b1cSMartin Matuska };
1616c03c5b1cSMartin Matuska
ZSTD_shouldAttachDict(const ZSTD_CDict * cdict,const ZSTD_CCtx_params * params,U64 pledgedSrcSize)1617c03c5b1cSMartin Matuska static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict,
1618c03c5b1cSMartin Matuska const ZSTD_CCtx_params* params,
1619c03c5b1cSMartin Matuska U64 pledgedSrcSize)
1620c03c5b1cSMartin Matuska {
1621c03c5b1cSMartin Matuska size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy];
1622c03c5b1cSMartin Matuska return ( pledgedSrcSize <= cutoff
1623c03c5b1cSMartin Matuska || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
1624c03c5b1cSMartin Matuska || params->attachDictPref == ZSTD_dictForceAttach )
1625c03c5b1cSMartin Matuska && params->attachDictPref != ZSTD_dictForceCopy
1626c03c5b1cSMartin Matuska && !params->forceWindow; /* dictMatchState isn't correctly
1627c03c5b1cSMartin Matuska * handled in _enforceMaxDist */
1628c03c5b1cSMartin Matuska }
1629c03c5b1cSMartin Matuska
1630c03c5b1cSMartin Matuska static size_t
ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx * cctx,const ZSTD_CDict * cdict,ZSTD_CCtx_params params,U64 pledgedSrcSize,ZSTD_buffered_policy_e zbuff)1631c03c5b1cSMartin Matuska ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
1632c03c5b1cSMartin Matuska const ZSTD_CDict* cdict,
1633c03c5b1cSMartin Matuska ZSTD_CCtx_params params,
1634c03c5b1cSMartin Matuska U64 pledgedSrcSize,
1635c03c5b1cSMartin Matuska ZSTD_buffered_policy_e zbuff)
1636c03c5b1cSMartin Matuska {
1637c03c5b1cSMartin Matuska { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams;
1638c03c5b1cSMartin Matuska unsigned const windowLog = params.cParams.windowLog;
1639c03c5b1cSMartin Matuska assert(windowLog != 0);
1640c03c5b1cSMartin Matuska /* Resize working context table params for input only, since the dict
1641c03c5b1cSMartin Matuska * has its own tables. */
1642c03c5b1cSMartin Matuska /* pledgeSrcSize == 0 means 0! */
1643c03c5b1cSMartin Matuska params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0);
1644c03c5b1cSMartin Matuska params.cParams.windowLog = windowLog;
1645c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
1646c03c5b1cSMartin Matuska ZSTDcrp_makeClean, zbuff), "");
1647c03c5b1cSMartin Matuska assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
1648c03c5b1cSMartin Matuska }
1649c03c5b1cSMartin Matuska
1650c03c5b1cSMartin Matuska { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc
1651c03c5b1cSMartin Matuska - cdict->matchState.window.base);
1652c03c5b1cSMartin Matuska const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit;
1653c03c5b1cSMartin Matuska if (cdictLen == 0) {
1654c03c5b1cSMartin Matuska /* don't even attach dictionaries with no contents */
1655c03c5b1cSMartin Matuska DEBUGLOG(4, "skipping attaching empty dictionary");
1656c03c5b1cSMartin Matuska } else {
1657c03c5b1cSMartin Matuska DEBUGLOG(4, "attaching dictionary into context");
1658c03c5b1cSMartin Matuska cctx->blockState.matchState.dictMatchState = &cdict->matchState;
1659c03c5b1cSMartin Matuska
1660c03c5b1cSMartin Matuska /* prep working match state so dict matches never have negative indices
1661c03c5b1cSMartin Matuska * when they are translated to the working context's index space. */
1662c03c5b1cSMartin Matuska if (cctx->blockState.matchState.window.dictLimit < cdictEnd) {
1663c03c5b1cSMartin Matuska cctx->blockState.matchState.window.nextSrc =
1664c03c5b1cSMartin Matuska cctx->blockState.matchState.window.base + cdictEnd;
1665c03c5b1cSMartin Matuska ZSTD_window_clear(&cctx->blockState.matchState.window);
1666c03c5b1cSMartin Matuska }
1667c03c5b1cSMartin Matuska /* loadedDictEnd is expressed within the referential of the active context */
1668c03c5b1cSMartin Matuska cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit;
1669c03c5b1cSMartin Matuska } }
1670c03c5b1cSMartin Matuska
1671c03c5b1cSMartin Matuska cctx->dictID = cdict->dictID;
1672c03c5b1cSMartin Matuska
1673c03c5b1cSMartin Matuska /* copy block state */
1674c03c5b1cSMartin Matuska memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1675c03c5b1cSMartin Matuska
1676c03c5b1cSMartin Matuska return 0;
1677c03c5b1cSMartin Matuska }
1678c03c5b1cSMartin Matuska
ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx * cctx,const ZSTD_CDict * cdict,ZSTD_CCtx_params params,U64 pledgedSrcSize,ZSTD_buffered_policy_e zbuff)1679c03c5b1cSMartin Matuska static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
1680c03c5b1cSMartin Matuska const ZSTD_CDict* cdict,
1681c03c5b1cSMartin Matuska ZSTD_CCtx_params params,
1682c03c5b1cSMartin Matuska U64 pledgedSrcSize,
1683c03c5b1cSMartin Matuska ZSTD_buffered_policy_e zbuff)
1684c03c5b1cSMartin Matuska {
1685c03c5b1cSMartin Matuska const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
1686c03c5b1cSMartin Matuska
1687c03c5b1cSMartin Matuska DEBUGLOG(4, "copying dictionary into context");
1688c03c5b1cSMartin Matuska
1689c03c5b1cSMartin Matuska { unsigned const windowLog = params.cParams.windowLog;
1690c03c5b1cSMartin Matuska assert(windowLog != 0);
1691c03c5b1cSMartin Matuska /* Copy only compression parameters related to tables. */
1692c03c5b1cSMartin Matuska params.cParams = *cdict_cParams;
1693c03c5b1cSMartin Matuska params.cParams.windowLog = windowLog;
1694c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
1695c03c5b1cSMartin Matuska ZSTDcrp_leaveDirty, zbuff), "");
1696c03c5b1cSMartin Matuska assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
1697c03c5b1cSMartin Matuska assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog);
1698c03c5b1cSMartin Matuska assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog);
1699c03c5b1cSMartin Matuska }
1700c03c5b1cSMartin Matuska
1701c03c5b1cSMartin Matuska ZSTD_cwksp_mark_tables_dirty(&cctx->workspace);
1702c03c5b1cSMartin Matuska
1703c03c5b1cSMartin Matuska /* copy tables */
1704c03c5b1cSMartin Matuska { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
1705c03c5b1cSMartin Matuska size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
1706c03c5b1cSMartin Matuska
1707c03c5b1cSMartin Matuska memcpy(cctx->blockState.matchState.hashTable,
1708c03c5b1cSMartin Matuska cdict->matchState.hashTable,
1709c03c5b1cSMartin Matuska hSize * sizeof(U32));
1710c03c5b1cSMartin Matuska memcpy(cctx->blockState.matchState.chainTable,
1711c03c5b1cSMartin Matuska cdict->matchState.chainTable,
1712c03c5b1cSMartin Matuska chainSize * sizeof(U32));
1713c03c5b1cSMartin Matuska }
1714c03c5b1cSMartin Matuska
1715c03c5b1cSMartin Matuska /* Zero the hashTable3, since the cdict never fills it */
1716c03c5b1cSMartin Matuska { int const h3log = cctx->blockState.matchState.hashLog3;
1717c03c5b1cSMartin Matuska size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
1718c03c5b1cSMartin Matuska assert(cdict->matchState.hashLog3 == 0);
1719c03c5b1cSMartin Matuska memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
1720c03c5b1cSMartin Matuska }
1721c03c5b1cSMartin Matuska
1722c03c5b1cSMartin Matuska ZSTD_cwksp_mark_tables_clean(&cctx->workspace);
1723c03c5b1cSMartin Matuska
1724c03c5b1cSMartin Matuska /* copy dictionary offsets */
1725c03c5b1cSMartin Matuska { ZSTD_matchState_t const* srcMatchState = &cdict->matchState;
1726c03c5b1cSMartin Matuska ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState;
1727c03c5b1cSMartin Matuska dstMatchState->window = srcMatchState->window;
1728c03c5b1cSMartin Matuska dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
1729c03c5b1cSMartin Matuska dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
1730c03c5b1cSMartin Matuska }
1731c03c5b1cSMartin Matuska
1732c03c5b1cSMartin Matuska cctx->dictID = cdict->dictID;
1733c03c5b1cSMartin Matuska
1734c03c5b1cSMartin Matuska /* copy block state */
1735c03c5b1cSMartin Matuska memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1736c03c5b1cSMartin Matuska
1737c03c5b1cSMartin Matuska return 0;
1738c03c5b1cSMartin Matuska }
1739c03c5b1cSMartin Matuska
1740c03c5b1cSMartin Matuska /* We have a choice between copying the dictionary context into the working
1741c03c5b1cSMartin Matuska * context, or referencing the dictionary context from the working context
1742c03c5b1cSMartin Matuska * in-place. We decide here which strategy to use. */
ZSTD_resetCCtx_usingCDict(ZSTD_CCtx * cctx,const ZSTD_CDict * cdict,const ZSTD_CCtx_params * params,U64 pledgedSrcSize,ZSTD_buffered_policy_e zbuff)1743c03c5b1cSMartin Matuska static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx,
1744c03c5b1cSMartin Matuska const ZSTD_CDict* cdict,
1745c03c5b1cSMartin Matuska const ZSTD_CCtx_params* params,
1746c03c5b1cSMartin Matuska U64 pledgedSrcSize,
1747c03c5b1cSMartin Matuska ZSTD_buffered_policy_e zbuff)
1748c03c5b1cSMartin Matuska {
1749c03c5b1cSMartin Matuska
1750c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)",
1751c03c5b1cSMartin Matuska (unsigned)pledgedSrcSize);
1752c03c5b1cSMartin Matuska
1753c03c5b1cSMartin Matuska if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) {
1754c03c5b1cSMartin Matuska return ZSTD_resetCCtx_byAttachingCDict(
1755c03c5b1cSMartin Matuska cctx, cdict, *params, pledgedSrcSize, zbuff);
1756c03c5b1cSMartin Matuska } else {
1757c03c5b1cSMartin Matuska return ZSTD_resetCCtx_byCopyingCDict(
1758c03c5b1cSMartin Matuska cctx, cdict, *params, pledgedSrcSize, zbuff);
1759c03c5b1cSMartin Matuska }
1760c03c5b1cSMartin Matuska }
1761c03c5b1cSMartin Matuska
1762c03c5b1cSMartin Matuska /*! ZSTD_copyCCtx_internal() :
1763c03c5b1cSMartin Matuska * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
1764c03c5b1cSMartin Matuska * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
1765c03c5b1cSMartin Matuska * The "context", in this case, refers to the hash and chain tables,
1766c03c5b1cSMartin Matuska * entropy tables, and dictionary references.
1767c03c5b1cSMartin Matuska * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx.
1768c03c5b1cSMartin Matuska * @return : 0, or an error code */
ZSTD_copyCCtx_internal(ZSTD_CCtx * dstCCtx,const ZSTD_CCtx * srcCCtx,ZSTD_frameParameters fParams,U64 pledgedSrcSize,ZSTD_buffered_policy_e zbuff)1769c03c5b1cSMartin Matuska static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1770c03c5b1cSMartin Matuska const ZSTD_CCtx* srcCCtx,
1771c03c5b1cSMartin Matuska ZSTD_frameParameters fParams,
1772c03c5b1cSMartin Matuska U64 pledgedSrcSize,
1773c03c5b1cSMartin Matuska ZSTD_buffered_policy_e zbuff)
1774c03c5b1cSMartin Matuska {
1775c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_copyCCtx_internal");
1776c03c5b1cSMartin Matuska RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong,
1777c03c5b1cSMartin Matuska "Can't copy a ctx that's not in init stage.");
1778c03c5b1cSMartin Matuska
1779c03c5b1cSMartin Matuska memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
1780c03c5b1cSMartin Matuska { ZSTD_CCtx_params params = dstCCtx->requestedParams;
1781c03c5b1cSMartin Matuska /* Copy only compression parameters related to tables. */
1782c03c5b1cSMartin Matuska params.cParams = srcCCtx->appliedParams.cParams;
1783c03c5b1cSMartin Matuska params.fParams = fParams;
1784c03c5b1cSMartin Matuska ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
1785c03c5b1cSMartin Matuska ZSTDcrp_leaveDirty, zbuff);
1786c03c5b1cSMartin Matuska assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
1787c03c5b1cSMartin Matuska assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
1788c03c5b1cSMartin Matuska assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog);
1789c03c5b1cSMartin Matuska assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog);
1790c03c5b1cSMartin Matuska assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3);
1791c03c5b1cSMartin Matuska }
1792c03c5b1cSMartin Matuska
1793c03c5b1cSMartin Matuska ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace);
1794c03c5b1cSMartin Matuska
1795c03c5b1cSMartin Matuska /* copy tables */
1796c03c5b1cSMartin Matuska { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
1797c03c5b1cSMartin Matuska size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
1798c03c5b1cSMartin Matuska int const h3log = srcCCtx->blockState.matchState.hashLog3;
1799c03c5b1cSMartin Matuska size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
1800c03c5b1cSMartin Matuska
1801c03c5b1cSMartin Matuska memcpy(dstCCtx->blockState.matchState.hashTable,
1802c03c5b1cSMartin Matuska srcCCtx->blockState.matchState.hashTable,
1803c03c5b1cSMartin Matuska hSize * sizeof(U32));
1804c03c5b1cSMartin Matuska memcpy(dstCCtx->blockState.matchState.chainTable,
1805c03c5b1cSMartin Matuska srcCCtx->blockState.matchState.chainTable,
1806c03c5b1cSMartin Matuska chainSize * sizeof(U32));
1807c03c5b1cSMartin Matuska memcpy(dstCCtx->blockState.matchState.hashTable3,
1808c03c5b1cSMartin Matuska srcCCtx->blockState.matchState.hashTable3,
1809c03c5b1cSMartin Matuska h3Size * sizeof(U32));
1810c03c5b1cSMartin Matuska }
1811c03c5b1cSMartin Matuska
1812c03c5b1cSMartin Matuska ZSTD_cwksp_mark_tables_clean(&dstCCtx->workspace);
1813c03c5b1cSMartin Matuska
1814c03c5b1cSMartin Matuska /* copy dictionary offsets */
1815c03c5b1cSMartin Matuska {
1816c03c5b1cSMartin Matuska const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState;
1817c03c5b1cSMartin Matuska ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
1818c03c5b1cSMartin Matuska dstMatchState->window = srcMatchState->window;
1819c03c5b1cSMartin Matuska dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
1820c03c5b1cSMartin Matuska dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
1821c03c5b1cSMartin Matuska }
1822c03c5b1cSMartin Matuska dstCCtx->dictID = srcCCtx->dictID;
1823c03c5b1cSMartin Matuska
1824c03c5b1cSMartin Matuska /* copy block state */
1825c03c5b1cSMartin Matuska memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
1826c03c5b1cSMartin Matuska
1827c03c5b1cSMartin Matuska return 0;
1828c03c5b1cSMartin Matuska }
1829c03c5b1cSMartin Matuska
1830c03c5b1cSMartin Matuska /*! ZSTD_copyCCtx() :
1831c03c5b1cSMartin Matuska * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
1832c03c5b1cSMartin Matuska * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
1833c03c5b1cSMartin Matuska * pledgedSrcSize==0 means "unknown".
1834c03c5b1cSMartin Matuska * @return : 0, or an error code */
ZSTD_copyCCtx(ZSTD_CCtx * dstCCtx,const ZSTD_CCtx * srcCCtx,unsigned long long pledgedSrcSize)1835c03c5b1cSMartin Matuska size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
1836c03c5b1cSMartin Matuska {
1837c03c5b1cSMartin Matuska ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
1838c03c5b1cSMartin Matuska ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
1839c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
1840c03c5b1cSMartin Matuska if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
1841c03c5b1cSMartin Matuska fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
1842c03c5b1cSMartin Matuska
1843c03c5b1cSMartin Matuska return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx,
1844c03c5b1cSMartin Matuska fParams, pledgedSrcSize,
1845c03c5b1cSMartin Matuska zbuff);
1846c03c5b1cSMartin Matuska }
1847c03c5b1cSMartin Matuska
1848c03c5b1cSMartin Matuska
1849c03c5b1cSMartin Matuska #define ZSTD_ROWSIZE 16
1850c03c5b1cSMartin Matuska /*! ZSTD_reduceTable() :
1851c03c5b1cSMartin Matuska * reduce table indexes by `reducerValue`, or squash to zero.
1852c03c5b1cSMartin Matuska * PreserveMark preserves "unsorted mark" for btlazy2 strategy.
1853c03c5b1cSMartin Matuska * It must be set to a clear 0/1 value, to remove branch during inlining.
1854c03c5b1cSMartin Matuska * Presume table size is a multiple of ZSTD_ROWSIZE
1855c03c5b1cSMartin Matuska * to help auto-vectorization */
1856c03c5b1cSMartin Matuska FORCE_INLINE_TEMPLATE void
ZSTD_reduceTable_internal(U32 * const table,U32 const size,U32 const reducerValue,int const preserveMark)1857c03c5b1cSMartin Matuska ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark)
1858c03c5b1cSMartin Matuska {
1859c03c5b1cSMartin Matuska int const nbRows = (int)size / ZSTD_ROWSIZE;
1860c03c5b1cSMartin Matuska int cellNb = 0;
1861c03c5b1cSMartin Matuska int rowNb;
1862c03c5b1cSMartin Matuska assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */
1863c03c5b1cSMartin Matuska assert(size < (1U<<31)); /* can be casted to int */
1864c03c5b1cSMartin Matuska
1865c03c5b1cSMartin Matuska #if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
1866c03c5b1cSMartin Matuska /* To validate that the table re-use logic is sound, and that we don't
1867c03c5b1cSMartin Matuska * access table space that we haven't cleaned, we re-"poison" the table
1868c03c5b1cSMartin Matuska * space every time we mark it dirty.
1869c03c5b1cSMartin Matuska *
1870c03c5b1cSMartin Matuska * This function however is intended to operate on those dirty tables and
1871c03c5b1cSMartin Matuska * re-clean them. So when this function is used correctly, we can unpoison
1872c03c5b1cSMartin Matuska * the memory it operated on. This introduces a blind spot though, since
1873c03c5b1cSMartin Matuska * if we now try to operate on __actually__ poisoned memory, we will not
1874c03c5b1cSMartin Matuska * detect that. */
1875c03c5b1cSMartin Matuska __msan_unpoison(table, size * sizeof(U32));
1876c03c5b1cSMartin Matuska #endif
1877c03c5b1cSMartin Matuska
1878c03c5b1cSMartin Matuska for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
1879c03c5b1cSMartin Matuska int column;
1880c03c5b1cSMartin Matuska for (column=0; column<ZSTD_ROWSIZE; column++) {
1881c03c5b1cSMartin Matuska if (preserveMark) {
1882c03c5b1cSMartin Matuska U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0;
1883c03c5b1cSMartin Matuska table[cellNb] += adder;
1884c03c5b1cSMartin Matuska }
1885c03c5b1cSMartin Matuska if (table[cellNb] < reducerValue) table[cellNb] = 0;
1886c03c5b1cSMartin Matuska else table[cellNb] -= reducerValue;
1887c03c5b1cSMartin Matuska cellNb++;
1888c03c5b1cSMartin Matuska } }
1889c03c5b1cSMartin Matuska }
1890c03c5b1cSMartin Matuska
ZSTD_reduceTable(U32 * const table,U32 const size,U32 const reducerValue)1891c03c5b1cSMartin Matuska static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue)
1892c03c5b1cSMartin Matuska {
1893c03c5b1cSMartin Matuska ZSTD_reduceTable_internal(table, size, reducerValue, 0);
1894c03c5b1cSMartin Matuska }
1895c03c5b1cSMartin Matuska
ZSTD_reduceTable_btlazy2(U32 * const table,U32 const size,U32 const reducerValue)1896c03c5b1cSMartin Matuska static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue)
1897c03c5b1cSMartin Matuska {
1898c03c5b1cSMartin Matuska ZSTD_reduceTable_internal(table, size, reducerValue, 1);
1899c03c5b1cSMartin Matuska }
1900c03c5b1cSMartin Matuska
1901c03c5b1cSMartin Matuska /*! ZSTD_reduceIndex() :
1902c03c5b1cSMartin Matuska * rescale all indexes to avoid future overflow (indexes are U32) */
ZSTD_reduceIndex(ZSTD_matchState_t * ms,ZSTD_CCtx_params const * params,const U32 reducerValue)1903c03c5b1cSMartin Matuska static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const U32 reducerValue)
1904c03c5b1cSMartin Matuska {
1905c03c5b1cSMartin Matuska { U32 const hSize = (U32)1 << params->cParams.hashLog;
1906c03c5b1cSMartin Matuska ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
1907c03c5b1cSMartin Matuska }
1908c03c5b1cSMartin Matuska
1909c03c5b1cSMartin Matuska if (params->cParams.strategy != ZSTD_fast) {
1910c03c5b1cSMartin Matuska U32 const chainSize = (U32)1 << params->cParams.chainLog;
1911c03c5b1cSMartin Matuska if (params->cParams.strategy == ZSTD_btlazy2)
1912c03c5b1cSMartin Matuska ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
1913c03c5b1cSMartin Matuska else
1914c03c5b1cSMartin Matuska ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
1915c03c5b1cSMartin Matuska }
1916c03c5b1cSMartin Matuska
1917c03c5b1cSMartin Matuska if (ms->hashLog3) {
1918c03c5b1cSMartin Matuska U32 const h3Size = (U32)1 << ms->hashLog3;
1919c03c5b1cSMartin Matuska ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
1920c03c5b1cSMartin Matuska }
1921c03c5b1cSMartin Matuska }
1922c03c5b1cSMartin Matuska
1923c03c5b1cSMartin Matuska
1924c03c5b1cSMartin Matuska /*-*******************************************************
1925c03c5b1cSMartin Matuska * Block entropic compression
1926c03c5b1cSMartin Matuska *********************************************************/
1927c03c5b1cSMartin Matuska
1928c03c5b1cSMartin Matuska /* See doc/zstd_compression_format.md for detailed format description */
1929c03c5b1cSMartin Matuska
ZSTD_seqToCodes(const seqStore_t * seqStorePtr)1930c03c5b1cSMartin Matuska void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
1931c03c5b1cSMartin Matuska {
1932c03c5b1cSMartin Matuska const seqDef* const sequences = seqStorePtr->sequencesStart;
1933c03c5b1cSMartin Matuska BYTE* const llCodeTable = seqStorePtr->llCode;
1934c03c5b1cSMartin Matuska BYTE* const ofCodeTable = seqStorePtr->ofCode;
1935c03c5b1cSMartin Matuska BYTE* const mlCodeTable = seqStorePtr->mlCode;
1936c03c5b1cSMartin Matuska U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1937c03c5b1cSMartin Matuska U32 u;
1938c03c5b1cSMartin Matuska assert(nbSeq <= seqStorePtr->maxNbSeq);
1939c03c5b1cSMartin Matuska for (u=0; u<nbSeq; u++) {
1940c03c5b1cSMartin Matuska U32 const llv = sequences[u].litLength;
1941c03c5b1cSMartin Matuska U32 const mlv = sequences[u].matchLength;
1942c03c5b1cSMartin Matuska llCodeTable[u] = (BYTE)ZSTD_LLcode(llv);
1943c03c5b1cSMartin Matuska ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
1944c03c5b1cSMartin Matuska mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
1945c03c5b1cSMartin Matuska }
1946c03c5b1cSMartin Matuska if (seqStorePtr->longLengthID==1)
1947c03c5b1cSMartin Matuska llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
1948c03c5b1cSMartin Matuska if (seqStorePtr->longLengthID==2)
1949c03c5b1cSMartin Matuska mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
1950c03c5b1cSMartin Matuska }
1951c03c5b1cSMartin Matuska
1952c03c5b1cSMartin Matuska /* ZSTD_useTargetCBlockSize():
1953c03c5b1cSMartin Matuska * Returns if target compressed block size param is being used.
1954c03c5b1cSMartin Matuska * If used, compression will do best effort to make a compressed block size to be around targetCBlockSize.
1955c03c5b1cSMartin Matuska * Returns 1 if true, 0 otherwise. */
ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params * cctxParams)1956c03c5b1cSMartin Matuska static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams)
1957c03c5b1cSMartin Matuska {
1958c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_useTargetCBlockSize (targetCBlockSize=%zu)", cctxParams->targetCBlockSize);
1959c03c5b1cSMartin Matuska return (cctxParams->targetCBlockSize != 0);
1960c03c5b1cSMartin Matuska }
1961c03c5b1cSMartin Matuska
1962c03c5b1cSMartin Matuska /* ZSTD_compressSequences_internal():
1963c03c5b1cSMartin Matuska * actually compresses both literals and sequences */
1964c03c5b1cSMartin Matuska MEM_STATIC size_t
ZSTD_compressSequences_internal(seqStore_t * seqStorePtr,const ZSTD_entropyCTables_t * prevEntropy,ZSTD_entropyCTables_t * nextEntropy,const ZSTD_CCtx_params * cctxParams,void * dst,size_t dstCapacity,void * entropyWorkspace,size_t entropyWkspSize,const int bmi2)1965c03c5b1cSMartin Matuska ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
1966c03c5b1cSMartin Matuska const ZSTD_entropyCTables_t* prevEntropy,
1967c03c5b1cSMartin Matuska ZSTD_entropyCTables_t* nextEntropy,
1968c03c5b1cSMartin Matuska const ZSTD_CCtx_params* cctxParams,
1969c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
1970c03c5b1cSMartin Matuska void* entropyWorkspace, size_t entropyWkspSize,
1971c03c5b1cSMartin Matuska const int bmi2)
1972c03c5b1cSMartin Matuska {
1973c03c5b1cSMartin Matuska const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
1974c03c5b1cSMartin Matuska ZSTD_strategy const strategy = cctxParams->cParams.strategy;
1975c03c5b1cSMartin Matuska unsigned count[MaxSeq+1];
1976c03c5b1cSMartin Matuska FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
1977c03c5b1cSMartin Matuska FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
1978c03c5b1cSMartin Matuska FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
1979c03c5b1cSMartin Matuska U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
1980c03c5b1cSMartin Matuska const seqDef* const sequences = seqStorePtr->sequencesStart;
1981c03c5b1cSMartin Matuska const BYTE* const ofCodeTable = seqStorePtr->ofCode;
1982c03c5b1cSMartin Matuska const BYTE* const llCodeTable = seqStorePtr->llCode;
1983c03c5b1cSMartin Matuska const BYTE* const mlCodeTable = seqStorePtr->mlCode;
1984c03c5b1cSMartin Matuska BYTE* const ostart = (BYTE*)dst;
1985c03c5b1cSMartin Matuska BYTE* const oend = ostart + dstCapacity;
1986c03c5b1cSMartin Matuska BYTE* op = ostart;
1987c03c5b1cSMartin Matuska size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1988c03c5b1cSMartin Matuska BYTE* seqHead;
1989c03c5b1cSMartin Matuska BYTE* lastNCount = NULL;
1990c03c5b1cSMartin Matuska
1991c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq);
1992c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
1993c03c5b1cSMartin Matuska
1994c03c5b1cSMartin Matuska /* Compress literals */
1995c03c5b1cSMartin Matuska { const BYTE* const literals = seqStorePtr->litStart;
1996c03c5b1cSMartin Matuska size_t const litSize = (size_t)(seqStorePtr->lit - literals);
1997c03c5b1cSMartin Matuska size_t const cSize = ZSTD_compressLiterals(
1998c03c5b1cSMartin Matuska &prevEntropy->huf, &nextEntropy->huf,
1999c03c5b1cSMartin Matuska cctxParams->cParams.strategy,
2000c03c5b1cSMartin Matuska ZSTD_disableLiteralsCompression(cctxParams),
2001c03c5b1cSMartin Matuska op, dstCapacity,
2002c03c5b1cSMartin Matuska literals, litSize,
2003c03c5b1cSMartin Matuska entropyWorkspace, entropyWkspSize,
2004c03c5b1cSMartin Matuska bmi2);
2005c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed");
2006c03c5b1cSMartin Matuska assert(cSize <= dstCapacity);
2007c03c5b1cSMartin Matuska op += cSize;
2008c03c5b1cSMartin Matuska }
2009c03c5b1cSMartin Matuska
2010c03c5b1cSMartin Matuska /* Sequences Header */
2011c03c5b1cSMartin Matuska RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,
2012c03c5b1cSMartin Matuska dstSize_tooSmall, "Can't fit seq hdr in output buf!");
2013c03c5b1cSMartin Matuska if (nbSeq < 128) {
2014c03c5b1cSMartin Matuska *op++ = (BYTE)nbSeq;
2015c03c5b1cSMartin Matuska } else if (nbSeq < LONGNBSEQ) {
2016c03c5b1cSMartin Matuska op[0] = (BYTE)((nbSeq>>8) + 0x80);
2017c03c5b1cSMartin Matuska op[1] = (BYTE)nbSeq;
2018c03c5b1cSMartin Matuska op+=2;
2019c03c5b1cSMartin Matuska } else {
2020c03c5b1cSMartin Matuska op[0]=0xFF;
2021c03c5b1cSMartin Matuska MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ));
2022c03c5b1cSMartin Matuska op+=3;
2023c03c5b1cSMartin Matuska }
2024c03c5b1cSMartin Matuska assert(op <= oend);
2025c03c5b1cSMartin Matuska if (nbSeq==0) {
2026c03c5b1cSMartin Matuska /* Copy the old tables over as if we repeated them */
2027c03c5b1cSMartin Matuska memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
2028c03c5b1cSMartin Matuska return (size_t)(op - ostart);
2029c03c5b1cSMartin Matuska }
2030c03c5b1cSMartin Matuska
2031c03c5b1cSMartin Matuska /* seqHead : flags for FSE encoding type */
2032c03c5b1cSMartin Matuska seqHead = op++;
2033c03c5b1cSMartin Matuska assert(op <= oend);
2034c03c5b1cSMartin Matuska
2035c03c5b1cSMartin Matuska /* convert length/distances into codes */
2036c03c5b1cSMartin Matuska ZSTD_seqToCodes(seqStorePtr);
2037c03c5b1cSMartin Matuska /* build CTable for Literal Lengths */
2038c03c5b1cSMartin Matuska { unsigned max = MaxLL;
2039c03c5b1cSMartin Matuska size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
2040c03c5b1cSMartin Matuska DEBUGLOG(5, "Building LL table");
2041c03c5b1cSMartin Matuska nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode;
2042c03c5b1cSMartin Matuska LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode,
2043c03c5b1cSMartin Matuska count, max, mostFrequent, nbSeq,
2044c03c5b1cSMartin Matuska LLFSELog, prevEntropy->fse.litlengthCTable,
2045c03c5b1cSMartin Matuska LL_defaultNorm, LL_defaultNormLog,
2046c03c5b1cSMartin Matuska ZSTD_defaultAllowed, strategy);
2047c03c5b1cSMartin Matuska assert(set_basic < set_compressed && set_rle < set_compressed);
2048c03c5b1cSMartin Matuska assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
2049c03c5b1cSMartin Matuska { size_t const countSize = ZSTD_buildCTable(
2050c03c5b1cSMartin Matuska op, (size_t)(oend - op),
2051c03c5b1cSMartin Matuska CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
2052c03c5b1cSMartin Matuska count, max, llCodeTable, nbSeq,
2053c03c5b1cSMartin Matuska LL_defaultNorm, LL_defaultNormLog, MaxLL,
2054c03c5b1cSMartin Matuska prevEntropy->fse.litlengthCTable,
2055c03c5b1cSMartin Matuska sizeof(prevEntropy->fse.litlengthCTable),
2056c03c5b1cSMartin Matuska entropyWorkspace, entropyWkspSize);
2057c03c5b1cSMartin Matuska FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
2058c03c5b1cSMartin Matuska if (LLtype == set_compressed)
2059c03c5b1cSMartin Matuska lastNCount = op;
2060c03c5b1cSMartin Matuska op += countSize;
2061c03c5b1cSMartin Matuska assert(op <= oend);
2062c03c5b1cSMartin Matuska } }
2063c03c5b1cSMartin Matuska /* build CTable for Offsets */
2064c03c5b1cSMartin Matuska { unsigned max = MaxOff;
2065c03c5b1cSMartin Matuska size_t const mostFrequent = HIST_countFast_wksp(
2066c03c5b1cSMartin Matuska count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
2067c03c5b1cSMartin Matuska /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
2068c03c5b1cSMartin Matuska ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
2069c03c5b1cSMartin Matuska DEBUGLOG(5, "Building OF table");
2070c03c5b1cSMartin Matuska nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode;
2071c03c5b1cSMartin Matuska Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode,
2072c03c5b1cSMartin Matuska count, max, mostFrequent, nbSeq,
2073c03c5b1cSMartin Matuska OffFSELog, prevEntropy->fse.offcodeCTable,
2074c03c5b1cSMartin Matuska OF_defaultNorm, OF_defaultNormLog,
2075c03c5b1cSMartin Matuska defaultPolicy, strategy);
2076c03c5b1cSMartin Matuska assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
2077c03c5b1cSMartin Matuska { size_t const countSize = ZSTD_buildCTable(
2078c03c5b1cSMartin Matuska op, (size_t)(oend - op),
2079c03c5b1cSMartin Matuska CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
2080c03c5b1cSMartin Matuska count, max, ofCodeTable, nbSeq,
2081c03c5b1cSMartin Matuska OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
2082c03c5b1cSMartin Matuska prevEntropy->fse.offcodeCTable,
2083c03c5b1cSMartin Matuska sizeof(prevEntropy->fse.offcodeCTable),
2084c03c5b1cSMartin Matuska entropyWorkspace, entropyWkspSize);
2085c03c5b1cSMartin Matuska FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
2086c03c5b1cSMartin Matuska if (Offtype == set_compressed)
2087c03c5b1cSMartin Matuska lastNCount = op;
2088c03c5b1cSMartin Matuska op += countSize;
2089c03c5b1cSMartin Matuska assert(op <= oend);
2090c03c5b1cSMartin Matuska } }
2091c03c5b1cSMartin Matuska /* build CTable for MatchLengths */
2092c03c5b1cSMartin Matuska { unsigned max = MaxML;
2093c03c5b1cSMartin Matuska size_t const mostFrequent = HIST_countFast_wksp(
2094c03c5b1cSMartin Matuska count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */
2095c03c5b1cSMartin Matuska DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
2096c03c5b1cSMartin Matuska nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode;
2097c03c5b1cSMartin Matuska MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode,
2098c03c5b1cSMartin Matuska count, max, mostFrequent, nbSeq,
2099c03c5b1cSMartin Matuska MLFSELog, prevEntropy->fse.matchlengthCTable,
2100c03c5b1cSMartin Matuska ML_defaultNorm, ML_defaultNormLog,
2101c03c5b1cSMartin Matuska ZSTD_defaultAllowed, strategy);
2102c03c5b1cSMartin Matuska assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
2103c03c5b1cSMartin Matuska { size_t const countSize = ZSTD_buildCTable(
2104c03c5b1cSMartin Matuska op, (size_t)(oend - op),
2105c03c5b1cSMartin Matuska CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
2106c03c5b1cSMartin Matuska count, max, mlCodeTable, nbSeq,
2107c03c5b1cSMartin Matuska ML_defaultNorm, ML_defaultNormLog, MaxML,
2108c03c5b1cSMartin Matuska prevEntropy->fse.matchlengthCTable,
2109c03c5b1cSMartin Matuska sizeof(prevEntropy->fse.matchlengthCTable),
2110c03c5b1cSMartin Matuska entropyWorkspace, entropyWkspSize);
2111c03c5b1cSMartin Matuska FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
2112c03c5b1cSMartin Matuska if (MLtype == set_compressed)
2113c03c5b1cSMartin Matuska lastNCount = op;
2114c03c5b1cSMartin Matuska op += countSize;
2115c03c5b1cSMartin Matuska assert(op <= oend);
2116c03c5b1cSMartin Matuska } }
2117c03c5b1cSMartin Matuska
2118c03c5b1cSMartin Matuska *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
2119c03c5b1cSMartin Matuska
2120c03c5b1cSMartin Matuska { size_t const bitstreamSize = ZSTD_encodeSequences(
2121c03c5b1cSMartin Matuska op, (size_t)(oend - op),
2122c03c5b1cSMartin Matuska CTable_MatchLength, mlCodeTable,
2123c03c5b1cSMartin Matuska CTable_OffsetBits, ofCodeTable,
2124c03c5b1cSMartin Matuska CTable_LitLength, llCodeTable,
2125c03c5b1cSMartin Matuska sequences, nbSeq,
2126c03c5b1cSMartin Matuska longOffsets, bmi2);
2127c03c5b1cSMartin Matuska FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed");
2128c03c5b1cSMartin Matuska op += bitstreamSize;
2129c03c5b1cSMartin Matuska assert(op <= oend);
2130c03c5b1cSMartin Matuska /* zstd versions <= 1.3.4 mistakenly report corruption when
2131c03c5b1cSMartin Matuska * FSE_readNCount() receives a buffer < 4 bytes.
2132c03c5b1cSMartin Matuska * Fixed by https://github.com/facebook/zstd/pull/1146.
2133c03c5b1cSMartin Matuska * This can happen when the last set_compressed table present is 2
2134c03c5b1cSMartin Matuska * bytes and the bitstream is only one byte.
2135c03c5b1cSMartin Matuska * In this exceedingly rare case, we will simply emit an uncompressed
2136c03c5b1cSMartin Matuska * block, since it isn't worth optimizing.
2137c03c5b1cSMartin Matuska */
2138c03c5b1cSMartin Matuska if (lastNCount && (op - lastNCount) < 4) {
2139c03c5b1cSMartin Matuska /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
2140c03c5b1cSMartin Matuska assert(op - lastNCount == 3);
2141c03c5b1cSMartin Matuska DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
2142c03c5b1cSMartin Matuska "emitting an uncompressed block.");
2143c03c5b1cSMartin Matuska return 0;
2144c03c5b1cSMartin Matuska }
2145c03c5b1cSMartin Matuska }
2146c03c5b1cSMartin Matuska
2147c03c5b1cSMartin Matuska DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart));
2148c03c5b1cSMartin Matuska return (size_t)(op - ostart);
2149c03c5b1cSMartin Matuska }
2150c03c5b1cSMartin Matuska
2151c03c5b1cSMartin Matuska MEM_STATIC size_t
ZSTD_compressSequences(seqStore_t * seqStorePtr,const ZSTD_entropyCTables_t * prevEntropy,ZSTD_entropyCTables_t * nextEntropy,const ZSTD_CCtx_params * cctxParams,void * dst,size_t dstCapacity,size_t srcSize,void * entropyWorkspace,size_t entropyWkspSize,int bmi2)2152c03c5b1cSMartin Matuska ZSTD_compressSequences(seqStore_t* seqStorePtr,
2153c03c5b1cSMartin Matuska const ZSTD_entropyCTables_t* prevEntropy,
2154c03c5b1cSMartin Matuska ZSTD_entropyCTables_t* nextEntropy,
2155c03c5b1cSMartin Matuska const ZSTD_CCtx_params* cctxParams,
2156c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
2157c03c5b1cSMartin Matuska size_t srcSize,
2158c03c5b1cSMartin Matuska void* entropyWorkspace, size_t entropyWkspSize,
2159c03c5b1cSMartin Matuska int bmi2)
2160c03c5b1cSMartin Matuska {
2161c03c5b1cSMartin Matuska size_t const cSize = ZSTD_compressSequences_internal(
2162c03c5b1cSMartin Matuska seqStorePtr, prevEntropy, nextEntropy, cctxParams,
2163c03c5b1cSMartin Matuska dst, dstCapacity,
2164c03c5b1cSMartin Matuska entropyWorkspace, entropyWkspSize, bmi2);
2165c03c5b1cSMartin Matuska if (cSize == 0) return 0;
2166c03c5b1cSMartin Matuska /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block.
2167c03c5b1cSMartin Matuska * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block.
2168c03c5b1cSMartin Matuska */
2169c03c5b1cSMartin Matuska if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
2170c03c5b1cSMartin Matuska return 0; /* block not compressed */
2171c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "ZSTD_compressSequences_internal failed");
2172c03c5b1cSMartin Matuska
2173c03c5b1cSMartin Matuska /* Check compressibility */
2174c03c5b1cSMartin Matuska { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
2175c03c5b1cSMartin Matuska if (cSize >= maxCSize) return 0; /* block not compressed */
2176c03c5b1cSMartin Matuska }
2177c03c5b1cSMartin Matuska
2178c03c5b1cSMartin Matuska return cSize;
2179c03c5b1cSMartin Matuska }
2180c03c5b1cSMartin Matuska
2181c03c5b1cSMartin Matuska /* ZSTD_selectBlockCompressor() :
2182c03c5b1cSMartin Matuska * Not static, but internal use only (used by long distance matcher)
2183c03c5b1cSMartin Matuska * assumption : strat is a valid strategy */
ZSTD_selectBlockCompressor(ZSTD_strategy strat,ZSTD_dictMode_e dictMode)2184c03c5b1cSMartin Matuska ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
2185c03c5b1cSMartin Matuska {
2186c03c5b1cSMartin Matuska static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = {
2187c03c5b1cSMartin Matuska { ZSTD_compressBlock_fast /* default for 0 */,
2188c03c5b1cSMartin Matuska ZSTD_compressBlock_fast,
2189c03c5b1cSMartin Matuska ZSTD_compressBlock_doubleFast,
2190c03c5b1cSMartin Matuska ZSTD_compressBlock_greedy,
2191c03c5b1cSMartin Matuska ZSTD_compressBlock_lazy,
2192c03c5b1cSMartin Matuska ZSTD_compressBlock_lazy2,
2193c03c5b1cSMartin Matuska ZSTD_compressBlock_btlazy2,
2194c03c5b1cSMartin Matuska ZSTD_compressBlock_btopt,
2195c03c5b1cSMartin Matuska ZSTD_compressBlock_btultra,
2196c03c5b1cSMartin Matuska ZSTD_compressBlock_btultra2 },
2197c03c5b1cSMartin Matuska { ZSTD_compressBlock_fast_extDict /* default for 0 */,
2198c03c5b1cSMartin Matuska ZSTD_compressBlock_fast_extDict,
2199c03c5b1cSMartin Matuska ZSTD_compressBlock_doubleFast_extDict,
2200c03c5b1cSMartin Matuska ZSTD_compressBlock_greedy_extDict,
2201c03c5b1cSMartin Matuska ZSTD_compressBlock_lazy_extDict,
2202c03c5b1cSMartin Matuska ZSTD_compressBlock_lazy2_extDict,
2203c03c5b1cSMartin Matuska ZSTD_compressBlock_btlazy2_extDict,
2204c03c5b1cSMartin Matuska ZSTD_compressBlock_btopt_extDict,
2205c03c5b1cSMartin Matuska ZSTD_compressBlock_btultra_extDict,
2206c03c5b1cSMartin Matuska ZSTD_compressBlock_btultra_extDict },
2207c03c5b1cSMartin Matuska { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */,
2208c03c5b1cSMartin Matuska ZSTD_compressBlock_fast_dictMatchState,
2209c03c5b1cSMartin Matuska ZSTD_compressBlock_doubleFast_dictMatchState,
2210c03c5b1cSMartin Matuska ZSTD_compressBlock_greedy_dictMatchState,
2211c03c5b1cSMartin Matuska ZSTD_compressBlock_lazy_dictMatchState,
2212c03c5b1cSMartin Matuska ZSTD_compressBlock_lazy2_dictMatchState,
2213c03c5b1cSMartin Matuska ZSTD_compressBlock_btlazy2_dictMatchState,
2214c03c5b1cSMartin Matuska ZSTD_compressBlock_btopt_dictMatchState,
2215c03c5b1cSMartin Matuska ZSTD_compressBlock_btultra_dictMatchState,
2216c03c5b1cSMartin Matuska ZSTD_compressBlock_btultra_dictMatchState }
2217c03c5b1cSMartin Matuska };
2218c03c5b1cSMartin Matuska ZSTD_blockCompressor selectedCompressor;
2219c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
2220c03c5b1cSMartin Matuska
2221c03c5b1cSMartin Matuska assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
2222c03c5b1cSMartin Matuska selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
2223c03c5b1cSMartin Matuska assert(selectedCompressor != NULL);
2224c03c5b1cSMartin Matuska return selectedCompressor;
2225c03c5b1cSMartin Matuska }
2226c03c5b1cSMartin Matuska
ZSTD_storeLastLiterals(seqStore_t * seqStorePtr,const BYTE * anchor,size_t lastLLSize)2227c03c5b1cSMartin Matuska static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
2228c03c5b1cSMartin Matuska const BYTE* anchor, size_t lastLLSize)
2229c03c5b1cSMartin Matuska {
2230c03c5b1cSMartin Matuska memcpy(seqStorePtr->lit, anchor, lastLLSize);
2231c03c5b1cSMartin Matuska seqStorePtr->lit += lastLLSize;
2232c03c5b1cSMartin Matuska }
2233c03c5b1cSMartin Matuska
ZSTD_resetSeqStore(seqStore_t * ssPtr)2234c03c5b1cSMartin Matuska void ZSTD_resetSeqStore(seqStore_t* ssPtr)
2235c03c5b1cSMartin Matuska {
2236c03c5b1cSMartin Matuska ssPtr->lit = ssPtr->litStart;
2237c03c5b1cSMartin Matuska ssPtr->sequences = ssPtr->sequencesStart;
2238c03c5b1cSMartin Matuska ssPtr->longLengthID = 0;
2239c03c5b1cSMartin Matuska }
2240c03c5b1cSMartin Matuska
2241c03c5b1cSMartin Matuska typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e;
2242c03c5b1cSMartin Matuska
ZSTD_buildSeqStore(ZSTD_CCtx * zc,const void * src,size_t srcSize)2243c03c5b1cSMartin Matuska static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2244c03c5b1cSMartin Matuska {
2245c03c5b1cSMartin Matuska ZSTD_matchState_t* const ms = &zc->blockState.matchState;
2246c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_buildSeqStore (srcSize=%zu)", srcSize);
2247c03c5b1cSMartin Matuska assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
2248c03c5b1cSMartin Matuska /* Assert that we have correctly flushed the ctx params into the ms's copy */
2249c03c5b1cSMartin Matuska ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams);
2250c03c5b1cSMartin Matuska if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
2251c03c5b1cSMartin Matuska ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
2252c03c5b1cSMartin Matuska return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */
2253c03c5b1cSMartin Matuska }
2254c03c5b1cSMartin Matuska ZSTD_resetSeqStore(&(zc->seqStore));
2255c03c5b1cSMartin Matuska /* required for optimal parser to read stats from dictionary */
2256c03c5b1cSMartin Matuska ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy;
2257c03c5b1cSMartin Matuska /* tell the optimal parser how we expect to compress literals */
2258c03c5b1cSMartin Matuska ms->opt.literalCompressionMode = zc->appliedParams.literalCompressionMode;
2259c03c5b1cSMartin Matuska /* a gap between an attached dict and the current window is not safe,
2260c03c5b1cSMartin Matuska * they must remain adjacent,
2261c03c5b1cSMartin Matuska * and when that stops being the case, the dict must be unset */
2262c03c5b1cSMartin Matuska assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit);
2263c03c5b1cSMartin Matuska
2264c03c5b1cSMartin Matuska /* limited update after a very long match */
2265c03c5b1cSMartin Matuska { const BYTE* const base = ms->window.base;
2266c03c5b1cSMartin Matuska const BYTE* const istart = (const BYTE*)src;
2267c03c5b1cSMartin Matuska const U32 current = (U32)(istart-base);
2268c03c5b1cSMartin Matuska if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */
2269c03c5b1cSMartin Matuska if (current > ms->nextToUpdate + 384)
2270c03c5b1cSMartin Matuska ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384));
2271c03c5b1cSMartin Matuska }
2272c03c5b1cSMartin Matuska
2273c03c5b1cSMartin Matuska /* select and store sequences */
2274c03c5b1cSMartin Matuska { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms);
2275c03c5b1cSMartin Matuska size_t lastLLSize;
2276c03c5b1cSMartin Matuska { int i;
2277c03c5b1cSMartin Matuska for (i = 0; i < ZSTD_REP_NUM; ++i)
2278c03c5b1cSMartin Matuska zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i];
2279c03c5b1cSMartin Matuska }
2280c03c5b1cSMartin Matuska if (zc->externSeqStore.pos < zc->externSeqStore.size) {
2281c03c5b1cSMartin Matuska assert(!zc->appliedParams.ldmParams.enableLdm);
2282c03c5b1cSMartin Matuska /* Updates ldmSeqStore.pos */
2283c03c5b1cSMartin Matuska lastLLSize =
2284c03c5b1cSMartin Matuska ZSTD_ldm_blockCompress(&zc->externSeqStore,
2285c03c5b1cSMartin Matuska ms, &zc->seqStore,
2286c03c5b1cSMartin Matuska zc->blockState.nextCBlock->rep,
2287c03c5b1cSMartin Matuska src, srcSize);
2288c03c5b1cSMartin Matuska assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
2289c03c5b1cSMartin Matuska } else if (zc->appliedParams.ldmParams.enableLdm) {
2290c03c5b1cSMartin Matuska rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
2291c03c5b1cSMartin Matuska
2292c03c5b1cSMartin Matuska ldmSeqStore.seq = zc->ldmSequences;
2293c03c5b1cSMartin Matuska ldmSeqStore.capacity = zc->maxNbLdmSequences;
2294c03c5b1cSMartin Matuska /* Updates ldmSeqStore.size */
2295c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore,
2296c03c5b1cSMartin Matuska &zc->appliedParams.ldmParams,
2297c03c5b1cSMartin Matuska src, srcSize), "");
2298c03c5b1cSMartin Matuska /* Updates ldmSeqStore.pos */
2299c03c5b1cSMartin Matuska lastLLSize =
2300c03c5b1cSMartin Matuska ZSTD_ldm_blockCompress(&ldmSeqStore,
2301c03c5b1cSMartin Matuska ms, &zc->seqStore,
2302c03c5b1cSMartin Matuska zc->blockState.nextCBlock->rep,
2303c03c5b1cSMartin Matuska src, srcSize);
2304c03c5b1cSMartin Matuska assert(ldmSeqStore.pos == ldmSeqStore.size);
2305c03c5b1cSMartin Matuska } else { /* not long range mode */
2306c03c5b1cSMartin Matuska ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
2307c03c5b1cSMartin Matuska lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
2308c03c5b1cSMartin Matuska }
2309c03c5b1cSMartin Matuska { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
2310c03c5b1cSMartin Matuska ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize);
2311c03c5b1cSMartin Matuska } }
2312c03c5b1cSMartin Matuska return ZSTDbss_compress;
2313c03c5b1cSMartin Matuska }
2314c03c5b1cSMartin Matuska
ZSTD_copyBlockSequences(ZSTD_CCtx * zc)2315c03c5b1cSMartin Matuska static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
2316c03c5b1cSMartin Matuska {
2317c03c5b1cSMartin Matuska const seqStore_t* seqStore = ZSTD_getSeqStore(zc);
2318c03c5b1cSMartin Matuska const seqDef* seqs = seqStore->sequencesStart;
2319c03c5b1cSMartin Matuska size_t seqsSize = seqStore->sequences - seqs;
2320c03c5b1cSMartin Matuska
2321c03c5b1cSMartin Matuska ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex];
2322c03c5b1cSMartin Matuska size_t i; size_t position; int repIdx;
2323c03c5b1cSMartin Matuska
2324c03c5b1cSMartin Matuska assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences);
2325c03c5b1cSMartin Matuska for (i = 0, position = 0; i < seqsSize; ++i) {
2326c03c5b1cSMartin Matuska outSeqs[i].offset = seqs[i].offset;
2327c03c5b1cSMartin Matuska outSeqs[i].litLength = seqs[i].litLength;
2328c03c5b1cSMartin Matuska outSeqs[i].matchLength = seqs[i].matchLength + MINMATCH;
2329c03c5b1cSMartin Matuska
2330c03c5b1cSMartin Matuska if (i == seqStore->longLengthPos) {
2331c03c5b1cSMartin Matuska if (seqStore->longLengthID == 1) {
2332c03c5b1cSMartin Matuska outSeqs[i].litLength += 0x10000;
2333c03c5b1cSMartin Matuska } else if (seqStore->longLengthID == 2) {
2334c03c5b1cSMartin Matuska outSeqs[i].matchLength += 0x10000;
2335c03c5b1cSMartin Matuska }
2336c03c5b1cSMartin Matuska }
2337c03c5b1cSMartin Matuska
2338c03c5b1cSMartin Matuska if (outSeqs[i].offset <= ZSTD_REP_NUM) {
2339c03c5b1cSMartin Matuska outSeqs[i].rep = outSeqs[i].offset;
2340c03c5b1cSMartin Matuska repIdx = (unsigned int)i - outSeqs[i].offset;
2341c03c5b1cSMartin Matuska
2342c03c5b1cSMartin Matuska if (outSeqs[i].litLength == 0) {
2343c03c5b1cSMartin Matuska if (outSeqs[i].offset < 3) {
2344c03c5b1cSMartin Matuska --repIdx;
2345c03c5b1cSMartin Matuska } else {
2346c03c5b1cSMartin Matuska repIdx = (unsigned int)i - 1;
2347c03c5b1cSMartin Matuska }
2348c03c5b1cSMartin Matuska ++outSeqs[i].rep;
2349c03c5b1cSMartin Matuska }
2350c03c5b1cSMartin Matuska assert(repIdx >= -3);
2351c03c5b1cSMartin Matuska outSeqs[i].offset = repIdx >= 0 ? outSeqs[repIdx].offset : repStartValue[-repIdx - 1];
2352c03c5b1cSMartin Matuska if (outSeqs[i].rep == 4) {
2353c03c5b1cSMartin Matuska --outSeqs[i].offset;
2354c03c5b1cSMartin Matuska }
2355c03c5b1cSMartin Matuska } else {
2356c03c5b1cSMartin Matuska outSeqs[i].offset -= ZSTD_REP_NUM;
2357c03c5b1cSMartin Matuska }
2358c03c5b1cSMartin Matuska
2359c03c5b1cSMartin Matuska position += outSeqs[i].litLength;
2360c03c5b1cSMartin Matuska outSeqs[i].matchPos = (unsigned int)position;
2361c03c5b1cSMartin Matuska position += outSeqs[i].matchLength;
2362c03c5b1cSMartin Matuska }
2363c03c5b1cSMartin Matuska zc->seqCollector.seqIndex += seqsSize;
2364c03c5b1cSMartin Matuska }
2365c03c5b1cSMartin Matuska
ZSTD_getSequences(ZSTD_CCtx * zc,ZSTD_Sequence * outSeqs,size_t outSeqsSize,const void * src,size_t srcSize)2366c03c5b1cSMartin Matuska size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
2367c03c5b1cSMartin Matuska size_t outSeqsSize, const void* src, size_t srcSize)
2368c03c5b1cSMartin Matuska {
2369c03c5b1cSMartin Matuska const size_t dstCapacity = ZSTD_compressBound(srcSize);
2370c03c5b1cSMartin Matuska void* dst = ZSTD_malloc(dstCapacity, ZSTD_defaultCMem);
2371c03c5b1cSMartin Matuska SeqCollector seqCollector;
2372c03c5b1cSMartin Matuska
2373c03c5b1cSMartin Matuska RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!");
2374c03c5b1cSMartin Matuska
2375c03c5b1cSMartin Matuska seqCollector.collectSequences = 1;
2376c03c5b1cSMartin Matuska seqCollector.seqStart = outSeqs;
2377c03c5b1cSMartin Matuska seqCollector.seqIndex = 0;
2378c03c5b1cSMartin Matuska seqCollector.maxSequences = outSeqsSize;
2379c03c5b1cSMartin Matuska zc->seqCollector = seqCollector;
2380c03c5b1cSMartin Matuska
2381c03c5b1cSMartin Matuska ZSTD_compress2(zc, dst, dstCapacity, src, srcSize);
2382c03c5b1cSMartin Matuska ZSTD_free(dst, ZSTD_defaultCMem);
2383c03c5b1cSMartin Matuska return zc->seqCollector.seqIndex;
2384c03c5b1cSMartin Matuska }
2385c03c5b1cSMartin Matuska
2386c03c5b1cSMartin Matuska /* Returns true if the given block is a RLE block */
ZSTD_isRLE(const BYTE * ip,size_t length)2387c03c5b1cSMartin Matuska static int ZSTD_isRLE(const BYTE *ip, size_t length) {
2388c03c5b1cSMartin Matuska size_t i;
2389c03c5b1cSMartin Matuska if (length < 2) return 1;
2390c03c5b1cSMartin Matuska for (i = 1; i < length; ++i) {
2391c03c5b1cSMartin Matuska if (ip[0] != ip[i]) return 0;
2392c03c5b1cSMartin Matuska }
2393c03c5b1cSMartin Matuska return 1;
2394c03c5b1cSMartin Matuska }
2395c03c5b1cSMartin Matuska
2396c03c5b1cSMartin Matuska /* Returns true if the given block may be RLE.
2397c03c5b1cSMartin Matuska * This is just a heuristic based on the compressibility.
2398c03c5b1cSMartin Matuska * It may return both false positives and false negatives.
2399c03c5b1cSMartin Matuska */
ZSTD_maybeRLE(seqStore_t const * seqStore)2400c03c5b1cSMartin Matuska static int ZSTD_maybeRLE(seqStore_t const* seqStore)
2401c03c5b1cSMartin Matuska {
2402c03c5b1cSMartin Matuska size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart);
2403c03c5b1cSMartin Matuska size_t const nbLits = (size_t)(seqStore->lit - seqStore->litStart);
2404c03c5b1cSMartin Matuska
2405c03c5b1cSMartin Matuska return nbSeqs < 4 && nbLits < 10;
2406c03c5b1cSMartin Matuska }
2407c03c5b1cSMartin Matuska
ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx * zc)2408c03c5b1cSMartin Matuska static void ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx* zc)
2409c03c5b1cSMartin Matuska {
2410c03c5b1cSMartin Matuska ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
2411c03c5b1cSMartin Matuska zc->blockState.prevCBlock = zc->blockState.nextCBlock;
2412c03c5b1cSMartin Matuska zc->blockState.nextCBlock = tmp;
2413c03c5b1cSMartin Matuska }
2414c03c5b1cSMartin Matuska
ZSTD_compressBlock_internal(ZSTD_CCtx * zc,void * dst,size_t dstCapacity,const void * src,size_t srcSize,U32 frame)2415c03c5b1cSMartin Matuska static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
2416c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
2417c03c5b1cSMartin Matuska const void* src, size_t srcSize, U32 frame)
2418c03c5b1cSMartin Matuska {
2419c03c5b1cSMartin Matuska /* This the upper bound for the length of an rle block.
2420c03c5b1cSMartin Matuska * This isn't the actual upper bound. Finding the real threshold
2421c03c5b1cSMartin Matuska * needs further investigation.
2422c03c5b1cSMartin Matuska */
2423c03c5b1cSMartin Matuska const U32 rleMaxLength = 25;
2424c03c5b1cSMartin Matuska size_t cSize;
2425c03c5b1cSMartin Matuska const BYTE* ip = (const BYTE*)src;
2426c03c5b1cSMartin Matuska BYTE* op = (BYTE*)dst;
2427c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
2428c03c5b1cSMartin Matuska (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit,
2429c03c5b1cSMartin Matuska (unsigned)zc->blockState.matchState.nextToUpdate);
2430c03c5b1cSMartin Matuska
2431c03c5b1cSMartin Matuska { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
2432c03c5b1cSMartin Matuska FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
2433c03c5b1cSMartin Matuska if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; }
2434c03c5b1cSMartin Matuska }
2435c03c5b1cSMartin Matuska
2436c03c5b1cSMartin Matuska if (zc->seqCollector.collectSequences) {
2437c03c5b1cSMartin Matuska ZSTD_copyBlockSequences(zc);
2438c03c5b1cSMartin Matuska return 0;
2439c03c5b1cSMartin Matuska }
2440c03c5b1cSMartin Matuska
2441c03c5b1cSMartin Matuska /* encode sequences and literals */
2442c03c5b1cSMartin Matuska cSize = ZSTD_compressSequences(&zc->seqStore,
2443c03c5b1cSMartin Matuska &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
2444c03c5b1cSMartin Matuska &zc->appliedParams,
2445c03c5b1cSMartin Matuska dst, dstCapacity,
2446c03c5b1cSMartin Matuska srcSize,
2447c03c5b1cSMartin Matuska zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
2448c03c5b1cSMartin Matuska zc->bmi2);
2449c03c5b1cSMartin Matuska
2450c03c5b1cSMartin Matuska if (frame &&
2451c03c5b1cSMartin Matuska /* We don't want to emit our first block as a RLE even if it qualifies because
2452c03c5b1cSMartin Matuska * doing so will cause the decoder (cli only) to throw a "should consume all input error."
2453c03c5b1cSMartin Matuska * This is only an issue for zstd <= v1.4.3
2454c03c5b1cSMartin Matuska */
2455c03c5b1cSMartin Matuska !zc->isFirstBlock &&
2456c03c5b1cSMartin Matuska cSize < rleMaxLength &&
2457c03c5b1cSMartin Matuska ZSTD_isRLE(ip, srcSize))
2458c03c5b1cSMartin Matuska {
2459c03c5b1cSMartin Matuska cSize = 1;
2460c03c5b1cSMartin Matuska op[0] = ip[0];
2461c03c5b1cSMartin Matuska }
2462c03c5b1cSMartin Matuska
2463c03c5b1cSMartin Matuska out:
2464c03c5b1cSMartin Matuska if (!ZSTD_isError(cSize) && cSize > 1) {
2465c03c5b1cSMartin Matuska ZSTD_confirmRepcodesAndEntropyTables(zc);
2466c03c5b1cSMartin Matuska }
2467c03c5b1cSMartin Matuska /* We check that dictionaries have offset codes available for the first
2468c03c5b1cSMartin Matuska * block. After the first block, the offcode table might not have large
2469c03c5b1cSMartin Matuska * enough codes to represent the offsets in the data.
2470c03c5b1cSMartin Matuska */
2471c03c5b1cSMartin Matuska if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
2472c03c5b1cSMartin Matuska zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
2473c03c5b1cSMartin Matuska
2474c03c5b1cSMartin Matuska return cSize;
2475c03c5b1cSMartin Matuska }
2476c03c5b1cSMartin Matuska
ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx * zc,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const size_t bss,U32 lastBlock)2477c03c5b1cSMartin Matuska static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc,
2478c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
2479c03c5b1cSMartin Matuska const void* src, size_t srcSize,
2480c03c5b1cSMartin Matuska const size_t bss, U32 lastBlock)
2481c03c5b1cSMartin Matuska {
2482c03c5b1cSMartin Matuska DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()");
2483c03c5b1cSMartin Matuska if (bss == ZSTDbss_compress) {
2484c03c5b1cSMartin Matuska if (/* We don't want to emit our first block as a RLE even if it qualifies because
2485c03c5b1cSMartin Matuska * doing so will cause the decoder (cli only) to throw a "should consume all input error."
2486c03c5b1cSMartin Matuska * This is only an issue for zstd <= v1.4.3
2487c03c5b1cSMartin Matuska */
2488c03c5b1cSMartin Matuska !zc->isFirstBlock &&
2489c03c5b1cSMartin Matuska ZSTD_maybeRLE(&zc->seqStore) &&
2490c03c5b1cSMartin Matuska ZSTD_isRLE((BYTE const*)src, srcSize))
2491c03c5b1cSMartin Matuska {
2492c03c5b1cSMartin Matuska return ZSTD_rleCompressBlock(dst, dstCapacity, *(BYTE const*)src, srcSize, lastBlock);
2493c03c5b1cSMartin Matuska }
2494c03c5b1cSMartin Matuska /* Attempt superblock compression.
2495c03c5b1cSMartin Matuska *
2496c03c5b1cSMartin Matuska * Note that compressed size of ZSTD_compressSuperBlock() is not bound by the
2497c03c5b1cSMartin Matuska * standard ZSTD_compressBound(). This is a problem, because even if we have
2498c03c5b1cSMartin Matuska * space now, taking an extra byte now could cause us to run out of space later
2499c03c5b1cSMartin Matuska * and violate ZSTD_compressBound().
2500c03c5b1cSMartin Matuska *
2501c03c5b1cSMartin Matuska * Define blockBound(blockSize) = blockSize + ZSTD_blockHeaderSize.
2502c03c5b1cSMartin Matuska *
2503c03c5b1cSMartin Matuska * In order to respect ZSTD_compressBound() we must attempt to emit a raw
2504c03c5b1cSMartin Matuska * uncompressed block in these cases:
2505c03c5b1cSMartin Matuska * * cSize == 0: Return code for an uncompressed block.
2506c03c5b1cSMartin Matuska * * cSize == dstSize_tooSmall: We may have expanded beyond blockBound(srcSize).
2507c03c5b1cSMartin Matuska * ZSTD_noCompressBlock() will return dstSize_tooSmall if we are really out of
2508c03c5b1cSMartin Matuska * output space.
2509c03c5b1cSMartin Matuska * * cSize >= blockBound(srcSize): We have expanded the block too much so
2510c03c5b1cSMartin Matuska * emit an uncompressed block.
2511c03c5b1cSMartin Matuska */
2512c03c5b1cSMartin Matuska {
2513c03c5b1cSMartin Matuska size_t const cSize = ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock);
2514c03c5b1cSMartin Matuska if (cSize != ERROR(dstSize_tooSmall)) {
2515c03c5b1cSMartin Matuska size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy);
2516c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed");
2517c03c5b1cSMartin Matuska if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) {
2518c03c5b1cSMartin Matuska ZSTD_confirmRepcodesAndEntropyTables(zc);
2519c03c5b1cSMartin Matuska return cSize;
2520c03c5b1cSMartin Matuska }
2521c03c5b1cSMartin Matuska }
2522c03c5b1cSMartin Matuska }
2523c03c5b1cSMartin Matuska }
2524c03c5b1cSMartin Matuska
2525c03c5b1cSMartin Matuska DEBUGLOG(6, "Resorting to ZSTD_noCompressBlock()");
2526c03c5b1cSMartin Matuska /* Superblock compression failed, attempt to emit a single no compress block.
2527c03c5b1cSMartin Matuska * The decoder will be able to stream this block since it is uncompressed.
2528c03c5b1cSMartin Matuska */
2529c03c5b1cSMartin Matuska return ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock);
2530c03c5b1cSMartin Matuska }
2531c03c5b1cSMartin Matuska
ZSTD_compressBlock_targetCBlockSize(ZSTD_CCtx * zc,void * dst,size_t dstCapacity,const void * src,size_t srcSize,U32 lastBlock)2532c03c5b1cSMartin Matuska static size_t ZSTD_compressBlock_targetCBlockSize(ZSTD_CCtx* zc,
2533c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
2534c03c5b1cSMartin Matuska const void* src, size_t srcSize,
2535c03c5b1cSMartin Matuska U32 lastBlock)
2536c03c5b1cSMartin Matuska {
2537c03c5b1cSMartin Matuska size_t cSize = 0;
2538c03c5b1cSMartin Matuska const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
2539c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compressBlock_targetCBlockSize (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u, srcSize=%zu)",
2540c03c5b1cSMartin Matuska (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate, srcSize);
2541c03c5b1cSMartin Matuska FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
2542c03c5b1cSMartin Matuska
2543c03c5b1cSMartin Matuska cSize = ZSTD_compressBlock_targetCBlockSize_body(zc, dst, dstCapacity, src, srcSize, bss, lastBlock);
2544c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize_body failed");
2545c03c5b1cSMartin Matuska
2546c03c5b1cSMartin Matuska if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
2547c03c5b1cSMartin Matuska zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
2548c03c5b1cSMartin Matuska
2549c03c5b1cSMartin Matuska return cSize;
2550c03c5b1cSMartin Matuska }
2551c03c5b1cSMartin Matuska
ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t * ms,ZSTD_cwksp * ws,ZSTD_CCtx_params const * params,void const * ip,void const * iend)2552c03c5b1cSMartin Matuska static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms,
2553c03c5b1cSMartin Matuska ZSTD_cwksp* ws,
2554c03c5b1cSMartin Matuska ZSTD_CCtx_params const* params,
2555c03c5b1cSMartin Matuska void const* ip,
2556c03c5b1cSMartin Matuska void const* iend)
2557c03c5b1cSMartin Matuska {
2558c03c5b1cSMartin Matuska if (ZSTD_window_needOverflowCorrection(ms->window, iend)) {
2559c03c5b1cSMartin Matuska U32 const maxDist = (U32)1 << params->cParams.windowLog;
2560c03c5b1cSMartin Matuska U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy);
2561c03c5b1cSMartin Matuska U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
2562c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
2563c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
2564c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
2565c03c5b1cSMartin Matuska ZSTD_cwksp_mark_tables_dirty(ws);
2566c03c5b1cSMartin Matuska ZSTD_reduceIndex(ms, params, correction);
2567c03c5b1cSMartin Matuska ZSTD_cwksp_mark_tables_clean(ws);
2568c03c5b1cSMartin Matuska if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
2569c03c5b1cSMartin Matuska else ms->nextToUpdate -= correction;
2570c03c5b1cSMartin Matuska /* invalidate dictionaries on overflow correction */
2571c03c5b1cSMartin Matuska ms->loadedDictEnd = 0;
2572c03c5b1cSMartin Matuska ms->dictMatchState = NULL;
2573c03c5b1cSMartin Matuska }
2574c03c5b1cSMartin Matuska }
2575c03c5b1cSMartin Matuska
2576c03c5b1cSMartin Matuska /*! ZSTD_compress_frameChunk() :
2577c03c5b1cSMartin Matuska * Compress a chunk of data into one or multiple blocks.
2578c03c5b1cSMartin Matuska * All blocks will be terminated, all input will be consumed.
2579c03c5b1cSMartin Matuska * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2580c03c5b1cSMartin Matuska * Frame is supposed already started (header already produced)
2581c03c5b1cSMartin Matuska * @return : compressed size, or an error code
2582c03c5b1cSMartin Matuska */
ZSTD_compress_frameChunk(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,U32 lastFrameChunk)2583c03c5b1cSMartin Matuska static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
2584c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
2585c03c5b1cSMartin Matuska const void* src, size_t srcSize,
2586c03c5b1cSMartin Matuska U32 lastFrameChunk)
2587c03c5b1cSMartin Matuska {
2588c03c5b1cSMartin Matuska size_t blockSize = cctx->blockSize;
2589c03c5b1cSMartin Matuska size_t remaining = srcSize;
2590c03c5b1cSMartin Matuska const BYTE* ip = (const BYTE*)src;
2591c03c5b1cSMartin Matuska BYTE* const ostart = (BYTE*)dst;
2592c03c5b1cSMartin Matuska BYTE* op = ostart;
2593c03c5b1cSMartin Matuska U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog;
2594c03c5b1cSMartin Matuska
2595c03c5b1cSMartin Matuska assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX);
2596c03c5b1cSMartin Matuska
2597c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
2598c03c5b1cSMartin Matuska if (cctx->appliedParams.fParams.checksumFlag && srcSize)
2599c03c5b1cSMartin Matuska XXH64_update(&cctx->xxhState, src, srcSize);
2600c03c5b1cSMartin Matuska
2601c03c5b1cSMartin Matuska while (remaining) {
2602c03c5b1cSMartin Matuska ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
2603c03c5b1cSMartin Matuska U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
2604c03c5b1cSMartin Matuska
2605c03c5b1cSMartin Matuska RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE,
2606c03c5b1cSMartin Matuska dstSize_tooSmall,
2607c03c5b1cSMartin Matuska "not enough space to store compressed block");
2608c03c5b1cSMartin Matuska if (remaining < blockSize) blockSize = remaining;
2609c03c5b1cSMartin Matuska
2610c03c5b1cSMartin Matuska ZSTD_overflowCorrectIfNeeded(
2611c03c5b1cSMartin Matuska ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize);
2612c03c5b1cSMartin Matuska ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState);
2613c03c5b1cSMartin Matuska
2614c03c5b1cSMartin Matuska /* Ensure hash/chain table insertion resumes no sooner than lowlimit */
2615c03c5b1cSMartin Matuska if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit;
2616c03c5b1cSMartin Matuska
2617c03c5b1cSMartin Matuska { size_t cSize;
2618c03c5b1cSMartin Matuska if (ZSTD_useTargetCBlockSize(&cctx->appliedParams)) {
2619c03c5b1cSMartin Matuska cSize = ZSTD_compressBlock_targetCBlockSize(cctx, op, dstCapacity, ip, blockSize, lastBlock);
2620c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed");
2621c03c5b1cSMartin Matuska assert(cSize > 0);
2622c03c5b1cSMartin Matuska assert(cSize <= blockSize + ZSTD_blockHeaderSize);
2623c03c5b1cSMartin Matuska } else {
2624c03c5b1cSMartin Matuska cSize = ZSTD_compressBlock_internal(cctx,
2625c03c5b1cSMartin Matuska op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
2626c03c5b1cSMartin Matuska ip, blockSize, 1 /* frame */);
2627c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_internal failed");
2628c03c5b1cSMartin Matuska
2629c03c5b1cSMartin Matuska if (cSize == 0) { /* block is not compressible */
2630c03c5b1cSMartin Matuska cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
2631c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
2632c03c5b1cSMartin Matuska } else {
2633c03c5b1cSMartin Matuska U32 const cBlockHeader = cSize == 1 ?
2634c03c5b1cSMartin Matuska lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) :
2635c03c5b1cSMartin Matuska lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
2636c03c5b1cSMartin Matuska MEM_writeLE24(op, cBlockHeader);
2637c03c5b1cSMartin Matuska cSize += ZSTD_blockHeaderSize;
2638c03c5b1cSMartin Matuska }
2639c03c5b1cSMartin Matuska }
2640c03c5b1cSMartin Matuska
2641c03c5b1cSMartin Matuska
2642c03c5b1cSMartin Matuska ip += blockSize;
2643c03c5b1cSMartin Matuska assert(remaining >= blockSize);
2644c03c5b1cSMartin Matuska remaining -= blockSize;
2645c03c5b1cSMartin Matuska op += cSize;
2646c03c5b1cSMartin Matuska assert(dstCapacity >= cSize);
2647c03c5b1cSMartin Matuska dstCapacity -= cSize;
2648c03c5b1cSMartin Matuska cctx->isFirstBlock = 0;
2649c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u",
2650c03c5b1cSMartin Matuska (unsigned)cSize);
2651c03c5b1cSMartin Matuska } }
2652c03c5b1cSMartin Matuska
2653c03c5b1cSMartin Matuska if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
2654c03c5b1cSMartin Matuska return (size_t)(op-ostart);
2655c03c5b1cSMartin Matuska }
2656c03c5b1cSMartin Matuska
2657c03c5b1cSMartin Matuska
ZSTD_writeFrameHeader(void * dst,size_t dstCapacity,const ZSTD_CCtx_params * params,U64 pledgedSrcSize,U32 dictID)2658c03c5b1cSMartin Matuska static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
2659c03c5b1cSMartin Matuska const ZSTD_CCtx_params* params, U64 pledgedSrcSize, U32 dictID)
2660c03c5b1cSMartin Matuska { BYTE* const op = (BYTE*)dst;
2661c03c5b1cSMartin Matuska U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2662c03c5b1cSMartin Matuska U32 const dictIDSizeCode = params->fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
2663c03c5b1cSMartin Matuska U32 const checksumFlag = params->fParams.checksumFlag>0;
2664c03c5b1cSMartin Matuska U32 const windowSize = (U32)1 << params->cParams.windowLog;
2665c03c5b1cSMartin Matuska U32 const singleSegment = params->fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
2666c03c5b1cSMartin Matuska BYTE const windowLogByte = (BYTE)((params->cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2667c03c5b1cSMartin Matuska U32 const fcsCode = params->fParams.contentSizeFlag ?
2668c03c5b1cSMartin Matuska (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
2669c03c5b1cSMartin Matuska BYTE const frameHeaderDescriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
2670c03c5b1cSMartin Matuska size_t pos=0;
2671c03c5b1cSMartin Matuska
2672c03c5b1cSMartin Matuska assert(!(params->fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN));
2673c03c5b1cSMartin Matuska RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall,
2674c03c5b1cSMartin Matuska "dst buf is too small to fit worst-case frame header size.");
2675c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
2676c03c5b1cSMartin Matuska !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode);
2677c03c5b1cSMartin Matuska
2678c03c5b1cSMartin Matuska if (params->format == ZSTD_f_zstd1) {
2679c03c5b1cSMartin Matuska MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
2680c03c5b1cSMartin Matuska pos = 4;
2681c03c5b1cSMartin Matuska }
2682c03c5b1cSMartin Matuska op[pos++] = frameHeaderDescriptionByte;
2683c03c5b1cSMartin Matuska if (!singleSegment) op[pos++] = windowLogByte;
2684c03c5b1cSMartin Matuska switch(dictIDSizeCode)
2685c03c5b1cSMartin Matuska {
2686c03c5b1cSMartin Matuska default: assert(0); /* impossible */
2687c03c5b1cSMartin Matuska case 0 : break;
2688c03c5b1cSMartin Matuska case 1 : op[pos] = (BYTE)(dictID); pos++; break;
2689c03c5b1cSMartin Matuska case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
2690c03c5b1cSMartin Matuska case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2691c03c5b1cSMartin Matuska }
2692c03c5b1cSMartin Matuska switch(fcsCode)
2693c03c5b1cSMartin Matuska {
2694c03c5b1cSMartin Matuska default: assert(0); /* impossible */
2695c03c5b1cSMartin Matuska case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
2696c03c5b1cSMartin Matuska case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2697c03c5b1cSMartin Matuska case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
2698c03c5b1cSMartin Matuska case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
2699c03c5b1cSMartin Matuska }
2700c03c5b1cSMartin Matuska return pos;
2701c03c5b1cSMartin Matuska }
2702c03c5b1cSMartin Matuska
2703c03c5b1cSMartin Matuska /* ZSTD_writeLastEmptyBlock() :
2704c03c5b1cSMartin Matuska * output an empty Block with end-of-frame mark to complete a frame
2705c03c5b1cSMartin Matuska * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
2706c03c5b1cSMartin Matuska * or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize)
2707c03c5b1cSMartin Matuska */
ZSTD_writeLastEmptyBlock(void * dst,size_t dstCapacity)2708c03c5b1cSMartin Matuska size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity)
2709c03c5b1cSMartin Matuska {
2710c03c5b1cSMartin Matuska RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall,
2711c03c5b1cSMartin Matuska "dst buf is too small to write frame trailer empty block.");
2712c03c5b1cSMartin Matuska { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */
2713c03c5b1cSMartin Matuska MEM_writeLE24(dst, cBlockHeader24);
2714c03c5b1cSMartin Matuska return ZSTD_blockHeaderSize;
2715c03c5b1cSMartin Matuska }
2716c03c5b1cSMartin Matuska }
2717c03c5b1cSMartin Matuska
ZSTD_referenceExternalSequences(ZSTD_CCtx * cctx,rawSeq * seq,size_t nbSeq)2718c03c5b1cSMartin Matuska size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq)
2719c03c5b1cSMartin Matuska {
2720c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong,
2721c03c5b1cSMartin Matuska "wrong cctx stage");
2722c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm,
2723c03c5b1cSMartin Matuska parameter_unsupported,
2724c03c5b1cSMartin Matuska "incompatible with ldm");
2725c03c5b1cSMartin Matuska cctx->externSeqStore.seq = seq;
2726c03c5b1cSMartin Matuska cctx->externSeqStore.size = nbSeq;
2727c03c5b1cSMartin Matuska cctx->externSeqStore.capacity = nbSeq;
2728c03c5b1cSMartin Matuska cctx->externSeqStore.pos = 0;
2729c03c5b1cSMartin Matuska return 0;
2730c03c5b1cSMartin Matuska }
2731c03c5b1cSMartin Matuska
2732c03c5b1cSMartin Matuska
ZSTD_compressContinue_internal(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,U32 frame,U32 lastFrameChunk)2733c03c5b1cSMartin Matuska static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
2734c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
2735c03c5b1cSMartin Matuska const void* src, size_t srcSize,
2736c03c5b1cSMartin Matuska U32 frame, U32 lastFrameChunk)
2737c03c5b1cSMartin Matuska {
2738c03c5b1cSMartin Matuska ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
2739c03c5b1cSMartin Matuska size_t fhSize = 0;
2740c03c5b1cSMartin Matuska
2741c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u",
2742c03c5b1cSMartin Matuska cctx->stage, (unsigned)srcSize);
2743c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->stage==ZSTDcs_created, stage_wrong,
2744c03c5b1cSMartin Matuska "missing init (ZSTD_compressBegin)");
2745c03c5b1cSMartin Matuska
2746c03c5b1cSMartin Matuska if (frame && (cctx->stage==ZSTDcs_init)) {
2747c03c5b1cSMartin Matuska fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams,
2748c03c5b1cSMartin Matuska cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
2749c03c5b1cSMartin Matuska FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
2750c03c5b1cSMartin Matuska assert(fhSize <= dstCapacity);
2751c03c5b1cSMartin Matuska dstCapacity -= fhSize;
2752c03c5b1cSMartin Matuska dst = (char*)dst + fhSize;
2753c03c5b1cSMartin Matuska cctx->stage = ZSTDcs_ongoing;
2754c03c5b1cSMartin Matuska }
2755c03c5b1cSMartin Matuska
2756c03c5b1cSMartin Matuska if (!srcSize) return fhSize; /* do not generate an empty block if no input */
2757c03c5b1cSMartin Matuska
2758c03c5b1cSMartin Matuska if (!ZSTD_window_update(&ms->window, src, srcSize)) {
2759c03c5b1cSMartin Matuska ms->nextToUpdate = ms->window.dictLimit;
2760c03c5b1cSMartin Matuska }
2761c03c5b1cSMartin Matuska if (cctx->appliedParams.ldmParams.enableLdm) {
2762c03c5b1cSMartin Matuska ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
2763c03c5b1cSMartin Matuska }
2764c03c5b1cSMartin Matuska
2765c03c5b1cSMartin Matuska if (!frame) {
2766c03c5b1cSMartin Matuska /* overflow check and correction for block mode */
2767c03c5b1cSMartin Matuska ZSTD_overflowCorrectIfNeeded(
2768c03c5b1cSMartin Matuska ms, &cctx->workspace, &cctx->appliedParams,
2769c03c5b1cSMartin Matuska src, (BYTE const*)src + srcSize);
2770c03c5b1cSMartin Matuska }
2771c03c5b1cSMartin Matuska
2772c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize);
2773c03c5b1cSMartin Matuska { size_t const cSize = frame ?
2774c03c5b1cSMartin Matuska ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2775c03c5b1cSMartin Matuska ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize, 0 /* frame */);
2776c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "%s", frame ? "ZSTD_compress_frameChunk failed" : "ZSTD_compressBlock_internal failed");
2777c03c5b1cSMartin Matuska cctx->consumedSrcSize += srcSize;
2778c03c5b1cSMartin Matuska cctx->producedCSize += (cSize + fhSize);
2779c03c5b1cSMartin Matuska assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
2780c03c5b1cSMartin Matuska if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */
2781c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
2782c03c5b1cSMartin Matuska RETURN_ERROR_IF(
2783c03c5b1cSMartin Matuska cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne,
2784c03c5b1cSMartin Matuska srcSize_wrong,
2785c03c5b1cSMartin Matuska "error : pledgedSrcSize = %u, while realSrcSize >= %u",
2786c03c5b1cSMartin Matuska (unsigned)cctx->pledgedSrcSizePlusOne-1,
2787c03c5b1cSMartin Matuska (unsigned)cctx->consumedSrcSize);
2788c03c5b1cSMartin Matuska }
2789c03c5b1cSMartin Matuska return cSize + fhSize;
2790c03c5b1cSMartin Matuska }
2791c03c5b1cSMartin Matuska }
2792c03c5b1cSMartin Matuska
ZSTD_compressContinue(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)2793c03c5b1cSMartin Matuska size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
2794c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
2795c03c5b1cSMartin Matuska const void* src, size_t srcSize)
2796c03c5b1cSMartin Matuska {
2797c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize);
2798c03c5b1cSMartin Matuska return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
2799c03c5b1cSMartin Matuska }
2800c03c5b1cSMartin Matuska
2801c03c5b1cSMartin Matuska
ZSTD_getBlockSize(const ZSTD_CCtx * cctx)2802c03c5b1cSMartin Matuska size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
2803c03c5b1cSMartin Matuska {
2804c03c5b1cSMartin Matuska ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams;
2805c03c5b1cSMartin Matuska assert(!ZSTD_checkCParams(cParams));
2806c03c5b1cSMartin Matuska return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
2807c03c5b1cSMartin Matuska }
2808c03c5b1cSMartin Matuska
ZSTD_compressBlock(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)2809c03c5b1cSMartin Matuska size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2810c03c5b1cSMartin Matuska {
2811c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize);
2812c03c5b1cSMartin Matuska { size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
2813c03c5b1cSMartin Matuska RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong, "input is larger than a block"); }
2814c03c5b1cSMartin Matuska
2815c03c5b1cSMartin Matuska return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
2816c03c5b1cSMartin Matuska }
2817c03c5b1cSMartin Matuska
2818c03c5b1cSMartin Matuska /*! ZSTD_loadDictionaryContent() :
2819c03c5b1cSMartin Matuska * @return : 0, or an error code
2820c03c5b1cSMartin Matuska */
ZSTD_loadDictionaryContent(ZSTD_matchState_t * ms,ldmState_t * ls,ZSTD_cwksp * ws,ZSTD_CCtx_params const * params,const void * src,size_t srcSize,ZSTD_dictTableLoadMethod_e dtlm)2821c03c5b1cSMartin Matuska static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
2822c03c5b1cSMartin Matuska ldmState_t* ls,
2823c03c5b1cSMartin Matuska ZSTD_cwksp* ws,
2824c03c5b1cSMartin Matuska ZSTD_CCtx_params const* params,
2825c03c5b1cSMartin Matuska const void* src, size_t srcSize,
2826c03c5b1cSMartin Matuska ZSTD_dictTableLoadMethod_e dtlm)
2827c03c5b1cSMartin Matuska {
2828c03c5b1cSMartin Matuska const BYTE* ip = (const BYTE*) src;
2829c03c5b1cSMartin Matuska const BYTE* const iend = ip + srcSize;
2830c03c5b1cSMartin Matuska
2831c03c5b1cSMartin Matuska ZSTD_window_update(&ms->window, src, srcSize);
2832c03c5b1cSMartin Matuska ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
2833c03c5b1cSMartin Matuska
2834c03c5b1cSMartin Matuska if (params->ldmParams.enableLdm && ls != NULL) {
2835c03c5b1cSMartin Matuska ZSTD_window_update(&ls->window, src, srcSize);
2836c03c5b1cSMartin Matuska ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base);
2837c03c5b1cSMartin Matuska }
2838c03c5b1cSMartin Matuska
2839c03c5b1cSMartin Matuska /* Assert that we the ms params match the params we're being given */
2840c03c5b1cSMartin Matuska ZSTD_assertEqualCParams(params->cParams, ms->cParams);
2841c03c5b1cSMartin Matuska
2842c03c5b1cSMartin Matuska if (srcSize <= HASH_READ_SIZE) return 0;
2843c03c5b1cSMartin Matuska
2844c03c5b1cSMartin Matuska while (iend - ip > HASH_READ_SIZE) {
2845c03c5b1cSMartin Matuska size_t const remaining = (size_t)(iend - ip);
2846c03c5b1cSMartin Matuska size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX);
2847c03c5b1cSMartin Matuska const BYTE* const ichunk = ip + chunk;
2848c03c5b1cSMartin Matuska
2849c03c5b1cSMartin Matuska ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk);
2850c03c5b1cSMartin Matuska
2851c03c5b1cSMartin Matuska if (params->ldmParams.enableLdm && ls != NULL)
2852c03c5b1cSMartin Matuska ZSTD_ldm_fillHashTable(ls, (const BYTE*)src, (const BYTE*)src + srcSize, ¶ms->ldmParams);
2853c03c5b1cSMartin Matuska
2854c03c5b1cSMartin Matuska switch(params->cParams.strategy)
2855c03c5b1cSMartin Matuska {
2856c03c5b1cSMartin Matuska case ZSTD_fast:
2857c03c5b1cSMartin Matuska ZSTD_fillHashTable(ms, ichunk, dtlm);
2858c03c5b1cSMartin Matuska break;
2859c03c5b1cSMartin Matuska case ZSTD_dfast:
2860c03c5b1cSMartin Matuska ZSTD_fillDoubleHashTable(ms, ichunk, dtlm);
2861c03c5b1cSMartin Matuska break;
2862c03c5b1cSMartin Matuska
2863c03c5b1cSMartin Matuska case ZSTD_greedy:
2864c03c5b1cSMartin Matuska case ZSTD_lazy:
2865c03c5b1cSMartin Matuska case ZSTD_lazy2:
2866c03c5b1cSMartin Matuska if (chunk >= HASH_READ_SIZE)
2867c03c5b1cSMartin Matuska ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE);
2868c03c5b1cSMartin Matuska break;
2869c03c5b1cSMartin Matuska
2870c03c5b1cSMartin Matuska case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
2871c03c5b1cSMartin Matuska case ZSTD_btopt:
2872c03c5b1cSMartin Matuska case ZSTD_btultra:
2873c03c5b1cSMartin Matuska case ZSTD_btultra2:
2874c03c5b1cSMartin Matuska if (chunk >= HASH_READ_SIZE)
2875c03c5b1cSMartin Matuska ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk);
2876c03c5b1cSMartin Matuska break;
2877c03c5b1cSMartin Matuska
2878c03c5b1cSMartin Matuska default:
2879c03c5b1cSMartin Matuska assert(0); /* not possible : not a valid strategy id */
2880c03c5b1cSMartin Matuska }
2881c03c5b1cSMartin Matuska
2882c03c5b1cSMartin Matuska ip = ichunk;
2883c03c5b1cSMartin Matuska }
2884c03c5b1cSMartin Matuska
2885c03c5b1cSMartin Matuska ms->nextToUpdate = (U32)(iend - ms->window.base);
2886c03c5b1cSMartin Matuska return 0;
2887c03c5b1cSMartin Matuska }
2888c03c5b1cSMartin Matuska
2889c03c5b1cSMartin Matuska
2890c03c5b1cSMartin Matuska /* Dictionaries that assign zero probability to symbols that show up causes problems
2891c03c5b1cSMartin Matuska when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2892c03c5b1cSMartin Matuska that we may encounter during compression.
2893c03c5b1cSMartin Matuska NOTE: This behavior is not standard and could be improved in the future. */
ZSTD_checkDictNCount(short * normalizedCounter,unsigned dictMaxSymbolValue,unsigned maxSymbolValue)2894c03c5b1cSMartin Matuska static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2895c03c5b1cSMartin Matuska U32 s;
2896c03c5b1cSMartin Matuska RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted, "dict fse tables don't have all symbols");
2897c03c5b1cSMartin Matuska for (s = 0; s <= maxSymbolValue; ++s) {
2898c03c5b1cSMartin Matuska RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted, "dict fse tables don't have all symbols");
2899c03c5b1cSMartin Matuska }
2900c03c5b1cSMartin Matuska return 0;
2901c03c5b1cSMartin Matuska }
2902c03c5b1cSMartin Matuska
ZSTD_loadCEntropy(ZSTD_compressedBlockState_t * bs,void * workspace,short * offcodeNCount,unsigned * offcodeMaxValue,const void * const dict,size_t dictSize)2903c03c5b1cSMartin Matuska size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2904c03c5b1cSMartin Matuska short* offcodeNCount, unsigned* offcodeMaxValue,
2905c03c5b1cSMartin Matuska const void* const dict, size_t dictSize)
2906c03c5b1cSMartin Matuska {
2907c03c5b1cSMartin Matuska const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */
2908c03c5b1cSMartin Matuska const BYTE* const dictEnd = dictPtr + dictSize;
2909c03c5b1cSMartin Matuska dictPtr += 8;
2910c03c5b1cSMartin Matuska bs->entropy.huf.repeatMode = HUF_repeat_check;
2911c03c5b1cSMartin Matuska
2912c03c5b1cSMartin Matuska { unsigned maxSymbolValue = 255;
2913c03c5b1cSMartin Matuska unsigned hasZeroWeights = 1;
2914c03c5b1cSMartin Matuska size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr,
2915c03c5b1cSMartin Matuska dictEnd-dictPtr, &hasZeroWeights);
2916c03c5b1cSMartin Matuska
2917c03c5b1cSMartin Matuska /* We only set the loaded table as valid if it contains all non-zero
2918c03c5b1cSMartin Matuska * weights. Otherwise, we set it to check */
2919c03c5b1cSMartin Matuska if (!hasZeroWeights)
2920c03c5b1cSMartin Matuska bs->entropy.huf.repeatMode = HUF_repeat_valid;
2921c03c5b1cSMartin Matuska
2922c03c5b1cSMartin Matuska RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted, "");
2923c03c5b1cSMartin Matuska RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted, "");
2924c03c5b1cSMartin Matuska dictPtr += hufHeaderSize;
2925c03c5b1cSMartin Matuska }
2926c03c5b1cSMartin Matuska
2927c03c5b1cSMartin Matuska { unsigned offcodeLog;
2928c03c5b1cSMartin Matuska size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
2929c03c5b1cSMartin Matuska RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
2930c03c5b1cSMartin Matuska RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
2931c03c5b1cSMartin Matuska /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
2932c03c5b1cSMartin Matuska /* fill all offset symbols to avoid garbage at end of table */
2933c03c5b1cSMartin Matuska RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
2934c03c5b1cSMartin Matuska bs->entropy.fse.offcodeCTable,
2935c03c5b1cSMartin Matuska offcodeNCount, MaxOff, offcodeLog,
2936c03c5b1cSMartin Matuska workspace, HUF_WORKSPACE_SIZE)),
2937c03c5b1cSMartin Matuska dictionary_corrupted, "");
2938c03c5b1cSMartin Matuska dictPtr += offcodeHeaderSize;
2939c03c5b1cSMartin Matuska }
2940c03c5b1cSMartin Matuska
2941c03c5b1cSMartin Matuska { short matchlengthNCount[MaxML+1];
2942c03c5b1cSMartin Matuska unsigned matchlengthMaxValue = MaxML, matchlengthLog;
2943c03c5b1cSMartin Matuska size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
2944c03c5b1cSMartin Matuska RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
2945c03c5b1cSMartin Matuska RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
2946c03c5b1cSMartin Matuska /* Every match length code must have non-zero probability */
2947c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML), "");
2948c03c5b1cSMartin Matuska RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
2949c03c5b1cSMartin Matuska bs->entropy.fse.matchlengthCTable,
2950c03c5b1cSMartin Matuska matchlengthNCount, matchlengthMaxValue, matchlengthLog,
2951c03c5b1cSMartin Matuska workspace, HUF_WORKSPACE_SIZE)),
2952c03c5b1cSMartin Matuska dictionary_corrupted, "");
2953c03c5b1cSMartin Matuska dictPtr += matchlengthHeaderSize;
2954c03c5b1cSMartin Matuska }
2955c03c5b1cSMartin Matuska
2956c03c5b1cSMartin Matuska { short litlengthNCount[MaxLL+1];
2957c03c5b1cSMartin Matuska unsigned litlengthMaxValue = MaxLL, litlengthLog;
2958c03c5b1cSMartin Matuska size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
2959c03c5b1cSMartin Matuska RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
2960c03c5b1cSMartin Matuska RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
2961c03c5b1cSMartin Matuska /* Every literal length code must have non-zero probability */
2962c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL), "");
2963c03c5b1cSMartin Matuska RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
2964c03c5b1cSMartin Matuska bs->entropy.fse.litlengthCTable,
2965c03c5b1cSMartin Matuska litlengthNCount, litlengthMaxValue, litlengthLog,
2966c03c5b1cSMartin Matuska workspace, HUF_WORKSPACE_SIZE)),
2967c03c5b1cSMartin Matuska dictionary_corrupted, "");
2968c03c5b1cSMartin Matuska dictPtr += litlengthHeaderSize;
2969c03c5b1cSMartin Matuska }
2970c03c5b1cSMartin Matuska
2971c03c5b1cSMartin Matuska RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");
2972c03c5b1cSMartin Matuska bs->rep[0] = MEM_readLE32(dictPtr+0);
2973c03c5b1cSMartin Matuska bs->rep[1] = MEM_readLE32(dictPtr+4);
2974c03c5b1cSMartin Matuska bs->rep[2] = MEM_readLE32(dictPtr+8);
2975c03c5b1cSMartin Matuska dictPtr += 12;
2976c03c5b1cSMartin Matuska
2977c03c5b1cSMartin Matuska return dictPtr - (const BYTE*)dict;
2978c03c5b1cSMartin Matuska }
2979c03c5b1cSMartin Matuska
2980c03c5b1cSMartin Matuska /* Dictionary format :
2981c03c5b1cSMartin Matuska * See :
2982c03c5b1cSMartin Matuska * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
2983c03c5b1cSMartin Matuska */
2984c03c5b1cSMartin Matuska /*! ZSTD_loadZstdDictionary() :
2985c03c5b1cSMartin Matuska * @return : dictID, or an error code
2986c03c5b1cSMartin Matuska * assumptions : magic number supposed already checked
2987c03c5b1cSMartin Matuska * dictSize supposed >= 8
2988c03c5b1cSMartin Matuska */
ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t * bs,ZSTD_matchState_t * ms,ZSTD_cwksp * ws,ZSTD_CCtx_params const * params,const void * dict,size_t dictSize,ZSTD_dictTableLoadMethod_e dtlm,void * workspace)2989c03c5b1cSMartin Matuska static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
2990c03c5b1cSMartin Matuska ZSTD_matchState_t* ms,
2991c03c5b1cSMartin Matuska ZSTD_cwksp* ws,
2992c03c5b1cSMartin Matuska ZSTD_CCtx_params const* params,
2993c03c5b1cSMartin Matuska const void* dict, size_t dictSize,
2994c03c5b1cSMartin Matuska ZSTD_dictTableLoadMethod_e dtlm,
2995c03c5b1cSMartin Matuska void* workspace)
2996c03c5b1cSMartin Matuska {
2997c03c5b1cSMartin Matuska const BYTE* dictPtr = (const BYTE*)dict;
2998c03c5b1cSMartin Matuska const BYTE* const dictEnd = dictPtr + dictSize;
2999c03c5b1cSMartin Matuska short offcodeNCount[MaxOff+1];
3000c03c5b1cSMartin Matuska unsigned offcodeMaxValue = MaxOff;
3001c03c5b1cSMartin Matuska size_t dictID;
3002c03c5b1cSMartin Matuska size_t eSize;
3003c03c5b1cSMartin Matuska
3004c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
3005c03c5b1cSMartin Matuska assert(dictSize >= 8);
3006c03c5b1cSMartin Matuska assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
3007c03c5b1cSMartin Matuska
3008c03c5b1cSMartin Matuska dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ );
3009c03c5b1cSMartin Matuska eSize = ZSTD_loadCEntropy(bs, workspace, offcodeNCount, &offcodeMaxValue, dict, dictSize);
3010c03c5b1cSMartin Matuska FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed");
3011c03c5b1cSMartin Matuska dictPtr += eSize;
3012c03c5b1cSMartin Matuska
3013c03c5b1cSMartin Matuska { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3014c03c5b1cSMartin Matuska U32 offcodeMax = MaxOff;
3015c03c5b1cSMartin Matuska if (dictContentSize <= ((U32)-1) - 128 KB) {
3016c03c5b1cSMartin Matuska U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
3017c03c5b1cSMartin Matuska offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
3018c03c5b1cSMartin Matuska }
3019c03c5b1cSMartin Matuska /* All offset values <= dictContentSize + 128 KB must be representable */
3020c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)), "");
3021c03c5b1cSMartin Matuska /* All repCodes must be <= dictContentSize and != 0*/
3022c03c5b1cSMartin Matuska { U32 u;
3023c03c5b1cSMartin Matuska for (u=0; u<3; u++) {
3024c03c5b1cSMartin Matuska RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, "");
3025c03c5b1cSMartin Matuska RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, "");
3026c03c5b1cSMartin Matuska } }
3027c03c5b1cSMartin Matuska
3028c03c5b1cSMartin Matuska bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid;
3029c03c5b1cSMartin Matuska bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid;
3030c03c5b1cSMartin Matuska bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid;
3031c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_loadDictionaryContent(
3032c03c5b1cSMartin Matuska ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), "");
3033c03c5b1cSMartin Matuska return dictID;
3034c03c5b1cSMartin Matuska }
3035c03c5b1cSMartin Matuska }
3036c03c5b1cSMartin Matuska
3037c03c5b1cSMartin Matuska /** ZSTD_compress_insertDictionary() :
3038c03c5b1cSMartin Matuska * @return : dictID, or an error code */
3039c03c5b1cSMartin Matuska static size_t
ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t * bs,ZSTD_matchState_t * ms,ldmState_t * ls,ZSTD_cwksp * ws,const ZSTD_CCtx_params * params,const void * dict,size_t dictSize,ZSTD_dictContentType_e dictContentType,ZSTD_dictTableLoadMethod_e dtlm,void * workspace)3040c03c5b1cSMartin Matuska ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
3041c03c5b1cSMartin Matuska ZSTD_matchState_t* ms,
3042c03c5b1cSMartin Matuska ldmState_t* ls,
3043c03c5b1cSMartin Matuska ZSTD_cwksp* ws,
3044c03c5b1cSMartin Matuska const ZSTD_CCtx_params* params,
3045c03c5b1cSMartin Matuska const void* dict, size_t dictSize,
3046c03c5b1cSMartin Matuska ZSTD_dictContentType_e dictContentType,
3047c03c5b1cSMartin Matuska ZSTD_dictTableLoadMethod_e dtlm,
3048c03c5b1cSMartin Matuska void* workspace)
3049c03c5b1cSMartin Matuska {
3050c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
3051c03c5b1cSMartin Matuska if ((dict==NULL) || (dictSize<8)) {
3052c03c5b1cSMartin Matuska RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, "");
3053c03c5b1cSMartin Matuska return 0;
3054c03c5b1cSMartin Matuska }
3055c03c5b1cSMartin Matuska
3056c03c5b1cSMartin Matuska ZSTD_reset_compressedBlockState(bs);
3057c03c5b1cSMartin Matuska
3058c03c5b1cSMartin Matuska /* dict restricted modes */
3059c03c5b1cSMartin Matuska if (dictContentType == ZSTD_dct_rawContent)
3060c03c5b1cSMartin Matuska return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm);
3061c03c5b1cSMartin Matuska
3062c03c5b1cSMartin Matuska if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
3063c03c5b1cSMartin Matuska if (dictContentType == ZSTD_dct_auto) {
3064c03c5b1cSMartin Matuska DEBUGLOG(4, "raw content dictionary detected");
3065c03c5b1cSMartin Matuska return ZSTD_loadDictionaryContent(
3066c03c5b1cSMartin Matuska ms, ls, ws, params, dict, dictSize, dtlm);
3067c03c5b1cSMartin Matuska }
3068c03c5b1cSMartin Matuska RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, "");
3069c03c5b1cSMartin Matuska assert(0); /* impossible */
3070c03c5b1cSMartin Matuska }
3071c03c5b1cSMartin Matuska
3072c03c5b1cSMartin Matuska /* dict as full zstd dictionary */
3073c03c5b1cSMartin Matuska return ZSTD_loadZstdDictionary(
3074c03c5b1cSMartin Matuska bs, ms, ws, params, dict, dictSize, dtlm, workspace);
3075c03c5b1cSMartin Matuska }
3076c03c5b1cSMartin Matuska
3077c03c5b1cSMartin Matuska #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB)
3078c03c5b1cSMartin Matuska #define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6)
3079c03c5b1cSMartin Matuska
3080c03c5b1cSMartin Matuska /*! ZSTD_compressBegin_internal() :
3081c03c5b1cSMartin Matuska * @return : 0, or an error code */
ZSTD_compressBegin_internal(ZSTD_CCtx * cctx,const void * dict,size_t dictSize,ZSTD_dictContentType_e dictContentType,ZSTD_dictTableLoadMethod_e dtlm,const ZSTD_CDict * cdict,const ZSTD_CCtx_params * params,U64 pledgedSrcSize,ZSTD_buffered_policy_e zbuff)3082c03c5b1cSMartin Matuska static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
3083c03c5b1cSMartin Matuska const void* dict, size_t dictSize,
3084c03c5b1cSMartin Matuska ZSTD_dictContentType_e dictContentType,
3085c03c5b1cSMartin Matuska ZSTD_dictTableLoadMethod_e dtlm,
3086c03c5b1cSMartin Matuska const ZSTD_CDict* cdict,
3087c03c5b1cSMartin Matuska const ZSTD_CCtx_params* params, U64 pledgedSrcSize,
3088c03c5b1cSMartin Matuska ZSTD_buffered_policy_e zbuff)
3089c03c5b1cSMartin Matuska {
3090c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog);
3091c03c5b1cSMartin Matuska /* params are supposed to be fully validated at this point */
3092c03c5b1cSMartin Matuska assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
3093c03c5b1cSMartin Matuska assert(!((dict) && (cdict))); /* either dict or cdict, not both */
3094c03c5b1cSMartin Matuska if ( (cdict)
3095c03c5b1cSMartin Matuska && (cdict->dictContentSize > 0)
3096c03c5b1cSMartin Matuska && ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
3097c03c5b1cSMartin Matuska || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
3098c03c5b1cSMartin Matuska || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
3099c03c5b1cSMartin Matuska || cdict->compressionLevel == 0)
3100c03c5b1cSMartin Matuska && (params->attachDictPref != ZSTD_dictForceLoad) ) {
3101c03c5b1cSMartin Matuska return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff);
3102c03c5b1cSMartin Matuska }
3103c03c5b1cSMartin Matuska
3104c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize,
3105c03c5b1cSMartin Matuska ZSTDcrp_makeClean, zbuff) , "");
3106c03c5b1cSMartin Matuska { size_t const dictID = cdict ?
3107c03c5b1cSMartin Matuska ZSTD_compress_insertDictionary(
3108c03c5b1cSMartin Matuska cctx->blockState.prevCBlock, &cctx->blockState.matchState,
3109c03c5b1cSMartin Matuska &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent,
3110c03c5b1cSMartin Matuska cdict->dictContentSize, dictContentType, dtlm,
3111c03c5b1cSMartin Matuska cctx->entropyWorkspace)
3112c03c5b1cSMartin Matuska : ZSTD_compress_insertDictionary(
3113c03c5b1cSMartin Matuska cctx->blockState.prevCBlock, &cctx->blockState.matchState,
3114c03c5b1cSMartin Matuska &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, dict, dictSize,
3115c03c5b1cSMartin Matuska dictContentType, dtlm, cctx->entropyWorkspace);
3116c03c5b1cSMartin Matuska FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
3117c03c5b1cSMartin Matuska assert(dictID <= UINT_MAX);
3118c03c5b1cSMartin Matuska cctx->dictID = (U32)dictID;
3119c03c5b1cSMartin Matuska }
3120c03c5b1cSMartin Matuska return 0;
3121c03c5b1cSMartin Matuska }
3122c03c5b1cSMartin Matuska
ZSTD_compressBegin_advanced_internal(ZSTD_CCtx * cctx,const void * dict,size_t dictSize,ZSTD_dictContentType_e dictContentType,ZSTD_dictTableLoadMethod_e dtlm,const ZSTD_CDict * cdict,const ZSTD_CCtx_params * params,unsigned long long pledgedSrcSize)3123c03c5b1cSMartin Matuska size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
3124c03c5b1cSMartin Matuska const void* dict, size_t dictSize,
3125c03c5b1cSMartin Matuska ZSTD_dictContentType_e dictContentType,
3126c03c5b1cSMartin Matuska ZSTD_dictTableLoadMethod_e dtlm,
3127c03c5b1cSMartin Matuska const ZSTD_CDict* cdict,
3128c03c5b1cSMartin Matuska const ZSTD_CCtx_params* params,
3129c03c5b1cSMartin Matuska unsigned long long pledgedSrcSize)
3130c03c5b1cSMartin Matuska {
3131c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params->cParams.windowLog);
3132c03c5b1cSMartin Matuska /* compression parameters verification and optimization */
3133c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) , "");
3134c03c5b1cSMartin Matuska return ZSTD_compressBegin_internal(cctx,
3135c03c5b1cSMartin Matuska dict, dictSize, dictContentType, dtlm,
3136c03c5b1cSMartin Matuska cdict,
3137c03c5b1cSMartin Matuska params, pledgedSrcSize,
3138c03c5b1cSMartin Matuska ZSTDb_not_buffered);
3139c03c5b1cSMartin Matuska }
3140c03c5b1cSMartin Matuska
3141c03c5b1cSMartin Matuska /*! ZSTD_compressBegin_advanced() :
3142c03c5b1cSMartin Matuska * @return : 0, or an error code */
ZSTD_compressBegin_advanced(ZSTD_CCtx * cctx,const void * dict,size_t dictSize,ZSTD_parameters params,unsigned long long pledgedSrcSize)3143c03c5b1cSMartin Matuska size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
3144c03c5b1cSMartin Matuska const void* dict, size_t dictSize,
3145c03c5b1cSMartin Matuska ZSTD_parameters params, unsigned long long pledgedSrcSize)
3146c03c5b1cSMartin Matuska {
3147c03c5b1cSMartin Matuska ZSTD_CCtx_params const cctxParams =
3148c03c5b1cSMartin Matuska ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, ¶ms);
3149c03c5b1cSMartin Matuska return ZSTD_compressBegin_advanced_internal(cctx,
3150c03c5b1cSMartin Matuska dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast,
3151c03c5b1cSMartin Matuska NULL /*cdict*/,
3152c03c5b1cSMartin Matuska &cctxParams, pledgedSrcSize);
3153c03c5b1cSMartin Matuska }
3154c03c5b1cSMartin Matuska
ZSTD_compressBegin_usingDict(ZSTD_CCtx * cctx,const void * dict,size_t dictSize,int compressionLevel)3155c03c5b1cSMartin Matuska size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
3156c03c5b1cSMartin Matuska {
3157c03c5b1cSMartin Matuska ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3158c03c5b1cSMartin Matuska ZSTD_CCtx_params const cctxParams =
3159c03c5b1cSMartin Matuska ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, ¶ms);
3160c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize);
3161c03c5b1cSMartin Matuska return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
3162c03c5b1cSMartin Matuska &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
3163c03c5b1cSMartin Matuska }
3164c03c5b1cSMartin Matuska
ZSTD_compressBegin(ZSTD_CCtx * cctx,int compressionLevel)3165c03c5b1cSMartin Matuska size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
3166c03c5b1cSMartin Matuska {
3167c03c5b1cSMartin Matuska return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
3168c03c5b1cSMartin Matuska }
3169c03c5b1cSMartin Matuska
3170c03c5b1cSMartin Matuska
3171c03c5b1cSMartin Matuska /*! ZSTD_writeEpilogue() :
3172c03c5b1cSMartin Matuska * Ends a frame.
3173c03c5b1cSMartin Matuska * @return : nb of bytes written into dst (or an error code) */
ZSTD_writeEpilogue(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity)3174c03c5b1cSMartin Matuska static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
3175c03c5b1cSMartin Matuska {
3176c03c5b1cSMartin Matuska BYTE* const ostart = (BYTE*)dst;
3177c03c5b1cSMartin Matuska BYTE* op = ostart;
3178c03c5b1cSMartin Matuska size_t fhSize = 0;
3179c03c5b1cSMartin Matuska
3180c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_writeEpilogue");
3181c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing");
3182c03c5b1cSMartin Matuska
3183c03c5b1cSMartin Matuska /* special case : empty frame */
3184c03c5b1cSMartin Matuska if (cctx->stage == ZSTDcs_init) {
3185c03c5b1cSMartin Matuska fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0);
3186c03c5b1cSMartin Matuska FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
3187c03c5b1cSMartin Matuska dstCapacity -= fhSize;
3188c03c5b1cSMartin Matuska op += fhSize;
3189c03c5b1cSMartin Matuska cctx->stage = ZSTDcs_ongoing;
3190c03c5b1cSMartin Matuska }
3191c03c5b1cSMartin Matuska
3192c03c5b1cSMartin Matuska if (cctx->stage != ZSTDcs_ending) {
3193c03c5b1cSMartin Matuska /* write one last empty block, make it the "last" block */
3194c03c5b1cSMartin Matuska U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
3195c03c5b1cSMartin Matuska RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for epilogue");
3196c03c5b1cSMartin Matuska MEM_writeLE32(op, cBlockHeader24);
3197c03c5b1cSMartin Matuska op += ZSTD_blockHeaderSize;
3198c03c5b1cSMartin Matuska dstCapacity -= ZSTD_blockHeaderSize;
3199c03c5b1cSMartin Matuska }
3200c03c5b1cSMartin Matuska
3201c03c5b1cSMartin Matuska if (cctx->appliedParams.fParams.checksumFlag) {
3202c03c5b1cSMartin Matuska U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
3203c03c5b1cSMartin Matuska RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum");
3204c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum);
3205c03c5b1cSMartin Matuska MEM_writeLE32(op, checksum);
3206c03c5b1cSMartin Matuska op += 4;
3207c03c5b1cSMartin Matuska }
3208c03c5b1cSMartin Matuska
3209c03c5b1cSMartin Matuska cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
3210c03c5b1cSMartin Matuska return op-ostart;
3211c03c5b1cSMartin Matuska }
3212c03c5b1cSMartin Matuska
ZSTD_compressEnd(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)3213c03c5b1cSMartin Matuska size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
3214c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
3215c03c5b1cSMartin Matuska const void* src, size_t srcSize)
3216c03c5b1cSMartin Matuska {
3217c03c5b1cSMartin Matuska size_t endResult;
3218c03c5b1cSMartin Matuska size_t const cSize = ZSTD_compressContinue_internal(cctx,
3219c03c5b1cSMartin Matuska dst, dstCapacity, src, srcSize,
3220c03c5b1cSMartin Matuska 1 /* frame mode */, 1 /* last chunk */);
3221c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "ZSTD_compressContinue_internal failed");
3222c03c5b1cSMartin Matuska endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
3223c03c5b1cSMartin Matuska FORWARD_IF_ERROR(endResult, "ZSTD_writeEpilogue failed");
3224c03c5b1cSMartin Matuska assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
3225c03c5b1cSMartin Matuska if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */
3226c03c5b1cSMartin Matuska ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
3227c03c5b1cSMartin Matuska DEBUGLOG(4, "end of frame : controlling src size");
3228c03c5b1cSMartin Matuska RETURN_ERROR_IF(
3229c03c5b1cSMartin Matuska cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1,
3230c03c5b1cSMartin Matuska srcSize_wrong,
3231c03c5b1cSMartin Matuska "error : pledgedSrcSize = %u, while realSrcSize = %u",
3232c03c5b1cSMartin Matuska (unsigned)cctx->pledgedSrcSizePlusOne-1,
3233c03c5b1cSMartin Matuska (unsigned)cctx->consumedSrcSize);
3234c03c5b1cSMartin Matuska }
3235c03c5b1cSMartin Matuska return cSize + endResult;
3236c03c5b1cSMartin Matuska }
3237c03c5b1cSMartin Matuska
3238c03c5b1cSMartin Matuska
ZSTD_compress_internal(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const void * dict,size_t dictSize,const ZSTD_parameters * params)3239c03c5b1cSMartin Matuska static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
3240c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
3241c03c5b1cSMartin Matuska const void* src, size_t srcSize,
3242c03c5b1cSMartin Matuska const void* dict,size_t dictSize,
3243c03c5b1cSMartin Matuska const ZSTD_parameters* params)
3244c03c5b1cSMartin Matuska {
3245c03c5b1cSMartin Matuska ZSTD_CCtx_params const cctxParams =
3246c03c5b1cSMartin Matuska ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params);
3247c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compress_internal");
3248c03c5b1cSMartin Matuska return ZSTD_compress_advanced_internal(cctx,
3249c03c5b1cSMartin Matuska dst, dstCapacity,
3250c03c5b1cSMartin Matuska src, srcSize,
3251c03c5b1cSMartin Matuska dict, dictSize,
3252c03c5b1cSMartin Matuska &cctxParams);
3253c03c5b1cSMartin Matuska }
3254c03c5b1cSMartin Matuska
ZSTD_compress_advanced(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const void * dict,size_t dictSize,ZSTD_parameters params)3255c03c5b1cSMartin Matuska size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
3256c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
3257c03c5b1cSMartin Matuska const void* src, size_t srcSize,
3258c03c5b1cSMartin Matuska const void* dict,size_t dictSize,
3259c03c5b1cSMartin Matuska ZSTD_parameters params)
3260c03c5b1cSMartin Matuska {
3261c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compress_advanced");
3262c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), "");
3263c03c5b1cSMartin Matuska return ZSTD_compress_internal(cctx,
3264c03c5b1cSMartin Matuska dst, dstCapacity,
3265c03c5b1cSMartin Matuska src, srcSize,
3266c03c5b1cSMartin Matuska dict, dictSize,
3267c03c5b1cSMartin Matuska ¶ms);
3268c03c5b1cSMartin Matuska }
3269c03c5b1cSMartin Matuska
3270c03c5b1cSMartin Matuska /* Internal */
ZSTD_compress_advanced_internal(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const void * dict,size_t dictSize,const ZSTD_CCtx_params * params)3271c03c5b1cSMartin Matuska size_t ZSTD_compress_advanced_internal(
3272c03c5b1cSMartin Matuska ZSTD_CCtx* cctx,
3273c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
3274c03c5b1cSMartin Matuska const void* src, size_t srcSize,
3275c03c5b1cSMartin Matuska const void* dict,size_t dictSize,
3276c03c5b1cSMartin Matuska const ZSTD_CCtx_params* params)
3277c03c5b1cSMartin Matuska {
3278c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize);
3279c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
3280c03c5b1cSMartin Matuska dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
3281c03c5b1cSMartin Matuska params, srcSize, ZSTDb_not_buffered) , "");
3282c03c5b1cSMartin Matuska return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
3283c03c5b1cSMartin Matuska }
3284c03c5b1cSMartin Matuska
ZSTD_compress_usingDict(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const void * dict,size_t dictSize,int compressionLevel)3285c03c5b1cSMartin Matuska size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
3286c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
3287c03c5b1cSMartin Matuska const void* src, size_t srcSize,
3288c03c5b1cSMartin Matuska const void* dict, size_t dictSize,
3289c03c5b1cSMartin Matuska int compressionLevel)
3290c03c5b1cSMartin Matuska {
3291c03c5b1cSMartin Matuska ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0);
3292c03c5b1cSMartin Matuska ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, ¶ms);
3293c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize);
3294c03c5b1cSMartin Matuska assert(params.fParams.contentSizeFlag == 1);
3295c03c5b1cSMartin Matuska return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams);
3296c03c5b1cSMartin Matuska }
3297c03c5b1cSMartin Matuska
ZSTD_compressCCtx(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,int compressionLevel)3298c03c5b1cSMartin Matuska size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
3299c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
3300c03c5b1cSMartin Matuska const void* src, size_t srcSize,
3301c03c5b1cSMartin Matuska int compressionLevel)
3302c03c5b1cSMartin Matuska {
3303c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize);
3304c03c5b1cSMartin Matuska assert(cctx != NULL);
3305c03c5b1cSMartin Matuska return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
3306c03c5b1cSMartin Matuska }
3307c03c5b1cSMartin Matuska
ZSTD_compress(void * dst,size_t dstCapacity,const void * src,size_t srcSize,int compressionLevel)3308c03c5b1cSMartin Matuska size_t ZSTD_compress(void* dst, size_t dstCapacity,
3309c03c5b1cSMartin Matuska const void* src, size_t srcSize,
3310c03c5b1cSMartin Matuska int compressionLevel)
3311c03c5b1cSMartin Matuska {
3312c03c5b1cSMartin Matuska size_t result;
3313c03c5b1cSMartin Matuska ZSTD_CCtx ctxBody;
3314c03c5b1cSMartin Matuska ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem);
3315c03c5b1cSMartin Matuska result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
3316c03c5b1cSMartin Matuska ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */
3317c03c5b1cSMartin Matuska return result;
3318c03c5b1cSMartin Matuska }
3319c03c5b1cSMartin Matuska
3320c03c5b1cSMartin Matuska
3321c03c5b1cSMartin Matuska /* ===== Dictionary API ===== */
3322c03c5b1cSMartin Matuska
3323c03c5b1cSMartin Matuska /*! ZSTD_estimateCDictSize_advanced() :
3324c03c5b1cSMartin Matuska * Estimate amount of memory that will be needed to create a dictionary with following arguments */
ZSTD_estimateCDictSize_advanced(size_t dictSize,ZSTD_compressionParameters cParams,ZSTD_dictLoadMethod_e dictLoadMethod)3325c03c5b1cSMartin Matuska size_t ZSTD_estimateCDictSize_advanced(
3326c03c5b1cSMartin Matuska size_t dictSize, ZSTD_compressionParameters cParams,
3327c03c5b1cSMartin Matuska ZSTD_dictLoadMethod_e dictLoadMethod)
3328c03c5b1cSMartin Matuska {
3329c03c5b1cSMartin Matuska DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
3330c03c5b1cSMartin Matuska return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
3331c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
3332c03c5b1cSMartin Matuska + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
3333c03c5b1cSMartin Matuska + (dictLoadMethod == ZSTD_dlm_byRef ? 0
3334c03c5b1cSMartin Matuska : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *))));
3335c03c5b1cSMartin Matuska }
3336c03c5b1cSMartin Matuska
ZSTD_estimateCDictSize(size_t dictSize,int compressionLevel)3337c03c5b1cSMartin Matuska size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
3338c03c5b1cSMartin Matuska {
3339c03c5b1cSMartin Matuska ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3340c03c5b1cSMartin Matuska return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
3341c03c5b1cSMartin Matuska }
3342c03c5b1cSMartin Matuska
ZSTD_sizeof_CDict(const ZSTD_CDict * cdict)3343c03c5b1cSMartin Matuska size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
3344c03c5b1cSMartin Matuska {
3345c03c5b1cSMartin Matuska if (cdict==NULL) return 0; /* support sizeof on NULL */
3346c03c5b1cSMartin Matuska DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict));
3347c03c5b1cSMartin Matuska /* cdict may be in the workspace */
3348c03c5b1cSMartin Matuska return (cdict->workspace.workspace == cdict ? 0 : sizeof(*cdict))
3349c03c5b1cSMartin Matuska + ZSTD_cwksp_sizeof(&cdict->workspace);
3350c03c5b1cSMartin Matuska }
3351c03c5b1cSMartin Matuska
ZSTD_initCDict_internal(ZSTD_CDict * cdict,const void * dictBuffer,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType,ZSTD_compressionParameters cParams)3352c03c5b1cSMartin Matuska static size_t ZSTD_initCDict_internal(
3353c03c5b1cSMartin Matuska ZSTD_CDict* cdict,
3354c03c5b1cSMartin Matuska const void* dictBuffer, size_t dictSize,
3355c03c5b1cSMartin Matuska ZSTD_dictLoadMethod_e dictLoadMethod,
3356c03c5b1cSMartin Matuska ZSTD_dictContentType_e dictContentType,
3357c03c5b1cSMartin Matuska ZSTD_compressionParameters cParams)
3358c03c5b1cSMartin Matuska {
3359c03c5b1cSMartin Matuska DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType);
3360c03c5b1cSMartin Matuska assert(!ZSTD_checkCParams(cParams));
3361c03c5b1cSMartin Matuska cdict->matchState.cParams = cParams;
3362c03c5b1cSMartin Matuska if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
3363c03c5b1cSMartin Matuska cdict->dictContent = dictBuffer;
3364c03c5b1cSMartin Matuska } else {
3365c03c5b1cSMartin Matuska void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*)));
3366c03c5b1cSMartin Matuska RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!");
3367c03c5b1cSMartin Matuska cdict->dictContent = internalBuffer;
3368c03c5b1cSMartin Matuska memcpy(internalBuffer, dictBuffer, dictSize);
3369c03c5b1cSMartin Matuska }
3370c03c5b1cSMartin Matuska cdict->dictContentSize = dictSize;
3371c03c5b1cSMartin Matuska
3372c03c5b1cSMartin Matuska cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE);
3373c03c5b1cSMartin Matuska
3374c03c5b1cSMartin Matuska
3375c03c5b1cSMartin Matuska /* Reset the state to no dictionary */
3376c03c5b1cSMartin Matuska ZSTD_reset_compressedBlockState(&cdict->cBlockState);
3377c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_reset_matchState(
3378c03c5b1cSMartin Matuska &cdict->matchState,
3379c03c5b1cSMartin Matuska &cdict->workspace,
3380c03c5b1cSMartin Matuska &cParams,
3381c03c5b1cSMartin Matuska ZSTDcrp_makeClean,
3382c03c5b1cSMartin Matuska ZSTDirp_reset,
3383c03c5b1cSMartin Matuska ZSTD_resetTarget_CDict), "");
3384c03c5b1cSMartin Matuska /* (Maybe) load the dictionary
3385c03c5b1cSMartin Matuska * Skips loading the dictionary if it is < 8 bytes.
3386c03c5b1cSMartin Matuska */
3387c03c5b1cSMartin Matuska { ZSTD_CCtx_params params;
3388c03c5b1cSMartin Matuska memset(¶ms, 0, sizeof(params));
3389c03c5b1cSMartin Matuska params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
3390c03c5b1cSMartin Matuska params.fParams.contentSizeFlag = 1;
3391c03c5b1cSMartin Matuska params.cParams = cParams;
3392c03c5b1cSMartin Matuska { size_t const dictID = ZSTD_compress_insertDictionary(
3393c03c5b1cSMartin Matuska &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace,
3394c03c5b1cSMartin Matuska ¶ms, cdict->dictContent, cdict->dictContentSize,
3395c03c5b1cSMartin Matuska dictContentType, ZSTD_dtlm_full, cdict->entropyWorkspace);
3396c03c5b1cSMartin Matuska FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
3397c03c5b1cSMartin Matuska assert(dictID <= (size_t)(U32)-1);
3398c03c5b1cSMartin Matuska cdict->dictID = (U32)dictID;
3399c03c5b1cSMartin Matuska }
3400c03c5b1cSMartin Matuska }
3401c03c5b1cSMartin Matuska
3402c03c5b1cSMartin Matuska return 0;
3403c03c5b1cSMartin Matuska }
3404c03c5b1cSMartin Matuska
ZSTD_createCDict_advanced(const void * dictBuffer,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType,ZSTD_compressionParameters cParams,ZSTD_customMem customMem)3405c03c5b1cSMartin Matuska ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3406c03c5b1cSMartin Matuska ZSTD_dictLoadMethod_e dictLoadMethod,
3407c03c5b1cSMartin Matuska ZSTD_dictContentType_e dictContentType,
3408c03c5b1cSMartin Matuska ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
3409c03c5b1cSMartin Matuska {
3410c03c5b1cSMartin Matuska DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType);
3411c03c5b1cSMartin Matuska if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
3412c03c5b1cSMartin Matuska
3413c03c5b1cSMartin Matuska { size_t const workspaceSize =
3414c03c5b1cSMartin Matuska ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) +
3415c03c5b1cSMartin Matuska ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) +
3416c03c5b1cSMartin Matuska ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
3417c03c5b1cSMartin Matuska (dictLoadMethod == ZSTD_dlm_byRef ? 0
3418c03c5b1cSMartin Matuska : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))));
3419c03c5b1cSMartin Matuska void* const workspace = ZSTD_malloc(workspaceSize, customMem);
3420c03c5b1cSMartin Matuska ZSTD_cwksp ws;
3421c03c5b1cSMartin Matuska ZSTD_CDict* cdict;
3422c03c5b1cSMartin Matuska
3423c03c5b1cSMartin Matuska if (!workspace) {
3424c03c5b1cSMartin Matuska ZSTD_free(workspace, customMem);
3425c03c5b1cSMartin Matuska return NULL;
3426c03c5b1cSMartin Matuska }
3427c03c5b1cSMartin Matuska
3428c03c5b1cSMartin Matuska ZSTD_cwksp_init(&ws, workspace, workspaceSize);
3429c03c5b1cSMartin Matuska
3430c03c5b1cSMartin Matuska cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
3431c03c5b1cSMartin Matuska assert(cdict != NULL);
3432c03c5b1cSMartin Matuska ZSTD_cwksp_move(&cdict->workspace, &ws);
3433c03c5b1cSMartin Matuska cdict->customMem = customMem;
3434c03c5b1cSMartin Matuska cdict->compressionLevel = 0; /* signals advanced API usage */
3435c03c5b1cSMartin Matuska
3436c03c5b1cSMartin Matuska if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3437c03c5b1cSMartin Matuska dictBuffer, dictSize,
3438c03c5b1cSMartin Matuska dictLoadMethod, dictContentType,
3439c03c5b1cSMartin Matuska cParams) )) {
3440c03c5b1cSMartin Matuska ZSTD_freeCDict(cdict);
3441c03c5b1cSMartin Matuska return NULL;
3442c03c5b1cSMartin Matuska }
3443c03c5b1cSMartin Matuska
3444c03c5b1cSMartin Matuska return cdict;
3445c03c5b1cSMartin Matuska }
3446c03c5b1cSMartin Matuska }
3447c03c5b1cSMartin Matuska
ZSTD_createCDict(const void * dict,size_t dictSize,int compressionLevel)3448c03c5b1cSMartin Matuska ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3449c03c5b1cSMartin Matuska {
3450c03c5b1cSMartin Matuska ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3451c03c5b1cSMartin Matuska ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize,
3452c03c5b1cSMartin Matuska ZSTD_dlm_byCopy, ZSTD_dct_auto,
3453c03c5b1cSMartin Matuska cParams, ZSTD_defaultCMem);
3454c03c5b1cSMartin Matuska if (cdict)
3455c03c5b1cSMartin Matuska cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
3456c03c5b1cSMartin Matuska return cdict;
3457c03c5b1cSMartin Matuska }
3458c03c5b1cSMartin Matuska
ZSTD_createCDict_byReference(const void * dict,size_t dictSize,int compressionLevel)3459c03c5b1cSMartin Matuska ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3460c03c5b1cSMartin Matuska {
3461c03c5b1cSMartin Matuska ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3462c03c5b1cSMartin Matuska return ZSTD_createCDict_advanced(dict, dictSize,
3463c03c5b1cSMartin Matuska ZSTD_dlm_byRef, ZSTD_dct_auto,
3464c03c5b1cSMartin Matuska cParams, ZSTD_defaultCMem);
3465c03c5b1cSMartin Matuska }
3466c03c5b1cSMartin Matuska
ZSTD_freeCDict(ZSTD_CDict * cdict)3467c03c5b1cSMartin Matuska size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3468c03c5b1cSMartin Matuska {
3469c03c5b1cSMartin Matuska if (cdict==NULL) return 0; /* support free on NULL */
3470c03c5b1cSMartin Matuska { ZSTD_customMem const cMem = cdict->customMem;
3471c03c5b1cSMartin Matuska int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict);
3472c03c5b1cSMartin Matuska ZSTD_cwksp_free(&cdict->workspace, cMem);
3473c03c5b1cSMartin Matuska if (!cdictInWorkspace) {
3474c03c5b1cSMartin Matuska ZSTD_free(cdict, cMem);
3475c03c5b1cSMartin Matuska }
3476c03c5b1cSMartin Matuska return 0;
3477c03c5b1cSMartin Matuska }
3478c03c5b1cSMartin Matuska }
3479c03c5b1cSMartin Matuska
3480c03c5b1cSMartin Matuska /*! ZSTD_initStaticCDict_advanced() :
3481c03c5b1cSMartin Matuska * Generate a digested dictionary in provided memory area.
3482c03c5b1cSMartin Matuska * workspace: The memory area to emplace the dictionary into.
3483c03c5b1cSMartin Matuska * Provided pointer must 8-bytes aligned.
3484c03c5b1cSMartin Matuska * It must outlive dictionary usage.
3485c03c5b1cSMartin Matuska * workspaceSize: Use ZSTD_estimateCDictSize()
3486c03c5b1cSMartin Matuska * to determine how large workspace must be.
3487c03c5b1cSMartin Matuska * cParams : use ZSTD_getCParams() to transform a compression level
3488c03c5b1cSMartin Matuska * into its relevants cParams.
3489c03c5b1cSMartin Matuska * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
3490c03c5b1cSMartin Matuska * Note : there is no corresponding "free" function.
3491c03c5b1cSMartin Matuska * Since workspace was allocated externally, it must be freed externally.
3492c03c5b1cSMartin Matuska */
ZSTD_initStaticCDict(void * workspace,size_t workspaceSize,const void * dict,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType,ZSTD_compressionParameters cParams)3493c03c5b1cSMartin Matuska const ZSTD_CDict* ZSTD_initStaticCDict(
3494c03c5b1cSMartin Matuska void* workspace, size_t workspaceSize,
3495c03c5b1cSMartin Matuska const void* dict, size_t dictSize,
3496c03c5b1cSMartin Matuska ZSTD_dictLoadMethod_e dictLoadMethod,
3497c03c5b1cSMartin Matuska ZSTD_dictContentType_e dictContentType,
3498c03c5b1cSMartin Matuska ZSTD_compressionParameters cParams)
3499c03c5b1cSMartin Matuska {
3500c03c5b1cSMartin Matuska size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
3501c03c5b1cSMartin Matuska size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
3502c03c5b1cSMartin Matuska + (dictLoadMethod == ZSTD_dlm_byRef ? 0
3503c03c5b1cSMartin Matuska : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))))
3504c03c5b1cSMartin Matuska + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
3505c03c5b1cSMartin Matuska + matchStateSize;
3506c03c5b1cSMartin Matuska ZSTD_CDict* cdict;
3507c03c5b1cSMartin Matuska
3508c03c5b1cSMartin Matuska if ((size_t)workspace & 7) return NULL; /* 8-aligned */
3509c03c5b1cSMartin Matuska
3510c03c5b1cSMartin Matuska {
3511c03c5b1cSMartin Matuska ZSTD_cwksp ws;
3512c03c5b1cSMartin Matuska ZSTD_cwksp_init(&ws, workspace, workspaceSize);
3513c03c5b1cSMartin Matuska cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
3514c03c5b1cSMartin Matuska if (cdict == NULL) return NULL;
3515c03c5b1cSMartin Matuska ZSTD_cwksp_move(&cdict->workspace, &ws);
3516c03c5b1cSMartin Matuska }
3517c03c5b1cSMartin Matuska
3518c03c5b1cSMartin Matuska DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u",
3519c03c5b1cSMartin Matuska (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize));
3520c03c5b1cSMartin Matuska if (workspaceSize < neededSize) return NULL;
3521c03c5b1cSMartin Matuska
3522c03c5b1cSMartin Matuska if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3523c03c5b1cSMartin Matuska dict, dictSize,
3524c03c5b1cSMartin Matuska dictLoadMethod, dictContentType,
3525c03c5b1cSMartin Matuska cParams) ))
3526c03c5b1cSMartin Matuska return NULL;
3527c03c5b1cSMartin Matuska
3528c03c5b1cSMartin Matuska return cdict;
3529c03c5b1cSMartin Matuska }
3530c03c5b1cSMartin Matuska
ZSTD_getCParamsFromCDict(const ZSTD_CDict * cdict)3531c03c5b1cSMartin Matuska ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
3532c03c5b1cSMartin Matuska {
3533c03c5b1cSMartin Matuska assert(cdict != NULL);
3534c03c5b1cSMartin Matuska return cdict->matchState.cParams;
3535c03c5b1cSMartin Matuska }
3536c03c5b1cSMartin Matuska
3537c03c5b1cSMartin Matuska /* ZSTD_compressBegin_usingCDict_advanced() :
3538c03c5b1cSMartin Matuska * cdict must be != NULL */
ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx * const cctx,const ZSTD_CDict * const cdict,ZSTD_frameParameters const fParams,unsigned long long const pledgedSrcSize)3539c03c5b1cSMartin Matuska size_t ZSTD_compressBegin_usingCDict_advanced(
3540c03c5b1cSMartin Matuska ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3541c03c5b1cSMartin Matuska ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
3542c03c5b1cSMartin Matuska {
3543c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
3544c03c5b1cSMartin Matuska RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!");
3545c03c5b1cSMartin Matuska { ZSTD_CCtx_params params = cctx->requestedParams;
3546c03c5b1cSMartin Matuska params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
3547c03c5b1cSMartin Matuska || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
3548c03c5b1cSMartin Matuska || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
3549c03c5b1cSMartin Matuska || cdict->compressionLevel == 0 )
3550c03c5b1cSMartin Matuska && (params.attachDictPref != ZSTD_dictForceLoad) ?
3551c03c5b1cSMartin Matuska ZSTD_getCParamsFromCDict(cdict)
3552c03c5b1cSMartin Matuska : ZSTD_getCParams(cdict->compressionLevel,
3553c03c5b1cSMartin Matuska pledgedSrcSize,
3554c03c5b1cSMartin Matuska cdict->dictContentSize);
3555c03c5b1cSMartin Matuska /* Increase window log to fit the entire dictionary and source if the
3556c03c5b1cSMartin Matuska * source size is known. Limit the increase to 19, which is the
3557c03c5b1cSMartin Matuska * window log for compression level 1 with the largest source size.
3558c03c5b1cSMartin Matuska */
3559c03c5b1cSMartin Matuska if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
3560c03c5b1cSMartin Matuska U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
3561c03c5b1cSMartin Matuska U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
3562c03c5b1cSMartin Matuska params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog);
3563c03c5b1cSMartin Matuska }
3564c03c5b1cSMartin Matuska params.fParams = fParams;
3565c03c5b1cSMartin Matuska return ZSTD_compressBegin_internal(cctx,
3566c03c5b1cSMartin Matuska NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
3567c03c5b1cSMartin Matuska cdict,
3568c03c5b1cSMartin Matuska ¶ms, pledgedSrcSize,
3569c03c5b1cSMartin Matuska ZSTDb_not_buffered);
3570c03c5b1cSMartin Matuska }
3571c03c5b1cSMartin Matuska }
3572c03c5b1cSMartin Matuska
3573c03c5b1cSMartin Matuska /* ZSTD_compressBegin_usingCDict() :
3574c03c5b1cSMartin Matuska * pledgedSrcSize=0 means "unknown"
3575c03c5b1cSMartin Matuska * if pledgedSrcSize>0, it will enable contentSizeFlag */
ZSTD_compressBegin_usingCDict(ZSTD_CCtx * cctx,const ZSTD_CDict * cdict)3576c03c5b1cSMartin Matuska size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
3577c03c5b1cSMartin Matuska {
3578c03c5b1cSMartin Matuska ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
3579c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
3580c03c5b1cSMartin Matuska return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
3581c03c5b1cSMartin Matuska }
3582c03c5b1cSMartin Matuska
ZSTD_compress_usingCDict_advanced(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const ZSTD_CDict * cdict,ZSTD_frameParameters fParams)3583c03c5b1cSMartin Matuska size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
3584c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
3585c03c5b1cSMartin Matuska const void* src, size_t srcSize,
3586c03c5b1cSMartin Matuska const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
3587c03c5b1cSMartin Matuska {
3588c03c5b1cSMartin Matuska FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */
3589c03c5b1cSMartin Matuska return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
3590c03c5b1cSMartin Matuska }
3591c03c5b1cSMartin Matuska
3592c03c5b1cSMartin Matuska /*! ZSTD_compress_usingCDict() :
3593c03c5b1cSMartin Matuska * Compression using a digested Dictionary.
3594c03c5b1cSMartin Matuska * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
3595c03c5b1cSMartin Matuska * Note that compression parameters are decided at CDict creation time
3596c03c5b1cSMartin Matuska * while frame parameters are hardcoded */
ZSTD_compress_usingCDict(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const ZSTD_CDict * cdict)3597c03c5b1cSMartin Matuska size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
3598c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
3599c03c5b1cSMartin Matuska const void* src, size_t srcSize,
3600c03c5b1cSMartin Matuska const ZSTD_CDict* cdict)
3601c03c5b1cSMartin Matuska {
3602c03c5b1cSMartin Matuska ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
3603c03c5b1cSMartin Matuska return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
3604c03c5b1cSMartin Matuska }
3605c03c5b1cSMartin Matuska
3606c03c5b1cSMartin Matuska
3607c03c5b1cSMartin Matuska
3608c03c5b1cSMartin Matuska /* ******************************************************************
3609c03c5b1cSMartin Matuska * Streaming
3610c03c5b1cSMartin Matuska ********************************************************************/
3611c03c5b1cSMartin Matuska
ZSTD_createCStream(void)3612c03c5b1cSMartin Matuska ZSTD_CStream* ZSTD_createCStream(void)
3613c03c5b1cSMartin Matuska {
3614c03c5b1cSMartin Matuska DEBUGLOG(3, "ZSTD_createCStream");
3615c03c5b1cSMartin Matuska return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
3616c03c5b1cSMartin Matuska }
3617c03c5b1cSMartin Matuska
ZSTD_initStaticCStream(void * workspace,size_t workspaceSize)3618c03c5b1cSMartin Matuska ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize)
3619c03c5b1cSMartin Matuska {
3620c03c5b1cSMartin Matuska return ZSTD_initStaticCCtx(workspace, workspaceSize);
3621c03c5b1cSMartin Matuska }
3622c03c5b1cSMartin Matuska
ZSTD_createCStream_advanced(ZSTD_customMem customMem)3623c03c5b1cSMartin Matuska ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
3624c03c5b1cSMartin Matuska { /* CStream and CCtx are now same object */
3625c03c5b1cSMartin Matuska return ZSTD_createCCtx_advanced(customMem);
3626c03c5b1cSMartin Matuska }
3627c03c5b1cSMartin Matuska
ZSTD_freeCStream(ZSTD_CStream * zcs)3628c03c5b1cSMartin Matuska size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
3629c03c5b1cSMartin Matuska {
3630c03c5b1cSMartin Matuska return ZSTD_freeCCtx(zcs); /* same object */
3631c03c5b1cSMartin Matuska }
3632c03c5b1cSMartin Matuska
3633c03c5b1cSMartin Matuska
3634c03c5b1cSMartin Matuska
3635c03c5b1cSMartin Matuska /*====== Initialization ======*/
3636c03c5b1cSMartin Matuska
ZSTD_CStreamInSize(void)3637c03c5b1cSMartin Matuska size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
3638c03c5b1cSMartin Matuska
ZSTD_CStreamOutSize(void)3639c03c5b1cSMartin Matuska size_t ZSTD_CStreamOutSize(void)
3640c03c5b1cSMartin Matuska {
3641c03c5b1cSMartin Matuska return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
3642c03c5b1cSMartin Matuska }
3643c03c5b1cSMartin Matuska
ZSTD_resetCStream_internal(ZSTD_CStream * cctx,const void * const dict,size_t const dictSize,ZSTD_dictContentType_e const dictContentType,const ZSTD_CDict * const cdict,ZSTD_CCtx_params params,unsigned long long const pledgedSrcSize)3644c03c5b1cSMartin Matuska static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx,
3645c03c5b1cSMartin Matuska const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType,
3646c03c5b1cSMartin Matuska const ZSTD_CDict* const cdict,
3647c03c5b1cSMartin Matuska ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize)
3648c03c5b1cSMartin Matuska {
3649c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_resetCStream_internal");
3650c03c5b1cSMartin Matuska /* Finalize the compression parameters */
3651c03c5b1cSMartin Matuska params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize);
3652c03c5b1cSMartin Matuska /* params are supposed to be fully validated at this point */
3653c03c5b1cSMartin Matuska assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
3654c03c5b1cSMartin Matuska assert(!((dict) && (cdict))); /* either dict or cdict, not both */
3655c03c5b1cSMartin Matuska
3656c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
3657c03c5b1cSMartin Matuska dict, dictSize, dictContentType, ZSTD_dtlm_fast,
3658c03c5b1cSMartin Matuska cdict,
3659c03c5b1cSMartin Matuska ¶ms, pledgedSrcSize,
3660c03c5b1cSMartin Matuska ZSTDb_buffered) , "");
3661c03c5b1cSMartin Matuska
3662c03c5b1cSMartin Matuska cctx->inToCompress = 0;
3663c03c5b1cSMartin Matuska cctx->inBuffPos = 0;
3664c03c5b1cSMartin Matuska cctx->inBuffTarget = cctx->blockSize
3665c03c5b1cSMartin Matuska + (cctx->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */
3666c03c5b1cSMartin Matuska cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
3667c03c5b1cSMartin Matuska cctx->streamStage = zcss_load;
3668c03c5b1cSMartin Matuska cctx->frameEnded = 0;
3669c03c5b1cSMartin Matuska return 0; /* ready to go */
3670c03c5b1cSMartin Matuska }
3671c03c5b1cSMartin Matuska
3672c03c5b1cSMartin Matuska /* ZSTD_resetCStream():
3673c03c5b1cSMartin Matuska * pledgedSrcSize == 0 means "unknown" */
ZSTD_resetCStream(ZSTD_CStream * zcs,unsigned long long pss)3674c03c5b1cSMartin Matuska size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss)
3675c03c5b1cSMartin Matuska {
3676c03c5b1cSMartin Matuska /* temporary : 0 interpreted as "unknown" during transition period.
3677c03c5b1cSMartin Matuska * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN.
3678c03c5b1cSMartin Matuska * 0 will be interpreted as "empty" in the future.
3679c03c5b1cSMartin Matuska */
3680c03c5b1cSMartin Matuska U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
3681c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize);
3682c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3683c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
3684c03c5b1cSMartin Matuska return 0;
3685c03c5b1cSMartin Matuska }
3686c03c5b1cSMartin Matuska
3687c03c5b1cSMartin Matuska /*! ZSTD_initCStream_internal() :
3688c03c5b1cSMartin Matuska * Note : for lib/compress only. Used by zstdmt_compress.c.
3689c03c5b1cSMartin Matuska * Assumption 1 : params are valid
3690c03c5b1cSMartin Matuska * Assumption 2 : either dict, or cdict, is defined, not both */
ZSTD_initCStream_internal(ZSTD_CStream * zcs,const void * dict,size_t dictSize,const ZSTD_CDict * cdict,const ZSTD_CCtx_params * params,unsigned long long pledgedSrcSize)3691c03c5b1cSMartin Matuska size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
3692c03c5b1cSMartin Matuska const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
3693c03c5b1cSMartin Matuska const ZSTD_CCtx_params* params,
3694c03c5b1cSMartin Matuska unsigned long long pledgedSrcSize)
3695c03c5b1cSMartin Matuska {
3696c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_initCStream_internal");
3697c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3698c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
3699c03c5b1cSMartin Matuska assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
3700c03c5b1cSMartin Matuska zcs->requestedParams = *params;
3701c03c5b1cSMartin Matuska assert(!((dict) && (cdict))); /* either dict or cdict, not both */
3702c03c5b1cSMartin Matuska if (dict) {
3703c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
3704c03c5b1cSMartin Matuska } else {
3705c03c5b1cSMartin Matuska /* Dictionary is cleared if !cdict */
3706c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
3707c03c5b1cSMartin Matuska }
3708c03c5b1cSMartin Matuska return 0;
3709c03c5b1cSMartin Matuska }
3710c03c5b1cSMartin Matuska
3711c03c5b1cSMartin Matuska /* ZSTD_initCStream_usingCDict_advanced() :
3712c03c5b1cSMartin Matuska * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream * zcs,const ZSTD_CDict * cdict,ZSTD_frameParameters fParams,unsigned long long pledgedSrcSize)3713c03c5b1cSMartin Matuska size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
3714c03c5b1cSMartin Matuska const ZSTD_CDict* cdict,
3715c03c5b1cSMartin Matuska ZSTD_frameParameters fParams,
3716c03c5b1cSMartin Matuska unsigned long long pledgedSrcSize)
3717c03c5b1cSMartin Matuska {
3718c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced");
3719c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3720c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
3721c03c5b1cSMartin Matuska zcs->requestedParams.fParams = fParams;
3722c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
3723c03c5b1cSMartin Matuska return 0;
3724c03c5b1cSMartin Matuska }
3725c03c5b1cSMartin Matuska
3726c03c5b1cSMartin Matuska /* note : cdict must outlive compression session */
ZSTD_initCStream_usingCDict(ZSTD_CStream * zcs,const ZSTD_CDict * cdict)3727c03c5b1cSMartin Matuska size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3728c03c5b1cSMartin Matuska {
3729c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_initCStream_usingCDict");
3730c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3731c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
3732c03c5b1cSMartin Matuska return 0;
3733c03c5b1cSMartin Matuska }
3734c03c5b1cSMartin Matuska
3735c03c5b1cSMartin Matuska
3736c03c5b1cSMartin Matuska /* ZSTD_initCStream_advanced() :
3737c03c5b1cSMartin Matuska * pledgedSrcSize must be exact.
3738c03c5b1cSMartin Matuska * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
3739c03c5b1cSMartin Matuska * dict is loaded with default parameters ZSTD_dct_auto and ZSTD_dlm_byCopy. */
ZSTD_initCStream_advanced(ZSTD_CStream * zcs,const void * dict,size_t dictSize,ZSTD_parameters params,unsigned long long pss)3740c03c5b1cSMartin Matuska size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3741c03c5b1cSMartin Matuska const void* dict, size_t dictSize,
3742c03c5b1cSMartin Matuska ZSTD_parameters params, unsigned long long pss)
3743c03c5b1cSMartin Matuska {
3744c03c5b1cSMartin Matuska /* for compatibility with older programs relying on this behavior.
3745c03c5b1cSMartin Matuska * Users should now specify ZSTD_CONTENTSIZE_UNKNOWN.
3746c03c5b1cSMartin Matuska * This line will be removed in the future.
3747c03c5b1cSMartin Matuska */
3748c03c5b1cSMartin Matuska U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
3749c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_initCStream_advanced");
3750c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3751c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
3752c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
3753c03c5b1cSMartin Matuska zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, ¶ms);
3754c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
3755c03c5b1cSMartin Matuska return 0;
3756c03c5b1cSMartin Matuska }
3757c03c5b1cSMartin Matuska
ZSTD_initCStream_usingDict(ZSTD_CStream * zcs,const void * dict,size_t dictSize,int compressionLevel)3758c03c5b1cSMartin Matuska size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3759c03c5b1cSMartin Matuska {
3760c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_initCStream_usingDict");
3761c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3762c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
3763c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
3764c03c5b1cSMartin Matuska return 0;
3765c03c5b1cSMartin Matuska }
3766c03c5b1cSMartin Matuska
ZSTD_initCStream_srcSize(ZSTD_CStream * zcs,int compressionLevel,unsigned long long pss)3767c03c5b1cSMartin Matuska size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss)
3768c03c5b1cSMartin Matuska {
3769c03c5b1cSMartin Matuska /* temporary : 0 interpreted as "unknown" during transition period.
3770c03c5b1cSMartin Matuska * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN.
3771c03c5b1cSMartin Matuska * 0 will be interpreted as "empty" in the future.
3772c03c5b1cSMartin Matuska */
3773c03c5b1cSMartin Matuska U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
3774c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_initCStream_srcSize");
3775c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3776c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , "");
3777c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
3778c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
3779c03c5b1cSMartin Matuska return 0;
3780c03c5b1cSMartin Matuska }
3781c03c5b1cSMartin Matuska
ZSTD_initCStream(ZSTD_CStream * zcs,int compressionLevel)3782c03c5b1cSMartin Matuska size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3783c03c5b1cSMartin Matuska {
3784c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_initCStream");
3785c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3786c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , "");
3787c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
3788c03c5b1cSMartin Matuska return 0;
3789c03c5b1cSMartin Matuska }
3790c03c5b1cSMartin Matuska
3791c03c5b1cSMartin Matuska /*====== Compression ======*/
3792c03c5b1cSMartin Matuska
ZSTD_nextInputSizeHint(const ZSTD_CCtx * cctx)3793c03c5b1cSMartin Matuska static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx)
3794c03c5b1cSMartin Matuska {
3795c03c5b1cSMartin Matuska size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos;
3796c03c5b1cSMartin Matuska if (hintInSize==0) hintInSize = cctx->blockSize;
3797c03c5b1cSMartin Matuska return hintInSize;
3798c03c5b1cSMartin Matuska }
3799c03c5b1cSMartin Matuska
3800c03c5b1cSMartin Matuska /** ZSTD_compressStream_generic():
3801c03c5b1cSMartin Matuska * internal function for all *compressStream*() variants
3802c03c5b1cSMartin Matuska * non-static, because can be called from zstdmt_compress.c
3803c03c5b1cSMartin Matuska * @return : hint size for next input */
ZSTD_compressStream_generic(ZSTD_CStream * zcs,ZSTD_outBuffer * output,ZSTD_inBuffer * input,ZSTD_EndDirective const flushMode)3804c03c5b1cSMartin Matuska static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3805c03c5b1cSMartin Matuska ZSTD_outBuffer* output,
3806c03c5b1cSMartin Matuska ZSTD_inBuffer* input,
3807c03c5b1cSMartin Matuska ZSTD_EndDirective const flushMode)
3808c03c5b1cSMartin Matuska {
3809c03c5b1cSMartin Matuska const char* const istart = (const char*)input->src;
3810c03c5b1cSMartin Matuska const char* const iend = input->size != 0 ? istart + input->size : istart;
3811c03c5b1cSMartin Matuska const char* ip = input->pos != 0 ? istart + input->pos : istart;
3812c03c5b1cSMartin Matuska char* const ostart = (char*)output->dst;
3813c03c5b1cSMartin Matuska char* const oend = output->size != 0 ? ostart + output->size : ostart;
3814c03c5b1cSMartin Matuska char* op = output->pos != 0 ? ostart + output->pos : ostart;
3815c03c5b1cSMartin Matuska U32 someMoreWork = 1;
3816c03c5b1cSMartin Matuska
3817c03c5b1cSMartin Matuska /* check expectations */
3818c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode);
3819c03c5b1cSMartin Matuska assert(zcs->inBuff != NULL);
3820c03c5b1cSMartin Matuska assert(zcs->inBuffSize > 0);
3821c03c5b1cSMartin Matuska assert(zcs->outBuff != NULL);
3822c03c5b1cSMartin Matuska assert(zcs->outBuffSize > 0);
3823c03c5b1cSMartin Matuska assert(output->pos <= output->size);
3824c03c5b1cSMartin Matuska assert(input->pos <= input->size);
3825c03c5b1cSMartin Matuska
3826c03c5b1cSMartin Matuska while (someMoreWork) {
3827c03c5b1cSMartin Matuska switch(zcs->streamStage)
3828c03c5b1cSMartin Matuska {
3829c03c5b1cSMartin Matuska case zcss_init:
3830c03c5b1cSMartin Matuska RETURN_ERROR(init_missing, "call ZSTD_initCStream() first!");
3831c03c5b1cSMartin Matuska
3832c03c5b1cSMartin Matuska case zcss_load:
3833c03c5b1cSMartin Matuska if ( (flushMode == ZSTD_e_end)
3834c03c5b1cSMartin Matuska && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */
3835c03c5b1cSMartin Matuska && (zcs->inBuffPos == 0) ) {
3836c03c5b1cSMartin Matuska /* shortcut to compression pass directly into output buffer */
3837c03c5b1cSMartin Matuska size_t const cSize = ZSTD_compressEnd(zcs,
3838c03c5b1cSMartin Matuska op, oend-op, ip, iend-ip);
3839c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize);
3840c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "ZSTD_compressEnd failed");
3841c03c5b1cSMartin Matuska ip = iend;
3842c03c5b1cSMartin Matuska op += cSize;
3843c03c5b1cSMartin Matuska zcs->frameEnded = 1;
3844c03c5b1cSMartin Matuska ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
3845c03c5b1cSMartin Matuska someMoreWork = 0; break;
3846c03c5b1cSMartin Matuska }
3847c03c5b1cSMartin Matuska /* complete loading into inBuffer */
3848c03c5b1cSMartin Matuska { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3849c03c5b1cSMartin Matuska size_t const loaded = ZSTD_limitCopy(
3850c03c5b1cSMartin Matuska zcs->inBuff + zcs->inBuffPos, toLoad,
3851c03c5b1cSMartin Matuska ip, iend-ip);
3852c03c5b1cSMartin Matuska zcs->inBuffPos += loaded;
3853c03c5b1cSMartin Matuska if (loaded != 0)
3854c03c5b1cSMartin Matuska ip += loaded;
3855c03c5b1cSMartin Matuska if ( (flushMode == ZSTD_e_continue)
3856c03c5b1cSMartin Matuska && (zcs->inBuffPos < zcs->inBuffTarget) ) {
3857c03c5b1cSMartin Matuska /* not enough input to fill full block : stop here */
3858c03c5b1cSMartin Matuska someMoreWork = 0; break;
3859c03c5b1cSMartin Matuska }
3860c03c5b1cSMartin Matuska if ( (flushMode == ZSTD_e_flush)
3861c03c5b1cSMartin Matuska && (zcs->inBuffPos == zcs->inToCompress) ) {
3862c03c5b1cSMartin Matuska /* empty */
3863c03c5b1cSMartin Matuska someMoreWork = 0; break;
3864c03c5b1cSMartin Matuska }
3865c03c5b1cSMartin Matuska }
3866c03c5b1cSMartin Matuska /* compress current block (note : this stage cannot be stopped in the middle) */
3867c03c5b1cSMartin Matuska DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
3868c03c5b1cSMartin Matuska { void* cDst;
3869c03c5b1cSMartin Matuska size_t cSize;
3870c03c5b1cSMartin Matuska size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3871c03c5b1cSMartin Matuska size_t oSize = oend-op;
3872c03c5b1cSMartin Matuska unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
3873c03c5b1cSMartin Matuska if (oSize >= ZSTD_compressBound(iSize))
3874c03c5b1cSMartin Matuska cDst = op; /* compress into output buffer, to skip flush stage */
3875c03c5b1cSMartin Matuska else
3876c03c5b1cSMartin Matuska cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3877c03c5b1cSMartin Matuska cSize = lastBlock ?
3878c03c5b1cSMartin Matuska ZSTD_compressEnd(zcs, cDst, oSize,
3879c03c5b1cSMartin Matuska zcs->inBuff + zcs->inToCompress, iSize) :
3880c03c5b1cSMartin Matuska ZSTD_compressContinue(zcs, cDst, oSize,
3881c03c5b1cSMartin Matuska zcs->inBuff + zcs->inToCompress, iSize);
3882c03c5b1cSMartin Matuska FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
3883c03c5b1cSMartin Matuska zcs->frameEnded = lastBlock;
3884c03c5b1cSMartin Matuska /* prepare next block */
3885c03c5b1cSMartin Matuska zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3886c03c5b1cSMartin Matuska if (zcs->inBuffTarget > zcs->inBuffSize)
3887c03c5b1cSMartin Matuska zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
3888c03c5b1cSMartin Matuska DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
3889c03c5b1cSMartin Matuska (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize);
3890c03c5b1cSMartin Matuska if (!lastBlock)
3891c03c5b1cSMartin Matuska assert(zcs->inBuffTarget <= zcs->inBuffSize);
3892c03c5b1cSMartin Matuska zcs->inToCompress = zcs->inBuffPos;
3893c03c5b1cSMartin Matuska if (cDst == op) { /* no need to flush */
3894c03c5b1cSMartin Matuska op += cSize;
3895c03c5b1cSMartin Matuska if (zcs->frameEnded) {
3896c03c5b1cSMartin Matuska DEBUGLOG(5, "Frame completed directly in outBuffer");
3897c03c5b1cSMartin Matuska someMoreWork = 0;
3898c03c5b1cSMartin Matuska ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
3899c03c5b1cSMartin Matuska }
3900c03c5b1cSMartin Matuska break;
3901c03c5b1cSMartin Matuska }
3902c03c5b1cSMartin Matuska zcs->outBuffContentSize = cSize;
3903c03c5b1cSMartin Matuska zcs->outBuffFlushedSize = 0;
3904c03c5b1cSMartin Matuska zcs->streamStage = zcss_flush; /* pass-through to flush stage */
3905c03c5b1cSMartin Matuska }
3906c03c5b1cSMartin Matuska /* fall-through */
3907c03c5b1cSMartin Matuska case zcss_flush:
3908c03c5b1cSMartin Matuska DEBUGLOG(5, "flush stage");
3909c03c5b1cSMartin Matuska { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3910c03c5b1cSMartin Matuska size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op),
3911c03c5b1cSMartin Matuska zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3912c03c5b1cSMartin Matuska DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u",
3913c03c5b1cSMartin Matuska (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed);
3914c03c5b1cSMartin Matuska if (flushed)
3915c03c5b1cSMartin Matuska op += flushed;
3916c03c5b1cSMartin Matuska zcs->outBuffFlushedSize += flushed;
3917c03c5b1cSMartin Matuska if (toFlush!=flushed) {
3918c03c5b1cSMartin Matuska /* flush not fully completed, presumably because dst is too small */
3919c03c5b1cSMartin Matuska assert(op==oend);
3920c03c5b1cSMartin Matuska someMoreWork = 0;
3921c03c5b1cSMartin Matuska break;
3922c03c5b1cSMartin Matuska }
3923c03c5b1cSMartin Matuska zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3924c03c5b1cSMartin Matuska if (zcs->frameEnded) {
3925c03c5b1cSMartin Matuska DEBUGLOG(5, "Frame completed on flush");
3926c03c5b1cSMartin Matuska someMoreWork = 0;
3927c03c5b1cSMartin Matuska ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
3928c03c5b1cSMartin Matuska break;
3929c03c5b1cSMartin Matuska }
3930c03c5b1cSMartin Matuska zcs->streamStage = zcss_load;
3931c03c5b1cSMartin Matuska break;
3932c03c5b1cSMartin Matuska }
3933c03c5b1cSMartin Matuska
3934c03c5b1cSMartin Matuska default: /* impossible */
3935c03c5b1cSMartin Matuska assert(0);
3936c03c5b1cSMartin Matuska }
3937c03c5b1cSMartin Matuska }
3938c03c5b1cSMartin Matuska
3939c03c5b1cSMartin Matuska input->pos = ip - istart;
3940c03c5b1cSMartin Matuska output->pos = op - ostart;
3941c03c5b1cSMartin Matuska if (zcs->frameEnded) return 0;
3942c03c5b1cSMartin Matuska return ZSTD_nextInputSizeHint(zcs);
3943c03c5b1cSMartin Matuska }
3944c03c5b1cSMartin Matuska
ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx * cctx)3945c03c5b1cSMartin Matuska static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx)
3946c03c5b1cSMartin Matuska {
3947c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
3948c03c5b1cSMartin Matuska if (cctx->appliedParams.nbWorkers >= 1) {
3949c03c5b1cSMartin Matuska assert(cctx->mtctx != NULL);
3950c03c5b1cSMartin Matuska return ZSTDMT_nextInputSizeHint(cctx->mtctx);
3951c03c5b1cSMartin Matuska }
3952c03c5b1cSMartin Matuska #endif
3953c03c5b1cSMartin Matuska return ZSTD_nextInputSizeHint(cctx);
3954c03c5b1cSMartin Matuska
3955c03c5b1cSMartin Matuska }
3956c03c5b1cSMartin Matuska
ZSTD_compressStream(ZSTD_CStream * zcs,ZSTD_outBuffer * output,ZSTD_inBuffer * input)3957c03c5b1cSMartin Matuska size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
3958c03c5b1cSMartin Matuska {
3959c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) , "");
3960c03c5b1cSMartin Matuska return ZSTD_nextInputSizeHint_MTorST(zcs);
3961c03c5b1cSMartin Matuska }
3962c03c5b1cSMartin Matuska
3963c03c5b1cSMartin Matuska
ZSTD_compressStream2(ZSTD_CCtx * cctx,ZSTD_outBuffer * output,ZSTD_inBuffer * input,ZSTD_EndDirective endOp)3964c03c5b1cSMartin Matuska size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
3965c03c5b1cSMartin Matuska ZSTD_outBuffer* output,
3966c03c5b1cSMartin Matuska ZSTD_inBuffer* input,
3967c03c5b1cSMartin Matuska ZSTD_EndDirective endOp)
3968c03c5b1cSMartin Matuska {
3969c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
3970c03c5b1cSMartin Matuska /* check conditions */
3971c03c5b1cSMartin Matuska RETURN_ERROR_IF(output->pos > output->size, GENERIC, "invalid buffer");
3972c03c5b1cSMartin Matuska RETURN_ERROR_IF(input->pos > input->size, GENERIC, "invalid buffer");
3973c03c5b1cSMartin Matuska assert(cctx!=NULL);
3974c03c5b1cSMartin Matuska
3975c03c5b1cSMartin Matuska /* transparent initialization stage */
3976c03c5b1cSMartin Matuska if (cctx->streamStage == zcss_init) {
3977c03c5b1cSMartin Matuska ZSTD_CCtx_params params = cctx->requestedParams;
3978c03c5b1cSMartin Matuska ZSTD_prefixDict const prefixDict = cctx->prefixDict;
3979c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */
3980c03c5b1cSMartin Matuska memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
3981c03c5b1cSMartin Matuska assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
3982c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
3983c03c5b1cSMartin Matuska if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */
3984c03c5b1cSMartin Matuska params.cParams = ZSTD_getCParamsFromCCtxParams(
3985c03c5b1cSMartin Matuska &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
3986c03c5b1cSMartin Matuska
3987c03c5b1cSMartin Matuska
3988c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
3989c03c5b1cSMartin Matuska if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
3990c03c5b1cSMartin Matuska params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
3991c03c5b1cSMartin Matuska }
3992c03c5b1cSMartin Matuska if (params.nbWorkers > 0) {
3993c03c5b1cSMartin Matuska /* mt context creation */
3994c03c5b1cSMartin Matuska if (cctx->mtctx == NULL) {
3995c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u",
3996c03c5b1cSMartin Matuska params.nbWorkers);
3997c03c5b1cSMartin Matuska cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem);
3998c03c5b1cSMartin Matuska RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!");
3999c03c5b1cSMartin Matuska }
4000c03c5b1cSMartin Matuska /* mt compression */
4001c03c5b1cSMartin Matuska DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
4002c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTDMT_initCStream_internal(
4003c03c5b1cSMartin Matuska cctx->mtctx,
4004c03c5b1cSMartin Matuska prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
4005c03c5b1cSMartin Matuska cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , "");
4006c03c5b1cSMartin Matuska cctx->streamStage = zcss_load;
4007c03c5b1cSMartin Matuska cctx->appliedParams.nbWorkers = params.nbWorkers;
4008c03c5b1cSMartin Matuska } else
4009c03c5b1cSMartin Matuska #endif
4010c03c5b1cSMartin Matuska { FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx,
4011c03c5b1cSMartin Matuska prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
4012c03c5b1cSMartin Matuska cctx->cdict,
4013c03c5b1cSMartin Matuska params, cctx->pledgedSrcSizePlusOne-1) , "");
4014c03c5b1cSMartin Matuska assert(cctx->streamStage == zcss_load);
4015c03c5b1cSMartin Matuska assert(cctx->appliedParams.nbWorkers == 0);
4016c03c5b1cSMartin Matuska } }
4017c03c5b1cSMartin Matuska /* end of transparent initialization stage */
4018c03c5b1cSMartin Matuska
4019c03c5b1cSMartin Matuska /* compression stage */
4020c03c5b1cSMartin Matuska #ifdef ZSTD_MULTITHREAD
4021c03c5b1cSMartin Matuska if (cctx->appliedParams.nbWorkers > 0) {
4022c03c5b1cSMartin Matuska int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end);
4023c03c5b1cSMartin Matuska size_t flushMin;
4024c03c5b1cSMartin Matuska assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */);
4025c03c5b1cSMartin Matuska if (cctx->cParamsChanged) {
4026c03c5b1cSMartin Matuska ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
4027c03c5b1cSMartin Matuska cctx->cParamsChanged = 0;
4028c03c5b1cSMartin Matuska }
4029c03c5b1cSMartin Matuska do {
4030c03c5b1cSMartin Matuska flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
4031c03c5b1cSMartin Matuska if ( ZSTD_isError(flushMin)
4032c03c5b1cSMartin Matuska || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
4033c03c5b1cSMartin Matuska ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
4034c03c5b1cSMartin Matuska }
4035c03c5b1cSMartin Matuska FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed");
4036c03c5b1cSMartin Matuska } while (forceMaxProgress && flushMin != 0 && output->pos < output->size);
4037c03c5b1cSMartin Matuska DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic");
4038c03c5b1cSMartin Matuska /* Either we don't require maximum forward progress, we've finished the
4039c03c5b1cSMartin Matuska * flush, or we are out of output space.
4040c03c5b1cSMartin Matuska */
4041c03c5b1cSMartin Matuska assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size);
4042c03c5b1cSMartin Matuska return flushMin;
4043c03c5b1cSMartin Matuska }
4044c03c5b1cSMartin Matuska #endif
4045c03c5b1cSMartin Matuska FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , "");
4046c03c5b1cSMartin Matuska DEBUGLOG(5, "completed ZSTD_compressStream2");
4047c03c5b1cSMartin Matuska return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
4048c03c5b1cSMartin Matuska }
4049c03c5b1cSMartin Matuska
ZSTD_compressStream2_simpleArgs(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,size_t * dstPos,const void * src,size_t srcSize,size_t * srcPos,ZSTD_EndDirective endOp)4050c03c5b1cSMartin Matuska size_t ZSTD_compressStream2_simpleArgs (
4051c03c5b1cSMartin Matuska ZSTD_CCtx* cctx,
4052c03c5b1cSMartin Matuska void* dst, size_t dstCapacity, size_t* dstPos,
4053c03c5b1cSMartin Matuska const void* src, size_t srcSize, size_t* srcPos,
4054c03c5b1cSMartin Matuska ZSTD_EndDirective endOp)
4055c03c5b1cSMartin Matuska {
4056c03c5b1cSMartin Matuska ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
4057c03c5b1cSMartin Matuska ZSTD_inBuffer input = { src, srcSize, *srcPos };
4058c03c5b1cSMartin Matuska /* ZSTD_compressStream2() will check validity of dstPos and srcPos */
4059c03c5b1cSMartin Matuska size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp);
4060c03c5b1cSMartin Matuska *dstPos = output.pos;
4061c03c5b1cSMartin Matuska *srcPos = input.pos;
4062c03c5b1cSMartin Matuska return cErr;
4063c03c5b1cSMartin Matuska }
4064c03c5b1cSMartin Matuska
ZSTD_compress2(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)4065c03c5b1cSMartin Matuska size_t ZSTD_compress2(ZSTD_CCtx* cctx,
4066c03c5b1cSMartin Matuska void* dst, size_t dstCapacity,
4067c03c5b1cSMartin Matuska const void* src, size_t srcSize)
4068c03c5b1cSMartin Matuska {
4069c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize);
4070c03c5b1cSMartin Matuska ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
4071c03c5b1cSMartin Matuska { size_t oPos = 0;
4072c03c5b1cSMartin Matuska size_t iPos = 0;
4073c03c5b1cSMartin Matuska size_t const result = ZSTD_compressStream2_simpleArgs(cctx,
4074c03c5b1cSMartin Matuska dst, dstCapacity, &oPos,
4075c03c5b1cSMartin Matuska src, srcSize, &iPos,
4076c03c5b1cSMartin Matuska ZSTD_e_end);
4077c03c5b1cSMartin Matuska FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed");
4078c03c5b1cSMartin Matuska if (result != 0) { /* compression not completed, due to lack of output space */
4079c03c5b1cSMartin Matuska assert(oPos == dstCapacity);
4080c03c5b1cSMartin Matuska RETURN_ERROR(dstSize_tooSmall, "");
4081c03c5b1cSMartin Matuska }
4082c03c5b1cSMartin Matuska assert(iPos == srcSize); /* all input is expected consumed */
4083c03c5b1cSMartin Matuska return oPos;
4084c03c5b1cSMartin Matuska }
4085c03c5b1cSMartin Matuska }
4086c03c5b1cSMartin Matuska
4087c03c5b1cSMartin Matuska /*====== Finalize ======*/
4088c03c5b1cSMartin Matuska
4089c03c5b1cSMartin Matuska /*! ZSTD_flushStream() :
4090c03c5b1cSMartin Matuska * @return : amount of data remaining to flush */
ZSTD_flushStream(ZSTD_CStream * zcs,ZSTD_outBuffer * output)4091c03c5b1cSMartin Matuska size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
4092c03c5b1cSMartin Matuska {
4093c03c5b1cSMartin Matuska ZSTD_inBuffer input = { NULL, 0, 0 };
4094c03c5b1cSMartin Matuska return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush);
4095c03c5b1cSMartin Matuska }
4096c03c5b1cSMartin Matuska
4097c03c5b1cSMartin Matuska
ZSTD_endStream(ZSTD_CStream * zcs,ZSTD_outBuffer * output)4098c03c5b1cSMartin Matuska size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
4099c03c5b1cSMartin Matuska {
4100c03c5b1cSMartin Matuska ZSTD_inBuffer input = { NULL, 0, 0 };
4101c03c5b1cSMartin Matuska size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end);
4102c03c5b1cSMartin Matuska FORWARD_IF_ERROR( remainingToFlush , "ZSTD_compressStream2 failed");
4103c03c5b1cSMartin Matuska if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */
4104c03c5b1cSMartin Matuska /* single thread mode : attempt to calculate remaining to flush more precisely */
4105c03c5b1cSMartin Matuska { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
4106c03c5b1cSMartin Matuska size_t const checksumSize = (size_t)(zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4);
4107c03c5b1cSMartin Matuska size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize;
4108c03c5b1cSMartin Matuska DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush);
4109c03c5b1cSMartin Matuska return toFlush;
4110c03c5b1cSMartin Matuska }
4111c03c5b1cSMartin Matuska }
4112c03c5b1cSMartin Matuska
4113c03c5b1cSMartin Matuska
4114c03c5b1cSMartin Matuska /*-===== Pre-defined compression levels =====-*/
4115c03c5b1cSMartin Matuska
4116c03c5b1cSMartin Matuska #define ZSTD_MAX_CLEVEL 22
ZSTD_maxCLevel(void)4117c03c5b1cSMartin Matuska int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
ZSTD_minCLevel(void)4118c03c5b1cSMartin Matuska int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; }
4119c03c5b1cSMartin Matuska
4120c03c5b1cSMartin Matuska static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
4121c03c5b1cSMartin Matuska { /* "default" - for any srcSize > 256 KB */
4122c03c5b1cSMartin Matuska /* W, C, H, S, L, TL, strat */
4123c03c5b1cSMartin Matuska { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */
4124c03c5b1cSMartin Matuska { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */
4125c03c5b1cSMartin Matuska { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */
4126c03c5b1cSMartin Matuska { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */
4127c03c5b1cSMartin Matuska { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */
4128c03c5b1cSMartin Matuska { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */
4129c03c5b1cSMartin Matuska { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */
4130c03c5b1cSMartin Matuska { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */
4131c03c5b1cSMartin Matuska { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
4132c03c5b1cSMartin Matuska { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */
4133c03c5b1cSMartin Matuska { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
4134c03c5b1cSMartin Matuska { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
4135c03c5b1cSMartin Matuska { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
4136c03c5b1cSMartin Matuska { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */
4137c03c5b1cSMartin Matuska { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */
4138c03c5b1cSMartin Matuska { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */
4139c03c5b1cSMartin Matuska { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */
4140c03c5b1cSMartin Matuska { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */
4141c03c5b1cSMartin Matuska { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */
4142c03c5b1cSMartin Matuska { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */
4143c03c5b1cSMartin Matuska { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */
4144c03c5b1cSMartin Matuska { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */
4145c03c5b1cSMartin Matuska { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */
4146c03c5b1cSMartin Matuska },
4147c03c5b1cSMartin Matuska { /* for srcSize <= 256 KB */
4148c03c5b1cSMartin Matuska /* W, C, H, S, L, T, strat */
4149c03c5b1cSMartin Matuska { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
4150c03c5b1cSMartin Matuska { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */
4151c03c5b1cSMartin Matuska { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */
4152c03c5b1cSMartin Matuska { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */
4153c03c5b1cSMartin Matuska { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/
4154c03c5b1cSMartin Matuska { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/
4155c03c5b1cSMartin Matuska { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/
4156c03c5b1cSMartin Matuska { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */
4157c03c5b1cSMartin Matuska { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
4158c03c5b1cSMartin Matuska { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
4159c03c5b1cSMartin Matuska { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
4160c03c5b1cSMartin Matuska { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/
4161c03c5b1cSMartin Matuska { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/
4162c03c5b1cSMartin Matuska { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */
4163c03c5b1cSMartin Matuska { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/
4164c03c5b1cSMartin Matuska { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/
4165c03c5b1cSMartin Matuska { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/
4166c03c5b1cSMartin Matuska { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/
4167c03c5b1cSMartin Matuska { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/
4168c03c5b1cSMartin Matuska { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/
4169c03c5b1cSMartin Matuska { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/
4170c03c5b1cSMartin Matuska { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/
4171c03c5b1cSMartin Matuska { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/
4172c03c5b1cSMartin Matuska },
4173c03c5b1cSMartin Matuska { /* for srcSize <= 128 KB */
4174c03c5b1cSMartin Matuska /* W, C, H, S, L, T, strat */
4175c03c5b1cSMartin Matuska { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
4176c03c5b1cSMartin Matuska { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */
4177c03c5b1cSMartin Matuska { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */
4178c03c5b1cSMartin Matuska { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */
4179c03c5b1cSMartin Matuska { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */
4180c03c5b1cSMartin Matuska { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */
4181c03c5b1cSMartin Matuska { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
4182c03c5b1cSMartin Matuska { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */
4183c03c5b1cSMartin Matuska { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
4184c03c5b1cSMartin Matuska { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
4185c03c5b1cSMartin Matuska { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
4186c03c5b1cSMartin Matuska { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */
4187c03c5b1cSMartin Matuska { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */
4188c03c5b1cSMartin Matuska { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/
4189c03c5b1cSMartin Matuska { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/
4190c03c5b1cSMartin Matuska { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/
4191c03c5b1cSMartin Matuska { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/
4192c03c5b1cSMartin Matuska { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/
4193c03c5b1cSMartin Matuska { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/
4194c03c5b1cSMartin Matuska { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/
4195c03c5b1cSMartin Matuska { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/
4196c03c5b1cSMartin Matuska { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/
4197c03c5b1cSMartin Matuska { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/
4198c03c5b1cSMartin Matuska },
4199c03c5b1cSMartin Matuska { /* for srcSize <= 16 KB */
4200c03c5b1cSMartin Matuska /* W, C, H, S, L, T, strat */
4201c03c5b1cSMartin Matuska { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
4202c03c5b1cSMartin Matuska { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */
4203c03c5b1cSMartin Matuska { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */
4204c03c5b1cSMartin Matuska { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */
4205c03c5b1cSMartin Matuska { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */
4206c03c5b1cSMartin Matuska { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/
4207c03c5b1cSMartin Matuska { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */
4208c03c5b1cSMartin Matuska { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */
4209c03c5b1cSMartin Matuska { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/
4210c03c5b1cSMartin Matuska { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/
4211c03c5b1cSMartin Matuska { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/
4212c03c5b1cSMartin Matuska { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/
4213c03c5b1cSMartin Matuska { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/
4214c03c5b1cSMartin Matuska { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/
4215c03c5b1cSMartin Matuska { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/
4216c03c5b1cSMartin Matuska { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/
4217c03c5b1cSMartin Matuska { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/
4218c03c5b1cSMartin Matuska { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/
4219c03c5b1cSMartin Matuska { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/
4220c03c5b1cSMartin Matuska { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/
4221c03c5b1cSMartin Matuska { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/
4222c03c5b1cSMartin Matuska { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/
4223c03c5b1cSMartin Matuska { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/
4224c03c5b1cSMartin Matuska },
4225c03c5b1cSMartin Matuska };
4226c03c5b1cSMartin Matuska
4227c03c5b1cSMartin Matuska /*! ZSTD_getCParams_internal() :
4228c03c5b1cSMartin Matuska * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
4229c03c5b1cSMartin Matuska * Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown.
4230c03c5b1cSMartin Matuska * Use dictSize == 0 for unknown or unused. */
ZSTD_getCParams_internal(int compressionLevel,unsigned long long srcSizeHint,size_t dictSize)4231c03c5b1cSMartin Matuska static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
4232c03c5b1cSMartin Matuska {
4233c03c5b1cSMartin Matuska int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN;
4234c03c5b1cSMartin Matuska size_t const addedSize = unknown && dictSize > 0 ? 500 : 0;
4235c03c5b1cSMartin Matuska U64 const rSize = unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize;
4236c03c5b1cSMartin Matuska U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB);
4237c03c5b1cSMartin Matuska int row = compressionLevel;
4238c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel);
4239c03c5b1cSMartin Matuska if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */
4240c03c5b1cSMartin Matuska if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */
4241c03c5b1cSMartin Matuska if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
4242c03c5b1cSMartin Matuska { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
4243c03c5b1cSMartin Matuska if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */
4244c03c5b1cSMartin Matuska /* refine parameters based on srcSize & dictSize */
4245c03c5b1cSMartin Matuska return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize);
4246c03c5b1cSMartin Matuska }
4247c03c5b1cSMartin Matuska }
4248c03c5b1cSMartin Matuska
4249c03c5b1cSMartin Matuska /*! ZSTD_getCParams() :
4250c03c5b1cSMartin Matuska * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
4251c03c5b1cSMartin Matuska * Size values are optional, provide 0 if not known or unused */
ZSTD_getCParams(int compressionLevel,unsigned long long srcSizeHint,size_t dictSize)4252c03c5b1cSMartin Matuska ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
4253c03c5b1cSMartin Matuska {
4254c03c5b1cSMartin Matuska if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
4255c03c5b1cSMartin Matuska return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
4256c03c5b1cSMartin Matuska }
4257c03c5b1cSMartin Matuska
4258c03c5b1cSMartin Matuska /*! ZSTD_getParams() :
4259c03c5b1cSMartin Matuska * same idea as ZSTD_getCParams()
4260c03c5b1cSMartin Matuska * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
4261c03c5b1cSMartin Matuska * Fields of `ZSTD_frameParameters` are set to default values */
ZSTD_getParams_internal(int compressionLevel,unsigned long long srcSizeHint,size_t dictSize)4262c03c5b1cSMartin Matuska static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
4263c03c5b1cSMartin Matuska ZSTD_parameters params;
4264c03c5b1cSMartin Matuska ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
4265c03c5b1cSMartin Matuska DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
4266c03c5b1cSMartin Matuska memset(¶ms, 0, sizeof(params));
4267c03c5b1cSMartin Matuska params.cParams = cParams;
4268c03c5b1cSMartin Matuska params.fParams.contentSizeFlag = 1;
4269c03c5b1cSMartin Matuska return params;
4270c03c5b1cSMartin Matuska }
4271c03c5b1cSMartin Matuska
4272c03c5b1cSMartin Matuska /*! ZSTD_getParams() :
4273c03c5b1cSMartin Matuska * same idea as ZSTD_getCParams()
4274c03c5b1cSMartin Matuska * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
4275c03c5b1cSMartin Matuska * Fields of `ZSTD_frameParameters` are set to default values */
ZSTD_getParams(int compressionLevel,unsigned long long srcSizeHint,size_t dictSize)4276c03c5b1cSMartin Matuska ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
4277c03c5b1cSMartin Matuska if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
4278c03c5b1cSMartin Matuska return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize);
4279c03c5b1cSMartin Matuska }
4280