zstd-ruby 1.4.5.0 → 1.4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +35 -0
  3. data/README.md +2 -2
  4. data/ext/zstdruby/libzstd/Makefile +237 -138
  5. data/ext/zstdruby/libzstd/README.md +28 -0
  6. data/ext/zstdruby/libzstd/common/bitstream.h +25 -16
  7. data/ext/zstdruby/libzstd/common/compiler.h +118 -4
  8. data/ext/zstdruby/libzstd/common/cpu.h +1 -3
  9. data/ext/zstdruby/libzstd/common/debug.c +1 -1
  10. data/ext/zstdruby/libzstd/common/debug.h +12 -19
  11. data/ext/zstdruby/libzstd/common/entropy_common.c +189 -43
  12. data/ext/zstdruby/libzstd/common/error_private.c +2 -1
  13. data/ext/zstdruby/libzstd/common/error_private.h +2 -2
  14. data/ext/zstdruby/libzstd/common/fse.h +40 -12
  15. data/ext/zstdruby/libzstd/common/fse_decompress.c +124 -17
  16. data/ext/zstdruby/libzstd/common/huf.h +27 -6
  17. data/ext/zstdruby/libzstd/common/mem.h +67 -94
  18. data/ext/zstdruby/libzstd/common/pool.c +23 -17
  19. data/ext/zstdruby/libzstd/common/pool.h +2 -2
  20. data/ext/zstdruby/libzstd/common/threading.c +6 -5
  21. data/ext/zstdruby/libzstd/common/xxhash.c +19 -57
  22. data/ext/zstdruby/libzstd/common/xxhash.h +2 -2
  23. data/ext/zstdruby/libzstd/common/zstd_common.c +10 -10
  24. data/ext/zstdruby/libzstd/common/zstd_deps.h +111 -0
  25. data/ext/zstdruby/libzstd/common/zstd_errors.h +2 -1
  26. data/ext/zstdruby/libzstd/common/zstd_internal.h +90 -59
  27. data/ext/zstdruby/libzstd/common/zstd_trace.c +42 -0
  28. data/ext/zstdruby/libzstd/common/zstd_trace.h +152 -0
  29. data/ext/zstdruby/libzstd/compress/fse_compress.c +31 -24
  30. data/ext/zstdruby/libzstd/compress/hist.c +27 -29
  31. data/ext/zstdruby/libzstd/compress/hist.h +2 -2
  32. data/ext/zstdruby/libzstd/compress/huf_compress.c +217 -101
  33. data/ext/zstdruby/libzstd/compress/zstd_compress.c +1495 -478
  34. data/ext/zstdruby/libzstd/compress/zstd_compress_internal.h +143 -44
  35. data/ext/zstdruby/libzstd/compress/zstd_compress_literals.c +7 -7
  36. data/ext/zstdruby/libzstd/compress/zstd_compress_literals.h +1 -1
  37. data/ext/zstdruby/libzstd/compress/zstd_compress_sequences.c +18 -4
  38. data/ext/zstdruby/libzstd/compress/zstd_compress_sequences.h +1 -1
  39. data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.c +25 -21
  40. data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.h +1 -1
  41. data/ext/zstdruby/libzstd/compress/zstd_cwksp.h +62 -26
  42. data/ext/zstdruby/libzstd/compress/zstd_double_fast.c +23 -23
  43. data/ext/zstdruby/libzstd/compress/zstd_double_fast.h +1 -1
  44. data/ext/zstdruby/libzstd/compress/zstd_fast.c +21 -21
  45. data/ext/zstdruby/libzstd/compress/zstd_fast.h +1 -1
  46. data/ext/zstdruby/libzstd/compress/zstd_lazy.c +352 -78
  47. data/ext/zstdruby/libzstd/compress/zstd_lazy.h +21 -1
  48. data/ext/zstdruby/libzstd/compress/zstd_ldm.c +276 -209
  49. data/ext/zstdruby/libzstd/compress/zstd_ldm.h +8 -2
  50. data/ext/zstdruby/libzstd/compress/zstd_ldm_geartab.h +103 -0
  51. data/ext/zstdruby/libzstd/compress/zstd_opt.c +191 -46
  52. data/ext/zstdruby/libzstd/compress/zstd_opt.h +1 -1
  53. data/ext/zstdruby/libzstd/compress/zstdmt_compress.c +79 -410
  54. data/ext/zstdruby/libzstd/compress/zstdmt_compress.h +27 -109
  55. data/ext/zstdruby/libzstd/decompress/huf_decompress.c +303 -201
  56. data/ext/zstdruby/libzstd/decompress/zstd_ddict.c +9 -9
  57. data/ext/zstdruby/libzstd/decompress/zstd_ddict.h +2 -2
  58. data/ext/zstdruby/libzstd/decompress/zstd_decompress.c +370 -87
  59. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.c +153 -45
  60. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.h +6 -3
  61. data/ext/zstdruby/libzstd/decompress/zstd_decompress_internal.h +28 -11
  62. data/ext/zstdruby/libzstd/deprecated/zbuff.h +1 -1
  63. data/ext/zstdruby/libzstd/deprecated/zbuff_common.c +1 -1
  64. data/ext/zstdruby/libzstd/deprecated/zbuff_compress.c +1 -1
  65. data/ext/zstdruby/libzstd/deprecated/zbuff_decompress.c +1 -1
  66. data/ext/zstdruby/libzstd/dictBuilder/cover.c +40 -31
  67. data/ext/zstdruby/libzstd/dictBuilder/cover.h +2 -2
  68. data/ext/zstdruby/libzstd/dictBuilder/divsufsort.c +1 -1
  69. data/ext/zstdruby/libzstd/dictBuilder/fastcover.c +26 -25
  70. data/ext/zstdruby/libzstd/dictBuilder/zdict.c +22 -24
  71. data/ext/zstdruby/libzstd/dictBuilder/zdict.h +5 -4
  72. data/ext/zstdruby/libzstd/dll/example/Makefile +1 -1
  73. data/ext/zstdruby/libzstd/dll/example/README.md +16 -22
  74. data/ext/zstdruby/libzstd/legacy/zstd_legacy.h +1 -1
  75. data/ext/zstdruby/libzstd/legacy/zstd_v01.c +6 -2
  76. data/ext/zstdruby/libzstd/legacy/zstd_v01.h +1 -1
  77. data/ext/zstdruby/libzstd/legacy/zstd_v02.c +6 -2
  78. data/ext/zstdruby/libzstd/legacy/zstd_v02.h +1 -1
  79. data/ext/zstdruby/libzstd/legacy/zstd_v03.c +6 -2
  80. data/ext/zstdruby/libzstd/legacy/zstd_v03.h +1 -1
  81. data/ext/zstdruby/libzstd/legacy/zstd_v04.c +7 -3
  82. data/ext/zstdruby/libzstd/legacy/zstd_v04.h +1 -1
  83. data/ext/zstdruby/libzstd/legacy/zstd_v05.c +10 -6
  84. data/ext/zstdruby/libzstd/legacy/zstd_v05.h +1 -1
  85. data/ext/zstdruby/libzstd/legacy/zstd_v06.c +10 -6
  86. data/ext/zstdruby/libzstd/legacy/zstd_v06.h +1 -1
  87. data/ext/zstdruby/libzstd/legacy/zstd_v07.c +10 -6
  88. data/ext/zstdruby/libzstd/legacy/zstd_v07.h +1 -1
  89. data/ext/zstdruby/libzstd/libzstd.pc.in +3 -3
  90. data/ext/zstdruby/libzstd/zstd.h +414 -54
  91. data/lib/zstd-ruby/version.rb +1 -1
  92. metadata +7 -3
  93. data/.travis.yml +0 -14
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
2
+ * Copyright (c) 2016-2021, Yann Collet, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under both the BSD-style license (found in the
@@ -11,10 +11,10 @@
11
11
  /*-*************************************
12
12
  * Dependencies
13
13
  ***************************************/
14
- #include <limits.h> /* INT_MAX */
15
- #include <string.h> /* memset */
14
+ #include "../common/zstd_deps.h" /* INT_MAX, ZSTD_memset, ZSTD_memcpy */
16
15
  #include "../common/cpu.h"
17
16
  #include "../common/mem.h"
17
+ #include "../common/zstd_trace.h"
18
18
  #include "hist.h" /* HIST_countFast_wksp */
19
19
  #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
20
20
  #include "../common/fse.h"
@@ -30,6 +30,19 @@
30
30
  #include "zstd_ldm.h"
31
31
  #include "zstd_compress_superblock.h"
32
32
 
33
+ /* ***************************************************************
34
+ * Tuning parameters
35
+ *****************************************************************/
36
+ /*!
37
+ * COMPRESS_HEAPMODE :
38
+ * Select how default decompression function ZSTD_compress() allocates its context,
39
+ * on stack (0, default), or into heap (1).
40
+ * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected.
41
+ */
42
+ #ifndef ZSTD_COMPRESS_HEAPMODE
43
+ # define ZSTD_COMPRESS_HEAPMODE 0
44
+ #endif
45
+
33
46
 
34
47
  /*-*************************************
35
48
  * Helper functions
@@ -52,6 +65,7 @@ size_t ZSTD_compressBound(size_t srcSize) {
52
65
  struct ZSTD_CDict_s {
53
66
  const void* dictContent;
54
67
  size_t dictContentSize;
68
+ ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */
55
69
  U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
56
70
  ZSTD_cwksp workspace;
57
71
  ZSTD_matchState_t matchState;
@@ -69,7 +83,7 @@ ZSTD_CCtx* ZSTD_createCCtx(void)
69
83
  static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
70
84
  {
71
85
  assert(cctx != NULL);
72
- memset(cctx, 0, sizeof(*cctx));
86
+ ZSTD_memset(cctx, 0, sizeof(*cctx));
73
87
  cctx->customMem = memManager;
74
88
  cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
75
89
  { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
@@ -82,8 +96,8 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
82
96
  {
83
97
  ZSTD_STATIC_ASSERT(zcss_init==0);
84
98
  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);
99
+ if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
100
+ { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem);
87
101
  if (!cctx) return NULL;
88
102
  ZSTD_initCCtx(cctx, customMem);
89
103
  return cctx;
@@ -96,20 +110,20 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
96
110
  ZSTD_CCtx* cctx;
97
111
  if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
98
112
  if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
99
- ZSTD_cwksp_init(&ws, workspace, workspaceSize);
113
+ ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc);
100
114
 
101
115
  cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx));
102
116
  if (cctx == NULL) return NULL;
103
117
 
104
- memset(cctx, 0, sizeof(ZSTD_CCtx));
118
+ ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx));
105
119
  ZSTD_cwksp_move(&cctx->workspace, &ws);
106
120
  cctx->staticSize = workspaceSize;
107
121
 
108
122
  /* 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;
123
+ if (!ZSTD_cwksp_check_available(&cctx->workspace, ENTROPY_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL;
110
124
  cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
111
125
  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);
126
+ cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, ENTROPY_WORKSPACE_SIZE);
113
127
  cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
114
128
  return cctx;
115
129
  }
@@ -119,10 +133,10 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
119
133
  */
120
134
  static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx)
121
135
  {
122
- ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem);
136
+ ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem);
123
137
  ZSTD_freeCDict(cctx->localDict.cdict);
124
- memset(&cctx->localDict, 0, sizeof(cctx->localDict));
125
- memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
138
+ ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict));
139
+ ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
126
140
  cctx->cdict = NULL;
127
141
  }
128
142
 
@@ -153,7 +167,7 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
153
167
  int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx);
154
168
  ZSTD_freeCCtxContent(cctx);
155
169
  if (!cctxInWorkspace) {
156
- ZSTD_free(cctx, cctx->customMem);
170
+ ZSTD_customFree(cctx, cctx->customMem);
157
171
  }
158
172
  }
159
173
  return 0;
@@ -189,15 +203,32 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
189
203
  /* private API call, for dictBuilder only */
190
204
  const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
191
205
 
206
+ /* Returns 1 if compression parameters are such that we should
207
+ * enable long distance matching (wlog >= 27, strategy >= btopt).
208
+ * Returns 0 otherwise.
209
+ */
210
+ static U32 ZSTD_CParams_shouldEnableLdm(const ZSTD_compressionParameters* const cParams) {
211
+ return cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27;
212
+ }
213
+
192
214
  static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
193
215
  ZSTD_compressionParameters cParams)
194
216
  {
195
217
  ZSTD_CCtx_params cctxParams;
196
- memset(&cctxParams, 0, sizeof(cctxParams));
218
+ /* should not matter, as all cParams are presumed properly defined */
219
+ ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT);
197
220
  cctxParams.cParams = cParams;
198
- cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
221
+
222
+ if (ZSTD_CParams_shouldEnableLdm(&cParams)) {
223
+ DEBUGLOG(4, "ZSTD_makeCCtxParamsFromCParams(): Including LDM into cctx params");
224
+ cctxParams.ldmParams.enableLdm = 1;
225
+ /* LDM is enabled by default for optimal parser and window size >= 128MB */
226
+ ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams);
227
+ assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog);
228
+ assert(cctxParams.ldmParams.hashRateLog < 32);
229
+ }
230
+
199
231
  assert(!ZSTD_checkCParams(cParams));
200
- cctxParams.fParams.contentSizeFlag = 1;
201
232
  return cctxParams;
202
233
  }
203
234
 
@@ -205,13 +236,12 @@ static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
205
236
  ZSTD_customMem customMem)
206
237
  {
207
238
  ZSTD_CCtx_params* params;
208
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
209
- params = (ZSTD_CCtx_params*)ZSTD_calloc(
239
+ if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
240
+ params = (ZSTD_CCtx_params*)ZSTD_customCalloc(
210
241
  sizeof(ZSTD_CCtx_params), customMem);
211
242
  if (!params) { return NULL; }
243
+ ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
212
244
  params->customMem = customMem;
213
- params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
214
- params->fParams.contentSizeFlag = 1;
215
245
  return params;
216
246
  }
217
247
 
@@ -223,7 +253,7 @@ ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
223
253
  size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
224
254
  {
225
255
  if (params == NULL) { return 0; }
226
- ZSTD_free(params, params->customMem);
256
+ ZSTD_customFree(params, params->customMem);
227
257
  return 0;
228
258
  }
229
259
 
@@ -234,35 +264,52 @@ size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
234
264
 
235
265
  size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
236
266
  RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
237
- memset(cctxParams, 0, sizeof(*cctxParams));
267
+ ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));
238
268
  cctxParams->compressionLevel = compressionLevel;
239
269
  cctxParams->fParams.contentSizeFlag = 1;
240
270
  return 0;
241
271
  }
242
272
 
273
+ #define ZSTD_NO_CLEVEL 0
274
+
275
+ /**
276
+ * Initializes the cctxParams from params and compressionLevel.
277
+ * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL.
278
+ */
279
+ static void ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, ZSTD_parameters const* params, int compressionLevel)
280
+ {
281
+ assert(!ZSTD_checkCParams(params->cParams));
282
+ ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));
283
+ cctxParams->cParams = params->cParams;
284
+ cctxParams->fParams = params->fParams;
285
+ /* Should not matter, as all cParams are presumed properly defined.
286
+ * But, set it for tracing anyway.
287
+ */
288
+ cctxParams->compressionLevel = compressionLevel;
289
+ }
290
+
243
291
  size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
244
292
  {
245
293
  RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
246
294
  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 */
295
+ ZSTD_CCtxParams_init_internal(cctxParams, &params, ZSTD_NO_CLEVEL);
252
296
  return 0;
253
297
  }
254
298
 
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)
299
+ /**
300
+ * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone.
301
+ * @param param Validated zstd parameters.
302
+ */
303
+ static void ZSTD_CCtxParams_setZstdParams(
304
+ ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params)
259
305
  {
260
- ZSTD_CCtx_params ret = *cctxParams;
261
306
  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;
307
+ cctxParams->cParams = params->cParams;
308
+ cctxParams->fParams = params->fParams;
309
+ /* Should not matter, as all cParams are presumed properly defined.
310
+ * But, set it for tracing anyway.
311
+ */
312
+ cctxParams->compressionLevel = ZSTD_NO_CLEVEL;
266
313
  }
267
314
 
268
315
  ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
@@ -354,6 +401,11 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
354
401
  #endif
355
402
  return bounds;
356
403
 
404
+ case ZSTD_c_enableDedicatedDictSearch:
405
+ bounds.lowerBound = 0;
406
+ bounds.upperBound = 1;
407
+ return bounds;
408
+
357
409
  case ZSTD_c_enableLongDistanceMatching:
