extlz4 0.2.4.2 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +5 -5
  2. data/HISTORY.ja.md +25 -0
  3. data/README.md +49 -41
  4. data/bin/extlz4 +1 -1
  5. data/contrib/lz4/INSTALL +1 -0
  6. data/contrib/lz4/Makefile.inc +87 -0
  7. data/contrib/lz4/NEWS +89 -0
  8. data/contrib/lz4/README.md +42 -36
  9. data/contrib/lz4/build/README.md +55 -0
  10. data/contrib/lz4/build/VS2010/datagen/datagen.vcxproj +169 -0
  11. data/contrib/lz4/build/VS2010/frametest/frametest.vcxproj +176 -0
  12. data/contrib/lz4/build/VS2010/fullbench-dll/fullbench-dll.vcxproj +180 -0
  13. data/contrib/lz4/build/VS2010/fullbench/fullbench.vcxproj +176 -0
  14. data/contrib/lz4/build/VS2010/fuzzer/fuzzer.vcxproj +173 -0
  15. data/contrib/lz4/build/VS2010/liblz4-dll/liblz4-dll.rc +51 -0
  16. data/contrib/lz4/build/VS2010/liblz4-dll/liblz4-dll.vcxproj +179 -0
  17. data/contrib/lz4/build/VS2010/liblz4/liblz4.vcxproj +175 -0
  18. data/contrib/lz4/build/VS2010/lz4.sln +98 -0
  19. data/contrib/lz4/build/VS2010/lz4/lz4.rc +51 -0
  20. data/contrib/lz4/build/VS2010/lz4/lz4.vcxproj +189 -0
  21. data/contrib/lz4/build/VS2017/datagen/datagen.vcxproj +173 -0
  22. data/contrib/lz4/build/VS2017/frametest/frametest.vcxproj +180 -0
  23. data/contrib/lz4/build/VS2017/fullbench-dll/fullbench-dll.vcxproj +184 -0
  24. data/contrib/lz4/build/VS2017/fullbench/fullbench.vcxproj +180 -0
  25. data/contrib/lz4/build/VS2017/fuzzer/fuzzer.vcxproj +177 -0
  26. data/contrib/lz4/build/VS2017/liblz4-dll/liblz4-dll.rc +51 -0
  27. data/contrib/lz4/build/VS2017/liblz4-dll/liblz4-dll.vcxproj +183 -0
  28. data/contrib/lz4/build/VS2017/liblz4/liblz4.vcxproj +179 -0
  29. data/contrib/lz4/build/VS2017/lz4.sln +103 -0
  30. data/contrib/lz4/build/VS2017/lz4/lz4.rc +51 -0
  31. data/contrib/lz4/build/VS2017/lz4/lz4.vcxproj +164 -0
  32. data/contrib/lz4/build/cmake/CMakeLists.txt +235 -0
  33. data/contrib/lz4/lib/README.md +98 -34
  34. data/contrib/lz4/lib/liblz4-dll.rc.in +35 -0
  35. data/contrib/lz4/lib/lz4.c +1698 -681
  36. data/contrib/lz4/lib/lz4.h +546 -235
  37. data/contrib/lz4/lib/lz4frame.c +608 -378
  38. data/contrib/lz4/lib/lz4frame.h +315 -83
  39. data/contrib/lz4/lib/lz4frame_static.h +4 -100
  40. data/contrib/lz4/lib/lz4hc.c +1090 -282
  41. data/contrib/lz4/lib/lz4hc.h +276 -141
  42. data/contrib/lz4/lib/xxhash.c +371 -235
  43. data/contrib/lz4/lib/xxhash.h +128 -93
  44. data/contrib/lz4/ossfuzz/Makefile +78 -0
  45. data/contrib/lz4/ossfuzz/compress_frame_fuzzer.c +48 -0
  46. data/contrib/lz4/ossfuzz/compress_fuzzer.c +58 -0
  47. data/contrib/lz4/ossfuzz/compress_hc_fuzzer.c +64 -0
  48. data/contrib/lz4/ossfuzz/decompress_frame_fuzzer.c +75 -0
  49. data/contrib/lz4/ossfuzz/decompress_fuzzer.c +62 -0
  50. data/contrib/lz4/ossfuzz/fuzz.h +48 -0
  51. data/contrib/lz4/ossfuzz/fuzz_data_producer.c +77 -0
  52. data/contrib/lz4/ossfuzz/fuzz_data_producer.h +36 -0
  53. data/contrib/lz4/ossfuzz/fuzz_helpers.h +94 -0
  54. data/contrib/lz4/ossfuzz/lz4_helpers.c +51 -0
  55. data/contrib/lz4/ossfuzz/lz4_helpers.h +13 -0
  56. data/contrib/lz4/ossfuzz/ossfuzz.sh +23 -0
  57. data/contrib/lz4/ossfuzz/round_trip_frame_fuzzer.c +43 -0
  58. data/contrib/lz4/ossfuzz/round_trip_fuzzer.c +57 -0
  59. data/contrib/lz4/ossfuzz/round_trip_hc_fuzzer.c +44 -0
  60. data/contrib/lz4/ossfuzz/round_trip_stream_fuzzer.c +302 -0
  61. data/contrib/lz4/ossfuzz/standaloneengine.c +74 -0
  62. data/contrib/lz4/ossfuzz/travisoss.sh +26 -0
  63. data/contrib/lz4/tmp +0 -0
  64. data/contrib/lz4/tmpsparse +0 -0
  65. data/ext/blockapi.c +5 -5
  66. data/ext/extlz4.c +2 -0
  67. data/ext/extlz4.h +5 -0
  68. data/ext/frameapi.c +1 -1
  69. data/ext/hashargs.c +2 -2
  70. data/ext/hashargs.h +1 -1
  71. data/ext/lz4_amalgam.c +0 -23
  72. data/gemstub.rb +5 -16
  73. data/lib/extlz4.rb +51 -3
  74. data/lib/extlz4/oldstream.rb +1 -1
  75. data/test/common.rb +2 -2
  76. metadata +73 -16
  77. data/contrib/lz4/circle.yml +0 -39
  78. data/contrib/lz4/lib/lz4opt.h +0 -366
  79. data/lib/extlz4/version.rb +0 -3
@@ -1,41 +1,44 @@
1
1
  /*
2
- LZ4 auto-framing library
3
- Copyright (C) 2011-2016, Yann Collet.
4
-
5
- BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
-
7
- Redistribution and use in source and binary forms, with or without
8
- modification, are permitted provided that the following conditions are
9
- met:
10
-
11
- * Redistributions of source code must retain the above copyright
12
- notice, this list of conditions and the following disclaimer.
13
- * Redistributions in binary form must reproduce the above
14
- copyright notice, this list of conditions and the following disclaimer
15
- in the documentation and/or other materials provided with the
16
- distribution.
17
-
18
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
-
30
- You can contact the author at :
31
- - LZ4 homepage : http://www.lz4.org
32
- - LZ4 source repository : https://github.com/lz4/lz4
33
- */
2
+ * LZ4 auto-framing library
3
+ * Copyright (C) 2011-2016, Yann Collet.
4
+ *
5
+ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are
9
+ * met:
10
+ *
11
+ * - Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * - Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following disclaimer
15
+ * in the documentation and/or other materials provided with the
16
+ * distribution.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ *
30
+ * You can contact the author at :
31
+ * - LZ4 homepage : http://www.lz4.org
32
+ * - LZ4 source repository : https://github.com/lz4/lz4
33
+ */
34
34
 
35
35
  /* LZ4F is a stand-alone API to create LZ4-compressed Frames
36
- * in full conformance with specification v1.5.0
37
- * All related operations, including memory management, are handled by the library.
38
- * */
36
+ * in full conformance with specification v1.6.1 .
37
+ * This library rely upon memory management capabilities (malloc, free)
38
+ * provided either by <stdlib.h>,
39
+ * or redirected towards another library of user's choice
40
+ * (see Memory Routines below).
41
+ */
39
42
 
40
43
 
41
44
  /*-************************************
@@ -46,20 +49,47 @@ You can contact the author at :
46
49
  #endif
47
50
 
48
51
 
52
+ /*-************************************
53
+ * Tuning parameters
54
+ **************************************/
55
+ /*
56
+ * LZ4F_HEAPMODE :
57
+ * Select how default compression functions will allocate memory for their hash table,
58
+ * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).
59
+ */
60
+ #ifndef LZ4F_HEAPMODE
61
+ # define LZ4F_HEAPMODE 0
62
+ #endif
63
+
64
+
49
65
  /*-************************************
50
66
  * Memory routines
51
67
  **************************************/
52
- #include <stdlib.h> /* malloc, calloc, free */
53
- #define ALLOCATOR(s) calloc(1,s)
54
- #define FREEMEM free
68
+ /*
69
+ * User may redirect invocations of
70
+ * malloc(), calloc() and free()
71
+ * towards another library or solution of their choice
72
+ * by modifying below section.
73
+ */
74
+ #ifndef LZ4_SRC_INCLUDED /* avoid redefinition when sources are coalesced */
75
+ # include <stdlib.h> /* malloc, calloc, free */
76
+ # define ALLOC(s) malloc(s)
77
+ # define ALLOC_AND_ZERO(s) calloc(1,(s))
78
+ # define FREEMEM(p) free(p)
79
+ #endif
80
+
55
81
  #include <string.h> /* memset, memcpy, memmove */
56
- #define MEM_INIT memset
82
+ #ifndef LZ4_SRC_INCLUDED /* avoid redefinition when sources are coalesced */
83
+ # define MEM_INIT(p,v,s) memset((p),(v),(s))
84
+ #endif
57
85
 
58
86
 
59
87
  /*-************************************
60
- * Includes
88
+ * Library declarations
61
89
  **************************************/
62
- #include "lz4frame_static.h"
90
+ #define LZ4F_STATIC_LINKING_ONLY
91
+ #include "lz4frame.h"
92
+ #define LZ4_STATIC_LINKING_ONLY
63
93
  #include "lz4.h"
64
94
  #define LZ4_HC_STATIC_LINKING_ONLY
65
95
  #include "lz4hc.h"
@@ -70,8 +100,29 @@ You can contact the author at :
70
100
  /*-************************************
71
101
  * Debug
72
102
  **************************************/
103
+ #if defined(LZ4_DEBUG) && (LZ4_DEBUG>=1)
104
+ # include <assert.h>
105
+ #else
106
+ # ifndef assert
107
+ # define assert(condition) ((void)0)
108
+ # endif
109
+ #endif
110
+
73
111
  #define LZ4F_STATIC_ASSERT(c) { enum { LZ4F_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
74
112
 
113
+ #if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2) && !defined(DEBUGLOG)
114
+ # include <stdio.h>
115
+ static int g_debuglog_enable = 1;
116
+ # define DEBUGLOG(l, ...) { \
117
+ if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \
118
+ fprintf(stderr, __FILE__ ": "); \
119
+ fprintf(stderr, __VA_ARGS__); \
120
+ fprintf(stderr, " \n"); \
121
+ } }
122
+ #else
123
+ # define DEBUGLOG(l, ...) {} /* disabled */
124
+ #endif
125
+
75
126
 
76
127
  /*-************************************
77
128
  * Basic Types
@@ -97,8 +148,8 @@ static U32 LZ4F_readLE32 (const void* src)
97
148
  {
98
149
  const BYTE* const srcPtr = (const BYTE*)src;
99
150
  U32 value32 = srcPtr[0];
100
- value32 += (srcPtr[1]<<8);
101
- value32 += (srcPtr[2]<<16);
151
+ value32 += ((U32)srcPtr[1])<< 8;
152
+ value32 += ((U32)srcPtr[2])<<16;
102
153
  value32 += ((U32)srcPtr[3])<<24;
103
154
  return value32;
104
155
  }
@@ -143,9 +194,11 @@ static void LZ4F_writeLE64 (void* dst, U64 value64)
143
194
  /*-************************************
144
195
  * Constants
145
196
  **************************************/
146
- #define KB *(1<<10)
147
- #define MB *(1<<20)
148
- #define GB *(1<<30)
197
+ #ifndef LZ4_SRC_INCLUDED /* avoid double definition */
198
+ # define KB *(1<<10)
199
+ # define MB *(1<<20)
200
+ # define GB *(1<<30)
201
+ #endif
149
202
 
150
203
  #define _1BIT 0x01
151
204
  #define _2BITS 0x03
