extzstd 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +28 -14
  3. data/contrib/zstd/CHANGELOG +114 -56
  4. data/contrib/zstd/CONTRIBUTING.md +14 -0
  5. data/contrib/zstd/Makefile +37 -31
  6. data/contrib/zstd/README.md +6 -0
  7. data/contrib/zstd/appveyor.yml +4 -1
  8. data/contrib/zstd/lib/Makefile +231 -134
  9. data/contrib/zstd/lib/README.md +28 -0
  10. data/contrib/zstd/lib/common/bitstream.h +24 -15
  11. data/contrib/zstd/lib/common/compiler.h +116 -3
  12. data/contrib/zstd/lib/common/cpu.h +0 -2
  13. data/contrib/zstd/lib/common/debug.h +11 -18
  14. data/contrib/zstd/lib/common/entropy_common.c +188 -42
  15. data/contrib/zstd/lib/common/error_private.c +1 -0
  16. data/contrib/zstd/lib/common/error_private.h +1 -1
  17. data/contrib/zstd/lib/common/fse.h +38 -11
  18. data/contrib/zstd/lib/common/fse_decompress.c +123 -16
  19. data/contrib/zstd/lib/common/huf.h +26 -5
  20. data/contrib/zstd/lib/common/mem.h +66 -93
  21. data/contrib/zstd/lib/common/pool.c +22 -16
  22. data/contrib/zstd/lib/common/pool.h +1 -1
  23. data/contrib/zstd/lib/common/threading.c +6 -5
  24. data/contrib/zstd/lib/common/xxhash.c +18 -56
  25. data/contrib/zstd/lib/common/xxhash.h +1 -1
  26. data/contrib/zstd/lib/common/zstd_common.c +9 -9
  27. data/contrib/zstd/lib/common/zstd_deps.h +111 -0
  28. data/contrib/zstd/lib/common/zstd_errors.h +1 -0
  29. data/contrib/zstd/lib/common/zstd_internal.h +89 -58
  30. data/contrib/zstd/lib/compress/fse_compress.c +30 -23
  31. data/contrib/zstd/lib/compress/hist.c +26 -28
  32. data/contrib/zstd/lib/compress/hist.h +1 -1
  33. data/contrib/zstd/lib/compress/huf_compress.c +210 -95
  34. data/contrib/zstd/lib/compress/zstd_compress.c +1339 -409
  35. data/contrib/zstd/lib/compress/zstd_compress_internal.h +119 -41
  36. data/contrib/zstd/lib/compress/zstd_compress_literals.c +4 -4
  37. data/contrib/zstd/lib/compress/zstd_compress_sequences.c +17 -3
  38. data/contrib/zstd/lib/compress/zstd_compress_superblock.c +23 -19
  39. data/contrib/zstd/lib/compress/zstd_cwksp.h +60 -24
  40. data/contrib/zstd/lib/compress/zstd_double_fast.c +22 -22
  41. data/contrib/zstd/lib/compress/zstd_fast.c +19 -19
  42. data/contrib/zstd/lib/compress/zstd_lazy.c +351 -77
  43. data/contrib/zstd/lib/compress/zstd_lazy.h +20 -0
  44. data/contrib/zstd/lib/compress/zstd_ldm.c +59 -18
  45. data/contrib/zstd/lib/compress/zstd_ldm.h +6 -0
  46. data/contrib/zstd/lib/compress/zstd_opt.c +190 -45
  47. data/contrib/zstd/lib/compress/zstdmt_compress.c +74 -406
  48. data/contrib/zstd/lib/compress/zstdmt_compress.h +26 -108
  49. data/contrib/zstd/lib/decompress/huf_decompress.c +302 -200
  50. data/contrib/zstd/lib/decompress/zstd_ddict.c +8 -8
  51. data/contrib/zstd/lib/decompress/zstd_ddict.h +1 -1
  52. data/contrib/zstd/lib/decompress/zstd_decompress.c +125 -80
  53. data/contrib/zstd/lib/decompress/zstd_decompress_block.c +145 -37
  54. data/contrib/zstd/lib/decompress/zstd_decompress_block.h +5 -2
  55. data/contrib/zstd/lib/decompress/zstd_decompress_internal.h +11 -10
  56. data/contrib/zstd/lib/dictBuilder/cover.c +29 -20
  57. data/contrib/zstd/lib/dictBuilder/cover.h +1 -1
  58. data/contrib/zstd/lib/dictBuilder/fastcover.c +20 -19
  59. data/contrib/zstd/lib/dictBuilder/zdict.c +15 -16
  60. data/contrib/zstd/lib/dictBuilder/zdict.h +1 -1
  61. data/contrib/zstd/lib/legacy/zstd_v01.c +5 -1
  62. data/contrib/zstd/lib/legacy/zstd_v02.c +5 -1
  63. data/contrib/zstd/lib/legacy/zstd_v03.c +5 -1
  64. data/contrib/zstd/lib/legacy/zstd_v04.c +6 -2
  65. data/contrib/zstd/lib/legacy/zstd_v05.c +5 -1
  66. data/contrib/zstd/lib/legacy/zstd_v06.c +5 -1
  67. data/contrib/zstd/lib/legacy/zstd_v07.c +5 -1
  68. data/contrib/zstd/lib/libzstd.pc.in +3 -3
  69. data/contrib/zstd/lib/zstd.h +348 -47
  70. data/ext/extzstd.c +6 -0
  71. data/ext/extzstd.h +6 -0
  72. data/gemstub.rb +3 -21
  73. data/lib/extzstd.rb +0 -2
  74. data/lib/extzstd/version.rb +6 -1
  75. data/test/test_basic.rb +0 -5
  76. metadata +5 -4
@@ -11,8 +11,7 @@
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"
18
17
  #include "hist.h" /* HIST_countFast_wksp */
@@ -30,6 +29,19 @@
30
29
  #include "zstd_ldm.h"
31
30
  #include "zstd_compress_superblock.h"
32
31
 
32
+ /* ***************************************************************
33
+ * Tuning parameters
34
+ *****************************************************************/
35
+ /*!
36
+ * COMPRESS_HEAPMODE :
37
+ * Select how default decompression function ZSTD_compress() allocates its context,
38
+ * on stack (0, default), or into heap (1).
39
+ * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected.
40
+ */
41
+ #ifndef ZSTD_COMPRESS_HEAPMODE
42
+ # define ZSTD_COMPRESS_HEAPMODE 0
43
+ #endif
44
+
33
45
 
34
46
  /*-*************************************
35
47
  * Helper functions
@@ -52,6 +64,7 @@ size_t ZSTD_compressBound(size_t srcSize) {
52
64
  struct ZSTD_CDict_s {
53
65
  const void* dictContent;
54
66
  size_t dictContentSize;
67
+ ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */
55
68
  U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
56
69
  ZSTD_cwksp workspace;
57
70
  ZSTD_matchState_t matchState;
@@ -69,7 +82,7 @@ ZSTD_CCtx* ZSTD_createCCtx(void)
69
82
  static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
70
83
  {
71
84
  assert(cctx != NULL);
72
- memset(cctx, 0, sizeof(*cctx));
85
+ ZSTD_memset(cctx, 0, sizeof(*cctx));
73
86
  cctx->customMem = memManager;
74
87
  cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
75
88
  { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
@@ -82,8 +95,8 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
82
95
  {
83
96
  ZSTD_STATIC_ASSERT(zcss_init==0);
84
97
  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);
98
+ if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
99
+ { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem);
87
100
  if (!cctx) return NULL;
88
101
  ZSTD_initCCtx(cctx, customMem);
89
102
  return cctx;
@@ -96,20 +109,20 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
96
109
  ZSTD_CCtx* cctx;
97
110
  if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
98
111
  if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
99
- ZSTD_cwksp_init(&ws, workspace, workspaceSize);
112
+ ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc);
100
113
 
101
114
  cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx));
102
115
  if (cctx == NULL) return NULL;
103
116
 
104
- memset(cctx, 0, sizeof(ZSTD_CCtx));
117
+ ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx));
105
118
  ZSTD_cwksp_move(&cctx->workspace, &ws);
106
119
  cctx->staticSize = workspaceSize;
107
120
 
108
121
  /* 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;
122
+ if (!ZSTD_cwksp_check_available(&cctx->workspace, ENTROPY_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL;
110
123
  cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
111
124
  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);
125
+ cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, ENTROPY_WORKSPACE_SIZE);
113
126
  cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
114
127
  return cctx;
115
128
  }
@@ -119,10 +132,10 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
119
132
  */
120
133
  static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx)
121
134
  {
122
- ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem);
135
+ ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem);
123
136
  ZSTD_freeCDict(cctx->localDict.cdict);
124
- memset(&cctx->localDict, 0, sizeof(cctx->localDict));
125
- memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
137
+ ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict));
138
+ ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
126
139
  cctx->cdict = NULL;
127
140
  }
128
141
 
@@ -153,7 +166,7 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
153
166
  int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx);
154
167
  ZSTD_freeCCtxContent(cctx);
155
168
  if (!cctxInWorkspace) {
156
- ZSTD_free(cctx, cctx->customMem);
169
+ ZSTD_customFree(cctx, cctx->customMem);
157
170
  }
158
171
  }
159
172
  return 0;
@@ -189,15 +202,32 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
189
202
  /* private API call, for dictBuilder only */
190
203
  const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
191
204
 
205
+ /* Returns 1 if compression parameters are such that we should
206
+ * enable long distance matching (wlog >= 27, strategy >= btopt).
207
+ * Returns 0 otherwise.
208
+ */
209
+ static U32 ZSTD_CParams_shouldEnableLdm(const ZSTD_compressionParameters* const cParams) {
210
+ return cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27;
211
+ }
212
+
192
213
  static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
193
214
  ZSTD_compressionParameters cParams)
194
215
  {
195
216
  ZSTD_CCtx_params cctxParams;
196
- memset(&cctxParams, 0, sizeof(cctxParams));
217
+ /* should not matter, as all cParams are presumed properly defined */
218
+ ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT);
197
219
  cctxParams.cParams = cParams;
198
- cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
220
+
221
+ if (ZSTD_CParams_shouldEnableLdm(&cParams)) {
222
+ DEBUGLOG(4, "ZSTD_makeCCtxParamsFromCParams(): Including LDM into cctx params");
223
+ cctxParams.ldmParams.enableLdm = 1;
224
+ /* LDM is enabled by default for optimal parser and window size >= 128MB */
225
+ ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams);
226
+ assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog);
227
+ assert(cctxParams.ldmParams.hashRateLog < 32);
228
+ }
229
+
199
230
  assert(!ZSTD_checkCParams(cParams));
200
- cctxParams.fParams.contentSizeFlag = 1;
201
231
  return cctxParams;
202
232
  }
203
233
 
@@ -205,13 +235,12 @@ static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
205
235
  ZSTD_customMem customMem)
206
236
  {
207
237
  ZSTD_CCtx_params* params;
208
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
209
- params = (ZSTD_CCtx_params*)ZSTD_calloc(
238
+ if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
239
+ params = (ZSTD_CCtx_params*)ZSTD_customCalloc(
210
240
  sizeof(ZSTD_CCtx_params), customMem);
211
241
  if (!params) { return NULL; }
242
+ ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
212
243
  params->customMem = customMem;
213
- params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
214
- params->fParams.contentSizeFlag = 1;
215
244
  return params;
216
245
  }
217
246
 
@@ -223,7 +252,7 @@ ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
223
252
  size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
224
253
  {
225
254
  if (params == NULL) { return 0; }
226
- ZSTD_free(params, params->customMem);
255
+ ZSTD_customFree(params, params->customMem);
227
256
  return 0;
228
257
  }
229
258
 
@@ -234,7 +263,7 @@ size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
234
263
 
235
264
  size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
236
265
  RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
237
- memset(cctxParams, 0, sizeof(*cctxParams));
266
+ ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));
238
267
  cctxParams->compressionLevel = compressionLevel;
239
268
  cctxParams->fParams.contentSizeFlag = 1;
240
269
  return 0;
@@ -244,7 +273,7 @@ size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_paramete
244
273
  {
245
274
  RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
246
275
  FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
247
- memset(cctxParams, 0, sizeof(*cctxParams));
276
+ ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));
248
277
  assert(!ZSTD_checkCParams(params.cParams));
249
278
  cctxParams->cParams = params.cParams;
250
279
  cctxParams->fParams = params.fParams;
@@ -354,6 +383,11 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
354
383
  #endif
355
384
  return bounds;
356
385
 
386
+ case ZSTD_c_enableDedicatedDictSearch:
387
+ bounds.lowerBound = 0;
388
+ bounds.upperBound = 1;
389
+ return bounds;
390
+
357
391
  case ZSTD_c_enableLongDistanceMatching:
358
392
  bounds.lowerBound = 0;
359
393
  bounds.upperBound = 1;
@@ -397,7 +431,7 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
397
431
  return bounds;
398
432
 
399
433
  case ZSTD_c_forceAttachDict:
400
- ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy);
434
+ ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceLoad);
401
435
  bounds.lowerBound = ZSTD_dictDefaultAttach;
402
436
  bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */
403
437
  return bounds;
@@ -418,6 +452,22 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
418
452
  bounds.upperBound = ZSTD_SRCSIZEHINT_MAX;
419
453
  return bounds;
420
454
 
455
+ case ZSTD_c_stableInBuffer:
456
+ case ZSTD_c_stableOutBuffer:
457
+ bounds.lowerBound = (int)ZSTD_bm_buffered;
458
+ bounds.upperBound = (int)ZSTD_bm_stable;
459
+ return bounds;
460
+
461
+ case ZSTD_c_blockDelimiters:
462
+ bounds.lowerBound = (int)ZSTD_sf_noBlockDelimiters;
463
+ bounds.upperBound = (int)ZSTD_sf_explicitBlockDelimiters;
464
+ return bounds;
465
+
466
+ case ZSTD_c_validateSequences:
467
+ bounds.lowerBound = 0;
468
+ bounds.upperBound = 1;
469
+ return bounds;
470
+
421
471
  default:
422
472
  bounds.error = ERROR(parameter_unsupported);
423
473
  return bounds;
@@ -465,6 +515,7 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
465
515
  case ZSTD_c_jobSize:
466
516
  case ZSTD_c_overlapLog:
467
517
  case ZSTD_c_rsyncable:
518
+ case ZSTD_c_enableDedicatedDictSearch:
468
519
  case ZSTD_c_enableLongDistanceMatching:
469
520
  case ZSTD_c_ldmHashLog:
470
521
  case ZSTD_c_ldmMinMatch:
@@ -474,6 +525,10 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
474
525
  case ZSTD_c_literalCompressionMode:
475
526
  case ZSTD_c_targetCBlockSize:
476
527
  case ZSTD_c_srcSizeHint:
