zstd-ruby 1.4.0.0 → 1.4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +35 -0
  3. data/README.md +2 -2
  4. data/ext/zstdruby/libzstd/Makefile +274 -107
  5. data/ext/zstdruby/libzstd/README.md +75 -16
  6. data/ext/zstdruby/libzstd/common/bitstream.h +59 -51
  7. data/ext/zstdruby/libzstd/common/compiler.h +154 -5
  8. data/ext/zstdruby/libzstd/common/cpu.h +1 -3
  9. data/ext/zstdruby/libzstd/common/debug.c +11 -31
  10. data/ext/zstdruby/libzstd/common/debug.h +22 -49
  11. data/ext/zstdruby/libzstd/common/entropy_common.c +201 -75
  12. data/ext/zstdruby/libzstd/common/error_private.c +3 -1
  13. data/ext/zstdruby/libzstd/common/error_private.h +7 -3
  14. data/ext/zstdruby/libzstd/common/fse.h +50 -42
  15. data/ext/zstdruby/libzstd/common/fse_decompress.c +134 -50
  16. data/ext/zstdruby/libzstd/common/huf.h +41 -38
  17. data/ext/zstdruby/libzstd/common/mem.h +68 -22
  18. data/ext/zstdruby/libzstd/common/pool.c +30 -20
  19. data/ext/zstdruby/libzstd/common/pool.h +3 -3
  20. data/ext/zstdruby/libzstd/common/threading.c +51 -4
  21. data/ext/zstdruby/libzstd/common/threading.h +36 -4
  22. data/ext/zstdruby/libzstd/common/xxhash.c +39 -89
  23. data/ext/zstdruby/libzstd/common/xxhash.h +12 -32
  24. data/ext/zstdruby/libzstd/common/zstd_common.c +10 -10
  25. data/ext/zstdruby/libzstd/common/zstd_deps.h +111 -0
  26. data/ext/zstdruby/libzstd/common/zstd_errors.h +3 -1
  27. data/ext/zstdruby/libzstd/common/zstd_internal.h +231 -72
  28. data/ext/zstdruby/libzstd/common/zstd_trace.c +42 -0
  29. data/ext/zstdruby/libzstd/common/zstd_trace.h +152 -0
  30. data/ext/zstdruby/libzstd/compress/fse_compress.c +47 -63
  31. data/ext/zstdruby/libzstd/compress/hist.c +41 -63
  32. data/ext/zstdruby/libzstd/compress/hist.h +13 -33
  33. data/ext/zstdruby/libzstd/compress/huf_compress.c +288 -172
  34. data/ext/zstdruby/libzstd/compress/zstd_compress.c +2504 -1626
  35. data/ext/zstdruby/libzstd/compress/zstd_compress_internal.h +446 -85
  36. data/ext/zstdruby/libzstd/compress/zstd_compress_literals.c +158 -0
  37. data/ext/zstdruby/libzstd/compress/zstd_compress_literals.h +29 -0
  38. data/ext/zstdruby/libzstd/compress/zstd_compress_sequences.c +433 -0
  39. data/ext/zstdruby/libzstd/compress/zstd_compress_sequences.h +54 -0
  40. data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.c +849 -0
  41. data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.h +32 -0
  42. data/ext/zstdruby/libzstd/compress/zstd_cwksp.h +561 -0
  43. data/ext/zstdruby/libzstd/compress/zstd_double_fast.c +82 -60
  44. data/ext/zstdruby/libzstd/compress/zstd_double_fast.h +2 -2
  45. data/ext/zstdruby/libzstd/compress/zstd_fast.c +106 -80
  46. data/ext/zstdruby/libzstd/compress/zstd_fast.h +2 -2
  47. data/ext/zstdruby/libzstd/compress/zstd_lazy.c +411 -105
  48. data/ext/zstdruby/libzstd/compress/zstd_lazy.h +21 -1
  49. data/ext/zstdruby/libzstd/compress/zstd_ldm.c +296 -207
  50. data/ext/zstdruby/libzstd/compress/zstd_ldm.h +14 -3
  51. data/ext/zstdruby/libzstd/compress/zstd_ldm_geartab.h +103 -0
  52. data/ext/zstdruby/libzstd/compress/zstd_opt.c +260 -148
  53. data/ext/zstdruby/libzstd/compress/zstd_opt.h +1 -1
  54. data/ext/zstdruby/libzstd/compress/zstdmt_compress.c +153 -440
  55. data/ext/zstdruby/libzstd/compress/zstdmt_compress.h +29 -110
  56. data/ext/zstdruby/libzstd/decompress/huf_decompress.c +356 -238
  57. data/ext/zstdruby/libzstd/decompress/zstd_ddict.c +20 -16
  58. data/ext/zstdruby/libzstd/decompress/zstd_ddict.h +3 -3
  59. data/ext/zstdruby/libzstd/decompress/zstd_decompress.c +641 -238
  60. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.c +600 -371
  61. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.h +8 -5
  62. data/ext/zstdruby/libzstd/decompress/zstd_decompress_internal.h +40 -9
  63. data/ext/zstdruby/libzstd/deprecated/zbuff.h +9 -8
  64. data/ext/zstdruby/libzstd/deprecated/zbuff_common.c +2 -2
  65. data/ext/zstdruby/libzstd/deprecated/zbuff_compress.c +1 -1
  66. data/ext/zstdruby/libzstd/deprecated/zbuff_decompress.c +1 -1
  67. data/ext/zstdruby/libzstd/dictBuilder/cover.c +197 -78
  68. data/ext/zstdruby/libzstd/dictBuilder/cover.h +52 -7
  69. data/ext/zstdruby/libzstd/dictBuilder/divsufsort.c +1 -1
  70. data/ext/zstdruby/libzstd/dictBuilder/fastcover.c +84 -66
  71. data/ext/zstdruby/libzstd/dictBuilder/zdict.c +58 -36
  72. data/ext/zstdruby/libzstd/dictBuilder/zdict.h +60 -31
  73. data/ext/zstdruby/libzstd/dll/example/Makefile +2 -1
  74. data/ext/zstdruby/libzstd/dll/example/README.md +16 -22
  75. data/ext/zstdruby/libzstd/legacy/zstd_legacy.h +8 -4
  76. data/ext/zstdruby/libzstd/legacy/zstd_v01.c +115 -111
  77. data/ext/zstdruby/libzstd/legacy/zstd_v01.h +1 -1
  78. data/ext/zstdruby/libzstd/legacy/zstd_v02.c +28 -14
  79. data/ext/zstdruby/libzstd/legacy/zstd_v02.h +1 -1
  80. data/ext/zstdruby/libzstd/legacy/zstd_v03.c +28 -14
  81. data/ext/zstdruby/libzstd/legacy/zstd_v03.h +1 -1
  82. data/ext/zstdruby/libzstd/legacy/zstd_v04.c +36 -19
  83. data/ext/zstdruby/libzstd/legacy/zstd_v04.h +1 -1
  84. data/ext/zstdruby/libzstd/legacy/zstd_v05.c +122 -107
  85. data/ext/zstdruby/libzstd/legacy/zstd_v05.h +2 -2
  86. data/ext/zstdruby/libzstd/legacy/zstd_v06.c +29 -23
  87. data/ext/zstdruby/libzstd/legacy/zstd_v06.h +1 -1
  88. data/ext/zstdruby/libzstd/legacy/zstd_v07.c +34 -24
  89. data/ext/zstdruby/libzstd/legacy/zstd_v07.h +1 -1
  90. data/ext/zstdruby/libzstd/libzstd.pc.in +2 -1
  91. data/ext/zstdruby/libzstd/zstd.h +655 -118
  92. data/lib/zstd-ruby/version.rb +1 -1
  93. data/zstd-ruby.gemspec +1 -1
  94. metadata +20 -10
  95. data/.travis.yml +0 -14
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
2
+ * Copyright (c) 2016-2021, Yann Collet, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under both the BSD-style license (found in the
@@ -14,18 +14,18 @@
14
14
  /*-*******************************************************
15
15
  * Dependencies
16
16
  *********************************************************/
17
- #include <string.h> /* memcpy, memmove, memset */
18
- #include "cpu.h" /* bmi2 */
19
- #include "mem.h" /* low level memory routines */
17
+ #include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
18
+ #include "../common/cpu.h" /* bmi2 */
19
+ #include "../common/mem.h" /* low level memory routines */
20
20
  #define FSE_STATIC_LINKING_ONLY
21
- #include "fse.h"
21
+ #include "../common/fse.h"
22
22
  #define HUF_STATIC_LINKING_ONLY
23
- #include "huf.h"
23
+ #include "../common/huf.h"
24
24
  #include "zstd_decompress_internal.h"
25
25
  #include "zstd_ddict.h"
26
26
 
27
27
  #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
28
- # include "zstd_legacy.h"
28
+ # include "../legacy/zstd_legacy.h"
29
29
  #endif
30
30
 
31
31
 
@@ -65,6 +65,10 @@ void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
65
65
  dctx->virtualStart = ddict->dictContent;
66
66
  dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize;
67
67
  dctx->previousDstEnd = dctx->dictEnd;
68
+ #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
69
+ dctx->dictContentBeginForFuzzing = dctx->prefixStart;
70
+ dctx->dictContentEndForFuzzing = dctx->previousDstEnd;
71
+ #endif
68
72
  if (ddict->entropyPresent) {
69
73
  dctx->litEntropy = 1;
70
74
  dctx->fseEntropy = 1;
@@ -107,7 +111,7 @@ ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict,
107
111
  /* load entropy tables */
108
112
  RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy(
109
113
  &ddict->entropy, ddict->dictContent, ddict->dictSize)),
110
- dictionary_corrupted);
114
+ dictionary_corrupted, "");
111
115
  ddict->entropyPresent = 1;