358
410
  bounds.lowerBound = 0;
359
411
  bounds.upperBound = 1;
@@ -397,7 +449,7 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
397
449
  return bounds;
398
450
 
399
451
  case ZSTD_c_forceAttachDict:
400
- ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy);
452
+ ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceLoad);
401
453
  bounds.lowerBound = ZSTD_dictDefaultAttach;
402
454
  bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */
403
455
  return bounds;
@@ -418,6 +470,22 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
418
470
  bounds.upperBound = ZSTD_SRCSIZEHINT_MAX;
419
471
  return bounds;
420
472
 
473
+ case ZSTD_c_stableInBuffer:
474
+ case ZSTD_c_stableOutBuffer:
475
+ bounds.lowerBound = (int)ZSTD_bm_buffered;
476
+ bounds.upperBound = (int)ZSTD_bm_stable;
477
+ return bounds;
478
+
479
+ case ZSTD_c_blockDelimiters:
480
+ bounds.lowerBound = (int)ZSTD_sf_noBlockDelimiters;
481
+ bounds.upperBound = (int)ZSTD_sf_explicitBlockDelimiters;
482
+ return bounds;
483
+
484
+ case ZSTD_c_validateSequences:
485
+ bounds.lowerBound = 0;
486
+ bounds.upperBound = 1;
487
+ return bounds;
488
+
421
489
  default:
422
490
  bounds.error = ERROR(parameter_unsupported);
423
491
  return bounds;
@@ -465,6 +533,7 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
465
533
  case ZSTD_c_jobSize:
466
534
  case ZSTD_c_overlapLog:
467
535
  case ZSTD_c_rsyncable:
536
+ case ZSTD_c_enableDedicatedDictSearch:
468
537
  case ZSTD_c_enableLongDistanceMatching:
469
538
  case ZSTD_c_ldmHashLog:
470
539
  case ZSTD_c_ldmMinMatch:
@@ -474,6 +543,10 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
474
543
  case ZSTD_c_literalCompressionMode:
475
544
  case ZSTD_c_targetCBlockSize:
476
545
  case ZSTD_c_srcSizeHint:
546
+ case ZSTD_c_stableInBuffer:
547
+ case ZSTD_c_stableOutBuffer:
548
+ case ZSTD_c_blockDelimiters:
549
+ case ZSTD_c_validateSequences:
477
550
  default:
478
551
  return 0;
479
552
  }
@@ -515,12 +588,17 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
515
588
  case ZSTD_c_jobSize:
516
589
  case ZSTD_c_overlapLog:
517
590
  case ZSTD_c_rsyncable:
591
+ case ZSTD_c_enableDedicatedDictSearch:
518
592
  case ZSTD_c_enableLongDistanceMatching:
519
593
  case ZSTD_c_ldmHashLog:
520
594
  case ZSTD_c_ldmMinMatch:
521
595
  case ZSTD_c_ldmBucketSizeLog:
522
596
  case ZSTD_c_targetCBlockSize:
523
597
  case ZSTD_c_srcSizeHint:
598
+ case ZSTD_c_stableInBuffer:
599
+ case ZSTD_c_stableOutBuffer:
600
+ case ZSTD_c_blockDelimiters:
601
+ case ZSTD_c_validateSequences:
524
602
  break;
525
603
 
526
604
  default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
@@ -541,9 +619,10 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
541
619
 
542
620
  case ZSTD_c_compressionLevel : {
543
621
  FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
544
- if (value) { /* 0 : does not change current level */
622
+ if (value == 0)
623
+ CCtxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default */
624
+ else
545
625
  CCtxParams->compressionLevel = value;
546
- }
547
626
  if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel;
548
627
  return 0; /* return type (size_t) cannot represent negative values */
549
628
  }
@@ -667,6 +746,10 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
667
746
  return CCtxParams->rsyncable;
668
747
  #endif
669
748
 
749
+ case ZSTD_c_enableDedicatedDictSearch :
750
+ CCtxParams->enableDedicatedDictSearch = (value!=0);
751
+ return CCtxParams->enableDedicatedDictSearch;
752
+
670
753
  case ZSTD_c_enableLongDistanceMatching :
671
754
  CCtxParams->ldmParams.enableLdm = (value!=0);
672
755
  return CCtxParams->ldmParams.enableLdm;
@@ -707,17 +790,37 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
707
790
  CCtxParams->srcSizeHint = value;
708
791
  return CCtxParams->srcSizeHint;
709
792
 
793
+ case ZSTD_c_stableInBuffer:
794
+ BOUNDCHECK(ZSTD_c_stableInBuffer, value);
795
+ CCtxParams->inBufferMode = (ZSTD_bufferMode_e)value;
796
+ return CCtxParams->inBufferMode;
797
+
798
+ case ZSTD_c_stableOutBuffer:
799
+ BOUNDCHECK(ZSTD_c_stableOutBuffer, value);
800
+ CCtxParams->outBufferMode = (ZSTD_bufferMode_e)value;
801
+ return CCtxParams->outBufferMode;
802
+
803
+ case ZSTD_c_blockDelimiters:
804
+ BOUNDCHECK(ZSTD_c_blockDelimiters, value);
805
+ CCtxParams->blockDelimiters = (ZSTD_sequenceFormat_e)value;
806
+ return CCtxParams->blockDelimiters;
807
+
808
+ case ZSTD_c_validateSequences:
809
+ BOUNDCHECK(ZSTD_c_validateSequences, value);
810
+ CCtxParams->validateSequences = value;
811
+ return CCtxParams->validateSequences;
812
+
710
813
  default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
711
814
  }
712
815
  }
713
816
 
714
- size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value)
817
+ size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value)
715
818
  {
716
819
  return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value);
717
820
  }
718
821
 
719
822
  size_t ZSTD_CCtxParams_getParameter(
720
- ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value)
823
+ ZSTD_CCtx_params const* CCtxParams, ZSTD_cParameter param, int* value)
721
824
  {
722
825
  switch(param)
723
826
  {
@@ -794,6 +897,9 @@ size_t ZSTD_CCtxParams_getParameter(
794
897
  *value = CCtxParams->rsyncable;
795
898
  break;
796
899
  #endif
900
+ case ZSTD_c_enableDedicatedDictSearch :
901
+ *value = CCtxParams->enableDedicatedDictSearch;
902
+ break;
797
903
  case ZSTD_c_enableLongDistanceMatching :
798
904
  *value = CCtxParams->ldmParams.enableLdm;
799
905
  break;
@@ -815,6 +921,18 @@ size_t ZSTD_CCtxParams_getParameter(
815
921
  case ZSTD_c_srcSizeHint :
816
922
  *value = (int)CCtxParams->srcSizeHint;
817
923
  break;
924
+ case ZSTD_c_stableInBuffer :
925
+ *value = (int)CCtxParams->inBufferMode;
926
+ break;
927
+ case ZSTD_c_stableOutBuffer :
928
+ *value = (int)CCtxParams->outBufferMode;
929
+ break;
930
+ case ZSTD_c_blockDelimiters :
931
+ *value = (int)CCtxParams->blockDelimiters;
932
+ break;
933
+ case ZSTD_c_validateSequences :
934
+ *value = (int)CCtxParams->validateSequences;
935
+ break;
818
936
  default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
819
937
  }
820
938
  return 0;
@@ -850,6 +968,14 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo
850
968
  return 0;
851
969
  }
852
970
 
971
+ static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(
972
+ int const compressionLevel,
973
+ size_t const dictSize);
974
+ static int ZSTD_dedicatedDictSearch_isSupported(
975
+ const ZSTD_compressionParameters* cParams);
976
+ static void ZSTD_dedicatedDictSearch_revertCParams(
977
+ ZSTD_compressionParameters* cParams);
978
+
853
979
  /**
854
980
  * Initializes the local dict using the requested parameters.
855
981
  * NOTE: This does not use the pledged src size, because it may be used for more
@@ -858,8 +984,6 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo
858
984
  static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
859
985
  {
860
986
  ZSTD_localDict* const dl = &cctx->localDict;
861
- ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(
862
- &cctx->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN, dl->dictSize);
863
987
  if (dl->dict == NULL) {
864
988
  /* No local dictionary. */
865
989
  assert(dl->dictBuffer == NULL);
@@ -876,12 +1000,12 @@ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
876
1000
  assert(cctx->cdict == NULL);
877
1001
  assert(cctx->prefixDict.dict == NULL);
878
1002
 
879
- dl->cdict = ZSTD_createCDict_advanced(
1003
+ dl->cdict = ZSTD_createCDict_advanced2(
880
1004
  dl->dict,
881
1005
  dl->dictSize,
882
1006
  ZSTD_dlm_byRef,
883
1007
  dl->dictContentType,
884
- cParams,
1008
+ &cctx->requestedParams,
885
1009
  cctx->customMem);
886
1010
  RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed");
887
1011
  cctx->cdict = dl->cdict;
@@ -894,8 +1018,6 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
894
1018
  {
895
1019
  RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
896
1020
  "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
1021
  DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
900
1022
  ZSTD_clearAllDicts(cctx); /* in case one already exists */
901
1023
  if (dict == NULL || dictSize == 0) /* no dictionary mode */
@@ -903,9 +1025,12 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
903
1025
  if (dictLoadMethod == ZSTD_dlm_byRef) {
904
1026
  cctx->localDict.dict = dict;
905
1027
  } else {
906
- void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem);
1028
+ void* dictBuffer;
1029
+ RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
1030
+ "no malloc for static CCtx");
1031
+ dictBuffer = ZSTD_customMalloc(dictSize, cctx->customMem);
907
1032
  RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!");
908
- memcpy(dictBuffer, dict, dictSize);
1033
+ ZSTD_memcpy(dictBuffer, dict, dictSize);
909
1034
  cctx->localDict.dictBuffer = dictBuffer;
910
1035
  cctx->localDict.dict = dictBuffer;
911
1036
  }
@@ -938,6 +1063,14 @@ size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
938
1063
  return 0;
939
1064
  }
940
1065
 
1066
+ size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool)
1067
+ {
1068
+ RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
1069
+ "Can't ref a pool when ctx not in init stage.");
1070
+ cctx->pool = pool;
1071
+ return 0;
1072
+ }
1073
+
941
1074
  size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
942
1075
  {
943
1076
  return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
@@ -1022,23 +1155,83 @@ U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
1022
1155
  return hashLog - btScale;
1023
1156
  }
1024
1157
 
1158
+ /** ZSTD_dictAndWindowLog() :
1159
+ * Returns an adjusted window log that is large enough to fit the source and the dictionary.
1160
+ * The zstd format says that the entire dictionary is valid if one byte of the dictionary
1161
+ * is within the window. So the hashLog and chainLog should be large enough to reference both
1162
+ * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing
1163
+ * the hashLog and windowLog.
1164
+ * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN.
1165
+ */
1166
+ static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize)
1167
+ {
1168
+ const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX;
1169
+ /* No dictionary ==> No change */
1170
+ if (dictSize == 0) {
1171
+ return windowLog;
1172
+ }
1173
+ assert(windowLog <= ZSTD_WINDOWLOG_MAX);
1174
+ assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */
1175
+ {
1176
+ U64 const windowSize = 1ULL << windowLog;
1177
+ U64 const dictAndWindowSize = dictSize + windowSize;
1178
+ /* If the window size is already large enough to fit both the source and the dictionary
1179
+ * then just use the window size. Otherwise adjust so that it fits the dictionary and
1180
+ * the window.
1181
+ */
1182
+ if (windowSize >= dictSize + srcSize) {
1183
+ return windowLog; /* Window size large enough already */
1184
+ } else if (dictAndWindowSize >= maxWindowSize) {
1185
+ return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */
1186
+ } else {
1187
+ return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1;
1188
+ }
1189
+ }
1190
+ }
1191
+
1025
1192
  /** ZSTD_adjustCParams_internal() :
1026
1193
  * optimize `cPar` for a specified input (`srcSize` and `dictSize`).
1027
1194
  * mostly downsize to reduce memory consumption and initialization latency.
1028
1195
  * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known.
1196
+ * `mode` is the mode for parameter adjustment. See docs for `ZSTD_cParamMode_e`.
1029
1197
  * note : `srcSize==0` means 0!
1030
1198
  * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */
1031
1199
  static ZSTD_compressionParameters
1032
1200
  ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
1033
1201
  unsigned long long srcSize,
1034
- size_t dictSize)
1202
+ size_t dictSize,
1203
+ ZSTD_cParamMode_e mode)
1035
1204
  {
1036
- static const U64 minSrcSize = 513; /* (1<<9) + 1 */
1037
- static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
1205
+ const U64 minSrcSize = 513; /* (1<<9) + 1 */
1206
+ const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
1038
1207
  assert(ZSTD_checkCParams(cPar)==0);
1039
1208
 
1040
- if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
1041
- srcSize = minSrcSize;
1209
+ switch (mode) {
1210
+ case ZSTD_cpm_unknown:
1211
+ case ZSTD_cpm_noAttachDict:
1212
+ /* If we don't know the source size, don't make any
1213
+ * assumptions about it. We will already have selected
1214
+ * smaller parameters if a dictionary is in use.
1215
+ */
1216
+ break;
1217
+ case ZSTD_cpm_createCDict:
1218
+ /* Assume a small source size when creating a dictionary
1219
+ * with an unkown source size.
1220
+ */
1221
+ if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
1222
+ srcSize = minSrcSize;
1223
+ break;
1224
+ case ZSTD_cpm_attachDict:
1225
+ /* Dictionary has its own dedicated parameters which have
1226
+ * already been selected. We are selecting parameters
1227
+ * for only the source.
1228
+ */
1229
+ dictSize = 0;
1230
+ break;
1231
+ default:
1232
+ assert(0);
1233
+ break;
1234
+ }
1042
1235
 
1043
1236
  /* resize windowLog if input is small enough, to use less memory */
1044
1237
  if ( (srcSize < maxWindowResize)
@@ -1049,10 +1242,12 @@ ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
1049
1242
  ZSTD_highbit32(tSize-1) + 1;
1050
1243
  if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
1051
1244
  }
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);
1245
+ if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
1246
+ U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize);
1247
+ U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
1248
+ if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1;
1249
+ if (cycleLog > dictAndWindowLog)
1250
+ cPar.chainLog -= (cycleLog - dictAndWindowLog);
1056
1251
  }
1057
1252
 
1058
1253
  if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
@@ -1068,31 +1263,38 @@ ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
1068
1263
  {
1069
1264
  cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */
1070
1265
  if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN;
1071
- return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
1266
+ return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown);
1072
1267
  }
1073
1268
 
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);
1269
+ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode);
1270
+ static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode);
1271
+
1272
+ static void ZSTD_overrideCParams(
1273
+ ZSTD_compressionParameters* cParams,
1274
+ const ZSTD_compressionParameters* overrides)
1275
+ {
1276
+ if (overrides->windowLog) cParams->windowLog = overrides->windowLog;
1277
+ if (overrides->hashLog) cParams->hashLog = overrides->hashLog;
1278
+ if (overrides->chainLog) cParams->chainLog = overrides->chainLog;
1279
+ if (overrides->searchLog) cParams->searchLog = overrides->searchLog;
1280
+ if (overrides->minMatch) cParams->minMatch = overrides->minMatch;
1281
+ if (overrides->targetLength) cParams->targetLength = overrides->targetLength;
1282
+ if (overrides->strategy) cParams->strategy = overrides->strategy;
1283
+ }
1076
1284
 
1077
1285
  ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
1078
- const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
1286
+ const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
1079
1287
  {
1080
1288
  ZSTD_compressionParameters cParams;
1081
1289
  if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) {
1082
1290
  srcSizeHint = CCtxParams->srcSizeHint;
1083
1291
  }
1084
- cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize);
1292
+ cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode);
1085
1293
  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;
1294
+ ZSTD_overrideCParams(&cParams, &CCtxParams->cParams);
1093
1295
  assert(!ZSTD_checkCParams(cParams));
1094
1296
  /* srcSizeHint == 0 means 0 */
1095
- return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize);
1297
+ return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode);
1096
1298
  }
1097
1299
 
1098
1300
  static size_t
@@ -1123,45 +1325,61 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
1123
1325
  return tableSpace + optSpace;
1124
1326
  }
1125
1327
 
