extzstd 0.3.2 → 0.3.3

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/contrib/zstd/CHANGELOG +188 -1
  4. data/contrib/zstd/CONTRIBUTING.md +157 -74
  5. data/contrib/zstd/LICENSE +4 -4
  6. data/contrib/zstd/Makefile +81 -58
  7. data/contrib/zstd/Package.swift +36 -0
  8. data/contrib/zstd/README.md +59 -35
  9. data/contrib/zstd/TESTING.md +2 -3
  10. data/contrib/zstd/appveyor.yml +49 -136
  11. data/contrib/zstd/lib/BUCK +5 -7
  12. data/contrib/zstd/lib/Makefile +87 -181
  13. data/contrib/zstd/lib/README.md +23 -6
  14. data/contrib/zstd/lib/common/allocations.h +55 -0
  15. data/contrib/zstd/lib/common/bits.h +200 -0
  16. data/contrib/zstd/lib/common/bitstream.h +33 -59
  17. data/contrib/zstd/lib/common/compiler.h +115 -45
  18. data/contrib/zstd/lib/common/cpu.h +1 -1
  19. data/contrib/zstd/lib/common/debug.c +1 -1
  20. data/contrib/zstd/lib/common/debug.h +1 -1
  21. data/contrib/zstd/lib/common/entropy_common.c +15 -37
  22. data/contrib/zstd/lib/common/error_private.c +9 -2
  23. data/contrib/zstd/lib/common/error_private.h +82 -3
  24. data/contrib/zstd/lib/common/fse.h +9 -85
  25. data/contrib/zstd/lib/common/fse_decompress.c +29 -111
  26. data/contrib/zstd/lib/common/huf.h +84 -172
  27. data/contrib/zstd/lib/common/mem.h +58 -49
  28. data/contrib/zstd/lib/common/pool.c +37 -16
  29. data/contrib/zstd/lib/common/pool.h +9 -3
  30. data/contrib/zstd/lib/common/portability_macros.h +156 -0
  31. data/contrib/zstd/lib/common/threading.c +68 -14
  32. data/contrib/zstd/lib/common/threading.h +5 -10
  33. data/contrib/zstd/lib/common/xxhash.c +7 -809
  34. data/contrib/zstd/lib/common/xxhash.h +5568 -167
  35. data/contrib/zstd/lib/common/zstd_common.c +1 -36
  36. data/contrib/zstd/lib/common/zstd_deps.h +1 -1
  37. data/contrib/zstd/lib/common/zstd_internal.h +64 -150
  38. data/contrib/zstd/lib/common/zstd_trace.h +163 -0
  39. data/contrib/zstd/lib/compress/clevels.h +134 -0
  40. data/contrib/zstd/lib/compress/fse_compress.c +69 -150
  41. data/contrib/zstd/lib/compress/hist.c +1 -1
  42. data/contrib/zstd/lib/compress/hist.h +1 -1
  43. data/contrib/zstd/lib/compress/huf_compress.c +773 -251
  44. data/contrib/zstd/lib/compress/zstd_compress.c +2650 -826
  45. data/contrib/zstd/lib/compress/zstd_compress_internal.h +509 -180
  46. data/contrib/zstd/lib/compress/zstd_compress_literals.c +117 -40
  47. data/contrib/zstd/lib/compress/zstd_compress_literals.h +16 -6
  48. data/contrib/zstd/lib/compress/zstd_compress_sequences.c +28 -19
  49. data/contrib/zstd/lib/compress/zstd_compress_sequences.h +1 -1
  50. data/contrib/zstd/lib/compress/zstd_compress_superblock.c +33 -305
  51. data/contrib/zstd/lib/compress/zstd_compress_superblock.h +1 -1
  52. data/contrib/zstd/lib/compress/zstd_cwksp.h +266 -85
  53. data/contrib/zstd/lib/compress/zstd_double_fast.c +369 -132
  54. data/contrib/zstd/lib/compress/zstd_double_fast.h +3 -2
  55. data/contrib/zstd/lib/compress/zstd_fast.c +722 -258
  56. data/contrib/zstd/lib/compress/zstd_fast.h +3 -2
  57. data/contrib/zstd/lib/compress/zstd_lazy.c +1105 -360
  58. data/contrib/zstd/lib/compress/zstd_lazy.h +41 -1
  59. data/contrib/zstd/lib/compress/zstd_ldm.c +272 -208
  60. data/contrib/zstd/lib/compress/zstd_ldm.h +3 -2
  61. data/contrib/zstd/lib/compress/zstd_ldm_geartab.h +106 -0
  62. data/contrib/zstd/lib/compress/zstd_opt.c +324 -197
  63. data/contrib/zstd/lib/compress/zstd_opt.h +1 -1
  64. data/contrib/zstd/lib/compress/zstdmt_compress.c +109 -53
  65. data/contrib/zstd/lib/compress/zstdmt_compress.h +9 -6
  66. data/contrib/zstd/lib/decompress/huf_decompress.c +1071 -539
  67. data/contrib/zstd/lib/decompress/huf_decompress_amd64.S +576 -0
  68. data/contrib/zstd/lib/decompress/zstd_ddict.c +4 -4
  69. data/contrib/zstd/lib/decompress/zstd_ddict.h +1 -1
  70. data/contrib/zstd/lib/decompress/zstd_decompress.c +507 -82
  71. data/contrib/zstd/lib/decompress/zstd_decompress_block.c +962 -310
  72. data/contrib/zstd/lib/decompress/zstd_decompress_block.h +14 -3
  73. data/contrib/zstd/lib/decompress/zstd_decompress_internal.h +54 -6
  74. data/contrib/zstd/lib/deprecated/zbuff.h +1 -1
  75. data/contrib/zstd/lib/deprecated/zbuff_common.c +1 -1
  76. data/contrib/zstd/lib/deprecated/zbuff_compress.c +24 -4
  77. data/contrib/zstd/lib/deprecated/zbuff_decompress.c +3 -1
  78. data/contrib/zstd/lib/dictBuilder/cover.c +44 -32
  79. data/contrib/zstd/lib/dictBuilder/cover.h +6 -5
  80. data/contrib/zstd/lib/dictBuilder/divsufsort.c +1 -1
  81. data/contrib/zstd/lib/dictBuilder/fastcover.c +24 -16
  82. data/contrib/zstd/lib/dictBuilder/zdict.c +88 -95
  83. data/contrib/zstd/lib/legacy/zstd_legacy.h +8 -1
  84. data/contrib/zstd/lib/legacy/zstd_v01.c +16 -53
  85. data/contrib/zstd/lib/legacy/zstd_v01.h +1 -1
  86. data/contrib/zstd/lib/legacy/zstd_v02.c +24 -69
  87. data/contrib/zstd/lib/legacy/zstd_v02.h +1 -1
  88. data/contrib/zstd/lib/legacy/zstd_v03.c +25 -72
  89. data/contrib/zstd/lib/legacy/zstd_v03.h +1 -1
  90. data/contrib/zstd/lib/legacy/zstd_v04.c +23 -69
  91. data/contrib/zstd/lib/legacy/zstd_v04.h +1 -1
  92. data/contrib/zstd/lib/legacy/zstd_v05.c +35 -85
  93. data/contrib/zstd/lib/legacy/zstd_v05.h +1 -1
  94. data/contrib/zstd/lib/legacy/zstd_v06.c +42 -87
  95. data/contrib/zstd/lib/legacy/zstd_v06.h +1 -1
  96. data/contrib/zstd/lib/legacy/zstd_v07.c +35 -82
  97. data/contrib/zstd/lib/legacy/zstd_v07.h +1 -1
  98. data/contrib/zstd/lib/libzstd.mk +214 -0
  99. data/contrib/zstd/lib/libzstd.pc.in +4 -3
  100. data/contrib/zstd/lib/module.modulemap +35 -0
  101. data/contrib/zstd/lib/{dictBuilder/zdict.h → zdict.h} +202 -33
  102. data/contrib/zstd/lib/zstd.h +922 -293
  103. data/contrib/zstd/lib/{common/zstd_errors.h → zstd_errors.h} +27 -8
  104. data/ext/extconf.rb +7 -6
  105. data/ext/extzstd.c +13 -10
  106. data/ext/libzstd_conf.h +0 -1
  107. data/ext/zstd_decompress_asm.S +1 -0
  108. metadata +16 -5
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under both the BSD-style license (found in the
@@ -55,23 +55,165 @@
55
55
  /*-*******************************************************
56
56
  * Dependencies
57
57
  *********************************************************/
58
+ #include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */
58
59
  #include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
59
- #include "../common/cpu.h" /* bmi2 */
60
60
  #include "../common/mem.h" /* low level memory routines */
61
61
  #define FSE_STATIC_LINKING_ONLY
62
62
  #include "../common/fse.h"
63
- #define HUF_STATIC_LINKING_ONLY
64
63
  #include "../common/huf.h"
64
+ #include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */
65
65
  #include "../common/zstd_internal.h" /* blockProperties_t */
66
66
  #include "zstd_decompress_internal.h" /* ZSTD_DCtx */
67
67
  #include "zstd_ddict.h" /* ZSTD_DDictDictContent */
68
68
  #include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
69
+ #include "../common/bits.h" /* ZSTD_highbit32 */
69
70
 
70
71
  #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
71
72
  # include "../legacy/zstd_legacy.h"
72
73
  #endif
73
74
 
74
75
 
76
+
77
+ /*************************************
78
+ * Multiple DDicts Hashset internals *
79
+ *************************************/
80
+
81
+ #define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4
82
+ #define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float.
83
+ * Currently, that means a 0.75 load factor.
84
+ * So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded
85
+ * the load factor of the ddict hash set.
86
+ */
87
+
88
+ #define DDICT_HASHSET_TABLE_BASE_SIZE 64
89
+ #define DDICT_HASHSET_RESIZE_FACTOR 2
90
+
91
+ /* Hash function to determine starting position of dict insertion within the table
92
+ * Returns an index between [0, hashSet->ddictPtrTableSize]
93
+ */
94
+ static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) {
95
+ const U64 hash = XXH64(&dictID, sizeof(U32), 0);
96
+ /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */
97
+ return hash & (hashSet->ddictPtrTableSize - 1);
98
+ }
99
+
100
+ /* Adds DDict to a hashset without resizing it.
101
+ * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set.
102
+ * Returns 0 if successful, or a zstd error code if something went wrong.
103
+ */
104
+ static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) {
105
+ const U32 dictID = ZSTD_getDictID_fromDDict(ddict);
106
+ size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
107
+ const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;
108
+ RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!");
109
+ DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);
110
+ while (hashSet->ddictPtrTable[idx] != NULL) {
111
+ /* Replace existing ddict if inserting ddict with same dictID */
112
+ if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) {
113
+ DEBUGLOG(4, "DictID already exists, replacing rather than adding");
114
+ hashSet->ddictPtrTable[idx] = ddict;
115
+ return 0;
116
+ }
117
+ idx &= idxRangeMask;
118
+ idx++;
119
+ }
120
+ DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);
121
+ hashSet->ddictPtrTable[idx] = ddict;
122
+ hashSet->ddictPtrCount++;
123
+ return 0;
124
+ }
125
+
126
+ /* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and
127
+ * rehashes all values, allocates new table, frees old table.
128
+ * Returns 0 on success, otherwise a zstd error code.
129
+ */
130
+ static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {
131
+ size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR;
132
+ const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem);
133
+ const ZSTD_DDict** oldTable = hashSet->ddictPtrTable;
134
+ size_t oldTableSize = hashSet->ddictPtrTableSize;
135
+ size_t i;
136
+
137
+ DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize);
138
+ RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!");
139
+ hashSet->ddictPtrTable = newTable;
140
+ hashSet->ddictPtrTableSize = newTableSize;
141
+ hashSet->ddictPtrCount = 0;
142
+ for (i = 0; i < oldTableSize; ++i) {
143
+ if (oldTable[i] != NULL) {
144
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), "");
145
+ }
146
+ }
147
+ ZSTD_customFree((void*)oldTable, customMem);
148
+ DEBUGLOG(4, "Finished re-hash");
149
+ return 0;
150
+ }
151
+
152
+ /* Fetches a DDict with the given dictID
153
+ * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL.
154
+ */
155
+ static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) {
156
+ size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
157
+ const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;
158
+ DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);
159
+ for (;;) {
160
+ size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]);
161
+ if (currDictID == dictID || currDictID == 0) {
162
+ /* currDictID == 0 implies a NULL ddict entry */
163
+ break;
164
+ } else {
165
+ idx &= idxRangeMask; /* Goes to start of table when we reach the end */
166
+ idx++;
167
+ }
168
+ }
169
+ DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);
170
+ return hashSet->ddictPtrTable[idx];
171
+ }
172
+
173
+ /* Allocates space for and returns a ddict hash set
174
+ * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with.
175
+ * Returns NULL if allocation failed.
176
+ */
177
+ static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) {
178
+ ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem);
179
+ DEBUGLOG(4, "Allocating new hash set");
180
+ if (!ret)
181
+ return NULL;
182
+ ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem);
183
+ if (!ret->ddictPtrTable) {
184
+ ZSTD_customFree(ret, customMem);
185
+ return NULL;
186
+ }
187
+ ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE;
188
+ ret->ddictPtrCount = 0;
189
+ return ret;
190
+ }
191
+
192
+ /* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself.
193
+ * Note: The ZSTD_DDict* within the table are NOT freed.
194
+ */
195
+ static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {
196
+ DEBUGLOG(4, "Freeing ddict hash set");
197
+ if (hashSet && hashSet->ddictPtrTable) {
198
+ ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem);
199
+ }
200
+ if (hashSet) {
201
+ ZSTD_customFree(hashSet, customMem);
202
+ }
203
+ }
204
+
205
+ /* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set.
206
+ * Returns 0 on success, or a ZSTD error.
207
+ */
208
+ static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) {
209
+ DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize);
210
+ if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) {
211
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), "");
212
+ }
213
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), "");
214
+ return 0;
215
+ }
216
+
75
217
  /*-*************************************************************
76
218
  * Context management
77
219
  ***************************************************************/