112
116
  return 0;
113
117
  }
@@ -123,17 +127,17 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict,
123
127
  ddict->dictContent = dict;
124
128
  if (!dict) dictSize = 0;
125
129
  } else {
126
- void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem);
130
+ void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem);
127
131
  ddict->dictBuffer = internalBuffer;
128
132
  ddict->dictContent = internalBuffer;
129
133
  if (!internalBuffer) return ERROR(memory_allocation);
130
- memcpy(internalBuffer, dict, dictSize);
134
+ ZSTD_memcpy(internalBuffer, dict, dictSize);
131
135
  }
132
136
  ddict->dictSize = dictSize;
133
137
  ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
134
138
 
135
139
  /* parse dictionary content */
136
- FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) );
140
+ FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , "");
137
141
 
138
142
  return 0;
139
143
  }
@@ -143,9 +147,9 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
143
147
  ZSTD_dictContentType_e dictContentType,
144
148
  ZSTD_customMem customMem)
145
149
  {
146
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
150
+ if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
147
151
 
148
- { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem);
152
+ { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem);
149
153
  if (ddict == NULL) return NULL;
150
154
  ddict->cMem = customMem;
151
155
  { size_t const initResult = ZSTD_initDDict_internal(ddict,
@@ -194,7 +198,7 @@ const ZSTD_DDict* ZSTD_initStaticDDict(
194
198
  if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */
195
199
  if (sBufferSize < neededSpace) return NULL;
196
200
  if (dictLoadMethod == ZSTD_dlm_byCopy) {
197
- memcpy(ddict+1, dict, dictSize); /* local copy */
201
+ ZSTD_memcpy(ddict+1, dict, dictSize); /* local copy */
198
202
  dict = ddict+1;
199
203
  }
200
204
  if (ZSTD_isError( ZSTD_initDDict_internal(ddict,
@@ -209,8 +213,8 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict)
209
213
  {
210
214
  if (ddict==NULL) return 0; /* support free on NULL */
211
215
  { ZSTD_customMem const cMem = ddict->cMem;
212
- ZSTD_free(ddict->dictBuffer, cMem);
213
- ZSTD_free(ddict, cMem);
216
+ ZSTD_customFree(ddict->dictBuffer, cMem);
217
+ ZSTD_customFree(ddict, cMem);
214
218
  return 0;
215
219
  }
216
220
  }
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
2
+ * Copyright (c) 2016-2021, Yann Collet, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under both the BSD-style license (found in the
@@ -15,8 +15,8 @@
15
15
  /*-*******************************************************
16
16
  * Dependencies
17
17
  *********************************************************/
18
- #include <stddef.h> /* size_t */
19
- #include "zstd.h" /* ZSTD_DDict, and several public functions */
18
+ #include "../common/zstd_deps.h" /* size_t */
19
+ #include "../zstd.h" /* ZSTD_DDict, and several public functions */
20
20
 
21
21
 
22
22
  /*-*******************************************************
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
2
+ * Copyright (c) 2016-2021, Yann Collet, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under both the BSD-style license (found in the
@@ -55,23 +55,163 @@
55
55
  /*-*******************************************************
56
56
  * Dependencies
57
57
  *********************************************************/
58
- #include <string.h> /* memcpy, memmove, memset */
59
- #include "cpu.h" /* bmi2 */
60
- #include "mem.h" /* low level memory routines */
58
+ #include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
59
+ #include "../common/cpu.h" /* bmi2 */
60
+ #include "../common/mem.h" /* low level memory routines */
61
+ #include "../common/zstd_trace.h"
61
62
  #define FSE_STATIC_LINKING_ONLY
62
- #include "fse.h"
63
+ #include "../common/fse.h"
63
64
  #define HUF_STATIC_LINKING_ONLY
64
- #include "huf.h"
65
- #include "zstd_internal.h" /* blockProperties_t */
65
+ #include "../common/huf.h"
66
+ #include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */
67
+ #include "../common/zstd_internal.h" /* blockProperties_t */
66
68
  #include "zstd_decompress_internal.h" /* ZSTD_DCtx */
67
69
  #include "zstd_ddict.h" /* ZSTD_DDictDictContent */
68
70
  #include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
69
71
 
70
72
  #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
71
- # include "zstd_legacy.h"
73
+ # include "../legacy/zstd_legacy.h"
72
74
  #endif
73
75
 
74
76
 
77
+
78
+ /*************************************
79
+ * Multiple DDicts Hashset internals *
80
+ *************************************/
81
+
82
+ #define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4
83
+ #define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float.
84
+ * Currently, that means a 0.75 load factor.
85
+ * So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded
86
+ * the load factor of the ddict hash set.
87
+ */
88
+
89
+ #define DDICT_HASHSET_TABLE_BASE_SIZE 64
90
+ #define DDICT_HASHSET_RESIZE_FACTOR 2
91
+
92
+ /* Hash function to determine starting position of dict insertion within the table
93
+ * Returns an index between [0, hashSet->ddictPtrTableSize]
94
+ */
95
+ static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) {
96
+ const U64 hash = XXH64(&dictID, sizeof(U32), 0);
97
+ /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */
98
+ return hash & (hashSet->ddictPtrTableSize - 1);
99
+ }
100
+
101
+ /* Adds DDict to a hashset without resizing it.
102
+ * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set.
103
+ * Returns 0 if successful, or a zstd error code if something went wrong.
104
+ */
105
+ static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) {
106
+ const U32 dictID = ZSTD_getDictID_fromDDict(ddict);
107
+ size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
108
+ const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;
109
+ RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!");
110
+ DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);
111
+ while (hashSet->ddictPtrTable[idx] != NULL) {
112
+ /* Replace existing ddict if inserting ddict with same dictID */
113
+ if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) {
114
+ DEBUGLOG(4, "DictID already exists, replacing rather than adding");
115
+ hashSet->ddictPtrTable[idx] = ddict;
116
+ return 0;
117
+ }
118
+ idx &= idxRangeMask;
119
+ idx++;
120
+ }
121
+ DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);
122
+ hashSet->ddictPtrTable[idx] = ddict;
123
+ hashSet->ddictPtrCount++;
124
+ return 0;
125
+ }
126
+
127
+ /* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and
128
+ * rehashes all values, allocates new table, frees old table.
129
+ * Returns 0 on success, otherwise a zstd error code.
130
+ */
131
+ static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {
132
+ size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR;
133
+ const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem);
134
+ const ZSTD_DDict** oldTable = hashSet->ddictPtrTable;
135
+ size_t oldTableSize = hashSet->ddictPtrTableSize;
136
+ size_t i;
137
+
138
+ DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize);
139
+ RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!");
140
+ hashSet->ddictPtrTable = newTable;
141
+ hashSet->ddictPtrTableSize = newTableSize;
142
+ hashSet->ddictPtrCount = 0;
143
+ for (i = 0; i < oldTableSize; ++i) {
144
+ if (oldTable[i] != NULL) {
145
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), "");
146
+ }
147
+ }
148
+ ZSTD_customFree((void*)oldTable, customMem);
149
+ DEBUGLOG(4, "Finished re-hash");
150
+ return 0;
151
+ }
152
+
153
+ /* Fetches a DDict with the given dictID
154
+ * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL.
155
+ */
156
+ static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) {
157
+ size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);
158
+ const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;
159
+ DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);
160
+ for (;;) {
161
+ size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]);
162
+ if (currDictID == dictID || currDictID == 0) {
163
+ /* currDictID == 0 implies a NULL ddict entry */
164
+ break;
165
+ } else {
166
+ idx &= idxRangeMask; /* Goes to start of table when we reach the end */
167
+ idx++;
168
+ }
169
+ }
170
+ DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);
171
+ return hashSet->ddictPtrTable[idx];
172
+ }
173
+
174
+ /* Allocates space for and returns a ddict hash set
175
+ * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with.
176
+ * Returns NULL if allocation failed.
177
+ */
178
+ static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) {
179
+ ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem);
180
+ DEBUGLOG(4, "Allocating new hash set");
181
+ ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem);
182
+ ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE;
183
+ ret->ddictPtrCount = 0;
184
+ if (!ret || !ret->ddictPtrTable) {
185
+ return NULL;
186
+ }
187
+ return ret;
188
+ }
189
+
190
+ /* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself.
191
+ * Note: The ZSTD_DDict* within the table are NOT freed.
192
+ */
193
+ static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {
194
+ DEBUGLOG(4, "Freeing ddict hash set");
195
+ if (hashSet && hashSet->ddictPtrTable) {
196
+ ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem);
197
+ }
198
+ if (hashSet) {
199
+ ZSTD_customFree(hashSet, customMem);
200
+ }
201
+ }
202
+
203
+ /* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set.
204
+ * Returns 0 on success, or a ZSTD error.
205
+ */
206
+ static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) {
207
+ DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize);
208
+ if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) {
209
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), "");
210
+ }
211
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), "");
212
+ return 0;
213
+ }
214
+
75
215
  /*-*************************************************************
76
216
  * Context management
77
217
  ***************************************************************/
@@ -88,20 +228,25 @@ size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
88
228
 
89
229
  static size_t ZSTD_startingInputLength(ZSTD_format_e format)
90
230
  {
91
- size_t const startingInputLength = (format==ZSTD_f_zstd1_magicless) ?
92
- ZSTD_FRAMEHEADERSIZE_PREFIX - ZSTD_FRAMEIDSIZE :
93
- ZSTD_FRAMEHEADERSIZE_PREFIX;
94
- ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE);
231
+ size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX(format);
95
232
  /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
96
233
  assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );
97
234
  return startingInputLength;
98
235
  }
99
236
 
237
+ static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx)
238
+ {
239
+ assert(dctx->streamStage == zdss_init);
240
+ dctx->format = ZSTD_f_zstd1;
241
+ dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
242
+ dctx->outBufferMode = ZSTD_bm_buffered;
243
+ dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;
244
+ dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict;
245
+ }
246
+
100
247
  static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
101
248
  {
102
- dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */
103
249
  dctx->staticSize = 0;
104
- dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
105
250
  dctx->ddict = NULL;
106
251
  dctx->ddictLocal = NULL;
107
252
  dctx->dictEnd = NULL;
@@ -114,7 +259,13 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
114
259
  dctx->legacyContext = NULL;
115
260
  dctx->previousLegacyVersion = 0;
116
261
  dctx->noForwardProgress = 0;
262
+ dctx->oversizedDuration = 0;
117
263
  dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
264
+ dctx->ddictSet = NULL;
265
+ ZSTD_DCtx_resetParameters(dctx);
266
+ #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
267
+ dctx->dictContentEndForFuzzing = NULL;
268
+ #endif
118
269
  }
119
270
 
120
271
  ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
@@ -132,9 +283,9 @@ ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
132
283
 
133
284
  ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
134
285
  {
135
- if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
286
+ if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
136
287
 
137
- { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem);
288
+ { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem);
138
289
  if (!dctx) return NULL;
139
290
  dctx->customMem = customMem;
140
291
  ZSTD_initDCtx_internal(dctx);
@@ -162,13 +313,17 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
162
313
  RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx");
163
314
  { ZSTD_customMem const cMem = dctx->customMem;
164
315
  ZSTD_clearDict(dctx);
165
- ZSTD_free(dctx->inBuff, cMem);
316
+ ZSTD_customFree(dctx->inBuff, cMem);
166
317
  dctx->inBuff = NULL;
167
318
  #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
168
319
  if (dctx->legacyContext)
169
320
  ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);
170
321
  #endif
171
- ZSTD_free(dctx, cMem);
322
+ if (dctx->ddictSet) {
323
+ ZSTD_freeDDictHashSet(dctx->ddictSet, cMem);
324
+ dctx->ddictSet = NULL;
325
+ }
326
+ ZSTD_customFree(dctx, cMem);
172
327
  return 0;
173
328
  }
174
329
  }
@@ -177,7 +332,30 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
177
332
  void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
178
333
  {
179
334
  size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);
180
- memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */
335
+ ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */
336
+ }
337
+
338
+ /* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on
339
+ * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then
340
+ * accordingly sets the ddict to be used to decompress the frame.
341
+ *
342
+ * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is.
343
+ *
344
+ * ZSTD_d_refMultipleDDicts must be enabled for this function to be called.
345
+ */
346
+ static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) {
347
+ assert(dctx->refMultipleDDicts && dctx->ddictSet);
348
+ DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame");
349
+ if (dctx->ddict) {
350
+ const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID);
351
+ if (frameDDict) {
352
+ DEBUGLOG(4, "DDict found!");
353
+ ZSTD_clearDict(dctx);
354
+ dctx->dictID = dctx->fParams.dictID;
355
+ dctx->ddict = frameDDict;
356
+ dctx->dictUses = ZSTD_use_indefinitely;
357
+ }
358
+ }
181
359
  }
182
360
 
183
361
 
@@ -211,7 +389,7 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size)
211
389
  static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
212
390
  {
213
391
  size_t const minInputSize = ZSTD_startingInputLength(format);
214
- RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong);
392
+ RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, "");
215
393
 
216
394
  { BYTE const fhd = ((const BYTE*)src)[minInputSize-1];
217
395
  U32 const dictID= fhd & 3;
@@ -244,7 +422,7 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s
244
422
  const BYTE* ip = (const BYTE*)src;
245
423
  size_t const minInputSize = ZSTD_startingInputLength(format);
246
424
 
247
- 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 */
425
+ 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 */
248
426
  if (srcSize < minInputSize) return minInputSize;
249
427
  RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter");
250
428
 
@@ -254,12 +432,12 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s
254
432
  /* skippable frame */
255
433
  if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
256
434
  return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */
257
- memset(zfhPtr, 0, sizeof(*zfhPtr));
435
+ ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr));
258
436
  zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);
259
437
  zfhPtr->frameType = ZSTD_skippableFrame;
260
438
  return 0;
261
439
  }
262
- RETURN_ERROR(prefix_unknown);
440
+ RETURN_ERROR(prefix_unknown, "");
263
441
  }
264
442
 
265
443
  /* ensure there is enough `srcSize` to fully read/decode frame header */
@@ -283,7 +461,7 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s
283
461
  if (!singleSegment) {
284
462
  BYTE const wlByte = ip[pos++];
285
463
  U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
286
- RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge);
464
+ RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, "");
287
465
  windowSize = (1ULL << windowLog);
288
466
  windowSize += (windowSize >> 3) * (wlByte&7);
289
467
  }
@@ -355,13 +533,16 @@ static size_t readSkippableFrameSize(void const* src, size_t srcSize)
355
533
  size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;
356
534
  U32 sizeU32;
357
535
 
358
- RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong);
536
+ RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");
359
537
 
360
538
  sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
361
539
  RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,
362
- frameParameter_unsupported);
363
-
364
- return skippableHeaderSize + sizeU32;
540
+ frameParameter_unsupported, "");
541
+ {
542
+ size_t const skippableSize = skippableHeaderSize + sizeU32;
543
+ RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");
544
+ return skippableSize;
545
+ }
365
546
  }
366
547
 
367
548
  /** ZSTD_findDecompressedSize() :
@@ -373,16 +554,15 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
373
554
  {
374
555
  unsigned long long totalDstSize = 0;
375
556
 
376
- while (srcSize >= ZSTD_FRAMEHEADERSIZE_PREFIX) {
557
+ while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) {
377
558
  U32 const magicNumber = MEM_readLE32(src);
378
559
 
379
560
  if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
380
561
  size_t const skippableSize = readSkippableFrameSize(src, srcSize);
381
- if (ZSTD_isError(skippableSize))
382
- return skippableSize;
383
- if (srcSize < skippableSize) {
562
+ if (ZSTD_isError(skippableSize)) {
384
563
  return ZSTD_CONTENTSIZE_ERROR;
385
564
  }
565
+ assert(skippableSize <= srcSize);
386
566
 
387
567
  src = (const BYTE *)src + skippableSize;
388
568
  srcSize -= skippableSize;
@@ -429,20 +609,29 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
429
609
 
430
610
  /** ZSTD_decodeFrameHeader() :
431
611
  * `headerSize` must be the size provided by ZSTD_frameHeaderSize().
612
+ * If multiple DDict references are enabled, also will choose the correct DDict to use.
432
613
  * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
433
614
  static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
434
615
  {
435
616
  size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
436
617
  if (ZSTD_isError(result)) return result; /* invalid header */
437
618
  RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");
619
+
620
+ /* Reference DDict requested by frame if dctx references multiple ddicts */
621
+ if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) {
622
+ ZSTD_DCtx_selectFrameDDict(dctx);
623
+ }
624
+
438
625
  #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
439
626
  /* Skip the dictID check in fuzzing mode, because it makes the search
440
627
  * harder.
441
628
  */
442
629
  RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID),
443
- dictionary_wrong);
630
+ dictionary_wrong, "");
444
631
  #endif
445
- if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
632
+ dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0;
633
+ if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0);
634
+ dctx->processedCSize += headerSize;
446
635
  return 0;
447
636
  }
448
637
 
@@ -457,7 +646,7 @@ static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)
457
646
  static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize)
458
647
  {
459
648
  ZSTD_frameSizeInfo frameSizeInfo;
460
- memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
649
+ ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
461
650
 
462
651
  #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
463
652
  if (ZSTD_isLegacy(src, srcSize))
@@ -467,6 +656,8 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize
467
656
  if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
468
657
  && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
469
658
  frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);
659
+ assert(ZSTD_isError(frameSizeInfo.compressedSize) ||
660
+ frameSizeInfo.compressedSize <= srcSize);
470
661
  return frameSizeInfo;
471
662
  } else {
472
663
  const BYTE* ip = (const BYTE*)src;
@@ -510,7 +701,7 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize
510
701
  ip += 4;
511
702
  }
512
703
 
513
- frameSizeInfo.compressedSize = ip - ipstart;
704
+ frameSizeInfo.compressedSize = (size_t)(ip - ipstart);
514
705
  frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)
515
706
  ? zfh.frameContentSize
516
707
  : nbBlocks * zfh.blockSizeMax;
@@ -529,7 +720,6 @@ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
529
720
  return frameSizeInfo.compressedSize;
530
721
  }
531
722
 
532
-
533
723
  /** ZSTD_decompressBound() :
534
724
  * compatible with legacy mode
535
725
  * `src` must point to the start of a ZSTD frame or a skippeable frame
@@ -546,6 +736,7 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
546
736
  unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
547
737
  if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)
548
738
  return ZSTD_CONTENTSIZE_ERROR;
739
+ assert(srcSize >= compressedSize);
549
740
  src = (const BYTE*)src + compressedSize;
550
741
  srcSize -= compressedSize;
551
742
  bound += decompressedBound;
@@ -558,22 +749,12 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
558
749
  * Frame decoding
559
750
  ***************************************************************/
560
751
 