1126
- size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1328
+ static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1329
+ const ZSTD_compressionParameters* cParams,
1330
+ const ldmParams_t* ldmParams,
1331
+ const int isStatic,
1332
+ const size_t buffInSize,
1333
+ const size_t buffOutSize,
1334
+ const U64 pledgedSrcSize)
1127
1335
  {
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);
1336
+ size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << cParams->windowLog), pledgedSrcSize));
1337
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
1338
+ U32 const divider = (cParams->minMatch==3) ? 3 : 4;
1339
+ size_t const maxNbSeq = blockSize / divider;
1340
+ size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
1341
+ + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
1342
+ + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
1343
+ size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE);
1344
+ size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
1345
+ size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, /* forCCtx */ 1);
1140
1346
 
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));
1347
+ size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams);
1348
+ size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize);
1349
+ size_t const ldmSeqSpace = ldmParams->enableLdm ?
1350
+ ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0;
1143
1351
 
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
1352
 
1150
- size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx));
1353
+ size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize)
1354
+ + ZSTD_cwksp_alloc_size(buffOutSize);
1151
1355
 
1152
- size_t const neededSpace =
1153
- cctxSpace +
1154
- entropySpace +
1155
- blockStateSpace +
1156
- ldmSpace +
1157
- ldmSeqSpace +
1158
- matchStateSize +
1159
- tokenSpace +
1160
- bufferSpace;
1356
+ size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
1161
1357
 
1162
- DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
1163
- return neededSpace;
1164
- }
1358
+ size_t const neededSpace =
1359
+ cctxSpace +
1360
+ entropySpace +
1361
+ blockStateSpace +
1362
+ ldmSpace +
1363
+ ldmSeqSpace +
1364
+ matchStateSize +
1365
+ tokenSpace +
1366
+ bufferSpace;
1367
+
1368
+ DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
1369
+ return neededSpace;
1370
+ }
1371
+
1372
+ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1373
+ {
1374
+ ZSTD_compressionParameters const cParams =
1375
+ ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1376
+
1377
+ RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
1378
+ /* estimateCCtxSize is for one-shot compression. So no buffers should
1379
+ * be needed. However, we still allocate two 0-sized buffers, which can
1380
+ * take space under ASAN. */
1381
+ return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1382
+ &cParams, &params->ldmParams, 1, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN);
1165
1383
  }
1166
1384
 
1167
1385
  size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
@@ -1172,7 +1390,7 @@ size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
1172
1390
 
1173
1391
  static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
1174
1392
  {
1175
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
1393
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1176
1394
  return ZSTD_estimateCCtxSize_usingCParams(cParams);
1177
1395
  }
1178
1396
 
@@ -1191,15 +1409,18 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1191
1409
  {
1192
1410
  RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
1193
1411
  { ZSTD_compressionParameters const cParams =
1194
- ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
1195
- size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
1412
+ ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1196
1413
  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;
1414
+ size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered)
1415
+ ? ((size_t)1 << cParams.windowLog) + blockSize
1416
+ : 0;
1417
+ size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered)
1418
+ ? ZSTD_compressBound(blockSize) + 1
1419
+ : 0;
1420
+
1421
+ return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1422
+ &cParams, &params->ldmParams, 1, inBuffSize, outBuffSize,
1423
+ ZSTD_CONTENTSIZE_UNKNOWN);
1203
1424
  }
1204
1425
  }
1205
1426
 
@@ -1211,7 +1432,7 @@ size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
1211
1432
 
1212
1433
  static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
1213
1434
  {
1214
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
1435
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1215
1436
  return ZSTD_estimateCStreamSize_usingCParams(cParams);
1216
1437
  }
1217
1438
 
@@ -1304,16 +1525,6 @@ static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
1304
1525
  ms->dictMatchState = NULL;
1305
1526
  }
1306
1527
 
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
1528
  /**
1318
1529
  * Controls, for this matchState reset, whether the tables need to be cleared /
1319
1530
  * prepared for the coming compression (ZSTDcrp_makeClean), or whether the
@@ -1434,52 +1645,38 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1434
1645
  ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
1435
1646
  assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
1436
1647
  assert(params.ldmParams.hashRateLog < 32);
1437
- zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
1438
1648
  }
1439
1649
 
1440
1650
  { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
1441
1651
  size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
1442
1652
  U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
1443
1653
  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);
1654
+ size_t const buffOutSize = (zbuff == ZSTDb_buffered && params.outBufferMode == ZSTD_bm_buffered)
1655
+ ? ZSTD_compressBound(blockSize) + 1
1656
+ : 0;
1657
+ size_t const buffInSize = (zbuff == ZSTDb_buffered && params.inBufferMode == ZSTD_bm_buffered)
1658
+ ? windowSize + blockSize
1659
+ : 0;
1450
1660
  size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
1451
1661
 
1452
- ZSTD_indexResetPolicy_e needsIndexReset = zc->initialized ? ZSTDirp_continue : ZSTDirp_reset;
1662
+ int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window);
1663
+ ZSTD_indexResetPolicy_e needsIndexReset =
1664
+ (!indexTooClose && zc->initialized) ? ZSTDirp_continue : ZSTDirp_reset;
1453
1665
 
1454
- if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) {
1455
- needsIndexReset = ZSTDirp_reset;
1456
- }
1666
+ size_t const neededSpace =
1667
+ ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1668
+ &params.cParams, &params.ldmParams, zc->staticSize != 0,
1669
+ buffInSize, buffOutSize, pledgedSrcSize);
1670
+ FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!");
1457
1671
 
1458
1672
  if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
1459
1673
 
1460
1674
  /* 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
-
1675
+ {
1478
1676
  int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
1479
1677
  int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
1480
1678
 
1481
- DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
1482
- neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
1679
+ DEBUGLOG(4, "Need %zu B workspace", neededSpace);
1483
1680
  DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
1484
1681
 
1485
1682
  if (workspaceTooSmall || workspaceWasteful) {
@@ -1503,7 +1700,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1503
1700
  RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock");
1504
1701
  zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
1505
1702
  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);
1703
+ zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, ENTROPY_WORKSPACE_SIZE);
1507
1704
  RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace");
1508
1705
  } }
1509
1706
 
@@ -1524,6 +1721,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1524
1721
  XXH64_reset(&zc->xxhState, 0);
1525
1722
  zc->stage = ZSTDcs_init;
1526
1723
  zc->dictID = 0;
1724
+ zc->dictContentSize = 0;
1527
1725
 
1528
1726
  ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
1529
1727
 
@@ -1534,6 +1732,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1534
1732
  zc->seqStore.maxNbLit = blockSize;
1535
1733
 
1536
1734
  /* buffers */
1735
+ zc->bufferedPolicy = zbuff;
1537
1736
  zc->inBuffSize = buffInSize;
1538
1737
  zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize);
1539
1738
  zc->outBuffSize = buffOutSize;
@@ -1542,11 +1741,11 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1542
1741
  /* ldm bucketOffsets table */
1543
1742
  if (params.ldmParams.enableLdm) {
1544
1743
  /* TODO: avoid memset? */
1545
- size_t const ldmBucketSize =
1744
+ size_t const numBuckets =
1546
1745
  ((size_t)1) << (params.ldmParams.hashLog -
1547
1746
  params.ldmParams.bucketSizeLog);
1548
- zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize);
1549
- memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize);
1747
+ zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets);
1748
+ ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets);
1550
1749
  }
1551
1750
 
1552
1751
  /* sequences storage */
@@ -1570,7 +1769,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1570
1769
  /* TODO: avoid memset? */
1571
1770
  size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
1572
1771
  zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t));
1573
- memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
1772
+ ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
1574
1773
  zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq));
1575
1774
  zc->maxNbLdmSequences = maxNbLdmSeq;
1576
1775
 
@@ -1579,6 +1778,12 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1579
1778
  zc->ldmState.loadedDictEnd = 0;
1580
1779
  }
1581
1780
 
1781
+ /* Due to alignment, when reusing a workspace, we can actually consume
1782
+ * up to 3 extra bytes for alignment. See the comments in zstd_cwksp.h
1783
+ */
1784
+ assert(ZSTD_cwksp_used(ws) >= neededSpace &&
1785
+ ZSTD_cwksp_used(ws) <= neededSpace + 3);
1786
+
1582
1787
  DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws));
1583
1788
  zc->initialized = 1;
1584
1789
 
@@ -1618,12 +1823,14 @@ static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict,
1618
1823
  U64 pledgedSrcSize)
1619
1824
  {
1620
1825
  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 */
1826
+ int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch;
1827
+ return dedicatedDictSearch
1828
+ || ( ( pledgedSrcSize <= cutoff
1829
+ || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
1830
+ || params->attachDictPref == ZSTD_dictForceAttach )
1831
+ && params->attachDictPref != ZSTD_dictForceCopy
1832
+ && !params->forceWindow ); /* dictMatchState isn't correctly
1833
+ * handled in _enforceMaxDist */
1627
1834
  }
1628
1835
 
1629
1836
  static size_t
@@ -1633,17 +1840,24 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
1633
1840
  U64 pledgedSrcSize,
1634
1841
  ZSTD_buffered_policy_e zbuff)
1635
1842
  {
1636
- { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams;
1843
+ {
1844
+ ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams;
1637
1845
  unsigned const windowLog = params.cParams.windowLog;
1638
1846
  assert(windowLog != 0);
1639
1847
  /* Resize working context table params for input only, since the dict
1640
1848
  * has its own tables. */
1641
- /* pledgeSrcSize == 0 means 0! */
1642
- params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0);
1849
+ /* pledgedSrcSize == 0 means 0! */
1850
+
1851
+ if (cdict->matchState.dedicatedDictSearch) {
1852
+ ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams);
1853
+ }
1854
+
1855
+ params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize,
1856
+ cdict->dictContentSize, ZSTD_cpm_attachDict);
1643
1857
  params.cParams.windowLog = windowLog;
1644
1858
  FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
1645
1859
  ZSTDcrp_makeClean, zbuff), "");
1646
- assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
1860
+ assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy);
1647
1861
  }
1648
1862
 
1649
1863
  { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc
@@ -1668,9 +1882,10 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
1668
1882
  } }
1669
1883
 
1670
1884
  cctx->dictID = cdict->dictID;
1885
+ cctx->dictContentSize = cdict->dictContentSize;
1671
1886
 
1672
1887
  /* copy block state */
1673
- memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1888
+ ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1674
1889
 
1675
1890
  return 0;
1676
1891
  }
@@ -1683,6 +1898,8 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
1683
1898
  {
1684
1899
  const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
1685
1900
 
1901
+ assert(!cdict->matchState.dedicatedDictSearch);
1902
+
1686
1903
  DEBUGLOG(4, "copying dictionary into context");
1687
1904
 
1688
1905
  { unsigned const windowLog = params.cParams.windowLog;
@@ -1703,10 +1920,10 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
1703
1920
  { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
1704
1921
  size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
1705
1922
 
1706
- memcpy(cctx->blockState.matchState.hashTable,
1923
+ ZSTD_memcpy(cctx->blockState.matchState.hashTable,
1707
1924
  cdict->matchState.hashTable,
1708
1925
  hSize * sizeof(U32));
1709
- memcpy(cctx->blockState.matchState.chainTable,
1926
+ ZSTD_memcpy(cctx->blockState.matchState.chainTable,
1710
1927
  cdict->matchState.chainTable,
1711
1928
  chainSize * sizeof(U32));
1712
1929
  }
@@ -1715,7 +1932,7 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
1715
1932
  { int const h3log = cctx->blockState.matchState.hashLog3;
1716
1933
  size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
1717
1934
  assert(cdict->matchState.hashLog3 == 0);
1718
- memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
1935
+ ZSTD_memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
1719
1936
  }
1720
1937
 
1721
1938
  ZSTD_cwksp_mark_tables_clean(&cctx->workspace);
@@ -1729,9 +1946,10 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
1729
1946
  }
1730
1947
 
1731
1948
  cctx->dictID = cdict->dictID;
1949
+ cctx->dictContentSize = cdict->dictContentSize;
1732
1950
 
1733
1951
  /* copy block state */
1734
- memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1952
+ ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1735
1953
 
1736
1954
  return 0;
1737
1955
  }
@@ -1775,7 +1993,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1775
1993
  RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong,
1776
1994
  "Can't copy a ctx that's not in init stage.");
1777
1995
 
1778
- memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
1996
+ ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
1779
1997
  { ZSTD_CCtx_params params = dstCCtx->requestedParams;
1780
1998
  /* Copy only compression parameters related to tables. */
1781
1999
  params.cParams = srcCCtx->appliedParams.cParams;
@@ -1797,13 +2015,13 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1797
2015
  int const h3log = srcCCtx->blockState.matchState.hashLog3;
1798
2016
  size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
1799
2017
 
1800
- memcpy(dstCCtx->blockState.matchState.hashTable,
2018
+ ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable,
1801
2019
  srcCCtx->blockState.matchState.hashTable,
1802
2020
  hSize * sizeof(U32));
1803
- memcpy(dstCCtx->blockState.matchState.chainTable,
2021
+ ZSTD_memcpy(dstCCtx->blockState.matchState.chainTable,
1804
2022
  srcCCtx->blockState.matchState.chainTable,
1805
2023
  chainSize * sizeof(U32));
1806
- memcpy(dstCCtx->blockState.matchState.hashTable3,
2024
+ ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable3,
1807
2025
  srcCCtx->blockState.matchState.hashTable3,
1808
2026
  h3Size * sizeof(U32));
1809
2027
  }
@@ -1819,9 +2037,10 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1819
2037
  dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
1820
2038
  }
1821
2039
  dstCCtx->dictID = srcCCtx->dictID;
2040
+ dstCCtx->dictContentSize = srcCCtx->dictContentSize;
1822
2041
 
1823
2042
  /* copy block state */
1824
- memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
2043
+ ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
1825
2044
 
1826
2045
  return 0;
1827
2046
  }
@@ -1834,7 +2053,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1834
2053
  size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
