extzstd 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
  }