@@ -101,6 +243,8 @@ static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx)
101
243
  dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
102
244
  dctx->outBufferMode = ZSTD_bm_buffered;
103
245
  dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;
246
+ dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict;
247
+ dctx->disableHufAsm = 0;
104
248
  }
105
249
 
106
250
  static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
@@ -115,13 +259,17 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
115
259
  dctx->inBuffSize = 0;
116
260
  dctx->outBuffSize = 0;
117
261
  dctx->streamStage = zdss_init;
262
+ #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
118
263
  dctx->legacyContext = NULL;
119
264
  dctx->previousLegacyVersion = 0;
265
+ #endif
120
266
  dctx->noForwardProgress = 0;
121
267
  dctx->oversizedDuration = 0;
122
- dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
268
+ #if DYNAMIC_BMI2
269
+ dctx->bmi2 = ZSTD_cpuSupportsBmi2();
270
+ #endif
271
+ dctx->ddictSet = NULL;
123
272
  ZSTD_DCtx_resetParameters(dctx);
124
- dctx->validateChecksum = 1;
125
273
  #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
126
274
  dctx->dictContentEndForFuzzing = NULL;
127
275
  #endif
@@ -140,8 +288,7 @@ ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
140
288
  return dctx;
141
289
  }
142
290
 