1835
2054
  {
1836
2055
  ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
1837
- ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
2056
+ ZSTD_buffered_policy_e const zbuff = srcCCtx->bufferedPolicy;
1838
2057
  ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
1839
2058
  if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
1840
2059
  fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
@@ -1861,7 +2080,7 @@ ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerVa
1861
2080
  assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */
1862
2081
  assert(size < (1U<<31)); /* can be casted to int */
1863
2082
 
1864
- #if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
2083
+ #if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
1865
2084
  /* To validate that the table re-use logic is sound, and that we don't
1866
2085
  * access table space that we haven't cleaned, we re-"poison" the table
1867
2086
  * space every time we mark it dirty.
@@ -1958,10 +2177,10 @@ static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams)
1958
2177
  return (cctxParams->targetCBlockSize != 0);
1959
2178
  }
1960
2179
 
1961
- /* ZSTD_compressSequences_internal():
2180
+ /* ZSTD_entropyCompressSequences_internal():
1962
2181
  * actually compresses both literals and sequences */
1963
2182
  MEM_STATIC size_t
1964
- ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
2183
+ ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
1965
2184
  const ZSTD_entropyCTables_t* prevEntropy,
1966
2185
  ZSTD_entropyCTables_t* nextEntropy,
1967
2186
  const ZSTD_CCtx_params* cctxParams,
@@ -1971,7 +2190,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
1971
2190
  {
1972
2191
  const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
1973
2192
  ZSTD_strategy const strategy = cctxParams->cParams.strategy;
1974
- unsigned count[MaxSeq+1];
2193
+ unsigned* count = (unsigned*)entropyWorkspace;
1975
2194
  FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
1976
2195
  FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
1977
2196
  FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
@@ -1987,8 +2206,12 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
1987
2206
  BYTE* seqHead;
1988
2207
  BYTE* lastNCount = NULL;
1989
2208
 
1990
- DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq);
2209
+ entropyWorkspace = count + (MaxSeq + 1);
2210
+ entropyWkspSize -= (MaxSeq + 1) * sizeof(*count);
2211
+
2212
+ DEBUGLOG(4, "ZSTD_entropyCompressSequences_internal (nbSeq=%zu)", nbSeq);
1991
2213
  ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
2214
+ assert(entropyWkspSize >= HUF_WORKSPACE_SIZE);
1992
2215
 
1993
2216
  /* Compress literals */
1994
2217
  { const BYTE* const literals = seqStorePtr->litStart;
@@ -2023,7 +2246,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
2023
2246
  assert(op <= oend);
2024
2247
  if (nbSeq==0) {
2025
2248
  /* Copy the old tables over as if we repeated them */
2026
- memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
2249
+ ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
2027
2250
  return (size_t)(op - ostart);
2028
2251
  }
2029
2252
 
@@ -2148,7 +2371,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
2148
2371
  }
2149
2372
 
2150
2373
  MEM_STATIC size_t
2151
- ZSTD_compressSequences(seqStore_t* seqStorePtr,
2374
+ ZSTD_entropyCompressSequences(seqStore_t* seqStorePtr,
2152
2375
  const ZSTD_entropyCTables_t* prevEntropy,
2153
2376
  ZSTD_entropyCTables_t* nextEntropy,
2154
2377
  const ZSTD_CCtx_params* cctxParams,
@@ -2157,7 +2380,7 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr,
2157
2380
  void* entropyWorkspace, size_t entropyWkspSize,
2158
2381
  int bmi2)
2159
2382
  {
2160
- size_t const cSize = ZSTD_compressSequences_internal(
2383
+ size_t const cSize = ZSTD_entropyCompressSequences_internal(
2161
2384
  seqStorePtr, prevEntropy, nextEntropy, cctxParams,
2162
2385
  dst, dstCapacity,
2163
2386
  entropyWorkspace, entropyWkspSize, bmi2);
@@ -2167,13 +2390,13 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr,
2167
2390
  */
2168
2391
  if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
2169
2392
  return 0; /* block not compressed */
2170
- FORWARD_IF_ERROR(cSize, "ZSTD_compressSequences_internal failed");
2393
+ FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSequences_internal failed");
2171
2394
 
2172
2395
  /* Check compressibility */
2173
2396
  { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
2174
2397
  if (cSize >= maxCSize) return 0; /* block not compressed */
2175
2398
  }
2176
-
2399
+ DEBUGLOG(4, "ZSTD_entropyCompressSequences() cSize: %zu\n", cSize);
2177
2400
  return cSize;
2178
2401
  }
2179
2402
 
@@ -2182,7 +2405,7 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr,
2182
2405
  * assumption : strat is a valid strategy */
2183
2406
  ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
2184
2407
  {
2185
- static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = {
2408
+ static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = {
2186
2409
  { ZSTD_compressBlock_fast /* default for 0 */,
2187
2410
  ZSTD_compressBlock_fast,
2188
2411
  ZSTD_compressBlock_doubleFast,
@@ -2212,7 +2435,17 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo
2212
2435
  ZSTD_compressBlock_btlazy2_dictMatchState,
2213
2436
  ZSTD_compressBlock_btopt_dictMatchState,
2214
2437
  ZSTD_compressBlock_btultra_dictMatchState,
2215
- ZSTD_compressBlock_btultra_dictMatchState }
2438
+ ZSTD_compressBlock_btultra_dictMatchState },
2439
+ { NULL /* default for 0 */,
2440
+ NULL,
2441
+ NULL,
2442
+ ZSTD_compressBlock_greedy_dedicatedDictSearch,
2443
+ ZSTD_compressBlock_lazy_dedicatedDictSearch,
2444
+ ZSTD_compressBlock_lazy2_dedicatedDictSearch,
2445
+ NULL,
2446
+ NULL,
2447
+ NULL,
2448
+ NULL }
2216
2449
  };
2217
2450
  ZSTD_blockCompressor selectedCompressor;
2218
2451
  ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
@@ -2226,7 +2459,7 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo
2226
2459
  static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
2227
2460
  const BYTE* anchor, size_t lastLLSize)
2228
2461
  {
2229
- memcpy(seqStorePtr->lit, anchor, lastLLSize);
2462
+ ZSTD_memcpy(seqStorePtr->lit, anchor, lastLLSize);
2230
2463
  seqStorePtr->lit += lastLLSize;
2231
2464
  }
2232
2465
 
@@ -2247,7 +2480,11 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2247
2480
  /* Assert that we have correctly flushed the ctx params into the ms's copy */
2248
2481
  ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams);
2249
2482
  if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
2250
- ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
2483
+ if (zc->appliedParams.cParams.strategy >= ZSTD_btopt) {
2484
+ ZSTD_ldm_skipRawSeqStoreBytes(&zc->externSeqStore, srcSize);
2485
+ } else {
2486
+ ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
2487
+ }
2251
2488
  return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */
2252
2489
  }
2253
2490
  ZSTD_resetSeqStore(&(zc->seqStore));
@@ -2263,10 +2500,10 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2263
2500
  /* limited update after a very long match */
2264
2501
  { const BYTE* const base = ms->window.base;
2265
2502
  const BYTE* const istart = (const BYTE*)src;
2266
- const U32 current = (U32)(istart-base);
2503
+ const U32 curr = (U32)(istart-base);
2267
2504
  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));
2505
+ if (curr > ms->nextToUpdate + 384)
2506
+ ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384));
2270
2507
  }
2271
2508
 
2272
2509
  /* select and store sequences */
@@ -2286,7 +2523,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2286
2523
  src, srcSize);
2287
2524
  assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
2288
2525
  } else if (zc->appliedParams.ldmParams.enableLdm) {
2289
- rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
2526
+ rawSeqStore_t ldmSeqStore = kNullRawSeqStore;
2290
2527
 
2291
2528
  ldmSeqStore.seq = zc->ldmSequences;
2292
2529
  ldmSeqStore.capacity = zc->maxNbLdmSequences;
@@ -2303,6 +2540,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2303
2540
  assert(ldmSeqStore.pos == ldmSeqStore.size);
2304
2541
  } else { /* not long range mode */
2305
2542
  ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
2543
+ ms->ldmSeqStore = NULL;
2306
2544
  lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
2307
2545
  }
2308
2546
  { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
@@ -2314,17 +2552,25 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2314
2552
  static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
2315
2553
  {
2316
2554
  const seqStore_t* seqStore = ZSTD_getSeqStore(zc);
2317
- const seqDef* seqs = seqStore->sequencesStart;
2318
- size_t seqsSize = seqStore->sequences - seqs;
2555
+ const seqDef* seqStoreSeqs = seqStore->sequencesStart;
2556
+ size_t seqStoreSeqSize = seqStore->sequences - seqStoreSeqs;
2557
+ size_t seqStoreLiteralsSize = (size_t)(seqStore->lit - seqStore->litStart);
2558
+ size_t literalsRead = 0;
2559
+ size_t lastLLSize;
2319
2560
 
2320
2561
  ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex];
2321
- size_t i; size_t position; int repIdx;
2562
+ size_t i;
2563
+ repcodes_t updatedRepcodes;
2322
2564
 
2323
2565
  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;
2566
+ /* Ensure we have enough space for last literals "sequence" */
2567
+ assert(zc->seqCollector.maxSequences >= seqStoreSeqSize + 1);
2568
+ ZSTD_memcpy(updatedRepcodes.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t));
2569
+ for (i = 0; i < seqStoreSeqSize; ++i) {
2570
+ U32 rawOffset = seqStoreSeqs[i].offset - ZSTD_REP_NUM;
2571
+ outSeqs[i].litLength = seqStoreSeqs[i].litLength;
2572
+ outSeqs[i].matchLength = seqStoreSeqs[i].matchLength + MINMATCH;
2573
+ outSeqs[i].rep = 0;
2328
2574
 
2329
2575
  if (i == seqStore->longLengthPos) {
2330
2576
  if (seqStore->longLengthID == 1) {
@@ -2334,39 +2580,44 @@ static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
2334
2580
  }
2335
2581
  }
2336
2582
 
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;
2583
+ if (seqStoreSeqs[i].offset <= ZSTD_REP_NUM) {
2584
+ /* Derive the correct offset corresponding to a repcode */
2585
+ outSeqs[i].rep = seqStoreSeqs[i].offset;
2586
+ if (outSeqs[i].litLength != 0) {
2587
+ rawOffset = updatedRepcodes.rep[outSeqs[i].rep - 1];
2588
+ } else {
2589
+ if (outSeqs[i].rep == 3) {
2590
+ rawOffset = updatedRepcodes.rep[0] - 1;
2344
2591
  } else {
2345
- repIdx = (unsigned int)i - 1;
2592
+ rawOffset = updatedRepcodes.rep[outSeqs[i].rep];
2346
2593
  }
2347
- ++outSeqs[i].rep;
2348
2594
  }
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
2595
  }
2357
-
2358
- position += outSeqs[i].litLength;
2359
- outSeqs[i].matchPos = (unsigned int)position;
2360
- position += outSeqs[i].matchLength;
2596
+ outSeqs[i].offset = rawOffset;
2597
+ /* seqStoreSeqs[i].offset == offCode+1, and ZSTD_updateRep() expects offCode
2598
+ so we provide seqStoreSeqs[i].offset - 1 */
2599
+ updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep,
2600
+ seqStoreSeqs[i].offset - 1,
2601
+ seqStoreSeqs[i].litLength == 0);
2602
+ literalsRead += outSeqs[i].litLength;
2361
2603
  }
2362
- zc->seqCollector.seqIndex += seqsSize;
2604
+ /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0.
2605
+ * If there are no last literals, then we'll emit (of: 0, ml: 0, ll: 0), which is a marker
2606
+ * for the block boundary, according to the API.
2607
+ */
2608
+ assert(seqStoreLiteralsSize >= literalsRead);
2609
+ lastLLSize = seqStoreLiteralsSize - literalsRead;
2610
+ outSeqs[i].litLength = (U32)lastLLSize;
2611
+ outSeqs[i].matchLength = outSeqs[i].offset = outSeqs[i].rep = 0;
2612
+ seqStoreSeqSize++;
2613
+ zc->seqCollector.seqIndex += seqStoreSeqSize;
2363
2614
  }
2364
2615
 
2365
- size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
2366
- size_t outSeqsSize, const void* src, size_t srcSize)
2616
+ size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
2617
+ size_t outSeqsSize, const void* src, size_t srcSize)
2367
2618
  {
2368
2619
  const size_t dstCapacity = ZSTD_compressBound(srcSize);
2369
- void* dst = ZSTD_malloc(dstCapacity, ZSTD_defaultCMem);
2620
+ void* dst = ZSTD_customMalloc(dstCapacity, ZSTD_defaultCMem);
2370
2621
  SeqCollector seqCollector;
2371
2622
 
2372
2623
  RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!");
@@ -2378,16 +2629,47 @@ size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
2378
2629
  zc->seqCollector = seqCollector;
2379
2630
 
2380
2631
  ZSTD_compress2(zc, dst, dstCapacity, src, srcSize);
2381
- ZSTD_free(dst, ZSTD_defaultCMem);
2632
+ ZSTD_customFree(dst, ZSTD_defaultCMem);
2382
2633
  return zc->seqCollector.seqIndex;
2383
2634
  }
2384
2635
 
2385
- /* Returns true if the given block is a RLE block */
2386
- static int ZSTD_isRLE(const BYTE *ip, size_t length) {
2636
+ size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize) {
2637
+ size_t in = 0;
2638
+ size_t out = 0;
2639
+ for (; in < seqsSize; ++in) {
2640
+ if (sequences[in].offset == 0 && sequences[in].matchLength == 0) {
2641
+ if (in != seqsSize - 1) {
2642
+ sequences[in+1].litLength += sequences[in].litLength;
2643
+ }
2644
+ } else {
2645
+ sequences[out] = sequences[in];
2646
+ ++out;
2647
+ }
2648
+ }
2649
+ return out;
2650
+ }
2651
+
2652
+ /* Unrolled loop to read four size_ts of input at a time. Returns 1 if is RLE, 0 if not. */
2653
+ static int ZSTD_isRLE(const BYTE* src, size_t length) {
2654
+ const BYTE* ip = src;
2655
+ const BYTE value = ip[0];
2656
+ const size_t valueST = (size_t)((U64)value * 0x0101010101010101ULL);
2657
+ const size_t unrollSize = sizeof(size_t) * 4;
2658
+ const size_t unrollMask = unrollSize - 1;
2659
+ const size_t prefixLength = length & unrollMask;
2387
2660
  size_t i;
2388
- if (length < 2) return 1;
2389
- for (i = 1; i < length; ++i) {
2390
- if (ip[0] != ip[i]) return 0;
2661
+ size_t u;
2662
+ if (length == 1) return 1;
2663
+ /* Check if prefix is RLE first before using unrolled loop */
2664
+ if (prefixLength && ZSTD_count(ip+1, ip, ip+prefixLength) != prefixLength-1) {
2665
+ return 0;
2666
+ }
2667
+ for (i = prefixLength; i != length; i += unrollSize) {
2668
+ for (u = 0; u < unrollSize; u += sizeof(size_t)) {
2669
+ if (MEM_readST(ip + i + u) != valueST) {
2670
+ return 0;
2671
+ }
2672
+ }
2391
2673
  }
2392
2674
  return 1;
2393
2675
  }
@@ -2434,18 +2716,25 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
2434
2716
 
2435
2717
  if (zc->seqCollector.collectSequences) {
2436
2718
  ZSTD_copyBlockSequences(zc);
2719
+ ZSTD_confirmRepcodesAndEntropyTables(zc);
2437
2720
  return 0;
2438
2721
  }
2439
2722
 
2440
2723
  /* encode sequences and literals */
2441
- cSize = ZSTD_compressSequences(&zc->seqStore,
2724
+ cSize = ZSTD_entropyCompressSequences(&zc->seqStore,
2442
2725
  &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
2443
2726
  &zc->appliedParams,
2444
2727
  dst, dstCapacity,
2445
2728
  srcSize,
2446
- zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
2729
+ zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
2447
2730
  zc->bmi2);
2448
2731
 
2732
+ if (zc->seqCollector.collectSequences) {
2733
+ ZSTD_copyBlockSequences(zc);
2734
+ return 0;
2735
+ }
2736
+
2737
+
2449
2738
  if (frame &&
2450
2739
  /* We don't want to emit our first block as a RLE even if it qualifies because
2451
2740
  * doing so will cause the decoder (cli only) to throw a "should consume all input error."
@@ -2593,7 +2882,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
2593
2882
 
2594
2883
  assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX);
2595
2884
 
2596
- DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
2885
+ DEBUGLOG(4, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
2597
2886
  if (cctx->appliedParams.fParams.checksumFlag && srcSize)
2598
2887
  XXH64_update(&cctx->xxhState, src, srcSize);
2599
2888
 
@@ -2673,7 +2962,6 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
2673
2962
  "dst buf is too small to fit worst-case frame header size.");
2674
2963
  DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
2675
2964
  !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode);
2676
-
2677
2965
  if (params->format == ZSTD_f_zstd1) {
2678
2966
  MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
2679
2967
  pos = 4;
@@ -2699,6 +2987,26 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
2699
2987
  return pos;
2700
2988
  }
2701
2989
 
2990
+ /* ZSTD_writeSkippableFrame_advanced() :
2991
+ * Writes out a skippable frame with the specified magic number variant (16 are supported),
2992
+ * from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15, and the desired source data.
2993
+ *
2994
+ * Returns the total number of bytes written, or a ZSTD error code.
2995
+ */
2996
+ size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity,
2997
+ const void* src, size_t srcSize, unsigned magicVariant) {
2998
+ BYTE* op = (BYTE*)dst;
2999
+ RETURN_ERROR_IF(dstCapacity < srcSize + ZSTD_SKIPPABLEHEADERSIZE /* Skippable frame overhead */,
3000
+ dstSize_tooSmall, "Not enough room for skippable frame");
3001
+ RETURN_ERROR_IF(srcSize > (unsigned)0xFFFFFFFF, srcSize_wrong, "Src size too large for skippable frame");
3002
+ RETURN_ERROR_IF(magicVariant > 15, parameter_outOfBound, "Skippable frame magic number variant not supported");
3003
+
3004
+ MEM_writeLE32(op, (U32)(ZSTD_MAGIC_SKIPPABLE_START + magicVariant));
3005
+ MEM_writeLE32(op+4, (U32)srcSize);
3006
+ ZSTD_memcpy(op+8, src, srcSize);
3007
+ return srcSize + ZSTD_SKIPPABLEHEADERSIZE;
3008
+ }
3009
+
2702
3010
  /* ZSTD_writeLastEmptyBlock() :
2703
3011
  * output an empty Block with end-of-frame mark to complete a frame
2704
3012
  * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
@@ -2725,6 +3033,7 @@ size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSe
2725
3033
  cctx->externSeqStore.size = nbSeq;
2726
3034
  cctx->externSeqStore.capacity = nbSeq;
2727
3035
  cctx->externSeqStore.pos = 0;
3036
+ cctx->externSeqStore.posInSequence = 0;
2728
3037
  return 0;
2729
3038
  }
2730
3039
 
@@ -2862,8 +3171,12 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
2862
3171
  case ZSTD_greedy:
2863
3172
  case ZSTD_lazy:
2864
3173
  case ZSTD_lazy2:
2865
- if (chunk >= HASH_READ_SIZE)
3174
+ if (chunk >= HASH_READ_SIZE && ms->dedicatedDictSearch) {
3175
+ assert(chunk == remaining); /* must load everything in one go */
3176
+ ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, ichunk-HASH_READ_SIZE);
3177
+ } else if (chunk >= HASH_READ_SIZE) {
2866
3178
  ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE);