@@ -158,9 +211,10 @@ static void LZ4F_writeLE64 (void* dst, U64 value64)
158
211
  #define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U
159
212
  #define LZ4F_BLOCKSIZEID_DEFAULT LZ4F_max64KB
160
213
 
161
- static const size_t minFHSize = 7;
214
+ static const size_t minFHSize = LZ4F_HEADER_SIZE_MIN; /* 7 */
162
215
  static const size_t maxFHSize = LZ4F_HEADER_SIZE_MAX; /* 19 */
163
- static const size_t BHSize = 4;
216
+ static const size_t BHSize = LZ4F_BLOCK_HEADER_SIZE; /* block header : size, and compress flag */
217
+ static const size_t BFSize = LZ4F_BLOCK_CHECKSUM_SIZE; /* block footer : checksum (optional) */
164
218
 
165
219
 
166
220
  /*-************************************
@@ -180,7 +234,8 @@ typedef struct LZ4F_cctx_s
180
234
  U64 totalInSize;
181
235
  XXH32_state_t xxh;
182
236
  void* lz4CtxPtr;
183
- U32 lz4CtxLevel; /* 0: unallocated; 1: LZ4_stream_t; 3: LZ4_streamHC_t */
237
+ U16 lz4CtxAlloc; /* sized for: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */
238
+ U16 lz4CtxState; /* in use as: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */
184
239
  } LZ4F_cctx_t;
185
240
 
186
241
 
@@ -220,22 +275,22 @@ unsigned LZ4F_getVersion(void) { return LZ4F_VERSION; }
220
275
 
221
276
  int LZ4F_compressionLevel_max(void) { return LZ4HC_CLEVEL_MAX; }
222
277
 
223
-
224
- /*-************************************
225
- * Private functions
226
- **************************************/
227
- #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
228
-
229
- static size_t LZ4F_getBlockSize(unsigned blockSizeID)
278
+ size_t LZ4F_getBlockSize(unsigned blockSizeID)
230
279
  {
231
280
  static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB };
232
281
 
233
282
  if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;
234
- blockSizeID -= 4;
235
- if (blockSizeID > 3) return err0r(LZ4F_ERROR_maxBlockSize_invalid);
283
+ if (blockSizeID < LZ4F_max64KB || blockSizeID > LZ4F_max4MB)
284
+ return err0r(LZ4F_ERROR_maxBlockSize_invalid);
285
+ blockSizeID -= LZ4F_max64KB;
236
286
  return blockSizes[blockSizeID];
237
287
  }
238
288
 
289
+ /*-************************************
290
+ * Private functions
291
+ **************************************/
292
+ #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
293
+
239
294
  static BYTE LZ4F_headerChecksum (const void* header, size_t length)
240
295
  {
241
296
  U32 const xxh = XXH32(header, length, 0);
@@ -270,9 +325,9 @@ static size_t LZ4F_compressBound_internal(size_t srcSize,
270
325
  const LZ4F_preferences_t* preferencesPtr,
271
326
  size_t alreadyBuffered)
272
327
  {
273
- LZ4F_preferences_t prefsNull;
274
- memset(&prefsNull, 0, sizeof(prefsNull));
328
+ LZ4F_preferences_t prefsNull = LZ4F_INIT_PREFERENCES;
275
329
  prefsNull.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; /* worst case */
330
+ prefsNull.frameInfo.blockChecksumFlag = LZ4F_blockChecksumEnabled; /* worst case */
276
331
  { const LZ4F_preferences_t* const prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr;
277
332
  U32 const flush = prefsPtr->autoFlush | (srcSize==0);
278
333
  LZ4F_blockSizeID_t const blockID = prefsPtr->frameInfo.blockSizeID;
@@ -281,15 +336,14 @@ static size_t LZ4F_compressBound_internal(size_t srcSize,
281
336
  size_t const bufferedSize = MIN(alreadyBuffered, maxBuffered);
282
337
  size_t const maxSrcSize = srcSize + bufferedSize;
283
338
  unsigned const nbFullBlocks = (unsigned)(maxSrcSize / blockSize);
284
- size_t const partialBlockSize = (srcSize - (srcSize==0)) & (blockSize-1); /* 0 => -1 == MAX => blockSize-1 */
339
+ size_t const partialBlockSize = maxSrcSize & (blockSize-1);
285
340
  size_t const lastBlockSize = flush ? partialBlockSize : 0;
286
341
  unsigned const nbBlocks = nbFullBlocks + (lastBlockSize>0);
287
342
 
288
- size_t const blockHeaderSize = 4;
289
- size_t const blockCRCSize = 4 * prefsPtr->frameInfo.blockChecksumFlag;
290
- size_t const frameEnd = 4 + (prefsPtr->frameInfo.contentChecksumFlag*4);
343
+ size_t const blockCRCSize = BFSize * prefsPtr->frameInfo.blockChecksumFlag;
344
+ size_t const frameEnd = BHSize + (prefsPtr->frameInfo.contentChecksumFlag*BFSize);
291
345
 
292
- return ((blockHeaderSize + blockCRCSize) * nbBlocks) +
346
+ return ((BHSize + blockCRCSize) * nbBlocks) +
293
347
  (blockSize * nbFullBlocks) + lastBlockSize + frameEnd;
294
348
  }
295
349
  }
@@ -300,7 +354,7 @@ size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* prefere
300
354
  size_t const headerSize = maxFHSize; /* max header size, including optional fields */
301
355
 
302
356
  if (preferencesPtr!=NULL) prefs = *preferencesPtr;
303
- else memset(&prefs, 0, sizeof(prefs));
357
+ else MEM_INIT(&prefs, 0, sizeof(prefs));
304
358
  prefs.autoFlush = 1;
305
359
 
306
360
  return headerSize + LZ4F_compressBound_internal(srcSize, &prefs, 0);;
@@ -316,27 +370,22 @@ size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* prefere
316
370
  * @return : number of bytes written into dstBuffer,
317
371
  * or an error code if it fails (can be tested using LZ4F_isError())
318
372
  */
319
- size_t LZ4F_compressFrame_usingCDict(void* dstBuffer, size_t dstCapacity,
373
+ size_t LZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx,
374
+ void* dstBuffer, size_t dstCapacity,
320
375
  const void* srcBuffer, size_t srcSize,
321
376
  const LZ4F_CDict* cdict,
322
377
  const LZ4F_preferences_t* preferencesPtr)
323
378
  {
324
- LZ4F_cctx_t cctxI;
325
- LZ4_stream_t lz4ctx;
326
379
  LZ4F_preferences_t prefs;
327
380
  LZ4F_compressOptions_t options;
328
381
  BYTE* const dstStart = (BYTE*) dstBuffer;
329
382
  BYTE* dstPtr = dstStart;
330
383
  BYTE* const dstEnd = dstStart + dstCapacity;
331
384
 
332
- memset(&cctxI, 0, sizeof(cctxI));
333
- cctxI.version = LZ4F_VERSION;
334
- cctxI.maxBufferSize = 5 MB; /* mess with real buffer size to prevent dynamic allocation; works only because autoflush==1 & stableSrc==1 */
335
-
336
385
  if (preferencesPtr!=NULL)
337
386
  prefs = *preferencesPtr;
338
387
  else
339
- memset(&prefs, 0, sizeof(prefs));
388
+ MEM_INIT(&prefs, 0, sizeof(prefs));
340
389
  if (prefs.frameInfo.contentSize != 0)
341
390
  prefs.frameInfo.contentSize = (U64)srcSize; /* auto-correct content size if selected (!=0) */
342
391
 
@@ -345,33 +394,28 @@ size_t LZ4F_compressFrame_usingCDict(void* dstBuffer, size_t dstCapacity,
345
394
  if (srcSize <= LZ4F_getBlockSize(prefs.frameInfo.blockSizeID))
346
395
  prefs.frameInfo.blockMode = LZ4F_blockIndependent; /* only one block => no need for inter-block link */
347
396
 
348
- if (prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {
349
- cctxI.lz4CtxPtr = &lz4ctx;
350
- cctxI.lz4CtxLevel = 1;
351
- } /* fast compression context pre-created on stack */
352
-
353
- memset(&options, 0, sizeof(options));
397
+ MEM_INIT(&options, 0, sizeof(options));
354
398
  options.stableSrc = 1;
355
399
 
356
400
  if (dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs)) /* condition to guarantee success */
357
401
  return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
358
402
 
359
- { size_t const headerSize = LZ4F_compressBegin_usingCDict(&cctxI, dstBuffer, dstCapacity, cdict, &prefs); /* write header */
403
+ { size_t const headerSize = LZ4F_compressBegin_usingCDict(cctx, dstBuffer, dstCapacity, cdict, &prefs); /* write header */
360
404
  if (LZ4F_isError(headerSize)) return headerSize;
361
405
  dstPtr += headerSize; /* header size */ }
362
406
 
363
- { size_t const cSize = LZ4F_compressUpdate(&cctxI, dstPtr, dstEnd-dstPtr, srcBuffer, srcSize, &options);
407
+ assert(dstEnd >= dstPtr);
408
+ { size_t const cSize = LZ4F_compressUpdate(cctx, dstPtr, (size_t)(dstEnd-dstPtr), srcBuffer, srcSize, &options);
364
409
  if (LZ4F_isError(cSize)) return cSize;
365
410
  dstPtr += cSize; }
366
411
 
367
- { size_t const tailSize = LZ4F_compressEnd(&cctxI, dstPtr, dstEnd-dstPtr, &options); /* flush last block, and generate suffix */
412
+ assert(dstEnd >= dstPtr);
413
+ { size_t const tailSize = LZ4F_compressEnd(cctx, dstPtr, (size_t)(dstEnd-dstPtr), &options); /* flush last block, and generate suffix */
368
414
  if (LZ4F_isError(tailSize)) return tailSize;
369
415
  dstPtr += tailSize; }
370
416
 
371
- if (prefs.compressionLevel >= LZ4HC_CLEVEL_MIN) /* Ctx allocation only for lz4hc */
372
- FREEMEM(cctxI.lz4CtxPtr);
373
-
374
- return (dstPtr - dstStart);
417
+ assert(dstEnd >= dstStart);
418
+ return (size_t)(dstPtr - dstStart);
375
419
  }
376
420
 
377
421
 
@@ -386,9 +430,44 @@ size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity,
386
430
  const void* srcBuffer, size_t srcSize,
387
431
  const LZ4F_preferences_t* preferencesPtr)
388
432
  {
389
- return LZ4F_compressFrame_usingCDict(dstBuffer, dstCapacity,
390
- srcBuffer, srcSize,
391
- NULL, preferencesPtr);
433
+ size_t result;
434
+ #if (LZ4F_HEAPMODE)
435
+ LZ4F_cctx_t *cctxPtr;
436
+ result = LZ4F_createCompressionContext(&cctxPtr, LZ4F_VERSION);
437
+ if (LZ4F_isError(result)) return result;
438
+ #else
439
+ LZ4F_cctx_t cctx;
440
+ LZ4_stream_t lz4ctx;
441
+ LZ4F_cctx_t *cctxPtr = &cctx;
442
+
443
+ DEBUGLOG(4, "LZ4F_compressFrame");
444
+ MEM_INIT(&cctx, 0, sizeof(cctx));
445
+ cctx.version = LZ4F_VERSION;
446
+ cctx.maxBufferSize = 5 MB; /* mess with real buffer size to prevent dynamic allocation; works only because autoflush==1 & stableSrc==1 */
447
+ if (preferencesPtr == NULL ||
448
+ preferencesPtr->compressionLevel < LZ4HC_CLEVEL_MIN)
449
+ {
450
+ LZ4_initStream(&lz4ctx, sizeof(lz4ctx));
451
+ cctxPtr->lz4CtxPtr = &lz4ctx;
452
+ cctxPtr->lz4CtxAlloc = 1;
453
+ cctxPtr->lz4CtxState = 1;
454
+ }
455
+ #endif
456
+
457
+ result = LZ4F_compressFrame_usingCDict(cctxPtr, dstBuffer, dstCapacity,
458
+ srcBuffer, srcSize,
459
+ NULL, preferencesPtr);
460
+
461
+ #if (LZ4F_HEAPMODE)
462
+ LZ4F_freeCompressionContext(cctxPtr);
463
+ #else
464
+ if (preferencesPtr != NULL &&
465
+ preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN)
466
+ {
467
+ FREEMEM(cctxPtr->lz4CtxPtr);
468
+ }
469
+ #endif
470
+ return result;
392
471
  }
393
472
 
394
473
 
@@ -411,13 +490,14 @@ struct LZ4F_CDict_s {
411
490
  LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize)
412
491
  {
413
492
  const char* dictStart = (const char*)dictBuffer;
414
- LZ4F_CDict* cdict = (LZ4F_CDict*) malloc(sizeof(*cdict));
493
+ LZ4F_CDict* cdict = (LZ4F_CDict*) ALLOC(sizeof(*cdict));
494
+ DEBUGLOG(4, "LZ4F_createCDict");
415
495
  if (!cdict) return NULL;
416
496
  if (dictSize > 64 KB) {
417
497
  dictStart += dictSize - 64 KB;
418
498
  dictSize = 64 KB;
419
499
  }
420
- cdict->dictContent = ALLOCATOR(dictSize);
500
+ cdict->dictContent = ALLOC(dictSize);
421
501
  cdict->fastCtx = LZ4_createStream();
422
502
  cdict->HCCtx = LZ4_createStreamHC();
423
503
  if (!cdict->dictContent || !cdict->fastCtx || !cdict->HCCtx) {
@@ -425,9 +505,8 @@ LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize)
425
505
  return NULL;
426
506
  }
427
507
  memcpy(cdict->dictContent, dictStart, dictSize);
428
- LZ4_resetStream(cdict->fastCtx);
429
508
  LZ4_loadDict (cdict->fastCtx, (const char*)cdict->dictContent, (int)dictSize);
430
- LZ4_resetStreamHC(cdict->HCCtx, LZ4HC_CLEVEL_DEFAULT);
509
+ LZ4_setCompressionLevel(cdict->HCCtx, LZ4HC_CLEVEL_DEFAULT);
431
510
  LZ4_loadDictHC(cdict->HCCtx, (const char*)cdict->dictContent, (int)dictSize);
432
511
  return cdict;
433
512
  }
@@ -454,34 +533,62 @@ void LZ4F_freeCDict(LZ4F_CDict* cdict)
454
533
  * If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation.
455
534
  * Object can release its memory using LZ4F_freeCompressionContext();
456
535
  */
457
- LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* LZ4F_compressionContextPtr, unsigned version)
536
+ LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** LZ4F_compressionContextPtr, unsigned version)
458
537
  {
459
- LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)ALLOCATOR(sizeof(LZ4F_cctx_t));
538
+ LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)ALLOC_AND_ZERO(sizeof(LZ4F_cctx_t));
460
539
  if (cctxPtr==NULL) return err0r(LZ4F_ERROR_allocation_failed);
461
540
 
462
541
  cctxPtr->version = version;
463
542
  cctxPtr->cStage = 0; /* Next stage : init stream */
464
543
 
465
- *LZ4F_compressionContextPtr = (LZ4F_compressionContext_t)cctxPtr;
544
+ *LZ4F_compressionContextPtr = cctxPtr;
466
545
 
467
546
  return LZ4F_OK_NoError;
468
547
  }
469
548
 
470
549
 
471
- LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_compressionContext)
550
+ LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctxPtr)
472
551
  {
473
- LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)LZ4F_compressionContext;
474
-
475
552
  if (cctxPtr != NULL) { /* support free on NULL */
476
- FREEMEM(cctxPtr->lz4CtxPtr); /* works because LZ4_streamHC_t and LZ4_stream_t are simple POD types */
553
+ FREEMEM(cctxPtr->lz4CtxPtr); /* note: LZ4_streamHC_t and LZ4_stream_t are simple POD types */
477
554
  FREEMEM(cctxPtr->tmpBuff);
478
- FREEMEM(LZ4F_compressionContext);
555
+ FREEMEM(cctxPtr);
479
556
  }
480
557
 
481
558
  return LZ4F_OK_NoError;
482
559
  }
483
560
 
484
561
 
562
+ /**
563
+ * This function prepares the internal LZ4(HC) stream for a new compression,
564
+ * resetting the context and attaching the dictionary, if there is one.
565
+ *
566
+ * It needs to be called at the beginning of each independent compression
567
+ * stream (i.e., at the beginning of a frame in blockLinked mode, or at the
568
+ * beginning of each block in blockIndependent mode).
569
+ */
570
+ static void LZ4F_initStream(void* ctx,
571
+ const LZ4F_CDict* cdict,
572
+ int level,
573
+ LZ4F_blockMode_t blockMode) {
574
+ if (level < LZ4HC_CLEVEL_MIN) {
575
+ if (cdict != NULL || blockMode == LZ4F_blockLinked) {
576
+ /* In these cases, we will call LZ4_compress_fast_continue(),
577
+ * which needs an already reset context. Otherwise, we'll call a
578
+ * one-shot API. The non-continued APIs internally perform their own
579
+ * resets at the beginning of their calls, where they know what
580
+ * tableType they need the context to be in. So in that case this
581
+ * would be misguided / wasted work. */
582
+ LZ4_resetStream_fast((LZ4_stream_t*)ctx);
583
+ }
584
+ LZ4_attach_dictionary((LZ4_stream_t *)ctx, cdict ? cdict->fastCtx : NULL);
585
+ } else {
586
+ LZ4_resetStreamHC_fast((LZ4_streamHC_t*)ctx, level);
587
+ LZ4_attach_HC_dictionary((LZ4_streamHC_t *)ctx, cdict ? cdict->HCCtx : NULL);
588
+ }
589
+ }
590
+
591
+
485
592
  /*! LZ4F_compressBegin_usingCDict() :
486
593
  * init streaming compression and writes frame header into dstBuffer.
487
594
  * dstBuffer must be >= LZ4F_HEADER_SIZE_MAX bytes.
@@ -499,21 +606,35 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,
499
606
  BYTE* headerStart;
500
607
 
501
608
  if (dstCapacity < maxFHSize) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
502
- memset(&prefNull, 0, sizeof(prefNull));
609
+ MEM_INIT(&prefNull, 0, sizeof(prefNull));
503
610
  if (preferencesPtr == NULL) preferencesPtr = &prefNull;
504
611
  cctxPtr->prefs = *preferencesPtr;
505
612
 
506
613
  /* Ctx Management */
507
- { U32 const tableID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2; /* 0:nothing ; 1:LZ4 table ; 2:HC tables */
508
- if (cctxPtr->lz4CtxLevel < tableID) {
614
+ { U16 const ctxTypeID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2;
615
+ if (cctxPtr->lz4CtxAlloc < ctxTypeID) {
509
616
  FREEMEM(cctxPtr->lz4CtxPtr);
510
- if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN)
511
- cctxPtr->lz4CtxPtr = (void*)LZ4_createStream();
512
- else
513
- cctxPtr->lz4CtxPtr = (void*)LZ4_createStreamHC();
514
- if (cctxPtr->lz4CtxPtr == NULL) return err0r(LZ4F_ERROR_allocation_failed);
515
- cctxPtr->lz4CtxLevel = tableID;
516
- } }
617
+ if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {
618
+ cctxPtr->lz4CtxPtr = LZ4_createStream();
619
+ } else {
620
+ cctxPtr->lz4CtxPtr = LZ4_createStreamHC();
621
+ }
622
+ if (cctxPtr->lz4CtxPtr == NULL)
623
+ return err0r(LZ4F_ERROR_allocation_failed);
624
+ cctxPtr->lz4CtxAlloc = ctxTypeID;
625
+ cctxPtr->lz4CtxState = ctxTypeID;
626
+ } else if (cctxPtr->lz4CtxState != ctxTypeID) {
627
+ /* otherwise, a sufficient buffer is allocated, but we need to
628
+ * reset it to the correct context type */
629
+ if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {
630
+ LZ4_initStream((LZ4_stream_t *) cctxPtr->lz4CtxPtr, sizeof (LZ4_stream_t));
631
+ } else {
632
+ LZ4_initStreamHC((LZ4_streamHC_t *) cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t));
633
+ LZ4_setCompressionLevel((LZ4_streamHC_t *) cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
634
+ }
635
+ cctxPtr->lz4CtxState = ctxTypeID;
636
+ }
637
+ }
517
638
 
518
639
  /* Buffer Management */
519
640
  if (cctxPtr->prefs.frameInfo.blockSizeID == 0)
@@ -521,37 +642,28 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,
521
642
  cctxPtr->maxBlockSize = LZ4F_getBlockSize(cctxPtr->prefs.frameInfo.blockSizeID);
522
643
 
523
644
  { size_t const requiredBuffSize = preferencesPtr->autoFlush ?
524
- (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) * 64 KB : /* only needs windows size */
525
- cctxPtr->maxBlockSize + ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) * 128 KB);
645
+ ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) ? 64 KB : 0) : /* only needs past data up to window size */
646
+ cctxPtr->maxBlockSize + ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) ? 128 KB : 0);
526
647
 
527
648
  if (cctxPtr->maxBufferSize < requiredBuffSize) {
528
649
  cctxPtr->maxBufferSize = 0;
529
650
  FREEMEM(cctxPtr->tmpBuff);
530
- cctxPtr->tmpBuff = (BYTE*)ALLOCATOR(requiredBuffSize);
651
+ cctxPtr->tmpBuff = (BYTE*)ALLOC_AND_ZERO(requiredBuffSize);
531
652
  if (cctxPtr->tmpBuff == NULL) return err0r(LZ4F_ERROR_allocation_failed);
532
653
  cctxPtr->maxBufferSize = requiredBuffSize;
533
654
  } }
534
655
  cctxPtr->tmpIn = cctxPtr->tmpBuff;
535
656
  cctxPtr->tmpInSize = 0;
536
- XXH32_reset(&(cctxPtr->xxh), 0);
657
+ (void)XXH32_reset(&(cctxPtr->xxh), 0);
537
658
 
538
659
  /* context init */
539
660
  cctxPtr->cdict = cdict;
540
661
  if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) {
541
662
  /* frame init only for blockLinked : blockIndependent will be init at each block */
542
- if (cdict) {
543
- if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {
544
- memcpy(cctxPtr->lz4CtxPtr, cdict->fastCtx, sizeof(*cdict->fastCtx));
545
- } else {
546
- memcpy(cctxPtr->lz4CtxPtr, cdict->HCCtx, sizeof(*cdict->HCCtx));
547
- LZ4_setCompressionLevel((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
548
- }
549
- } else {
550
- if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN)
551
- LZ4_resetStream((LZ4_stream_t*)(cctxPtr->lz4CtxPtr));
552
- else
553
- LZ4_resetStreamHC((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), cctxPtr->prefs.compressionLevel);
554
- }
663
+ LZ4F_initStream(cctxPtr->lz4CtxPtr, cdict, cctxPtr->prefs.compressionLevel, LZ4F_blockLinked);
664
+ }
665
+ if (preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN) {
666
+ LZ4_favorDecompressionSpeed((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, (int)preferencesPtr->favorDecSpeed);
555
667
  }
556
668
 
557
669
  /* Magic Number */
@@ -563,7 +675,7 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,
563
675
  *dstPtr++ = (BYTE)(((1 & _2BITS) << 6) /* Version('01') */
564
676
  + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5)
565
677
  + ((cctxPtr->prefs.frameInfo.blockChecksumFlag & _1BIT ) << 4)
566
- + ((cctxPtr->prefs.frameInfo.contentSize > 0) << 3)
678
+ + ((unsigned)(cctxPtr->prefs.frameInfo.contentSize > 0) << 3)
567
679
  + ((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2)
568
680
  + (cctxPtr->prefs.frameInfo.dictID > 0) );
569
681
  /* BD Byte */
@@ -580,11 +692,11 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,
580
692
  dstPtr += 4;
581
693
  }
582
694
  /* Header CRC Byte */
583
- *dstPtr = LZ4F_headerChecksum(headerStart, dstPtr - headerStart);
695
+ *dstPtr = LZ4F_headerChecksum(headerStart, (size_t)(dstPtr - headerStart));
584
696
  dstPtr++;
585
697
 
586
698
  cctxPtr->cStage = 1; /* header written, now request input data block */
587
- return (dstPtr - dstStart);
699
+ return (size_t)(dstPtr - dstStart);
588
700
  }
589
701
 
590
702
 
@@ -593,7 +705,7 @@ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,
593
705
  * dstBuffer must be >= LZ4F_HEADER_SIZE_MAX bytes.
594
706
  * preferencesPtr can be NULL, in which case default parameters are selected.
595
707
  * @return : number of bytes written into dstBuffer for the header
596
- * or an error code (can be tested using LZ4F_isError())
708
+ * or an error code (can be tested using LZ4F_isError())
597
709
  */
598
710
  size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr,
599
711
  void* dstBuffer, size_t dstCapacity,
@@ -604,13 +716,16 @@ size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr,
604
716
  }
605
717
 
606
718
 
607
- /* LZ4F_compressBound() :
608
- * @ return size of Dst buffer given a srcSize to handle worst case situations.
609
- * The LZ4F_frameInfo_t structure is optional : if NULL, preferences will be set to cover worst case situations.
610
- * This function cannot fail.
719
+ /* LZ4F_compressBound() :
720
+ * @return minimum capacity of dstBuffer for a given srcSize to handle worst case scenario.
721
+ * LZ4F_preferences_t structure is optional : if NULL, preferences will be set to cover worst case scenario.
722
+ * This function cannot fail.
611
723
  */
612
724
  size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
613
725
  {
726
+ if (preferencesPtr && preferencesPtr->autoFlush) {
727
+ return LZ4F_compressBound_internal(srcSize, preferencesPtr, 0);
728
+ }
614
729
  return LZ4F_compressBound_internal(srcSize, preferencesPtr, (size_t)-1);
615
730
  }
616
731
 
@@ -619,55 +734,60 @@ typedef int (*compressFunc_t)(void* ctx, const char* src, char* dst, int srcSize
619
734
 
620
735
 
621
736
  /*! LZ4F_makeBlock():
622
- * compress a single block, add header and checksum
623
- * assumption : dst buffer capacity is >= srcSize */
624
- static size_t LZ4F_makeBlock(void* dst, const void* src, size_t srcSize,
737
+ * compress a single block, add header and optional checksum.
738
+ * assumption : dst buffer capacity is >= BHSize + srcSize + crcSize
739
+ */
740
+ static size_t LZ4F_makeBlock(void* dst,
741
+ const void* src, size_t srcSize,
625
742
  compressFunc_t compress, void* lz4ctx, int level,
626
- const LZ4F_CDict* cdict, LZ4F_blockChecksum_t crcFlag)
743
+ const LZ4F_CDict* cdict,
744
+ LZ4F_blockChecksum_t crcFlag)
627
745
  {
628
746
  BYTE* const cSizePtr = (BYTE*)dst;
629
- U32 cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+4),
747
+ U32 cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+BHSize),
630
748
  (int)(srcSize), (int)(srcSize-1),
631
749
  level, cdict);
632
- LZ4F_writeLE32(cSizePtr, cSize);
633
750
  if (cSize == 0) { /* compression failed */
751
+ DEBUGLOG(5, "LZ4F_makeBlock: compression failed, creating a raw block (size %u)", (U32)srcSize);
634
752
  cSize = (U32)srcSize;
635
753
  LZ4F_writeLE32(cSizePtr, cSize | LZ4F_BLOCKUNCOMPRESSED_FLAG);
636
- memcpy(cSizePtr+4, src, srcSize);
754
+ memcpy(cSizePtr+BHSize, src, srcSize);
755
+ } else {
756
+ LZ4F_writeLE32(cSizePtr, cSize);
637
757
  }
638
758
  if (crcFlag) {
639
- U32 const crc32 = XXH32(cSizePtr+4, cSize, 0); /* checksum of compressed data */
640
- LZ4F_writeLE32(cSizePtr+4+cSize, crc32);
759
+ U32 const crc32 = XXH32(cSizePtr+BHSize, cSize, 0); /* checksum of compressed data */
760
+ LZ4F_writeLE32(cSizePtr+BHSize+cSize, crc32);
641
761
  }
642
- return 4 + cSize + ((U32)crcFlag)*4;
762
+ return BHSize + cSize + ((U32)crcFlag)*BFSize;
643
763
  }
644
764
 
645
765
 
646
766
  static int LZ4F_compressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)
647
767
  {
648
- int const acceleration = (level < -1) ? -level : 1;
768
+ int const acceleration = (level < 0) ? -level + 1 : 1;
769
+ LZ4F_initStream(ctx, cdict, level, LZ4F_blockIndependent);
649
770
  if (cdict) {
650
- memcpy(ctx, cdict->fastCtx, sizeof(*cdict->fastCtx));
651
771
  return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration);
772
+ } else {
773
+ return LZ4_compress_fast_extState_fastReset(ctx, src, dst, srcSize, dstCapacity, acceleration);
652
774
  }
653
- return LZ4_compress_fast_extState(ctx, src, dst, srcSize, dstCapacity, acceleration);
654
775
  }
655
776
 
656
777
  static int LZ4F_compressBlock_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)
657
778
  {
658
- int const acceleration = (level < -1) ? -level : 1;
779
+ int const acceleration = (level < 0) ? -level + 1 : 1;
659
780
  (void)cdict; /* init once at beginning of frame */
660
781
  return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration);
661
782
  }
662
783
 
663
784
  static int LZ4F_compressBlockHC(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)
664
785
  {
786
+ LZ4F_initStream(ctx, cdict, level, LZ4F_blockIndependent);
665
787
  if (cdict) {
666
- memcpy(ctx, cdict->HCCtx, sizeof(*cdict->HCCtx));
667
- LZ4_setCompressionLevel((LZ4_streamHC_t*)ctx, level);
668
788
  return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity);
669
789
  }
670
- return LZ4_compress_HC_extStateHC(ctx, src, dst, srcSize, dstCapacity, level);
790
+ return LZ4_compress_HC_extStateHC_fastReset(ctx, src, dst, srcSize, dstCapacity, level);
671
791
  }
672
792
 
673
793
  static int LZ4F_compressBlockHC_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)
@@ -716,10 +836,12 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr,
716
836
  LZ4F_lastBlockStatus lastBlockCompressed = notDone;
717
837
  compressFunc_t const compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel);
718
838
 
839
+ DEBUGLOG(4, "LZ4F_compressUpdate (srcSize=%zu)", srcSize);
719
840
 
720
841
  if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC);
721
- if (dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize)) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
722
- memset(&cOptionsNull, 0, sizeof(cOptionsNull));
842
+ if (dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize))
843
+ return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
844
+ MEM_INIT(&cOptionsNull, 0, sizeof(cOptionsNull));
723
845
  if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull;
724
846
 
725
847
  /* complete tmp buffer */
@@ -737,9 +859,11 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr,
737
859
  memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, sizeToCopy);
738
860
  srcPtr += sizeToCopy;
739
861
 
740
- dstPtr += LZ4F_makeBlock(dstPtr, cctxPtr->tmpIn, blockSize,
862
+ dstPtr += LZ4F_makeBlock(dstPtr,
863
+ cctxPtr->tmpIn, blockSize,
741
864
  compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,
742
- cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag);
865
+ cctxPtr->cdict,
866
+ cctxPtr->prefs.frameInfo.blockChecksumFlag);
743
867
 
744
868
  if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += blockSize;
745
869
  cctxPtr->tmpInSize = 0;
@@ -749,18 +873,22 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr,
749
873
  while ((size_t)(srcEnd - srcPtr) >= blockSize) {
750
874
  /* compress full blocks */
751
875
  lastBlockCompressed = fromSrcBuffer;
752
- dstPtr += LZ4F_makeBlock(dstPtr, srcPtr, blockSize,
876
+ dstPtr += LZ4F_makeBlock(dstPtr,
877
+ srcPtr, blockSize,
753
878
  compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,
754
- cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag);
879
+ cctxPtr->cdict,
880
+ cctxPtr->prefs.frameInfo.blockChecksumFlag);
755
881
  srcPtr += blockSize;
756
882
  }
757
883
 
758
884
  if ((cctxPtr->prefs.autoFlush) && (srcPtr < srcEnd)) {
759
885
  /* compress remaining input < blockSize */
760
886
  lastBlockCompressed = fromSrcBuffer;
761
- dstPtr += LZ4F_makeBlock(dstPtr, srcPtr, srcEnd - srcPtr,
887
+ dstPtr += LZ4F_makeBlock(dstPtr,
888
+ srcPtr, (size_t)(srcEnd - srcPtr),
762
889
  compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,
763
- cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag);
890
+ cctxPtr->cdict,
891
+ cctxPtr->prefs.frameInfo.blockChecksumFlag);
764
892
  srcPtr = srcEnd;
765
893
  }
766
894
 
@@ -786,28 +914,30 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr,
786
914
  /* some input data left, necessarily < blockSize */
787
915
  if (srcPtr < srcEnd) {
788
916
  /* fill tmp buffer */
789
- size_t const sizeToCopy = srcEnd - srcPtr;
917
+ size_t const sizeToCopy = (size_t)(srcEnd - srcPtr);
790
918
  memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy);
791
919
  cctxPtr->tmpInSize = sizeToCopy;
792
920
  }
793
921
 
794
922
  if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled)
795
- XXH32_update(&(cctxPtr->xxh), srcBuffer, srcSize);
923
+ (void)XXH32_update(&(cctxPtr->xxh), srcBuffer, srcSize);
796
924
 
797
925
  cctxPtr->totalInSize += srcSize;
798
- return dstPtr - dstStart;
926
+ return (size_t)(dstPtr - dstStart);
799
927
  }
800
928
 
801
929
 
802
930
  /*! LZ4F_flush() :
803
- * Should you need to create compressed data immediately, without waiting for a block to be filled,
804
- * you can call LZ4_flush(), which will immediately compress any remaining data stored within compressionContext.
805
- * The result of the function is the number of bytes written into dstBuffer
806
- * (it can be zero, this means there was no data left within compressionContext)
931
+ * When compressed data must be sent immediately, without waiting for a block to be filled,
932
+ * invoke LZ4_flush(), which will immediately compress any remaining data stored within LZ4F_cctx.
933
+ * The result of the function is the number of bytes written into dstBuffer.
934
+ * It can be zero, this means there was no data left within LZ4F_cctx.
807
935
  * The function outputs an error code if it fails (can be tested using LZ4F_isError())
808
- * The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
936
+ * LZ4F_compressOptions_t* is optional. NULL is a valid argument.
809
937
  */
810
- size_t LZ4F_flush(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* compressOptionsPtr)
938
+ size_t LZ4F_flush(LZ4F_cctx* cctxPtr,
939
+ void* dstBuffer, size_t dstCapacity,
940
+ const LZ4F_compressOptions_t* compressOptionsPtr)
811
941
  {
812
942
  BYTE* const dstStart = (BYTE*)dstBuffer;
813
943
  BYTE* dstPtr = dstStart;
@@ -815,52 +945,67 @@ size_t LZ4F_flush(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const
815
945
 
816
946
  if (cctxPtr->tmpInSize == 0) return 0; /* nothing to flush */
817
947
  if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC);
818
- if (dstCapacity < (cctxPtr->tmpInSize + 4)) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); /* +4 : block header(4) */
948
+ if (dstCapacity < (cctxPtr->tmpInSize + BHSize + BFSize))
949
+ return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
819
950
  (void)compressOptionsPtr; /* not yet useful */
820
951
 
821
952
  /* select compression function */
822
953
  compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel);
823
954
 
824
955
  /* compress tmp buffer */
825
- dstPtr += LZ4F_makeBlock(dstPtr, cctxPtr->tmpIn, cctxPtr->tmpInSize,
956
+ dstPtr += LZ4F_makeBlock(dstPtr,
957
+ cctxPtr->tmpIn, cctxPtr->tmpInSize,
826
958
  compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,
827
- cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag);
828
- if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += cctxPtr->tmpInSize;
959
+ cctxPtr->cdict,
960
+ cctxPtr->prefs.frameInfo.blockChecksumFlag);
961
+ assert(((void)"flush overflows dstBuffer!", (size_t)(dstPtr - dstStart) <= dstCapacity));
962
+
963
+ if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked)
964
+ cctxPtr->tmpIn += cctxPtr->tmpInSize;
829
965
  cctxPtr->tmpInSize = 0;
830
966
 
831
967
  /* keep tmpIn within limits */
832
968
  if ((cctxPtr->tmpIn + cctxPtr->maxBlockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)) { /* necessarily LZ4F_blockLinked */
833
- int realDictSize = LZ4F_localSaveDict(cctxPtr);
969
+ int const realDictSize = LZ4F_localSaveDict(cctxPtr);
834
970
  cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;
835
971
  }
836
972
 
837
- return dstPtr - dstStart;
973
+ return (size_t)(dstPtr - dstStart);
838
974
  }
839
975
 
840
976
 
841
977
  /*! LZ4F_compressEnd() :
842
- * When you want to properly finish the compressed frame, just call LZ4F_compressEnd().
843
- * It will flush whatever data remained within compressionContext (like LZ4_flush())
844
- * but also properly finalize the frame, with an endMark and a checksum.
845
- * The result of the function is the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))
846
- * The function outputs an error code if it fails (can be tested using LZ4F_isError())
847
- * The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
848
- * compressionContext can then be used again, starting with LZ4F_compressBegin(). The preferences will remain the same.
978
+ * When you want to properly finish the compressed frame, just call LZ4F_compressEnd().
979
+ * It will flush whatever data remained within compressionContext (like LZ4_flush())
980
+ * but also properly finalize the frame, with an endMark and an (optional) checksum.
981
+ * LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
982
+ * @return: the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))
983
+ * or an error code if it fails (can be tested using LZ4F_isError())
984
+ * The context can then be used again to compress a new frame, starting with LZ4F_compressBegin().
849
985
  */
850
- size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr)
986
+ size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr,
987
+ void* dstBuffer, size_t dstCapacity,
988
+ const LZ4F_compressOptions_t* compressOptionsPtr)
851
989
  {
852
990
  BYTE* const dstStart = (BYTE*)dstBuffer;
853
991
  BYTE* dstPtr = dstStart;
854
992
 
855
- size_t const flushSize = LZ4F_flush(cctxPtr, dstBuffer, dstMaxSize, compressOptionsPtr);
993
+ size_t const flushSize = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr);
994
+ DEBUGLOG(5,"LZ4F_compressEnd: dstCapacity=%u", (unsigned)dstCapacity);
856
995
  if (LZ4F_isError(flushSize)) return flushSize;
857
996
  dstPtr += flushSize;
858
997
 
998
+ assert(flushSize <= dstCapacity);
999
+ dstCapacity -= flushSize;
1000
+
1001
+ if (dstCapacity < 4) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
859
1002
  LZ4F_writeLE32(dstPtr, 0);
860
- dstPtr+=4; /* endMark */
1003
+ dstPtr += 4; /* endMark */
861
1004
 
862
1005
  if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) {
863
1006
  U32 const xxh = XXH32_digest(&(cctxPtr->xxh));
1007
+ if (dstCapacity < 8) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
1008
+ DEBUGLOG(5,"Writing 32-bit content checksum");
864
1009
  LZ4F_writeLE32(dstPtr, xxh);
865
1010
  dstPtr+=4; /* content Checksum */
866
1011
  }
@@ -873,7 +1018,7 @@ size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstMaxSize,
873
1018
  return err0r(LZ4F_ERROR_frameSize_wrong);
874
1019
  }
875
1020
 
876
- return dstPtr - dstStart;
1021
+ return (size_t)(dstPtr - dstStart);
877
1022
  }
878
1023
 
879
1024
 
@@ -887,8 +1032,7 @@ typedef enum {
887
1032
  dstage_getBlockHeader, dstage_storeBlockHeader,
888
1033
  dstage_copyDirect, dstage_getBlockChecksum,
889
1034
  dstage_getCBlock, dstage_storeCBlock,
890
- dstage_decodeCBlock, dstage_decodeCBlock_intoDst,
891
- dstage_decodeCBlock_intoTmp, dstage_flushOut,
1035
+ dstage_flushOut,
892
1036
  dstage_getSuffix, dstage_storeSuffix,
893
1037
  dstage_getSFrameSize, dstage_storeSFrameSize,
894
1038
  dstage_skipSkippable
@@ -924,8 +1068,11 @@ struct LZ4F_dctx_s {
924
1068
  */
925
1069
  LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber)
926
1070
  {
927
- LZ4F_dctx* const dctx = (LZ4F_dctx*)ALLOCATOR(sizeof(LZ4F_dctx));
928
- if (dctx==NULL) return err0r(LZ4F_ERROR_GENERIC);
1071
+ LZ4F_dctx* const dctx = (LZ4F_dctx*)ALLOC_AND_ZERO(sizeof(LZ4F_dctx));
1072
+ if (dctx == NULL) { /* failed allocation */
1073
+ *LZ4F_decompressionContextPtr = NULL;
1074
+ return err0r(LZ4F_ERROR_allocation_failed);
1075
+ }
929
1076
 
930
1077
  dctx->version = versionNumber;
931
1078
  *LZ4F_decompressionContextPtr = dctx;
@@ -955,31 +1102,6 @@ void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx)
955
1102
  }
956
1103
 
957
1104
 
958
- /*! LZ4F_headerSize() :
959
- * @return : size of frame header
960
- * or an error code, which can be tested using LZ4F_isError()
961
- */
962
- static size_t LZ4F_headerSize(const void* src, size_t srcSize)
963
- {
964
- /* minimal srcSize to determine header size */
965
- if (srcSize < 5) return err0r(LZ4F_ERROR_frameHeader_incomplete);
966
-
967
- /* special case : skippable frames */
968
- if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) return 8;
969
-
970
- /* control magic number */
971
- if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER)
972
- return err0r(LZ4F_ERROR_frameType_unknown);
973
-
974
- /* Frame Header Size */
975
- { BYTE const FLG = ((const BYTE*)src)[4];
976
- U32 const contentSizeFlag = (FLG>>3) & _1BIT;
977
- U32 const dictIDFlag = FLG & _1BIT;
978
- return minFHSize + (contentSizeFlag*8) + (dictIDFlag*4);
979
- }
980
- }
981
-
982
-
983
1105
  /*! LZ4F_decodeHeader() :
984
1106
  * input : `src` points at the **beginning of the frame**
985
1107
  * output : set internal values of dctx, such as
@@ -994,9 +1116,10 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize
994
1116
  size_t frameHeaderSize;
995
1117
  const BYTE* srcPtr = (const BYTE*)src;
996
1118
 
1119
+ DEBUGLOG(5, "LZ4F_decodeHeader");
997
1120
  /* need to decode header to get frameInfo */
998
1121
  if (srcSize < minFHSize) return err0r(LZ4F_ERROR_frameHeader_incomplete); /* minimal frame header size */
999
- memset(&(dctx->frameInfo), 0, sizeof(dctx->frameInfo));
1122
+ MEM_INIT(&(dctx->frameInfo), 0, sizeof(dctx->frameInfo));
1000
1123
 
1001
1124
  /* special case : skippable frames */
1002
1125
  if ((LZ4F_readLE32(srcPtr) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) {
@@ -1013,8 +1136,12 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize
1013
1136
  }
1014
1137
 
1015
1138
  /* control magic number */
1016
- if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER)
1139
+ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1140
+ if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) {
1141
+ DEBUGLOG(4, "frame header error : unknown magic number");
1017
1142
  return err0r(LZ4F_ERROR_frameType_unknown);
1143
+ }
1144
+ #endif
1018
1145
  dctx->frameInfo.frameType = LZ4F_frame;
1019
1146
 
1020
1147
  /* Flags */
@@ -1031,7 +1158,7 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize
1031
1158
  }
1032
1159
 
1033
1160
  /* Frame Header Size */
1034
- frameHeaderSize = minFHSize + (contentSizeFlag*8) + (dictIDFlag*4);
1161
+ frameHeaderSize = minFHSize + (contentSizeFlag?8:0) + (dictIDFlag?4:0);
1035
1162
 
1036
1163
  if (srcSize < frameHeaderSize) {
1037
1164
  /* not enough input to fully decode frame header */
@@ -1052,10 +1179,13 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize
1052
1179
  }
1053
1180
 
1054
1181
  /* check header */
1182
+ assert(frameHeaderSize > 5);
1183
+ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1055
1184
  { BYTE const HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5);
1056
1185
  if (HC != srcPtr[frameHeaderSize-1])
1057
1186
  return err0r(LZ4F_ERROR_headerChecksum_invalid);
1058
1187
  }
1188
+ #endif
1059
1189
 
1060
1190
  /* save */
1061
1191
  dctx->frameInfo.blockMode = (LZ4F_blockMode_t)blockMode;
@@ -1075,6 +1205,36 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize
1075
1205
  }
1076
1206
 
1077
1207
 
1208
+ /*! LZ4F_headerSize() :
1209
+ * @return : size of frame header
1210
+ * or an error code, which can be tested using LZ4F_isError()
1211
+ */
1212
+ size_t LZ4F_headerSize(const void* src, size_t srcSize)
1213
+ {
1214
+ if (src == NULL) return err0r(LZ4F_ERROR_srcPtr_wrong);
1215
+
1216
+ /* minimal srcSize to determine header size */
1217
+ if (srcSize < LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH)
1218
+ return err0r(LZ4F_ERROR_frameHeader_incomplete);
1219
+
1220
+ /* special case : skippable frames */
1221
+ if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START)
1222
+ return 8;
1223
+
1224
+ /* control magic number */
1225
+ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1226
+ if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER)
1227
+ return err0r(LZ4F_ERROR_frameType_unknown);
1228
+ #endif
1229
+
1230
+ /* Frame Header Size */
1231
+ { BYTE const FLG = ((const BYTE*)src)[4];
1232
+ U32 const contentSizeFlag = (FLG>>3) & _1BIT;
1233
+ U32 const dictIDFlag = FLG & _1BIT;
1234
+ return minFHSize + (contentSizeFlag?8:0) + (dictIDFlag?4:0);
1235
+ }
1236
+ }
1237
+
1078
1238
  /*! LZ4F_getFrameInfo() :
1079
1239
  * This function extracts frame parameters (max blockSize, frame checksum, etc.).
1080
1240
  * Usage is optional. Objective is to provide relevant information for allocation purposes.
@@ -1090,10 +1250,12 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize
1090
1250
  * note 1 : in case of error, dctx is not modified. Decoding operations can resume from where they stopped.
1091
1251
  * note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure.
1092
1252
  */
1093
- LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, LZ4F_frameInfo_t* frameInfoPtr,
1094
- const void* srcBuffer, size_t* srcSizePtr)
1253
+ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx,
1254
+ LZ4F_frameInfo_t* frameInfoPtr,
1255
+ const void* srcBuffer, size_t* srcSizePtr)
1095
1256
  {
1096
- if (dctx->dStage > dstage_storeFrameHeader) { /* assumption : dstage_* header enum at beginning of range */
1257
+ LZ4F_STATIC_ASSERT(dstage_getFrameHeader < dstage_storeFrameHeader);
1258
+ if (dctx->dStage > dstage_storeFrameHeader) {
1097
1259
  /* frameInfo already decoded */
1098
1260
  size_t o=0, i=0;
1099
1261
  *srcSizePtr = 0;
@@ -1106,7 +1268,6 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, LZ4F_frameInfo_t* frameInfoP
1106
1268
  *srcSizePtr = 0;
1107
1269
  return err0r(LZ4F_ERROR_frameDecoding_alreadyStarted);
1108
1270
  } else {
1109
- size_t decodeResult;
1110
1271
  size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr);
1111
1272
  if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; }
1112
1273
  if (*srcSizePtr < hSize) {
@@ -1114,45 +1275,59 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, LZ4F_frameInfo_t* frameInfoP
1114
1275
  return err0r(LZ4F_ERROR_frameHeader_incomplete);
1115
1276
  }
1116
1277
 
1117
- decodeResult = LZ4F_decodeHeader(dctx, srcBuffer, hSize);
1118
- if (LZ4F_isError(decodeResult)) {
1119
- *srcSizePtr = 0;
1120
- } else {
1121
- *srcSizePtr = decodeResult;
1122
- decodeResult = BHSize; /* block header size */
1123
- }
1124
- *frameInfoPtr = dctx->frameInfo;
1125
- return decodeResult;
1126
- } }
1278
+ { size_t decodeResult = LZ4F_decodeHeader(dctx, srcBuffer, hSize);
1279
+ if (LZ4F_isError(decodeResult)) {
1280
+ *srcSizePtr = 0;
1281
+ } else {
1282
+ *srcSizePtr = decodeResult;
1283
+ decodeResult = BHSize; /* block header size */
1284
+ }
1285
+ *frameInfoPtr = dctx->frameInfo;
1286
+ return decodeResult;
1287
+ } } }
1127
1288
  }
1128
1289
 
1129
1290
 
1130
1291
  /* LZ4F_updateDict() :
1131
- * only used for LZ4F_blockLinked mode */
1132
- static void LZ4F_updateDict(LZ4F_dctx* dctx, const BYTE* dstPtr, size_t dstSize, const BYTE* dstPtr0, unsigned withinTmp)
1292
+ * only used for LZ4F_blockLinked mode
1293
+ * Condition : dstPtr != NULL
1294
+ */
1295
+ static void LZ4F_updateDict(LZ4F_dctx* dctx,
1296
+ const BYTE* dstPtr, size_t dstSize, const BYTE* dstBufferStart,
1297
+ unsigned withinTmp)
1133
1298
  {
1134
- if (dctx->dictSize==0)
1135
- dctx->dict = (const BYTE*)dstPtr; /* priority to dictionary continuity */
1299
+ assert(dstPtr != NULL);
1300
+ if (dctx->dictSize==0) {
1301
+ dctx->dict = (const BYTE*)dstPtr; /* priority to prefix mode */
1302
+ }
1303
+ assert(dctx->dict != NULL);
1136
1304
 
1137
- if (dctx->dict + dctx->dictSize == dstPtr) { /* dictionary continuity */
1305
+ if (dctx->dict + dctx->dictSize == dstPtr) { /* prefix mode, everything within dstBuffer */
1138
1306
  dctx->dictSize += dstSize;
1139
1307
  return;
1140
1308
  }
1141
1309
 
1142
- if (dstPtr - dstPtr0 + dstSize >= 64 KB) { /* dstBuffer large enough to become dictionary */
1143
- dctx->dict = (const BYTE*)dstPtr0;
1144
- dctx->dictSize = dstPtr - dstPtr0 + dstSize;
1310
+ assert(dstPtr >= dstBufferStart);
1311
+ if ((size_t)(dstPtr - dstBufferStart) + dstSize >= 64 KB) { /* history in dstBuffer becomes large enough to become dictionary */
1312
+ dctx->dict = (const BYTE*)dstBufferStart;
1313
+ dctx->dictSize = (size_t)(dstPtr - dstBufferStart) + dstSize;
1145
1314
  return;
1146
1315
  }
1147
1316
 
1148
- if ((withinTmp) && (dctx->dict == dctx->tmpOutBuffer)) {
1149
- /* assumption : dctx->dict + dctx->dictSize == dctx->tmpOut + dctx->tmpOutStart */
1317
+ assert(dstSize < 64 KB); /* if dstSize >= 64 KB, dictionary would be set into dstBuffer directly */
1318
+
1319
+ /* dstBuffer does not contain whole useful history (64 KB), so it must be saved within tmpOutBuffer */
1320
+ assert(dctx->tmpOutBuffer != NULL);
1321
+
1322
+ if (withinTmp && (dctx->dict == dctx->tmpOutBuffer)) { /* continue history within tmpOutBuffer */
1323
+ /* withinTmp expectation : content of [dstPtr,dstSize] is same as [dict+dictSize,dstSize], so we just extend it */
1324
+ assert(dctx->dict + dctx->dictSize == dctx->tmpOut + dctx->tmpOutStart);
1150
1325
  dctx->dictSize += dstSize;
1151
1326
  return;
1152
1327
  }
1153
1328
 
1154
1329
  if (withinTmp) { /* copy relevant dict portion in front of tmpOut within tmpOutBuffer */
1155
- size_t const preserveSize = dctx->tmpOut - dctx->tmpOutBuffer;
1330
+ size_t const preserveSize = (size_t)(dctx->tmpOut - dctx->tmpOutBuffer);
1156
1331
  size_t copySize = 64 KB - dctx->tmpOutSize;
1157
1332
  const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart;
1158
1333
  if (dctx->tmpOutSize > 64 KB) copySize = 0;
@@ -1167,7 +1342,7 @@ static void LZ4F_updateDict(LZ4F_dctx* dctx, const BYTE* dstPtr, size_t dstSize,
1167
1342
 
1168
1343
  if (dctx->dict == dctx->tmpOutBuffer) { /* copy dst into tmp to complete dict */
1169
1344
  if (dctx->dictSize + dstSize > dctx->maxBufferSize) { /* tmp buffer not large enough */
1170
- size_t const preserveSize = 64 KB - dstSize; /* note : dstSize < 64 KB */
1345
+ size_t const preserveSize = 64 KB - dstSize;
1171
1346
  memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - preserveSize, preserveSize);
1172
1347
  dctx->dictSize = preserveSize;
1173
1348
  }
@@ -1177,7 +1352,7 @@ static void LZ4F_updateDict(LZ4F_dctx* dctx, const BYTE* dstPtr, size_t dstSize,
1177
1352
  }
1178
1353
 
1179
1354
  /* join dict & dest into tmp */
1180
- { size_t preserveSize = 64 KB - dstSize; /* note : dstSize < 64 KB */
1355
+ { size_t preserveSize = 64 KB - dstSize;
1181
1356
  if (preserveSize > dctx->dictSize) preserveSize = dctx->dictSize;
1182
1357
  memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - preserveSize, preserveSize);
1183
1358
  memcpy(dctx->tmpOutBuffer + preserveSize, dstPtr, dstSize);
@@ -1216,17 +1391,21 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1216
1391
  const BYTE* const srcEnd = srcStart + *srcSizePtr;
1217
1392
  const BYTE* srcPtr = srcStart;
1218
1393
  BYTE* const dstStart = (BYTE*)dstBuffer;
1219
- BYTE* const dstEnd = dstStart + *dstSizePtr;
1394
+ BYTE* const dstEnd = dstStart ? dstStart + *dstSizePtr : NULL;
1220
1395
  BYTE* dstPtr = dstStart;
1221
1396
  const BYTE* selectedIn = NULL;
1222
1397
  unsigned doAnotherStage = 1;
1223
1398
  size_t nextSrcSizeHint = 1;
1224
1399
 
1225
1400
 
1226
- memset(&optionsNull, 0, sizeof(optionsNull));
1401
+ DEBUGLOG(5, "LZ4F_decompress : %p,%u => %p,%u",
1402
+ srcBuffer, (unsigned)*srcSizePtr, dstBuffer, (unsigned)*dstSizePtr);
1403
+ if (dstBuffer == NULL) assert(*dstSizePtr == 0);
1404
+ MEM_INIT(&optionsNull, 0, sizeof(optionsNull));
1227
1405
  if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull;
1228
1406
  *srcSizePtr = 0;
1229
1407
  *dstSizePtr = 0;
1408
+ assert(dctx != NULL);
1230
1409
 
1231
1410
  /* behaves as a state machine */
1232
1411
 
@@ -1236,46 +1415,52 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1236
1415
  {
1237
1416
 
1238
1417
  case dstage_getFrameHeader:
1418
+ DEBUGLOG(6, "dstage_getFrameHeader");
1239
1419
  if ((size_t)(srcEnd-srcPtr) >= maxFHSize) { /* enough to decode - shortcut */
1240
- size_t const hSize = LZ4F_decodeHeader(dctx, srcPtr, srcEnd-srcPtr); /* will update dStage appropriately */
1420
+ size_t const hSize = LZ4F_decodeHeader(dctx, srcPtr, (size_t)(srcEnd-srcPtr)); /* will update dStage appropriately */
1241
1421
  if (LZ4F_isError(hSize)) return hSize;
1242
1422
  srcPtr += hSize;
1243
1423
  break;
1244
1424
  }
1245
1425
  dctx->tmpInSize = 0;
1246
1426
  if (srcEnd-srcPtr == 0) return minFHSize; /* 0-size input */
1247
- dctx->tmpInTarget = minFHSize; /* minimum to attempt decode */
1427
+ dctx->tmpInTarget = minFHSize; /* minimum size to decode header */
1248
1428
  dctx->dStage = dstage_storeFrameHeader;
1249
1429
  /* fall-through */
1250
1430
 
1251
1431
  case dstage_storeFrameHeader:
1432
+ DEBUGLOG(6, "dstage_storeFrameHeader");
1252
1433
  { size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize, (size_t)(srcEnd - srcPtr));
1253
1434
  memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy);
1254
1435
  dctx->tmpInSize += sizeToCopy;
1255
1436
  srcPtr += sizeToCopy;
1256
- if (dctx->tmpInSize < dctx->tmpInTarget) {
1257
- nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize) + BHSize; /* rest of header + nextBlockHeader */
1258
- doAnotherStage = 0; /* not enough src data, ask for some more */
1259
- break;
1260
- }
1261
- { size_t const hSize = LZ4F_decodeHeader(dctx, dctx->header, dctx->tmpInTarget); /* will update dStage appropriately */
1262
- if (LZ4F_isError(hSize)) return hSize;
1263
- }
1437
+ }
1438
+ if (dctx->tmpInSize < dctx->tmpInTarget) {
1439
+ nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize) + BHSize; /* rest of header + nextBlockHeader */
1440
+ doAnotherStage = 0; /* not enough src data, ask for some more */
1264
1441
  break;
1265
1442
  }
1443
+ { size_t const hSize = LZ4F_decodeHeader(dctx, dctx->header, dctx->tmpInTarget); /* will update dStage appropriately */
1444
+ if (LZ4F_isError(hSize)) return hSize;
1445
+ }
1446
+ break;
1266
1447
 
1267
1448
  case dstage_init:
1268
- if (dctx->frameInfo.contentChecksumFlag) XXH32_reset(&(dctx->xxh), 0);
1449
+ DEBUGLOG(6, "dstage_init");
1450
+ if (dctx->frameInfo.contentChecksumFlag) (void)XXH32_reset(&(dctx->xxh), 0);
1269
1451
  /* internal buffers allocation */
1270
- { size_t const bufferNeeded = dctx->maxBlockSize + ((dctx->frameInfo.blockMode==LZ4F_blockLinked) * 128 KB) + 4 /* block checksum */;
1452
+ { size_t const bufferNeeded = dctx->maxBlockSize
1453
+ + ((dctx->frameInfo.blockMode==LZ4F_blockLinked) ? 128 KB : 0);
1271
1454
  if (bufferNeeded > dctx->maxBufferSize) { /* tmp buffers too small */
1272
1455
  dctx->maxBufferSize = 0; /* ensure allocation will be re-attempted on next entry*/
1273
1456
  FREEMEM(dctx->tmpIn);
1274
- dctx->tmpIn = (BYTE*)ALLOCATOR(dctx->maxBlockSize);
1275
- if (dctx->tmpIn == NULL) return err0r(LZ4F_ERROR_allocation_failed);
1457
+ dctx->tmpIn = (BYTE*)ALLOC(dctx->maxBlockSize + BFSize /* block checksum */);
1458
+ if (dctx->tmpIn == NULL)
1459
+ return err0r(LZ4F_ERROR_allocation_failed);
1276
1460
  FREEMEM(dctx->tmpOutBuffer);
1277
- dctx->tmpOutBuffer= (BYTE*)ALLOCATOR(bufferNeeded);
1278
- if (dctx->tmpOutBuffer== NULL) return err0r(LZ4F_ERROR_allocation_failed);
1461
+ dctx->tmpOutBuffer= (BYTE*)ALLOC(bufferNeeded);
1462
+ if (dctx->tmpOutBuffer== NULL)
1463
+ return err0r(LZ4F_ERROR_allocation_failed);
1279
1464
  dctx->maxBufferSize = bufferNeeded;
1280
1465
  } }
1281
1466
  dctx->tmpInSize = 0;
@@ -1299,33 +1484,39 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1299
1484
 
1300
1485
  if (dctx->dStage == dstage_storeBlockHeader) /* can be skipped */
1301
1486
  case dstage_storeBlockHeader:
1302
- { size_t sizeToCopy = BHSize - dctx->tmpInSize;
1303
- if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
1487
+ { size_t const remainingInput = (size_t)(srcEnd - srcPtr);
1488
+ size_t const wantedData = BHSize - dctx->tmpInSize;
1489
+ size_t const sizeToCopy = MIN(wantedData, remainingInput);
1304
1490
  memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy);
1305
1491
  srcPtr += sizeToCopy;
1306
1492
  dctx->tmpInSize += sizeToCopy;
1493
+
1307
1494
  if (dctx->tmpInSize < BHSize) { /* not enough input for cBlockSize */
1308
1495
  nextSrcSizeHint = BHSize - dctx->tmpInSize;
1309
1496
  doAnotherStage = 0;
1310
1497
  break;
1311
1498
  }
1312
1499
  selectedIn = dctx->tmpIn;
1313
- }
1500
+ } /* if (dctx->dStage == dstage_storeBlockHeader) */
1314
1501
 
1315
1502
  /* decode block header */
1316
- { size_t const nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU;
1317
- size_t const crcSize = dctx->frameInfo.blockChecksumFlag * 4;
1318
- if (nextCBlockSize==0) { /* frameEnd signal, no more block */
1503
+ { U32 const blockHeader = LZ4F_readLE32(selectedIn);
1504
+ size_t const nextCBlockSize = blockHeader & 0x7FFFFFFFU;
1505
+ size_t const crcSize = dctx->frameInfo.blockChecksumFlag * BFSize;
1506
+ if (blockHeader==0) { /* frameEnd signal, no more block */
1507
+ DEBUGLOG(5, "end of frame");
1319
1508
  dctx->dStage = dstage_getSuffix;
1320
1509
  break;
1321
1510
  }
1322
- if (nextCBlockSize > dctx->maxBlockSize)
1511
+ if (nextCBlockSize > dctx->maxBlockSize) {
1323
1512
  return err0r(LZ4F_ERROR_maxBlockSize_invalid);
1324
- if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG) {
1513
+ }
1514
+ if (blockHeader & LZ4F_BLOCKUNCOMPRESSED_FLAG) {
1325
1515
  /* next block is uncompressed */
1326
1516
  dctx->tmpInTarget = nextCBlockSize;
1517
+ DEBUGLOG(5, "next block is uncompressed (size %u)", (U32)nextCBlockSize);
1327
1518
  if (dctx->frameInfo.blockChecksumFlag) {
1328
- XXH32_reset(&dctx->blockChecksum, 0);
1519
+ (void)XXH32_reset(&dctx->blockChecksum, 0);
1329
1520
  }
1330
1521
  dctx->dStage = dstage_copyDirect;
1331
1522
  break;
@@ -1333,28 +1524,34 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1333
1524
  /* next block is a compressed block */
1334
1525
  dctx->tmpInTarget = nextCBlockSize + crcSize;
1335
1526
  dctx->dStage = dstage_getCBlock;
1336
- if (dstPtr==dstEnd) {
1337
- nextSrcSizeHint = nextCBlockSize + crcSize + BHSize;
1527
+ if (dstPtr==dstEnd || srcPtr==srcEnd) {
1528
+ nextSrcSizeHint = BHSize + nextCBlockSize + crcSize;
1338
1529
  doAnotherStage = 0;
1339
1530
  }
1340
1531
  break;
1341
1532
  }
1342
1533
 
1343
1534
  case dstage_copyDirect: /* uncompressed block */
1344
- { size_t const minBuffSize = MIN((size_t)(srcEnd-srcPtr), (size_t)(dstEnd-dstPtr));
1345
- size_t const sizeToCopy = MIN(dctx->tmpInTarget, minBuffSize);
1346
- memcpy(dstPtr, srcPtr, sizeToCopy);
1347
- if (dctx->frameInfo.blockChecksumFlag) {
1348
- XXH32_update(&dctx->blockChecksum, srcPtr, sizeToCopy);
1349
- }
1350
- if (dctx->frameInfo.contentChecksumFlag)
1351
- XXH32_update(&dctx->xxh, srcPtr, sizeToCopy);
1352
- if (dctx->frameInfo.contentSize)
1353
- dctx->frameRemainingSize -= sizeToCopy;
1535
+ DEBUGLOG(6, "dstage_copyDirect");
1536
+ { size_t sizeToCopy;
1537
+ if (dstPtr == NULL) {
1538
+ sizeToCopy = 0;
1539
+ } else {
1540
+ size_t const minBuffSize = MIN((size_t)(srcEnd-srcPtr), (size_t)(dstEnd-dstPtr));
1541
+ sizeToCopy = MIN(dctx->tmpInTarget, minBuffSize);
1542
+ memcpy(dstPtr, srcPtr, sizeToCopy);
1543
+ if (dctx->frameInfo.blockChecksumFlag) {
1544
+ (void)XXH32_update(&dctx->blockChecksum, srcPtr, sizeToCopy);
1545
+ }
1546
+ if (dctx->frameInfo.contentChecksumFlag)
1547
+ (void)XXH32_update(&dctx->xxh, srcPtr, sizeToCopy);
1548
+ if (dctx->frameInfo.contentSize)
1549
+ dctx->frameRemainingSize -= sizeToCopy;
1354
1550
 
1355
- /* history management (linked blocks only)*/
1356
- if (dctx->frameInfo.blockMode == LZ4F_blockLinked)
1357
- LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0);
1551
+ /* history management (linked blocks only)*/
1552
+ if (dctx->frameInfo.blockMode == LZ4F_blockLinked) {
1553
+ LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0);
1554
+ } }
1358
1555
 
1359
1556
  srcPtr += sizeToCopy;
1360
1557
  dstPtr += sizeToCopy;
@@ -1367,15 +1564,16 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1367
1564
  break;
1368
1565
  }
1369
1566
  dctx->tmpInTarget -= sizeToCopy; /* need to copy more */
1370
- nextSrcSizeHint = dctx->tmpInTarget +
1371
- + dctx->frameInfo.contentChecksumFlag * 4 /* block checksum */
1372
- + BHSize /* next header size */;
1373
- doAnotherStage = 0;
1374
- break;
1375
1567
  }
1568
+ nextSrcSizeHint = dctx->tmpInTarget +
1569
+ +(dctx->frameInfo.blockChecksumFlag ? BFSize : 0)
1570
+ + BHSize /* next header size */;
1571
+ doAnotherStage = 0;
1572
+ break;
1376
1573
 
1377
1574
  /* check block checksum for recently transferred uncompressed block */
1378
1575
  case dstage_getBlockChecksum:
1576
+ DEBUGLOG(6, "dstage_getBlockChecksum");
1379
1577
  { const void* crcSrc;
1380
1578
  if ((srcEnd-srcPtr >= 4) && (dctx->tmpInSize==0)) {
1381
1579
  crcSrc = srcPtr;
@@ -1394,14 +1592,23 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1394
1592
  }
1395
1593
  { U32 const readCRC = LZ4F_readLE32(crcSrc);
1396
1594
  U32 const calcCRC = XXH32_digest(&dctx->blockChecksum);
1397
- if (readCRC != calcCRC)
1595
+ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1596
+ DEBUGLOG(6, "compare block checksum");
1597
+ if (readCRC != calcCRC) {
1598
+ DEBUGLOG(4, "incorrect block checksum: %08X != %08X",
1599
+ readCRC, calcCRC);
1398
1600
  return err0r(LZ4F_ERROR_blockChecksum_invalid);
1399
- }
1400
- }
1601
+ }
1602
+ #else
1603
+ (void)readCRC;
1604
+ (void)calcCRC;
1605
+ #endif
1606
+ } }
1401
1607
  dctx->dStage = dstage_getBlockHeader; /* new block */
1402
1608
  break;
1403
1609
 
1404
- case dstage_getCBlock: /* entry from dstage_decodeCBlockSize */
1610
+ case dstage_getCBlock:
1611
+ DEBUGLOG(6, "dstage_getCBlock");
1405
1612
  if ((size_t)(srcEnd-srcPtr) < dctx->tmpInTarget) {
1406
1613
  dctx->tmpInSize = 0;
1407
1614
  dctx->dStage = dstage_storeCBlock;
@@ -1410,62 +1617,72 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1410
1617
  /* input large enough to read full block directly */
1411
1618
  selectedIn = srcPtr;
1412
1619
  srcPtr += dctx->tmpInTarget;
1413
- dctx->dStage = dstage_decodeCBlock;
1414
- break;
1415
1620
 
1621
+ if (0) /* always jump over next block */
1416
1622
  case dstage_storeCBlock:
1417
- { size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize, (size_t)(srcEnd-srcPtr));
1623
+ { size_t const wantedData = dctx->tmpInTarget - dctx->tmpInSize;
1624
+ size_t const inputLeft = (size_t)(srcEnd-srcPtr);
1625
+ size_t const sizeToCopy = MIN(wantedData, inputLeft);
1418
1626
  memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy);
1419
1627
  dctx->tmpInSize += sizeToCopy;
1420
1628
  srcPtr += sizeToCopy;
1421
1629
  if (dctx->tmpInSize < dctx->tmpInTarget) { /* need more input */
1422
- nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize) + BHSize;
1423
- doAnotherStage=0;
1630
+ nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize)
1631
+ + (dctx->frameInfo.blockChecksumFlag ? BFSize : 0)
1632
+ + BHSize /* next header size */;
1633
+ doAnotherStage = 0;
1424
1634
  break;
1425
1635
  }
1426
1636
  selectedIn = dctx->tmpIn;
1427
- dctx->dStage = dstage_decodeCBlock;
1428
1637
  }
1429
- /* fall-through */
1430
1638
 
1431
- /* At this stage, input is large enough to decode a block */
1432
- case dstage_decodeCBlock:
1639
+ /* At this stage, input is large enough to decode a block */
1433
1640
  if (dctx->frameInfo.blockChecksumFlag) {
1434
1641
  dctx->tmpInTarget -= 4;
1642
+ assert(selectedIn != NULL); /* selectedIn is defined at this stage (either srcPtr, or dctx->tmpIn) */
1435
1643
  { U32 const readBlockCrc = LZ4F_readLE32(selectedIn + dctx->tmpInTarget);
1436
1644
  U32 const calcBlockCrc = XXH32(selectedIn, dctx->tmpInTarget, 0);
1645
+ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1437
1646
  if (readBlockCrc != calcBlockCrc)
1438
1647
  return err0r(LZ4F_ERROR_blockChecksum_invalid);
1648
+ #else
1649
+ (void)readBlockCrc;
1650
+ (void)calcBlockCrc;
1651
+ #endif
1439
1652
  } }
1440
- if ((size_t)(dstEnd-dstPtr) < dctx->maxBlockSize) /* not enough place into dst : decode into tmpOut */
1441
- dctx->dStage = dstage_decodeCBlock_intoTmp;
1442
- else
1443
- dctx->dStage = dstage_decodeCBlock_intoDst;
1444
- break;
1445
1653
 
1446
- case dstage_decodeCBlock_intoDst:
1447
- { int const decodedSize = LZ4_decompress_safe_usingDict(
1654
+ if ((size_t)(dstEnd-dstPtr) >= dctx->maxBlockSize) {
1655
+ const char* dict = (const char*)dctx->dict;
1656
+ size_t dictSize = dctx->dictSize;
1657
+ int decodedSize;
1658
+ assert(dstPtr != NULL);
1659
+ if (dict && dictSize > 1 GB) {
1660
+ /* the dictSize param is an int, avoid truncation / sign issues */
1661
+ dict += dictSize - 64 KB;
1662
+ dictSize = 64 KB;
1663
+ }
1664
+ /* enough capacity in `dst` to decompress directly there */
1665
+ decodedSize = LZ4_decompress_safe_usingDict(
1448
1666
  (const char*)selectedIn, (char*)dstPtr,
1449
1667
  (int)dctx->tmpInTarget, (int)dctx->maxBlockSize,
1450
- (const char*)dctx->dict, (int)dctx->dictSize);
1668
+ dict, (int)dictSize);
1451
1669
  if (decodedSize < 0) return err0r(LZ4F_ERROR_GENERIC); /* decompression failed */
1452
1670
  if (dctx->frameInfo.contentChecksumFlag)
1453
- XXH32_update(&(dctx->xxh), dstPtr, decodedSize);
1671
+ XXH32_update(&(dctx->xxh), dstPtr, (size_t)decodedSize);
1454
1672
  if (dctx->frameInfo.contentSize)
1455
- dctx->frameRemainingSize -= decodedSize;
1673
+ dctx->frameRemainingSize -= (size_t)decodedSize;
1456
1674
 
1457
1675
  /* dictionary management */
1458
- if (dctx->frameInfo.blockMode==LZ4F_blockLinked)
1459
- LZ4F_updateDict(dctx, dstPtr, decodedSize, dstStart, 0);
1676
+ if (dctx->frameInfo.blockMode==LZ4F_blockLinked) {
1677
+ LZ4F_updateDict(dctx, dstPtr, (size_t)decodedSize, dstStart, 0);
1678
+ }
1460
1679
 
1461
1680
  dstPtr += decodedSize;
1462
1681
  dctx->dStage = dstage_getBlockHeader;
1463
1682
  break;
1464
1683
  }
1465
1684
 
1466
- case dstage_decodeCBlock_intoTmp:
1467
1685
  /* not enough place into dst : decode into tmpOut */
1468
-
1469
1686
  /* ensure enough place for tmpOut */
1470
1687
  if (dctx->frameInfo.blockMode == LZ4F_blockLinked) {
1471
1688
  if (dctx->dict == dctx->tmpOutBuffer) {
@@ -1477,70 +1694,77 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1477
1694
  } else { /* dict not within tmp */
1478
1695
  size_t const reservedDictSpace = MIN(dctx->dictSize, 64 KB);
1479
1696
  dctx->tmpOut = dctx->tmpOutBuffer + reservedDictSpace;
1480
- }
1481
- }
1697
+ } }
1482
1698
 
1483
1699
  /* Decode block */
1484
- { int const decodedSize = LZ4_decompress_safe_usingDict(
1700
+ { const char* dict = (const char*)dctx->dict;
1701
+ size_t dictSize = dctx->dictSize;
1702
+ int decodedSize;
1703
+ if (dict && dictSize > 1 GB) {
1704
+ /* the dictSize param is an int, avoid truncation / sign issues */
1705
+ dict += dictSize - 64 KB;
1706
+ dictSize = 64 KB;
1707
+ }
1708
+ decodedSize = LZ4_decompress_safe_usingDict(
1485
1709
  (const char*)selectedIn, (char*)dctx->tmpOut,
1486
1710
  (int)dctx->tmpInTarget, (int)dctx->maxBlockSize,
1487
- (const char*)dctx->dict, (int)dctx->dictSize);
1711
+ dict, (int)dictSize);
1488
1712
  if (decodedSize < 0) /* decompression failed */
1489
1713
  return err0r(LZ4F_ERROR_decompressionFailed);
1490
1714
  if (dctx->frameInfo.contentChecksumFlag)
1491
- XXH32_update(&(dctx->xxh), dctx->tmpOut, decodedSize);
1715
+ XXH32_update(&(dctx->xxh), dctx->tmpOut, (size_t)decodedSize);
1492
1716
  if (dctx->frameInfo.contentSize)
1493
- dctx->frameRemainingSize -= decodedSize;
1494
- dctx->tmpOutSize = decodedSize;
1717
+ dctx->frameRemainingSize -= (size_t)decodedSize;
1718
+ dctx->tmpOutSize = (size_t)decodedSize;
1495
1719
  dctx->tmpOutStart = 0;
1496
1720
  dctx->dStage = dstage_flushOut;
1497
1721
  }
1498
1722
  /* fall-through */
1499
1723
 
1500
1724
  case dstage_flushOut: /* flush decoded data from tmpOut to dstBuffer */
1501
- { size_t const sizeToCopy = MIN(dctx->tmpOutSize - dctx->tmpOutStart, (size_t)(dstEnd-dstPtr));
1725
+ DEBUGLOG(6, "dstage_flushOut");
1726
+ if (dstPtr != NULL) {
1727
+ size_t const sizeToCopy = MIN(dctx->tmpOutSize - dctx->tmpOutStart, (size_t)(dstEnd-dstPtr));
1502
1728
  memcpy(dstPtr, dctx->tmpOut + dctx->tmpOutStart, sizeToCopy);
1503
1729
 
1504
1730
  /* dictionary management */
1505
- if (dctx->frameInfo.blockMode==LZ4F_blockLinked)
1506
- LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 1);
1731
+ if (dctx->frameInfo.blockMode == LZ4F_blockLinked)
1732
+ LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 1 /*withinTmp*/);
1507
1733
 
1508
1734
  dctx->tmpOutStart += sizeToCopy;
1509
1735
  dstPtr += sizeToCopy;
1510
-
1511
- if (dctx->tmpOutStart == dctx->tmpOutSize) { /* all flushed */
1512
- dctx->dStage = dstage_getBlockHeader; /* get next block */
1513
- break;
1514
- }
1515
- nextSrcSizeHint = BHSize;
1516
- doAnotherStage = 0; /* still some data to flush */
1736
+ }
1737
+ if (dctx->tmpOutStart == dctx->tmpOutSize) { /* all flushed */
1738
+ dctx->dStage = dstage_getBlockHeader; /* get next block */
1517
1739
  break;
1518
1740
  }
1741
+ /* could not flush everything : stop there, just request a block header */
1742
+ doAnotherStage = 0;
1743
+ nextSrcSizeHint = BHSize;
1744
+ break;
1519
1745
 
1520
1746
  case dstage_getSuffix:
1521
- { size_t const suffixSize = dctx->frameInfo.contentChecksumFlag * 4;
1522
- if (dctx->frameRemainingSize)
1523
- return err0r(LZ4F_ERROR_frameSize_wrong); /* incorrect frame size decoded */
1524
- if (suffixSize == 0) { /* frame completed */
1525
- nextSrcSizeHint = 0;
1526
- LZ4F_resetDecompressionContext(dctx);
1527
- doAnotherStage = 0;
1528
- break;
1529
- }
1530
- if ((srcEnd - srcPtr) < 4) { /* not enough size for entire CRC */
1531
- dctx->tmpInSize = 0;
1532
- dctx->dStage = dstage_storeSuffix;
1533
- } else {
1534
- selectedIn = srcPtr;
1535
- srcPtr += 4;
1536
- }
1747
+ if (dctx->frameRemainingSize)
1748
+ return err0r(LZ4F_ERROR_frameSize_wrong); /* incorrect frame size decoded */
1749
+ if (!dctx->frameInfo.contentChecksumFlag) { /* no checksum, frame is completed */
1750
+ nextSrcSizeHint = 0;
1751
+ LZ4F_resetDecompressionContext(dctx);
1752
+ doAnotherStage = 0;
1753
+ break;
1754
+ }
1755
+ if ((srcEnd - srcPtr) < 4) { /* not enough size for entire CRC */
1756
+ dctx->tmpInSize = 0;
1757
+ dctx->dStage = dstage_storeSuffix;
1758
+ } else {
1759
+ selectedIn = srcPtr;
1760
+ srcPtr += 4;
1537
1761
  }
1538
1762
 
1539
1763
  if (dctx->dStage == dstage_storeSuffix) /* can be skipped */
1540
1764
  case dstage_storeSuffix:
1541
- {
1542
- size_t sizeToCopy = 4 - dctx->tmpInSize;
1543
- if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
1765
+ { size_t const remainingInput = (size_t)(srcEnd - srcPtr);
1766
+ size_t const wantedData = 4 - dctx->tmpInSize;
1767
+ size_t const sizeToCopy = MIN(wantedData, remainingInput);
1544
1768
  memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy);
1545
1769
  srcPtr += sizeToCopy;
1546
1770
  dctx->tmpInSize += sizeToCopy;
@@ -1550,13 +1774,18 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1550
1774
  break;
1551
1775
  }
1552
1776
  selectedIn = dctx->tmpIn;
1553
- }
1777
+ } /* if (dctx->dStage == dstage_storeSuffix) */
1554
1778
 
1555
- /* case dstage_checkSuffix: */ /* no direct call, avoid scan-build warning */
1779
+ /* case dstage_checkSuffix: */ /* no direct entry, avoid initialization risks */
1556
1780
  { U32 const readCRC = LZ4F_readLE32(selectedIn);
1557
1781
  U32 const resultCRC = XXH32_digest(&(dctx->xxh));
1782
+ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1558
1783
  if (readCRC != resultCRC)
1559
1784
  return err0r(LZ4F_ERROR_contentChecksum_invalid);
1785
+ #else
1786
+ (void)readCRC;
1787
+ (void)resultCRC;
1788
+ #endif
1560
1789
  nextSrcSizeHint = 0;
1561
1790
  LZ4F_resetDecompressionContext(dctx);
1562
1791
  doAnotherStage = 0;
@@ -1576,8 +1805,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1576
1805
 
1577
1806
  if (dctx->dStage == dstage_storeSFrameSize)
1578
1807
  case dstage_storeSFrameSize:
1579
- {
1580
- size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize,
1808
+ { size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize,
1581
1809
  (size_t)(srcEnd - srcPtr) );
1582
1810
  memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy);
1583
1811
  srcPtr += sizeToCopy;
@@ -1589,9 +1817,9 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1589
1817
  break;
1590
1818
  }
1591
1819
  selectedIn = dctx->header + 4;
1592
- }
1820
+ } /* if (dctx->dStage == dstage_storeSFrameSize) */
1593
1821
 
1594
- /* case dstage_decodeSFrameSize: */ /* no direct access */
1822
+ /* case dstage_decodeSFrameSize: */ /* no direct entry */
1595
1823
  { size_t const SFrameSize = LZ4F_readLE32(selectedIn);
1596
1824
  dctx->frameInfo.contentSize = SFrameSize;
1597
1825
  dctx->tmpInTarget = SFrameSize;
@@ -1606,34 +1834,36 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1606
1834
  doAnotherStage = 0;
1607
1835
  nextSrcSizeHint = dctx->tmpInTarget;
1608
1836
  if (nextSrcSizeHint) break; /* still more to skip */
1837
+ /* frame fully skipped : prepare context for a new frame */
1609
1838
  LZ4F_resetDecompressionContext(dctx);
1610
1839
  break;
1611
1840
  }
1612
- }
1613
- }
1614
-
1615
- /* preserve history within tmp if necessary */
1616
- if ( (dctx->frameInfo.blockMode==LZ4F_blockLinked)
1617
- && (dctx->dict != dctx->tmpOutBuffer)
1618
- && (dctx->dStage != dstage_getFrameHeader)
1619
- && (!decompressOptionsPtr->stableDst)
1620
- && ((unsigned)(dctx->dStage-1) < (unsigned)(dstage_getSuffix-1)) )
1841
+ } /* switch (dctx->dStage) */
1842
+ } /* while (doAnotherStage) */
1843
+
1844
+ /* preserve history within tmp whenever necessary */
1845
+ LZ4F_STATIC_ASSERT((unsigned)dstage_init == 2);
1846
+ if ( (dctx->frameInfo.blockMode==LZ4F_blockLinked) /* next block will use up to 64KB from previous ones */
1847
+ && (dctx->dict != dctx->tmpOutBuffer) /* dictionary is not already within tmp */
1848
+ && (dctx->dict != NULL) /* dictionary exists */
1849
+ && (!decompressOptionsPtr->stableDst) /* cannot rely on dst data to remain there for next call */
1850
+ && ((unsigned)(dctx->dStage)-2 < (unsigned)(dstage_getSuffix)-2) ) /* valid stages : [init ... getSuffix[ */
1621
1851
  {
1622
1852
  if (dctx->dStage == dstage_flushOut) {
1623
- size_t preserveSize = dctx->tmpOut - dctx->tmpOutBuffer;
1853
+ size_t const preserveSize = (size_t)(dctx->tmpOut - dctx->tmpOutBuffer);
1624
1854
  size_t copySize = 64 KB - dctx->tmpOutSize;
1625
1855
  const BYTE* oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart;
1626
1856
  if (dctx->tmpOutSize > 64 KB) copySize = 0;
1627
1857
  if (copySize > preserveSize) copySize = preserveSize;
1858
+ assert(dctx->tmpOutBuffer != NULL);
1628
1859
 
1629
1860
  memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);
1630
1861
 
1631
1862
  dctx->dict = dctx->tmpOutBuffer;
1632
1863
  dctx->dictSize = preserveSize + dctx->tmpOutStart;
1633
1864
  } else {
1634
- size_t newDictSize = dctx->dictSize;
1635
- const BYTE* oldDictEnd = dctx->dict + dctx->dictSize;
1636
- if ((newDictSize) > 64 KB) newDictSize = 64 KB;
1865
+ const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize;
1866
+ size_t const newDictSize = MIN(dctx->dictSize, 64 KB);
1637
1867
 
1638
1868
  memcpy(dctx->tmpOutBuffer, oldDictEnd - newDictSize, newDictSize);
1639
1869
 
@@ -1643,8 +1873,8 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
1643
1873
  }
1644
1874
  }
1645
1875
 
1646
- *srcSizePtr = (srcPtr - srcStart);
1647
- *dstSizePtr = (dstPtr - dstStart);
1876
+ *srcSizePtr = (size_t)(srcPtr - srcStart);
1877
+ *dstSizePtr = (size_t)(dstPtr - dstStart);
1648
1878
  return nextSrcSizeHint;
1649
1879
  }
1650
1880