143
- ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
144
- {
291
+ static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) {
145
292
  if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
146
293
 
147
294
  { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem);
@@ -152,10 +299,15 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
152
299
  }
153
300
  }
154
301
 
302
+ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
303
+ {
304
+ return ZSTD_createDCtx_internal(customMem);
305
+ }
306
+
155
307
  ZSTD_DCtx* ZSTD_createDCtx(void)
156
308
  {
157
309
  DEBUGLOG(3, "ZSTD_createDCtx");
158
- return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
310
+ return ZSTD_createDCtx_internal(ZSTD_defaultCMem);
159
311
  }
160
312
 
161
313
  static void ZSTD_clearDict(ZSTD_DCtx* dctx)
@@ -178,6 +330,10 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
178
330
  if (dctx->legacyContext)
179
331
  ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);
180
332
  #endif
333
+ if (dctx->ddictSet) {
334
+ ZSTD_freeDDictHashSet(dctx->ddictSet, cMem);
335
+ dctx->ddictSet = NULL;
336
+ }
181
337
  ZSTD_customFree(dctx, cMem);
182
338
  return 0;
183
339
  }
@@ -190,6 +346,29 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
190
346
  ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */
191
347
  }
192
348
 
349
+ /* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on
350
+ * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then
351
+ * accordingly sets the ddict to be used to decompress the frame.
352
+ *
353
+ * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is.
354
+ *
355
+ * ZSTD_d_refMultipleDDicts must be enabled for this function to be called.
356
+ */
357
+ static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) {
358
+ assert(dctx->refMultipleDDicts && dctx->ddictSet);
359
+ DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame");
360
+ if (dctx->ddict) {
361
+ const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID);
362
+ if (frameDDict) {
363
+ DEBUGLOG(4, "DDict found!");
364
+ ZSTD_clearDict(dctx);
365
+ dctx->dictID = dctx->fParams.dictID;
366
+ dctx->ddict = frameDDict;
367
+ dctx->dictUses = ZSTD_use_indefinitely;
368
+ }
369
+ }
370
+ }
371
+
193
372
 
194
373
  /*-*************************************************************
195
374
  * Frame header decoding
@@ -213,6 +392,19 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size)
213
392
  return 0;
214
393
  }
215
394
 
395
+ /*! ZSTD_isSkippableFrame() :
396
+ * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame.
397
+ * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
398
+ */
399
+ unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size)
400
+ {
401
+ if (size < ZSTD_FRAMEIDSIZE) return 0;
402
+ { U32 const magic = MEM_readLE32(buffer);
403
+ if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
404
+ }
405
+ return 0;
406
+ }
407
+
216
408
  /** ZSTD_frameHeaderSize_internal() :
217
409
  * srcSize must be large enough to reach header size fields.
218
410
  * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.
@@ -248,16 +440,40 @@ size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
248
440
  * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
249
441
  * @return : 0, `zfhPtr` is correctly filled,
250
442
  * >0, `srcSize` is too small, value is wanted `srcSize` amount,
251
- * or an error code, which can be tested using ZSTD_isError() */
443
+ ** or an error code, which can be tested using ZSTD_isError() */
252
444
  size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
253
445
  {
254
446
  const BYTE* ip = (const BYTE*)src;
255
447
  size_t const minInputSize = ZSTD_startingInputLength(format);
256
448
 
257
- ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */
258
- if (srcSize < minInputSize) return minInputSize;
259
- RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter");
449
+ DEBUGLOG(5, "ZSTD_getFrameHeader_advanced: minInputSize = %zu, srcSize = %zu", minInputSize, srcSize);
450
+
451
+ if (srcSize > 0) {
452
+ /* note : technically could be considered an assert(), since it's an invalid entry */
453
+ RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter : src==NULL, but srcSize>0");
454
+ }
455
+ if (srcSize < minInputSize) {
456
+ if (srcSize > 0 && format != ZSTD_f_zstd1_magicless) {
457
+ /* when receiving less than @minInputSize bytes,
458
+ * control these bytes at least correspond to a supported magic number
459
+ * in order to error out early if they don't.
460
+ **/
461
+ size_t const toCopy = MIN(4, srcSize);
462
+ unsigned char hbuf[4]; MEM_writeLE32(hbuf, ZSTD_MAGICNUMBER);
463
+ assert(src != NULL);
464
+ ZSTD_memcpy(hbuf, src, toCopy);
465
+ if ( MEM_readLE32(hbuf) != ZSTD_MAGICNUMBER ) {
466
+ /* not a zstd frame : let's check if it's a skippable frame */
467
+ MEM_writeLE32(hbuf, ZSTD_MAGIC_SKIPPABLE_START);
468
+ ZSTD_memcpy(hbuf, src, toCopy);
469
+ if ((MEM_readLE32(hbuf) & ZSTD_MAGIC_SKIPPABLE_MASK) != ZSTD_MAGIC_SKIPPABLE_START) {
470
+ RETURN_ERROR(prefix_unknown,
471
+ "first bytes don't correspond to any supported magic number");
472
+ } } }
473
+ return minInputSize;
474
+ }
260
475
 
476
+ ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzers may not understand that zfhPtr will be read only if return value is zero, since they are 2 different signals */
261
477
  if ( (format != ZSTD_f_zstd1_magicless)
262
478
  && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
263
479
  if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
@@ -299,7 +515,9 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s
299
515
  }
300
516
  switch(dictIDSizeCode)
301
517
  {
302
- default: assert(0); /* impossible */
518
+ default:
519
+ assert(0); /* impossible */
520
+ ZSTD_FALLTHROUGH;
303
521
  case 0 : break;
304
522
  case 1 : dictID = ip[pos]; pos++; break;
305
523
  case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;
@@ -307,7 +525,9 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s
307
525
  }
308
526
  switch(fcsID)
309
527
  {
310
- default: assert(0); /* impossible */
528
+ default:
529
+ assert(0); /* impossible */
530
+ ZSTD_FALLTHROUGH;
311
531
  case 0 : if (singleSegment) frameContentSize = ip[pos]; break;
312
532
  case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;
313
533
  case 2 : frameContentSize = MEM_readLE32(ip+pos); break;
@@ -336,7 +556,6 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src
336
556
  return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);
337
557
  }