561
-
562
- void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
563
- {
564
- if (dst != dctx->previousDstEnd) { /* not contiguous */
565
- dctx->dictEnd = dctx->previousDstEnd;
566
- dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
567
- dctx->prefixStart = dst;
568
- dctx->previousDstEnd = dst;
569
- }
570
- }
571
-
572
752
  /** ZSTD_insertBlock() :
573
- insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
753
+ * insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
574
754
  size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
575
755
  {
576
- ZSTD_checkContinuity(dctx, blockStart);
756
+ DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);
757
+ ZSTD_checkContinuity(dctx, blockStart, blockSize);
577
758
  dctx->previousDstEnd = (const char*)blockStart + blockSize;
578
759
  return blockSize;
579
760
  }
@@ -583,12 +764,12 @@ static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,
583
764
  const void* src, size_t srcSize)
584
765
  {
585
766
  DEBUGLOG(5, "ZSTD_copyRawBlock");
767
+ RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, "");
586
768
  if (dst == NULL) {
587
769
  if (srcSize == 0) return 0;
588
- RETURN_ERROR(dstBuffer_null);
770
+ RETURN_ERROR(dstBuffer_null, "");
589
771
  }
590
- RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall);
591
- memcpy(dst, src, srcSize);
772
+ ZSTD_memcpy(dst, src, srcSize);
592
773
  return srcSize;
593
774
  }
594
775
 
@@ -596,15 +777,41 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
596
777
  BYTE b,
597
778
  size_t regenSize)
598
779
  {
780
+ RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, "");
599
781
  if (dst == NULL) {
600
782
  if (regenSize == 0) return 0;
601
- RETURN_ERROR(dstBuffer_null);
783
+ RETURN_ERROR(dstBuffer_null, "");
602
784
  }
603
- RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall);
604
- memset(dst, b, regenSize);
785
+ ZSTD_memset(dst, b, regenSize);
605
786
  return regenSize;
606
787
  }
607
788
 
789
+ static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming)
790
+ {
791
+ #if ZSTD_TRACE
792
+ if (dctx->traceCtx) {
793
+ ZSTD_Trace trace;
794
+ ZSTD_memset(&trace, 0, sizeof(trace));
795
+ trace.version = ZSTD_VERSION_NUMBER;
796
+ trace.streaming = streaming;
797
+ if (dctx->ddict) {
798
+ trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict);
799
+ trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict);
800
+ trace.dictionaryIsCold = dctx->ddictIsCold;
801
+ }
802
+ trace.uncompressedSize = (size_t)uncompressedSize;
803
+ trace.compressedSize = (size_t)compressedSize;
804
+ trace.dctx = dctx;
805
+ ZSTD_trace_decompress_end(dctx->traceCtx, &trace);
806
+ }
807
+ #else
808
+ (void)dctx;
809
+ (void)uncompressedSize;
810
+ (void)compressedSize;
811
+ (void)streaming;
812
+ #endif
813
+ }
814
+
608
815
 
609
816
  /*! ZSTD_decompressFrame() :
610
817
  * @dctx must be properly initialized
@@ -614,9 +821,10 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
614
821
  void* dst, size_t dstCapacity,
615
822
  const void** srcPtr, size_t *srcSizePtr)
616
823
  {
617
- const BYTE* ip = (const BYTE*)(*srcPtr);
618
- BYTE* const ostart = (BYTE* const)dst;
619
- BYTE* const oend = ostart + dstCapacity;
824
+ const BYTE* const istart = (const BYTE*)(*srcPtr);
825
+ const BYTE* ip = istart;
826
+ BYTE* const ostart = (BYTE*)dst;
827
+ BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart;
620
828
  BYTE* op = ostart;
621
829
  size_t remainingSrcSize = *srcSizePtr;
622
830
 
@@ -624,15 +832,16 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
624
832
 
625
833
  /* check */
626
834
  RETURN_ERROR_IF(
627
- remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN+ZSTD_blockHeaderSize,
628
- srcSize_wrong);
835
+ remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize,
836
+ srcSize_wrong, "");
629
837
 
630
838
  /* Frame Header */
631
- { size_t const frameHeaderSize = ZSTD_frameHeaderSize(ip, ZSTD_FRAMEHEADERSIZE_PREFIX);
839
+ { size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal(
840
+ ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format);
632
841
  if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
633
842
  RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize,
634
- srcSize_wrong);
635
- FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) );
843
+ srcSize_wrong, "");
844
+ FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , "");
636
845
  ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;
637
846
  }
638
847
 
@@ -645,28 +854,30 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
645
854
 
646
855
  ip += ZSTD_blockHeaderSize;
647
856
  remainingSrcSize -= ZSTD_blockHeaderSize;
648
- RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong);
857
+ RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, "");
649
858
 
650
859
  switch(blockProperties.blockType)
651
860
  {
652
861
  case bt_compressed:
653
- decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1);
862
+ decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oend-op), ip, cBlockSize, /* frame */ 1);
654
863
  break;
655
864
  case bt_raw :
656
- decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize);
865
+ decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize);
657
866
  break;
658
867
  case bt_rle :
659
- decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize);
868
+ decodedSize = ZSTD_setRleBlock(op, (size_t)(oend-op), *ip, blockProperties.origSize);
660
869
  break;
661
870
  case bt_reserved :
662
871
  default:
663
- RETURN_ERROR(corruption_detected);
872
+ RETURN_ERROR(corruption_detected, "invalid block type");
664
873
  }
665
874
 
666
875
  if (ZSTD_isError(decodedSize)) return decodedSize;
667
- if (dctx->fParams.checksumFlag)
876
+ if (dctx->validateChecksum)
668
877
  XXH64_update(&dctx->xxhState, op, decodedSize);
669
- op += decodedSize;
878
+ if (decodedSize != 0)
879
+ op += decodedSize;
880
+ assert(ip != NULL);
670
881
  ip += cBlockSize;
671
882
  remainingSrcSize -= cBlockSize;
672
883
  if (blockProperties.lastBlock) break;
@@ -674,22 +885,24 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
674
885
 
675
886
  if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
676
887
  RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize,
677
- corruption_detected);
888
+ corruption_detected, "");
678
889
  }
679
890
  if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
680
- U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
681
- U32 checkRead;
682
- RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong);
683
- checkRead = MEM_readLE32(ip);
684
- RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong);
891
+ RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, "");
892
+ if (!dctx->forceIgnoreChecksum) {
893
+ U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
894
+ U32 checkRead;
895
+ checkRead = MEM_readLE32(ip);
896
+ RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, "");
897
+ }
685
898
  ip += 4;
686
899
  remainingSrcSize -= 4;
687
900
  }
688
-
901
+ ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0);
689
902
  /* Allow caller to get size read */
690
903
  *srcPtr = ip;
691
904
  *srcSizePtr = remainingSrcSize;
692
- return op-ostart;
905
+ return (size_t)(op-ostart);
693
906
  }
694
907
 
695
908
  static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
@@ -709,7 +922,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
709
922
  dictSize = ZSTD_DDict_dictSize(ddict);
710
923
  }
711
924
 
712
- while (srcSize >= ZSTD_FRAMEHEADERSIZE_PREFIX) {
925
+ while (srcSize >= ZSTD_startingInputLength(dctx->format)) {
713
926
 
714
927
  #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
715
928
  if (ZSTD_isLegacy(src, srcSize)) {
@@ -722,7 +935,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
722
935
  decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
723
936
  if (ZSTD_isError(decodedSize)) return decodedSize;
724
937
 
725
- assert(decodedSize <=- dstCapacity);
938
+ assert(decodedSize <= dstCapacity);
726
939
  dst = (BYTE*)dst + decodedSize;
727
940
  dstCapacity -= decodedSize;
728
941
 
@@ -738,9 +951,8 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
738
951
  (unsigned)magicNumber, ZSTD_MAGICNUMBER);
739
952
  if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
740
953
  size_t const skippableSize = readSkippableFrameSize(src, srcSize);
741
- if (ZSTD_isError(skippableSize))
742
- return skippableSize;
743
- RETURN_ERROR_IF(srcSize < skippableSize, srcSize_wrong);
954
+ FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed");
955
+ assert(skippableSize <= srcSize);
744
956
 
745
957
  src = (const BYTE *)src + skippableSize;
746
958
  srcSize -= skippableSize;
@@ -749,13 +961,13 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
749
961
 
750
962
  if (ddict) {
751
963
  /* we were called from ZSTD_decompress_usingDDict */
752
- FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict));
964
+ FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), "");
753
965
  } else {
754
966
  /* this will initialize correctly with no dict if dict == NULL, so
755
967
  * use this in all cases but ddict */
756
- FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize));
968
+ FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), "");
757
969
  }
758
- ZSTD_checkContinuity(dctx, dst);
970
+ ZSTD_checkContinuity(dctx, dst, dstCapacity);
759
971
 
760
972
  { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
761
973
  &src, &srcSize);
@@ -763,18 +975,17 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
763
975
  (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)
764
976
  && (moreThan1Frame==1),
765
977
  srcSize_wrong,
766
- "at least one frame successfully completed, but following "
767
- "bytes are garbage: it's more likely to be a srcSize error, "
768
- "specifying more bytes than compressed size of frame(s). This "
769
- "error message replaces ERROR(prefix_unknown), which would be "
770
- "confusing, as the first header is actually correct. Note that "
771
- "one could be unlucky, it might be a corruption error instead, "
772
- "happening right at the place where we expect zstd magic "
773
- "bytes. But this is _much_ less likely than a srcSize field "
774
- "error.");
978
+ "At least one frame successfully completed, "
979
+ "but following bytes are garbage: "
980
+ "it's more likely to be a srcSize error, "
981
+ "specifying more input bytes than size of frame(s). "
982
+ "Note: one could be unlucky, it might be a corruption error instead, "
983
+ "happening right at the place where we expect zstd magic bytes. "
984
+ "But this is _much_ less likely than a srcSize field error.");
775
985
  if (ZSTD_isError(res)) return res;
