line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
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
|
|
|
|
|
|
|
*/ |
34
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
* */ |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
/*-************************************ |
42
|
|
|
|
|
|
|
* Compiler Options |
43
|
|
|
|
|
|
|
**************************************/ |
44
|
|
|
|
|
|
|
#ifdef _MSC_VER /* Visual Studio */ |
45
|
|
|
|
|
|
|
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ |
46
|
|
|
|
|
|
|
#endif |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
/*-************************************ |
50
|
|
|
|
|
|
|
* Memory routines |
51
|
|
|
|
|
|
|
**************************************/ |
52
|
|
|
|
|
|
|
#include /* malloc, calloc, free */ |
53
|
|
|
|
|
|
|
#define ALLOCATOR(s) calloc(1,s) |
54
|
|
|
|
|
|
|
#define FREEMEM free |
55
|
|
|
|
|
|
|
#include /* memset, memcpy, memmove */ |
56
|
|
|
|
|
|
|
#define MEM_INIT memset |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
/*-************************************ |
60
|
|
|
|
|
|
|
* Includes |
61
|
|
|
|
|
|
|
**************************************/ |
62
|
|
|
|
|
|
|
#include "lz4frame_static.h" |
63
|
|
|
|
|
|
|
#include "lz4.h" |
64
|
|
|
|
|
|
|
#define LZ4_HC_STATIC_LINKING_ONLY |
65
|
|
|
|
|
|
|
#include "lz4hc.h" |
66
|
|
|
|
|
|
|
#define XXH_STATIC_LINKING_ONLY |
67
|
|
|
|
|
|
|
#include "xxhash.h" |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
/*-************************************ |
71
|
|
|
|
|
|
|
* Debug |
72
|
|
|
|
|
|
|
**************************************/ |
73
|
|
|
|
|
|
|
#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=1) |
74
|
|
|
|
|
|
|
# include |
75
|
|
|
|
|
|
|
#else |
76
|
|
|
|
|
|
|
# ifndef assert |
77
|
|
|
|
|
|
|
# define assert(condition) ((void)0) |
78
|
|
|
|
|
|
|
# endif |
79
|
|
|
|
|
|
|
#endif |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
#define LZ4F_STATIC_ASSERT(c) { enum { LZ4F_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
/*-************************************ |
85
|
|
|
|
|
|
|
* Basic Types |
86
|
|
|
|
|
|
|
**************************************/ |
87
|
|
|
|
|
|
|
#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) |
88
|
|
|
|
|
|
|
# include |
89
|
|
|
|
|
|
|
typedef uint8_t BYTE; |
90
|
|
|
|
|
|
|
typedef uint16_t U16; |
91
|
|
|
|
|
|
|
typedef uint32_t U32; |
92
|
|
|
|
|
|
|
typedef int32_t S32; |
93
|
|
|
|
|
|
|
typedef uint64_t U64; |
94
|
|
|
|
|
|
|
#else |
95
|
|
|
|
|
|
|
typedef unsigned char BYTE; |
96
|
|
|
|
|
|
|
typedef unsigned short U16; |
97
|
|
|
|
|
|
|
typedef unsigned int U32; |
98
|
|
|
|
|
|
|
typedef signed int S32; |
99
|
|
|
|
|
|
|
typedef unsigned long long U64; |
100
|
|
|
|
|
|
|
#endif |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
/* unoptimized version; solves endianess & alignment issues */ |
104
|
122
|
|
|
|
|
|
static U32 LZ4F_readLE32 (const void* src) |
105
|
|
|
|
|
|
|
{ |
106
|
122
|
|
|
|
|
|
const BYTE* const srcPtr = (const BYTE*)src; |
107
|
122
|
|
|
|
|
|
U32 value32 = srcPtr[0]; |
108
|
122
|
|
|
|
|
|
value32 += (srcPtr[1]<<8); |
109
|
122
|
|
|
|
|
|
value32 += (srcPtr[2]<<16); |
110
|
122
|
|
|
|
|
|
value32 += ((U32)srcPtr[3])<<24; |
111
|
122
|
|
|
|
|
|
return value32; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
15
|
|
|
|
|
|
static void LZ4F_writeLE32 (void* dst, U32 value32) |
115
|
|
|
|
|
|
|
{ |
116
|
15
|
|
|
|
|
|
BYTE* const dstPtr = (BYTE*)dst; |
117
|
15
|
|
|
|
|
|
dstPtr[0] = (BYTE)value32; |
118
|
15
|
|
|
|
|
|
dstPtr[1] = (BYTE)(value32 >> 8); |
119
|
15
|
|
|
|
|
|
dstPtr[2] = (BYTE)(value32 >> 16); |
120
|
15
|
|
|
|
|
|
dstPtr[3] = (BYTE)(value32 >> 24); |
121
|
15
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
4
|
|
|
|
|
|
static U64 LZ4F_readLE64 (const void* src) |
124
|
|
|
|
|
|
|
{ |
125
|
4
|
|
|
|
|
|
const BYTE* const srcPtr = (const BYTE*)src; |
126
|
4
|
|
|
|
|
|
U64 value64 = srcPtr[0]; |
127
|
4
|
|
|
|
|
|
value64 += ((U64)srcPtr[1]<<8); |
128
|
4
|
|
|
|
|
|
value64 += ((U64)srcPtr[2]<<16); |
129
|
4
|
|
|
|
|
|
value64 += ((U64)srcPtr[3]<<24); |
130
|
4
|
|
|
|
|
|
value64 += ((U64)srcPtr[4]<<32); |
131
|
4
|
|
|
|
|
|
value64 += ((U64)srcPtr[5]<<40); |
132
|
4
|
|
|
|
|
|
value64 += ((U64)srcPtr[6]<<48); |
133
|
4
|
|
|
|
|
|
value64 += ((U64)srcPtr[7]<<56); |
134
|
4
|
|
|
|
|
|
return value64; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
1
|
|
|
|
|
|
static void LZ4F_writeLE64 (void* dst, U64 value64) |
138
|
|
|
|
|
|
|
{ |
139
|
1
|
|
|
|
|
|
BYTE* const dstPtr = (BYTE*)dst; |
140
|
1
|
|
|
|
|
|
dstPtr[0] = (BYTE)value64; |
141
|
1
|
|
|
|
|
|
dstPtr[1] = (BYTE)(value64 >> 8); |
142
|
1
|
|
|
|
|
|
dstPtr[2] = (BYTE)(value64 >> 16); |
143
|
1
|
|
|
|
|
|
dstPtr[3] = (BYTE)(value64 >> 24); |
144
|
1
|
|
|
|
|
|
dstPtr[4] = (BYTE)(value64 >> 32); |
145
|
1
|
|
|
|
|
|
dstPtr[5] = (BYTE)(value64 >> 40); |
146
|
1
|
|
|
|
|
|
dstPtr[6] = (BYTE)(value64 >> 48); |
147
|
1
|
|
|
|
|
|
dstPtr[7] = (BYTE)(value64 >> 56); |
148
|
1
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
/*-************************************ |
152
|
|
|
|
|
|
|
* Constants |
153
|
|
|
|
|
|
|
**************************************/ |
154
|
|
|
|
|
|
|
#define KB *(1<<10) |
155
|
|
|
|
|
|
|
#define MB *(1<<20) |
156
|
|
|
|
|
|
|
#define GB *(1<<30) |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
#define _1BIT 0x01 |
159
|
|
|
|
|
|
|
#define _2BITS 0x03 |
160
|
|
|
|
|
|
|
#define _3BITS 0x07 |
161
|
|
|
|
|
|
|
#define _4BITS 0x0F |
162
|
|
|
|
|
|
|
#define _8BITS 0xFF |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
#define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U |
165
|
|
|
|
|
|
|
#define LZ4F_MAGICNUMBER 0x184D2204U |
166
|
|
|
|
|
|
|
#define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U |
167
|
|
|
|
|
|
|
#define LZ4F_BLOCKSIZEID_DEFAULT LZ4F_max64KB |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
static const size_t minFHSize = 7; |
170
|
|
|
|
|
|
|
static const size_t maxFHSize = LZ4F_HEADER_SIZE_MAX; /* 19 */ |
171
|
|
|
|
|
|
|
static const size_t BHSize = 4; |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
/*-************************************ |
175
|
|
|
|
|
|
|
* Structures and local types |
176
|
|
|
|
|
|
|
**************************************/ |
177
|
|
|
|
|
|
|
typedef struct LZ4F_cctx_s |
178
|
|
|
|
|
|
|
{ |
179
|
|
|
|
|
|
|
LZ4F_preferences_t prefs; |
180
|
|
|
|
|
|
|
U32 version; |
181
|
|
|
|
|
|
|
U32 cStage; |
182
|
|
|
|
|
|
|
const LZ4F_CDict* cdict; |
183
|
|
|
|
|
|
|
size_t maxBlockSize; |
184
|
|
|
|
|
|
|
size_t maxBufferSize; |
185
|
|
|
|
|
|
|
BYTE* tmpBuff; |
186
|
|
|
|
|
|
|
BYTE* tmpIn; |
187
|
|
|
|
|
|
|
size_t tmpInSize; |
188
|
|
|
|
|
|
|
U64 totalInSize; |
189
|
|
|
|
|
|
|
XXH32_state_t xxh; |
190
|
|
|
|
|
|
|
void* lz4CtxPtr; |
191
|
|
|
|
|
|
|
U32 lz4CtxLevel; /* 0: unallocated; 1: LZ4_stream_t; 3: LZ4_streamHC_t */ |
192
|
|
|
|
|
|
|
} LZ4F_cctx_t; |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
/*-************************************ |
196
|
|
|
|
|
|
|
* Error management |
197
|
|
|
|
|
|
|
**************************************/ |
198
|
|
|
|
|
|
|
#define LZ4F_GENERATE_STRING(STRING) #STRING, |
199
|
|
|
|
|
|
|
static const char* LZ4F_errorStrings[] = { LZ4F_LIST_ERRORS(LZ4F_GENERATE_STRING) }; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
|
202
|
557
|
|
|
|
|
|
unsigned LZ4F_isError(LZ4F_errorCode_t code) |
203
|
|
|
|
|
|
|
{ |
204
|
557
|
|
|
|
|
|
return (code > (LZ4F_errorCode_t)(-LZ4F_ERROR_maxCode)); |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
0
|
|
|
|
|
|
const char* LZ4F_getErrorName(LZ4F_errorCode_t code) |
208
|
|
|
|
|
|
|
{ |
209
|
|
|
|
|
|
|
static const char* codeError = "Unspecified error code"; |
210
|
0
|
0
|
|
|
|
|
if (LZ4F_isError(code)) return LZ4F_errorStrings[-(int)(code)]; |
211
|
0
|
|
|
|
|
|
return codeError; |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
|
LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult) |
215
|
|
|
|
|
|
|
{ |
216
|
0
|
0
|
|
|
|
|
if (!LZ4F_isError(functionResult)) return LZ4F_OK_NoError; |
217
|
0
|
|
|
|
|
|
return (LZ4F_errorCodes)(-(ptrdiff_t)functionResult); |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
1
|
|
|
|
|
|
static LZ4F_errorCode_t err0r(LZ4F_errorCodes code) |
221
|
|
|
|
|
|
|
{ |
222
|
|
|
|
|
|
|
/* A compilation error here means sizeof(ptrdiff_t) is not large enough */ |
223
|
|
|
|
|
|
|
LZ4F_STATIC_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t)); |
224
|
1
|
|
|
|
|
|
return (LZ4F_errorCode_t)-(ptrdiff_t)code; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
unsigned LZ4F_getVersion(void) { return LZ4F_VERSION; } |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
int LZ4F_compressionLevel_max(void) { return LZ4HC_CLEVEL_MAX; } |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
/*-************************************ |
233
|
|
|
|
|
|
|
* Private functions |
234
|
|
|
|
|
|
|
**************************************/ |
235
|
|
|
|
|
|
|
#define MIN(a,b) ( (a) < (b) ? (a) : (b) ) |
236
|
|
|
|
|
|
|
|
237
|
12
|
|
|
|
|
|
static size_t LZ4F_getBlockSize(unsigned blockSizeID) |
238
|
|
|
|
|
|
|
{ |
239
|
|
|
|
|
|
|
static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB }; |
240
|
|
|
|
|
|
|
|
241
|
12
|
100
|
|
|
|
|
if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT; |
242
|
12
|
|
|
|
|
|
blockSizeID -= 4; |
243
|
12
|
50
|
|
|
|
|
if (blockSizeID > 3) return err0r(LZ4F_ERROR_maxBlockSize_invalid); |
244
|
12
|
|
|
|
|
|
return blockSizes[blockSizeID]; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
8
|
|
|
|
|
|
static BYTE LZ4F_headerChecksum (const void* header, size_t length) |
248
|
|
|
|
|
|
|
{ |
249
|
8
|
|
|
|
|
|
U32 const xxh = XXH32(header, length, 0); |
250
|
8
|
|
|
|
|
|
return (BYTE)(xxh >> 8); |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
/*-************************************ |
255
|
|
|
|
|
|
|
* Simple-pass compression functions |
256
|
|
|
|
|
|
|
**************************************/ |
257
|
1
|
|
|
|
|
|
static LZ4F_blockSizeID_t LZ4F_optimalBSID(const LZ4F_blockSizeID_t requestedBSID, |
258
|
|
|
|
|
|
|
const size_t srcSize) |
259
|
|
|
|
|
|
|
{ |
260
|
1
|
|
|
|
|
|
LZ4F_blockSizeID_t proposedBSID = LZ4F_max64KB; |
261
|
1
|
|
|
|
|
|
size_t maxBlockSize = 64 KB; |
262
|
1
|
50
|
|
|
|
|
while (requestedBSID > proposedBSID) { |
263
|
0
|
0
|
|
|
|
|
if (srcSize <= maxBlockSize) |
264
|
0
|
|
|
|
|
|
return proposedBSID; |
265
|
0
|
|
|
|
|
|
proposedBSID = (LZ4F_blockSizeID_t)((int)proposedBSID + 1); |
266
|
0
|
|
|
|
|
|
maxBlockSize <<= 2; |
267
|
|
|
|
|
|
|
} |
268
|
1
|
|
|
|
|
|
return requestedBSID; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
/*! LZ4F_compressBound_internal() : |
272
|
|
|
|
|
|
|
* Provides dstCapacity given a srcSize to guarantee operation success in worst case situations. |
273
|
|
|
|
|
|
|
* prefsPtr is optional : if NULL is provided, preferences will be set to cover worst case scenario. |
274
|
|
|
|
|
|
|
* @return is always the same for a srcSize and prefsPtr, so it can be relied upon to size reusable buffers. |
275
|
|
|
|
|
|
|
* When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() operations. |
276
|
|
|
|
|
|
|
*/ |
277
|
3
|
|
|
|
|
|
static size_t LZ4F_compressBound_internal(size_t srcSize, |
278
|
|
|
|
|
|
|
const LZ4F_preferences_t* preferencesPtr, |
279
|
|
|
|
|
|
|
size_t alreadyBuffered) |
280
|
|
|
|
|
|
|
{ |
281
|
|
|
|
|
|
|
LZ4F_preferences_t prefsNull; |
282
|
3
|
|
|
|
|
|
memset(&prefsNull, 0, sizeof(prefsNull)); |
283
|
3
|
|
|
|
|
|
prefsNull.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; /* worst case */ |
284
|
3
|
50
|
|
|
|
|
{ const LZ4F_preferences_t* const prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr; |
285
|
3
|
|
|
|
|
|
U32 const flush = prefsPtr->autoFlush | (srcSize==0); |
286
|
3
|
|
|
|
|
|
LZ4F_blockSizeID_t const blockID = prefsPtr->frameInfo.blockSizeID; |
287
|
3
|
|
|
|
|
|
size_t const blockSize = LZ4F_getBlockSize(blockID); |
288
|
3
|
|
|
|
|
|
size_t const maxBuffered = blockSize - 1; |
289
|
3
|
|
|
|
|
|
size_t const bufferedSize = MIN(alreadyBuffered, maxBuffered); |
290
|
3
|
|
|
|
|
|
size_t const maxSrcSize = srcSize + bufferedSize; |
291
|
3
|
|
|
|
|
|
unsigned const nbFullBlocks = (unsigned)(maxSrcSize / blockSize); |
292
|
3
|
|
|
|
|
|
size_t const partialBlockSize = maxSrcSize & (blockSize-1); |
293
|
3
|
50
|
|
|
|
|
size_t const lastBlockSize = flush ? partialBlockSize : 0; |
294
|
3
|
|
|
|
|
|
unsigned const nbBlocks = nbFullBlocks + (lastBlockSize>0); |
295
|
|
|
|
|
|
|
|
296
|
3
|
|
|
|
|
|
size_t const blockHeaderSize = 4; |
297
|
3
|
|
|
|
|
|
size_t const blockCRCSize = 4 * prefsPtr->frameInfo.blockChecksumFlag; |
298
|
3
|
|
|
|
|
|
size_t const frameEnd = 4 + (prefsPtr->frameInfo.contentChecksumFlag*4); |
299
|
|
|
|
|
|
|
|
300
|
3
|
|
|
|
|
|
return ((blockHeaderSize + blockCRCSize) * nbBlocks) + |
301
|
6
|
|
|
|
|
|
(blockSize * nbFullBlocks) + lastBlockSize + frameEnd; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
2
|
|
|
|
|
|
size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr) |
306
|
|
|
|
|
|
|
{ |
307
|
|
|
|
|
|
|
LZ4F_preferences_t prefs; |
308
|
2
|
|
|
|
|
|
size_t const headerSize = maxFHSize; /* max header size, including optional fields */ |
309
|
|
|
|
|
|
|
|
310
|
2
|
50
|
|
|
|
|
if (preferencesPtr!=NULL) prefs = *preferencesPtr; |
311
|
0
|
|
|
|
|
|
else memset(&prefs, 0, sizeof(prefs)); |
312
|
2
|
|
|
|
|
|
prefs.autoFlush = 1; |
313
|
|
|
|
|
|
|
|
314
|
2
|
|
|
|
|
|
return headerSize + LZ4F_compressBound_internal(srcSize, &prefs, 0);; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
/*! LZ4F_compressFrame_usingCDict() : |
319
|
|
|
|
|
|
|
* Compress srcBuffer using a dictionary, in a single step. |
320
|
|
|
|
|
|
|
* cdict can be NULL, in which case, no dictionary is used. |
321
|
|
|
|
|
|
|
* dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr). |
322
|
|
|
|
|
|
|
* The LZ4F_preferences_t structure is optional : you may provide NULL as argument, |
323
|
|
|
|
|
|
|
* however, it's the only way to provide a dictID, so it's not recommended. |
324
|
|
|
|
|
|
|
* @return : number of bytes written into dstBuffer, |
325
|
|
|
|
|
|
|
* or an error code if it fails (can be tested using LZ4F_isError()) |
326
|
|
|
|
|
|
|
*/ |
327
|
1
|
|
|
|
|
|
size_t LZ4F_compressFrame_usingCDict(void* dstBuffer, size_t dstCapacity, |
328
|
|
|
|
|
|
|
const void* srcBuffer, size_t srcSize, |
329
|
|
|
|
|
|
|
const LZ4F_CDict* cdict, |
330
|
|
|
|
|
|
|
const LZ4F_preferences_t* preferencesPtr) |
331
|
|
|
|
|
|
|
{ |
332
|
|
|
|
|
|
|
LZ4F_cctx_t cctxI; |
333
|
|
|
|
|
|
|
LZ4_stream_t lz4ctx; /* pretty large on stack */ |
334
|
|
|
|
|
|
|
LZ4F_preferences_t prefs; |
335
|
|
|
|
|
|
|
LZ4F_compressOptions_t options; |
336
|
1
|
|
|
|
|
|
BYTE* const dstStart = (BYTE*) dstBuffer; |
337
|
1
|
|
|
|
|
|
BYTE* dstPtr = dstStart; |
338
|
1
|
|
|
|
|
|
BYTE* const dstEnd = dstStart + dstCapacity; |
339
|
|
|
|
|
|
|
|
340
|
1
|
|
|
|
|
|
memset(&cctxI, 0, sizeof(cctxI)); |
341
|
1
|
|
|
|
|
|
cctxI.version = LZ4F_VERSION; |
342
|
1
|
|
|
|
|
|
cctxI.maxBufferSize = 5 MB; /* mess with real buffer size to prevent dynamic allocation; works only because autoflush==1 & stableSrc==1 */ |
343
|
|
|
|
|
|
|
|
344
|
1
|
50
|
|
|
|
|
if (preferencesPtr!=NULL) |
345
|
1
|
|
|
|
|
|
prefs = *preferencesPtr; |
346
|
|
|
|
|
|
|
else |
347
|
0
|
|
|
|
|
|
memset(&prefs, 0, sizeof(prefs)); |
348
|
1
|
50
|
|
|
|
|
if (prefs.frameInfo.contentSize != 0) |
349
|
1
|
|
|
|
|
|
prefs.frameInfo.contentSize = (U64)srcSize; /* auto-correct content size if selected (!=0) */ |
350
|
|
|
|
|
|
|
|
351
|
1
|
|
|
|
|
|
prefs.frameInfo.blockSizeID = LZ4F_optimalBSID(prefs.frameInfo.blockSizeID, srcSize); |
352
|
1
|
|
|
|
|
|
prefs.autoFlush = 1; |
353
|
1
|
50
|
|
|
|
|
if (srcSize <= LZ4F_getBlockSize(prefs.frameInfo.blockSizeID)) |
354
|
0
|
|
|
|
|
|
prefs.frameInfo.blockMode = LZ4F_blockIndependent; /* only one block => no need for inter-block link */ |
355
|
|
|
|
|
|
|
|
356
|
1
|
50
|
|
|
|
|
if (prefs.compressionLevel < LZ4HC_CLEVEL_MIN) { |
357
|
1
|
|
|
|
|
|
cctxI.lz4CtxPtr = &lz4ctx; |
358
|
1
|
|
|
|
|
|
cctxI.lz4CtxLevel = 1; |
359
|
|
|
|
|
|
|
} /* fast compression context pre-created on stack */ |
360
|
|
|
|
|
|
|
|
361
|
1
|
|
|
|
|
|
memset(&options, 0, sizeof(options)); |
362
|
1
|
|
|
|
|
|
options.stableSrc = 1; |
363
|
|
|
|
|
|
|
|
364
|
1
|
50
|
|
|
|
|
if (dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs)) /* condition to guarantee success */ |
365
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); |
366
|
|
|
|
|
|
|
|
367
|
1
|
|
|
|
|
|
{ size_t const headerSize = LZ4F_compressBegin_usingCDict(&cctxI, dstBuffer, dstCapacity, cdict, &prefs); /* write header */ |
368
|
1
|
50
|
|
|
|
|
if (LZ4F_isError(headerSize)) return headerSize; |
369
|
1
|
|
|
|
|
|
dstPtr += headerSize; /* header size */ } |
370
|
|
|
|
|
|
|
|
371
|
1
|
|
|
|
|
|
{ size_t const cSize = LZ4F_compressUpdate(&cctxI, dstPtr, dstEnd-dstPtr, srcBuffer, srcSize, &options); |
372
|
1
|
50
|
|
|
|
|
if (LZ4F_isError(cSize)) return cSize; |
373
|
1
|
|
|
|
|
|
dstPtr += cSize; } |
374
|
|
|
|
|
|
|
|
375
|
1
|
|
|
|
|
|
{ size_t const tailSize = LZ4F_compressEnd(&cctxI, dstPtr, dstEnd-dstPtr, &options); /* flush last block, and generate suffix */ |
376
|
1
|
50
|
|
|
|
|
if (LZ4F_isError(tailSize)) return tailSize; |
377
|
1
|
|
|
|
|
|
dstPtr += tailSize; } |
378
|
|
|
|
|
|
|
|
379
|
1
|
50
|
|
|
|
|
if (prefs.compressionLevel >= LZ4HC_CLEVEL_MIN) /* Ctx allocation only for lz4hc */ |
380
|
0
|
|
|
|
|
|
FREEMEM(cctxI.lz4CtxPtr); |
381
|
|
|
|
|
|
|
|
382
|
1
|
|
|
|
|
|
return (dstPtr - dstStart); |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
/*! LZ4F_compressFrame() : |
387
|
|
|
|
|
|
|
* Compress an entire srcBuffer into a valid LZ4 frame, in a single step. |
388
|
|
|
|
|
|
|
* dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr). |
389
|
|
|
|
|
|
|
* The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will be set to default. |
390
|
|
|
|
|
|
|
* @return : number of bytes written into dstBuffer. |
391
|
|
|
|
|
|
|
* or an error code if it fails (can be tested using LZ4F_isError()) |
392
|
|
|
|
|
|
|
*/ |
393
|
1
|
|
|
|
|
|
size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, |
394
|
|
|
|
|
|
|
const void* srcBuffer, size_t srcSize, |
395
|
|
|
|
|
|
|
const LZ4F_preferences_t* preferencesPtr) |
396
|
|
|
|
|
|
|
{ |
397
|
1
|
|
|
|
|
|
return LZ4F_compressFrame_usingCDict(dstBuffer, dstCapacity, |
398
|
|
|
|
|
|
|
srcBuffer, srcSize, |
399
|
|
|
|
|
|
|
NULL, preferencesPtr); |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
/*-*************************************************** |
404
|
|
|
|
|
|
|
* Dictionary compression |
405
|
|
|
|
|
|
|
*****************************************************/ |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
struct LZ4F_CDict_s { |
408
|
|
|
|
|
|
|
void* dictContent; |
409
|
|
|
|
|
|
|
LZ4_stream_t* fastCtx; |
410
|
|
|
|
|
|
|
LZ4_streamHC_t* HCCtx; |
411
|
|
|
|
|
|
|
}; /* typedef'd to LZ4F_CDict within lz4frame_static.h */ |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
/*! LZ4F_createCDict() : |
414
|
|
|
|
|
|
|
* When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once. |
415
|
|
|
|
|
|
|
* LZ4F_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay. |
416
|
|
|
|
|
|
|
* LZ4F_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only. |
417
|
|
|
|
|
|
|
* `dictBuffer` can be released after LZ4F_CDict creation, since its content is copied within CDict |
418
|
|
|
|
|
|
|
* @return : digested dictionary for compression, or NULL if failed */ |
419
|
0
|
|
|
|
|
|
LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize) |
420
|
|
|
|
|
|
|
{ |
421
|
0
|
|
|
|
|
|
const char* dictStart = (const char*)dictBuffer; |
422
|
0
|
|
|
|
|
|
LZ4F_CDict* cdict = (LZ4F_CDict*) malloc(sizeof(*cdict)); |
423
|
0
|
0
|
|
|
|
|
if (!cdict) return NULL; |
424
|
0
|
0
|
|
|
|
|
if (dictSize > 64 KB) { |
425
|
0
|
|
|
|
|
|
dictStart += dictSize - 64 KB; |
426
|
0
|
|
|
|
|
|
dictSize = 64 KB; |
427
|
|
|
|
|
|
|
} |
428
|
0
|
|
|
|
|
|
cdict->dictContent = ALLOCATOR(dictSize); |
429
|
0
|
|
|
|
|
|
cdict->fastCtx = LZ4_createStream(); |
430
|
0
|
|
|
|
|
|
cdict->HCCtx = LZ4_createStreamHC(); |
431
|
0
|
0
|
|
|
|
|
if (!cdict->dictContent || !cdict->fastCtx || !cdict->HCCtx) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
432
|
0
|
|
|
|
|
|
LZ4F_freeCDict(cdict); |
433
|
0
|
|
|
|
|
|
return NULL; |
434
|
|
|
|
|
|
|
} |
435
|
0
|
|
|
|
|
|
memcpy(cdict->dictContent, dictStart, dictSize); |
436
|
0
|
|
|
|
|
|
LZ4_resetStream(cdict->fastCtx); |
437
|
0
|
|
|
|
|
|
LZ4_loadDict (cdict->fastCtx, (const char*)cdict->dictContent, (int)dictSize); |
438
|
0
|
|
|
|
|
|
LZ4_resetStreamHC(cdict->HCCtx, LZ4HC_CLEVEL_DEFAULT); |
439
|
0
|
|
|
|
|
|
LZ4_loadDictHC(cdict->HCCtx, (const char*)cdict->dictContent, (int)dictSize); |
440
|
0
|
|
|
|
|
|
return cdict; |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
|
443
|
0
|
|
|
|
|
|
void LZ4F_freeCDict(LZ4F_CDict* cdict) |
444
|
|
|
|
|
|
|
{ |
445
|
0
|
0
|
|
|
|
|
if (cdict==NULL) return; /* support free on NULL */ |
446
|
0
|
|
|
|
|
|
FREEMEM(cdict->dictContent); |
447
|
0
|
|
|
|
|
|
LZ4_freeStream(cdict->fastCtx); |
448
|
0
|
|
|
|
|
|
LZ4_freeStreamHC(cdict->HCCtx); |
449
|
0
|
|
|
|
|
|
FREEMEM(cdict); |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
/*-********************************* |
454
|
|
|
|
|
|
|
* Advanced compression functions |
455
|
|
|
|
|
|
|
***********************************/ |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
/*! LZ4F_createCompressionContext() : |
458
|
|
|
|
|
|
|
* The first thing to do is to create a compressionContext object, which will be used in all compression operations. |
459
|
|
|
|
|
|
|
* This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure. |
460
|
|
|
|
|
|
|
* The version provided MUST be LZ4F_VERSION. It is intended to track potential incompatible differences between different binaries. |
461
|
|
|
|
|
|
|
* The function will provide a pointer to an allocated LZ4F_compressionContext_t object. |
462
|
|
|
|
|
|
|
* If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation. |
463
|
|
|
|
|
|
|
* Object can release its memory using LZ4F_freeCompressionContext(); |
464
|
|
|
|
|
|
|
*/ |
465
|
0
|
|
|
|
|
|
LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* LZ4F_compressionContextPtr, unsigned version) |
466
|
|
|
|
|
|
|
{ |
467
|
0
|
|
|
|
|
|
LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)ALLOCATOR(sizeof(LZ4F_cctx_t)); |
468
|
0
|
0
|
|
|
|
|
if (cctxPtr==NULL) return err0r(LZ4F_ERROR_allocation_failed); |
469
|
|
|
|
|
|
|
|
470
|
0
|
|
|
|
|
|
cctxPtr->version = version; |
471
|
0
|
|
|
|
|
|
cctxPtr->cStage = 0; /* Next stage : init stream */ |
472
|
|
|
|
|
|
|
|
473
|
0
|
|
|
|
|
|
*LZ4F_compressionContextPtr = (LZ4F_compressionContext_t)cctxPtr; |
474
|
|
|
|
|
|
|
|
475
|
0
|
|
|
|
|
|
return LZ4F_OK_NoError; |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
|
479
|
0
|
|
|
|
|
|
LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_compressionContext) |
480
|
|
|
|
|
|
|
{ |
481
|
0
|
|
|
|
|
|
LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)LZ4F_compressionContext; |
482
|
|
|
|
|
|
|
|
483
|
0
|
0
|
|
|
|
|
if (cctxPtr != NULL) { /* support free on NULL */ |
484
|
0
|
|
|
|
|
|
FREEMEM(cctxPtr->lz4CtxPtr); /* works because LZ4_streamHC_t and LZ4_stream_t are simple POD types */ |
485
|
0
|
|
|
|
|
|
FREEMEM(cctxPtr->tmpBuff); |
486
|
0
|
|
|
|
|
|
FREEMEM(LZ4F_compressionContext); |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
|
489
|
0
|
|
|
|
|
|
return LZ4F_OK_NoError; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
/*! LZ4F_compressBegin_usingCDict() : |
494
|
|
|
|
|
|
|
* init streaming compression and writes frame header into dstBuffer. |
495
|
|
|
|
|
|
|
* dstBuffer must be >= LZ4F_HEADER_SIZE_MAX bytes. |
496
|
|
|
|
|
|
|
* @return : number of bytes written into dstBuffer for the header |
497
|
|
|
|
|
|
|
* or an error code (can be tested using LZ4F_isError()) |
498
|
|
|
|
|
|
|
*/ |
499
|
1
|
|
|
|
|
|
size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr, |
500
|
|
|
|
|
|
|
void* dstBuffer, size_t dstCapacity, |
501
|
|
|
|
|
|
|
const LZ4F_CDict* cdict, |
502
|
|
|
|
|
|
|
const LZ4F_preferences_t* preferencesPtr) |
503
|
|
|
|
|
|
|
{ |
504
|
|
|
|
|
|
|
LZ4F_preferences_t prefNull; |
505
|
1
|
|
|
|
|
|
BYTE* const dstStart = (BYTE*)dstBuffer; |
506
|
1
|
|
|
|
|
|
BYTE* dstPtr = dstStart; |
507
|
|
|
|
|
|
|
BYTE* headerStart; |
508
|
|
|
|
|
|
|
|
509
|
1
|
50
|
|
|
|
|
if (dstCapacity < maxFHSize) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); |
510
|
1
|
|
|
|
|
|
memset(&prefNull, 0, sizeof(prefNull)); |
511
|
1
|
50
|
|
|
|
|
if (preferencesPtr == NULL) preferencesPtr = &prefNull; |
512
|
1
|
|
|
|
|
|
cctxPtr->prefs = *preferencesPtr; |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
/* Ctx Management */ |
515
|
1
|
50
|
|
|
|
|
{ U32 const ctxTypeID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2; /* 0:nothing ; 1:LZ4 table ; 2:HC tables */ |
516
|
1
|
50
|
|
|
|
|
if (cctxPtr->lz4CtxLevel < ctxTypeID) { |
517
|
0
|
|
|
|
|
|
FREEMEM(cctxPtr->lz4CtxPtr); |
518
|
0
|
0
|
|
|
|
|
if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) |
519
|
0
|
|
|
|
|
|
cctxPtr->lz4CtxPtr = (void*)LZ4_createStream(); |
520
|
|
|
|
|
|
|
else |
521
|
0
|
|
|
|
|
|
cctxPtr->lz4CtxPtr = (void*)LZ4_createStreamHC(); |
522
|
0
|
0
|
|
|
|
|
if (cctxPtr->lz4CtxPtr == NULL) return err0r(LZ4F_ERROR_allocation_failed); |
523
|
0
|
|
|
|
|
|
cctxPtr->lz4CtxLevel = ctxTypeID; |
524
|
|
|
|
|
|
|
} } |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
/* Buffer Management */ |
527
|
1
|
50
|
|
|
|
|
if (cctxPtr->prefs.frameInfo.blockSizeID == 0) |
528
|
1
|
|
|
|
|
|
cctxPtr->prefs.frameInfo.blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT; |
529
|
1
|
|
|
|
|
|
cctxPtr->maxBlockSize = LZ4F_getBlockSize(cctxPtr->prefs.frameInfo.blockSizeID); |
530
|
|
|
|
|
|
|
|
531
|
2
|
|
|
|
|
|
{ size_t const requiredBuffSize = preferencesPtr->autoFlush ? |
532
|
1
|
50
|
|
|
|
|
(cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) * 64 KB : /* only needs windows size */ |
|
|
50
|
|
|
|
|
|
533
|
0
|
0
|
|
|
|
|
cctxPtr->maxBlockSize + ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) * 128 KB); |
534
|
|
|
|
|
|
|
|
535
|
1
|
50
|
|
|
|
|
if (cctxPtr->maxBufferSize < requiredBuffSize) { |
536
|
0
|
|
|
|
|
|
cctxPtr->maxBufferSize = 0; |
537
|
0
|
|
|
|
|
|
FREEMEM(cctxPtr->tmpBuff); |
538
|
0
|
|
|
|
|
|
cctxPtr->tmpBuff = (BYTE*)ALLOCATOR(requiredBuffSize); |
539
|
0
|
0
|
|
|
|
|
if (cctxPtr->tmpBuff == NULL) return err0r(LZ4F_ERROR_allocation_failed); |
540
|
0
|
|
|
|
|
|
cctxPtr->maxBufferSize = requiredBuffSize; |
541
|
|
|
|
|
|
|
} } |
542
|
1
|
|
|
|
|
|
cctxPtr->tmpIn = cctxPtr->tmpBuff; |
543
|
1
|
|
|
|
|
|
cctxPtr->tmpInSize = 0; |
544
|
1
|
|
|
|
|
|
XXH32_reset(&(cctxPtr->xxh), 0); |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
/* context init */ |
547
|
1
|
|
|
|
|
|
cctxPtr->cdict = cdict; |
548
|
1
|
50
|
|
|
|
|
if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) { |
549
|
|
|
|
|
|
|
/* frame init only for blockLinked : blockIndependent will be init at each block */ |
550
|
1
|
50
|
|
|
|
|
if (cdict) { |
551
|
0
|
0
|
|
|
|
|
if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) { |
552
|
0
|
|
|
|
|
|
memcpy(cctxPtr->lz4CtxPtr, cdict->fastCtx, sizeof(*cdict->fastCtx)); |
553
|
|
|
|
|
|
|
} else { |
554
|
0
|
|
|
|
|
|
memcpy(cctxPtr->lz4CtxPtr, cdict->HCCtx, sizeof(*cdict->HCCtx)); |
555
|
0
|
|
|
|
|
|
LZ4_setCompressionLevel((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel); |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
} else { |
558
|
1
|
50
|
|
|
|
|
if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) |
559
|
1
|
|
|
|
|
|
LZ4_resetStream((LZ4_stream_t*)(cctxPtr->lz4CtxPtr)); |
560
|
|
|
|
|
|
|
else |
561
|
0
|
|
|
|
|
|
LZ4_resetStreamHC((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), cctxPtr->prefs.compressionLevel); |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
/* Magic Number */ |
566
|
1
|
|
|
|
|
|
LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER); |
567
|
1
|
|
|
|
|
|
dstPtr += 4; |
568
|
1
|
|
|
|
|
|
headerStart = dstPtr; |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
/* FLG Byte */ |
571
|
1
|
50
|
|
|
|
|
*dstPtr++ = (BYTE)(((1 & _2BITS) << 6) /* Version('01') */ |
572
|
1
|
|
|
|
|
|
+ ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5) |
573
|
1
|
|
|
|
|
|
+ ((cctxPtr->prefs.frameInfo.blockChecksumFlag & _1BIT ) << 4) |
574
|
1
|
|
|
|
|
|
+ ((cctxPtr->prefs.frameInfo.contentSize > 0) << 3) |
575
|
1
|
|
|
|
|
|
+ ((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2) |
576
|
1
|
|
|
|
|
|
+ (cctxPtr->prefs.frameInfo.dictID > 0) ); |
577
|
|
|
|
|
|
|
/* BD Byte */ |
578
|
1
|
|
|
|
|
|
*dstPtr++ = (BYTE)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4); |
579
|
|
|
|
|
|
|
/* Optional Frame content size field */ |
580
|
1
|
50
|
|
|
|
|
if (cctxPtr->prefs.frameInfo.contentSize) { |
581
|
1
|
|
|
|
|
|
LZ4F_writeLE64(dstPtr, cctxPtr->prefs.frameInfo.contentSize); |
582
|
1
|
|
|
|
|
|
dstPtr += 8; |
583
|
1
|
|
|
|
|
|
cctxPtr->totalInSize = 0; |
584
|
|
|
|
|
|
|
} |
585
|
|
|
|
|
|
|
/* Optional dictionary ID field */ |
586
|
1
|
50
|
|
|
|
|
if (cctxPtr->prefs.frameInfo.dictID) { |
587
|
0
|
|
|
|
|
|
LZ4F_writeLE32(dstPtr, cctxPtr->prefs.frameInfo.dictID); |
588
|
0
|
|
|
|
|
|
dstPtr += 4; |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
/* Header CRC Byte */ |
591
|
1
|
|
|
|
|
|
*dstPtr = LZ4F_headerChecksum(headerStart, dstPtr - headerStart); |
592
|
1
|
|
|
|
|
|
dstPtr++; |
593
|
|
|
|
|
|
|
|
594
|
1
|
|
|
|
|
|
cctxPtr->cStage = 1; /* header written, now request input data block */ |
595
|
1
|
|
|
|
|
|
return (dstPtr - dstStart); |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
/*! LZ4F_compressBegin() : |
600
|
|
|
|
|
|
|
* init streaming compression and writes frame header into dstBuffer. |
601
|
|
|
|
|
|
|
* dstBuffer must be >= LZ4F_HEADER_SIZE_MAX bytes. |
602
|
|
|
|
|
|
|
* preferencesPtr can be NULL, in which case default parameters are selected. |
603
|
|
|
|
|
|
|
* @return : number of bytes written into dstBuffer for the header |
604
|
|
|
|
|
|
|
* or an error code (can be tested using LZ4F_isError()) |
605
|
|
|
|
|
|
|
*/ |
606
|
0
|
|
|
|
|
|
size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr, |
607
|
|
|
|
|
|
|
void* dstBuffer, size_t dstCapacity, |
608
|
|
|
|
|
|
|
const LZ4F_preferences_t* preferencesPtr) |
609
|
|
|
|
|
|
|
{ |
610
|
0
|
|
|
|
|
|
return LZ4F_compressBegin_usingCDict(cctxPtr, dstBuffer, dstCapacity, |
611
|
|
|
|
|
|
|
NULL, preferencesPtr); |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
/* LZ4F_compressBound() : |
616
|
|
|
|
|
|
|
* @return minimum capacity of dstBuffer for a given srcSize to handle worst case scenario. |
617
|
|
|
|
|
|
|
* LZ4F_preferences_t structure is optional : if NULL, preferences will be set to cover worst case scenario. |
618
|
|
|
|
|
|
|
* This function cannot fail. |
619
|
|
|
|
|
|
|
*/ |
620
|
0
|
|
|
|
|
|
size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr) |
621
|
|
|
|
|
|
|
{ |
622
|
0
|
|
|
|
|
|
return LZ4F_compressBound_internal(srcSize, preferencesPtr, (size_t)-1); |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
typedef int (*compressFunc_t)(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level, const LZ4F_CDict* cdict); |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
/*! LZ4F_makeBlock(): |
630
|
|
|
|
|
|
|
* compress a single block, add header and checksum |
631
|
|
|
|
|
|
|
* assumption : dst buffer capacity is >= srcSize */ |
632
|
13
|
|
|
|
|
|
static size_t LZ4F_makeBlock(void* dst, const void* src, size_t srcSize, |
633
|
|
|
|
|
|
|
compressFunc_t compress, void* lz4ctx, int level, |
634
|
|
|
|
|
|
|
const LZ4F_CDict* cdict, LZ4F_blockChecksum_t crcFlag) |
635
|
|
|
|
|
|
|
{ |
636
|
13
|
|
|
|
|
|
BYTE* const cSizePtr = (BYTE*)dst; |
637
|
13
|
|
|
|
|
|
U32 cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+4), |
638
|
|
|
|
|
|
|
(int)(srcSize), (int)(srcSize-1), |
639
|
|
|
|
|
|
|
level, cdict); |
640
|
13
|
|
|
|
|
|
LZ4F_writeLE32(cSizePtr, cSize); |
641
|
13
|
50
|
|
|
|
|
if (cSize == 0) { /* compression failed */ |
642
|
0
|
|
|
|
|
|
cSize = (U32)srcSize; |
643
|
0
|
|
|
|
|
|
LZ4F_writeLE32(cSizePtr, cSize | LZ4F_BLOCKUNCOMPRESSED_FLAG); |
644
|
0
|
|
|
|
|
|
memcpy(cSizePtr+4, src, srcSize); |
645
|
|
|
|
|
|
|
} |
646
|
13
|
50
|
|
|
|
|
if (crcFlag) { |
647
|
0
|
|
|
|
|
|
U32 const crc32 = XXH32(cSizePtr+4, cSize, 0); /* checksum of compressed data */ |
648
|
0
|
|
|
|
|
|
LZ4F_writeLE32(cSizePtr+4+cSize, crc32); |
649
|
|
|
|
|
|
|
} |
650
|
13
|
|
|
|
|
|
return 4 + cSize + ((U32)crcFlag)*4; |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
|
654
|
0
|
|
|
|
|
|
static int LZ4F_compressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) |
655
|
|
|
|
|
|
|
{ |
656
|
0
|
0
|
|
|
|
|
int const acceleration = (level < -1) ? -level : 1; |
657
|
0
|
0
|
|
|
|
|
if (cdict) { |
658
|
0
|
|
|
|
|
|
memcpy(ctx, cdict->fastCtx, sizeof(*cdict->fastCtx)); |
659
|
0
|
|
|
|
|
|
return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration); |
660
|
|
|
|
|
|
|
} |
661
|
0
|
|
|
|
|
|
return LZ4_compress_fast_extState(ctx, src, dst, srcSize, dstCapacity, acceleration); |
662
|
|
|
|
|
|
|
} |
663
|
|
|
|
|
|
|
|
664
|
13
|
|
|
|
|
|
static int LZ4F_compressBlock_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) |
665
|
|
|
|
|
|
|
{ |
666
|
13
|
50
|
|
|
|
|
int const acceleration = (level < -1) ? -level : 1; |
667
|
|
|
|
|
|
|
(void)cdict; /* init once at beginning of frame */ |
668
|
13
|
|
|
|
|
|
return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration); |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
|
671
|
0
|
|
|
|
|
|
static int LZ4F_compressBlockHC(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) |
672
|
|
|
|
|
|
|
{ |
673
|
0
|
0
|
|
|
|
|
if (cdict) { |
674
|
0
|
|
|
|
|
|
memcpy(ctx, cdict->HCCtx, sizeof(*cdict->HCCtx)); |
675
|
0
|
|
|
|
|
|
LZ4_setCompressionLevel((LZ4_streamHC_t*)ctx, level); |
676
|
0
|
|
|
|
|
|
return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity); |
677
|
|
|
|
|
|
|
} |
678
|
0
|
|
|
|
|
|
return LZ4_compress_HC_extStateHC(ctx, src, dst, srcSize, dstCapacity, level); |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
0
|
|
|
|
|
|
static int LZ4F_compressBlockHC_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) |
682
|
|
|
|
|
|
|
{ |
683
|
|
|
|
|
|
|
(void)level; (void)cdict; /* init once at beginning of frame */ |
684
|
0
|
|
|
|
|
|
return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity); |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
|
687
|
1
|
|
|
|
|
|
static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int level) |
688
|
|
|
|
|
|
|
{ |
689
|
1
|
50
|
|
|
|
|
if (level < LZ4HC_CLEVEL_MIN) { |
690
|
1
|
50
|
|
|
|
|
if (blockMode == LZ4F_blockIndependent) return LZ4F_compressBlock; |
691
|
1
|
|
|
|
|
|
return LZ4F_compressBlock_continue; |
692
|
|
|
|
|
|
|
} |
693
|
0
|
0
|
|
|
|
|
if (blockMode == LZ4F_blockIndependent) return LZ4F_compressBlockHC; |
694
|
0
|
|
|
|
|
|
return LZ4F_compressBlockHC_continue; |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
|
697
|
0
|
|
|
|
|
|
static int LZ4F_localSaveDict(LZ4F_cctx_t* cctxPtr) |
698
|
|
|
|
|
|
|
{ |
699
|
0
|
0
|
|
|
|
|
if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) |
700
|
0
|
|
|
|
|
|
return LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB); |
701
|
0
|
|
|
|
|
|
return LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB); |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus; |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
/*! LZ4F_compressUpdate() : |
707
|
|
|
|
|
|
|
* LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary. |
708
|
|
|
|
|
|
|
* dstBuffer MUST be >= LZ4F_compressBound(srcSize, preferencesPtr). |
709
|
|
|
|
|
|
|
* LZ4F_compressOptions_t structure is optional : you can provide NULL as argument. |
710
|
|
|
|
|
|
|
* @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered. |
711
|
|
|
|
|
|
|
* or an error code if it fails (which can be tested using LZ4F_isError()) |
712
|
|
|
|
|
|
|
*/ |
713
|
1
|
|
|
|
|
|
size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, |
714
|
|
|
|
|
|
|
void* dstBuffer, size_t dstCapacity, |
715
|
|
|
|
|
|
|
const void* srcBuffer, size_t srcSize, |
716
|
|
|
|
|
|
|
const LZ4F_compressOptions_t* compressOptionsPtr) |
717
|
|
|
|
|
|
|
{ |
718
|
|
|
|
|
|
|
LZ4F_compressOptions_t cOptionsNull; |
719
|
1
|
|
|
|
|
|
size_t const blockSize = cctxPtr->maxBlockSize; |
720
|
1
|
|
|
|
|
|
const BYTE* srcPtr = (const BYTE*)srcBuffer; |
721
|
1
|
|
|
|
|
|
const BYTE* const srcEnd = srcPtr + srcSize; |
722
|
1
|
|
|
|
|
|
BYTE* const dstStart = (BYTE*)dstBuffer; |
723
|
1
|
|
|
|
|
|
BYTE* dstPtr = dstStart; |
724
|
1
|
|
|
|
|
|
LZ4F_lastBlockStatus lastBlockCompressed = notDone; |
725
|
1
|
|
|
|
|
|
compressFunc_t const compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel); |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
|
728
|
1
|
50
|
|
|
|
|
if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC); |
729
|
1
|
50
|
|
|
|
|
if (dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize)) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); |
730
|
1
|
|
|
|
|
|
memset(&cOptionsNull, 0, sizeof(cOptionsNull)); |
731
|
1
|
50
|
|
|
|
|
if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull; |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
/* complete tmp buffer */ |
734
|
1
|
50
|
|
|
|
|
if (cctxPtr->tmpInSize > 0) { /* some data already within tmp buffer */ |
735
|
0
|
|
|
|
|
|
size_t const sizeToCopy = blockSize - cctxPtr->tmpInSize; |
736
|
0
|
0
|
|
|
|
|
if (sizeToCopy > srcSize) { |
737
|
|
|
|
|
|
|
/* add src to tmpIn buffer */ |
738
|
0
|
|
|
|
|
|
memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize); |
739
|
0
|
|
|
|
|
|
srcPtr = srcEnd; |
740
|
0
|
|
|
|
|
|
cctxPtr->tmpInSize += srcSize; |
741
|
|
|
|
|
|
|
/* still needs some CRC */ |
742
|
|
|
|
|
|
|
} else { |
743
|
|
|
|
|
|
|
/* complete tmpIn block and then compress it */ |
744
|
0
|
|
|
|
|
|
lastBlockCompressed = fromTmpBuffer; |
745
|
0
|
|
|
|
|
|
memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, sizeToCopy); |
746
|
0
|
|
|
|
|
|
srcPtr += sizeToCopy; |
747
|
|
|
|
|
|
|
|
748
|
0
|
|
|
|
|
|
dstPtr += LZ4F_makeBlock(dstPtr, cctxPtr->tmpIn, blockSize, |
749
|
|
|
|
|
|
|
compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, |
750
|
|
|
|
|
|
|
cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag); |
751
|
|
|
|
|
|
|
|
752
|
0
|
0
|
|
|
|
|
if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += blockSize; |
753
|
0
|
|
|
|
|
|
cctxPtr->tmpInSize = 0; |
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
} |
756
|
|
|
|
|
|
|
|
757
|
13
|
100
|
|
|
|
|
while ((size_t)(srcEnd - srcPtr) >= blockSize) { |
758
|
|
|
|
|
|
|
/* compress full blocks */ |
759
|
12
|
|
|
|
|
|
lastBlockCompressed = fromSrcBuffer; |
760
|
12
|
|
|
|
|
|
dstPtr += LZ4F_makeBlock(dstPtr, srcPtr, blockSize, |
761
|
|
|
|
|
|
|
compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, |
762
|
|
|
|
|
|
|
cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag); |
763
|
12
|
|
|
|
|
|
srcPtr += blockSize; |
764
|
|
|
|
|
|
|
} |
765
|
|
|
|
|
|
|
|
766
|
1
|
50
|
|
|
|
|
if ((cctxPtr->prefs.autoFlush) && (srcPtr < srcEnd)) { |
|
|
50
|
|
|
|
|
|
767
|
|
|
|
|
|
|
/* compress remaining input < blockSize */ |
768
|
1
|
|
|
|
|
|
lastBlockCompressed = fromSrcBuffer; |
769
|
1
|
|
|
|
|
|
dstPtr += LZ4F_makeBlock(dstPtr, srcPtr, srcEnd - srcPtr, |
770
|
|
|
|
|
|
|
compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, |
771
|
|
|
|
|
|
|
cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag); |
772
|
1
|
|
|
|
|
|
srcPtr = srcEnd; |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
/* preserve dictionary if necessary */ |
776
|
1
|
50
|
|
|
|
|
if ((cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) && (lastBlockCompressed==fromSrcBuffer)) { |
|
|
50
|
|
|
|
|
|
777
|
1
|
50
|
|
|
|
|
if (compressOptionsPtr->stableSrc) { |
778
|
1
|
|
|
|
|
|
cctxPtr->tmpIn = cctxPtr->tmpBuff; |
779
|
|
|
|
|
|
|
} else { |
780
|
0
|
|
|
|
|
|
int const realDictSize = LZ4F_localSaveDict(cctxPtr); |
781
|
0
|
0
|
|
|
|
|
if (realDictSize==0) return err0r(LZ4F_ERROR_GENERIC); |
782
|
0
|
|
|
|
|
|
cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
} |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
/* keep tmpIn within limits */ |
787
|
1
|
50
|
|
|
|
|
if ((cctxPtr->tmpIn + blockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize) /* necessarily LZ4F_blockLinked && lastBlockCompressed==fromTmpBuffer */ |
788
|
0
|
0
|
|
|
|
|
&& !(cctxPtr->prefs.autoFlush)) |
789
|
|
|
|
|
|
|
{ |
790
|
0
|
|
|
|
|
|
int const realDictSize = LZ4F_localSaveDict(cctxPtr); |
791
|
0
|
|
|
|
|
|
cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; |
792
|
|
|
|
|
|
|
} |
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
/* some input data left, necessarily < blockSize */ |
795
|
1
|
50
|
|
|
|
|
if (srcPtr < srcEnd) { |
796
|
|
|
|
|
|
|
/* fill tmp buffer */ |
797
|
0
|
|
|
|
|
|
size_t const sizeToCopy = srcEnd - srcPtr; |
798
|
0
|
|
|
|
|
|
memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy); |
799
|
0
|
|
|
|
|
|
cctxPtr->tmpInSize = sizeToCopy; |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
|
802
|
1
|
50
|
|
|
|
|
if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) |
803
|
0
|
|
|
|
|
|
XXH32_update(&(cctxPtr->xxh), srcBuffer, srcSize); |
804
|
|
|
|
|
|
|
|
805
|
1
|
|
|
|
|
|
cctxPtr->totalInSize += srcSize; |
806
|
1
|
|
|
|
|
|
return dstPtr - dstStart; |
807
|
|
|
|
|
|
|
} |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
/*! LZ4F_flush() : |
811
|
|
|
|
|
|
|
* Should you need to create compressed data immediately, without waiting for a block to be filled, |
812
|
|
|
|
|
|
|
* you can call LZ4_flush(), which will immediately compress any remaining data stored within compressionContext. |
813
|
|
|
|
|
|
|
* The result of the function is the number of bytes written into dstBuffer |
814
|
|
|
|
|
|
|
* (it can be zero, this means there was no data left within compressionContext) |
815
|
|
|
|
|
|
|
* The function outputs an error code if it fails (can be tested using LZ4F_isError()) |
816
|
|
|
|
|
|
|
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument. |
817
|
|
|
|
|
|
|
*/ |
818
|
1
|
|
|
|
|
|
size_t LZ4F_flush(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* compressOptionsPtr) |
819
|
|
|
|
|
|
|
{ |
820
|
1
|
|
|
|
|
|
BYTE* const dstStart = (BYTE*)dstBuffer; |
821
|
1
|
|
|
|
|
|
BYTE* dstPtr = dstStart; |
822
|
|
|
|
|
|
|
compressFunc_t compress; |
823
|
|
|
|
|
|
|
|
824
|
1
|
50
|
|
|
|
|
if (cctxPtr->tmpInSize == 0) return 0; /* nothing to flush */ |
825
|
0
|
0
|
|
|
|
|
if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC); |
826
|
0
|
0
|
|
|
|
|
if (dstCapacity < (cctxPtr->tmpInSize + 4)) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); /* +4 : block header(4) */ |
827
|
|
|
|
|
|
|
(void)compressOptionsPtr; /* not yet useful */ |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
/* select compression function */ |
830
|
0
|
|
|
|
|
|
compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel); |
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
/* compress tmp buffer */ |
833
|
0
|
|
|
|
|
|
dstPtr += LZ4F_makeBlock(dstPtr, cctxPtr->tmpIn, cctxPtr->tmpInSize, |
834
|
|
|
|
|
|
|
compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, |
835
|
|
|
|
|
|
|
cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag); |
836
|
0
|
0
|
|
|
|
|
if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += cctxPtr->tmpInSize; |
837
|
0
|
|
|
|
|
|
cctxPtr->tmpInSize = 0; |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
/* keep tmpIn within limits */ |
840
|
0
|
0
|
|
|
|
|
if ((cctxPtr->tmpIn + cctxPtr->maxBlockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)) { /* necessarily LZ4F_blockLinked */ |
841
|
0
|
|
|
|
|
|
int realDictSize = LZ4F_localSaveDict(cctxPtr); |
842
|
0
|
|
|
|
|
|
cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; |
843
|
|
|
|
|
|
|
} |
844
|
|
|
|
|
|
|
|
845
|
0
|
|
|
|
|
|
return dstPtr - dstStart; |
846
|
|
|
|
|
|
|
} |
847
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
/*! LZ4F_compressEnd() : |
850
|
|
|
|
|
|
|
* When you want to properly finish the compressed frame, just call LZ4F_compressEnd(). |
851
|
|
|
|
|
|
|
* It will flush whatever data remained within compressionContext (like LZ4_flush()) |
852
|
|
|
|
|
|
|
* but also properly finalize the frame, with an endMark and a checksum. |
853
|
|
|
|
|
|
|
* The result of the function is the number of bytes written into dstBuffer (necessarily >= 4 (endMark size)) |
854
|
|
|
|
|
|
|
* The function outputs an error code if it fails (can be tested using LZ4F_isError()) |
855
|
|
|
|
|
|
|
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument. |
856
|
|
|
|
|
|
|
* compressionContext can then be used again, starting with LZ4F_compressBegin(). The preferences will remain the same. |
857
|
|
|
|
|
|
|
*/ |
858
|
1
|
|
|
|
|
|
size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr) |
859
|
|
|
|
|
|
|
{ |
860
|
1
|
|
|
|
|
|
BYTE* const dstStart = (BYTE*)dstBuffer; |
861
|
1
|
|
|
|
|
|
BYTE* dstPtr = dstStart; |
862
|
|
|
|
|
|
|
|
863
|
1
|
|
|
|
|
|
size_t const flushSize = LZ4F_flush(cctxPtr, dstBuffer, dstMaxSize, compressOptionsPtr); |
864
|
1
|
50
|
|
|
|
|
if (LZ4F_isError(flushSize)) return flushSize; |
865
|
1
|
|
|
|
|
|
dstPtr += flushSize; |
866
|
|
|
|
|
|
|
|
867
|
1
|
|
|
|
|
|
LZ4F_writeLE32(dstPtr, 0); |
868
|
1
|
|
|
|
|
|
dstPtr+=4; /* endMark */ |
869
|
|
|
|
|
|
|
|
870
|
1
|
50
|
|
|
|
|
if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) { |
871
|
0
|
|
|
|
|
|
U32 const xxh = XXH32_digest(&(cctxPtr->xxh)); |
872
|
0
|
|
|
|
|
|
LZ4F_writeLE32(dstPtr, xxh); |
873
|
0
|
|
|
|
|
|
dstPtr+=4; /* content Checksum */ |
874
|
|
|
|
|
|
|
} |
875
|
|
|
|
|
|
|
|
876
|
1
|
|
|
|
|
|
cctxPtr->cStage = 0; /* state is now re-usable (with identical preferences) */ |
877
|
1
|
|
|
|
|
|
cctxPtr->maxBufferSize = 0; /* reuse HC context */ |
878
|
|
|
|
|
|
|
|
879
|
1
|
50
|
|
|
|
|
if (cctxPtr->prefs.frameInfo.contentSize) { |
880
|
1
|
50
|
|
|
|
|
if (cctxPtr->prefs.frameInfo.contentSize != cctxPtr->totalInSize) |
881
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_frameSize_wrong); |
882
|
|
|
|
|
|
|
} |
883
|
|
|
|
|
|
|
|
884
|
1
|
|
|
|
|
|
return dstPtr - dstStart; |
885
|
|
|
|
|
|
|
} |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
/*-*************************************************** |
889
|
|
|
|
|
|
|
* Frame Decompression |
890
|
|
|
|
|
|
|
*****************************************************/ |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
typedef enum { |
893
|
|
|
|
|
|
|
dstage_getFrameHeader=0, dstage_storeFrameHeader, |
894
|
|
|
|
|
|
|
dstage_init, |
895
|
|
|
|
|
|
|
dstage_getBlockHeader, dstage_storeBlockHeader, |
896
|
|
|
|
|
|
|
dstage_copyDirect, dstage_getBlockChecksum, |
897
|
|
|
|
|
|
|
dstage_getCBlock, dstage_storeCBlock, |
898
|
|
|
|
|
|
|
dstage_flushOut, |
899
|
|
|
|
|
|
|
dstage_getSuffix, dstage_storeSuffix, |
900
|
|
|
|
|
|
|
dstage_getSFrameSize, dstage_storeSFrameSize, |
901
|
|
|
|
|
|
|
dstage_skipSkippable |
902
|
|
|
|
|
|
|
} dStage_t; |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
struct LZ4F_dctx_s { |
905
|
|
|
|
|
|
|
LZ4F_frameInfo_t frameInfo; |
906
|
|
|
|
|
|
|
U32 version; |
907
|
|
|
|
|
|
|
dStage_t dStage; |
908
|
|
|
|
|
|
|
U64 frameRemainingSize; |
909
|
|
|
|
|
|
|
size_t maxBlockSize; |
910
|
|
|
|
|
|
|
size_t maxBufferSize; |
911
|
|
|
|
|
|
|
BYTE* tmpIn; |
912
|
|
|
|
|
|
|
size_t tmpInSize; |
913
|
|
|
|
|
|
|
size_t tmpInTarget; |
914
|
|
|
|
|
|
|
BYTE* tmpOutBuffer; |
915
|
|
|
|
|
|
|
const BYTE* dict; |
916
|
|
|
|
|
|
|
size_t dictSize; |
917
|
|
|
|
|
|
|
BYTE* tmpOut; |
918
|
|
|
|
|
|
|
size_t tmpOutSize; |
919
|
|
|
|
|
|
|
size_t tmpOutStart; |
920
|
|
|
|
|
|
|
XXH32_state_t xxh; |
921
|
|
|
|
|
|
|
XXH32_state_t blockChecksum; |
922
|
|
|
|
|
|
|
BYTE header[LZ4F_HEADER_SIZE_MAX]; |
923
|
|
|
|
|
|
|
}; /* typedef'd to LZ4F_dctx in lz4frame.h */ |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
/*! LZ4F_createDecompressionContext() : |
927
|
|
|
|
|
|
|
* Create a decompressionContext object, which will track all decompression operations. |
928
|
|
|
|
|
|
|
* Provides a pointer to a fully allocated and initialized LZ4F_decompressionContext object. |
929
|
|
|
|
|
|
|
* Object can later be released using LZ4F_freeDecompressionContext(). |
930
|
|
|
|
|
|
|
* @return : if != 0, there was an error during context creation. |
931
|
|
|
|
|
|
|
*/ |
932
|
8
|
|
|
|
|
|
LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber) |
933
|
|
|
|
|
|
|
{ |
934
|
8
|
|
|
|
|
|
LZ4F_dctx* const dctx = (LZ4F_dctx*)ALLOCATOR(sizeof(LZ4F_dctx)); |
935
|
8
|
50
|
|
|
|
|
if (dctx==NULL) return err0r(LZ4F_ERROR_GENERIC); |
936
|
|
|
|
|
|
|
|
937
|
8
|
|
|
|
|
|
dctx->version = versionNumber; |
938
|
8
|
|
|
|
|
|
*LZ4F_decompressionContextPtr = dctx; |
939
|
8
|
|
|
|
|
|
return LZ4F_OK_NoError; |
940
|
|
|
|
|
|
|
} |
941
|
|
|
|
|
|
|
|
942
|
8
|
|
|
|
|
|
LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx) |
943
|
|
|
|
|
|
|
{ |
944
|
8
|
|
|
|
|
|
LZ4F_errorCode_t result = LZ4F_OK_NoError; |
945
|
8
|
50
|
|
|
|
|
if (dctx != NULL) { /* can accept NULL input, like free() */ |
946
|
8
|
|
|
|
|
|
result = (LZ4F_errorCode_t)dctx->dStage; |
947
|
8
|
|
|
|
|
|
FREEMEM(dctx->tmpIn); |
948
|
8
|
|
|
|
|
|
FREEMEM(dctx->tmpOutBuffer); |
949
|
8
|
|
|
|
|
|
FREEMEM(dctx); |
950
|
|
|
|
|
|
|
} |
951
|
8
|
|
|
|
|
|
return result; |
952
|
|
|
|
|
|
|
} |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
/*==--- Streaming Decompression operations ---==*/ |
956
|
|
|
|
|
|
|
|
957
|
5
|
|
|
|
|
|
void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx) |
958
|
|
|
|
|
|
|
{ |
959
|
5
|
|
|
|
|
|
dctx->dStage = dstage_getFrameHeader; |
960
|
5
|
|
|
|
|
|
dctx->dict = NULL; |
961
|
5
|
|
|
|
|
|
dctx->dictSize = 0; |
962
|
5
|
|
|
|
|
|
} |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
/*! LZ4F_headerSize() : |
966
|
|
|
|
|
|
|
* @return : size of frame header |
967
|
|
|
|
|
|
|
* or an error code, which can be tested using LZ4F_isError() |
968
|
|
|
|
|
|
|
*/ |
969
|
8
|
|
|
|
|
|
static size_t LZ4F_headerSize(const void* src, size_t srcSize) |
970
|
|
|
|
|
|
|
{ |
971
|
|
|
|
|
|
|
/* minimal srcSize to determine header size */ |
972
|
8
|
50
|
|
|
|
|
if (srcSize < 5) return err0r(LZ4F_ERROR_frameHeader_incomplete); |
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
/* special case : skippable frames */ |
975
|
8
|
50
|
|
|
|
|
if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) return 8; |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
/* control magic number */ |
978
|
8
|
100
|
|
|
|
|
if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER) |
979
|
1
|
|
|
|
|
|
return err0r(LZ4F_ERROR_frameType_unknown); |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
/* Frame Header Size */ |
982
|
7
|
|
|
|
|
|
{ BYTE const FLG = ((const BYTE*)src)[4]; |
983
|
7
|
|
|
|
|
|
U32 const contentSizeFlag = (FLG>>3) & _1BIT; |
984
|
7
|
|
|
|
|
|
U32 const dictIDFlag = FLG & _1BIT; |
985
|
7
|
|
|
|
|
|
return minFHSize + (contentSizeFlag*8) + (dictIDFlag*4); |
986
|
|
|
|
|
|
|
} |
987
|
|
|
|
|
|
|
} |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
/*! LZ4F_decodeHeader() : |
991
|
|
|
|
|
|
|
* input : `src` points at the **beginning of the frame** |
992
|
|
|
|
|
|
|
* output : set internal values of dctx, such as |
993
|
|
|
|
|
|
|
* dctx->frameInfo and dctx->dStage. |
994
|
|
|
|
|
|
|
* Also allocates internal buffers. |
995
|
|
|
|
|
|
|
* @return : nb Bytes read from src (necessarily <= srcSize) |
996
|
|
|
|
|
|
|
* or an error code (testable with LZ4F_isError()) |
997
|
|
|
|
|
|
|
*/ |
998
|
7
|
|
|
|
|
|
static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize) |
999
|
|
|
|
|
|
|
{ |
1000
|
|
|
|
|
|
|
unsigned blockMode, blockChecksumFlag, contentSizeFlag, contentChecksumFlag, dictIDFlag, blockSizeID; |
1001
|
|
|
|
|
|
|
size_t frameHeaderSize; |
1002
|
7
|
|
|
|
|
|
const BYTE* srcPtr = (const BYTE*)src; |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
/* need to decode header to get frameInfo */ |
1005
|
7
|
50
|
|
|
|
|
if (srcSize < minFHSize) return err0r(LZ4F_ERROR_frameHeader_incomplete); /* minimal frame header size */ |
1006
|
7
|
|
|
|
|
|
memset(&(dctx->frameInfo), 0, sizeof(dctx->frameInfo)); |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
/* special case : skippable frames */ |
1009
|
7
|
50
|
|
|
|
|
if ((LZ4F_readLE32(srcPtr) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) { |
1010
|
0
|
|
|
|
|
|
dctx->frameInfo.frameType = LZ4F_skippableFrame; |
1011
|
0
|
0
|
|
|
|
|
if (src == (void*)(dctx->header)) { |
1012
|
0
|
|
|
|
|
|
dctx->tmpInSize = srcSize; |
1013
|
0
|
|
|
|
|
|
dctx->tmpInTarget = 8; |
1014
|
0
|
|
|
|
|
|
dctx->dStage = dstage_storeSFrameSize; |
1015
|
0
|
|
|
|
|
|
return srcSize; |
1016
|
|
|
|
|
|
|
} else { |
1017
|
0
|
|
|
|
|
|
dctx->dStage = dstage_getSFrameSize; |
1018
|
0
|
|
|
|
|
|
return 4; |
1019
|
|
|
|
|
|
|
} |
1020
|
|
|
|
|
|
|
} |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
/* control magic number */ |
1023
|
7
|
50
|
|
|
|
|
if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) |
1024
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_frameType_unknown); |
1025
|
7
|
|
|
|
|
|
dctx->frameInfo.frameType = LZ4F_frame; |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
/* Flags */ |
1028
|
7
|
|
|
|
|
|
{ U32 const FLG = srcPtr[4]; |
1029
|
7
|
|
|
|
|
|
U32 const version = (FLG>>6) & _2BITS; |
1030
|
7
|
|
|
|
|
|
blockChecksumFlag = (FLG>>4) & _1BIT; |
1031
|
7
|
|
|
|
|
|
blockMode = (FLG>>5) & _1BIT; |
1032
|
7
|
|
|
|
|
|
contentSizeFlag = (FLG>>3) & _1BIT; |
1033
|
7
|
|
|
|
|
|
contentChecksumFlag = (FLG>>2) & _1BIT; |
1034
|
7
|
|
|
|
|
|
dictIDFlag = FLG & _1BIT; |
1035
|
|
|
|
|
|
|
/* validate */ |
1036
|
7
|
50
|
|
|
|
|
if (((FLG>>1)&_1BIT) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bit */ |
1037
|
7
|
50
|
|
|
|
|
if (version != 1) return err0r(LZ4F_ERROR_headerVersion_wrong); /* Version Number, only supported value */ |
1038
|
|
|
|
|
|
|
} |
1039
|
|
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
/* Frame Header Size */ |
1041
|
7
|
|
|
|
|
|
frameHeaderSize = minFHSize + (contentSizeFlag*8) + (dictIDFlag*4); |
1042
|
|
|
|
|
|
|
|
1043
|
7
|
50
|
|
|
|
|
if (srcSize < frameHeaderSize) { |
1044
|
|
|
|
|
|
|
/* not enough input to fully decode frame header */ |
1045
|
0
|
0
|
|
|
|
|
if (srcPtr != dctx->header) |
1046
|
0
|
|
|
|
|
|
memcpy(dctx->header, srcPtr, srcSize); |
1047
|
0
|
|
|
|
|
|
dctx->tmpInSize = srcSize; |
1048
|
0
|
|
|
|
|
|
dctx->tmpInTarget = frameHeaderSize; |
1049
|
0
|
|
|
|
|
|
dctx->dStage = dstage_storeFrameHeader; |
1050
|
0
|
|
|
|
|
|
return srcSize; |
1051
|
|
|
|
|
|
|
} |
1052
|
|
|
|
|
|
|
|
1053
|
7
|
|
|
|
|
|
{ U32 const BD = srcPtr[5]; |
1054
|
7
|
|
|
|
|
|
blockSizeID = (BD>>4) & _3BITS; |
1055
|
|
|
|
|
|
|
/* validate */ |
1056
|
7
|
50
|
|
|
|
|
if (((BD>>7)&_1BIT) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bit */ |
1057
|
7
|
50
|
|
|
|
|
if (blockSizeID < 4) return err0r(LZ4F_ERROR_maxBlockSize_invalid); /* 4-7 only supported values for the time being */ |
1058
|
7
|
50
|
|
|
|
|
if (((BD>>0)&_4BITS) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bits */ |
1059
|
|
|
|
|
|
|
} |
1060
|
|
|
|
|
|
|
|
1061
|
|
|
|
|
|
|
/* check header */ |
1062
|
7
|
|
|
|
|
|
{ BYTE const HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5); |
1063
|
7
|
50
|
|
|
|
|
if (HC != srcPtr[frameHeaderSize-1]) |
1064
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_headerChecksum_invalid); |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
/* save */ |
1068
|
7
|
|
|
|
|
|
dctx->frameInfo.blockMode = (LZ4F_blockMode_t)blockMode; |
1069
|
7
|
|
|
|
|
|
dctx->frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)blockChecksumFlag; |
1070
|
7
|
|
|
|
|
|
dctx->frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)contentChecksumFlag; |
1071
|
7
|
|
|
|
|
|
dctx->frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID; |
1072
|
7
|
|
|
|
|
|
dctx->maxBlockSize = LZ4F_getBlockSize(blockSizeID); |
1073
|
7
|
100
|
|
|
|
|
if (contentSizeFlag) |
1074
|
4
|
|
|
|
|
|
dctx->frameRemainingSize = |
1075
|
4
|
|
|
|
|
|
dctx->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6); |
1076
|
7
|
50
|
|
|
|
|
if (dictIDFlag) |
1077
|
0
|
|
|
|
|
|
dctx->frameInfo.dictID = LZ4F_readLE32(srcPtr + frameHeaderSize - 5); |
1078
|
|
|
|
|
|
|
|
1079
|
7
|
|
|
|
|
|
dctx->dStage = dstage_init; |
1080
|
|
|
|
|
|
|
|
1081
|
7
|
|
|
|
|
|
return frameHeaderSize; |
1082
|
|
|
|
|
|
|
} |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
/*! LZ4F_getFrameInfo() : |
1086
|
|
|
|
|
|
|
* This function extracts frame parameters (max blockSize, frame checksum, etc.). |
1087
|
|
|
|
|
|
|
* Usage is optional. Objective is to provide relevant information for allocation purposes. |
1088
|
|
|
|
|
|
|
* This function works in 2 situations : |
1089
|
|
|
|
|
|
|
* - At the beginning of a new frame, in which case it will decode this information from `srcBuffer`, and start the decoding process. |
1090
|
|
|
|
|
|
|
* Amount of input data provided must be large enough to successfully decode the frame header. |
1091
|
|
|
|
|
|
|
* A header size is variable, but is guaranteed to be <= LZ4F_HEADER_SIZE_MAX bytes. It's possible to provide more input data than this minimum. |
1092
|
|
|
|
|
|
|
* - After decoding has been started. In which case, no input is read, frame parameters are extracted from dctx. |
1093
|
|
|
|
|
|
|
* The number of bytes consumed from srcBuffer will be updated within *srcSizePtr (necessarily <= original value). |
1094
|
|
|
|
|
|
|
* Decompression must resume from (srcBuffer + *srcSizePtr). |
1095
|
|
|
|
|
|
|
* @return : an hint about how many srcSize bytes LZ4F_decompress() expects for next call, |
1096
|
|
|
|
|
|
|
* or an error code which can be tested using LZ4F_isError() |
1097
|
|
|
|
|
|
|
* note 1 : in case of error, dctx is not modified. Decoding operations can resume from where they stopped. |
1098
|
|
|
|
|
|
|
* note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure. |
1099
|
|
|
|
|
|
|
*/ |
1100
|
8
|
|
|
|
|
|
LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, LZ4F_frameInfo_t* frameInfoPtr, |
1101
|
|
|
|
|
|
|
const void* srcBuffer, size_t* srcSizePtr) |
1102
|
|
|
|
|
|
|
{ |
1103
|
8
|
50
|
|
|
|
|
if (dctx->dStage > dstage_storeFrameHeader) { /* assumption : dstage_* header enum at beginning of range */ |
1104
|
|
|
|
|
|
|
/* frameInfo already decoded */ |
1105
|
0
|
|
|
|
|
|
size_t o=0, i=0; |
1106
|
0
|
|
|
|
|
|
*srcSizePtr = 0; |
1107
|
0
|
|
|
|
|
|
*frameInfoPtr = dctx->frameInfo; |
1108
|
|
|
|
|
|
|
/* returns : recommended nb of bytes for LZ4F_decompress() */ |
1109
|
0
|
|
|
|
|
|
return LZ4F_decompress(dctx, NULL, &o, NULL, &i, NULL); |
1110
|
|
|
|
|
|
|
} else { |
1111
|
8
|
50
|
|
|
|
|
if (dctx->dStage == dstage_storeFrameHeader) { |
1112
|
|
|
|
|
|
|
/* frame decoding already started, in the middle of header => automatic fail */ |
1113
|
0
|
|
|
|
|
|
*srcSizePtr = 0; |
1114
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_frameDecoding_alreadyStarted); |
1115
|
|
|
|
|
|
|
} else { |
1116
|
|
|
|
|
|
|
size_t decodeResult; |
1117
|
8
|
|
|
|
|
|
size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr); |
1118
|
8
|
100
|
|
|
|
|
if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; } |
1119
|
7
|
50
|
|
|
|
|
if (*srcSizePtr < hSize) { |
1120
|
0
|
|
|
|
|
|
*srcSizePtr=0; |
1121
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_frameHeader_incomplete); |
1122
|
|
|
|
|
|
|
} |
1123
|
|
|
|
|
|
|
|
1124
|
7
|
|
|
|
|
|
decodeResult = LZ4F_decodeHeader(dctx, srcBuffer, hSize); |
1125
|
7
|
50
|
|
|
|
|
if (LZ4F_isError(decodeResult)) { |
1126
|
0
|
|
|
|
|
|
*srcSizePtr = 0; |
1127
|
|
|
|
|
|
|
} else { |
1128
|
7
|
|
|
|
|
|
*srcSizePtr = decodeResult; |
1129
|
7
|
|
|
|
|
|
decodeResult = BHSize; /* block header size */ |
1130
|
|
|
|
|
|
|
} |
1131
|
7
|
|
|
|
|
|
*frameInfoPtr = dctx->frameInfo; |
1132
|
7
|
|
|
|
|
|
return decodeResult; |
1133
|
|
|
|
|
|
|
} } |
1134
|
|
|
|
|
|
|
} |
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
/* LZ4F_updateDict() : |
1138
|
|
|
|
|
|
|
* only used for LZ4F_blockLinked mode */ |
1139
|
39
|
|
|
|
|
|
static void LZ4F_updateDict(LZ4F_dctx* dctx, const BYTE* dstPtr, size_t dstSize, const BYTE* dstPtr0, unsigned withinTmp) |
1140
|
|
|
|
|
|
|
{ |
1141
|
39
|
100
|
|
|
|
|
if (dctx->dictSize==0) |
1142
|
3
|
|
|
|
|
|
dctx->dict = (const BYTE*)dstPtr; /* priority to dictionary continuity */ |
1143
|
|
|
|
|
|
|
|
1144
|
39
|
50
|
|
|
|
|
if (dctx->dict + dctx->dictSize == dstPtr) { /* dictionary continuity */ |
1145
|
39
|
|
|
|
|
|
dctx->dictSize += dstSize; |
1146
|
39
|
|
|
|
|
|
return; |
1147
|
|
|
|
|
|
|
} |
1148
|
|
|
|
|
|
|
|
1149
|
0
|
0
|
|
|
|
|
if (dstPtr - dstPtr0 + dstSize >= 64 KB) { /* dstBuffer large enough to become dictionary */ |
1150
|
0
|
|
|
|
|
|
dctx->dict = (const BYTE*)dstPtr0; |
1151
|
0
|
|
|
|
|
|
dctx->dictSize = dstPtr - dstPtr0 + dstSize; |
1152
|
0
|
|
|
|
|
|
return; |
1153
|
|
|
|
|
|
|
} |
1154
|
|
|
|
|
|
|
|
1155
|
0
|
0
|
|
|
|
|
if ((withinTmp) && (dctx->dict == dctx->tmpOutBuffer)) { |
|
|
0
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
/* assumption : dctx->dict + dctx->dictSize == dctx->tmpOut + dctx->tmpOutStart */ |
1157
|
0
|
|
|
|
|
|
dctx->dictSize += dstSize; |
1158
|
0
|
|
|
|
|
|
return; |
1159
|
|
|
|
|
|
|
} |
1160
|
|
|
|
|
|
|
|
1161
|
0
|
0
|
|
|
|
|
if (withinTmp) { /* copy relevant dict portion in front of tmpOut within tmpOutBuffer */ |
1162
|
0
|
|
|
|
|
|
size_t const preserveSize = dctx->tmpOut - dctx->tmpOutBuffer; |
1163
|
0
|
|
|
|
|
|
size_t copySize = 64 KB - dctx->tmpOutSize; |
1164
|
0
|
|
|
|
|
|
const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart; |
1165
|
0
|
0
|
|
|
|
|
if (dctx->tmpOutSize > 64 KB) copySize = 0; |
1166
|
0
|
0
|
|
|
|
|
if (copySize > preserveSize) copySize = preserveSize; |
1167
|
|
|
|
|
|
|
|
1168
|
0
|
|
|
|
|
|
memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize); |
1169
|
|
|
|
|
|
|
|
1170
|
0
|
|
|
|
|
|
dctx->dict = dctx->tmpOutBuffer; |
1171
|
0
|
|
|
|
|
|
dctx->dictSize = preserveSize + dctx->tmpOutStart + dstSize; |
1172
|
0
|
|
|
|
|
|
return; |
1173
|
|
|
|
|
|
|
} |
1174
|
|
|
|
|
|
|
|
1175
|
0
|
0
|
|
|
|
|
if (dctx->dict == dctx->tmpOutBuffer) { /* copy dst into tmp to complete dict */ |
1176
|
0
|
0
|
|
|
|
|
if (dctx->dictSize + dstSize > dctx->maxBufferSize) { /* tmp buffer not large enough */ |
1177
|
0
|
|
|
|
|
|
size_t const preserveSize = 64 KB - dstSize; /* note : dstSize < 64 KB */ |
1178
|
0
|
|
|
|
|
|
memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - preserveSize, preserveSize); |
1179
|
0
|
|
|
|
|
|
dctx->dictSize = preserveSize; |
1180
|
|
|
|
|
|
|
} |
1181
|
0
|
|
|
|
|
|
memcpy(dctx->tmpOutBuffer + dctx->dictSize, dstPtr, dstSize); |
1182
|
0
|
|
|
|
|
|
dctx->dictSize += dstSize; |
1183
|
0
|
|
|
|
|
|
return; |
1184
|
|
|
|
|
|
|
} |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
/* join dict & dest into tmp */ |
1187
|
0
|
|
|
|
|
|
{ size_t preserveSize = 64 KB - dstSize; /* note : dstSize < 64 KB */ |
1188
|
0
|
0
|
|
|
|
|
if (preserveSize > dctx->dictSize) preserveSize = dctx->dictSize; |
1189
|
0
|
|
|
|
|
|
memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - preserveSize, preserveSize); |
1190
|
0
|
|
|
|
|
|
memcpy(dctx->tmpOutBuffer + preserveSize, dstPtr, dstSize); |
1191
|
0
|
|
|
|
|
|
dctx->dict = dctx->tmpOutBuffer; |
1192
|
0
|
|
|
|
|
|
dctx->dictSize = preserveSize + dstSize; |
1193
|
|
|
|
|
|
|
} |
1194
|
|
|
|
|
|
|
} |
1195
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
/*! LZ4F_decompress() : |
1199
|
|
|
|
|
|
|
* Call this function repetitively to regenerate compressed data in srcBuffer. |
1200
|
|
|
|
|
|
|
* The function will attempt to decode up to *srcSizePtr bytes from srcBuffer |
1201
|
|
|
|
|
|
|
* into dstBuffer of capacity *dstSizePtr. |
1202
|
|
|
|
|
|
|
* |
1203
|
|
|
|
|
|
|
* The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value). |
1204
|
|
|
|
|
|
|
* |
1205
|
|
|
|
|
|
|
* The number of bytes effectively read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value). |
1206
|
|
|
|
|
|
|
* If number of bytes read is < number of bytes provided, then decompression operation is not complete. |
1207
|
|
|
|
|
|
|
* Remaining data will have to be presented again in a subsequent invocation. |
1208
|
|
|
|
|
|
|
* |
1209
|
|
|
|
|
|
|
* The function result is an hint of the better srcSize to use for next call to LZ4F_decompress. |
1210
|
|
|
|
|
|
|
* Schematically, it's the size of the current (or remaining) compressed block + header of next block. |
1211
|
|
|
|
|
|
|
* Respecting the hint provides a small boost to performance, since it allows less buffer shuffling. |
1212
|
|
|
|
|
|
|
* Note that this is just a hint, and it's always possible to any srcSize value. |
1213
|
|
|
|
|
|
|
* When a frame is fully decoded, @return will be 0. |
1214
|
|
|
|
|
|
|
* If decompression failed, @return is an error code which can be tested using LZ4F_isError(). |
1215
|
|
|
|
|
|
|
*/ |
1216
|
520
|
|
|
|
|
|
size_t LZ4F_decompress(LZ4F_dctx* dctx, |
1217
|
|
|
|
|
|
|
void* dstBuffer, size_t* dstSizePtr, |
1218
|
|
|
|
|
|
|
const void* srcBuffer, size_t* srcSizePtr, |
1219
|
|
|
|
|
|
|
const LZ4F_decompressOptions_t* decompressOptionsPtr) |
1220
|
|
|
|
|
|
|
{ |
1221
|
|
|
|
|
|
|
LZ4F_decompressOptions_t optionsNull; |
1222
|
520
|
|
|
|
|
|
const BYTE* const srcStart = (const BYTE*)srcBuffer; |
1223
|
520
|
|
|
|
|
|
const BYTE* const srcEnd = srcStart + *srcSizePtr; |
1224
|
520
|
|
|
|
|
|
const BYTE* srcPtr = srcStart; |
1225
|
520
|
|
|
|
|
|
BYTE* const dstStart = (BYTE*)dstBuffer; |
1226
|
520
|
|
|
|
|
|
BYTE* const dstEnd = dstStart + *dstSizePtr; |
1227
|
520
|
|
|
|
|
|
BYTE* dstPtr = dstStart; |
1228
|
520
|
|
|
|
|
|
const BYTE* selectedIn = NULL; |
1229
|
520
|
|
|
|
|
|
unsigned doAnotherStage = 1; |
1230
|
520
|
|
|
|
|
|
size_t nextSrcSizeHint = 1; |
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
|
1233
|
520
|
|
|
|
|
|
memset(&optionsNull, 0, sizeof(optionsNull)); |
1234
|
520
|
50
|
|
|
|
|
if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull; |
1235
|
520
|
|
|
|
|
|
*srcSizePtr = 0; |
1236
|
520
|
|
|
|
|
|
*dstSizePtr = 0; |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
/* behaves as a state machine */ |
1239
|
|
|
|
|
|
|
|
1240
|
1130
|
100
|
|
|
|
|
while (doAnotherStage) { |
1241
|
|
|
|
|
|
|
|
1242
|
610
|
|
|
|
|
|
switch(dctx->dStage) |
1243
|
|
|
|
|
|
|
{ |
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
case dstage_getFrameHeader: |
1246
|
0
|
0
|
|
|
|
|
if ((size_t)(srcEnd-srcPtr) >= maxFHSize) { /* enough to decode - shortcut */ |
1247
|
0
|
|
|
|
|
|
size_t const hSize = LZ4F_decodeHeader(dctx, srcPtr, srcEnd-srcPtr); /* will update dStage appropriately */ |
1248
|
0
|
0
|
|
|
|
|
if (LZ4F_isError(hSize)) return hSize; |
1249
|
0
|
|
|
|
|
|
srcPtr += hSize; |
1250
|
0
|
|
|
|
|
|
break; |
1251
|
|
|
|
|
|
|
} |
1252
|
0
|
|
|
|
|
|
dctx->tmpInSize = 0; |
1253
|
0
|
0
|
|
|
|
|
if (srcEnd-srcPtr == 0) return minFHSize; /* 0-size input */ |
1254
|
0
|
|
|
|
|
|
dctx->tmpInTarget = minFHSize; /* minimum to attempt decode */ |
1255
|
0
|
|
|
|
|
|
dctx->dStage = dstage_storeFrameHeader; |
1256
|
|
|
|
|
|
|
/* fall-through */ |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
case dstage_storeFrameHeader: |
1259
|
0
|
|
|
|
|
|
{ size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize, (size_t)(srcEnd - srcPtr)); |
1260
|
0
|
|
|
|
|
|
memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy); |
1261
|
0
|
|
|
|
|
|
dctx->tmpInSize += sizeToCopy; |
1262
|
0
|
|
|
|
|
|
srcPtr += sizeToCopy; |
1263
|
|
|
|
|
|
|
} |
1264
|
0
|
0
|
|
|
|
|
if (dctx->tmpInSize < dctx->tmpInTarget) { |
1265
|
0
|
|
|
|
|
|
nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize) + BHSize; /* rest of header + nextBlockHeader */ |
1266
|
0
|
|
|
|
|
|
doAnotherStage = 0; /* not enough src data, ask for some more */ |
1267
|
0
|
|
|
|
|
|
break; |
1268
|
|
|
|
|
|
|
} |
1269
|
0
|
|
|
|
|
|
{ size_t const hSize = LZ4F_decodeHeader(dctx, dctx->header, dctx->tmpInTarget); /* will update dStage appropriately */ |
1270
|
0
|
0
|
|
|
|
|
if (LZ4F_isError(hSize)) return hSize; |
1271
|
|
|
|
|
|
|
} |
1272
|
0
|
|
|
|
|
|
break; |
1273
|
|
|
|
|
|
|
|
1274
|
|
|
|
|
|
|
case dstage_init: |
1275
|
6
|
100
|
|
|
|
|
if (dctx->frameInfo.contentChecksumFlag) XXH32_reset(&(dctx->xxh), 0); |
1276
|
|
|
|
|
|
|
/* internal buffers allocation */ |
1277
|
12
|
|
|
|
|
|
{ size_t const bufferNeeded = dctx->maxBlockSize |
1278
|
6
|
100
|
|
|
|
|
+ ((dctx->frameInfo.blockMode==LZ4F_blockLinked) * 128 KB); |
1279
|
6
|
50
|
|
|
|
|
if (bufferNeeded > dctx->maxBufferSize) { /* tmp buffers too small */ |
1280
|
6
|
|
|
|
|
|
dctx->maxBufferSize = 0; /* ensure allocation will be re-attempted on next entry*/ |
1281
|
6
|
|
|
|
|
|
FREEMEM(dctx->tmpIn); |
1282
|
6
|
|
|
|
|
|
dctx->tmpIn = (BYTE*)ALLOCATOR(dctx->maxBlockSize + 4 /* block checksum */); |
1283
|
6
|
50
|
|
|
|
|
if (dctx->tmpIn == NULL) |
1284
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_allocation_failed); |
1285
|
6
|
|
|
|
|
|
FREEMEM(dctx->tmpOutBuffer); |
1286
|
6
|
|
|
|
|
|
dctx->tmpOutBuffer= (BYTE*)ALLOCATOR(bufferNeeded); |
1287
|
6
|
50
|
|
|
|
|
if (dctx->tmpOutBuffer== NULL) |
1288
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_allocation_failed); |
1289
|
6
|
|
|
|
|
|
dctx->maxBufferSize = bufferNeeded; |
1290
|
|
|
|
|
|
|
} } |
1291
|
6
|
|
|
|
|
|
dctx->tmpInSize = 0; |
1292
|
6
|
|
|
|
|
|
dctx->tmpInTarget = 0; |
1293
|
6
|
|
|
|
|
|
dctx->tmpOut = dctx->tmpOutBuffer; |
1294
|
6
|
|
|
|
|
|
dctx->tmpOutStart = 0; |
1295
|
6
|
|
|
|
|
|
dctx->tmpOutSize = 0; |
1296
|
|
|
|
|
|
|
|
1297
|
6
|
|
|
|
|
|
dctx->dStage = dstage_getBlockHeader; |
1298
|
|
|
|
|
|
|
/* fall-through */ |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
case dstage_getBlockHeader: |
1301
|
48
|
50
|
|
|
|
|
if ((size_t)(srcEnd - srcPtr) >= BHSize) { |
1302
|
48
|
|
|
|
|
|
selectedIn = srcPtr; |
1303
|
48
|
|
|
|
|
|
srcPtr += BHSize; |
1304
|
|
|
|
|
|
|
} else { |
1305
|
|
|
|
|
|
|
/* not enough input to read cBlockSize field */ |
1306
|
0
|
|
|
|
|
|
dctx->tmpInSize = 0; |
1307
|
0
|
|
|
|
|
|
dctx->dStage = dstage_storeBlockHeader; |
1308
|
|
|
|
|
|
|
} |
1309
|
|
|
|
|
|
|
|
1310
|
48
|
50
|
|
|
|
|
if (dctx->dStage == dstage_storeBlockHeader) /* can be skipped */ |
1311
|
|
|
|
|
|
|
case dstage_storeBlockHeader: |
1312
|
0
|
|
|
|
|
|
{ size_t const remainingInput = (size_t)(srcEnd - srcPtr); |
1313
|
0
|
|
|
|
|
|
size_t const wantedData = BHSize - dctx->tmpInSize; |
1314
|
0
|
|
|
|
|
|
size_t const sizeToCopy = MIN(wantedData, remainingInput); |
1315
|
0
|
|
|
|
|
|
memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy); |
1316
|
0
|
|
|
|
|
|
srcPtr += sizeToCopy; |
1317
|
0
|
|
|
|
|
|
dctx->tmpInSize += sizeToCopy; |
1318
|
|
|
|
|
|
|
|
1319
|
0
|
0
|
|
|
|
|
if (dctx->tmpInSize < BHSize) { /* not enough input for cBlockSize */ |
1320
|
0
|
|
|
|
|
|
nextSrcSizeHint = BHSize - dctx->tmpInSize; |
1321
|
0
|
|
|
|
|
|
doAnotherStage = 0; |
1322
|
0
|
|
|
|
|
|
break; |
1323
|
|
|
|
|
|
|
} |
1324
|
0
|
|
|
|
|
|
selectedIn = dctx->tmpIn; |
1325
|
|
|
|
|
|
|
} /* if (dctx->dStage == dstage_storeBlockHeader) */ |
1326
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
/* decode block header */ |
1328
|
48
|
|
|
|
|
|
{ size_t const nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU; |
1329
|
48
|
|
|
|
|
|
size_t const crcSize = dctx->frameInfo.blockChecksumFlag * 4; |
1330
|
48
|
100
|
|
|
|
|
if (nextCBlockSize==0) { /* frameEnd signal, no more block */ |
1331
|
5
|
|
|
|
|
|
dctx->dStage = dstage_getSuffix; |
1332
|
5
|
|
|
|
|
|
break; |
1333
|
|
|
|
|
|
|
} |
1334
|
43
|
50
|
|
|
|
|
if (nextCBlockSize > dctx->maxBlockSize) |
1335
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_maxBlockSize_invalid); |
1336
|
43
|
50
|
|
|
|
|
if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG) { |
1337
|
|
|
|
|
|
|
/* next block is uncompressed */ |
1338
|
0
|
|
|
|
|
|
dctx->tmpInTarget = nextCBlockSize; |
1339
|
0
|
0
|
|
|
|
|
if (dctx->frameInfo.blockChecksumFlag) { |
1340
|
0
|
|
|
|
|
|
XXH32_reset(&dctx->blockChecksum, 0); |
1341
|
|
|
|
|
|
|
} |
1342
|
0
|
|
|
|
|
|
dctx->dStage = dstage_copyDirect; |
1343
|
0
|
|
|
|
|
|
break; |
1344
|
|
|
|
|
|
|
} |
1345
|
|
|
|
|
|
|
/* next block is a compressed block */ |
1346
|
43
|
|
|
|
|
|
dctx->tmpInTarget = nextCBlockSize + crcSize; |
1347
|
43
|
|
|
|
|
|
dctx->dStage = dstage_getCBlock; |
1348
|
43
|
100
|
|
|
|
|
if (dstPtr==dstEnd) { |
1349
|
1
|
|
|
|
|
|
nextSrcSizeHint = nextCBlockSize + crcSize + BHSize; |
1350
|
1
|
|
|
|
|
|
doAnotherStage = 0; |
1351
|
|
|
|
|
|
|
} |
1352
|
43
|
|
|
|
|
|
break; |
1353
|
|
|
|
|
|
|
} |
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
case dstage_copyDirect: /* uncompressed block */ |
1356
|
0
|
|
|
|
|
|
{ size_t const minBuffSize = MIN((size_t)(srcEnd-srcPtr), (size_t)(dstEnd-dstPtr)); |
1357
|
0
|
|
|
|
|
|
size_t const sizeToCopy = MIN(dctx->tmpInTarget, minBuffSize); |
1358
|
0
|
|
|
|
|
|
memcpy(dstPtr, srcPtr, sizeToCopy); |
1359
|
0
|
0
|
|
|
|
|
if (dctx->frameInfo.blockChecksumFlag) { |
1360
|
0
|
|
|
|
|
|
XXH32_update(&dctx->blockChecksum, srcPtr, sizeToCopy); |
1361
|
|
|
|
|
|
|
} |
1362
|
0
|
0
|
|
|
|
|
if (dctx->frameInfo.contentChecksumFlag) |
1363
|
0
|
|
|
|
|
|
XXH32_update(&dctx->xxh, srcPtr, sizeToCopy); |
1364
|
0
|
0
|
|
|
|
|
if (dctx->frameInfo.contentSize) |
1365
|
0
|
|
|
|
|
|
dctx->frameRemainingSize -= sizeToCopy; |
1366
|
|
|
|
|
|
|
|
1367
|
|
|
|
|
|
|
/* history management (linked blocks only)*/ |
1368
|
0
|
0
|
|
|
|
|
if (dctx->frameInfo.blockMode == LZ4F_blockLinked) |
1369
|
0
|
|
|
|
|
|
LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0); |
1370
|
|
|
|
|
|
|
|
1371
|
0
|
|
|
|
|
|
srcPtr += sizeToCopy; |
1372
|
0
|
|
|
|
|
|
dstPtr += sizeToCopy; |
1373
|
0
|
0
|
|
|
|
|
if (sizeToCopy == dctx->tmpInTarget) { /* all done */ |
1374
|
0
|
0
|
|
|
|
|
if (dctx->frameInfo.blockChecksumFlag) { |
1375
|
0
|
|
|
|
|
|
dctx->tmpInSize = 0; |
1376
|
0
|
|
|
|
|
|
dctx->dStage = dstage_getBlockChecksum; |
1377
|
|
|
|
|
|
|
} else |
1378
|
0
|
|
|
|
|
|
dctx->dStage = dstage_getBlockHeader; /* new block */ |
1379
|
0
|
|
|
|
|
|
break; |
1380
|
|
|
|
|
|
|
} |
1381
|
0
|
|
|
|
|
|
dctx->tmpInTarget -= sizeToCopy; /* need to copy more */ |
1382
|
0
|
|
|
|
|
|
nextSrcSizeHint = dctx->tmpInTarget + |
1383
|
0
|
|
|
|
|
|
+ dctx->frameInfo.contentChecksumFlag * 4 /* block checksum */ |
1384
|
0
|
|
|
|
|
|
+ BHSize /* next header size */; |
1385
|
0
|
|
|
|
|
|
doAnotherStage = 0; |
1386
|
0
|
|
|
|
|
|
break; |
1387
|
|
|
|
|
|
|
} |
1388
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
/* check block checksum for recently transferred uncompressed block */ |
1390
|
|
|
|
|
|
|
case dstage_getBlockChecksum: |
1391
|
|
|
|
|
|
|
{ const void* crcSrc; |
1392
|
0
|
0
|
|
|
|
|
if ((srcEnd-srcPtr >= 4) && (dctx->tmpInSize==0)) { |
|
|
0
|
|
|
|
|
|
1393
|
0
|
|
|
|
|
|
crcSrc = srcPtr; |
1394
|
0
|
|
|
|
|
|
srcPtr += 4; |
1395
|
|
|
|
|
|
|
} else { |
1396
|
0
|
|
|
|
|
|
size_t const stillToCopy = 4 - dctx->tmpInSize; |
1397
|
0
|
|
|
|
|
|
size_t const sizeToCopy = MIN(stillToCopy, (size_t)(srcEnd-srcPtr)); |
1398
|
0
|
|
|
|
|
|
memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy); |
1399
|
0
|
|
|
|
|
|
dctx->tmpInSize += sizeToCopy; |
1400
|
0
|
|
|
|
|
|
srcPtr += sizeToCopy; |
1401
|
0
|
0
|
|
|
|
|
if (dctx->tmpInSize < 4) { /* all input consumed */ |
1402
|
0
|
|
|
|
|
|
doAnotherStage = 0; |
1403
|
0
|
|
|
|
|
|
break; |
1404
|
|
|
|
|
|
|
} |
1405
|
0
|
|
|
|
|
|
crcSrc = dctx->header; |
1406
|
|
|
|
|
|
|
} |
1407
|
0
|
|
|
|
|
|
{ U32 const readCRC = LZ4F_readLE32(crcSrc); |
1408
|
0
|
|
|
|
|
|
U32 const calcCRC = XXH32_digest(&dctx->blockChecksum); |
1409
|
0
|
0
|
|
|
|
|
if (readCRC != calcCRC) |
1410
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_blockChecksum_invalid); |
1411
|
|
|
|
|
|
|
} |
1412
|
|
|
|
|
|
|
} |
1413
|
0
|
|
|
|
|
|
dctx->dStage = dstage_getBlockHeader; /* new block */ |
1414
|
0
|
|
|
|
|
|
break; |
1415
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
case dstage_getCBlock: |
1417
|
43
|
100
|
|
|
|
|
if ((size_t)(srcEnd-srcPtr) < dctx->tmpInTarget) { |
1418
|
1
|
|
|
|
|
|
dctx->tmpInSize = 0; |
1419
|
1
|
|
|
|
|
|
dctx->dStage = dstage_storeCBlock; |
1420
|
1
|
|
|
|
|
|
break; |
1421
|
|
|
|
|
|
|
} |
1422
|
|
|
|
|
|
|
/* input large enough to read full block directly */ |
1423
|
42
|
|
|
|
|
|
selectedIn = srcPtr; |
1424
|
42
|
|
|
|
|
|
srcPtr += dctx->tmpInTarget; |
1425
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
if (0) /* jump over next block */ |
1427
|
|
|
|
|
|
|
case dstage_storeCBlock: |
1428
|
1
|
|
|
|
|
|
{ size_t const wantedData = dctx->tmpInTarget - dctx->tmpInSize; |
1429
|
1
|
|
|
|
|
|
size_t const inputLeft = (size_t)(srcEnd-srcPtr); |
1430
|
1
|
|
|
|
|
|
size_t const sizeToCopy = MIN(wantedData, inputLeft); |
1431
|
1
|
|
|
|
|
|
memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy); |
1432
|
1
|
|
|
|
|
|
dctx->tmpInSize += sizeToCopy; |
1433
|
1
|
|
|
|
|
|
srcPtr += sizeToCopy; |
1434
|
1
|
50
|
|
|
|
|
if (dctx->tmpInSize < dctx->tmpInTarget) { /* need more input */ |
1435
|
1
|
|
|
|
|
|
nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize) + BHSize; |
1436
|
1
|
|
|
|
|
|
doAnotherStage=0; |
1437
|
1
|
|
|
|
|
|
break; |
1438
|
|
|
|
|
|
|
} |
1439
|
0
|
|
|
|
|
|
selectedIn = dctx->tmpIn; |
1440
|
|
|
|
|
|
|
} |
1441
|
|
|
|
|
|
|
|
1442
|
|
|
|
|
|
|
/* At this stage, input is large enough to decode a block */ |
1443
|
42
|
50
|
|
|
|
|
if (dctx->frameInfo.blockChecksumFlag) { |
1444
|
0
|
|
|
|
|
|
dctx->tmpInTarget -= 4; |
1445
|
|
|
|
|
|
|
assert(selectedIn != NULL); /* selectedIn is defined at this stage (either srcPtr, or dctx->tmpIn) */ |
1446
|
0
|
|
|
|
|
|
{ U32 const readBlockCrc = LZ4F_readLE32(selectedIn + dctx->tmpInTarget); |
1447
|
0
|
|
|
|
|
|
U32 const calcBlockCrc = XXH32(selectedIn, dctx->tmpInTarget, 0); |
1448
|
0
|
0
|
|
|
|
|
if (readBlockCrc != calcBlockCrc) |
1449
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_blockChecksum_invalid); |
1450
|
|
|
|
|
|
|
} } |
1451
|
|
|
|
|
|
|
|
1452
|
42
|
100
|
|
|
|
|
if ((size_t)(dstEnd-dstPtr) >= dctx->maxBlockSize) { |
1453
|
|
|
|
|
|
|
/* enough capacity in `dst` to decompress directly there */ |
1454
|
37
|
|
|
|
|
|
int const decodedSize = LZ4_decompress_safe_usingDict( |
1455
|
|
|
|
|
|
|
(const char*)selectedIn, (char*)dstPtr, |
1456
|
74
|
|
|
|
|
|
(int)dctx->tmpInTarget, (int)dctx->maxBlockSize, |
1457
|
74
|
|
|
|
|
|
(const char*)dctx->dict, (int)dctx->dictSize); |
1458
|
37
|
50
|
|
|
|
|
if (decodedSize < 0) return err0r(LZ4F_ERROR_GENERIC); /* decompression failed */ |
1459
|
37
|
50
|
|
|
|
|
if (dctx->frameInfo.contentChecksumFlag) |
1460
|
0
|
|
|
|
|
|
XXH32_update(&(dctx->xxh), dstPtr, decodedSize); |
1461
|
37
|
100
|
|
|
|
|
if (dctx->frameInfo.contentSize) |
1462
|
36
|
|
|
|
|
|
dctx->frameRemainingSize -= decodedSize; |
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
/* dictionary management */ |
1465
|
37
|
100
|
|
|
|
|
if (dctx->frameInfo.blockMode==LZ4F_blockLinked) |
1466
|
36
|
|
|
|
|
|
LZ4F_updateDict(dctx, dstPtr, decodedSize, dstStart, 0); |
1467
|
|
|
|
|
|
|
|
1468
|
37
|
|
|
|
|
|
dstPtr += decodedSize; |
1469
|
37
|
|
|
|
|
|
dctx->dStage = dstage_getBlockHeader; |
1470
|
37
|
|
|
|
|
|
break; |
1471
|
|
|
|
|
|
|
} |
1472
|
|
|
|
|
|
|
|
1473
|
|
|
|
|
|
|
/* not enough place into dst : decode into tmpOut */ |
1474
|
|
|
|
|
|
|
/* ensure enough place for tmpOut */ |
1475
|
5
|
100
|
|
|
|
|
if (dctx->frameInfo.blockMode == LZ4F_blockLinked) { |
1476
|
3
|
50
|
|
|
|
|
if (dctx->dict == dctx->tmpOutBuffer) { |
1477
|
0
|
0
|
|
|
|
|
if (dctx->dictSize > 128 KB) { |
1478
|
0
|
|
|
|
|
|
memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - 64 KB, 64 KB); |
1479
|
0
|
|
|
|
|
|
dctx->dictSize = 64 KB; |
1480
|
|
|
|
|
|
|
} |
1481
|
0
|
|
|
|
|
|
dctx->tmpOut = dctx->tmpOutBuffer + dctx->dictSize; |
1482
|
|
|
|
|
|
|
} else { /* dict not within tmp */ |
1483
|
3
|
|
|
|
|
|
size_t const reservedDictSpace = MIN(dctx->dictSize, 64 KB); |
1484
|
3
|
|
|
|
|
|
dctx->tmpOut = dctx->tmpOutBuffer + reservedDictSpace; |
1485
|
|
|
|
|
|
|
} |
1486
|
|
|
|
|
|
|
} |
1487
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
/* Decode block */ |
1489
|
5
|
|
|
|
|
|
{ int const decodedSize = LZ4_decompress_safe_usingDict( |
1490
|
5
|
|
|
|
|
|
(const char*)selectedIn, (char*)dctx->tmpOut, |
1491
|
10
|
|
|
|
|
|
(int)dctx->tmpInTarget, (int)dctx->maxBlockSize, |
1492
|
10
|
|
|
|
|
|
(const char*)dctx->dict, (int)dctx->dictSize); |
1493
|
5
|
50
|
|
|
|
|
if (decodedSize < 0) /* decompression failed */ |
1494
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_decompressionFailed); |
1495
|
5
|
100
|
|
|
|
|
if (dctx->frameInfo.contentChecksumFlag) |
1496
|
1
|
|
|
|
|
|
XXH32_update(&(dctx->xxh), dctx->tmpOut, decodedSize); |
1497
|
5
|
100
|
|
|
|
|
if (dctx->frameInfo.contentSize) |
1498
|
3
|
|
|
|
|
|
dctx->frameRemainingSize -= decodedSize; |
1499
|
5
|
|
|
|
|
|
dctx->tmpOutSize = decodedSize; |
1500
|
5
|
|
|
|
|
|
dctx->tmpOutStart = 0; |
1501
|
5
|
|
|
|
|
|
dctx->dStage = dstage_flushOut; |
1502
|
|
|
|
|
|
|
} |
1503
|
|
|
|
|
|
|
/* fall-through */ |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
case dstage_flushOut: /* flush decoded data from tmpOut to dstBuffer */ |
1506
|
518
|
|
|
|
|
|
{ size_t const sizeToCopy = MIN(dctx->tmpOutSize - dctx->tmpOutStart, (size_t)(dstEnd-dstPtr)); |
1507
|
518
|
|
|
|
|
|
memcpy(dstPtr, dctx->tmpOut + dctx->tmpOutStart, sizeToCopy); |
1508
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
/* dictionary management */ |
1510
|
518
|
100
|
|
|
|
|
if (dctx->frameInfo.blockMode==LZ4F_blockLinked) |
1511
|
3
|
|
|
|
|
|
LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 1); |
1512
|
|
|
|
|
|
|
|
1513
|
518
|
|
|
|
|
|
dctx->tmpOutStart += sizeToCopy; |
1514
|
518
|
|
|
|
|
|
dstPtr += sizeToCopy; |
1515
|
|
|
|
|
|
|
|
1516
|
518
|
100
|
|
|
|
|
if (dctx->tmpOutStart == dctx->tmpOutSize) { /* all flushed */ |
1517
|
5
|
|
|
|
|
|
dctx->dStage = dstage_getBlockHeader; /* get next block */ |
1518
|
5
|
|
|
|
|
|
break; |
1519
|
|
|
|
|
|
|
} |
1520
|
513
|
|
|
|
|
|
nextSrcSizeHint = BHSize; |
1521
|
513
|
|
|
|
|
|
doAnotherStage = 0; /* still some data to flush */ |
1522
|
513
|
|
|
|
|
|
break; |
1523
|
|
|
|
|
|
|
} |
1524
|
|
|
|
|
|
|
|
1525
|
|
|
|
|
|
|
case dstage_getSuffix: |
1526
|
5
|
50
|
|
|
|
|
if (dctx->frameRemainingSize) |
1527
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_frameSize_wrong); /* incorrect frame size decoded */ |
1528
|
5
|
100
|
|
|
|
|
if (!dctx->frameInfo.contentChecksumFlag) { /* no checksum, frame is completed */ |
1529
|
4
|
|
|
|
|
|
nextSrcSizeHint = 0; |
1530
|
4
|
|
|
|
|
|
LZ4F_resetDecompressionContext(dctx); |
1531
|
4
|
|
|
|
|
|
doAnotherStage = 0; |
1532
|
4
|
|
|
|
|
|
break; |
1533
|
|
|
|
|
|
|
} |
1534
|
1
|
50
|
|
|
|
|
if ((srcEnd - srcPtr) < 4) { /* not enough size for entire CRC */ |
1535
|
0
|
|
|
|
|
|
dctx->tmpInSize = 0; |
1536
|
0
|
|
|
|
|
|
dctx->dStage = dstage_storeSuffix; |
1537
|
|
|
|
|
|
|
} else { |
1538
|
1
|
|
|
|
|
|
selectedIn = srcPtr; |
1539
|
1
|
|
|
|
|
|
srcPtr += 4; |
1540
|
|
|
|
|
|
|
} |
1541
|
|
|
|
|
|
|
|
1542
|
1
|
50
|
|
|
|
|
if (dctx->dStage == dstage_storeSuffix) /* can be skipped */ |
1543
|
|
|
|
|
|
|
case dstage_storeSuffix: |
1544
|
0
|
|
|
|
|
|
{ size_t const remainingInput = (size_t)(srcEnd - srcPtr); |
1545
|
0
|
|
|
|
|
|
size_t const wantedData = 4 - dctx->tmpInSize; |
1546
|
0
|
|
|
|
|
|
size_t const sizeToCopy = MIN(wantedData, remainingInput); |
1547
|
0
|
|
|
|
|
|
memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy); |
1548
|
0
|
|
|
|
|
|
srcPtr += sizeToCopy; |
1549
|
0
|
|
|
|
|
|
dctx->tmpInSize += sizeToCopy; |
1550
|
0
|
0
|
|
|
|
|
if (dctx->tmpInSize < 4) { /* not enough input to read complete suffix */ |
1551
|
0
|
|
|
|
|
|
nextSrcSizeHint = 4 - dctx->tmpInSize; |
1552
|
0
|
|
|
|
|
|
doAnotherStage=0; |
1553
|
0
|
|
|
|
|
|
break; |
1554
|
|
|
|
|
|
|
} |
1555
|
0
|
|
|
|
|
|
selectedIn = dctx->tmpIn; |
1556
|
|
|
|
|
|
|
} /* if (dctx->dStage == dstage_storeSuffix) */ |
1557
|
|
|
|
|
|
|
|
1558
|
|
|
|
|
|
|
/* case dstage_checkSuffix: */ /* no direct call, avoid scan-build warning */ |
1559
|
1
|
|
|
|
|
|
{ U32 const readCRC = LZ4F_readLE32(selectedIn); |
1560
|
1
|
|
|
|
|
|
U32 const resultCRC = XXH32_digest(&(dctx->xxh)); |
1561
|
1
|
50
|
|
|
|
|
if (readCRC != resultCRC) |
1562
|
0
|
|
|
|
|
|
return err0r(LZ4F_ERROR_contentChecksum_invalid); |
1563
|
1
|
|
|
|
|
|
nextSrcSizeHint = 0; |
1564
|
1
|
|
|
|
|
|
LZ4F_resetDecompressionContext(dctx); |
1565
|
1
|
|
|
|
|
|
doAnotherStage = 0; |
1566
|
1
|
|
|
|
|
|
break; |
1567
|
|
|
|
|
|
|
} |
1568
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
case dstage_getSFrameSize: |
1570
|
0
|
0
|
|
|
|
|
if ((srcEnd - srcPtr) >= 4) { |
1571
|
0
|
|
|
|
|
|
selectedIn = srcPtr; |
1572
|
0
|
|
|
|
|
|
srcPtr += 4; |
1573
|
|
|
|
|
|
|
} else { |
1574
|
|
|
|
|
|
|
/* not enough input to read cBlockSize field */ |
1575
|
0
|
|
|
|
|
|
dctx->tmpInSize = 4; |
1576
|
0
|
|
|
|
|
|
dctx->tmpInTarget = 8; |
1577
|
0
|
|
|
|
|
|
dctx->dStage = dstage_storeSFrameSize; |
1578
|
|
|
|
|
|
|
} |
1579
|
|
|
|
|
|
|
|
1580
|
0
|
0
|
|
|
|
|
if (dctx->dStage == dstage_storeSFrameSize) |
1581
|
|
|
|
|
|
|
case dstage_storeSFrameSize: |
1582
|
|
|
|
|
|
|
{ |
1583
|
0
|
|
|
|
|
|
size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize, |
1584
|
|
|
|
|
|
|
(size_t)(srcEnd - srcPtr) ); |
1585
|
0
|
|
|
|
|
|
memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy); |
1586
|
0
|
|
|
|
|
|
srcPtr += sizeToCopy; |
1587
|
0
|
|
|
|
|
|
dctx->tmpInSize += sizeToCopy; |
1588
|
0
|
0
|
|
|
|
|
if (dctx->tmpInSize < dctx->tmpInTarget) { |
1589
|
|
|
|
|
|
|
/* not enough input to get full sBlockSize; wait for more */ |
1590
|
0
|
|
|
|
|
|
nextSrcSizeHint = dctx->tmpInTarget - dctx->tmpInSize; |
1591
|
0
|
|
|
|
|
|
doAnotherStage = 0; |
1592
|
0
|
|
|
|
|
|
break; |
1593
|
|
|
|
|
|
|
} |
1594
|
0
|
|
|
|
|
|
selectedIn = dctx->header + 4; |
1595
|
|
|
|
|
|
|
} /* if (dctx->dStage == dstage_storeSFrameSize) */ |
1596
|
|
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
/* case dstage_decodeSFrameSize: */ /* no direct access */ |
1598
|
0
|
|
|
|
|
|
{ size_t const SFrameSize = LZ4F_readLE32(selectedIn); |
1599
|
0
|
|
|
|
|
|
dctx->frameInfo.contentSize = SFrameSize; |
1600
|
0
|
|
|
|
|
|
dctx->tmpInTarget = SFrameSize; |
1601
|
0
|
|
|
|
|
|
dctx->dStage = dstage_skipSkippable; |
1602
|
0
|
|
|
|
|
|
break; |
1603
|
|
|
|
|
|
|
} |
1604
|
|
|
|
|
|
|
|
1605
|
|
|
|
|
|
|
case dstage_skipSkippable: |
1606
|
0
|
|
|
|
|
|
{ size_t const skipSize = MIN(dctx->tmpInTarget, (size_t)(srcEnd-srcPtr)); |
1607
|
0
|
|
|
|
|
|
srcPtr += skipSize; |
1608
|
0
|
|
|
|
|
|
dctx->tmpInTarget -= skipSize; |
1609
|
0
|
|
|
|
|
|
doAnotherStage = 0; |
1610
|
0
|
|
|
|
|
|
nextSrcSizeHint = dctx->tmpInTarget; |
1611
|
0
|
0
|
|
|
|
|
if (nextSrcSizeHint) break; /* still more to skip */ |
1612
|
|
|
|
|
|
|
/* frame fully skipped : prepare context for a new frame */ |
1613
|
0
|
|
|
|
|
|
LZ4F_resetDecompressionContext(dctx); |
1614
|
0
|
|
|
|
|
|
break; |
1615
|
|
|
|
|
|
|
} |
1616
|
|
|
|
|
|
|
} |
1617
|
|
|
|
|
|
|
} /* while (doAnotherStage) */ |
1618
|
|
|
|
|
|
|
|
1619
|
|
|
|
|
|
|
/* preserve history within tmp whenever necessary */ |
1620
|
|
|
|
|
|
|
LZ4F_STATIC_ASSERT((unsigned)dstage_init == 2); |
1621
|
520
|
100
|
|
|
|
|
if ( (dctx->frameInfo.blockMode==LZ4F_blockLinked) /* next block will use up to 64KB from previous ones */ |
1622
|
3
|
50
|
|
|
|
|
&& (dctx->dict != dctx->tmpOutBuffer) /* dictionary is not already within tmp */ |
1623
|
3
|
50
|
|
|
|
|
&& (!decompressOptionsPtr->stableDst) /* cannot rely on dst data to remain there for next call */ |
1624
|
3
|
50
|
|
|
|
|
&& ((unsigned)(dctx->dStage)-2 < (unsigned)(dstage_getSuffix)-2) ) /* valid stages : [init ... getSuffix[ */ |
1625
|
|
|
|
|
|
|
{ |
1626
|
0
|
0
|
|
|
|
|
if (dctx->dStage == dstage_flushOut) { |
1627
|
0
|
|
|
|
|
|
size_t const preserveSize = dctx->tmpOut - dctx->tmpOutBuffer; |
1628
|
0
|
|
|
|
|
|
size_t copySize = 64 KB - dctx->tmpOutSize; |
1629
|
0
|
|
|
|
|
|
const BYTE* oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart; |
1630
|
0
|
0
|
|
|
|
|
if (dctx->tmpOutSize > 64 KB) copySize = 0; |
1631
|
0
|
0
|
|
|
|
|
if (copySize > preserveSize) copySize = preserveSize; |
1632
|
|
|
|
|
|
|
|
1633
|
0
|
0
|
|
|
|
|
if (copySize > 0) |
1634
|
0
|
|
|
|
|
|
memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize); |
1635
|
|
|
|
|
|
|
|
1636
|
0
|
|
|
|
|
|
dctx->dict = dctx->tmpOutBuffer; |
1637
|
0
|
|
|
|
|
|
dctx->dictSize = preserveSize + dctx->tmpOutStart; |
1638
|
|
|
|
|
|
|
} else { |
1639
|
0
|
|
|
|
|
|
const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize; |
1640
|
0
|
|
|
|
|
|
size_t const newDictSize = MIN(dctx->dictSize, 64 KB); |
1641
|
|
|
|
|
|
|
|
1642
|
0
|
0
|
|
|
|
|
if (newDictSize > 0) |
1643
|
0
|
|
|
|
|
|
memcpy(dctx->tmpOutBuffer, oldDictEnd - newDictSize, newDictSize); |
1644
|
|
|
|
|
|
|
|
1645
|
0
|
|
|
|
|
|
dctx->dict = dctx->tmpOutBuffer; |
1646
|
0
|
|
|
|
|
|
dctx->dictSize = newDictSize; |
1647
|
0
|
|
|
|
|
|
dctx->tmpOut = dctx->tmpOutBuffer + newDictSize; |
1648
|
|
|
|
|
|
|
} |
1649
|
|
|
|
|
|
|
} |
1650
|
|
|
|
|
|
|
|
1651
|
520
|
|
|
|
|
|
*srcSizePtr = (srcPtr - srcStart); |
1652
|
520
|
|
|
|
|
|
*dstSizePtr = (dstPtr - dstStart); |
1653
|
520
|
|
|
|
|
|
return nextSrcSizeHint; |
1654
|
|
|
|
|
|
|
} |
1655
|
|
|
|
|
|
|
|
1656
|
|
|
|
|
|
|
/*! LZ4F_decompress_usingDict() : |
1657
|
|
|
|
|
|
|
* Same as LZ4F_decompress(), using a predefined dictionary. |
1658
|
|
|
|
|
|
|
* Dictionary is used "in place", without any preprocessing. |
1659
|
|
|
|
|
|
|
* It must remain accessible throughout the entire frame decoding. |
1660
|
|
|
|
|
|
|
*/ |
1661
|
0
|
|
|
|
|
|
size_t LZ4F_decompress_usingDict(LZ4F_dctx* dctx, |
1662
|
|
|
|
|
|
|
void* dstBuffer, size_t* dstSizePtr, |
1663
|
|
|
|
|
|
|
const void* srcBuffer, size_t* srcSizePtr, |
1664
|
|
|
|
|
|
|
const void* dict, size_t dictSize, |
1665
|
|
|
|
|
|
|
const LZ4F_decompressOptions_t* decompressOptionsPtr) |
1666
|
|
|
|
|
|
|
{ |
1667
|
0
|
0
|
|
|
|
|
if (dctx->dStage <= dstage_init) { |
1668
|
0
|
|
|
|
|
|
dctx->dict = (const BYTE*)dict; |
1669
|
0
|
|
|
|
|
|
dctx->dictSize = dictSize; |
1670
|
|
|
|
|
|
|
} |
1671
|
0
|
|
|
|
|
|
return LZ4F_decompress(dctx, dstBuffer, dstSizePtr, |
1672
|
|
|
|
|
|
|
srcBuffer, srcSizePtr, |
1673
|
|
|
|
|
|
|
decompressOptionsPtr); |
1674
|
|
|
|
|
|
|
} |