528
+ case ZSTD_c_stableInBuffer:
529
+ case ZSTD_c_stableOutBuffer:
530
+ case ZSTD_c_blockDelimiters:
531
+ case ZSTD_c_validateSequences:
477
532
  default:
478
533
  return 0;
479
534
  }
@@ -515,12 +570,17 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
515
570
  case ZSTD_c_jobSize:
516
571
  case ZSTD_c_overlapLog:
517
572
  case ZSTD_c_rsyncable:
573
+ case ZSTD_c_enableDedicatedDictSearch:
518
574
  case ZSTD_c_enableLongDistanceMatching:
519
575
  case ZSTD_c_ldmHashLog:
520
576
  case ZSTD_c_ldmMinMatch:
521
577
  case ZSTD_c_ldmBucketSizeLog:
522
578
  case ZSTD_c_targetCBlockSize:
523
579
  case ZSTD_c_srcSizeHint:
580
+ case ZSTD_c_stableInBuffer:
581
+ case ZSTD_c_stableOutBuffer:
582
+ case ZSTD_c_blockDelimiters:
583
+ case ZSTD_c_validateSequences:
524
584
  break;
525
585
 
526
586
  default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
@@ -541,9 +601,10 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
541
601
 
542
602
  case ZSTD_c_compressionLevel : {
543
603
  FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
544
- if (value) { /* 0 : does not change current level */
604
+ if (value == 0)
605
+ CCtxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default */
606
+ else
545
607
  CCtxParams->compressionLevel = value;
546
- }
547
608
  if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel;
548
609
  return 0; /* return type (size_t) cannot represent negative values */
549
610
  }
@@ -667,6 +728,10 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
667
728
  return CCtxParams->rsyncable;
668
729
  #endif
669
730
 
731
+ case ZSTD_c_enableDedicatedDictSearch :
732
+ CCtxParams->enableDedicatedDictSearch = (value!=0);
733
+ return CCtxParams->enableDedicatedDictSearch;
734
+
670
735
  case ZSTD_c_enableLongDistanceMatching :
671
736
  CCtxParams->ldmParams.enableLdm = (value!=0);
672
737
  return CCtxParams->ldmParams.enableLdm;
@@ -707,6 +772,26 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
707
772
  CCtxParams->srcSizeHint = value;
708
773
  return CCtxParams->srcSizeHint;
709
774
 
775
+ case ZSTD_c_stableInBuffer:
776
+ BOUNDCHECK(ZSTD_c_stableInBuffer, value);
777
+ CCtxParams->inBufferMode = (ZSTD_bufferMode_e)value;
778
+ return CCtxParams->inBufferMode;
779
+
780
+ case ZSTD_c_stableOutBuffer:
781
+ BOUNDCHECK(ZSTD_c_stableOutBuffer, value);
782
+ CCtxParams->outBufferMode = (ZSTD_bufferMode_e)value;
783
+ return CCtxParams->outBufferMode;
784
+
785
+ case ZSTD_c_blockDelimiters:
786
+ BOUNDCHECK(ZSTD_c_blockDelimiters, value);
787
+ CCtxParams->blockDelimiters = (ZSTD_sequenceFormat_e)value;
788
+ return CCtxParams->blockDelimiters;
789
+
790
+ case ZSTD_c_validateSequences:
791
+ BOUNDCHECK(ZSTD_c_validateSequences, value);
792
+ CCtxParams->validateSequences = value;
793
+ return CCtxParams->validateSequences;
794
+
710
795
  default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
711
796
  }
712
797
  }
@@ -794,6 +879,9 @@ size_t ZSTD_CCtxParams_getParameter(
794
879
  *value = CCtxParams->rsyncable;
795
880
  break;
796
881
  #endif
882
+ case ZSTD_c_enableDedicatedDictSearch :
883
+ *value = CCtxParams->enableDedicatedDictSearch;
884
+ break;
797
885
  case ZSTD_c_enableLongDistanceMatching :
798
886
  *value = CCtxParams->ldmParams.enableLdm;
799
887
  break;
@@ -815,6 +903,18 @@ size_t ZSTD_CCtxParams_getParameter(
815
903
  case ZSTD_c_srcSizeHint :
816
904
  *value = (int)CCtxParams->srcSizeHint;
817
905
  break;
906
+ case ZSTD_c_stableInBuffer :
907
+ *value = (int)CCtxParams->inBufferMode;
908
+ break;
909
+ case ZSTD_c_stableOutBuffer :
910
+ *value = (int)CCtxParams->outBufferMode;
911
+ break;
912
+ case ZSTD_c_blockDelimiters :
913
+ *value = (int)CCtxParams->blockDelimiters;
914
+ break;
915
+ case ZSTD_c_validateSequences :
916
+ *value = (int)CCtxParams->validateSequences;
917
+ break;
818
918
  default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
819
919
  }
820
920
  return 0;
@@ -850,6 +950,14 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo
850
950
  return 0;
851
951
  }
852
952
 
953
+ static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(
954
+ int const compressionLevel,
955
+ size_t const dictSize);
956
+ static int ZSTD_dedicatedDictSearch_isSupported(
957
+ const ZSTD_compressionParameters* cParams);
958
+ static void ZSTD_dedicatedDictSearch_revertCParams(
959
+ ZSTD_compressionParameters* cParams);
960
+
853
961
  /**
854
962
  * Initializes the local dict using the requested parameters.
855
963
  * NOTE: This does not use the pledged src size, because it may be used for more
@@ -858,8 +966,6 @@ ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long lo
858
966
  static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
859
967
  {
860
968
  ZSTD_localDict* const dl = &cctx->localDict;
861
- ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(
862
- &cctx->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN, dl->dictSize);
863
969
  if (dl->dict == NULL) {
864
970
  /* No local dictionary. */
865
971
  assert(dl->dictBuffer == NULL);
@@ -876,12 +982,12 @@ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
876
982
  assert(cctx->cdict == NULL);
877
983
  assert(cctx->prefixDict.dict == NULL);
878
984
 
879
- dl->cdict = ZSTD_createCDict_advanced(
985
+ dl->cdict = ZSTD_createCDict_advanced2(
880
986
  dl->dict,
881
987
  dl->dictSize,
882
988
  ZSTD_dlm_byRef,
883
989
  dl->dictContentType,
884
- cParams,
990
+ &cctx->requestedParams,
885
991
  cctx->customMem);
886
992
  RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed");
887
993
  cctx->cdict = dl->cdict;
@@ -894,8 +1000,6 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
894
1000
  {
895
1001
  RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
896
1002
  "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
1003
  DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
900
1004
  ZSTD_clearAllDicts(cctx); /* in case one already exists */
901
1005
  if (dict == NULL || dictSize == 0) /* no dictionary mode */
@@ -903,9 +1007,12 @@ size_t ZSTD_CCtx_loadDictionary_advanced(
903
1007
  if (dictLoadMethod == ZSTD_dlm_byRef) {
904
1008
  cctx->localDict.dict = dict;
905
1009
  } else {
906
- void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem);
1010
+ void* dictBuffer;
1011
+ RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
1012
+ "no malloc for static CCtx");
1013
+ dictBuffer = ZSTD_customMalloc(dictSize, cctx->customMem);
907
1014
  RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!");
908
- memcpy(dictBuffer, dict, dictSize);
1015
+ ZSTD_memcpy(dictBuffer, dict, dictSize);
909
1016
  cctx->localDict.dictBuffer = dictBuffer;
910
1017
  cctx->localDict.dict = dictBuffer;
911
1018
  }
@@ -938,6 +1045,14 @@ size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
938
1045
  return 0;
939
1046
  }
940
1047
 
1048
+ size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool)
1049
+ {
1050
+ RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
1051
+ "Can't ref a pool when ctx not in init stage.");
1052
+ cctx->pool = pool;
1053
+ return 0;
1054
+ }
1055
+
941
1056
  size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
942
1057
  {
943
1058
  return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
@@ -1022,24 +1137,73 @@ U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
1022
1137
  return hashLog - btScale;
1023
1138
  }
1024
1139
 
1140
+ /** ZSTD_dictAndWindowLog() :
1141
+ * Returns an adjusted window log that is large enough to fit the source and the dictionary.
1142
+ * The zstd format says that the entire dictionary is valid if one byte of the dictionary
1143
+ * is within the window. So the hashLog and chainLog should be large enough to reference both
1144
+ * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing
1145
+ * the hashLog and windowLog.
1146
+ * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN.
1147
+ */
1148
+ static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize)
1149
+ {
1150
+ const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX;
1151
+ /* No dictionary ==> No change */
1152
+ if (dictSize == 0) {
1153
+ return windowLog;
1154
+ }
1155
+ assert(windowLog <= ZSTD_WINDOWLOG_MAX);
1156
+ assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */
1157
+ {
1158
+ U64 const windowSize = 1ULL << windowLog;
1159
+ U64 const dictAndWindowSize = dictSize + windowSize;
1160
+ /* If the window size is already large enough to fit both the source and the dictionary
1161
+ * then just use the window size. Otherwise adjust so that it fits the dictionary and
1162
+ * the window.
1163
+ */
1164
+ if (windowSize >= dictSize + srcSize) {
1165
+ return windowLog; /* Window size large enough already */
1166
+ } else if (dictAndWindowSize >= maxWindowSize) {
1167
+ return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */
1168
+ } else {
1169
+ return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1;
1170
+ }
1171
+ }
1172
+ }
1173
+
1025
1174
  /** ZSTD_adjustCParams_internal() :
1026
1175
  * optimize `cPar` for a specified input (`srcSize` and `dictSize`).
1027
1176
  * mostly downsize to reduce memory consumption and initialization latency.
1028
1177
  * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known.
1178
+ * `mode` is the mode for parameter adjustment. See docs for `ZSTD_cParamMode_e`.
1029
1179
  * note : `srcSize==0` means 0!
1030
1180
  * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */
1031
1181
  static ZSTD_compressionParameters
1032
1182
  ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
1033
1183
  unsigned long long srcSize,
1034
- size_t dictSize)
1184
+ size_t dictSize,
1185
+ ZSTD_cParamMode_e mode)
1035
1186
  {
1036
- static const U64 minSrcSize = 513; /* (1<<9) + 1 */
1037
- static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
1187
+ const U64 minSrcSize = 513; /* (1<<9) + 1 */
1188
+ const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
1038
1189
  assert(ZSTD_checkCParams(cPar)==0);
1039
1190
 
1040
1191
  if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
1041
1192
  srcSize = minSrcSize;
1042
1193
 
1194
+ switch (mode) {
1195
+ case ZSTD_cpm_noAttachDict:
1196
+ case ZSTD_cpm_unknown:
1197
+ case ZSTD_cpm_createCDict:
1198
+ break;
1199
+ case ZSTD_cpm_attachDict:
1200
+ dictSize = 0;
1201
+ break;
1202
+ default:
1203
+ assert(0);
1204
+ break;
1205
+ }
1206
+
1043
1207
  /* resize windowLog if input is small enough, to use less memory */
1044
1208
  if ( (srcSize < maxWindowResize)
1045
1209
  && (dictSize < maxWindowResize) ) {
@@ -1049,10 +1213,11 @@ ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
1049
1213
  ZSTD_highbit32(tSize-1) + 1;
1050
1214
  if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
1051
1215
  }
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);
1216
+ { U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize);
1217
+ U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
1218
+ if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1;
1219
+ if (cycleLog > dictAndWindowLog)
1220
+ cPar.chainLog -= (cycleLog - dictAndWindowLog);
1056
1221
  }
1057
1222
 
1058
1223
  if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
@@ -1068,31 +1233,38 @@ ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
1068
1233
  {
1069
1234
  cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */
1070
1235
  if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN;
1071
- return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
1236
+ return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown);
1072
1237
  }
1073
1238
 
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);
1239
+ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode);
1240
+ static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode);
1241
+
1242
+ static void ZSTD_overrideCParams(
1243
+ ZSTD_compressionParameters* cParams,
1244
+ const ZSTD_compressionParameters* overrides)
1245
+ {
1246
+ if (overrides->windowLog) cParams->windowLog = overrides->windowLog;
1247
+ if (overrides->hashLog) cParams->hashLog = overrides->hashLog;
1248
+ if (overrides->chainLog) cParams->chainLog = overrides->chainLog;
1249
+ if (overrides->searchLog) cParams->searchLog = overrides->searchLog;
1250
+ if (overrides->minMatch) cParams->minMatch = overrides->minMatch;
1251
+ if (overrides->targetLength) cParams->targetLength = overrides->targetLength;
1252
+ if (overrides->strategy) cParams->strategy = overrides->strategy;
1253
+ }
1076
1254
 
1077
1255
  ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
1078
- const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
1256
+ const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
1079
1257
  {
1080
1258
  ZSTD_compressionParameters cParams;
1081
1259
  if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) {
1082
1260
  srcSizeHint = CCtxParams->srcSizeHint;
1083
1261
  }
1084
- cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize);
1262
+ cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode);
1085
1263
  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;
1264
+ ZSTD_overrideCParams(&cParams, &CCtxParams->cParams);
1093
1265
  assert(!ZSTD_checkCParams(cParams));
1094
1266
  /* srcSizeHint == 0 means 0 */
1095
- return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize);
1267
+ return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode);
1096
1268
  }
1097
1269
 
1098
1270
  static size_t
@@ -1123,45 +1295,61 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
1123
1295
  return tableSpace + optSpace;
1124
1296
  }
1125
1297
 
1126
- size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1298
+ static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1299
+ const ZSTD_compressionParameters* cParams,
1300
+ const ldmParams_t* ldmParams,
1301
+ const int isStatic,
1302
+ const size_t buffInSize,
1303
+ const size_t buffOutSize,
1304
+ const U64 pledgedSrcSize)
1127
1305
  {
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);
1306
+ size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << cParams->windowLog), pledgedSrcSize));
1307
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
1308
+ U32 const divider = (cParams->minMatch==3) ? 3 : 4;
1309
+ size_t const maxNbSeq = blockSize / divider;
1310
+ size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
1311
+ + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
1312
+ + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
1313
+ size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE);
1314
+ size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
1315
+ size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, /* forCCtx */ 1);
1140
1316
 
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));
1317
+ size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams);
1318
+ size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize);
1319
+ size_t const ldmSeqSpace = ldmParams->enableLdm ?
1320
+ ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0;
1143
1321
 
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
1322
 
1150
- size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx));
1323
+ size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize)
1324
+ + ZSTD_cwksp_alloc_size(buffOutSize);
1151
1325
 
1152
- size_t const neededSpace =
1153
- cctxSpace +
1154
- entropySpace +
1155
- blockStateSpace +
1156
- ldmSpace +
1157
- ldmSeqSpace +
1158
- matchStateSize +
1159
- tokenSpace +
1160
- bufferSpace;
1326
+ size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
1161
1327
 