776
986
  assert(res <= dstCapacity);
777
- dst = (BYTE*)dst + res;
987
+ if (res != 0)
988
+ dst = (BYTE*)dst + res;
778
989
  dstCapacity -= res;
779
990
  }
780
991
  moreThan1Frame = 1;
@@ -782,7 +993,7 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
782
993
 
783
994
  RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed");
784
995
 
785
- return (BYTE*)dst - (BYTE*)dststart;
996
+ return (size_t)((BYTE*)dst - (BYTE*)dststart);
786
997
  }
787
998
 
788
999
  size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
@@ -822,7 +1033,7 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr
822
1033
  #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)
823
1034
  size_t regenSize;
824
1035
  ZSTD_DCtx* const dctx = ZSTD_createDCtx();
825
- RETURN_ERROR_IF(dctx==NULL, memory_allocation);
1036
+ RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!");
826
1037
  regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);
827
1038
  ZSTD_freeDCtx(dctx);
828
1039
  return regenSize;
@@ -840,6 +1051,24 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr
840
1051
  ****************************************/
841
1052
  size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
842
1053
 
1054
+ /**
1055
+ * Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed,
1056
+ * we allow taking a partial block as the input. Currently only raw uncompressed blocks can
1057
+ * be streamed.
1058
+ *
1059
+ * For blocks that can be streamed, this allows us to reduce the latency until we produce
1060
+ * output, and avoid copying the input.
1061
+ *
1062
+ * @param inputSize - The total amount of input that the caller currently has.
1063
+ */
1064
+ static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) {
1065
+ if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock))
1066
+ return dctx->expected;
1067
+ if (dctx->bType != bt_raw)
1068
+ return dctx->expected;
1069
+ return MIN(MAX(inputSize, 1), dctx->expected);
1070
+ }
1071
+
843
1072
  ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
844
1073
  switch(dctx->stage)
845
1074
  {
@@ -872,8 +1101,10 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
872
1101
  {
873
1102
  DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);
874
1103
  /* Sanity check */
875
- RETURN_ERROR_IF(srcSize != dctx->expected, srcSize_wrong, "not allowed");
876
- if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
1104
+ RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed");
1105
+ ZSTD_checkContinuity(dctx, dst, dstCapacity);
1106
+
1107
+ dctx->processedCSize += srcSize;
877
1108
 
878
1109
  switch (dctx->stage)
879
1110
  {
@@ -882,22 +1113,22 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
882
1113
  if (dctx->format == ZSTD_f_zstd1) { /* allows header */
883
1114
  assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */
884
1115
  if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
885
- memcpy(dctx->headerBuffer, src, srcSize);
1116
+ ZSTD_memcpy(dctx->headerBuffer, src, srcSize);
886
1117
  dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */
887
1118
  dctx->stage = ZSTDds_decodeSkippableHeader;
888
1119
  return 0;
889
1120
  } }
890
1121
  dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
891
1122
  if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
892
- memcpy(dctx->headerBuffer, src, srcSize);
1123
+ ZSTD_memcpy(dctx->headerBuffer, src, srcSize);
893
1124
  dctx->expected = dctx->headerSize - srcSize;
894
1125
  dctx->stage = ZSTDds_decodeFrameHeader;
895
1126
  return 0;
896
1127
 
897
1128
  case ZSTDds_decodeFrameHeader:
898
1129
  assert(src != NULL);
899
- memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
900
- FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize));
1130
+ ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
1131
+ FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), "");
901
1132
  dctx->expected = ZSTD_blockHeaderSize;
902
1133
  dctx->stage = ZSTDds_decodeBlockHeader;
903
1134
  return 0;
@@ -906,6 +1137,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
906
1137
  { blockProperties_t bp;
907
1138
  size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
908
1139
  if (ZSTD_isError(cBlockSize)) return cBlockSize;
1140
+ RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum");
909
1141
  dctx->expected = cBlockSize;
910
1142
  dctx->bType = bp.blockType;
911
1143
  dctx->rleSize = bp.origSize;
@@ -938,49 +1170,66 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
938
1170
  case bt_compressed:
939
1171
  DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
940
1172
  rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
1173
+ dctx->expected = 0; /* Streaming not supported */
941
1174
  break;
942
1175
  case bt_raw :
1176
+ assert(srcSize <= dctx->expected);
943
1177
  rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);
1178
+ FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed");
1179
+ assert(rSize == srcSize);
1180
+ dctx->expected -= rSize;
944
1181
  break;
945
1182
  case bt_rle :
946
1183
  rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize);
1184
+ dctx->expected = 0; /* Streaming not supported */
947
1185
  break;
948
1186
  case bt_reserved : /* should never happen */
949
1187
  default:
950
- RETURN_ERROR(corruption_detected);
1188
+ RETURN_ERROR(corruption_detected, "invalid block type");
951
1189
  }
952
- if (ZSTD_isError(rSize)) return rSize;
1190
+ FORWARD_IF_ERROR(rSize, "");
1191
+ RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum");
953
1192
  DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);
954
1193
  dctx->decodedSize += rSize;
955
- if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
1194
+ if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize);
1195
+ dctx->previousDstEnd = (char*)dst + rSize;
1196
+
1197
+ /* Stay on the same stage until we are finished streaming the block. */
1198
+ if (dctx->expected > 0) {
1199
+ return rSize;
1200
+ }
956
1201
 
957
1202
  if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
958
1203
  DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize);
959
1204
  RETURN_ERROR_IF(
960
1205
  dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
961
1206
  && dctx->decodedSize != dctx->fParams.frameContentSize,
962
- corruption_detected);
1207
+ corruption_detected, "");
963
1208
  if (dctx->fParams.checksumFlag) { /* another round for frame checksum */
964
1209
  dctx->expected = 4;
965
1210
  dctx->stage = ZSTDds_checkChecksum;
966
1211
  } else {
1212
+ ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);
967
1213
  dctx->expected = 0; /* ends here */
968
1214
  dctx->stage = ZSTDds_getFrameHeaderSize;
969
1215
  }
970
1216
  } else {
971
1217
  dctx->stage = ZSTDds_decodeBlockHeader;
972
1218
  dctx->expected = ZSTD_blockHeaderSize;
973
- dctx->previousDstEnd = (char*)dst + rSize;
974
1219
  }
975
1220
  return rSize;
976
1221
  }
977
1222
 
978
1223
  case ZSTDds_checkChecksum:
979
1224
  assert(srcSize == 4); /* guaranteed by dctx->expected */
980
- { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
981
- U32 const check32 = MEM_readLE32(src);
982
- DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
983
- RETURN_ERROR_IF(check32 != h32, checksum_wrong);
1225
+ {
1226
+ if (dctx->validateChecksum) {
1227
+ U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
1228
+ U32 const check32 = MEM_readLE32(src);
1229
+ DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
1230
+ RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");
1231
+ }
1232
+ ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);
984
1233
  dctx->expected = 0;
985
1234
  dctx->stage = ZSTDds_getFrameHeaderSize;
986
1235
  return 0;
@@ -989,7 +1238,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
989
1238
  case ZSTDds_decodeSkippableHeader:
990
1239
  assert(src != NULL);
991
1240
  assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
992
- memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */
1241
+ ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */
993
1242
  dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */
994
1243
  dctx->stage = ZSTDds_skipFrame;
995
1244
  return 0;
@@ -1001,7 +1250,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
1001
1250
 
1002
1251
  default:
1003
1252
  assert(0); /* impossible */
1004
- RETURN_ERROR(GENERIC); /* some compiler require default to do something */
1253
+ RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */
1005
1254
  }
1006
1255
  }
1007
1256
 
@@ -1012,6 +1261,10 @@ static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dict
1012
1261
  dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
1013
1262
  dctx->prefixStart = dict;
1014
1263
  dctx->previousDstEnd = (const char*)dict + dictSize;
1264
+ #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1265
+ dctx->dictContentBeginForFuzzing = dctx->prefixStart;
1266
+ dctx->dictContentEndForFuzzing = dctx->previousDstEnd;
1267
+ #endif
1015
1268
  return 0;
1016
1269
  }
1017
1270
 
@@ -1025,7 +1278,7 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
1025
1278
  const BYTE* dictPtr = (const BYTE*)dict;
1026
1279
  const BYTE* const dictEnd = dictPtr + dictSize;
1027
1280
 
1028
- RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted);
1281
+ RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small");
1029
1282
  assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */
1030
1283
  dictPtr += 8; /* skip header = magic + dictID */
1031
1284
 
@@ -1041,63 +1294,69 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
1041
1294
  workspace, workspaceSize);
1042
1295
  #else
1043
1296
  size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
1044
- dictPtr, dictEnd - dictPtr,
1297
+ dictPtr, (size_t)(dictEnd - dictPtr),
1045
1298
  workspace, workspaceSize);
1046
1299
  #endif
1047
- RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted);
1300
+ RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");
1048
1301
  dictPtr += hSize;
1049
1302
  }
1050
1303
 
1051
1304
  { short offcodeNCount[MaxOff+1];
1052
1305
  unsigned offcodeMaxValue = MaxOff, offcodeLog;
1053
- size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
1054
- RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted);
1055
- RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted);
1056
- RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted);
1306
+ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr));
1307
+ RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
1308
+ RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, "");
1309
+ RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
1057
1310
  ZSTD_buildFSETable( entropy->OFTable,
1058
1311
  offcodeNCount, offcodeMaxValue,
1059
1312
  OF_base, OF_bits,
1060
- offcodeLog);
1313
+ offcodeLog,
1314
+ entropy->workspace, sizeof(entropy->workspace),
1315
+ /* bmi2 */0);
1061
1316
  dictPtr += offcodeHeaderSize;