338
558
 
339
-
340
559
  /** ZSTD_getFrameContentSize() :
341
560
  * compatible with legacy mode
342
561
  * @return : decompressed size of the single frame pointed to be `src` if known, otherwise
@@ -370,18 +589,52 @@ static size_t readSkippableFrameSize(void const* src, size_t srcSize)
370
589
  sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
371
590
  RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,
372
591
  frameParameter_unsupported, "");
373
- {
374
- size_t const skippableSize = skippableHeaderSize + sizeU32;
592
+ { size_t const skippableSize = skippableHeaderSize + sizeU32;
375
593
  RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");
376
594
  return skippableSize;
377
595
  }
378
596
  }
379
597
 
598
+ /*! ZSTD_readSkippableFrame() :
599
+ * Retrieves content of a skippable frame, and writes it to dst buffer.
600
+ *
601
+ * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written,
602
+ * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested
603
+ * in the magicVariant.
604
+ *
605
+ * Returns an error if destination buffer is not large enough, or if this is not a valid skippable frame.
606
+ *
607
+ * @return : number of bytes written or a ZSTD error.
608
+ */
609
+ size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity,
610
+ unsigned* magicVariant, /* optional, can be NULL */
611
+ const void* src, size_t srcSize)
612
+ {
613
+ RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");
614
+
615
+ { U32 const magicNumber = MEM_readLE32(src);
616
+ size_t skippableFrameSize = readSkippableFrameSize(src, srcSize);
617
+ size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE;
618
+
619
+ /* check input validity */
620
+ RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, "");
621
+ RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, "");
622
+ RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, "");
623
+
624
+ /* deliver payload */
625
+ if (skippableContentSize > 0 && dst != NULL)
626
+ ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize);
627
+ if (magicVariant != NULL)
628
+ *magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START;
629
+ return skippableContentSize;
630
+ }
631
+ }
632
+
380
633
  /** ZSTD_findDecompressedSize() :
381
- * compatible with legacy mode
382
634
  * `srcSize` must be the exact length of some number of ZSTD compressed and/or
383
635
  * skippable frames
384
- * @return : decompressed size of the frames contained */
636
+ * note: compatible with legacy mode
637
+ * @return : decompressed size of the frames contained */
385
638
  unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
386
639
  {
387
640
  unsigned long long totalDstSize = 0;
@@ -391,9 +644,7 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
391
644
 
392
645
  if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
393
646
  size_t const skippableSize = readSkippableFrameSize(src, srcSize);
394
- if (ZSTD_isError(skippableSize)) {
395
- return ZSTD_CONTENTSIZE_ERROR;
396
- }
647
+ if (ZSTD_isError(skippableSize)) return ZSTD_CONTENTSIZE_ERROR;
397
648
  assert(skippableSize <= srcSize);
398
649
 
399
650
  src = (const BYTE *)src + skippableSize;
@@ -401,17 +652,17 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
401
652
  continue;
402
653
  }
403
654
 
404
- { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
405
- if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
655
+ { unsigned long long const fcs = ZSTD_getFrameContentSize(src, srcSize);
656
+ if (fcs >= ZSTD_CONTENTSIZE_ERROR) return fcs;
406
657
 
407
- /* check for overflow */
408
- if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
409
- totalDstSize += ret;
658
+ if (totalDstSize + fcs < totalDstSize)
659
+ return ZSTD_CONTENTSIZE_ERROR; /* check for overflow */
660
+ totalDstSize += fcs;
410
661
  }
662
+ /* skip to next frame */
411
663
  { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
412
- if (ZSTD_isError(frameSrcSize)) {
413
- return ZSTD_CONTENTSIZE_ERROR;
414
- }
664
+ if (ZSTD_isError(frameSrcSize)) return ZSTD_CONTENTSIZE_ERROR;
665
+ assert(frameSrcSize <= srcSize);
415
666
 
416
667
  src = (const BYTE *)src + frameSrcSize;
417
668
  srcSize -= frameSrcSize;
@@ -441,12 +692,19 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
441
692
 
442
693
  /** ZSTD_decodeFrameHeader() :
443
694
  * `headerSize` must be the size provided by ZSTD_frameHeaderSize().
695
+ * If multiple DDict references are enabled, also will choose the correct DDict to use.
444
696
  * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
445
697
  static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
446
698
  {
447
699
  size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
448
700
  if (ZSTD_isError(result)) return result; /* invalid header */
449
701
  RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");
702
+
703
+ /* Reference DDict requested by frame if dctx references multiple ddicts */
704
+ if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) {
705
+ ZSTD_DCtx_selectFrameDDict(dctx);
706
+ }
707
+
450
708
  #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
451
709
  /* Skip the dictID check in fuzzing mode, because it makes the search
452
710
  * harder.
@@ -456,6 +714,7 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he
456
714
  #endif
457
715
  dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0;
458
716
  if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0);
717
+ dctx->processedCSize += headerSize;
459
718
  return 0;
460
719
  }
461
720
 
@@ -525,10 +784,11 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize
525
784
  ip += 4;
526
785
  }
527
786
 
787
+ frameSizeInfo.nbBlocks = nbBlocks;
528
788
  frameSizeInfo.compressedSize = (size_t)(ip - ipstart);
529
789
  frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)
530
790
  ? zfh.frameContentSize
531
- : nbBlocks * zfh.blockSizeMax;
791
+ : (unsigned long long)nbBlocks * zfh.blockSizeMax;
532
792
  return frameSizeInfo;
533
793
  }
534
794
  }
@@ -568,6 +828,48 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
568
828
  return bound;
569
829
  }
570
830
 
831
+ size_t ZSTD_decompressionMargin(void const* src, size_t srcSize)
832
+ {
833
+ size_t margin = 0;
834
+ unsigned maxBlockSize = 0;
835
+
836
+ /* Iterate over each frame */
837
+ while (srcSize > 0) {
838
+ ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
839
+ size_t const compressedSize = frameSizeInfo.compressedSize;
840
+ unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
841
+ ZSTD_frameHeader zfh;
842
+
843
+ FORWARD_IF_ERROR(ZSTD_getFrameHeader(&zfh, src, srcSize), "");
844
+ if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)
845
+ return ERROR(corruption_detected);
846
+
847
+ if (zfh.frameType == ZSTD_frame) {
848
+ /* Add the frame header to our margin */
849
+ margin += zfh.headerSize;
850
+ /* Add the checksum to our margin */
851
+ margin += zfh.checksumFlag ? 4 : 0;
852
+ /* Add 3 bytes per block */
853
+ margin += 3 * frameSizeInfo.nbBlocks;
854
+
855
+ /* Compute the max block size */
856
+ maxBlockSize = MAX(maxBlockSize, zfh.blockSizeMax);
857
+ } else {
858
+ assert(zfh.frameType == ZSTD_skippableFrame);
859
+ /* Add the entire skippable frame size to our margin. */
860
+ margin += compressedSize;
861
+ }
862
+
863
+ assert(srcSize >= compressedSize);
864
+ src = (const BYTE*)src + compressedSize;
865
+ srcSize -= compressedSize;
866
+ }
867
+
868
+ /* Add the max block size back to the margin. */
869
+ margin += maxBlockSize;
870
+
871
+ return margin;
872
+ }
571
873
 