1162
- DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
1163
- return neededSpace;
1164
- }
1328
+ size_t const neededSpace =
1329
+ cctxSpace +
1330
+ entropySpace +
1331
+ blockStateSpace +
1332
+ ldmSpace +
1333
+ ldmSeqSpace +
1334
+ matchStateSize +
1335
+ tokenSpace +
1336
+ bufferSpace;
1337
+
1338
+ DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
1339
+ return neededSpace;
1340
+ }
1341
+
1342
+ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1343
+ {
1344
+ ZSTD_compressionParameters const cParams =
1345
+ ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1346
+
1347
+ RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
1348
+ /* estimateCCtxSize is for one-shot compression. So no buffers should
1349
+ * be needed. However, we still allocate two 0-sized buffers, which can
1350
+ * take space under ASAN. */
1351
+ return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1352
+ &cParams, &params->ldmParams, 1, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN);
1165
1353
  }
1166
1354
 
1167
1355
  size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
@@ -1172,7 +1360,7 @@ size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
1172
1360
 
1173
1361
  static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
1174
1362
  {
1175
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
1363
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1176
1364
  return ZSTD_estimateCCtxSize_usingCParams(cParams);
1177
1365
  }
1178
1366
 
@@ -1191,15 +1379,18 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1191
1379
  {
1192
1380
  RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
1193
1381
  { ZSTD_compressionParameters const cParams =
1194
- ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0);
1195
- size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
1382
+ ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1196
1383
  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;
1384
+ size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered)
1385
+ ? ((size_t)1 << cParams.windowLog) + blockSize
1386
+ : 0;
1387
+ size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered)
1388
+ ? ZSTD_compressBound(blockSize) + 1
1389
+ : 0;
1390
+
1391
+ return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1392
+ &cParams, &params->ldmParams, 1, inBuffSize, outBuffSize,
1393
+ ZSTD_CONTENTSIZE_UNKNOWN);
1203
1394
  }
1204
1395
  }
1205
1396
 
@@ -1211,7 +1402,7 @@ size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
1211
1402
 
1212
1403
  static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
1213
1404
  {
1214
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0);
1405
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1215
1406
  return ZSTD_estimateCStreamSize_usingCParams(cParams);
1216
1407
  }
1217
1408
 
@@ -1304,16 +1495,6 @@ static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
1304
1495
  ms->dictMatchState = NULL;
1305
1496
  }
1306
1497
 
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
1498
  /**
1318
1499
  * Controls, for this matchState reset, whether the tables need to be cleared /
1319
1500
  * prepared for the coming compression (ZSTDcrp_makeClean), or whether the
@@ -1441,45 +1622,32 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1441
1622
  size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
1442
1623
  U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
1443
1624
  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);
1625
+ size_t const buffOutSize = (zbuff == ZSTDb_buffered && params.outBufferMode == ZSTD_bm_buffered)
1626
+ ? ZSTD_compressBound(blockSize) + 1
1627
+ : 0;
1628
+ size_t const buffInSize = (zbuff == ZSTDb_buffered && params.inBufferMode == ZSTD_bm_buffered)
1629
+ ? windowSize + blockSize
1630
+ : 0;
1450
1631
  size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
1451
1632
 
1452
- ZSTD_indexResetPolicy_e needsIndexReset = zc->initialized ? ZSTDirp_continue : ZSTDirp_reset;
1633
+ int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window);
1634
+ ZSTD_indexResetPolicy_e needsIndexReset =
1635
+ (!indexTooClose && zc->initialized) ? ZSTDirp_continue : ZSTDirp_reset;
1453
1636
 
1454
- if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) {
1455
- needsIndexReset = ZSTDirp_reset;
1456
- }
1637
+ size_t const neededSpace =
1638
+ ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1639
+ &params.cParams, &params.ldmParams, zc->staticSize != 0,
1640
+ buffInSize, buffOutSize, pledgedSrcSize);
1641
+ FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!");
1457
1642
 
1458
1643
  if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
1459
1644
 
1460
1645
  /* 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
-
1646
+ {
1478
1647
  int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
1479
1648
  int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
1480
1649
 
1481
- DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
1482
- neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
1650
+ DEBUGLOG(4, "Need %zu B workspace", neededSpace);
1483
1651
  DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
1484
1652
 
1485
1653
  if (workspaceTooSmall || workspaceWasteful) {
@@ -1503,7 +1671,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1503
1671
  RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock");
1504
1672
  zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
1505
1673
  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);
1674
+ zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, ENTROPY_WORKSPACE_SIZE);
1507
1675
  RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace");
1508
1676
  } }
1509
1677
 
@@ -1534,6 +1702,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1534
1702
  zc->seqStore.maxNbLit = blockSize;
1535
1703
 
1536
1704
  /* buffers */
1705
+ zc->bufferedPolicy = zbuff;
1537
1706
  zc->inBuffSize = buffInSize;
1538
1707
  zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize);
1539
1708
  zc->outBuffSize = buffOutSize;
@@ -1546,7 +1715,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1546
1715
  ((size_t)1) << (params.ldmParams.hashLog -
1547
1716
  params.ldmParams.bucketSizeLog);
1548
1717
  zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize);
1549
- memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize);
1718
+ ZSTD_memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize);
1550
1719
  }
1551
1720
 
1552
1721
  /* sequences storage */
@@ -1570,7 +1739,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1570
1739
  /* TODO: avoid memset? */
1571
1740
  size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
1572
1741
  zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t));
1573
- memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
1742
+ ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
1574
1743
  zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq));
1575
1744
  zc->maxNbLdmSequences = maxNbLdmSeq;
1576
1745
 
@@ -1579,6 +1748,12 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1579
1748
  zc->ldmState.loadedDictEnd = 0;
1580
1749
  }
1581
1750
 
1751
+ /* Due to alignment, when reusing a workspace, we can actually consume
1752
+ * up to 3 extra bytes for alignment. See the comments in zstd_cwksp.h
1753
+ */
1754
+ assert(ZSTD_cwksp_used(ws) >= neededSpace &&
1755
+ ZSTD_cwksp_used(ws) <= neededSpace + 3);
1756
+
1582
1757
  DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws));
1583
1758
  zc->initialized = 1;
1584
1759
 
@@ -1618,12 +1793,14 @@ static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict,
1618
1793
  U64 pledgedSrcSize)
1619
1794
  {
1620
1795
  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 */
1796
+ int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch;
1797
+ return dedicatedDictSearch
1798
+ || ( ( pledgedSrcSize <= cutoff
1799
+ || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
1800
+ || params->attachDictPref == ZSTD_dictForceAttach )
1801
+ && params->attachDictPref != ZSTD_dictForceCopy
1802
+ && !params->forceWindow ); /* dictMatchState isn't correctly
1803
+ * handled in _enforceMaxDist */
1627
1804
  }
1628
1805
 
1629
1806
  static size_t
@@ -1633,17 +1810,24 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
1633
1810
  U64 pledgedSrcSize,
1634
1811
  ZSTD_buffered_policy_e zbuff)
1635
1812
  {
1636
- { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams;
1813
+ {
1814
+ ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams;
1637
1815
  unsigned const windowLog = params.cParams.windowLog;
1638
1816
  assert(windowLog != 0);
1639
1817
  /* Resize working context table params for input only, since the dict
1640
1818
  * has its own tables. */
1641
- /* pledgeSrcSize == 0 means 0! */
1642
- params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0);
1819
+ /* pledgedSrcSize == 0 means 0! */
1820
+
1821
+ if (cdict->matchState.dedicatedDictSearch) {
1822
+ ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams);
1823
+ }
1824
+
1825
+ params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize,
1826
+ cdict->dictContentSize, ZSTD_cpm_attachDict);
1643
1827
  params.cParams.windowLog = windowLog;
1644
1828
  FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
1645
1829
  ZSTDcrp_makeClean, zbuff), "");
1646
- assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
1830
+ assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy);
1647
1831
  }
1648
1832
 
1649
1833
  { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc
@@ -1670,7 +1854,7 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
1670
1854
  cctx->dictID = cdict->dictID;
1671
1855
 
1672
1856
  /* copy block state */
1673
- memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1857
+ ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1674
1858
 
1675
1859
  return 0;
1676
1860
  }
@@ -1683,6 +1867,8 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
1683
1867
  {
1684
1868
  const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
1685
1869
 
1870
+ assert(!cdict->matchState.dedicatedDictSearch);
1871
+
1686
1872
  DEBUGLOG(4, "copying dictionary into context");
1687
1873
 
1688
1874
  { unsigned const windowLog = params.cParams.windowLog;
@@ -1703,10 +1889,10 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
1703
1889
  { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
1704
1890
  size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
1705
1891
 
1706
- memcpy(cctx->blockState.matchState.hashTable,
1892
+ ZSTD_memcpy(cctx->blockState.matchState.hashTable,
1707
1893
  cdict->matchState.hashTable,
1708
1894
  hSize * sizeof(U32));
1709
- memcpy(cctx->blockState.matchState.chainTable,
1895
+ ZSTD_memcpy(cctx->blockState.matchState.chainTable,
1710
1896
  cdict->matchState.chainTable,
1711
1897
  chainSize * sizeof(U32));
1712
1898
  }
@@ -1715,7 +1901,7 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
1715
1901
  { int const h3log = cctx->blockState.matchState.hashLog3;
1716
1902
  size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
1717
1903
  assert(cdict->matchState.hashLog3 == 0);
1718
- memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
1904
+ ZSTD_memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
1719
1905
  }
1720
1906
 
1721
1907
  ZSTD_cwksp_mark_tables_clean(&cctx->workspace);
@@ -1731,7 +1917,7 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
1731
1917
  cctx->dictID = cdict->dictID;
1732
1918
 
1733
1919
  /* copy block state */
1734
- memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1920
+ ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1735
1921
 
1736
1922
  return 0;
1737
1923
  }
@@ -1775,7 +1961,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1775
1961
  RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong,
1776
1962
  "Can't copy a ctx that's not in init stage.");
1777
1963
 
1778
- memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
1964
+ ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
1779
1965
  { ZSTD_CCtx_params params = dstCCtx->requestedParams;
1780
1966
  /* Copy only compression parameters related to tables. */
1781
1967
  params.cParams = srcCCtx->appliedParams.cParams;
@@ -1797,13 +1983,13 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1797
1983
  int const h3log = srcCCtx->blockState.matchState.hashLog3;
1798
1984
  size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
1799
1985
 
1800
- memcpy(dstCCtx->blockState.matchState.hashTable,
1986
+ ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable,
1801
1987
  srcCCtx->blockState.matchState.hashTable,
1802
1988
  hSize * sizeof(U32));
1803
- memcpy(dstCCtx->blockState.matchState.chainTable,
1989
+ ZSTD_memcpy(dstCCtx->blockState.matchState.chainTable,
1804
1990
  srcCCtx->blockState.matchState.chainTable,
1805
1991
  chainSize * sizeof(U32));
1806
- memcpy(dstCCtx->blockState.matchState.hashTable3,
1992
+ ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable3,
1807
1993
  srcCCtx->blockState.matchState.hashTable3,
1808
1994
  h3Size * sizeof(U32));
1809
1995
  }
@@ -1821,7 +2007,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1821
2007
  dstCCtx->dictID = srcCCtx->dictID;
1822
2008
 
1823
2009
  /* copy block state */
1824
- memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
2010
+ ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
1825
2011
 
1826
2012
  return 0;
1827
2013
  }
@@ -1834,7 +2020,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1834
2020
  size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
1835
2021
  {
1836
2022
  ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
1837
- ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
2023
+ ZSTD_buffered_policy_e const zbuff = srcCCtx->bufferedPolicy;
1838
2024
  ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
1839
2025
  if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
1840
2026
  fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
@@ -1861,7 +2047,7 @@ ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerVa
1861
2047
  assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */
1862
2048
  assert(size < (1U<<31)); /* can be casted to int */
1863
2049
 
1864
- #if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
2050
+ #if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
1865
2051
  /* To validate that the table re-use logic is sound, and that we don't
1866
2052
  * access table space that we haven't cleaned, we re-"poison" the table
1867
2053
  * space every time we mark it dirty.
@@ -1958,10 +2144,10 @@ static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams)
1958
2144
  return (cctxParams->targetCBlockSize != 0);
1959
2145
  }
1960
2146
 
1961
- /* ZSTD_compressSequences_internal():
2147
+ /* ZSTD_entropyCompressSequences_internal():
1962
2148
  * actually compresses both literals and sequences */
1963
2149
  MEM_STATIC size_t
1964
- ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
2150
+ ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
1965
2151
  const ZSTD_entropyCTables_t* prevEntropy,
1966
2152
  ZSTD_entropyCTables_t* nextEntropy,
1967
2153
  const ZSTD_CCtx_params* cctxParams,
@@ -1971,7 +2157,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
1971
2157
  {
1972
2158
  const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
1973
2159
  ZSTD_strategy const strategy = cctxParams->cParams.strategy;
1974
- unsigned count[MaxSeq+1];
2160
+ unsigned* count = (unsigned*)entropyWorkspace;
1975
2161
  FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
1976
2162
  FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
1977
2163
  FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
@@ -1987,8 +2173,12 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
1987
2173
  BYTE* seqHead;
1988
2174
  BYTE* lastNCount = NULL;
1989
2175
 
1990
- DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq);
2176
+ entropyWorkspace = count + (MaxSeq + 1);
2177
+ entropyWkspSize -= (MaxSeq + 1) * sizeof(*count);
2178
+
2179
+ DEBUGLOG(4, "ZSTD_entropyCompressSequences_internal (nbSeq=%zu)", nbSeq);
1991
2180
  ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
2181
+ assert(entropyWkspSize >= HUF_WORKSPACE_SIZE);
1992
2182
 
1993
2183
  /* Compress literals */
1994
2184
  { const BYTE* const literals = seqStorePtr->litStart;
@@ -2023,7 +2213,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
2023
2213
  assert(op <= oend);
2024
2214
  if (nbSeq==0) {
2025
2215
  /* Copy the old tables over as if we repeated them */
2026
- memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
2216
+ ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
2027
2217
  return (size_t)(op - ostart);
2028
2218
  }
2029
2219
 
@@ -2148,7 +2338,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
2148
2338
  }
2149
2339
 
2150
2340
  MEM_STATIC size_t
2151
- ZSTD_compressSequences(seqStore_t* seqStorePtr,
2341
+ ZSTD_entropyCompressSequences(seqStore_t* seqStorePtr,
2152
2342
  const ZSTD_entropyCTables_t* prevEntropy,
2153
2343
  ZSTD_entropyCTables_t* nextEntropy,
2154
2344
  const ZSTD_CCtx_params* cctxParams,
@@ -2157,7 +2347,7 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr,
2157
2347
  void* entropyWorkspace, size_t entropyWkspSize,
2158
2348
  int bmi2)
2159
2349
  {
2160
- size_t const cSize = ZSTD_compressSequences_internal(
2350
+ size_t const cSize = ZSTD_entropyCompressSequences_internal(
2161
2351
  seqStorePtr, prevEntropy, nextEntropy, cctxParams,
2162
2352
  dst, dstCapacity,
2163
2353
  entropyWorkspace, entropyWkspSize, bmi2);
@@ -2167,13 +2357,13 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr,
2167
2357
  */
2168
2358
  if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
2169
2359
  return 0; /* block not compressed */
2170
- FORWARD_IF_ERROR(cSize, "ZSTD_compressSequences_internal failed");
2360
+ FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSequences_internal failed");
2171
2361
 
2172
2362
  /* Check compressibility */
2173
2363
  { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
2174
2364
  if (cSize >= maxCSize) return 0; /* block not compressed */
2175
2365
  }
2176
-
2366
+ DEBUGLOG(4, "ZSTD_entropyCompressSequences() cSize: %zu\n", cSize);
2177
2367
  return cSize;
2178
2368
  }
2179
2369
 
@@ -2182,7 +2372,7 @@ ZSTD_compressSequences(seqStore_t* seqStorePtr,
2182
2372
  * assumption : strat is a valid strategy */
2183
2373
  ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
2184
2374
  {
2185
- static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = {
2375
+ static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = {
2186
2376
  { ZSTD_compressBlock_fast /* default for 0 */,
2187
2377
  ZSTD_compressBlock_fast,
2188
2378
  ZSTD_compressBlock_doubleFast,
@@ -2212,7 +2402,17 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo
2212
2402
  ZSTD_compressBlock_btlazy2_dictMatchState,
2213
2403
  ZSTD_compressBlock_btopt_dictMatchState,
2214
2404
  ZSTD_compressBlock_btultra_dictMatchState,
2215
- ZSTD_compressBlock_btultra_dictMatchState }
2405
+ ZSTD_compressBlock_btultra_dictMatchState },
2406
+ { NULL /* default for 0 */,
2407
+ NULL,
2408
+ NULL,
2409
+ ZSTD_compressBlock_greedy_dedicatedDictSearch,
2410
+ ZSTD_compressBlock_lazy_dedicatedDictSearch,
2411
+ ZSTD_compressBlock_lazy2_dedicatedDictSearch,
2412
+ NULL,
2413
+ NULL,
2414
+ NULL,
2415
+ NULL }
2216
2416
  };
2217
2417
  ZSTD_blockCompressor selectedCompressor;
2218
2418
  ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
@@ -2226,7 +2426,7 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMo
2226
2426
  static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
2227
2427
  const BYTE* anchor, size_t lastLLSize)
2228
2428
  {
2229
- memcpy(seqStorePtr->lit, anchor, lastLLSize);
2429
+ ZSTD_memcpy(seqStorePtr->lit, anchor, lastLLSize);
2230
2430
  seqStorePtr->lit += lastLLSize;
2231
2431
  }
2232
2432
 
@@ -2247,7 +2447,11 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2247
2447
  /* Assert that we have correctly flushed the ctx params into the ms's copy */
2248
2448
  ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams);
2249
2449
  if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
2250
- ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
2450
+ if (zc->appliedParams.cParams.strategy >= ZSTD_btopt) {
2451
+ ZSTD_ldm_skipRawSeqStoreBytes(&zc->externSeqStore, srcSize);
2452
+ } else {
2453
+ ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
2454
+ }
2251
2455
  return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */
2252
2456
  }
2253
2457
  ZSTD_resetSeqStore(&(zc->seqStore));
@@ -2263,10 +2467,10 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2263
2467
  /* limited update after a very long match */
2264
2468
  { const BYTE* const base = ms->window.base;
2265
2469
  const BYTE* const istart = (const BYTE*)src;
2266
- const U32 current = (U32)(istart-base);
2470
+ const U32 curr = (U32)(istart-base);
2267
2471
  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));
2472
+ if (curr > ms->nextToUpdate + 384)
2473
+ ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384));
2270
2474
  }