1062
1317
  }
1063
1318
 
1064
1319
  { short matchlengthNCount[MaxML+1];
1065
1320
  unsigned matchlengthMaxValue = MaxML, matchlengthLog;
1066
- size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
1067
- RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted);
1068
- RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted);
1069
- RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted);
1321
+ size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));
1322
+ RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
1323
+ RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, "");
1324
+ RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
1070
1325
  ZSTD_buildFSETable( entropy->MLTable,
1071
1326
  matchlengthNCount, matchlengthMaxValue,
1072
1327
  ML_base, ML_bits,
1073
- matchlengthLog);
1328
+ matchlengthLog,
1329
+ entropy->workspace, sizeof(entropy->workspace),
1330
+ /* bmi2 */ 0);
1074
1331
  dictPtr += matchlengthHeaderSize;
1075
1332
  }
1076
1333
 
1077
1334
  { short litlengthNCount[MaxLL+1];
1078
1335
  unsigned litlengthMaxValue = MaxLL, litlengthLog;
1079
- size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
1080
- RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted);
1081
- RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted);
1082
- RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted);
1336
+ size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));
1337
+ RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
1338
+ RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, "");
1339
+ RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
1083
1340
  ZSTD_buildFSETable( entropy->LLTable,
1084
1341
  litlengthNCount, litlengthMaxValue,
1085
1342
  LL_base, LL_bits,
1086
- litlengthLog);
1343
+ litlengthLog,
1344
+ entropy->workspace, sizeof(entropy->workspace),
1345
+ /* bmi2 */ 0);
1087
1346
  dictPtr += litlengthHeaderSize;
1088
1347
  }
1089
1348
 
1090
- RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted);
1349
+ RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");
1091
1350
  { int i;
1092
1351
  size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));
1093
1352
  for (i=0; i<3; i++) {
1094
1353
  U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;
1095
- RETURN_ERROR_IF(rep==0 || rep >= dictContentSize,
1096
- dictionary_corrupted);
1354
+ RETURN_ERROR_IF(rep==0 || rep > dictContentSize,
1355
+ dictionary_corrupted, "");
1097
1356
  entropy->rep[i] = rep;
1098
1357
  } }
1099
1358
 
1100
- return dictPtr - (const BYTE*)dict;
1359
+ return (size_t)(dictPtr - (const BYTE*)dict);
1101
1360
  }
1102
1361
 
1103
1362
  static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
@@ -1111,7 +1370,7 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
1111
1370
 
1112
1371
  /* load entropy tables */
1113
1372
  { size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize);
1114
- RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted);
1373
+ RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, "");
1115
1374
  dict = (const char*)dict + eSize;
1116
1375
  dictSize -= eSize;
1117
1376
  }
@@ -1124,8 +1383,12 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
1124
1383
  size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
1125
1384
  {
1126
1385
  assert(dctx != NULL);
1386
+ #if ZSTD_TRACE
1387
+ dctx->traceCtx = ZSTD_trace_decompress_begin(dctx);
1388
+ #endif
1127
1389
  dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */
1128
1390
  dctx->stage = ZSTDds_getFrameHeaderSize;
1391
+ dctx->processedCSize = 0;
1129
1392
  dctx->decodedSize = 0;
1130
1393
  dctx->previousDstEnd = NULL;
1131
1394
  dctx->prefixStart = NULL;
@@ -1134,8 +1397,9 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
1134
1397
  dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
1135
1398
  dctx->litEntropy = dctx->fseEntropy = 0;
1136
1399
  dctx->dictID = 0;
1400
+ dctx->bType = bt_reserved;
1137
1401
  ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
1138
- memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
1402
+ ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
1139
1403
  dctx->LLTptr = dctx->entropy.LLTable;
1140
1404
  dctx->MLTptr = dctx->entropy.MLTable;
1141
1405
  dctx->OFTptr = dctx->entropy.OFTable;
@@ -1145,11 +1409,11 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
1145
1409
 
1146
1410
  size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1147
1411
  {
1148
- FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) );
1412
+ FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");
1149
1413
  if (dict && dictSize)
1150
1414
  RETURN_ERROR_IF(
1151
1415
  ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)),
1152
- dictionary_corrupted);
1416
+ dictionary_corrupted, "");
1153
1417
  return 0;
1154
1418
  }
1155
1419
 
@@ -1168,7 +1432,7 @@ size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
1168
1432
  DEBUGLOG(4, "DDict is %s",
1169
1433
  dctx->ddictIsCold ? "~cold~" : "hot!");
1170
1434
  }
1171
- FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) );
1435
+ FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");
1172
1436
  if (ddict) { /* NULL ddict is equivalent to no dictionary */
1173
1437
  ZSTD_copyDDictParameters(dctx, ddict);
1174
1438
  }
@@ -1259,11 +1523,11 @@ size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx,
1259
1523
  ZSTD_dictLoadMethod_e dictLoadMethod,
1260
1524
  ZSTD_dictContentType_e dictContentType)
1261
1525
  {
1262
- RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong);
1526
+ RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
1263
1527
  ZSTD_clearDict(dctx);
1264
- if (dict && dictSize >= 8) {
1528
+ if (dict && dictSize != 0) {
1265
1529
  dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);
1266
- RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation);
1530
+ RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!");
1267
1531
  dctx->ddict = dctx->ddictLocal;
1268
1532
  dctx->dictUses = ZSTD_use_indefinitely;
1269
1533
  }
@@ -1282,7 +1546,7 @@ size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSi
1282
1546
 
1283
1547
  size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
1284
1548
  {
1285
- FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType));
1549
+ FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), "");
1286
1550
  dctx->dictUses = ZSTD_use_once;
1287
1551
  return 0;
1288
1552
  }
@@ -1294,14 +1558,14 @@ size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSiz
1294
1558
 
1295
1559
 
1296
1560
  /* ZSTD_initDStream_usingDict() :
1297
- * return : expected size, aka ZSTD_FRAMEHEADERSIZE_PREFIX.
1561
+ * return : expected size, aka ZSTD_startingInputLength().
1298
1562
  * this function cannot fail */
1299
1563
  size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
1300
1564
  {
1301
1565
  DEBUGLOG(4, "ZSTD_initDStream_usingDict");
1302
- FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) );
1303
- FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) );
1304
- return ZSTD_FRAMEHEADERSIZE_PREFIX;
1566
+ FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , "");
1567
+ FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , "");
1568
+ return ZSTD_startingInputLength(zds->format);
1305
1569
  }
1306
1570
 
1307
1571
  /* note : this variant can't fail */
@@ -1316,28 +1580,38 @@ size_t ZSTD_initDStream(ZSTD_DStream* zds)
1316
1580
  * this function cannot fail */
1317
1581
  size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
1318
1582
  {
1319
- FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) );
1320
- FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) );
1321
- return ZSTD_FRAMEHEADERSIZE_PREFIX;
1583
+ FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , "");
1584
+ FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , "");
1585
+ return ZSTD_startingInputLength(dctx->format);
1322
1586
  }
1323
1587
 
1324
1588
  /* ZSTD_resetDStream() :
1325
- * return : expected size, aka ZSTD_FRAMEHEADERSIZE_PREFIX.
1589
+ * return : expected size, aka ZSTD_startingInputLength().
1326
1590
  * this function cannot fail */
1327
1591
  size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
1328
1592
  {
1329
- FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only));
1330
- return ZSTD_FRAMEHEADERSIZE_PREFIX;
1593
+ FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), "");
1594
+ return ZSTD_startingInputLength(dctx->format);
1331
1595
  }
1332
1596
 
1333
1597
 
1334
1598
  size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
1335
1599
  {
1336
- RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong);
1600
+ RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
1337
1601
  ZSTD_clearDict(dctx);
1338
1602
  if (ddict) {
1339
1603
  dctx->ddict = ddict;
1340
1604
  dctx->dictUses = ZSTD_use_indefinitely;
1605
+ if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) {
1606
+ if (dctx->ddictSet == NULL) {
1607
+ dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem);
1608
+ if (!dctx->ddictSet) {
1609
+ RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!");
1610
+ }
1611
+ }
1612
+ assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */
1613
+ FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), "");
1614
+ }
1341
1615
  }
1342
1616
  return 0;
1343
1617
  }
@@ -1350,16 +1624,16 @@ size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
1350
1624
  ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);
1351
1625
  size_t const min = (size_t)1 << bounds.lowerBound;
1352
1626
  size_t const max = (size_t)1 << bounds.upperBound;
1353
- RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong);
1354
- RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound);
1355
- RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound);
1627
+ RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
1628
+ RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, "");
1629
+ RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, "");
1356
1630
  dctx->maxWindowSize = maxWindowSize;
1357
1631
  return 0;
1358
1632
  }
1359
1633
 
1360
1634
  size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
1361
1635
  {
1362
- return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format);
1636
+ return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format);
1363
1637
  }
1364
1638
 
1365
1639
  ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
@@ -1375,6 +1649,18 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
1375
1649
  bounds.upperBound = (int)ZSTD_f_zstd1_magicless;
1376
1650
  ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
1377
1651
  return bounds;
1652
+ case ZSTD_d_stableOutBuffer:
1653
+ bounds.lowerBound = (int)ZSTD_bm_buffered;
1654
+ bounds.upperBound = (int)ZSTD_bm_stable;
1655
+ return bounds;
1656
+ case ZSTD_d_forceIgnoreChecksum:
1657
+ bounds.lowerBound = (int)ZSTD_d_validateChecksum;
1658
+ bounds.upperBound = (int)ZSTD_d_ignoreChecksum;
1659
+ return bounds;
1660
+ case ZSTD_d_refMultipleDDicts:
1661
+ bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict;
1662
+ bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts;
1663
+ return bounds;
1378
1664
  default:;