572
874
  /*-*************************************************************
573
875
  * Frame decoding
@@ -578,7 +880,7 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
578
880
  size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
579
881
  {
580
882
  DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);
581
- ZSTD_checkContinuity(dctx, blockStart);
883
+ ZSTD_checkContinuity(dctx, blockStart, blockSize);
582
884
  dctx->previousDstEnd = (const char*)blockStart + blockSize;
583
885
  return blockSize;
584
886
  }
@@ -593,7 +895,7 @@ static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,
593
895
  if (srcSize == 0) return 0;
594
896
  RETURN_ERROR(dstBuffer_null, "");
595
897
  }
596
- ZSTD_memcpy(dst, src, srcSize);
898
+ ZSTD_memmove(dst, src, srcSize);
597
899
  return srcSize;
598
900
  }
599
901
 
@@ -610,6 +912,32 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
610
912
  return regenSize;
611
913
  }
612
914
 
915
+ static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming)
916
+ {
917
+ #if ZSTD_TRACE
918
+ if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) {
919
+ ZSTD_Trace trace;
920
+ ZSTD_memset(&trace, 0, sizeof(trace));
921
+ trace.version = ZSTD_VERSION_NUMBER;
922
+ trace.streaming = streaming;
923
+ if (dctx->ddict) {
924
+ trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict);
925
+ trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict);
926
+ trace.dictionaryIsCold = dctx->ddictIsCold;
927
+ }
928
+ trace.uncompressedSize = (size_t)uncompressedSize;
929
+ trace.compressedSize = (size_t)compressedSize;
930
+ trace.dctx = dctx;
931
+ ZSTD_trace_decompress_end(dctx->traceCtx, &trace);
932
+ }
933
+ #else
934
+ (void)dctx;
935
+ (void)uncompressedSize;
936
+ (void)compressedSize;
937
+ (void)streaming;
938
+ #endif
939
+ }
940
+
613
941
 
614
942
  /*! ZSTD_decompressFrame() :
615
943
  * @dctx must be properly initialized
@@ -619,8 +947,9 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
619
947
  void* dst, size_t dstCapacity,
620
948
  const void** srcPtr, size_t *srcSizePtr)
621
949
  {
622
- const BYTE* ip = (const BYTE*)(*srcPtr);
623
- BYTE* const ostart = (BYTE* const)dst;
950
+ const BYTE* const istart = (const BYTE*)(*srcPtr);
951
+ const BYTE* ip = istart;
952
+ BYTE* const ostart = (BYTE*)dst;
624
953
  BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart;
625
954
  BYTE* op = ostart;
626
955
  size_t remainingSrcSize = *srcSizePtr;
@@ -644,6 +973,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
644
973
 
645
974
  /* Loop on each block */
646
975
  while (1) {
976
+ BYTE* oBlockEnd = oend;
647
977
  size_t decodedSize;
648
978
  blockProperties_t blockProperties;
649
979
  size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties);
@@ -653,16 +983,34 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
653
983
  remainingSrcSize -= ZSTD_blockHeaderSize;
654
984
  RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, "");
655
985
 
986
+ if (ip >= op && ip < oBlockEnd) {
987
+ /* We are decompressing in-place. Limit the output pointer so that we
988
+ * don't overwrite the block that we are currently reading. This will
989
+ * fail decompression if the input & output pointers aren't spaced
990
+ * far enough apart.
991
+ *
992
+ * This is important to set, even when the pointers are far enough
993
+ * apart, because ZSTD_decompressBlock_internal() can decide to store
994
+ * literals in the output buffer, after the block it is decompressing.
995
+ * Since we don't want anything to overwrite our input, we have to tell
996
+ * ZSTD_decompressBlock_internal to never write past ip.
997
+ *
998
+ * See ZSTD_allocateLiteralsBuffer() for reference.
999
+ */
1000
+ oBlockEnd = op + (ip - op);
1001
+ }
1002
+
656
1003
  switch(blockProperties.blockType)
657
1004
  {
658
1005
  case bt_compressed:
659
- decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oend-op), ip, cBlockSize, /* frame */ 1);
1006
+ decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, /* frame */ 1, not_streaming);
660
1007
  break;
661
1008
  case bt_raw :
1009
+ /* Use oend instead of oBlockEnd because this function is safe to overlap. It uses memmove. */
662
1010
  decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize);
663
1011
  break;
664
1012
  case bt_rle :
665
- decodedSize = ZSTD_setRleBlock(op, (size_t)(oend-op), *ip, blockProperties.origSize);
1013
+ decodedSize = ZSTD_setRleBlock(op, (size_t)(oBlockEnd-op), *ip, blockProperties.origSize);
666
1014
  break;
667
1015
  case bt_reserved :
668
1016
  default:
@@ -695,8 +1043,9 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
695
1043
  ip += 4;
696
1044
  remainingSrcSize -= 4;
697
1045
  }
698
-
1046
+ ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0);
699
1047
  /* Allow caller to get size read */