3179
+ }
2867
3180
  break;
2868
3181
 
2869
3182
  case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
@@ -2887,22 +3200,28 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
2887
3200
 
2888
3201
 
2889
3202
  /* 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) {
3203
+ * when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check
3204
+ * and only dictionaries with 100% valid symbols can be assumed valid.
3205
+ */
3206
+ static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue)
3207
+ {
2894
3208
  U32 s;
2895
- RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted, "dict fse tables don't have all symbols");
3209
+ if (dictMaxSymbolValue < maxSymbolValue) {
3210
+ return FSE_repeat_check;
3211
+ }
2896
3212
  for (s = 0; s <= maxSymbolValue; ++s) {
2897
- RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted, "dict fse tables don't have all symbols");
3213
+ if (normalizedCounter[s] == 0) {
3214
+ return FSE_repeat_check;
3215
+ }
2898
3216
  }
2899
- return 0;
3217
+ return FSE_repeat_valid;
2900
3218
  }
2901
3219
 
2902
3220
  size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2903
- short* offcodeNCount, unsigned* offcodeMaxValue,
2904
3221
  const void* const dict, size_t dictSize)
2905
3222
  {
3223
+ short offcodeNCount[MaxOff+1];
3224
+ unsigned offcodeMaxValue = MaxOff;
2906
3225
  const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */
2907
3226
  const BYTE* const dictEnd = dictPtr + dictSize;
2908
3227
  dictPtr += 8;
@@ -2924,16 +3243,16 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2924
3243
  }
2925
3244
 
2926
3245
  { unsigned offcodeLog;
2927
- size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
3246
+ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
2928
3247
  RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
2929
3248
  RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
2930
- /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
2931
3249
  /* fill all offset symbols to avoid garbage at end of table */
2932
3250
  RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
2933
3251
  bs->entropy.fse.offcodeCTable,
2934
3252
  offcodeNCount, MaxOff, offcodeLog,
2935
3253
  workspace, HUF_WORKSPACE_SIZE)),
2936
3254
  dictionary_corrupted, "");
3255
+ /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
2937
3256
  dictPtr += offcodeHeaderSize;
2938
3257
  }
2939
3258
 
@@ -2942,13 +3261,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2942
3261
  size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
2943
3262
  RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
2944
3263
  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
3264
  RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
2948
3265
  bs->entropy.fse.matchlengthCTable,
2949
3266
  matchlengthNCount, matchlengthMaxValue, matchlengthLog,
2950
3267
  workspace, HUF_WORKSPACE_SIZE)),
2951
3268
  dictionary_corrupted, "");
3269
+ bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML);
2952
3270
  dictPtr += matchlengthHeaderSize;
2953
3271
  }
2954
3272
 
@@ -2957,13 +3275,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2957
3275
  size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
2958
3276
  RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
2959
3277
  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
3278
  RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
2963
3279
  bs->entropy.fse.litlengthCTable,
2964
3280
  litlengthNCount, litlengthMaxValue, litlengthLog,
2965
3281
  workspace, HUF_WORKSPACE_SIZE)),
2966
3282
  dictionary_corrupted, "");
3283
+ bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL);
2967
3284
  dictPtr += litlengthHeaderSize;
2968
3285
  }
2969
3286
 
@@ -2973,12 +3290,28 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2973
3290
  bs->rep[2] = MEM_readLE32(dictPtr+8);
2974
3291
  dictPtr += 12;
2975
3292
 
3293
+ { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3294
+ U32 offcodeMax = MaxOff;
3295
+ if (dictContentSize <= ((U32)-1) - 128 KB) {
3296
+ U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
3297
+ offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
3298
+ }
3299
+ /* All offset values <= dictContentSize + 128 KB must be representable for a valid table */
3300
+ bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff));
3301
+
3302
+ /* All repCodes must be <= dictContentSize and != 0 */
3303
+ { U32 u;
3304
+ for (u=0; u<3; u++) {
3305
+ RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, "");
3306
+ RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, "");
3307
+ } } }
3308
+
2976
3309
  return dictPtr - (const BYTE*)dict;
2977
3310
  }
2978
3311
 
2979
3312
  /* Dictionary format :
2980
3313
  * See :
2981
- * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
3314
+ * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#dictionary-format
2982
3315
  */
2983
3316
  /*! ZSTD_loadZstdDictionary() :
2984
3317
  * @return : dictID, or an error code
@@ -2995,8 +3328,6 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
2995
3328
  {
2996
3329
  const BYTE* dictPtr = (const BYTE*)dict;
2997
3330
  const BYTE* const dictEnd = dictPtr + dictSize;
2998
- short offcodeNCount[MaxOff+1];
2999
- unsigned offcodeMaxValue = MaxOff;
3000
3331
  size_t dictID;
3001
3332
  size_t eSize;
3002
3333
 
@@ -3005,32 +3336,16 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
3005
3336
  assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
3006
3337
 
3007
3338
  dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ );
3008
- eSize = ZSTD_loadCEntropy(bs, workspace, offcodeNCount, &offcodeMaxValue, dict, dictSize);
3339
+ eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize);
3009
3340
  FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed");
3010
3341
  dictPtr += eSize;
3011
3342
 
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;
3343
+ {
3344
+ size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3030
3345
  FORWARD_IF_ERROR(ZSTD_loadDictionaryContent(
3031
3346
  ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), "");
3032
- return dictID;
3033
3347
  }
3348
+ return dictID;
3034
3349
  }
3035
3350
 
3036
3351
  /** ZSTD_compress_insertDictionary() :
@@ -3074,7 +3389,7 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
3074
3389
  }
3075
3390
 
3076
3391
  #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB)
3077
- #define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6)
3392
+ #define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6ULL)
3078
3393
 
3079
3394
  /*! ZSTD_compressBegin_internal() :
3080
3395
  * @return : 0, or an error code */
@@ -3086,6 +3401,9 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
3086
3401
  const ZSTD_CCtx_params* params, U64 pledgedSrcSize,
3087
3402
  ZSTD_buffered_policy_e zbuff)
3088
3403
  {
3404
+ #if ZSTD_TRACE
3405
+ cctx->traceCtx = ZSTD_trace_compress_begin(cctx);
3406
+ #endif
3089
3407
  DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog);
3090
3408
  /* params are supposed to be fully validated at this point */
3091
3409
  assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
@@ -3106,7 +3424,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
3106
3424
  ZSTD_compress_insertDictionary(
3107
3425
  cctx->blockState.prevCBlock, &cctx->blockState.matchState,
3108
3426
  &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent,
3109
- cdict->dictContentSize, dictContentType, dtlm,
3427
+ cdict->dictContentSize, cdict->dictContentType, dtlm,
3110
3428
  cctx->entropyWorkspace)
3111
3429
  : ZSTD_compress_insertDictionary(
3112
3430
  cctx->blockState.prevCBlock, &cctx->blockState.matchState,
@@ -3115,6 +3433,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
3115
3433
  FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
3116
3434
  assert(dictID <= UINT_MAX);
3117
3435
  cctx->dictID = (U32)dictID;
3436
+ cctx->dictContentSize = cdict ? cdict->dictContentSize : dictSize;
3118
3437
  }
3119
3438
  return 0;
3120
3439
  }
@@ -3143,8 +3462,8 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
3143
3462
  const void* dict, size_t dictSize,
3144
3463
  ZSTD_parameters params, unsigned long long pledgedSrcSize)
3145
3464
  {
3146
- ZSTD_CCtx_params const cctxParams =
3147
- ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
3465
+ ZSTD_CCtx_params cctxParams;
3466
+ ZSTD_CCtxParams_init_internal(&cctxParams, &params, ZSTD_NO_CLEVEL);
3148
3467
  return ZSTD_compressBegin_advanced_internal(cctx,
3149
3468
  dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast,
3150
3469
  NULL /*cdict*/,
@@ -3153,9 +3472,11 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
3153
3472
 
3154
3473
  size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
3155
3474
  {
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);
3475
+ ZSTD_CCtx_params cctxParams;
3476
+ {
3477
+ ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict);
3478
+ ZSTD_CCtxParams_init_internal(&cctxParams, &params, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel);
3479
+ }
3159
3480
  DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize);
3160
3481
  return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
3161
3482
  &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
@@ -3209,6 +3530,30 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
3209
3530
  return op-ostart;
3210
3531
  }
3211
3532
 
3533
+ void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize)
3534
+ {
3535
+ #if ZSTD_TRACE
3536
+ if (cctx->traceCtx) {
3537
+ int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0;
3538
+ ZSTD_Trace trace;
3539
+ ZSTD_memset(&trace, 0, sizeof(trace));
3540
+ trace.version = ZSTD_VERSION_NUMBER;
3541
+ trace.streaming = streaming;
3542
+ trace.dictionaryID = cctx->dictID;
3543
+ trace.dictionarySize = cctx->dictContentSize;
3544
+ trace.uncompressedSize = cctx->consumedSrcSize;
3545
+ trace.compressedSize = cctx->producedCSize + extraCSize;
3546
+ trace.params = &cctx->appliedParams;
3547
+ trace.cctx = cctx;
3548
+ ZSTD_trace_compress_end(cctx->traceCtx, &trace);
3549
+ }
3550
+ cctx->traceCtx = 0;
3551
+ #else
3552
+ (void)cctx;
3553
+ (void)extraCSize;
3554
+ #endif
3555
+ }
3556
+
3212
3557
  size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
3213
3558
  void* dst, size_t dstCapacity,
3214
3559
  const void* src, size_t srcSize)
@@ -3231,39 +3576,25 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
3231
3576
  (unsigned)cctx->pledgedSrcSizePlusOne-1,
3232
3577
  (unsigned)cctx->consumedSrcSize);
3233
3578
  }
3579
+ ZSTD_CCtx_trace(cctx, endResult);
3234
3580
  return cSize + endResult;
3235
3581
  }
3236
3582
 
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
3583
  size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
3255
3584
  void* dst, size_t dstCapacity,
3256
3585
  const void* src, size_t srcSize,
3257
3586
  const void* dict,size_t dictSize,
3258
3587
  ZSTD_parameters params)
3259
3588
  {
3589
+ ZSTD_CCtx_params cctxParams;
3260
3590
  DEBUGLOG(4, "ZSTD_compress_advanced");
3261
3591
  FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), "");
3262
- return ZSTD_compress_internal(cctx,
3263
- dst, dstCapacity,
3264
- src, srcSize,
3265
- dict, dictSize,
3266
- &params);
3592
+ ZSTD_CCtxParams_init_internal(&cctxParams, &params, ZSTD_NO_CLEVEL);
3593
+ return ZSTD_compress_advanced_internal(cctx,
3594
+ dst, dstCapacity,
3595
+ src, srcSize,
3596
+ dict, dictSize,
3597
+ &cctxParams);
3267
3598
  }
3268
3599
 
3269
3600
  /* Internal */
@@ -3287,10 +3618,13 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
3287
3618
  const void* dict, size_t dictSize,
3288
3619
  int compressionLevel)
3289
3620
  {
3290
- ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0);
3291
- ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
3621
+ ZSTD_CCtx_params cctxParams;
3622
+ {
3623
+ ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict);
3624
+ assert(params.fParams.contentSizeFlag == 1);
3625
+ ZSTD_CCtxParams_init_internal(&cctxParams, &params, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel);
3626
+ }
3292
3627
  DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize);
3293
- assert(params.fParams.contentSizeFlag == 1);
3294
3628
  return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams);
3295
3629
  }
3296
3630
 
@@ -3309,10 +3643,17 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity,
3309
3643
  int compressionLevel)
3310
3644
  {
3311
3645
  size_t result;
3646
+ #if ZSTD_COMPRESS_HEAPMODE
3647
+ ZSTD_CCtx* cctx = ZSTD_createCCtx();
3648
+ RETURN_ERROR_IF(!cctx, memory_allocation, "ZSTD_createCCtx failed");
3649
+ result = ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel);
3650
+ ZSTD_freeCCtx(cctx);
3651
+ #else
3312
3652
  ZSTD_CCtx ctxBody;
3313
3653
  ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem);
3314
3654
  result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
3315
3655
  ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */
3656
+ #endif
3316
3657
  return result;
3317
3658
  }
3318
3659
 
@@ -3335,7 +3676,7 @@ size_t ZSTD_estimateCDictSize_advanced(
3335
3676
 
3336
3677
  size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
3337
3678
  {
3338
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3679
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3339
3680
  return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
3340
3681
  }
3341
3682
 
@@ -3353,20 +3694,25 @@ static size_t ZSTD_initCDict_internal(
3353
3694
  const void* dictBuffer, size_t dictSize,
3354
3695
  ZSTD_dictLoadMethod_e dictLoadMethod,
3355
3696
  ZSTD_dictContentType_e dictContentType,
3356
- ZSTD_compressionParameters cParams)
3697
+ ZSTD_CCtx_params params)
3357
3698
  {
3358
3699
  DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType);
3359
- assert(!ZSTD_checkCParams(cParams));
3360
- cdict->matchState.cParams = cParams;
3700
+ assert(!ZSTD_checkCParams(params.cParams));
3701
+ cdict->matchState.cParams = params.cParams;
3702
+ cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch;
3703
+ if (cdict->matchState.dedicatedDictSearch && dictSize > ZSTD_CHUNKSIZE_MAX) {
3704
+ cdict->matchState.dedicatedDictSearch = 0;
3705
+ }
3361
3706
  if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
3362
3707
  cdict->dictContent = dictBuffer;
3363
3708
  } else {
3364
3709
  void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*)));
3365
3710
  RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!");
3366
3711
  cdict->dictContent = internalBuffer;
3367
- memcpy(internalBuffer, dictBuffer, dictSize);
3712
+ ZSTD_memcpy(internalBuffer, dictBuffer, dictSize);
3368
3713
  }
3369
3714
  cdict->dictContentSize = dictSize;
3715
+ cdict->dictContentType = dictContentType;
3370
3716
 
3371
3717
  cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE);
3372
3718
 
@@ -3376,18 +3722,15 @@ static size_t ZSTD_initCDict_internal(
3376
3722
  FORWARD_IF_ERROR(ZSTD_reset_matchState(
3377
3723
  &cdict->matchState,
3378
3724
  &cdict->workspace,
3379
- &cParams,
3725
+ &params.cParams,
3380
3726
  ZSTDcrp_makeClean,
3381
3727
  ZSTDirp_reset,
3382
3728
  ZSTD_resetTarget_CDict), "");
3383
3729
  /* (Maybe) load the dictionary
3384
3730
  * Skips loading the dictionary if it is < 8 bytes.
3385
3731
  */
3386
- { ZSTD_CCtx_params params;
3387
- memset(&params, 0, sizeof(params));
3388
- params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
3732
+ { params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
3389
3733
  params.fParams.contentSizeFlag = 1;
3390
- params.cParams = cParams;
3391
3734
  { size_t const dictID = ZSTD_compress_insertDictionary(
3392
3735
  &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace,
3393
3736
  &params, cdict->dictContent, cdict->dictContentSize,
@@ -3401,13 +3744,11 @@ static size_t ZSTD_initCDict_internal(
3401
3744
  return 0;
3402
3745
  }
3403
3746
 
3404
- ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3747
+ static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize,
3405
3748
  ZSTD_dictLoadMethod_e dictLoadMethod,
3406
- ZSTD_dictContentType_e dictContentType,
3407
3749
  ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
3408
3750
  {
3409
- DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType);
3410
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
3751
+ if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
3411
3752
 
3412
3753
  { size_t const workspaceSize =
3413
3754
  ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) +
@@ -3415,52 +3756,111 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3415
3756
  ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
3416
3757
  (dictLoadMethod == ZSTD_dlm_byRef ? 0
3417
3758
  : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))));
3418
- void* const workspace = ZSTD_malloc(workspaceSize, customMem);
3759
+ void* const workspace = ZSTD_customMalloc(workspaceSize, customMem);
3419
3760
  ZSTD_cwksp ws;
3420
3761
  ZSTD_CDict* cdict;
3421
3762
 
3422
3763
  if (!workspace) {
3423
- ZSTD_free(workspace, customMem);
3764
+ ZSTD_customFree(workspace, customMem);
3424
3765
  return NULL;
3425
3766
  }
3426
3767
 
3427
- ZSTD_cwksp_init(&ws, workspace, workspaceSize);
3768
+ ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_dynamic_alloc);
3428
3769
 
3429
3770
  cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
3430
3771
  assert(cdict != NULL);
3431
3772
  ZSTD_cwksp_move(&cdict->workspace, &ws);
3432
3773
  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
- }
3774
+ cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */
3442
3775
 
