extzstd 0.0.3.CONCEPT → 0.3.1

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