extlz4 0.2.4.2 → 0.3.2

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