3443
3776
  return cdict;
3444
3777
  }
3445
3778
  }
3446
3779
 
3780
+ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3781
+ ZSTD_dictLoadMethod_e dictLoadMethod,
3782
+ ZSTD_dictContentType_e dictContentType,
3783
+ ZSTD_compressionParameters cParams,
3784
+ ZSTD_customMem customMem)
3785
+ {
3786
+ ZSTD_CCtx_params cctxParams;
3787
+ ZSTD_memset(&cctxParams, 0, sizeof(cctxParams));
3788
+ ZSTD_CCtxParams_init(&cctxParams, 0);
3789
+ cctxParams.cParams = cParams;
3790
+ cctxParams.customMem = customMem;
3791
+ return ZSTD_createCDict_advanced2(
3792
+ dictBuffer, dictSize,
3793
+ dictLoadMethod, dictContentType,
3794
+ &cctxParams, customMem);
3795
+ }
3796
+
3797
+ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced2(
3798
+ const void* dict, size_t dictSize,
3799
+ ZSTD_dictLoadMethod_e dictLoadMethod,
3800
+ ZSTD_dictContentType_e dictContentType,
3801
+ const ZSTD_CCtx_params* originalCctxParams,
3802
+ ZSTD_customMem customMem)
3803
+ {
3804
+ ZSTD_CCtx_params cctxParams = *originalCctxParams;
3805
+ ZSTD_compressionParameters cParams;
3806
+ ZSTD_CDict* cdict;
3807
+
3808
+ DEBUGLOG(3, "ZSTD_createCDict_advanced2, mode %u", (unsigned)dictContentType);
3809
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
3810
+
3811
+ if (cctxParams.enableDedicatedDictSearch) {
3812
+ cParams = ZSTD_dedicatedDictSearch_getCParams(
3813
+ cctxParams.compressionLevel, dictSize);
3814
+ ZSTD_overrideCParams(&cParams, &cctxParams.cParams);
3815
+ } else {
3816
+ cParams = ZSTD_getCParamsFromCCtxParams(
3817
+ &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3818
+ }
3819
+
3820
+ if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) {
3821
+ /* Fall back to non-DDSS params */
3822
+ cctxParams.enableDedicatedDictSearch = 0;
3823
+ cParams = ZSTD_getCParamsFromCCtxParams(
3824
+ &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3825
+ }
3826
+
3827
+ cctxParams.cParams = cParams;
3828
+
3829
+ cdict = ZSTD_createCDict_advanced_internal(dictSize,
3830
+ dictLoadMethod, cctxParams.cParams,
3831
+ customMem);
3832
+
3833
+ if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3834
+ dict, dictSize,
3835
+ dictLoadMethod, dictContentType,
3836
+ cctxParams) )) {
3837
+ ZSTD_freeCDict(cdict);
3838
+ return NULL;
3839
+ }
3840
+
3841
+ return cdict;
3842
+ }
3843
+
3447
3844
  ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3448
3845
  {
3449
- ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3450
- ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize,
3846
+ ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3847
+ ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize,
3451
3848
  ZSTD_dlm_byCopy, ZSTD_dct_auto,
3452
3849
  cParams, ZSTD_defaultCMem);
3453
3850
  if (cdict)
3454
- cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
3851
+ cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
3455
3852
  return cdict;
3456
3853
  }
3457
3854
 
3458
3855
  ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3459
3856
  {
3460
- ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3461
- return ZSTD_createCDict_advanced(dict, dictSize,
3857
+ ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3858
+ ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize,
3462
3859
  ZSTD_dlm_byRef, ZSTD_dct_auto,
3463
3860
  cParams, ZSTD_defaultCMem);
3861
+ if (cdict)
3862
+ cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
3863
+ return cdict;
3464
3864
  }
3465
3865
 
3466
3866
  size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
@@ -3470,7 +3870,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3470
3870
  int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict);
3471
3871
  ZSTD_cwksp_free(&cdict->workspace, cMem);
3472
3872
  if (!cdictInWorkspace) {
3473
- ZSTD_free(cdict, cMem);
3873
+ ZSTD_customFree(cdict, cMem);
3474
3874
  }
3475
3875
  return 0;
3476
3876
  }
@@ -3503,12 +3903,13 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
3503
3903
  + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
3504
3904
  + matchStateSize;
3505
3905
  ZSTD_CDict* cdict;
3906
+ ZSTD_CCtx_params params;
3506
3907
 
3507
3908
  if ((size_t)workspace & 7) return NULL; /* 8-aligned */
3508
3909
 
3509
3910
  {
3510
3911
  ZSTD_cwksp ws;
3511
- ZSTD_cwksp_init(&ws, workspace, workspaceSize);
3912
+ ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc);
3512
3913
  cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
3513
3914
  if (cdict == NULL) return NULL;
3514
3915
  ZSTD_cwksp_move(&cdict->workspace, &ws);
@@ -3518,10 +3919,13 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
3518
3919
  (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize));
3519
3920
  if (workspaceSize < neededSize) return NULL;
3520
3921
 
3922
+ ZSTD_CCtxParams_init(&params, 0);
3923
+ params.cParams = cParams;
3924
+
3521
3925
  if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3522
3926
  dict, dictSize,
3523
3927
  dictLoadMethod, dictContentType,
3524
- cParams) ))
3928
+ params) ))
3525
3929
  return NULL;
3526
3930
 
3527
3931
  return cdict;
@@ -3533,40 +3937,54 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
3533
3937
  return cdict->matchState.cParams;
3534
3938
  }
3535
3939
 
3940
+ /*! ZSTD_getDictID_fromCDict() :
3941
+ * Provides the dictID of the dictionary loaded into `cdict`.
3942
+ * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
3943
+ * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
3944
+ unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict)
3945
+ {
3946
+ if (cdict==NULL) return 0;
3947
+ return cdict->dictID;
3948
+ }
3949
+
3950
+
3536
3951
  /* ZSTD_compressBegin_usingCDict_advanced() :
3537
3952
  * cdict must be != NULL */
3538
3953
  size_t ZSTD_compressBegin_usingCDict_advanced(
3539
3954
  ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3540
3955
  ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
3541
3956
  {
3957
+ ZSTD_CCtx_params cctxParams;
3542
3958
  DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
3543
3959
  RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!");
3544
- { ZSTD_CCtx_params params = cctx->requestedParams;
3960
+ /* Initialize the cctxParams from the cdict */
3961
+ {
3962
+ ZSTD_parameters params;
3963
+ params.fParams = fParams;
3545
3964
  params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
3546
3965
  || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
3547
3966
  || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
3548
- || cdict->compressionLevel == 0 )
3549
- && (params.attachDictPref != ZSTD_dictForceLoad) ?
3967
+ || cdict->compressionLevel == 0 ) ?
3550
3968
  ZSTD_getCParamsFromCDict(cdict)
3551
3969
  : ZSTD_getCParams(cdict->compressionLevel,
3552
3970
  pledgedSrcSize,
3553
3971
  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);
3972
+ ZSTD_CCtxParams_init_internal(&cctxParams, &params, cdict->compressionLevel);
3569
3973
  }
3974
+ /* Increase window log to fit the entire dictionary and source if the
3975
+ * source size is known. Limit the increase to 19, which is the
3976
+ * window log for compression level 1 with the largest source size.
3977
+ */
3978
+ if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
3979
+ U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
3980
+ U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
3981
+ cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog);
3982
+ }
3983
+ return ZSTD_compressBegin_internal(cctx,
3984
+ NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
3985
+ cdict,
3986
+ &cctxParams, pledgedSrcSize,
3987
+ ZSTDb_not_buffered);
3570
3988
  }
3571
3989
 
3572
3990
  /* ZSTD_compressBegin_usingCDict() :
@@ -3640,32 +4058,12 @@ size_t ZSTD_CStreamOutSize(void)
3640
4058
  return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
3641
4059
  }
3642
4060
 
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)
4061
+ static ZSTD_cParamMode_e ZSTD_getCParamMode(ZSTD_CDict const* cdict, ZSTD_CCtx_params const* params, U64 pledgedSrcSize)
3647
4062
  {
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 */
4063
+ if (cdict != NULL && ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize))
4064
+ return ZSTD_cpm_attachDict;
4065
+ else
4066
+ return ZSTD_cpm_noAttachDict;
3669
4067
  }
3670
4068
 
3671
4069
  /* ZSTD_resetCStream():
@@ -3749,7 +4147,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3749
4147
  FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3750
4148
  FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
3751
4149
  FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
3752
- zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, &params);
4150
+ ZSTD_CCtxParams_setZstdParams(&zcs->requestedParams, &params);
3753
4151
  FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
3754
4152
  return 0;
3755
4153
  }
@@ -3815,12 +4213,17 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3815
4213
 
3816
4214
  /* check expectations */
3817
4215
  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);
4216
+ if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) {
4217
+ assert(zcs->inBuff != NULL);
4218
+ assert(zcs->inBuffSize > 0);
4219
+ }
4220
+ if (zcs->appliedParams.outBufferMode == ZSTD_bm_buffered) {
4221
+ assert(zcs->outBuff != NULL);
4222
+ assert(zcs->outBuffSize > 0);
4223
+ }
3822
4224
  assert(output->pos <= output->size);
3823
4225
  assert(input->pos <= input->size);
4226
+ assert((U32)flushMode <= (U32)ZSTD_e_end);
3824
4227
 
3825
4228
  while (someMoreWork) {
3826
4229
  switch(zcs->streamStage)
@@ -3830,7 +4233,8 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3830
4233
 
3831
4234
  case zcss_load:
3832
4235
  if ( (flushMode == ZSTD_e_end)
3833
- && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */
4236
+ && ( (size_t)(oend-op) >= ZSTD_compressBound(iend-ip) /* Enough output space */
4237
+ || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) /* OR we are allowed to return dstSizeTooSmall */
3834
4238
  && (zcs->inBuffPos == 0) ) {
3835
4239
  /* shortcut to compression pass directly into output buffer */
3836
4240
  size_t const cSize = ZSTD_compressEnd(zcs,
@@ -3843,8 +4247,9 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3843
4247
  ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
3844
4248
  someMoreWork = 0; break;
3845
4249
  }
3846
- /* complete loading into inBuffer */
3847
- { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
4250
+ /* complete loading into inBuffer in buffered mode */
4251
+ if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) {
4252
+ size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3848
4253
  size_t const loaded = ZSTD_limitCopy(
3849
4254
  zcs->inBuff + zcs->inBuffPos, toLoad,
3850
4255
  ip, iend-ip);
@@ -3864,31 +4269,49 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3864
4269
  }
3865
4270
  /* compress current block (note : this stage cannot be stopped in the middle) */
3866
4271
  DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
3867
- { void* cDst;
4272
+ { int const inputBuffered = (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered);
4273
+ void* cDst;
3868
4274
  size_t cSize;
3869
- size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3870
4275
  size_t oSize = oend-op;
3871
- unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
3872
- if (oSize >= ZSTD_compressBound(iSize))
4276
+ size_t const iSize = inputBuffered
4277
+ ? zcs->inBuffPos - zcs->inToCompress
4278
+ : MIN((size_t)(iend - ip), zcs->blockSize);
4279
+ if (oSize >= ZSTD_compressBound(iSize) || zcs->appliedParams.outBufferMode == ZSTD_bm_stable)
3873
4280
  cDst = op; /* compress into output buffer, to skip flush stage */
3874
4281
  else
3875
4282
  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;
4283
+ if (inputBuffered) {
4284
+ unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
4285
+ cSize = lastBlock ?
4286
+ ZSTD_compressEnd(zcs, cDst, oSize,
4287
+ zcs->inBuff + zcs->inToCompress, iSize) :
4288
+ ZSTD_compressContinue(zcs, cDst, oSize,
4289
+ zcs->inBuff + zcs->inToCompress, iSize);
4290
+ FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
4291
+ zcs->frameEnded = lastBlock;
4292
+ /* prepare next block */
4293
+ zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
4294
+ if (zcs->inBuffTarget > zcs->inBuffSize)
4295
+ zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
4296
+ DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
4297
+ (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize);
4298
+ if (!lastBlock)
4299
+ assert(zcs->inBuffTarget <= zcs->inBuffSize);
4300
+ zcs->inToCompress = zcs->inBuffPos;
4301
+ } else {
4302
+ unsigned const lastBlock = (ip + iSize == iend);
4303
+ assert(flushMode == ZSTD_e_end /* Already validated */);
4304
+ cSize = lastBlock ?
4305
+ ZSTD_compressEnd(zcs, cDst, oSize, ip, iSize) :
4306
+ ZSTD_compressContinue(zcs, cDst, oSize, ip, iSize);
4307
+ /* Consume the input prior to error checking to mirror buffered mode. */
4308
+ if (iSize > 0)
4309
+ ip += iSize;
4310
+ FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
4311
+ zcs->frameEnded = lastBlock;
4312
+ if (lastBlock)
4313
+ assert(ip == iend);
4314
+ }
3892
4315
  if (cDst == op) { /* no need to flush */
3893
4316
  op += cSize;
3894
4317
  if (zcs->frameEnded) {
@@ -3905,6 +4328,7 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3905
4328
  /* fall-through */
3906
4329
  case zcss_flush:
3907
4330
  DEBUGLOG(5, "flush stage");
4331
+ assert(zcs->appliedParams.outBufferMode == ZSTD_bm_buffered);
3908
4332
  { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3909
4333
  size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op),
3910
4334
  zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
@@ -3959,6 +4383,123 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf
3959
4383
  return ZSTD_nextInputSizeHint_MTorST(zcs);
3960
4384
  }
3961
4385
 
4386
+ /* After a compression call set the expected input/output buffer.
4387
+ * This is validated at the start of the next compression call.
4388
+ */
4389
+ static void ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, ZSTD_outBuffer const* output, ZSTD_inBuffer const* input)
4390
+ {
4391
+ if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) {
4392
+ cctx->expectedInBuffer = *input;
4393
+ }
4394
+ if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) {
4395
+ cctx->expectedOutBufferSize = output->size - output->pos;
4396
+ }
4397
+ }
4398
+
4399
+ /* Validate that the input/output buffers match the expectations set by
4400
+ * ZSTD_setBufferExpectations.
4401
+ */
4402
+ static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx,
4403
+ ZSTD_outBuffer const* output,
4404
+ ZSTD_inBuffer const* input,
4405
+ ZSTD_EndDirective endOp)
4406
+ {
4407
+ if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) {
4408
+ ZSTD_inBuffer const expect = cctx->expectedInBuffer;
4409
+ if (expect.src != input->src || expect.pos != input->pos || expect.size != input->size)
4410
+ RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer enabled but input differs!");
4411
+ if (endOp != ZSTD_e_end)
4412
+ RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer can only be used with ZSTD_e_end!");
4413
+ }
4414
+ if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) {
4415
+ size_t const outBufferSize = output->size - output->pos;
4416
+ if (cctx->expectedOutBufferSize != outBufferSize)
4417
+ RETURN_ERROR(dstBuffer_wrong, "ZSTD_c_stableOutBuffer enabled but output size differs!");
4418
+ }
4419
+ return 0;
4420
+ }
4421
+
4422
+ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
4423
+ ZSTD_EndDirective endOp,
4424
+ size_t inSize) {
4425
+ ZSTD_CCtx_params params = cctx->requestedParams;
4426
+ ZSTD_prefixDict const prefixDict = cctx->prefixDict;
4427
+ FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */
4428
+ ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
4429
+ assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
4430
+ if (cctx->cdict)
4431
+ params.compressionLevel = cctx->cdict->compressionLevel; /* let cdict take priority in terms of compression level */
4432
+ DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
4433
+ if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-fix pledgedSrcSize */
4434
+ {
4435
+ size_t const dictSize = prefixDict.dict
4436
+ ? prefixDict.dictSize
4437
+ : (cctx->cdict ? cctx->cdict->dictContentSize : 0);
4438
+ ZSTD_cParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, &params, cctx->pledgedSrcSizePlusOne - 1);
4439
+ params.cParams = ZSTD_getCParamsFromCCtxParams(
4440
+ &params, cctx->pledgedSrcSizePlusOne-1,
4441
+ dictSize, mode);
4442
+ }
4443
+
4444
+ if (ZSTD_CParams_shouldEnableLdm(&params.cParams)) {
4445
+ /* Enable LDM by default for optimal parser and window size >= 128MB */
4446
+ DEBUGLOG(4, "LDM enabled by default (window size >= 128MB, strategy >= btopt)");
4447
+ params.ldmParams.enableLdm = 1;
4448
+ }
4449
+
4450
+ #ifdef ZSTD_MULTITHREAD
4451
+ if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
4452
+ params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
4453
+ }
4454
+ if (params.nbWorkers > 0) {
4455
+ #if ZSTD_TRACE
4456
+ cctx->traceCtx = ZSTD_trace_compress_begin(cctx);
4457
+ #endif
4458
+ /* mt context creation */
4459
+ if (cctx->mtctx == NULL) {
4460
+ DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u",
4461
+ params.nbWorkers);
4462
+ cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem, cctx->pool);
4463
+ RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!");
4464
+ }
4465
+ /* mt compression */
4466
+ DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
4467
+ FORWARD_IF_ERROR( ZSTDMT_initCStream_internal(
4468
+ cctx->mtctx,
4469
+ prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
4470
+ cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , "");
4471
+ cctx->dictID = cctx->cdict ? cctx->cdict->dictID : 0;
4472
+ cctx->dictContentSize = cctx->cdict ? cctx->cdict->dictContentSize : prefixDict.dictSize;
4473
+ cctx->consumedSrcSize = 0;
4474
+ cctx->producedCSize = 0;
4475
+ cctx->streamStage = zcss_load;
4476
+ cctx->appliedParams = params;
4477
+ } else
4478
+ #endif
4479
+ { U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1;
4480
+ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
4481
+ FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
4482
+ prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast,
4483
+ cctx->cdict,
4484
+ &params, pledgedSrcSize,
4485
+ ZSTDb_buffered) , "");
4486
+ assert(cctx->appliedParams.nbWorkers == 0);
4487
+ cctx->inToCompress = 0;
4488
+ cctx->inBuffPos = 0;
4489
+ if (cctx->appliedParams.inBufferMode == ZSTD_bm_buffered) {
4490
+ /* for small input: avoid automatic flush on reaching end of block, since
4491
+ * it would require to add a 3-bytes null block to end frame
4492
+ */
4493
+ cctx->inBuffTarget = cctx->blockSize + (cctx->blockSize == pledgedSrcSize);
4494
+ } else {
4495
+ cctx->inBuffTarget = 0;
4496
+ }
4497
+ cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
4498
+ cctx->streamStage = zcss_load;
4499
+ cctx->frameEnded = 0;
4500
+ }
4501
+ return 0;
4502
+ }
3962
4503
 