2271
2475
 
2272
2476
  /* select and store sequences */
@@ -2286,7 +2490,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2286
2490
  src, srcSize);
2287
2491
  assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
2288
2492
  } else if (zc->appliedParams.ldmParams.enableLdm) {
2289
- rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
2493
+ rawSeqStore_t ldmSeqStore = kNullRawSeqStore;
2290
2494
 
2291
2495
  ldmSeqStore.seq = zc->ldmSequences;
2292
2496
  ldmSeqStore.capacity = zc->maxNbLdmSequences;
@@ -2303,6 +2507,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2303
2507
  assert(ldmSeqStore.pos == ldmSeqStore.size);
2304
2508
  } else { /* not long range mode */
2305
2509
  ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
2510
+ ms->ldmSeqStore = NULL;
2306
2511
  lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
2307
2512
  }
2308
2513
  { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
@@ -2314,17 +2519,25 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2314
2519
  static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
2315
2520
  {
2316
2521
  const seqStore_t* seqStore = ZSTD_getSeqStore(zc);
2317
- const seqDef* seqs = seqStore->sequencesStart;
2318
- size_t seqsSize = seqStore->sequences - seqs;
2522
+ const seqDef* seqStoreSeqs = seqStore->sequencesStart;
2523
+ size_t seqStoreSeqSize = seqStore->sequences - seqStoreSeqs;
2524
+ size_t seqStoreLiteralsSize = (size_t)(seqStore->lit - seqStore->litStart);
2525
+ size_t literalsRead = 0;
2526
+ size_t lastLLSize;
2319
2527
 
2320
2528
  ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex];
2321
- size_t i; size_t position; int repIdx;
2529
+ size_t i;
2530
+ repcodes_t updatedRepcodes;
2322
2531
 
2323
2532
  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;
2533
+ /* Ensure we have enough space for last literals "sequence" */
2534
+ assert(zc->seqCollector.maxSequences >= seqStoreSeqSize + 1);
2535
+ ZSTD_memcpy(updatedRepcodes.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t));
2536
+ for (i = 0; i < seqStoreSeqSize; ++i) {
2537
+ U32 rawOffset = seqStoreSeqs[i].offset - ZSTD_REP_NUM;
2538
+ outSeqs[i].litLength = seqStoreSeqs[i].litLength;
2539
+ outSeqs[i].matchLength = seqStoreSeqs[i].matchLength + MINMATCH;
2540
+ outSeqs[i].rep = 0;
2328
2541
 
2329
2542
  if (i == seqStore->longLengthPos) {
2330
2543
  if (seqStore->longLengthID == 1) {
@@ -2334,39 +2547,44 @@ static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
2334
2547
  }
2335
2548
  }
2336
2549
 
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;
2550
+ if (seqStoreSeqs[i].offset <= ZSTD_REP_NUM) {
2551
+ /* Derive the correct offset corresponding to a repcode */
2552
+ outSeqs[i].rep = seqStoreSeqs[i].offset;
2553
+ if (outSeqs[i].litLength != 0) {
2554
+ rawOffset = updatedRepcodes.rep[outSeqs[i].rep - 1];
2555
+ } else {
2556
+ if (outSeqs[i].rep == 3) {
2557
+ rawOffset = updatedRepcodes.rep[0] - 1;
2344
2558
  } else {
2345
- repIdx = (unsigned int)i - 1;
2559
+ rawOffset = updatedRepcodes.rep[outSeqs[i].rep];
2346
2560
  }
2347
- ++outSeqs[i].rep;
2348
- }
2349
- assert(repIdx >= -3);
2350
- outSeqs[i].offset = repIdx >= 0 ? outSeqs[repIdx].offset : repStartValue[-repIdx - 1];
2351
- if (outSeqs[i].rep == 4) {
2352
- --outSeqs[i].offset;
2353
2561
  }
2354
- } else {
2355
- outSeqs[i].offset -= ZSTD_REP_NUM;
2356
2562
  }
2357
-
2358
- position += outSeqs[i].litLength;
2359
- outSeqs[i].matchPos = (unsigned int)position;
2360
- position += outSeqs[i].matchLength;
2563
+ outSeqs[i].offset = rawOffset;
2564
+ /* seqStoreSeqs[i].offset == offCode+1, and ZSTD_updateRep() expects offCode
2565
+ so we provide seqStoreSeqs[i].offset - 1 */
2566
+ updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep,
2567
+ seqStoreSeqs[i].offset - 1,
2568
+ seqStoreSeqs[i].litLength == 0);
2569
+ literalsRead += outSeqs[i].litLength;
2361
2570
  }
2362
- zc->seqCollector.seqIndex += seqsSize;
2571
+ /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0.
2572
+ * If there are no last literals, then we'll emit (of: 0, ml: 0, ll: 0), which is a marker
2573
+ * for the block boundary, according to the API.
2574
+ */
2575
+ assert(seqStoreLiteralsSize >= literalsRead);
2576
+ lastLLSize = seqStoreLiteralsSize - literalsRead;
2577
+ outSeqs[i].litLength = (U32)lastLLSize;
2578
+ outSeqs[i].matchLength = outSeqs[i].offset = outSeqs[i].rep = 0;
2579
+ seqStoreSeqSize++;
2580
+ zc->seqCollector.seqIndex += seqStoreSeqSize;
2363
2581
  }
2364
2582
 
2365
- size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
2366
- size_t outSeqsSize, const void* src, size_t srcSize)
2583
+ size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
2584
+ size_t outSeqsSize, const void* src, size_t srcSize)
2367
2585
  {
2368
2586
  const size_t dstCapacity = ZSTD_compressBound(srcSize);
2369
- void* dst = ZSTD_malloc(dstCapacity, ZSTD_defaultCMem);
2587
+ void* dst = ZSTD_customMalloc(dstCapacity, ZSTD_defaultCMem);
2370
2588
  SeqCollector seqCollector;
2371
2589
 
2372
2590
  RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!");
@@ -2378,16 +2596,47 @@ size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
2378
2596
  zc->seqCollector = seqCollector;
2379
2597
 
2380
2598
  ZSTD_compress2(zc, dst, dstCapacity, src, srcSize);
2381
- ZSTD_free(dst, ZSTD_defaultCMem);
2599
+ ZSTD_customFree(dst, ZSTD_defaultCMem);
2382
2600
  return zc->seqCollector.seqIndex;
2383
2601
  }
2384
2602
 
2385
- /* Returns true if the given block is a RLE block */
2386
- static int ZSTD_isRLE(const BYTE *ip, size_t length) {
2603
+ size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize) {
2604
+ size_t in = 0;
2605
+ size_t out = 0;
2606
+ for (; in < seqsSize; ++in) {
2607
+ if (sequences[in].offset == 0 && sequences[in].matchLength == 0) {
2608
+ if (in != seqsSize - 1) {
2609
+ sequences[in+1].litLength += sequences[in].litLength;
2610
+ }
2611
+ } else {
2612
+ sequences[out] = sequences[in];
2613
+ ++out;
2614
+ }
2615
+ }
2616
+ return out;
2617
+ }
2618
+
2619
+ /* Unrolled loop to read four size_ts of input at a time. Returns 1 if is RLE, 0 if not. */
2620
+ static int ZSTD_isRLE(const BYTE* src, size_t length) {
2621
+ const BYTE* ip = src;
2622
+ const BYTE value = ip[0];
2623
+ const size_t valueST = (size_t)((U64)value * 0x0101010101010101ULL);
2624
+ const size_t unrollSize = sizeof(size_t) * 4;
2625
+ const size_t unrollMask = unrollSize - 1;
2626
+ const size_t prefixLength = length & unrollMask;
2387
2627
  size_t i;
2388
- if (length < 2) return 1;
2389
- for (i = 1; i < length; ++i) {
2390
- if (ip[0] != ip[i]) return 0;
2628
+ size_t u;
2629
+ if (length == 1) return 1;
2630
+ /* Check if prefix is RLE first before using unrolled loop */
2631
+ if (prefixLength && ZSTD_count(ip+1, ip, ip+prefixLength) != prefixLength-1) {
2632
+ return 0;
2633
+ }
2634
+ for (i = prefixLength; i != length; i += unrollSize) {
2635
+ for (u = 0; u < unrollSize; u += sizeof(size_t)) {
2636
+ if (MEM_readST(ip + i + u) != valueST) {
2637
+ return 0;
2638
+ }
2639
+ }
2391
2640
  }
2392
2641
  return 1;
2393
2642
  }
@@ -2434,18 +2683,25 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
2434
2683
 
2435
2684
  if (zc->seqCollector.collectSequences) {
2436
2685
  ZSTD_copyBlockSequences(zc);
2686
+ ZSTD_confirmRepcodesAndEntropyTables(zc);
2437
2687
  return 0;
2438
2688
  }
2439
2689
 
2440
2690
  /* encode sequences and literals */
2441
- cSize = ZSTD_compressSequences(&zc->seqStore,
2691
+ cSize = ZSTD_entropyCompressSequences(&zc->seqStore,
2442
2692
  &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
2443
2693
  &zc->appliedParams,
2444
2694
  dst, dstCapacity,
2445
2695
  srcSize,
2446
- zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
2696
+ zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
2447
2697
  zc->bmi2);
2448
2698
 
2699
+ if (zc->seqCollector.collectSequences) {
2700
+ ZSTD_copyBlockSequences(zc);
2701
+ return 0;
2702
+ }
2703
+
2704
+
2449
2705
  if (frame &&
2450
2706
  /* We don't want to emit our first block as a RLE even if it qualifies because
2451
2707
  * doing so will cause the decoder (cli only) to throw a "should consume all input error."
@@ -2593,7 +2849,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
2593
2849
 
2594
2850
  assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX);
2595
2851
 
2596
- DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
2852
+ DEBUGLOG(4, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
2597
2853
  if (cctx->appliedParams.fParams.checksumFlag && srcSize)
2598
2854
  XXH64_update(&cctx->xxhState, src, srcSize);
2599
2855
 
@@ -2673,7 +2929,6 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
2673
2929
  "dst buf is too small to fit worst-case frame header size.");
2674
2930
  DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
2675
2931
  !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode);
2676
-
2677
2932
  if (params->format == ZSTD_f_zstd1) {
2678
2933
  MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
2679
2934
  pos = 4;
@@ -2725,6 +2980,7 @@ size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSe
2725
2980
  cctx->externSeqStore.size = nbSeq;
2726
2981
  cctx->externSeqStore.capacity = nbSeq;
2727
2982
  cctx->externSeqStore.pos = 0;
2983
+ cctx->externSeqStore.posInSequence = 0;
2728
2984
  return 0;
2729
2985
  }
2730
2986
 
@@ -2862,8 +3118,12 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
2862
3118
  case ZSTD_greedy:
2863
3119
  case ZSTD_lazy:
2864
3120
  case ZSTD_lazy2:
2865
- if (chunk >= HASH_READ_SIZE)
3121
+ if (chunk >= HASH_READ_SIZE && ms->dedicatedDictSearch) {
3122
+ assert(chunk == remaining); /* must load everything in one go */
3123
+ ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, ichunk-HASH_READ_SIZE);
3124
+ } else if (chunk >= HASH_READ_SIZE) {
2866
3125
  ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE);
3126
+ }
2867
3127
  break;