1048
+ DEBUGLOG(4, "ZSTD_decompressFrame: decompressed frame of size %zi, consuming %zi bytes of input", op-ostart, ip - (const BYTE*)*srcPtr);
700
1049
  *srcPtr = ip;
701
1050
  *srcSizePtr = remainingSrcSize;
702
1051
  return (size_t)(op-ostart);
@@ -743,17 +1092,18 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
743
1092
  }
744
1093
  #endif
745
1094
 
746
- { U32 const magicNumber = MEM_readLE32(src);
747
- DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
748
- (unsigned)magicNumber, ZSTD_MAGICNUMBER);
1095
+ if (srcSize >= 4) {
1096
+ U32 const magicNumber = MEM_readLE32(src);
1097
+ DEBUGLOG(5, "reading magic number %08X", (unsigned)magicNumber);
749
1098
  if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
1099
+ /* skippable frame detected : skip it */
750
1100
  size_t const skippableSize = readSkippableFrameSize(src, srcSize);
751
- FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed");
1101
+ FORWARD_IF_ERROR(skippableSize, "invalid skippable frame");
752
1102
  assert(skippableSize <= srcSize);
753
1103
 
754
1104
  src = (const BYTE *)src + skippableSize;
755
1105
  srcSize -= skippableSize;
756
- continue;
1106
+ continue; /* check next frame */
757
1107
  } }
758
1108
 
759
1109
  if (ddict) {
@@ -764,7 +1114,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
764
1114
  * use this in all cases but ddict */
765
1115
  FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), "");
766
1116
  }
767
- ZSTD_checkContinuity(dctx, dst);
1117
+ ZSTD_checkContinuity(dctx, dst, dstCapacity);
768
1118
 
769
1119
  { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
770
1120
  &src, &srcSize);
@@ -807,7 +1157,7 @@ static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx)
807
1157
  switch (dctx->dictUses) {
808
1158
  default:
809
1159
  assert(0 /* Impossible */);
810
- /* fall-through */
1160
+ ZSTD_FALLTHROUGH;
811
1161
  case ZSTD_dont_use:
812
1162
  ZSTD_clearDict(dctx);
813
1163
  return NULL;
@@ -829,7 +1179,7 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr
829
1179
  {
830
1180
  #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)
831
1181
  size_t regenSize;
832
- ZSTD_DCtx* const dctx = ZSTD_createDCtx();
1182
+ ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem);
833
1183
  RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!");
834
1184
  regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);
835
1185
  ZSTD_freeDCtx(dctx);
@@ -849,8 +1199,8 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr
849
1199
  size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
850
1200
 
851
1201
  /**
852
- * Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed,
853
- * we allow taking a partial block as the input. Currently only raw uncompressed blocks can
1202
+ * Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed, we
1203
+ * allow taking a partial block as the input. Currently only raw uncompressed blocks can
854
1204
  * be streamed.
855
1205
  *
856
1206
  * For blocks that can be streamed, this allows us to reduce the latency until we produce
@@ -863,7 +1213,7 @@ static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t
863
1213
  return dctx->expected;
864
1214
  if (dctx->bType != bt_raw)
865
1215
  return dctx->expected;
866
- return MIN(MAX(inputSize, 1), dctx->expected);
1216
+ return BOUNDED(1, inputSize, dctx->expected);
867
1217
  }
868
1218
 
869
1219
  ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
@@ -871,7 +1221,9 @@ ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
871
1221
  {
872
1222
  default: /* should not happen */
873
1223
  assert(0);
1224
+ ZSTD_FALLTHROUGH;
874
1225
  case ZSTDds_getFrameHeaderSize:
1226
+ ZSTD_FALLTHROUGH;
875
1227
  case ZSTDds_decodeFrameHeader:
876
1228
  return ZSTDnit_frameHeader;
877
1229
  case ZSTDds_decodeBlockHeader:
@@ -883,6 +1235,7 @@ ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
883
1235
  case ZSTDds_checkChecksum:
884
1236
  return ZSTDnit_checksum;
885
1237
  case ZSTDds_decodeSkippableHeader:
1238
+ ZSTD_FALLTHROUGH;
886
1239
  case ZSTDds_skipFrame:
887
1240
  return ZSTDnit_skippableFrame;
888
1241
  }
@@ -899,7 +1252,9 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
899
1252
  DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);
900
1253
  /* Sanity check */
901
1254
  RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed");
902
- if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
1255
+ ZSTD_checkContinuity(dctx, dst, dstCapacity);
1256
+
1257
+ dctx->processedCSize += srcSize;
903
1258
 
904
1259
  switch (dctx->stage)
905
1260
  {
@@ -964,7 +1319,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
964
1319
  {
965
1320
  case bt_compressed:
966
1321
  DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
967
- rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
1322
+ rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1, is_streaming);
968
1323
  dctx->expected = 0; /* Streaming not supported */
969
1324
  break;
970
1325
  case bt_raw :
@@ -1004,6 +1359,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
1004
1359
  dctx->expected = 4;
1005
1360
  dctx->stage = ZSTDds_checkChecksum;
1006
1361
  } else {
1362
+ ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);
1007
1363
  dctx->expected = 0; /* ends here */
1008
1364
  dctx->stage = ZSTDds_getFrameHeaderSize;
1009
1365
  }
@@ -1023,6 +1379,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
1023
1379
  DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
1024
1380
  RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");
1025
1381
  }
1382
+ ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);
1026
1383
  dctx->expected = 0;
1027
1384
  dctx->stage = ZSTDds_getFrameHeaderSize;
1028
1385
  return 0;
@@ -1043,7 +1400,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
1043
1400
 
1044
1401
  default:
1045
1402
  assert(0); /* impossible */
1046
- RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */
1403
+ RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */
1047
1404
  }
1048
1405
  }
1049
1406
 
@@ -1084,11 +1441,11 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
1084
1441
  /* in minimal huffman, we always use X1 variants */
1085
1442
  size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,
1086
1443
  dictPtr, dictEnd - dictPtr,
1087
- workspace, workspaceSize);
1444
+ workspace, workspaceSize, /* flags */ 0);
1088
1445
  #else
1089
1446
  size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
1090
1447
  dictPtr, (size_t)(dictEnd - dictPtr),
1091
- workspace, workspaceSize);
1448
+ workspace, workspaceSize, /* flags */ 0);
1092
1449
  #endif
1093
1450
  RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");
1094
1451
  dictPtr += hSize;
@@ -1176,14 +1533,18 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
1176
1533
  size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