3963
4504
  size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
3964
4505
  ZSTD_outBuffer* output,
@@ -3967,82 +4508,69 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
3967
4508
  {
3968
4509
  DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
3969
4510
  /* 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);
4511
+ RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer");
4512
+ RETURN_ERROR_IF(input->pos > input->size, srcSize_wrong, "invalid input buffer");
4513
+ RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective");
4514
+ assert(cctx != NULL);
3973
4515
 
3974
4516
  /* transparent initialization stage */
3975
4517
  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
- } }
4518
+ FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, endOp, input->size), "CompressStream2 initialization failed");
4519
+ ZSTD_setBufferExpectations(cctx, output, input); /* Set initial buffer expectations now that we've initialized */
4520
+ }
4016
4521
  /* end of transparent initialization stage */
4017
4522
 
4523
+ FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers");
4018
4524
  /* compression stage */
4019
4525
  #ifdef ZSTD_MULTITHREAD
4020
4526
  if (cctx->appliedParams.nbWorkers > 0) {
4021
- int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end);
4022
4527
  size_t flushMin;
4023
- assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */);
4024
4528
  if (cctx->cParamsChanged) {
4025
4529
  ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
4026
4530
  cctx->cParamsChanged = 0;
4027
4531
  }
4028
- do {
4532
+ for (;;) {
4533
+ size_t const ipos = input->pos;
4534
+ size_t const opos = output->pos;
4029
4535
  flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
4536
+ cctx->consumedSrcSize += (U64)(input->pos - ipos);
4537
+ cctx->producedCSize += (U64)(output->pos - opos);
4030
4538
  if ( ZSTD_isError(flushMin)
4031
4539
  || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
4540
+ if (flushMin == 0)
4541
+ ZSTD_CCtx_trace(cctx, 0);
4032
4542
  ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
4033
4543
  }
4034
4544
  FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed");
4035
- } while (forceMaxProgress && flushMin != 0 && output->pos < output->size);
4545
+
4546
+ if (endOp == ZSTD_e_continue) {
4547
+ /* We only require some progress with ZSTD_e_continue, not maximal progress.
4548
+ * We're done if we've consumed or produced any bytes, or either buffer is
4549
+ * full.
4550
+ */
4551
+ if (input->pos != ipos || output->pos != opos || input->pos == input->size || output->pos == output->size)
4552
+ break;
4553
+ } else {
4554
+ assert(endOp == ZSTD_e_flush || endOp == ZSTD_e_end);
4555
+ /* We require maximal progress. We're done when the flush is complete or the
4556
+ * output buffer is full.
4557
+ */
4558
+ if (flushMin == 0 || output->pos == output->size)
4559
+ break;
4560
+ }
4561
+ }
4036
4562
  DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic");
4037
4563
  /* Either we don't require maximum forward progress, we've finished the
4038
4564
  * flush, or we are out of output space.
4039
4565
  */
4040
- assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size);
4566
+ assert(endOp == ZSTD_e_continue || flushMin == 0 || output->pos == output->size);
4567
+ ZSTD_setBufferExpectations(cctx, output, input);
4041
4568
  return flushMin;
4042
4569
  }
4043
4570
  #endif
4044
4571
  FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , "");
4045
4572
  DEBUGLOG(5, "completed ZSTD_compressStream2");
4573
+ ZSTD_setBufferExpectations(cctx, output, input);
4046
4574
  return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
4047
4575
  }
4048
4576
 
@@ -4065,14 +4593,22 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx,
4065
4593
  void* dst, size_t dstCapacity,
4066
4594
  const void* src, size_t srcSize)
4067
4595
  {
4596
+ ZSTD_bufferMode_e const originalInBufferMode = cctx->requestedParams.inBufferMode;
4597
+ ZSTD_bufferMode_e const originalOutBufferMode = cctx->requestedParams.outBufferMode;
4068
4598
  DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize);
4069
4599
  ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
4600
+ /* Enable stable input/output buffers. */
4601
+ cctx->requestedParams.inBufferMode = ZSTD_bm_stable;
4602
+ cctx->requestedParams.outBufferMode = ZSTD_bm_stable;
4070
4603
  { size_t oPos = 0;
4071
4604
  size_t iPos = 0;
4072
4605
  size_t const result = ZSTD_compressStream2_simpleArgs(cctx,
4073
4606
  dst, dstCapacity, &oPos,
4074
4607
  src, srcSize, &iPos,
4075
4608
  ZSTD_e_end);
4609
+ /* Reset to the original values. */
4610
+ cctx->requestedParams.inBufferMode = originalInBufferMode;
4611
+ cctx->requestedParams.outBufferMode = originalOutBufferMode;
4076
4612
  FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed");
4077
4613
  if (result != 0) { /* compression not completed, due to lack of output space */
4078
4614
  assert(oPos == dstCapacity);
@@ -4083,6 +4619,409 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx,
4083
4619
  }
4084
4620
  }
4085
4621
 