2868
3128
 
2869
3129
  case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
@@ -2887,22 +3147,28 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
2887
3147
 
2888
3148
 
2889
3149
  /* 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) {
3150
+ * when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check
3151
+ * and only dictionaries with 100% valid symbols can be assumed valid.
3152
+ */
3153
+ static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue)
3154
+ {
2894
3155
  U32 s;
2895
- RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted, "dict fse tables don't have all symbols");
3156
+ if (dictMaxSymbolValue < maxSymbolValue) {
3157
+ return FSE_repeat_check;
3158
+ }
2896
3159
  for (s = 0; s <= maxSymbolValue; ++s) {
2897
- RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted, "dict fse tables don't have all symbols");
3160
+ if (normalizedCounter[s] == 0) {
3161
+ return FSE_repeat_check;
3162
+ }
2898
3163
  }
2899
- return 0;
3164
+ return FSE_repeat_valid;
2900
3165
  }
2901
3166
 
2902
3167
  size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2903
- short* offcodeNCount, unsigned* offcodeMaxValue,
2904
3168
  const void* const dict, size_t dictSize)
2905
3169
  {
3170
+ short offcodeNCount[MaxOff+1];
3171
+ unsigned offcodeMaxValue = MaxOff;
2906
3172
  const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */
2907
3173
  const BYTE* const dictEnd = dictPtr + dictSize;
2908
3174
  dictPtr += 8;
@@ -2924,16 +3190,16 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2924
3190
  }
2925
3191
 
2926
3192
  { unsigned offcodeLog;
2927
- size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
3193
+ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
2928
3194
  RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
2929
3195
  RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
2930
- /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
2931
3196
  /* fill all offset symbols to avoid garbage at end of table */
2932
3197
  RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
2933
3198
  bs->entropy.fse.offcodeCTable,
2934
3199
  offcodeNCount, MaxOff, offcodeLog,
2935
3200
  workspace, HUF_WORKSPACE_SIZE)),
2936
3201
  dictionary_corrupted, "");
3202
+ /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
2937
3203
  dictPtr += offcodeHeaderSize;
2938
3204
  }
2939
3205
 
@@ -2942,13 +3208,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2942
3208
  size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
2943
3209
  RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
2944
3210
  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
3211
  RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
2948
3212
  bs->entropy.fse.matchlengthCTable,
2949
3213
  matchlengthNCount, matchlengthMaxValue, matchlengthLog,
2950
3214
  workspace, HUF_WORKSPACE_SIZE)),
2951
3215
  dictionary_corrupted, "");
3216
+ bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML);
2952
3217
  dictPtr += matchlengthHeaderSize;
2953
3218
  }
2954
3219
 
@@ -2957,13 +3222,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2957
3222
  size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
2958
3223
  RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
2959
3224
  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
3225
  RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
2963
3226
  bs->entropy.fse.litlengthCTable,
2964
3227
  litlengthNCount, litlengthMaxValue, litlengthLog,
2965
3228
  workspace, HUF_WORKSPACE_SIZE)),
2966
3229
  dictionary_corrupted, "");
3230
+ bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL);
2967
3231
  dictPtr += litlengthHeaderSize;
2968
3232
  }
2969
3233
 
@@ -2973,6 +3237,22 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
2973
3237
  bs->rep[2] = MEM_readLE32(dictPtr+8);
2974
3238
  dictPtr += 12;
2975
3239
 
3240
+ { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3241
+ U32 offcodeMax = MaxOff;
3242
+ if (dictContentSize <= ((U32)-1) - 128 KB) {
3243
+ U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
3244
+ offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
3245
+ }
3246
+ /* All offset values <= dictContentSize + 128 KB must be representable for a valid table */
3247
+ bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff));
3248
+
3249
+ /* All repCodes must be <= dictContentSize and != 0 */
3250
+ { U32 u;
3251
+ for (u=0; u<3; u++) {
3252
+ RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, "");
3253
+ RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, "");
3254
+ } } }
3255
+
2976
3256
  return dictPtr - (const BYTE*)dict;
2977
3257
  }
2978
3258
 
@@ -2995,8 +3275,6 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
2995
3275
  {
2996
3276
  const BYTE* dictPtr = (const BYTE*)dict;
2997
3277
  const BYTE* const dictEnd = dictPtr + dictSize;
2998
- short offcodeNCount[MaxOff+1];
2999
- unsigned offcodeMaxValue = MaxOff;
3000
3278
  size_t dictID;
3001
3279
  size_t eSize;
3002
3280
 
@@ -3005,32 +3283,16 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
3005
3283
  assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
3006
3284
 
3007
3285
  dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ );
3008
- eSize = ZSTD_loadCEntropy(bs, workspace, offcodeNCount, &offcodeMaxValue, dict, dictSize);
3286
+ eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize);
3009
3287
  FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed");
3010
3288
  dictPtr += eSize;
3011
3289
 
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;
3290
+ {
3291
+ size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3030
3292
  FORWARD_IF_ERROR(ZSTD_loadDictionaryContent(
3031
3293
  ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), "");
3032
- return dictID;
3033
3294
  }
3295
+ return dictID;
3034
3296
  }
3035
3297
 
3036
3298
  /** ZSTD_compress_insertDictionary() :
@@ -3074,7 +3336,7 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
3074
3336
  }
3075
3337
 
3076
3338
  #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB)
3077
- #define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6)
3339
+ #define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6ULL)
3078
3340
 
3079
3341
  /*! ZSTD_compressBegin_internal() :
3080
3342
  * @return : 0, or an error code */
@@ -3106,7 +3368,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
3106
3368
  ZSTD_compress_insertDictionary(
3107
3369
  cctx->blockState.prevCBlock, &cctx->blockState.matchState,
3108
3370
  &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent,
3109
- cdict->dictContentSize, dictContentType, dtlm,
3371
+ cdict->dictContentSize, cdict->dictContentType, dtlm,
3110
3372
  cctx->entropyWorkspace)
3111
3373
  : ZSTD_compress_insertDictionary(
3112
3374
  cctx->blockState.prevCBlock, &cctx->blockState.matchState,
@@ -3153,7 +3415,7 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
3153
3415
 
3154
3416
  size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
3155
3417
  {
3156
- ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3418
+ ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict);
3157
3419
  ZSTD_CCtx_params const cctxParams =
3158
3420
  ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
3159
3421
  DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize);
@@ -3234,7 +3496,6 @@ size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
3234
3496
  return cSize + endResult;
3235
3497
  }
3236
3498
 
3237
-
3238
3499
  static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
3239
3500
  void* dst, size_t dstCapacity,
3240
3501
  const void* src, size_t srcSize,
@@ -3287,7 +3548,7 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
3287
3548
  const void* dict, size_t dictSize,
3288
3549
  int compressionLevel)
3289
3550
  {
3290
- ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0);
3551
+ ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict);
3291
3552
  ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, &params);
3292
3553
  DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize);
3293
3554
  assert(params.fParams.contentSizeFlag == 1);
@@ -3309,10 +3570,17 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity,
3309
3570
  int compressionLevel)
3310
3571
  {
3311
3572
  size_t result;
3573
+ #if ZSTD_COMPRESS_HEAPMODE
3574
+ ZSTD_CCtx* cctx = ZSTD_createCCtx();
3575
+ RETURN_ERROR_IF(!cctx, memory_allocation, "ZSTD_createCCtx failed");
3576
+ result = ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel);
3577
+ ZSTD_freeCCtx(cctx);
3578
+ #else
3312
3579
  ZSTD_CCtx ctxBody;
3313
3580
  ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem);
3314
3581
  result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
3315
3582
  ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */
3583
+ #endif
3316
3584
  return result;
3317
3585
  }
3318
3586
 
@@ -3335,7 +3603,7 @@ size_t ZSTD_estimateCDictSize_advanced(
3335
3603
 
3336
3604
  size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
3337
3605
  {
3338
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3606
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3339
3607
  return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
3340
3608
  }
3341
3609
 
@@ -3353,20 +3621,25 @@ static size_t ZSTD_initCDict_internal(
3353
3621
  const void* dictBuffer, size_t dictSize,
3354
3622
  ZSTD_dictLoadMethod_e dictLoadMethod,
3355
3623
  ZSTD_dictContentType_e dictContentType,
3356
- ZSTD_compressionParameters cParams)
3624
+ ZSTD_CCtx_params params)
3357
3625
  {
3358
3626
  DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType);
3359
- assert(!ZSTD_checkCParams(cParams));
3360
- cdict->matchState.cParams = cParams;
3627
+ assert(!ZSTD_checkCParams(params.cParams));
3628
+ cdict->matchState.cParams = params.cParams;
3629
+ cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch;
3630
+ if (cdict->matchState.dedicatedDictSearch && dictSize > ZSTD_CHUNKSIZE_MAX) {
3631
+ cdict->matchState.dedicatedDictSearch = 0;
3632
+ }
3361
3633
  if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
3362
3634
  cdict->dictContent = dictBuffer;
3363
3635
  } else {
3364
3636
  void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*)));
3365
3637
  RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!");
3366
3638
  cdict->dictContent = internalBuffer;
3367
- memcpy(internalBuffer, dictBuffer, dictSize);
3639
+ ZSTD_memcpy(internalBuffer, dictBuffer, dictSize);
3368
3640
  }
3369
3641
  cdict->dictContentSize = dictSize;
3642
+ cdict->dictContentType = dictContentType;
3370
3643
 
3371
3644
  cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE);
3372
3645
 
@@ -3376,18 +3649,15 @@ static size_t ZSTD_initCDict_internal(
3376
3649
  FORWARD_IF_ERROR(ZSTD_reset_matchState(
3377
3650
  &cdict->matchState,
3378
3651
  &cdict->workspace,
3379
- &cParams,
3652
+ &params.cParams,
3380
3653
  ZSTDcrp_makeClean,
3381
3654
  ZSTDirp_reset,
3382
3655
  ZSTD_resetTarget_CDict), "");
3383
3656
  /* (Maybe) load the dictionary
3384
3657
  * Skips loading the dictionary if it is < 8 bytes.
3385
3658
  */
3386
- { ZSTD_CCtx_params params;
3387
- memset(&params, 0, sizeof(params));
3388
- params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
3659
+ { params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
3389
3660
  params.fParams.contentSizeFlag = 1;
3390
- params.cParams = cParams;
3391
3661
  { size_t const dictID = ZSTD_compress_insertDictionary(
3392
3662
  &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace,
3393
3663
  &params, cdict->dictContent, cdict->dictContentSize,
@@ -3401,13 +3671,11 @@ static size_t ZSTD_initCDict_internal(
3401
3671
  return 0;
3402
3672
  }
3403
3673
 
3404
- ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3674
+ static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize,
3405
3675
  ZSTD_dictLoadMethod_e dictLoadMethod,
3406
- ZSTD_dictContentType_e dictContentType,
3407
3676
  ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
3408
3677
  {
3409
- DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType);
3410
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
3678
+ if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
3411
3679
 
3412
3680
  { size_t const workspaceSize =
3413
3681
  ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) +
@@ -3415,16 +3683,16 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3415
3683
  ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
3416
3684
  (dictLoadMethod == ZSTD_dlm_byRef ? 0
3417
3685
  : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))));
3418
- void* const workspace = ZSTD_malloc(workspaceSize, customMem);
3686
+ void* const workspace = ZSTD_customMalloc(workspaceSize, customMem);
3419
3687
  ZSTD_cwksp ws;
3420
3688
  ZSTD_CDict* cdict;
3421
3689
 
3422
3690
  if (!workspace) {
3423
- ZSTD_free(workspace, customMem);
3691
+ ZSTD_customFree(workspace, customMem);
3424
3692
  return NULL;
3425
3693
  }
3426
3694
 
3427
- ZSTD_cwksp_init(&ws, workspace, workspaceSize);
3695
+ ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_dynamic_alloc);
3428
3696
 
3429
3697
  cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
3430
3698
  assert(cdict != NULL);
@@ -3432,35 +3700,94 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3432
3700
  cdict->customMem = customMem;
3433
3701
  cdict->compressionLevel = 0; /* signals advanced API usage */
3434
3702
 
3435
- if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3436
- dictBuffer, dictSize,
3437
- dictLoadMethod, dictContentType,
3438
- cParams) )) {
3439
- ZSTD_freeCDict(cdict);
3440
- return NULL;
3441
- }
3442
-
3443
3703
  return cdict;
3444
3704
  }
3445
3705
  }
3446
3706
 
3707
+ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3708
+ ZSTD_dictLoadMethod_e dictLoadMethod,
3709
+ ZSTD_dictContentType_e dictContentType,
3710
+ ZSTD_compressionParameters cParams,
3711
+ ZSTD_customMem customMem)
3712
+ {
3713
+ ZSTD_CCtx_params cctxParams;
3714
+ ZSTD_memset(&cctxParams, 0, sizeof(cctxParams));
3715
+ ZSTD_CCtxParams_init(&cctxParams, 0);
3716
+ cctxParams.cParams = cParams;
3717
+ cctxParams.customMem = customMem;
3718
+ return ZSTD_createCDict_advanced2(
3719
+ dictBuffer, dictSize,
3720
+ dictLoadMethod, dictContentType,
3721
+ &cctxParams, customMem);
3722
+ }
3723
+
3724
+ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced2(
3725
+ const void* dict, size_t dictSize,
3726
+ ZSTD_dictLoadMethod_e dictLoadMethod,
3727
+ ZSTD_dictContentType_e dictContentType,
3728
+ const ZSTD_CCtx_params* originalCctxParams,
3729
+ ZSTD_customMem customMem)
3730
+ {
3731
+ ZSTD_CCtx_params cctxParams = *originalCctxParams;
3732
+ ZSTD_compressionParameters cParams;
3733
+ ZSTD_CDict* cdict;
3734
+
3735
+ DEBUGLOG(3, "ZSTD_createCDict_advanced2, mode %u", (unsigned)dictContentType);
3736
+ if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
3737
+
3738
+ if (cctxParams.enableDedicatedDictSearch) {
3739
+ cParams = ZSTD_dedicatedDictSearch_getCParams(
3740
+ cctxParams.compressionLevel, dictSize);
3741
+ ZSTD_overrideCParams(&cParams, &cctxParams.cParams);
3742
+ } else {
3743
+ cParams = ZSTD_getCParamsFromCCtxParams(
3744
+ &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3745
+ }
3746
+
3747
+ if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) {
3748
+ /* Fall back to non-DDSS params */
3749
+ cctxParams.enableDedicatedDictSearch = 0;
3750
+ cParams = ZSTD_getCParamsFromCCtxParams(
3751
+ &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3752
+ }
3753
+
3754
+ cctxParams.cParams = cParams;
3755
+
3756
+ cdict = ZSTD_createCDict_advanced_internal(dictSize,
3757
+ dictLoadMethod, cctxParams.cParams,
3758
+ customMem);
3759
+
3760
+ if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3761
+ dict, dictSize,
3762
+ dictLoadMethod, dictContentType,
3763
+ cctxParams) )) {
3764
+ ZSTD_freeCDict(cdict);
3765
+ return NULL;
3766
+ }
3767
+
3768
+ return cdict;
3769
+ }
3770
+
3447
3771
  ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3448