1379
1665
  }
1380
1666
  bounds.error = ERROR(parameter_unsupported);
@@ -1394,12 +1680,35 @@ static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)
1394
1680
  }
1395
1681
 
1396
1682
  #define CHECK_DBOUNDS(p,v) { \
1397
- RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound); \
1683
+ RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \
1684
+ }
1685
+
1686
+ size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value)
1687
+ {
1688
+ switch (param) {
1689
+ case ZSTD_d_windowLogMax:
1690
+ *value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize);
1691
+ return 0;
1692
+ case ZSTD_d_format:
1693
+ *value = (int)dctx->format;
1694
+ return 0;
1695
+ case ZSTD_d_stableOutBuffer:
1696
+ *value = (int)dctx->outBufferMode;
1697
+ return 0;
1698
+ case ZSTD_d_forceIgnoreChecksum:
1699
+ *value = (int)dctx->forceIgnoreChecksum;
1700
+ return 0;
1701
+ case ZSTD_d_refMultipleDDicts:
1702
+ *value = (int)dctx->refMultipleDDicts;
1703
+ return 0;
1704
+ default:;
1705
+ }
1706
+ RETURN_ERROR(parameter_unsupported, "");
1398
1707
  }
1399
1708
 
1400
1709
  size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)
1401
1710
  {
1402
- RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong);
1711
+ RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
1403
1712
  switch(dParam) {
1404
1713
  case ZSTD_d_windowLogMax:
1405
1714
  if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT;
@@ -1410,9 +1719,24 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value
1410
1719
  CHECK_DBOUNDS(ZSTD_d_format, value);
1411
1720
  dctx->format = (ZSTD_format_e)value;
1412
1721
  return 0;
1722
+ case ZSTD_d_stableOutBuffer:
1723
+ CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value);
1724
+ dctx->outBufferMode = (ZSTD_bufferMode_e)value;
1725
+ return 0;
1726
+ case ZSTD_d_forceIgnoreChecksum:
1727
+ CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value);
1728
+ dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value;
1729
+ return 0;
1730
+ case ZSTD_d_refMultipleDDicts:
1731
+ CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value);
1732
+ if (dctx->staticSize != 0) {
1733
+ RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!");
1734
+ }
1735
+ dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value;
1736
+ return 0;
1413
1737
  default:;
1414
1738
  }
1415
- RETURN_ERROR(parameter_unsupported);
1739
+ RETURN_ERROR(parameter_unsupported, "");
1416
1740
  }
1417
1741
 
1418
1742
  size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
@@ -1424,10 +1748,9 @@ size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
1424
1748
  }
1425
1749
  if ( (reset == ZSTD_reset_parameters)
1426
1750
  || (reset == ZSTD_reset_session_and_parameters) ) {
1427
- RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong);
1751
+ RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
1428
1752
  ZSTD_clearDict(dctx);
1429
- dctx->format = ZSTD_f_zstd1;
1430
- dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
1753
+ ZSTD_DCtx_resetParameters(dctx);
1431
1754
  }
1432
1755
  return 0;
1433
1756
  }
@@ -1445,7 +1768,7 @@ size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long
1445
1768
  unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
1446
1769
  size_t const minRBSize = (size_t) neededSize;
1447
1770
  RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,
1448
- frameParameter_windowTooLarge);
1771
+ frameParameter_windowTooLarge, "");
1449
1772
  return minRBSize;
1450
1773
  }
1451
1774
 
@@ -1463,30 +1786,94 @@ size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
1463
1786
  ZSTD_frameHeader zfh;
1464
1787
  size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);
1465
1788
  if (ZSTD_isError(err)) return err;
1466
- RETURN_ERROR_IF(err>0, srcSize_wrong);
1789
+ RETURN_ERROR_IF(err>0, srcSize_wrong, "");
1467
1790
  RETURN_ERROR_IF(zfh.windowSize > windowSizeMax,
1468
- frameParameter_windowTooLarge);
1791
+ frameParameter_windowTooLarge, "");
1469
1792
  return ZSTD_estimateDStreamSize((size_t)zfh.windowSize);
1470
1793
  }
1471
1794
 
1472
1795
 
1473
1796
  /* ***** Decompression ***** */
1474
1797
 
1475
- MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
1798
+ static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)
1476
1799
  {
1477
- size_t const length = MIN(dstCapacity, srcSize);
1478
- memcpy(dst, src, length);
1479
- return length;
1800
+ return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR;
1480
1801
  }
1481
1802
 
1803
+ static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)
1804
+ {
1805
+ if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize))
1806
+ zds->oversizedDuration++;
1807
+ else
1808
+ zds->oversizedDuration = 0;
1809
+ }
1810
+
1811
+ static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds)
1812
+ {
1813
+ return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION;
1814
+ }
1815
+
1816
+ /* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */
1817
+ static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output)
1818
+ {
1819
+ ZSTD_outBuffer const expect = zds->expectedOutBuffer;
1820
+ /* No requirement when ZSTD_obm_stable is not enabled. */
1821
+ if (zds->outBufferMode != ZSTD_bm_stable)
1822
+ return 0;
1823
+ /* Any buffer is allowed in zdss_init, this must be the same for every other call until
1824
+ * the context is reset.
1825
+ */
1826
+ if (zds->streamStage == zdss_init)
1827
+ return 0;
1828
+ /* The buffer must match our expectation exactly. */
1829
+ if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size)
1830
+ return 0;
1831
+ RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!");
1832
+ }
1833
+
1834
+ /* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream()
1835
+ * and updates the stage and the output buffer state. This call is extracted so it can be
1836
+ * used both when reading directly from the ZSTD_inBuffer, and in buffered input mode.
1837
+ * NOTE: You must break after calling this function since the streamStage is modified.
1838
+ */
1839
+ static size_t ZSTD_decompressContinueStream(
1840
+ ZSTD_DStream* zds, char** op, char* oend,
1841
+ void const* src, size_t srcSize) {
1842
+ int const isSkipFrame = ZSTD_isSkipFrame(zds);
1843
+ if (zds->outBufferMode == ZSTD_bm_buffered) {
1844
+ size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart;
1845
+ size_t const decodedSize = ZSTD_decompressContinue(zds,
1846
+ zds->outBuff + zds->outStart, dstSize, src, srcSize);
1847
+ FORWARD_IF_ERROR(decodedSize, "");
1848
+ if (!decodedSize && !isSkipFrame) {
1849
+ zds->streamStage = zdss_read;
1850
+ } else {
1851
+ zds->outEnd = zds->outStart + decodedSize;
1852
+ zds->streamStage = zdss_flush;
1853
+ }
1854
+ } else {
1855
+ /* Write directly into the output buffer */
1856
+ size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op);
1857
+ size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize);
1858
+ FORWARD_IF_ERROR(decodedSize, "");
1859
+ *op += decodedSize;
1860
+ /* Flushing is not needed. */
1861
+ zds->streamStage = zdss_read;
1862
+ assert(*op <= oend);
1863
+ assert(zds->outBufferMode == ZSTD_bm_stable);
1864
+ }
1865
+ return 0;
1866
+ }
1482
1867
 
1483
1868
  size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
1484
1869
  {
1485
- const char* const istart = (const char*)(input->src) + input->pos;
1486
- const char* const iend = (const char*)(input->src) + input->size;
1870
+ const char* const src = (const char*)input->src;
1871
+ const char* const istart = input->pos != 0 ? src + input->pos : src;
1872
+ const char* const iend = input->size != 0 ? src + input->size : src;
1487
1873
  const char* ip = istart;
1488
- char* const ostart = (char*)(output->dst) + output->pos;
1489
- char* const oend = (char*)(output->dst) + output->size;
1874
+ char* const dst = (char*)output->dst;
1875
+ char* const ostart = output->pos != 0 ? dst + output->pos : dst;
1876
+ char* const oend = output->size != 0 ? dst + output->size : dst;
1490
1877
  char* op = ostart;
1491
1878
  U32 someMoreWork = 1;
1492
1879
 
@@ -1502,6 +1889,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1502
1889
  "forbidden. out: pos: %u vs size: %u",
1503
1890
  (U32)output->pos, (U32)output->size);
1504
1891
  DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
1892
+ FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), "");
1505
1893
 
1506
1894
  while (someMoreWork) {
1507
1895
  switch(zds->streamStage)
@@ -1512,6 +1900,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1512
1900
  zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
1513
1901
  zds->legacyVersion = 0;
1514
1902
  zds->hostageByte = 0;
1903
+ zds->expectedOutBuffer = *output;
1515
1904
  /* fall-through */
1516
1905
 
1517
1906
  case zdss_loadHeader :
@@ -1526,6 +1915,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1526
1915
  } }
1527
1916
  #endif
1528
1917
  { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
1918
+ if (zds->refMultipleDDicts && zds->ddictSet) {
1919
+ ZSTD_DCtx_selectFrameDDict(zds);
1920
+ }
1529
1921
  DEBUGLOG(5, "header size : %u", (U32)hSize);
1530
1922
  if (ZSTD_isError(hSize)) {
1531
1923
  #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
@@ -1539,7 +1931,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1539
1931
  "legacy support is incompatible with static dctx");
1540
1932
  FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext,
1541
1933
  zds->previousLegacyVersion, legacyVersion,
1542
- dict, dictSize));
1934
+ dict, dictSize), "");
1543
1935
  zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;
1544
1936
  { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);
1545
1937
  if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */
@@ -1554,24 +1946,25 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1554
1946
  assert(iend >= ip);
1555
1947
  if (toLoad > remainingInput) { /* not enough input to load full header */
1556
1948
  if (remainingInput > 0) {
1557
- memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
1949
+ ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
1558
1950
  zds->lhSize += remainingInput;
1559
1951
  }
1560
1952
  input->pos = input->size;
1561
- return (MAX(ZSTD_FRAMEHEADERSIZE_MIN, hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
1953
+ return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
1562
1954
  }
1563
1955
  assert(ip != NULL);
1564
- memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
1956
+ ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
1565
1957
  break;
1566
1958
  } }
1567
1959
 
1568
1960
  /* check for single-pass mode opportunity */
1569
- if (zds->fParams.frameContentSize && zds->fParams.windowSize /* skippable frame if == 0 */
1961
+ if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
1962
+ && zds->fParams.frameType != ZSTD_skippableFrame
1570
1963
  && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
1571
- size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart);
1964
+ size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart));
1572
1965
  if (cSize <= (size_t)(iend-istart)) {
1573
1966
  /* shortcut : using single-pass mode */
1574
- size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, ZSTD_getDDict(zds));
1967
+ size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));
1575
1968
  if (ZSTD_isError(decompressedSize)) return decompressedSize;
1576
1969
  DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
1577
1970
  ip = istart + cSize;
@@ -1582,15 +1975,23 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1582
1975
  break;
1583
1976
  } }
1584
1977
 
1978
+ /* Check output buffer is large enough for ZSTD_odm_stable. */
1979
+ if (zds->outBufferMode == ZSTD_bm_stable
1980
+ && zds->fParams.frameType != ZSTD_skippableFrame
1981
+ && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
1982
+ && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) {
1983
+ RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small");
1984
+ }
1985
+
1585
1986
  /* Consume header (see ZSTDds_decodeFrameHeader) */
1586
1987
  DEBUGLOG(4, "Consume header");
1587
- FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)));
1988
+ FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), "");
1588
1989
 
1589
1990
  if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
1590
1991
  zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);
1591
1992
  zds->stage = ZSTDds_skipFrame;
1592
1993
  } else {
1593
- FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize));
1994
+ FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), "");
1594
1995
  zds->expected = ZSTD_blockHeaderSize;
1595
1996
  zds->stage = ZSTDds_decodeBlockHeader;
1596
1997
  }
@@ -1601,40 +2002,48 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1601
2002
  (U32)(zds->maxWindowSize >> 10) );
1602
2003
  zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
1603
2004
  RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,
1604
- frameParameter_windowTooLarge);
2005
+ frameParameter_windowTooLarge, "");
1605
2006
 
1606
2007
  /* Adapt buffer sizes to frame header instructions */
1607
2008
  { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
1608
- size_t const neededOutBuffSize = ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize);
1609
- if ((zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize)) {
1610
- size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
1611
- DEBUGLOG(4, "inBuff : from %u to %u",
1612
- (U32)zds->inBuffSize, (U32)neededInBuffSize);
1613
- DEBUGLOG(4, "outBuff : from %u to %u",
1614
- (U32)zds->outBuffSize, (U32)neededOutBuffSize);
1615
- if (zds->staticSize) { /* static DCtx */
1616
- DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);
1617
- assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */
1618
- RETURN_ERROR_IF(
1619
- bufferSize > zds->staticSize - sizeof(ZSTD_DCtx),
1620
- memory_allocation);
1621
- } else {
1622
- ZSTD_free(zds->inBuff, zds->customMem);
1623
- zds->inBuffSize = 0;
1624
- zds->outBuffSize = 0;
1625
- zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem);
1626
- RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation);
1627
- }
1628
- zds->inBuffSize = neededInBuffSize;
1629
- zds->outBuff = zds->inBuff + zds->inBuffSize;
1630
- zds->outBuffSize = neededOutBuffSize;
1631
- } }
2009
+ size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered
2010
+ ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize)
2011
+ : 0;
2012
+
2013
+ ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);
2014
+
2015
+ { int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize);
2016
+ int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds);
2017
+
2018
+ if (tooSmall || tooLarge) {
2019
+ size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
2020
+ DEBUGLOG(4, "inBuff : from %u to %u",
2021
+ (U32)zds->inBuffSize, (U32)neededInBuffSize);
2022
+ DEBUGLOG(4, "outBuff : from %u to %u",
2023
+ (U32)zds->outBuffSize, (U32)neededOutBuffSize);
2024
+ if (zds->staticSize) { /* static DCtx */
2025
+ DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);
2026
+ assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */
2027
+ RETURN_ERROR_IF(
2028
+ bufferSize > zds->staticSize - sizeof(ZSTD_DCtx),
2029
+ memory_allocation, "");
2030
+ } else {
2031
+ ZSTD_customFree(zds->inBuff, zds->customMem);
2032
+ zds->inBuffSize = 0;
2033
+ zds->outBuffSize = 0;
2034
+ zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem);
2035
+ RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, "");
2036
+ }
2037
+ zds->inBuffSize = neededInBuffSize;
2038
+ zds->outBuff = zds->inBuff + zds->inBuffSize;
2039
+ zds->outBuffSize = neededOutBuffSize;
2040
+ } } }
1632
2041
  zds->streamStage = zdss_read;
1633
2042
  /* fall-through */
1634
2043
 
1635
2044
  case zdss_read:
1636
2045
  DEBUGLOG(5, "stage zdss_read");
1637
- { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
2046
+ { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip));
1638
2047
  DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);
1639
2048
  if (neededInSize==0) { /* end of frame */
1640
2049
  zds->streamStage = zdss_init;
@@ -1642,15 +2051,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1642
2051
  break;
1643
2052
  }
1644
2053
  if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */
1645
- int const isSkipFrame = ZSTD_isSkipFrame(zds);
1646
- size_t const decodedSize = ZSTD_decompressContinue(zds,
1647
- zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart),
1648
- ip, neededInSize);
1649
- if (ZSTD_isError(decodedSize)) return decodedSize;
2054
+ FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), "");
1650
2055
  ip += neededInSize;
1651
- if (!decodedSize && !isSkipFrame) break; /* this was just a header */
1652
- zds->outEnd = zds->outStart + decodedSize;
1653
- zds->streamStage = zdss_flush;
2056
+ /* Function modifies the stage so we must break */
1654
2057
  break;
1655
2058
  } }
1656
2059
  if (ip==iend) { someMoreWork = 0; break; } /* no more input */
@@ -1662,33 +2065,29 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1662
2065
  size_t const toLoad = neededInSize - zds->inPos;
1663
2066
  int const isSkipFrame = ZSTD_isSkipFrame(zds);
1664
2067
  size_t loadedSize;
2068
+ /* At this point we shouldn't be decompressing a block that we can stream. */
2069
+ assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip));
1665
2070
  if (isSkipFrame) {
1666
2071
  loadedSize = MIN(toLoad, (size_t)(iend-ip));
1667
2072
  } else {
1668
2073
  RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos,
1669
2074
  corruption_detected,
1670
2075
  "should never happen");
1671
- loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);
2076
+ loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip));
1672
2077
  }
1673
2078
  ip += loadedSize;
1674
2079
  zds->inPos += loadedSize;
1675
2080
  if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */
1676
2081
 
1677
2082
  /* decode loaded input */
1678
- { size_t const decodedSize = ZSTD_decompressContinue(zds,
1679
- zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart,
1680
- zds->inBuff, neededInSize);
1681
- if (ZSTD_isError(decodedSize)) return decodedSize;
1682
- zds->inPos = 0; /* input is consumed */
1683
- if (!decodedSize && !isSkipFrame) { zds->streamStage = zdss_read; break; } /* this was just a header */
1684
- zds->outEnd = zds->outStart + decodedSize;
1685
- } }
1686
- zds->streamStage = zdss_flush;
1687
- /* fall-through */
1688
-
2083
+ zds->inPos = 0; /* input is consumed */
2084
+ FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), "");
2085
+ /* Function modifies the stage so we must break */
2086
+ break;
2087
+ }
1689
2088
  case zdss_flush:
1690
2089
  { size_t const toFlushSize = zds->outEnd - zds->outStart;
1691
- size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize);
2090
+ size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize);
1692
2091
  op += flushedSize;
1693
2092
  zds->outStart += flushedSize;
1694
2093
  if (flushedSize == toFlushSize) { /* flush completed */
@@ -1708,17 +2107,21 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
1708
2107
 
1709
2108
  default:
1710
2109
  assert(0); /* impossible */
1711
- RETURN_ERROR(GENERIC); /* some compiler require default to do something */
2110
+ RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */
1712
2111
  } }
1713
2112
 
1714
2113
  /* result */
1715
2114
  input->pos = (size_t)(ip - (const char*)(input->src));
1716
2115
  output->pos = (size_t)(op - (char*)(output->dst));
2116
+
2117
+ /* Update the expected output buffer for ZSTD_obm_stable. */
2118
+ zds->expectedOutBuffer = *output;
2119
+
1717
2120
  if ((ip==istart) && (op==ostart)) { /* no forward progress */
1718
2121
  zds->noForwardProgress ++;
1719
2122
  if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
1720
- RETURN_ERROR_IF(op==oend, dstSize_tooSmall);
1721
- RETURN_ERROR_IF(ip==iend, srcSize_wrong);
2123
+ RETURN_ERROR_IF(op==oend, dstSize_tooSmall, "");
2124
+ RETURN_ERROR_IF(ip==iend, srcSize_wrong, "");
1722
2125
  assert(0);
1723
2126
  }
1724
2127
  } else {