1177
1534
  {
1178
1535
  assert(dctx != NULL);
1536
+ #if ZSTD_TRACE
1537
+ dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0;
1538
+ #endif
1179
1539
  dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */
1180
1540
  dctx->stage = ZSTDds_getFrameHeaderSize;
1541
+ dctx->processedCSize = 0;
1181
1542
  dctx->decodedSize = 0;
1182
1543
  dctx->previousDstEnd = NULL;
1183
1544
  dctx->prefixStart = NULL;
1184
1545
  dctx->virtualStart = NULL;
1185
1546
  dctx->dictEnd = NULL;
1186
- dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
1547
+ dctx->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */
1187
1548
  dctx->litEntropy = dctx->fseEntropy = 0;
1188
1549
  dctx->dictID = 0;
1189
1550
  dctx->bType = bt_reserved;
@@ -1245,7 +1606,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
1245
1606
  * This could for one of the following reasons :
1246
1607
  * - The frame does not require a dictionary (most common case).
1247
1608
  * - The frame was built with dictID intentionally removed.
1248
- * Needed dictionary is a hidden information.
1609
+ * Needed dictionary is a hidden piece of information.
1249
1610
  * Note : this use case also happens when using a non-conformant dictionary.
1250
1611
  * - `srcSize` is too small, and as a result, frame header could not be decoded.
1251
1612
  * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.
@@ -1254,7 +1615,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
1254
1615
  * ZSTD_getFrameHeader(), which will provide a more precise error code. */
1255
1616
  unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
1256
1617
  {
1257
- ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 };
1618
+ ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0, 0, 0 };
1258
1619
  size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);
1259
1620
  if (ZSTD_isError(hError)) return 0;
1260
1621
  return zfp.dictID;
@@ -1283,7 +1644,7 @@ size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
1283
1644
  ZSTD_DStream* ZSTD_createDStream(void)
1284
1645
  {
1285
1646
  DEBUGLOG(3, "ZSTD_createDStream");
1286
- return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
1647
+ return ZSTD_createDCtx_internal(ZSTD_defaultCMem);
1287
1648
  }
1288
1649
 
1289
1650
  ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)
@@ -1293,7 +1654,7 @@ ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)
1293
1654
 
1294
1655
  ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)
1295
1656
  {
1296
- return ZSTD_createDCtx_advanced(customMem);
1657
+ return ZSTD_createDCtx_internal(customMem);
1297
1658
  }
1298
1659
 
1299
1660
  size_t ZSTD_freeDStream(ZSTD_DStream* zds)
@@ -1361,7 +1722,9 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di
1361
1722
  size_t ZSTD_initDStream(ZSTD_DStream* zds)
1362
1723
  {
1363
1724
  DEBUGLOG(4, "ZSTD_initDStream");
1364
- return ZSTD_initDStream_usingDDict(zds, NULL);
1725
+ FORWARD_IF_ERROR(ZSTD_DCtx_reset(zds, ZSTD_reset_session_only), "");
1726
+ FORWARD_IF_ERROR(ZSTD_DCtx_refDDict(zds, NULL), "");
1727
+ return ZSTD_startingInputLength(zds->format);
1365
1728
  }
1366
1729
 
1367
1730
  /* ZSTD_initDStream_usingDDict() :
@@ -1369,6 +1732,7 @@ size_t ZSTD_initDStream(ZSTD_DStream* zds)
1369
1732
  * this function cannot fail */
1370
1733
  size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
1371
1734
  {
1735
+ DEBUGLOG(4, "ZSTD_initDStream_usingDDict");
1372
1736
  FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , "");
1373
1737
  FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , "");
1374
1738
  return ZSTD_startingInputLength(dctx->format);
@@ -1379,6 +1743,7 @@ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
1379
1743
  * this function cannot fail */
1380
1744
  size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
1381
1745
  {
1746
+ DEBUGLOG(4, "ZSTD_resetDStream");
1382
1747
  FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), "");
1383
1748
  return ZSTD_startingInputLength(dctx->format);
1384
1749
  }
@@ -1391,6 +1756,16 @@ size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
1391
1756
  if (ddict) {
1392
1757
  dctx->ddict = ddict;
1393
1758
  dctx->dictUses = ZSTD_use_indefinitely;
1759
+ if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) {
1760
+ if (dctx->ddictSet == NULL) {
1761
+ dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem);
1762
+ if (!dctx->ddictSet) {
1763
+ RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!");
1764
+ }
1765
+ }
1766
+ assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */
1767
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), "");
1768
+ }
1394
1769
  }
1395
1770
  return 0;
1396
1771
  }
@@ -1436,6 +1811,15 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
1436
1811
  bounds.lowerBound = (int)ZSTD_d_validateChecksum;
1437
1812
  bounds.upperBound = (int)ZSTD_d_ignoreChecksum;
1438
1813
  return bounds;
1814
+ case ZSTD_d_refMultipleDDicts:
1815
+ bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict;
1816
+ bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts;
1817
+ return bounds;
1818
+ case ZSTD_d_disableHuffmanAssembly:
1819
+ bounds.lowerBound = 0;
1820
+ bounds.upperBound = 1;
1821
+ return bounds;
1822
+
1439
1823
  default:;
1440
1824
  }
1441
1825
  bounds.error = ERROR(parameter_unsupported);
@@ -1473,6 +1857,12 @@ size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value
1473
1857
  case ZSTD_d_forceIgnoreChecksum:
1474
1858
  *value = (int)dctx->forceIgnoreChecksum;
1475
1859
  return 0;
1860
+ case ZSTD_d_refMultipleDDicts:
1861
+ *value = (int)dctx->refMultipleDDicts;
1862
+ return 0;
1863
+ case ZSTD_d_disableHuffmanAssembly:
1864
+ *value = (int)dctx->disableHufAsm;
1865
+ return 0;
1476
1866
  default:;
1477
1867
  }
1478
1868
  RETURN_ERROR(parameter_unsupported, "");
@@ -1499,6 +1889,17 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value
1499
1889
  CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value);
1500
1890
  dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value;
1501
1891
  return 0;
1892
+ case ZSTD_d_refMultipleDDicts:
1893
+ CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value);
1894
+ if (dctx->staticSize != 0) {
1895
+ RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!");
1896
+ }
1897
+ dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value;
1898
+ return 0;
1899
+ case ZSTD_d_disableHuffmanAssembly:
1900
+ CHECK_DBOUNDS(ZSTD_d_disableHuffmanAssembly, value);
1901
+ dctx->disableHufAsm = value != 0;
1902
+ return 0;
1502
1903
  default:;
1503
1904
  }
1504
1905
  RETURN_ERROR(parameter_unsupported, "");
@@ -1529,7 +1930,8 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)
1529
1930
  size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
1530
1931
  {
1531
1932
  size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
1532
- unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2);
1933
+ /* space is needed to store the litbuffer after the output of a given block without stomping the extDict of a previous run, as well as to cover both windows against wildcopy*/
1934
+ unsigned long long const neededRBSize = windowSize + blockSize + ZSTD_BLOCKSIZE_MAX + (WILDCOPY_OVERLENGTH * 2);
1533
1935
  unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
1534
1936
  size_t const minRBSize = (size_t) neededSize;