3772
  {
3449
- ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3450
- ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize,
3773
+ ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3774
+ ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize,
3451
3775
  ZSTD_dlm_byCopy, ZSTD_dct_auto,
3452
3776
  cParams, ZSTD_defaultCMem);
3453
3777
  if (cdict)
3454
- cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
3778
+ cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
3455
3779
  return cdict;
3456
3780
  }
3457
3781
 
3458
3782
  ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3459
3783
  {
3460
- ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
3461
- return ZSTD_createCDict_advanced(dict, dictSize,
3784
+ ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3785
+ ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize,
3462
3786
  ZSTD_dlm_byRef, ZSTD_dct_auto,
3463
3787
  cParams, ZSTD_defaultCMem);
3788
+ if (cdict)
3789
+ cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
3790
+ return cdict;
3464
3791
  }
3465
3792
 
3466
3793
  size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
@@ -3470,7 +3797,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3470
3797
  int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict);
3471
3798
  ZSTD_cwksp_free(&cdict->workspace, cMem);
3472
3799
  if (!cdictInWorkspace) {
3473
- ZSTD_free(cdict, cMem);
3800
+ ZSTD_customFree(cdict, cMem);
3474
3801
  }
3475
3802
  return 0;
3476
3803
  }
@@ -3503,12 +3830,13 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
3503
3830
  + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
3504
3831
  + matchStateSize;
3505
3832
  ZSTD_CDict* cdict;
3833
+ ZSTD_CCtx_params params;
3506
3834
 
3507
3835
  if ((size_t)workspace & 7) return NULL; /* 8-aligned */
3508
3836
 
3509
3837
  {
3510
3838
  ZSTD_cwksp ws;
3511
- ZSTD_cwksp_init(&ws, workspace, workspaceSize);
3839
+ ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc);
3512
3840
  cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
3513
3841
  if (cdict == NULL) return NULL;
3514
3842
  ZSTD_cwksp_move(&cdict->workspace, &ws);
@@ -3518,10 +3846,13 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
3518
3846
  (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize));
3519
3847
  if (workspaceSize < neededSize) return NULL;
3520
3848
 
3849
+ ZSTD_CCtxParams_init(&params, 0);
3850
+ params.cParams = cParams;
3851
+
3521
3852
  if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3522
3853
  dict, dictSize,
3523
3854
  dictLoadMethod, dictContentType,
3524
- cParams) ))
3855
+ params) ))
3525
3856
  return NULL;
3526
3857
 
3527
3858
  return cdict;
@@ -3533,6 +3864,17 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
3533
3864
  return cdict->matchState.cParams;
3534
3865
  }
3535
3866
 
3867
+ /*! ZSTD_getDictID_fromCDict() :
3868
+ * Provides the dictID of the dictionary loaded into `cdict`.
3869
+ * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
3870
+ * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
3871
+ unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict)
3872
+ {
3873
+ if (cdict==NULL) return 0;
3874
+ return cdict->dictID;
3875
+ }
3876
+
3877
+
3536
3878
  /* ZSTD_compressBegin_usingCDict_advanced() :
3537
3879
  * cdict must be != NULL */
3538
3880
  size_t ZSTD_compressBegin_usingCDict_advanced(
@@ -3640,32 +3982,12 @@ size_t ZSTD_CStreamOutSize(void)
3640
3982
  return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
3641
3983
  }
3642
3984
 
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)
3985
+ static ZSTD_cParamMode_e ZSTD_getCParamMode(ZSTD_CDict const* cdict, ZSTD_CCtx_params const* params, U64 pledgedSrcSize)
3647
3986
  {
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 */
3987
+ if (cdict != NULL && ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize))
3988
+ return ZSTD_cpm_attachDict;
3989
+ else
3990
+ return ZSTD_cpm_noAttachDict;
3669
3991
  }
3670
3992
 
3671
3993
  /* ZSTD_resetCStream():
@@ -3815,12 +4137,17 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3815
4137
 
3816
4138
  /* check expectations */
3817
4139
  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);
4140
+ if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) {
4141
+ assert(zcs->inBuff != NULL);
4142
+ assert(zcs->inBuffSize > 0);
4143
+ }
4144
+ if (zcs->appliedParams.outBufferMode == ZSTD_bm_buffered) {
4145
+ assert(zcs->outBuff != NULL);
4146
+ assert(zcs->outBuffSize > 0);
4147
+ }
3822
4148
  assert(output->pos <= output->size);
3823
4149
  assert(input->pos <= input->size);
4150
+ assert((U32)flushMode <= (U32)ZSTD_e_end);
3824
4151
 
3825
4152
  while (someMoreWork) {
3826
4153
  switch(zcs->streamStage)
@@ -3830,7 +4157,8 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3830
4157
 
3831
4158
  case zcss_load:
3832
4159
  if ( (flushMode == ZSTD_e_end)
3833
- && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */
4160
+ && ( (size_t)(oend-op) >= ZSTD_compressBound(iend-ip) /* Enough output space */
4161
+ || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) /* OR we are allowed to return dstSizeTooSmall */
3834
4162
  && (zcs->inBuffPos == 0) ) {
3835
4163
  /* shortcut to compression pass directly into output buffer */
3836
4164
  size_t const cSize = ZSTD_compressEnd(zcs,
@@ -3843,8 +4171,9 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3843
4171
  ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
3844
4172
  someMoreWork = 0; break;
3845
4173
  }
3846
- /* complete loading into inBuffer */
3847
- { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
4174
+ /* complete loading into inBuffer in buffered mode */
4175
+ if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) {
4176
+ size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3848
4177
  size_t const loaded = ZSTD_limitCopy(
3849
4178
  zcs->inBuff + zcs->inBuffPos, toLoad,
3850
4179
  ip, iend-ip);
@@ -3864,31 +4193,49 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3864
4193
  }
3865
4194
  /* compress current block (note : this stage cannot be stopped in the middle) */
3866
4195
  DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
3867
- { void* cDst;
4196
+ { int const inputBuffered = (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered);
4197
+ void* cDst;
3868
4198
  size_t cSize;
3869
- size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3870
4199
  size_t oSize = oend-op;
3871
- unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
3872
- if (oSize >= ZSTD_compressBound(iSize))
4200
+ size_t const iSize = inputBuffered
4201
+ ? zcs->inBuffPos - zcs->inToCompress
4202
+ : MIN((size_t)(iend - ip), zcs->blockSize);
4203
+ if (oSize >= ZSTD_compressBound(iSize) || zcs->appliedParams.outBufferMode == ZSTD_bm_stable)
3873
4204
  cDst = op; /* compress into output buffer, to skip flush stage */
3874
4205
  else
3875
4206
  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;
4207
+ if (inputBuffered) {
4208
+ unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
4209
+ cSize = lastBlock ?
4210
+ ZSTD_compressEnd(zcs, cDst, oSize,
4211
+ zcs->inBuff + zcs->inToCompress, iSize) :
4212
+ ZSTD_compressContinue(zcs, cDst, oSize,
4213
+ zcs->inBuff + zcs->inToCompress, iSize);
4214
+ FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
4215
+ zcs->frameEnded = lastBlock;
4216
+ /* prepare next block */
4217
+ zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
4218
+ if (zcs->inBuffTarget > zcs->inBuffSize)
4219
+ zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
4220
+ DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
4221
+ (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize);
4222
+ if (!lastBlock)
4223
+ assert(zcs->inBuffTarget <= zcs->inBuffSize);
4224
+ zcs->inToCompress = zcs->inBuffPos;
4225
+ } else {
4226
+ unsigned const lastBlock = (ip + iSize == iend);
4227
+ assert(flushMode == ZSTD_e_end /* Already validated */);
4228
+ cSize = lastBlock ?
4229
+ ZSTD_compressEnd(zcs, cDst, oSize, ip, iSize) :
4230
+ ZSTD_compressContinue(zcs, cDst, oSize, ip, iSize);
4231
+ /* Consume the input prior to error checking to mirror buffered mode. */
4232
+ if (iSize > 0)
4233
+ ip += iSize;
4234
+ FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
4235
+ zcs->frameEnded = lastBlock;
4236
+ if (lastBlock)
4237
+ assert(ip == iend);
4238
+ }
3892
4239
  if (cDst == op) { /* no need to flush */
3893
4240
  op += cSize;
3894
4241
  if (zcs->frameEnded) {
@@ -3905,6 +4252,7 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3905
4252
  /* fall-through */
3906
4253
  case zcss_flush:
3907
4254
  DEBUGLOG(5, "flush stage");
4255
+ assert(zcs->appliedParams.outBufferMode == ZSTD_bm_buffered);
3908
4256
  { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3909
4257
  size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op),
3910
4258
  zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
@@ -3959,6 +4307,116 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf
3959
4307
  return ZSTD_nextInputSizeHint_MTorST(zcs);
3960
4308
  }
3961
4309
 
4310
+ /* After a compression call set the expected input/output buffer.
4311
+ * This is validated at the start of the next compression call.
4312
+ */
4313
+ static void ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, ZSTD_outBuffer const* output, ZSTD_inBuffer const* input)
4314
+ {
4315
+ if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) {
4316
+ cctx->expectedInBuffer = *input;
4317
+ }
4318
+ if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) {
4319
+ cctx->expectedOutBufferSize = output->size - output->pos;
4320
+ }
4321
+ }
4322
+
4323
+ /* Validate that the input/output buffers match the expectations set by
4324
+ * ZSTD_setBufferExpectations.
4325
+ */
4326
+ static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx,
4327
+ ZSTD_outBuffer const* output,
4328
+ ZSTD_inBuffer const* input,
4329
+ ZSTD_EndDirective endOp)
4330
+ {
4331
+ if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) {
4332
+ ZSTD_inBuffer const expect = cctx->expectedInBuffer;
4333
+ if (expect.src != input->src || expect.pos != input->pos || expect.size != input->size)
4334
+ RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer enabled but input differs!");
4335
+ if (endOp != ZSTD_e_end)
4336
+ RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer can only be used with ZSTD_e_end!");
4337
+ }
4338
+ if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) {
4339
+ size_t const outBufferSize = output->size - output->pos;
4340
+ if (cctx->expectedOutBufferSize != outBufferSize)
4341
+ RETURN_ERROR(dstBuffer_wrong, "ZSTD_c_stableOutBuffer enabled but output size differs!");
4342
+ }
4343
+ return 0;
4344
+ }
4345
+
4346
+ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
4347
+ ZSTD_EndDirective endOp,
4348
+ size_t inSize) {
4349
+ ZSTD_CCtx_params params = cctx->requestedParams;
4350
+ ZSTD_prefixDict const prefixDict = cctx->prefixDict;
4351
+ FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */
4352
+ ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
4353
+ assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
4354
+ if (cctx->cdict)
4355
+ params.compressionLevel = cctx->cdict->compressionLevel; /* let cdict take priority in terms of compression level */
4356
+ DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
4357
+ if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-fix pledgedSrcSize */
4358
+ {
4359
+ size_t const dictSize = prefixDict.dict
4360
+ ? prefixDict.dictSize
4361
+ : (cctx->cdict ? cctx->cdict->dictContentSize : 0);
4362
+ ZSTD_cParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, &params, cctx->pledgedSrcSizePlusOne - 1);
4363
+ params.cParams = ZSTD_getCParamsFromCCtxParams(
4364
+ &params, cctx->pledgedSrcSizePlusOne-1,
4365
+ dictSize, mode);
4366
+ }
4367
+
4368
+ if (ZSTD_CParams_shouldEnableLdm(&params.cParams)) {
4369
+ /* Enable LDM by default for optimal parser and window size >= 128MB */
4370
+ DEBUGLOG(4, "LDM enabled by default (window size >= 128MB, strategy >= btopt)");
4371
+ params.ldmParams.enableLdm = 1;
4372
+ }
4373
+
4374
+ #ifdef ZSTD_MULTITHREAD
4375
+ if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
4376
+ params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
4377
+ }
4378
+ if (params.nbWorkers > 0) {
4379
+ /* mt context creation */
4380
+ if (cctx->mtctx == NULL) {
4381
+ DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u",
4382
+ params.nbWorkers);
4383
+ cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem, cctx->pool);
4384
+ RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!");
4385
+ }
4386
+ /* mt compression */
4387
+ DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
4388
+ FORWARD_IF_ERROR( ZSTDMT_initCStream_internal(
4389
+ cctx->mtctx,
4390
+ prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
4391
+ cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , "");
4392
+ cctx->streamStage = zcss_load;
4393
+ cctx->appliedParams = params;
4394
+ } else
4395
+ #endif
4396
+ { U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1;
4397
+ assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
4398
+ FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
4399
+ prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast,
4400
+ cctx->cdict,
4401
+ &params, pledgedSrcSize,
4402
+ ZSTDb_buffered) , "");
4403
+ assert(cctx->appliedParams.nbWorkers == 0);
4404
+ cctx->inToCompress = 0;
4405
+ cctx->inBuffPos = 0;
4406
+ if (cctx->appliedParams.inBufferMode == ZSTD_bm_buffered) {
4407
+ /* for small input: avoid automatic flush on reaching end of block, since
4408
+ * it would require to add a 3-bytes null block to end frame
4409
+ */
4410
+ cctx->inBuffTarget = cctx->blockSize + (cctx->blockSize == pledgedSrcSize);
4411
+ } else {
4412
+ cctx->inBuffTarget = 0;
4413
+ }
4414
+ cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
4415
+ cctx->streamStage = zcss_load;
4416
+ cctx->frameEnded = 0;
4417
+ }
4418
+ return 0;
4419
+ }
3962
4420
 
3963
4421
  size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
3964
4422
  ZSTD_outBuffer* output,