4622
+ typedef struct {
4623
+ U32 idx; /* Index in array of ZSTD_Sequence */
4624
+ U32 posInSequence; /* Position within sequence at idx */
4625
+ size_t posInSrc; /* Number of bytes given by sequences provided so far */
4626
+ } ZSTD_sequencePosition;
4627
+
4628
+ /* Returns a ZSTD error code if sequence is not valid */
4629
+ static size_t ZSTD_validateSequence(U32 offCode, U32 matchLength,
4630
+ size_t posInSrc, U32 windowLog, size_t dictSize, U32 minMatch) {
4631
+ size_t offsetBound;
4632
+ U32 windowSize = 1 << windowLog;
4633
+ /* posInSrc represents the amount of data the the decoder would decode up to this point.
4634
+ * As long as the amount of data decoded is less than or equal to window size, offsets may be
4635
+ * larger than the total length of output decoded in order to reference the dict, even larger than
4636
+ * window size. After output surpasses windowSize, we're limited to windowSize offsets again.
4637
+ */
4638
+ offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize;
4639
+ RETURN_ERROR_IF(offCode > offsetBound + ZSTD_REP_MOVE, corruption_detected, "Offset too large!");
4640
+ RETURN_ERROR_IF(matchLength < minMatch, corruption_detected, "Matchlength too small");
4641
+ return 0;
4642
+ }
4643
+
4644
+ /* Returns an offset code, given a sequence's raw offset, the ongoing repcode array, and whether litLength == 0 */
4645
+ static U32 ZSTD_finalizeOffCode(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0) {
4646
+ U32 offCode = rawOffset + ZSTD_REP_MOVE;
4647
+ U32 repCode = 0;
4648
+
4649
+ if (!ll0 && rawOffset == rep[0]) {
4650
+ repCode = 1;
4651
+ } else if (rawOffset == rep[1]) {
4652
+ repCode = 2 - ll0;
4653
+ } else if (rawOffset == rep[2]) {
4654
+ repCode = 3 - ll0;
4655
+ } else if (ll0 && rawOffset == rep[0] - 1) {
4656
+ repCode = 3;
4657
+ }
4658
+ if (repCode) {
4659
+ /* ZSTD_storeSeq expects a number in the range [0, 2] to represent a repcode */
4660
+ offCode = repCode - 1;
4661
+ }
4662
+ return offCode;
4663
+ }
4664
+
4665
+ /* Returns 0 on success, and a ZSTD_error otherwise. This function scans through an array of
4666
+ * ZSTD_Sequence, storing the sequences it finds, until it reaches a block delimiter.
4667
+ */
4668
+ static size_t ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
4669
+ const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
4670
+ const void* src, size_t blockSize) {
4671
+ U32 idx = seqPos->idx;
4672
+ BYTE const* ip = (BYTE const*)(src);
4673
+ const BYTE* const iend = ip + blockSize;
4674
+ repcodes_t updatedRepcodes;
4675
+ U32 dictSize;
4676
+ U32 litLength;
4677
+ U32 matchLength;
4678
+ U32 ll0;
4679
+ U32 offCode;
4680
+
4681
+ if (cctx->cdict) {
4682
+ dictSize = (U32)cctx->cdict->dictContentSize;
4683
+ } else if (cctx->prefixDict.dict) {
4684
+ dictSize = (U32)cctx->prefixDict.dictSize;
4685
+ } else {
4686
+ dictSize = 0;
4687
+ }
4688
+ ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t));
4689
+ for (; (inSeqs[idx].matchLength != 0 || inSeqs[idx].offset != 0) && idx < inSeqsSize; ++idx) {
4690
+ litLength = inSeqs[idx].litLength;
4691
+ matchLength = inSeqs[idx].matchLength;
4692
+ ll0 = litLength == 0;
4693
+ offCode = ZSTD_finalizeOffCode(inSeqs[idx].offset, updatedRepcodes.rep, ll0);
4694
+ updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, offCode, ll0);
4695
+
4696
+ DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offCode, matchLength, litLength);
4697
+ if (cctx->appliedParams.validateSequences) {
4698
+ seqPos->posInSrc += litLength + matchLength;
4699
+ FORWARD_IF_ERROR(ZSTD_validateSequence(offCode, matchLength, seqPos->posInSrc,
4700
+ cctx->appliedParams.cParams.windowLog, dictSize,
4701
+ cctx->appliedParams.cParams.minMatch),
4702
+ "Sequence validation failed");
4703
+ }
4704
+ RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation,
4705
+ "Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
4706
+ ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offCode, matchLength - MINMATCH);
4707
+ ip += matchLength + litLength;
4708
+ }
4709
+ ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t));
4710
+
4711
+ if (inSeqs[idx].litLength) {
4712
+ DEBUGLOG(6, "Storing last literals of size: %u", inSeqs[idx].litLength);
4713
+ ZSTD_storeLastLiterals(&cctx->seqStore, ip, inSeqs[idx].litLength);
4714
+ ip += inSeqs[idx].litLength;
4715
+ seqPos->posInSrc += inSeqs[idx].litLength;
4716
+ }
4717
+ RETURN_ERROR_IF(ip != iend, corruption_detected, "Blocksize doesn't agree with block delimiter!");
4718
+ seqPos->idx = idx+1;
4719
+ return 0;
4720
+ }
4721
+
4722
+ /* Returns the number of bytes to move the current read position back by. Only non-zero
4723
+ * if we ended up splitting a sequence. Otherwise, it may return a ZSTD error if something
4724
+ * went wrong.
4725
+ *
4726
+ * This function will attempt to scan through blockSize bytes represented by the sequences
4727
+ * in inSeqs, storing any (partial) sequences.
4728
+ *
4729
+ * Occasionally, we may want to change the actual number of bytes we consumed from inSeqs to
4730
+ * avoid splitting a match, or to avoid splitting a match such that it would produce a match
4731
+ * smaller than MINMATCH. In this case, we return the number of bytes that we didn't read from this block.
4732
+ */
4733
+ static size_t ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
4734
+ const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
4735
+ const void* src, size_t blockSize) {
4736
+ U32 idx = seqPos->idx;
4737
+ U32 startPosInSequence = seqPos->posInSequence;
4738
+ U32 endPosInSequence = seqPos->posInSequence + (U32)blockSize;
4739
+ size_t dictSize;
4740
+ BYTE const* ip = (BYTE const*)(src);
4741
+ BYTE const* iend = ip + blockSize; /* May be adjusted if we decide to process fewer than blockSize bytes */
4742
+ repcodes_t updatedRepcodes;
4743
+ U32 bytesAdjustment = 0;
4744
+ U32 finalMatchSplit = 0;
4745
+ U32 litLength;
4746
+ U32 matchLength;
4747
+ U32 rawOffset;
4748
+ U32 offCode;
4749
+
4750
+ if (cctx->cdict) {
4751
+ dictSize = cctx->cdict->dictContentSize;
4752
+ } else if (cctx->prefixDict.dict) {
4753
+ dictSize = cctx->prefixDict.dictSize;
4754
+ } else {
4755
+ dictSize = 0;
4756
+ }
4757
+ DEBUGLOG(5, "ZSTD_copySequencesToSeqStore: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize);
4758
+ DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength);
4759
+ ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t));
4760
+ while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) {
4761
+ const ZSTD_Sequence currSeq = inSeqs[idx];
4762
+ litLength = currSeq.litLength;
4763
+ matchLength = currSeq.matchLength;
4764
+ rawOffset = currSeq.offset;
4765
+
4766
+ /* Modify the sequence depending on where endPosInSequence lies */
4767
+ if (endPosInSequence >= currSeq.litLength + currSeq.matchLength) {
4768
+ if (startPosInSequence >= litLength) {
4769
+ startPosInSequence -= litLength;
4770
+ litLength = 0;
4771
+ matchLength -= startPosInSequence;
4772
+ } else {
4773
+ litLength -= startPosInSequence;
4774
+ }
4775
+ /* Move to the next sequence */
4776
+ endPosInSequence -= currSeq.litLength + currSeq.matchLength;
4777
+ startPosInSequence = 0;
4778
+ idx++;
4779
+ } else {
4780
+ /* This is the final (partial) sequence we're adding from inSeqs, and endPosInSequence
4781
+ does not reach the end of the match. So, we have to split the sequence */
4782
+ DEBUGLOG(6, "Require a split: diff: %u, idx: %u PIS: %u",
4783
+ currSeq.litLength + currSeq.matchLength - endPosInSequence, idx, endPosInSequence);
4784
+ if (endPosInSequence > litLength) {
4785
+ U32 firstHalfMatchLength;
4786
+ litLength = startPosInSequence >= litLength ? 0 : litLength - startPosInSequence;
4787
+ firstHalfMatchLength = endPosInSequence - startPosInSequence - litLength;
4788
+ if (matchLength > blockSize && firstHalfMatchLength >= cctx->appliedParams.cParams.minMatch) {
4789
+ /* Only ever split the match if it is larger than the block size */
4790
+ U32 secondHalfMatchLength = currSeq.matchLength + currSeq.litLength - endPosInSequence;
4791
+ if (secondHalfMatchLength < cctx->appliedParams.cParams.minMatch) {
4792
+ /* Move the endPosInSequence backward so that it creates match of minMatch length */
4793
+ endPosInSequence -= cctx->appliedParams.cParams.minMatch - secondHalfMatchLength;
4794
+ bytesAdjustment = cctx->appliedParams.cParams.minMatch - secondHalfMatchLength;
4795
+ firstHalfMatchLength -= bytesAdjustment;
4796
+ }
4797
+ matchLength = firstHalfMatchLength;
4798
+ /* Flag that we split the last match - after storing the sequence, exit the loop,
4799
+ but keep the value of endPosInSequence */
4800
+ finalMatchSplit = 1;
4801
+ } else {
4802
+ /* Move the position in sequence backwards so that we don't split match, and break to store
4803
+ * the last literals. We use the original currSeq.litLength as a marker for where endPosInSequence
4804
+ * should go. We prefer to do this whenever it is not necessary to split the match, or if doing so
4805
+ * would cause the first half of the match to be too small
4806
+ */
4807
+ bytesAdjustment = endPosInSequence - currSeq.litLength;
4808
+ endPosInSequence = currSeq.litLength;
4809
+ break;
4810
+ }
4811
+ } else {
4812
+ /* This sequence ends inside the literals, break to store the last literals */
4813
+ break;
4814
+ }
4815
+ }
4816
+ /* Check if this offset can be represented with a repcode */
4817
+ { U32 ll0 = (litLength == 0);
4818
+ offCode = ZSTD_finalizeOffCode(rawOffset, updatedRepcodes.rep, ll0);
4819
+ updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, offCode, ll0);
4820
+ }
4821
+
4822
+ if (cctx->appliedParams.validateSequences) {
4823
+ seqPos->posInSrc += litLength + matchLength;
4824
+ FORWARD_IF_ERROR(ZSTD_validateSequence(offCode, matchLength, seqPos->posInSrc,
4825
+ cctx->appliedParams.cParams.windowLog, dictSize,
4826
+ cctx->appliedParams.cParams.minMatch),
4827
+ "Sequence validation failed");
4828
+ }
4829
+ DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offCode, matchLength, litLength);
4830
+ RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation,
4831
+ "Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
4832
+ ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offCode, matchLength - MINMATCH);
4833
+ ip += matchLength + litLength;
4834
+ }
4835
+ DEBUGLOG(5, "Ending seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength);
4836
+ assert(idx == inSeqsSize || endPosInSequence <= inSeqs[idx].litLength + inSeqs[idx].matchLength);
4837
+ seqPos->idx = idx;
4838
+ seqPos->posInSequence = endPosInSequence;
4839
+ ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t));
4840
+
4841
+ iend -= bytesAdjustment;
4842
+ if (ip != iend) {
4843
+ /* Store any last literals */
4844
+ U32 lastLLSize = (U32)(iend - ip);
4845
+ assert(ip <= iend);
4846
+ DEBUGLOG(6, "Storing last literals of size: %u", lastLLSize);
4847
+ ZSTD_storeLastLiterals(&cctx->seqStore, ip, lastLLSize);
4848
+ seqPos->posInSrc += lastLLSize;
4849
+ }
4850
+
4851
+ return bytesAdjustment;
4852
+ }
4853
+
4854
+ typedef size_t (*ZSTD_sequenceCopier) (ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
4855
+ const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
4856
+ const void* src, size_t blockSize);
4857
+ static ZSTD_sequenceCopier ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode) {
4858
+ ZSTD_sequenceCopier sequenceCopier = NULL;
4859
+ assert(ZSTD_cParam_withinBounds(ZSTD_c_blockDelimiters, mode));
4860
+ if (mode == ZSTD_sf_explicitBlockDelimiters) {
4861
+ return ZSTD_copySequencesToSeqStoreExplicitBlockDelim;
4862
+ } else if (mode == ZSTD_sf_noBlockDelimiters) {
4863
+ return ZSTD_copySequencesToSeqStoreNoBlockDelim;
4864
+ }
4865
+ assert(sequenceCopier != NULL);
4866
+ return sequenceCopier;
4867
+ }
4868
+
4869
+ /* Compress, block-by-block, all of the sequences given.
4870
+ *
4871
+ * Returns the cumulative size of all compressed blocks (including their headers), otherwise a ZSTD error.
4872
+ */
4873
+ static size_t ZSTD_compressSequences_internal(ZSTD_CCtx* cctx,
4874
+ void* dst, size_t dstCapacity,
4875
+ const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
4876
+ const void* src, size_t srcSize) {
4877
+ size_t cSize = 0;
4878
+ U32 lastBlock;
4879
+ size_t blockSize;
4880
+ size_t compressedSeqsSize;
4881
+ size_t remaining = srcSize;
4882
+ ZSTD_sequencePosition seqPos = {0, 0, 0};
4883
+
4884
+ BYTE const* ip = (BYTE const*)src;
4885
+ BYTE* op = (BYTE*)dst;
4886
+ ZSTD_sequenceCopier sequenceCopier = ZSTD_selectSequenceCopier(cctx->appliedParams.blockDelimiters);
4887
+
4888
+ DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize);
4889
+ /* Special case: empty frame */
4890
+ if (remaining == 0) {
4891
+ U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1);
4892
+ RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "No room for empty frame block header");
4893
+ MEM_writeLE32(op, cBlockHeader24);
4894
+ op += ZSTD_blockHeaderSize;
4895
+ dstCapacity -= ZSTD_blockHeaderSize;
4896
+ cSize += ZSTD_blockHeaderSize;
4897
+ }
4898
+
4899
+ while (remaining) {
4900
+ size_t cBlockSize;
4901
+ size_t additionalByteAdjustment;
4902
+ lastBlock = remaining <= cctx->blockSize;
4903
+ blockSize = lastBlock ? (U32)remaining : (U32)cctx->blockSize;
4904
+ ZSTD_resetSeqStore(&cctx->seqStore);
4905
+ DEBUGLOG(4, "Working on new block. Blocksize: %zu", blockSize);
4906
+
4907
+ additionalByteAdjustment = sequenceCopier(cctx, &seqPos, inSeqs, inSeqsSize, ip, blockSize);
4908
+ FORWARD_IF_ERROR(additionalByteAdjustment, "Bad sequence copy");
4909
+ blockSize -= additionalByteAdjustment;
4910
+
4911
+ /* If blocks are too small, emit as a nocompress block */
4912
+ if (blockSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
4913
+ cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
4914
+ FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed");
4915
+ DEBUGLOG(4, "Block too small, writing out nocompress block: cSize: %zu", cBlockSize);
4916
+ cSize += cBlockSize;
4917
+ ip += blockSize;
4918
+ op += cBlockSize;
4919
+ remaining -= blockSize;
4920
+ dstCapacity -= cBlockSize;
4921
+ continue;
4922
+ }
4923
+
4924
+ compressedSeqsSize = ZSTD_entropyCompressSequences(&cctx->seqStore,
4925
+ &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy,
4926
+ &cctx->appliedParams,
4927
+ op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize,
4928
+ blockSize,
4929
+ cctx->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
4930
+ cctx->bmi2);
4931
+ FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed");
4932
+ DEBUGLOG(4, "Compressed sequences size: %zu", compressedSeqsSize);
4933
+
4934
+ if (!cctx->isFirstBlock &&
4935
+ ZSTD_maybeRLE(&cctx->seqStore) &&
4936
+ ZSTD_isRLE((BYTE const*)src, srcSize)) {
4937
+ /* We don't want to emit our first block as a RLE even if it qualifies because
4938
+ * doing so will cause the decoder (cli only) to throw a "should consume all input error."
4939
+ * This is only an issue for zstd <= v1.4.3
4940
+ */
4941
+ compressedSeqsSize = 1;
4942
+ }
4943
+
4944
+ if (compressedSeqsSize == 0) {
4945
+ /* ZSTD_noCompressBlock writes the block header as well */
4946
+ cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
4947
+ FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed");
4948
+ DEBUGLOG(4, "Writing out nocompress block, size: %zu", cBlockSize);
4949
+ } else if (compressedSeqsSize == 1) {
4950
+ cBlockSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, blockSize, lastBlock);
4951
+ FORWARD_IF_ERROR(cBlockSize, "RLE compress block failed");
4952
+ DEBUGLOG(4, "Writing out RLE block, size: %zu", cBlockSize);
4953
+ } else {
4954
+ U32 cBlockHeader;
4955
+ /* Error checking and repcodes update */
4956
+ ZSTD_confirmRepcodesAndEntropyTables(cctx);
4957
+ if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
4958
+ cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
4959
+
4960
+ /* Write block header into beginning of block*/
4961
+ cBlockHeader = lastBlock + (((U32)bt_compressed)<<1) + (U32)(compressedSeqsSize << 3);
4962
+ MEM_writeLE24(op, cBlockHeader);
4963
+ cBlockSize = ZSTD_blockHeaderSize + compressedSeqsSize;
4964
+ DEBUGLOG(4, "Writing out compressed block, size: %zu", cBlockSize);
4965
+ }
4966
+
4967
+ cSize += cBlockSize;
4968
+ DEBUGLOG(4, "cSize running total: %zu", cSize);
4969
+
4970
+ if (lastBlock) {
4971
+ break;
4972
+ } else {
4973
+ ip += blockSize;
4974
+ op += cBlockSize;
4975
+ remaining -= blockSize;
4976
+ dstCapacity -= cBlockSize;
4977
+ cctx->isFirstBlock = 0;
4978
+ }
4979
+ }
4980
+
4981
+ return cSize;
4982
+ }
4983
+
4984
+ size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size_t dstCapacity,
4985
+ const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
4986
+ const void* src, size_t srcSize) {
4987
+ BYTE* op = (BYTE*)dst;
4988
+ size_t cSize = 0;
4989
+ size_t compressedBlocksSize = 0;
4990
+ size_t frameHeaderSize = 0;
4991
+
4992
+ /* Transparent initialization stage, same as compressStream2() */
4993
+ DEBUGLOG(3, "ZSTD_compressSequences()");
4994
+ assert(cctx != NULL);
4995
+ FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed");
4996
+ /* Begin writing output, starting with frame header */
4997
+ frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity, &cctx->appliedParams, srcSize, cctx->dictID);
4998
+ op += frameHeaderSize;
4999
+ dstCapacity -= frameHeaderSize;
5000
+ cSize += frameHeaderSize;
5001
+ if (cctx->appliedParams.fParams.checksumFlag && srcSize) {
5002
+ XXH64_update(&cctx->xxhState, src, srcSize);
5003
+ }
5004
+ /* cSize includes block header size and compressed sequences size */
5005
+ compressedBlocksSize = ZSTD_compressSequences_internal(cctx,
5006
+ op, dstCapacity,
5007
+ inSeqs, inSeqsSize,
5008
+ src, srcSize);
5009
+ FORWARD_IF_ERROR(compressedBlocksSize, "Compressing blocks failed!");
5010
+ cSize += compressedBlocksSize;
5011
+ dstCapacity -= compressedBlocksSize;
5012
+
5013
+ if (cctx->appliedParams.fParams.checksumFlag) {
5014
+ U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
5015
+ RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum");
5016
+ DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum);
5017
+ MEM_writeLE32((char*)dst + cSize, checksum);
5018
+ cSize += 4;
5019
+ }
5020
+
5021
+ DEBUGLOG(3, "Final compressed size: %zu", cSize);
5022
+ return cSize;
5023
+ }
5024
+
4086
5025
  /*====== Finalize ======*/
4087
5026
 
4088
5027
  /*! ZSTD_flushStream() :
@@ -4223,25 +5162,103 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
4223
5162
  },
4224
5163
  };
4225
5164
 
5165
+ static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize)
5166
+ {
5167
+ ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict);
5168
+ switch (cParams.strategy) {
5169
+ case ZSTD_fast:
5170
+ case ZSTD_dfast:
5171
+ break;
5172
+ case ZSTD_greedy:
5173
+ case ZSTD_lazy:
5174
+ case ZSTD_lazy2:
5175
+ cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG;
5176
+ break;
5177
+ case ZSTD_btlazy2:
5178
+ case ZSTD_btopt:
5179
+ case ZSTD_btultra:
5180
+ case ZSTD_btultra2:
5181
+ break;
5182
+ }
5183
+ return cParams;
5184
+ }
5185
+
5186
+ static int ZSTD_dedicatedDictSearch_isSupported(
5187
+ ZSTD_compressionParameters const* cParams)
5188
+ {
5189
+ return (cParams->strategy >= ZSTD_greedy) && (cParams->strategy <= ZSTD_lazy2);
5190
+ }
5191
+
5192
+ /**
5193
+ * Reverses the adjustment applied to cparams when enabling dedicated dict
5194
+ * search. This is used to recover the params set to be used in the working
5195
+ * context. (Otherwise, those tables would also grow.)
5196
+ */
5197
+ static void ZSTD_dedicatedDictSearch_revertCParams(
5198
+ ZSTD_compressionParameters* cParams) {
5199
+ switch (cParams->strategy) {
5200
+ case ZSTD_fast:
5201
+ case ZSTD_dfast:
5202
+ break;
5203
+ case ZSTD_greedy:
5204
+ case ZSTD_lazy:
5205
+ case ZSTD_lazy2:
5206
+ cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG;
5207
+ break;
5208
+ case ZSTD_btlazy2:
5209
+ case ZSTD_btopt:
5210
+ case ZSTD_btultra:
5211
+ case ZSTD_btultra2:
5212
+ break;
5213
+ }
5214
+ }
5215
+
5216
+ static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
5217
+ {
5218
+ switch (mode) {
5219
+ case ZSTD_cpm_unknown:
5220
+ case ZSTD_cpm_noAttachDict:
5221
+ case ZSTD_cpm_createCDict:
5222
+ break;
5223
+ case ZSTD_cpm_attachDict:
5224
+ dictSize = 0;
5225
+ break;
5226
+ default:
5227
+ assert(0);
5228
+ break;
5229
+ }
5230
+ { int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN;
5231
+ size_t const addedSize = unknown && dictSize > 0 ? 500 : 0;
5232
+ return unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize;
5233
+ }
5234
+ }
5235
+
4226
5236
  /*! ZSTD_getCParams_internal() :
4227
5237
  * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
4228
5238
  * 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)
5239
+ * Use dictSize == 0 for unknown or unused.
5240
+ * Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_cParamMode_e`. */
5241
+ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
4231
5242
  {
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;
5243
+ U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode);
4235
5244
  U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB);
4236
- int row = compressionLevel;
5245
+ int row;
4237
5246
  DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel);
5247
+
5248
+ /* row */
4238
5249
  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;
5250
+ else if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */
5251
+ else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
5252
+ else row = compressionLevel;
5253
+
4241
5254
  { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
4242
- if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */
5255
+ /* acceleration factor */
5256
+ if (compressionLevel < 0) {
5257
+ int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel);
5258
+ cp.targetLength = (unsigned)(-clampedCompressionLevel);
5259
+ }
4243
5260
  /* refine parameters based on srcSize & dictSize */
4244
- return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize);
5261
+ return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode);
4245
5262
  }
4246
5263
  }
4247
5264
 
@@ -4251,18 +5268,18 @@ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel,
4251
5268
  ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
4252
5269
  {
4253
5270
  if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
4254
- return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
5271
+ return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown);
4255
5272
  }
4256
5273
 
4257
5274
  /*! ZSTD_getParams() :
4258
5275
  * same idea as ZSTD_getCParams()
4259
5276
  * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
4260
5277
  * 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) {
5278
+ static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) {
4262
5279
  ZSTD_parameters params;
4263
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
5280
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode);
4264
5281
  DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
4265
- memset(&params, 0, sizeof(params));
5282
+ ZSTD_memset(&params, 0, sizeof(params));
4266
5283
  params.cParams = cParams;
4267
5284
  params.fParams.contentSizeFlag = 1;
4268
5285
  return params;
@@ -4274,5 +5291,5 @@ static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned lo
4274
5291
  * Fields of `ZSTD_frameParameters` are set to default values */
4275
5292
  ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
4276
5293
  if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
4277
- return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize);
5294
+ return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown);
4278
5295
  }