1535
1937
  RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,
@@ -1663,10 +2065,12 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1663
2065
  DEBUGLOG(5, "stage zdss_init => transparent reset ");
1664
2066
  zds->streamStage = zdss_loadHeader;
1665
2067
  zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
2068
+ #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
1666
2069
  zds->legacyVersion = 0;
2070
+ #endif
1667
2071
  zds->hostageByte = 0;
1668
2072
  zds->expectedOutBuffer = *output;
1669
- /* fall-through */
2073
+ ZSTD_FALLTHROUGH;
1670
2074
 
1671
2075
  case zdss_loadHeader :
1672
2076
  DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
@@ -1680,7 +2084,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1680
2084
  } }
1681
2085
  #endif
1682
2086
  { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
1683
- DEBUGLOG(5, "header size : %u", (U32)hSize);
2087
+ if (zds->refMultipleDDicts && zds->ddictSet) {
2088
+ ZSTD_DCtx_selectFrameDDict(zds);
2089
+ }
1684
2090
  if (ZSTD_isError(hSize)) {
1685
2091
  #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
1686
2092
  U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);
@@ -1712,6 +2118,11 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1712
2118
  zds->lhSize += remainingInput;
1713
2119
  }
1714
2120
  input->pos = input->size;
2121
+ /* check first few bytes */
2122
+ FORWARD_IF_ERROR(
2123
+ ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format),
2124
+ "First few bytes detected incorrect" );
2125
+ /* return hint input size */
1715
2126
  return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
1716
2127
  }
1717
2128
  assert(ip != NULL);
@@ -1729,8 +2140,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1729
2140
  size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));
1730
2141
  if (ZSTD_isError(decompressedSize)) return decompressedSize;
1731
2142
  DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
2143
+ assert(istart != NULL);
1732
2144
  ip = istart + cSize;
1733
- op += decompressedSize;
2145
+ op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */
1734
2146
  zds->expected = 0;
1735
2147
  zds->streamStage = zdss_init;
1736
2148
  someMoreWork = 0;
@@ -1801,7 +2213,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1801
2213
  zds->outBuffSize = neededOutBuffSize;
1802
2214
  } } }
1803
2215
  zds->streamStage = zdss_read;
1804
- /* fall-through */
2216
+ ZSTD_FALLTHROUGH;
1805
2217
 
1806
2218
  case zdss_read:
1807
2219
  DEBUGLOG(5, "stage zdss_read");
@@ -1814,13 +2226,14 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1814
2226
  }
1815
2227
  if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */
1816
2228
  FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), "");
2229
+ assert(ip != NULL);
1817
2230
  ip += neededInSize;
1818
2231
  /* Function modifies the stage so we must break */
1819
2232
  break;
1820
2233
  } }
1821
2234
  if (ip==iend) { someMoreWork = 0; break; } /* no more input */
1822
2235
  zds->streamStage = zdss_load;
1823
- /* fall-through */
2236
+ ZSTD_FALLTHROUGH;
1824
2237
 
1825
2238
  case zdss_load:
1826
2239
  { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
@@ -1828,7 +2241,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1828
2241
  int const isSkipFrame = ZSTD_isSkipFrame(zds);
1829
2242
  size_t loadedSize;
1830
2243
  /* At this point we shouldn't be decompressing a block that we can stream. */
1831
- assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip));
2244
+ assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)));
1832
2245
  if (isSkipFrame) {
1833
2246
  loadedSize = MIN(toLoad, (size_t)(iend-ip));
1834
2247
  } else {
@@ -1837,8 +2250,11 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1837
2250
  "should never happen");
1838
2251
  loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip));
1839
2252
  }
1840
- ip += loadedSize;
1841
- zds->inPos += loadedSize;
2253
+ if (loadedSize != 0) {
2254
+ /* ip may be NULL */
2255
+ ip += loadedSize;
2256
+ zds->inPos += loadedSize;
2257
+ }
1842
2258
  if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */
1843
2259
 
1844
2260
  /* decode loaded input */
@@ -1848,14 +2264,17 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1848
2264
  break;
1849
2265
  }
1850
2266
  case zdss_flush:
1851
- { size_t const toFlushSize = zds->outEnd - zds->outStart;
2267
+ {
2268
+ size_t const toFlushSize = zds->outEnd - zds->outStart;
1852
2269
  size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize);
1853
- op += flushedSize;
2270
+
2271
+ op = op ? op + flushedSize : op;
2272
+
1854
2273
  zds->outStart += flushedSize;
1855
2274
  if (flushedSize == toFlushSize) { /* flush completed */
1856
2275
  zds->streamStage = zdss_read;
1857
2276
  if ( (zds->outBuffSize < zds->fParams.frameContentSize)
1858
- && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {
2277
+ && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {
1859
2278
  DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",
1860
2279
  (int)(zds->outBuffSize - zds->outStart),
1861
2280
  (U32)zds->fParams.blockSizeMax);
@@ -1869,7 +2288,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1869
2288
 
1870
2289
  default:
1871
2290
  assert(0); /* impossible */
1872
- RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */
2291
+ RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */
1873
2292
  } }
1874
2293
 
1875
2294
  /* result */
@@ -1882,8 +2301,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1882
2301
  if ((ip==istart) && (op==ostart)) { /* no forward progress */
1883
2302
  zds->noForwardProgress ++;
1884
2303
  if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
1885
- RETURN_ERROR_IF(op==oend, dstSize_tooSmall, "");
1886
- RETURN_ERROR_IF(ip==iend, srcSize_wrong, "");
2304
+ RETURN_ERROR_IF(op==oend, noForwardProgress_destFull, "");
2305
+ RETURN_ERROR_IF(ip==iend, noForwardProgress_inputEmpty, "");
1887
2306
  assert(0);
1888
2307
  }
1889
2308
  } else {
@@ -1920,11 +2339,17 @@ size_t ZSTD_decompressStream_simpleArgs (
1920
2339
  void* dst, size_t dstCapacity, size_t* dstPos,
1921
2340
  const void* src, size_t srcSize, size_t* srcPos)
1922
2341
  {
1923
- ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
1924
- ZSTD_inBuffer input = { src, srcSize, *srcPos };
1925
- /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
1926
- size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
1927
- *dstPos = output.pos;
1928
- *srcPos = input.pos;
1929
- return cErr;
2342
+ ZSTD_outBuffer output;
2343
+ ZSTD_inBuffer input;
2344
+ output.dst = dst;
2345
+ output.size = dstCapacity;
2346
+ output.pos = *dstPos;
2347
+ input.src = src;
2348
+ input.size = srcSize;
2349
+ input.pos = *srcPos;
2350
+ { size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
2351
+ *dstPos = output.pos;
2352
+ *srcPos = input.pos;
2353
+ return cErr;
2354
+ }
1930
2355
  }