@@ -3967,82 +4425,65 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
3967
4425
  {
3968
4426
  DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
3969
4427
  /* 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);
4428
+ RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer");
4429
+ RETURN_ERROR_IF(input->pos > input->size, srcSize_wrong, "invalid input buffer");
4430
+ RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective");
4431
+ assert(cctx != NULL);
3973
4432
 
3974
4433
  /* transparent initialization stage */
3975
4434
  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
- } }
4435
+ FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, endOp, input->size), "CompressStream2 initialization failed");
4436
+ ZSTD_setBufferExpectations(cctx, output, input); /* Set initial buffer expectations now that we've initialized */
4437
+ }
4016
4438
  /* end of transparent initialization stage */
4017
4439
 
4440
+ FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers");
4018
4441
  /* compression stage */
4019
4442
  #ifdef ZSTD_MULTITHREAD
4020
4443
  if (cctx->appliedParams.nbWorkers > 0) {
4021
- int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end);
4022
4444
  size_t flushMin;
4023
- assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */);
4024
4445
  if (cctx->cParamsChanged) {
4025
4446
  ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
4026
4447
  cctx->cParamsChanged = 0;
4027
4448
  }
4028
- do {
4449
+ for (;;) {
4450
+ size_t const ipos = input->pos;
4451
+ size_t const opos = output->pos;
4029
4452
  flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
4030
4453
  if ( ZSTD_isError(flushMin)
4031
4454
  || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
4032
4455
  ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
4033
4456
  }
4034
4457
  FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed");
4035
- } while (forceMaxProgress && flushMin != 0 && output->pos < output->size);
4458
+
4459
+ if (endOp == ZSTD_e_continue) {
4460
+ /* We only require some progress with ZSTD_e_continue, not maximal progress.
4461
+ * We're done if we've consumed or produced any bytes, or either buffer is
4462
+ * full.
4463
+ */
4464
+ if (input->pos != ipos || output->pos != opos || input->pos == input->size || output->pos == output->size)
4465
+ break;
4466
+ } else {
4467
+ assert(endOp == ZSTD_e_flush || endOp == ZSTD_e_end);
4468
+ /* We require maximal progress. We're done when the flush is complete or the
4469
+ * output buffer is full.
4470
+ */
4471
+ if (flushMin == 0 || output->pos == output->size)
4472
+ break;
4473
+ }
4474
+ }
4036
4475
  DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic");
4037
4476
  /* Either we don't require maximum forward progress, we've finished the
4038
4477
  * flush, or we are out of output space.
4039
4478
  */
4040
- assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size);
4479
+ assert(endOp == ZSTD_e_continue || flushMin == 0 || output->pos == output->size);
4480
+ ZSTD_setBufferExpectations(cctx, output, input);
4041
4481
  return flushMin;
4042
4482
  }
4043
4483
  #endif
4044
4484
  FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , "");
4045
4485
  DEBUGLOG(5, "completed ZSTD_compressStream2");
4486
+ ZSTD_setBufferExpectations(cctx, output, input);
4046
4487
  return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
4047
4488
  }
4048
4489
 
@@ -4065,14 +4506,22 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx,
4065
4506
  void* dst, size_t dstCapacity,
4066
4507
  const void* src, size_t srcSize)
4067
4508
  {
4509
+ ZSTD_bufferMode_e const originalInBufferMode = cctx->requestedParams.inBufferMode;
4510
+ ZSTD_bufferMode_e const originalOutBufferMode = cctx->requestedParams.outBufferMode;
4068
4511
  DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize);
4069
4512
  ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
4513
+ /* Enable stable input/output buffers. */
4514
+ cctx->requestedParams.inBufferMode = ZSTD_bm_stable;
4515
+ cctx->requestedParams.outBufferMode = ZSTD_bm_stable;
4070
4516
  { size_t oPos = 0;
4071
4517
  size_t iPos = 0;
4072
4518
  size_t const result = ZSTD_compressStream2_simpleArgs(cctx,
4073
4519
  dst, dstCapacity, &oPos,
4074
4520
  src, srcSize, &iPos,
4075
4521
  ZSTD_e_end);
4522
+ /* Reset to the original values. */
4523
+ cctx->requestedParams.inBufferMode = originalInBufferMode;
4524
+ cctx->requestedParams.outBufferMode = originalOutBufferMode;
4076
4525
  FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed");
4077
4526
  if (result != 0) { /* compression not completed, due to lack of output space */
4078
4527
  assert(oPos == dstCapacity);
@@ -4083,6 +4532,409 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx,
4083
4532
  }
4084
4533
  }
4085
4534
 
4535
+ typedef struct {
4536
+ U32 idx; /* Index in array of ZSTD_Sequence */
4537
+ U32 posInSequence; /* Position within sequence at idx */
4538
+ size_t posInSrc; /* Number of bytes given by sequences provided so far */
4539
+ } ZSTD_sequencePosition;
4540
+
4541
+ /* Returns a ZSTD error code if sequence is not valid */
4542
+ static size_t ZSTD_validateSequence(U32 offCode, U32 matchLength,
4543
+ size_t posInSrc, U32 windowLog, size_t dictSize, U32 minMatch) {
4544
+ size_t offsetBound;
4545
+ U32 windowSize = 1 << windowLog;
4546
+ /* posInSrc represents the amount of data the the decoder would decode up to this point.
4547
+ * As long as the amount of data decoded is less than or equal to window size, offsets may be
4548
+ * larger than the total length of output decoded in order to reference the dict, even larger than
4549
+ * window size. After output surpasses windowSize, we're limited to windowSize offsets again.
4550
+ */
4551
+ offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize;
4552
+ RETURN_ERROR_IF(offCode > offsetBound + ZSTD_REP_MOVE, corruption_detected, "Offset too large!");
4553
+ RETURN_ERROR_IF(matchLength < minMatch, corruption_detected, "Matchlength too small");
4554
+ return 0;
4555
+ }
4556
+
4557
+ /* Returns an offset code, given a sequence's raw offset, the ongoing repcode array, and whether litLength == 0 */
4558
+ static U32 ZSTD_finalizeOffCode(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0) {
4559
+ U32 offCode = rawOffset + ZSTD_REP_MOVE;
4560
+ U32 repCode = 0;
4561
+
4562
+ if (!ll0 && rawOffset == rep[0]) {
4563
+ repCode = 1;
4564
+ } else if (rawOffset == rep[1]) {
4565
+ repCode = 2 - ll0;
4566
+ } else if (rawOffset == rep[2]) {
4567
+ repCode = 3 - ll0;
4568
+ } else if (ll0 && rawOffset == rep[0] - 1) {
4569
+ repCode = 3;
4570
+ }
4571
+ if (repCode) {
4572
+ /* ZSTD_storeSeq expects a number in the range [0, 2] to represent a repcode */
4573
+ offCode = repCode - 1;
4574
+ }
4575
+ return offCode;
4576
+ }
4577
+
4578
+ /* Returns 0 on success, and a ZSTD_error otherwise. This function scans through an array of
4579
+ * ZSTD_Sequence, storing the sequences it finds, until it reaches a block delimiter.
4580
+ */
4581
+ static size_t ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
4582
+ const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
4583
+ const void* src, size_t blockSize) {
4584
+ U32 idx = seqPos->idx;
4585
+ BYTE const* ip = (BYTE const*)(src);
4586
+ const BYTE* const iend = ip + blockSize;
4587
+ repcodes_t updatedRepcodes;
4588
+ U32 dictSize;
4589
+ U32 litLength;
4590
+ U32 matchLength;
4591
+ U32 ll0;
4592
+ U32 offCode;
4593
+
4594
+ if (cctx->cdict) {
4595
+ dictSize = (U32)cctx->cdict->dictContentSize;
4596
+ } else if (cctx->prefixDict.dict) {
4597
+ dictSize = (U32)cctx->prefixDict.dictSize;
4598
+ } else {
4599
+ dictSize = 0;
4600
+ }
4601
+ ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t));
4602
+ for (; (inSeqs[idx].matchLength != 0 || inSeqs[idx].offset != 0) && idx < inSeqsSize; ++idx) {
4603
+ litLength = inSeqs[idx].litLength;
4604
+ matchLength = inSeqs[idx].matchLength;
4605
+ ll0 = litLength == 0;
4606
+ offCode = ZSTD_finalizeOffCode(inSeqs[idx].offset, updatedRepcodes.rep, ll0);
4607
+ updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, offCode, ll0);
4608
+
4609
+ DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offCode, matchLength, litLength);
4610
+ if (cctx->appliedParams.validateSequences) {
4611
+ seqPos->posInSrc += litLength + matchLength;
4612
+ FORWARD_IF_ERROR(ZSTD_validateSequence(offCode, matchLength, seqPos->posInSrc,
4613
+ cctx->appliedParams.cParams.windowLog, dictSize,
4614
+ cctx->appliedParams.cParams.minMatch),
4615
+ "Sequence validation failed");
4616
+ }
4617
+ RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation,
4618
+ "Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
4619
+ ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offCode, matchLength - MINMATCH);
4620
+ ip += matchLength + litLength;
4621
+ }
4622
+ ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t));
4623
+
4624
+ if (inSeqs[idx].litLength) {
4625
+ DEBUGLOG(6, "Storing last literals of size: %u", inSeqs[idx].litLength);
4626
+ ZSTD_storeLastLiterals(&cctx->seqStore, ip, inSeqs[idx].litLength);
4627
+ ip += inSeqs[idx].litLength;
4628
+ seqPos->posInSrc += inSeqs[idx].litLength;
4629
+ }
4630
+ RETURN_ERROR_IF(ip != iend, corruption_detected, "Blocksize doesn't agree with block delimiter!");
4631
+ seqPos->idx = idx+1;
4632
+ return 0;
4633
+ }
4634
+
4635
+ /* Returns the number of bytes to move the current read position back by. Only non-zero
4636
+ * if we ended up splitting a sequence. Otherwise, it may return a ZSTD error if something
4637
+ * went wrong.
4638
+ *
4639
+ * This function will attempt to scan through blockSize bytes represented by the sequences
4640
+ * in inSeqs, storing any (partial) sequences.
4641
+ *
4642
+ * Occasionally, we may want to change the actual number of bytes we consumed from inSeqs to
4643
+ * avoid splitting a match, or to avoid splitting a match such that it would produce a match
4644
+ * smaller than MINMATCH. In this case, we return the number of bytes that we didn't read from this block.
4645
+ */
4646
+ static size_t ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
4647
+ const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
4648
+ const void* src, size_t blockSize) {
4649
+ U32 idx = seqPos->idx;
4650
+ U32 startPosInSequence = seqPos->posInSequence;
4651
+ U32 endPosInSequence = seqPos->posInSequence + (U32)blockSize;
4652
+ size_t dictSize;
4653
+ BYTE const* ip = (BYTE const*)(src);
4654
+ BYTE const* iend = ip + blockSize; /* May be adjusted if we decide to process fewer than blockSize bytes */
4655
+ repcodes_t updatedRepcodes;
4656
+ U32 bytesAdjustment = 0;
4657
+ U32 finalMatchSplit = 0;
4658
+ U32 litLength;
4659
+ U32 matchLength;
4660
+ U32 rawOffset;
4661
+ U32 offCode;
4662
+
4663
+ if (cctx->cdict) {
4664
+ dictSize = cctx->cdict->dictContentSize;
4665
+ } else if (cctx->prefixDict.dict) {
4666
+ dictSize = cctx->prefixDict.dictSize;
4667
+ } else {
4668
+ dictSize = 0;
4669
+ }
4670
+ DEBUGLOG(5, "ZSTD_copySequencesToSeqStore: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize);
4671
+ DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength);
4672
+ ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t));
4673
+ while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) {
4674
+ const ZSTD_Sequence currSeq = inSeqs[idx];
4675
+ litLength = currSeq.litLength;
4676
+ matchLength = currSeq.matchLength;
4677
+ rawOffset = currSeq.offset;
4678
+
4679
+ /* Modify the sequence depending on where endPosInSequence lies */
4680
+ if (endPosInSequence >= currSeq.litLength + currSeq.matchLength) {
4681
+ if (startPosInSequence >= litLength) {
4682
+ startPosInSequence -= litLength;
4683
+ litLength = 0;
4684
+ matchLength -= startPosInSequence;
4685
+ } else {
4686
+ litLength -= startPosInSequence;
4687
+ }
4688
+ /* Move to the next sequence */
4689
+ endPosInSequence -= currSeq.litLength + currSeq.matchLength;
4690
+ startPosInSequence = 0;
4691
+ idx++;
4692
+ } else {
4693
+ /* This is the final (partial) sequence we're adding from inSeqs, and endPosInSequence
4694
+ does not reach the end of the match. So, we have to split the sequence */
4695
+ DEBUGLOG(6, "Require a split: diff: %u, idx: %u PIS: %u",
4696
+ currSeq.litLength + currSeq.matchLength - endPosInSequence, idx, endPosInSequence);
4697
+ if (endPosInSequence > litLength) {
4698
+ U32 firstHalfMatchLength;
4699
+ litLength = startPosInSequence >= litLength ? 0 : litLength - startPosInSequence;
4700
+ firstHalfMatchLength = endPosInSequence - startPosInSequence - litLength;
4701
+ if (matchLength > blockSize && firstHalfMatchLength >= cctx->appliedParams.cParams.minMatch) {
4702
+ /* Only ever split the match if it is larger than the block size */
4703
+ U32 secondHalfMatchLength = currSeq.matchLength + currSeq.litLength - endPosInSequence;
4704
+ if (secondHalfMatchLength < cctx->appliedParams.cParams.minMatch) {
4705
+ /* Move the endPosInSequence backward so that it creates match of minMatch length */
4706
+ endPosInSequence -= cctx->appliedParams.cParams.minMatch - secondHalfMatchLength;
4707
+ bytesAdjustment = cctx->appliedParams.cParams.minMatch - secondHalfMatchLength;
4708
+ firstHalfMatchLength -= bytesAdjustment;
4709
+ }
4710
+ matchLength = firstHalfMatchLength;
4711
+ /* Flag that we split the last match - after storing the sequence, exit the loop,
4712
+ but keep the value of endPosInSequence */
4713
+ finalMatchSplit = 1;
4714
+ } else {
4715
+ /* Move the position in sequence backwards so that we don't split match, and break to store
4716
+ * the last literals. We use the original currSeq.litLength as a marker for where endPosInSequence
4717
+ * should go. We prefer to do this whenever it is not necessary to split the match, or if doing so
4718
+ * would cause the first half of the match to be too small
4719
+ */
4720
+ bytesAdjustment = endPosInSequence - currSeq.litLength;
4721
+ endPosInSequence = currSeq.litLength;
4722
+ break;
4723
+ }
4724
+ } else {
4725
+ /* This sequence ends inside the literals, break to store the last literals */
4726
+ break;
4727
+ }
4728
+ }
4729
+ /* Check if this offset can be represented with a repcode */
4730
+ { U32 ll0 = (litLength == 0);
4731
+ offCode = ZSTD_finalizeOffCode(rawOffset, updatedRepcodes.rep, ll0);
4732
+ updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, offCode, ll0);
4733
+ }
4734
+
4735
+ if (cctx->appliedParams.validateSequences) {
4736
+ seqPos->posInSrc += litLength + matchLength;
4737
+ FORWARD_IF_ERROR(ZSTD_validateSequence(offCode, matchLength, seqPos->posInSrc,
4738
+ cctx->appliedParams.cParams.windowLog, dictSize,
4739
+ cctx->appliedParams.cParams.minMatch),
4740
+ "Sequence validation failed");
4741
+ }
4742
+ DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offCode, matchLength, litLength);
4743
+ RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation,
4744
+ "Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
4745
+ ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offCode, matchLength - MINMATCH);
4746
+ ip += matchLength + litLength;
4747
+ }
4748
+ DEBUGLOG(5, "Ending seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength);
4749
+ assert(idx == inSeqsSize || endPosInSequence <= inSeqs[idx].litLength + inSeqs[idx].matchLength);
4750
+ seqPos->idx = idx;
4751
+ seqPos->posInSequence = endPosInSequence;
4752
+ ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t));
4753
+
4754
+ iend -= bytesAdjustment;
4755
+ if (ip != iend) {
4756
+ /* Store any last literals */
4757
+ U32 lastLLSize = (U32)(iend - ip);
4758
+ assert(ip <= iend);
4759
+ DEBUGLOG(6, "Storing last literals of size: %u", lastLLSize);
4760
+ ZSTD_storeLastLiterals(&cctx->seqStore, ip, lastLLSize);
4761
+ seqPos->posInSrc += lastLLSize;
4762
+ }
4763
+
4764
+ return bytesAdjustment;
4765
+ }
4766
+
4767
+ typedef size_t (*ZSTD_sequenceCopier) (ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
4768
+ const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
4769
+ const void* src, size_t blockSize);
4770
+ static ZSTD_sequenceCopier ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode) {
4771
+ ZSTD_sequenceCopier sequenceCopier = NULL;
4772
+ assert(ZSTD_cParam_withinBounds(ZSTD_c_blockDelimiters, mode));
4773
+ if (mode == ZSTD_sf_explicitBlockDelimiters) {
4774
+ return ZSTD_copySequencesToSeqStoreExplicitBlockDelim;
4775
+ } else if (mode == ZSTD_sf_noBlockDelimiters) {
4776
+ return ZSTD_copySequencesToSeqStoreNoBlockDelim;
4777
+ }
4778
+ assert(sequenceCopier != NULL);
4779
+ return sequenceCopier;
4780
+ }
4781
+
4782
+ /* Compress, block-by-block, all of the sequences given.
4783
+ *
4784
+ * Returns the cumulative size of all compressed blocks (including their headers), otherwise a ZSTD error.
4785
+ */
4786
+ static size_t ZSTD_compressSequences_internal(ZSTD_CCtx* cctx,
4787
+ void* dst, size_t dstCapacity,
4788
+ const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
4789
+ const void* src, size_t srcSize) {
4790
+ size_t cSize = 0;
4791
+ U32 lastBlock;
4792
+ size_t blockSize;
4793
+ size_t compressedSeqsSize;
4794
+ size_t remaining = srcSize;
4795
+ ZSTD_sequencePosition seqPos = {0, 0, 0};
4796
+
4797
+ BYTE const* ip = (BYTE const*)src;
4798
+ BYTE* op = (BYTE*)dst;
4799
+ ZSTD_sequenceCopier sequenceCopier = ZSTD_selectSequenceCopier(cctx->appliedParams.blockDelimiters);
4800
+
4801
+ DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize);
4802
+ /* Special case: empty frame */
4803
+ if (remaining == 0) {
4804
+ U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1);
4805
+ RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "No room for empty frame block header");
4806
+ MEM_writeLE32(op, cBlockHeader24);
4807
+ op += ZSTD_blockHeaderSize;
4808
+ dstCapacity -= ZSTD_blockHeaderSize;
4809
+ cSize += ZSTD_blockHeaderSize;
4810
+ }
4811
+
4812
+ while (remaining) {
4813
+ size_t cBlockSize;
4814
+ size_t additionalByteAdjustment;
4815
+ lastBlock = remaining <= cctx->blockSize;
4816
+ blockSize = lastBlock ? (U32)remaining : (U32)cctx->blockSize;
4817
+ ZSTD_resetSeqStore(&cctx->seqStore);
4818
+ DEBUGLOG(4, "Working on new block. Blocksize: %zu", blockSize);
4819
+
4820
+ additionalByteAdjustment = sequenceCopier(cctx, &seqPos, inSeqs, inSeqsSize, ip, blockSize);
4821
+ FORWARD_IF_ERROR(additionalByteAdjustment, "Bad sequence copy");
4822
+ blockSize -= additionalByteAdjustment;
4823
+
4824
+ /* If blocks are too small, emit as a nocompress block */
4825
+ if (blockSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
4826
+ cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
4827
+ FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed");
4828
+ DEBUGLOG(4, "Block too small, writing out nocompress block: cSize: %zu", cBlockSize);
4829
+ cSize += cBlockSize;
4830
+ ip += blockSize;
4831
+ op += cBlockSize;
4832
+ remaining -= blockSize;
4833
+ dstCapacity -= cBlockSize;
4834
+ continue;
4835
+ }
4836
+
4837
+ compressedSeqsSize = ZSTD_entropyCompressSequences(&cctx->seqStore,
4838
+ &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy,
4839
+ &cctx->appliedParams,
4840
+ op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize,
4841
+ blockSize,
4842
+ cctx->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
4843
+ cctx->bmi2);
4844
+ FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed");
4845
+ DEBUGLOG(4, "Compressed sequences size: %zu", compressedSeqsSize);
4846
+
4847
+ if (!cctx->isFirstBlock &&
4848
+ ZSTD_maybeRLE(&cctx->seqStore) &&
4849
+ ZSTD_isRLE((BYTE const*)src, srcSize)) {
4850
+ /* We don't want to emit our first block as a RLE even if it qualifies because
4851
+ * doing so will cause the decoder (cli only) to throw a "should consume all input error."
4852
+ * This is only an issue for zstd <= v1.4.3
4853
+ */
4854
+ compressedSeqsSize = 1;
4855
+ }
4856
+
4857
+ if (compressedSeqsSize == 0) {
4858
+ /* ZSTD_noCompressBlock writes the block header as well */
4859
+ cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
4860
+ FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed");
4861
+ DEBUGLOG(4, "Writing out nocompress block, size: %zu", cBlockSize);
4862
+ } else if (compressedSeqsSize == 1) {
4863
+ cBlockSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, blockSize, lastBlock);
4864
+ FORWARD_IF_ERROR(cBlockSize, "RLE compress block failed");
4865
+ DEBUGLOG(4, "Writing out RLE block, size: %zu", cBlockSize);
4866
+ } else {
4867
+ U32 cBlockHeader;
4868
+ /* Error checking and repcodes update */
4869
+ ZSTD_confirmRepcodesAndEntropyTables(cctx);
4870
+ if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
4871
+ cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
4872
+
4873
+ /* Write block header into beginning of block*/
4874
+ cBlockHeader = lastBlock + (((U32)bt_compressed)<<1) + (U32)(compressedSeqsSize << 3);
4875
+ MEM_writeLE24(op, cBlockHeader);
4876
+ cBlockSize = ZSTD_blockHeaderSize + compressedSeqsSize;
4877
+ DEBUGLOG(4, "Writing out compressed block, size: %zu", cBlockSize);
4878
+ }
4879
+
4880
+ cSize += cBlockSize;
4881
+ DEBUGLOG(4, "cSize running total: %zu", cSize);
4882
+
4883
+ if (lastBlock) {
4884
+ break;
4885
+ } else {
4886
+ ip += blockSize;
4887
+ op += cBlockSize;
4888
+ remaining -= blockSize;
4889
+ dstCapacity -= cBlockSize;
4890
+ cctx->isFirstBlock = 0;
4891
+ }
4892
+ }
4893
+
4894
+ return cSize;
4895
+ }
4896
+
4897
+ size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size_t dstCapacity,
4898
+ const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
4899
+ const void* src, size_t srcSize) {
4900
+ BYTE* op = (BYTE*)dst;
4901
+ size_t cSize = 0;
4902
+ size_t compressedBlocksSize = 0;
4903
+ size_t frameHeaderSize = 0;
4904
+
4905
+ /* Transparent initialization stage, same as compressStream2() */
4906
+ DEBUGLOG(3, "ZSTD_compressSequences()");
4907
+ assert(cctx != NULL);
4908
+ FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed");
4909
+ /* Begin writing output, starting with frame header */
4910
+ frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity, &cctx->appliedParams, srcSize, cctx->dictID);
4911
+ op += frameHeaderSize;
4912
+ dstCapacity -= frameHeaderSize;
4913
+ cSize += frameHeaderSize;
4914
+ if (cctx->appliedParams.fParams.checksumFlag && srcSize) {
4915
+ XXH64_update(&cctx->xxhState, src, srcSize);
4916
+ }
4917
+ /* cSize includes block header size and compressed sequences size */
4918
+ compressedBlocksSize = ZSTD_compressSequences_internal(cctx,
4919
+ op, dstCapacity,
4920
+ inSeqs, inSeqsSize,
4921
+ src, srcSize);
4922
+ FORWARD_IF_ERROR(compressedBlocksSize, "Compressing blocks failed!");
4923
+ cSize += compressedBlocksSize;
4924
+ dstCapacity -= compressedBlocksSize;
4925
+
4926
+ if (cctx->appliedParams.fParams.checksumFlag) {
4927
+ U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
4928
+ RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum");
4929
+ DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum);
4930
+ MEM_writeLE32((char*)dst + cSize, checksum);
4931
+ cSize += 4;
4932
+ }
4933
+
4934
+ DEBUGLOG(3, "Final compressed size: %zu", cSize);
4935
+ return cSize;
4936
+ }
4937
+
4086
4938
  /*====== Finalize ======*/
4087
4939
 
4088
4940
  /*! ZSTD_flushStream() :
@@ -4223,25 +5075,103 @@ static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEV
4223
5075
  },
4224
5076
  };
4225
5077
 
5078
+ static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize)
5079
+ {
5080
+ ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict);
5081
+ switch (cParams.strategy) {
5082
+ case ZSTD_fast:
5083
+ case ZSTD_dfast:
5084
+ break;
5085
+ case ZSTD_greedy:
5086
+ case ZSTD_lazy:
5087
+ case ZSTD_lazy2:
5088
+ cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG;
5089
+ break;
5090
+ case ZSTD_btlazy2:
5091
+ case ZSTD_btopt:
5092
+ case ZSTD_btultra:
5093
+ case ZSTD_btultra2:
5094
+ break;
5095
+ }
5096
+ return cParams;
5097
+ }
5098
+
5099
+ static int ZSTD_dedicatedDictSearch_isSupported(
5100
+ ZSTD_compressionParameters const* cParams)
5101
+ {
5102
+ return (cParams->strategy >= ZSTD_greedy) && (cParams->strategy <= ZSTD_lazy2);
5103
+ }
5104
+
5105
+ /**
5106
+ * Reverses the adjustment applied to cparams when enabling dedicated dict
5107
+ * search. This is used to recover the params set to be used in the working
5108
+ * context. (Otherwise, those tables would also grow.)
5109
+ */
5110
+ static void ZSTD_dedicatedDictSearch_revertCParams(
5111
+ ZSTD_compressionParameters* cParams) {
5112
+ switch (cParams->strategy) {
5113
+ case ZSTD_fast:
5114
+ case ZSTD_dfast:
5115
+ break;
5116
+ case ZSTD_greedy:
5117
+ case ZSTD_lazy:
5118
+ case ZSTD_lazy2:
5119
+ cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG;
5120
+ break;
5121
+ case ZSTD_btlazy2:
5122
+ case ZSTD_btopt:
5123
+ case ZSTD_btultra:
5124
+ case ZSTD_btultra2:
5125
+ break;
5126
+ }
5127
+ }
5128
+
5129
+ static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
5130
+ {
5131
+ switch (mode) {
5132
+ case ZSTD_cpm_unknown:
5133
+ case ZSTD_cpm_noAttachDict:
5134
+ case ZSTD_cpm_createCDict:
5135
+ break;
5136
+ case ZSTD_cpm_attachDict:
5137
+ dictSize = 0;
5138
+ break;
5139
+ default:
5140
+ assert(0);
5141
+ break;
5142
+ }
5143
+ { int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN;
5144
+ size_t const addedSize = unknown && dictSize > 0 ? 500 : 0;
5145
+ return unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize;
5146
+ }
5147
+ }
5148
+
4226
5149
  /*! ZSTD_getCParams_internal() :
4227
5150
  * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
4228
5151
  * 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)
5152
+ * Use dictSize == 0 for unknown or unused.
5153
+ * Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_cParamMode_e`. */
5154
+ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
4231
5155
  {
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;
5156
+ U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode);
4235
5157
  U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB);
4236
- int row = compressionLevel;
5158
+ int row;
4237
5159
  DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel);
5160
+
5161
+ /* row */
4238
5162
  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;
5163
+ else if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */
5164
+ else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
5165
+ else row = compressionLevel;
5166
+
4241
5167
  { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
4242
- if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */
5168
+ /* acceleration factor */
5169
+ if (compressionLevel < 0) {
5170
+ int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel);
5171
+ cp.targetLength = (unsigned)(-clampedCompressionLevel);
5172
+ }
4243
5173
  /* refine parameters based on srcSize & dictSize */
4244
- return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize);
5174
+ return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode);
4245
5175
  }
4246
5176
  }
4247
5177
 
@@ -4251,18 +5181,18 @@ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel,
4251
5181
  ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
4252
5182
  {
4253
5183
  if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
4254
- return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
5184
+ return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown);
4255
5185
  }
4256
5186
 
4257
5187
  /*! ZSTD_getParams() :
4258
5188
  * same idea as ZSTD_getCParams()
4259
5189
  * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
4260
5190
  * 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) {
5191
+ static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) {
4262
5192
  ZSTD_parameters params;
4263
- ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize);
5193
+ ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode);
4264
5194
  DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
4265
- memset(&params, 0, sizeof(params));
5195
+ ZSTD_memset(&params, 0, sizeof(params));
4266
5196
  params.cParams = cParams;
4267
5197
  params.fParams.contentSizeFlag = 1;
4268
5198
  return params;
@@ -4274,5 +5204,5 @@ static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned lo
4274
5204
  * Fields of `ZSTD_frameParameters` are set to default values */
4275
5205
  ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
4276
5206
  if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
4277
- return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize);
5207
+ return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown);
4278
5208
  }