zstd-ruby 1.4.5.0 → 1.4.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }