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.
- checksums.yaml +5 -5
- data/HISTORY.ja.md +25 -0
- data/README.md +49 -41
- data/bin/extlz4 +1 -1
- data/contrib/lz4/INSTALL +1 -0
- data/contrib/lz4/Makefile.inc +87 -0
- data/contrib/lz4/NEWS +89 -0
- data/contrib/lz4/README.md +42 -36
- data/contrib/lz4/build/README.md +55 -0
- data/contrib/lz4/build/VS2010/datagen/datagen.vcxproj +169 -0
- data/contrib/lz4/build/VS2010/frametest/frametest.vcxproj +176 -0
- data/contrib/lz4/build/VS2010/fullbench-dll/fullbench-dll.vcxproj +180 -0
- data/contrib/lz4/build/VS2010/fullbench/fullbench.vcxproj +176 -0
- data/contrib/lz4/build/VS2010/fuzzer/fuzzer.vcxproj +173 -0
- data/contrib/lz4/build/VS2010/liblz4-dll/liblz4-dll.rc +51 -0
- data/contrib/lz4/build/VS2010/liblz4-dll/liblz4-dll.vcxproj +179 -0
- data/contrib/lz4/build/VS2010/liblz4/liblz4.vcxproj +175 -0
- data/contrib/lz4/build/VS2010/lz4.sln +98 -0
- data/contrib/lz4/build/VS2010/lz4/lz4.rc +51 -0
- data/contrib/lz4/build/VS2010/lz4/lz4.vcxproj +189 -0
- data/contrib/lz4/build/VS2017/datagen/datagen.vcxproj +173 -0
- data/contrib/lz4/build/VS2017/frametest/frametest.vcxproj +180 -0
- data/contrib/lz4/build/VS2017/fullbench-dll/fullbench-dll.vcxproj +184 -0
- data/contrib/lz4/build/VS2017/fullbench/fullbench.vcxproj +180 -0
- data/contrib/lz4/build/VS2017/fuzzer/fuzzer.vcxproj +177 -0
- data/contrib/lz4/build/VS2017/liblz4-dll/liblz4-dll.rc +51 -0
- data/contrib/lz4/build/VS2017/liblz4-dll/liblz4-dll.vcxproj +183 -0
- data/contrib/lz4/build/VS2017/liblz4/liblz4.vcxproj +179 -0
- data/contrib/lz4/build/VS2017/lz4.sln +103 -0
- data/contrib/lz4/build/VS2017/lz4/lz4.rc +51 -0
- data/contrib/lz4/build/VS2017/lz4/lz4.vcxproj +164 -0
- data/contrib/lz4/build/cmake/CMakeLists.txt +235 -0
- data/contrib/lz4/lib/README.md +98 -34
- data/contrib/lz4/lib/liblz4-dll.rc.in +35 -0
- data/contrib/lz4/lib/lz4.c +1698 -681
- data/contrib/lz4/lib/lz4.h +546 -235
- data/contrib/lz4/lib/lz4frame.c +608 -378
- data/contrib/lz4/lib/lz4frame.h +315 -83
- data/contrib/lz4/lib/lz4frame_static.h +4 -100
- data/contrib/lz4/lib/lz4hc.c +1090 -282
- data/contrib/lz4/lib/lz4hc.h +276 -141
- data/contrib/lz4/lib/xxhash.c +371 -235
- data/contrib/lz4/lib/xxhash.h +128 -93
- data/contrib/lz4/ossfuzz/Makefile +78 -0
- data/contrib/lz4/ossfuzz/compress_frame_fuzzer.c +48 -0
- data/contrib/lz4/ossfuzz/compress_fuzzer.c +58 -0
- data/contrib/lz4/ossfuzz/compress_hc_fuzzer.c +64 -0
- data/contrib/lz4/ossfuzz/decompress_frame_fuzzer.c +75 -0
- data/contrib/lz4/ossfuzz/decompress_fuzzer.c +62 -0
- data/contrib/lz4/ossfuzz/fuzz.h +48 -0
- data/contrib/lz4/ossfuzz/fuzz_data_producer.c +77 -0
- data/contrib/lz4/ossfuzz/fuzz_data_producer.h +36 -0
- data/contrib/lz4/ossfuzz/fuzz_helpers.h +94 -0
- data/contrib/lz4/ossfuzz/lz4_helpers.c +51 -0
- data/contrib/lz4/ossfuzz/lz4_helpers.h +13 -0
- data/contrib/lz4/ossfuzz/ossfuzz.sh +23 -0
- data/contrib/lz4/ossfuzz/round_trip_frame_fuzzer.c +43 -0
- data/contrib/lz4/ossfuzz/round_trip_fuzzer.c +57 -0
- data/contrib/lz4/ossfuzz/round_trip_hc_fuzzer.c +44 -0
- data/contrib/lz4/ossfuzz/round_trip_stream_fuzzer.c +302 -0
- data/contrib/lz4/ossfuzz/standaloneengine.c +74 -0
- data/contrib/lz4/ossfuzz/travisoss.sh +26 -0
- data/contrib/lz4/tmp +0 -0
- data/contrib/lz4/tmpsparse +0 -0
- data/ext/blockapi.c +5 -5
- data/ext/extlz4.c +2 -0
- data/ext/extlz4.h +5 -0
- data/ext/frameapi.c +1 -1
- data/ext/hashargs.c +2 -2
- data/ext/hashargs.h +1 -1
- data/ext/lz4_amalgam.c +0 -23
- data/gemstub.rb +5 -16
- data/lib/extlz4.rb +51 -3
- data/lib/extlz4/oldstream.rb +1 -1
- data/test/common.rb +2 -2
- metadata +73 -16
- data/contrib/lz4/circle.yml +0 -39
- data/contrib/lz4/lib/lz4opt.h +0 -366
- data/lib/extlz4/version.rb +0 -3
data/contrib/lz4/lib/lz4frame.c
CHANGED
|
@@ -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
|
-
*
|
|
37
|
-
*
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
#
|
|
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
|
-
*
|
|
88
|
+
* Library declarations
|
|
61
89
|
**************************************/
|
|
62
|
-
#
|
|
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
|
-
#
|
|
147
|
-
#define
|
|
148
|
-
#define
|
|
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 =
|
|
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
|
-
|
|
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
|
|
235
|
-
|
|
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 =
|
|
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
|
|
289
|
-
size_t const
|
|
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 ((
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
372
|
-
|
|
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
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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*)
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
536
|
+
LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** LZ4F_compressionContextPtr, unsigned version)
|
|
458
537
|
{
|
|
459
|
-
LZ4F_cctx_t* const cctxPtr = (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 =
|
|
544
|
+
*LZ4F_compressionContextPtr = cctxPtr;
|
|
466
545
|
|
|
467
546
|
return LZ4F_OK_NoError;
|
|
468
547
|
}
|
|
469
548
|
|
|
470
549
|
|
|
471
|
-
LZ4F_errorCode_t LZ4F_freeCompressionContext(
|
|
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); /*
|
|
553
|
+
FREEMEM(cctxPtr->lz4CtxPtr); /* note: LZ4_streamHC_t and LZ4_stream_t are simple POD types */
|
|
477
554
|
FREEMEM(cctxPtr->tmpBuff);
|
|
478
|
-
FREEMEM(
|
|
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
|
-
|
|
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
|
-
{
|
|
508
|
-
if (cctxPtr->
|
|
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 =
|
|
512
|
-
else
|
|
513
|
-
cctxPtr->lz4CtxPtr =
|
|
514
|
-
|
|
515
|
-
cctxPtr->
|
|
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)
|
|
525
|
-
cctxPtr->maxBlockSize + ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked)
|
|
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*)
|
|
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
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
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
|
-
*
|
|
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
|
-
/*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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+
|
|
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+
|
|
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+
|
|
640
|
-
LZ4F_writeLE32(cSizePtr+
|
|
759
|
+
U32 const crc32 = XXH32(cSizePtr+BHSize, cSize, 0); /* checksum of compressed data */
|
|
760
|
+
LZ4F_writeLE32(cSizePtr+BHSize+cSize, crc32);
|
|
641
761
|
}
|
|
642
|
-
return
|
|
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 <
|
|
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 <
|
|
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
|
|
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))
|
|
722
|
-
|
|
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,
|
|
862
|
+
dstPtr += LZ4F_makeBlock(dstPtr,
|
|
863
|
+
cctxPtr->tmpIn, blockSize,
|
|
741
864
|
compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,
|
|
742
|
-
cctxPtr->cdict,
|
|
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,
|
|
876
|
+
dstPtr += LZ4F_makeBlock(dstPtr,
|
|
877
|
+
srcPtr, blockSize,
|
|
753
878
|
compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,
|
|
754
|
-
cctxPtr->cdict,
|
|
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,
|
|
887
|
+
dstPtr += LZ4F_makeBlock(dstPtr,
|
|
888
|
+
srcPtr, (size_t)(srcEnd - srcPtr),
|
|
762
889
|
compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,
|
|
763
|
-
cctxPtr->cdict,
|
|
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
|
-
*
|
|
804
|
-
*
|
|
805
|
-
* The result of the function is the number of bytes written into dstBuffer
|
|
806
|
-
*
|
|
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
|
-
*
|
|
936
|
+
* LZ4F_compressOptions_t* is optional. NULL is a valid argument.
|
|
809
937
|
*/
|
|
810
|
-
size_t LZ4F_flush(LZ4F_cctx* cctxPtr,
|
|
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 +
|
|
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,
|
|
956
|
+
dstPtr += LZ4F_makeBlock(dstPtr,
|
|
957
|
+
cctxPtr->tmpIn, cctxPtr->tmpInSize,
|
|
826
958
|
compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,
|
|
827
|
-
cctxPtr->cdict,
|
|
828
|
-
|
|
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
|
-
*
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
*
|
|
847
|
-
*
|
|
848
|
-
*
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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*)
|
|
928
|
-
if (dctx==NULL)
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
1094
|
-
|
|
1253
|
+
LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx,
|
|
1254
|
+
LZ4F_frameInfo_t* frameInfoPtr,
|
|
1255
|
+
const void* srcBuffer, size_t* srcSizePtr)
|
|
1095
1256
|
{
|
|
1096
|
-
|
|
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
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1135
|
-
|
|
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) { /*
|
|
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
|
-
|
|
1143
|
-
|
|
1144
|
-
dctx->
|
|
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
|
-
|
|
1149
|
-
|
|
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;
|
|
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;
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
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
|
-
|
|
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
|
|
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*)
|
|
1275
|
-
if (dctx->tmpIn == NULL)
|
|
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*)
|
|
1278
|
-
if (dctx->tmpOutBuffer== NULL)
|
|
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
|
|
1303
|
-
|
|
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
|
-
{
|
|
1317
|
-
size_t const
|
|
1318
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
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
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
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)
|
|
1423
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1447
|
-
|
|
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
|
-
|
|
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
|
-
{
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1512
|
-
|
|
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
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
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
|
|
1543
|
-
|
|
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
|
|
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
|
|
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
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
&& (dctx->
|
|
1619
|
-
&& (
|
|
1620
|
-
&& (
|
|
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
|
-
|
|
1635
|
-
const
|
|
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
|
|