1 /*
2 LZ4 auto-framing library
3 Copyright (C) 2011-2014, Yann Collet.
4 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are
8 met:
9
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following disclaimer
14 in the documentation and/or other materials provided with the
15 distribution.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 You can contact the author at :
30 - LZ4 source repository : http://code.google.com/p/lz4/
31 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
32 */
33
34 /* LZ4F is a stand-alone API to create LZ4-compressed Frames
35 * fully conformant to specification v1.4.1.
36 * All related operations, including memory management, are handled by the library.
37 * */
38
39
40 /**************************************
41 Compiler Options
42 **************************************/
43 #ifdef _MSC_VER /* Visual Studio */
44 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
45 #endif
46
47 #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
48 #ifdef __GNUC__
49 # pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
50 # pragma GCC diagnostic ignored "-Wmissing-field-initializers" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
51 #endif
52
53
54 /**************************************
55 Memory routines
56 **************************************/
57 #include <stdlib.h> /* malloc, calloc, free */
58 #define ALLOCATOR(s) calloc(1,s)
59 #define FREEMEM free
60 #include <string.h> /* memset, memcpy, memmove */
61 #define MEM_INIT memset
62
63
64 /**************************************
65 Includes
66 **************************************/
67 #include "lz4frame_static.h"
68 #include "lz4.h"
69 #include "lz4hc.h"
70 #include "xxhash.h"
71
72
73 /**************************************
74 Basic Types
75 **************************************/
76 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
77 # include <stdint.h>
78 typedef uint8_t BYTE;
79 typedef uint16_t U16;
80 typedef uint32_t U32;
81 typedef int32_t S32;
82 typedef uint64_t U64;
83 #else
84 typedef unsigned char BYTE;
85 typedef unsigned short U16;
86 typedef unsigned int U32;
87 typedef signed int S32;
88 typedef unsigned long long U64;
89 #endif
90
91
92 /**************************************
93 Constants
94 **************************************/
95 #define KB *(1<<10)
96 #define MB *(1<<20)
97 #define GB *(1<<30)
98
99 #define _1BIT 0x01
100 #define _2BITS 0x03
101 #define _3BITS 0x07
102 #define _4BITS 0x0F
103 #define _8BITS 0xFF
104
105 #define LZ4F_MAGICNUMBER 0x184D2204U
106 #define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U
107 #define LZ4F_MAXHEADERFRAME_SIZE 7
108 #define LZ4F_BLOCKSIZEID_DEFAULT max64KB
109
110 static const U32 minHClevel = 3;
111
112 /**************************************
113 Structures and local types
114 **************************************/
115 typedef struct
116 {
117 LZ4F_preferences_t prefs;
118 U32 version;
119 U32 cStage;
120 size_t maxBlockSize;
121 size_t maxBufferSize;
122 BYTE* tmpBuff;
123 BYTE* tmpIn;
124 size_t tmpInSize;
125 XXH32_state_t xxh;
126 void* lz4CtxPtr;
127 U32 lz4CtxLevel; /* 0: unallocated; 1: LZ4_stream_t; 3: LZ4_streamHC_t */
128 } LZ4F_cctx_internal_t;
129
130 typedef struct
131 {
132 LZ4F_frameInfo_t frameInfo;
133 unsigned version;
134 unsigned dStage;
135 size_t maxBlockSize;
136 size_t maxBufferSize;
137 const BYTE* srcExpect;
138 BYTE* tmpIn;
139 size_t tmpInSize;
140 size_t tmpInTarget;
141 BYTE* tmpOutBuffer;
142 BYTE* dict;
143 size_t dictSize;
144 BYTE* tmpOut;
145 size_t tmpOutSize;
146 size_t tmpOutStart;
147 XXH32_state_t xxh;
148 BYTE header[8];
149 } LZ4F_dctx_internal_t;
150
151
152 /**************************************
153 Macros
154 **************************************/
155
156
157 /**************************************
158 Error management
159 **************************************/
160 #define LZ4F_GENERATE_STRING(STRING) #STRING,
161 static const char* LZ4F_errorStrings[] = { LZ4F_LIST_ERRORS(LZ4F_GENERATE_STRING) };
162
163
LZ4F_isError(LZ4F_errorCode_t code)164 U32 LZ4F_isError(LZ4F_errorCode_t code)
165 {
166 return (code > (LZ4F_errorCode_t)(-ERROR_maxCode));
167 }
168
LZ4F_getErrorName(LZ4F_errorCode_t code)169 const char* LZ4F_getErrorName(LZ4F_errorCode_t code)
170 {
171 static const char* codeError = "Unspecified error code";
172 if (LZ4F_isError(code)) return LZ4F_errorStrings[-(int)(code)];
173 return codeError;
174 }
175
176
177 /**************************************
178 Private functions
179 **************************************/
LZ4F_getBlockSize(unsigned blockSizeID)180 static size_t LZ4F_getBlockSize(unsigned blockSizeID)
181 {
182 static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB };
183
184 if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;
185 blockSizeID -= 4;
186 if (blockSizeID > 3) return (size_t)-ERROR_maxBlockSize_invalid;
187 return blockSizes[blockSizeID];
188 }
189
190
191 /* unoptimized version; solves endianess & alignment issues */
LZ4F_writeLE32(BYTE * dstPtr,U32 value32)192 static void LZ4F_writeLE32 (BYTE* dstPtr, U32 value32)
193 {
194 dstPtr[0] = (BYTE)value32;
195 dstPtr[1] = (BYTE)(value32 >> 8);
196 dstPtr[2] = (BYTE)(value32 >> 16);
197 dstPtr[3] = (BYTE)(value32 >> 24);
198 }
199
LZ4F_readLE32(const BYTE * srcPtr)200 static U32 LZ4F_readLE32 (const BYTE* srcPtr)
201 {
202 U32 value32 = srcPtr[0];
203 value32 += (srcPtr[1]<<8);
204 value32 += (srcPtr[2]<<16);
205 value32 += (srcPtr[3]<<24);
206 return value32;
207 }
208
209
LZ4F_headerChecksum(const BYTE * header,size_t length)210 static BYTE LZ4F_headerChecksum (const BYTE* header, size_t length)
211 {
212 U32 xxh = XXH32(header, (U32)length, 0);
213 return (BYTE)(xxh >> 8);
214 }
215
216
217 /**************************************
218 Simple compression functions
219 **************************************/
LZ4F_compressFrameBound(size_t srcSize,const LZ4F_preferences_t * preferencesPtr)220 size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
221 {
222 LZ4F_preferences_t prefs = { 0 };
223 size_t headerSize;
224 size_t streamSize;
225
226 if (preferencesPtr!=NULL) prefs = *preferencesPtr;
227 {
228 blockSizeID_t proposedBSID = max64KB;
229 size_t maxBlockSize = 64 KB;
230 while (prefs.frameInfo.blockSizeID > proposedBSID)
231 {
232 if (srcSize <= maxBlockSize)
233 {
234 prefs.frameInfo.blockSizeID = proposedBSID;
235 break;
236 }
237 proposedBSID++;
238 maxBlockSize <<= 2;
239 }
240 }
241 prefs.autoFlush = 1;
242
243 headerSize = 7; /* basic header size (no option) including magic number */
244 streamSize = LZ4F_compressBound(srcSize, &prefs);
245
246 return headerSize + streamSize;
247 }
248
249
250 /* LZ4F_compressFrame()
251 * Compress an entire srcBuffer into a valid LZ4 frame, as defined by specification v1.4.1, in a single step.
252 * The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure compression completion even in worst case.
253 * You can get the minimum value of dstMaxSize by using LZ4F_compressFrameBound()
254 * If this condition is not respected, LZ4F_compressFrame() will fail (result is an errorCode)
255 * The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will be set to default.
256 * The result of the function is the number of bytes written into dstBuffer.
257 * The function outputs an error code if it fails (can be tested using LZ4F_isError())
258 */
LZ4F_compressFrame(void * dstBuffer,size_t dstMaxSize,const void * srcBuffer,size_t srcSize,const LZ4F_preferences_t * preferencesPtr)259 size_t LZ4F_compressFrame(void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
260 {
261 LZ4F_cctx_internal_t cctxI = { 0 }; /* works because no allocation */
262 LZ4F_preferences_t prefs = { 0 };
263 LZ4F_compressOptions_t options = { 0 };
264 LZ4F_errorCode_t errorCode;
265 BYTE* const dstStart = (BYTE*) dstBuffer;
266 BYTE* dstPtr = dstStart;
267 BYTE* const dstEnd = dstStart + dstMaxSize;
268
269
270 cctxI.version = LZ4F_VERSION;
271 cctxI.maxBufferSize = 5 MB; /* mess with real buffer size to prevent allocation; works because autoflush==1 & stableSrc==1 */
272
273 if (preferencesPtr!=NULL) prefs = *preferencesPtr;
274 {
275 blockSizeID_t proposedBSID = max64KB;
276 size_t maxBlockSize = 64 KB;
277 while (prefs.frameInfo.blockSizeID > proposedBSID)
278 {
279 if (srcSize <= maxBlockSize)
280 {
281 prefs.frameInfo.blockSizeID = proposedBSID;
282 break;
283 }
284 proposedBSID++;
285 maxBlockSize <<= 2;
286 }
287 }
288 prefs.autoFlush = 1;
289 if (srcSize <= LZ4F_getBlockSize(prefs.frameInfo.blockSizeID))
290 prefs.frameInfo.blockMode = blockIndependent; /* no need for linked blocks */
291
292 options.stableSrc = 1;
293
294 if (dstMaxSize < LZ4F_compressFrameBound(srcSize, &prefs))
295 return (size_t)-ERROR_dstMaxSize_tooSmall;
296
297 errorCode = LZ4F_compressBegin(&cctxI, dstBuffer, dstMaxSize, &prefs); /* write header */
298 if (LZ4F_isError(errorCode)) return errorCode;
299 dstPtr += errorCode; /* header size */
300
301 dstMaxSize -= errorCode;
302 errorCode = LZ4F_compressUpdate(&cctxI, dstPtr, dstMaxSize, srcBuffer, srcSize, &options);
303 if (LZ4F_isError(errorCode)) return errorCode;
304 dstPtr += errorCode;
305
306 errorCode = LZ4F_compressEnd(&cctxI, dstPtr, dstEnd-dstPtr, &options); /* flush last block, and generate suffix */
307 if (LZ4F_isError(errorCode)) return errorCode;
308 dstPtr += errorCode;
309
310 FREEMEM(cctxI.lz4CtxPtr);
311
312 return (dstPtr - dstStart);
313 }
314
315
316 /***********************************
317 * Advanced compression functions
318 * *********************************/
319
320 /* LZ4F_createCompressionContext() :
321 * The first thing to do is to create a compressionContext object, which will be used in all compression operations.
322 * This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure.
323 * The version provided MUST be LZ4F_VERSION. It is intended to track potential version differences between different binaries.
324 * The function will provide a pointer to an allocated LZ4F_compressionContext_t object.
325 * If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation.
326 * Object can release its memory using LZ4F_freeCompressionContext();
327 */
LZ4F_createCompressionContext(LZ4F_compressionContext_t * LZ4F_compressionContextPtr,unsigned version)328 LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* LZ4F_compressionContextPtr, unsigned version)
329 {
330 LZ4F_cctx_internal_t* cctxPtr;
331
332 cctxPtr = (LZ4F_cctx_internal_t*)ALLOCATOR(sizeof(LZ4F_cctx_internal_t));
333 if (cctxPtr==NULL) return (LZ4F_errorCode_t)(-ERROR_allocation_failed);
334
335 cctxPtr->version = version;
336 cctxPtr->cStage = 0; /* Next stage : write header */
337
338 *LZ4F_compressionContextPtr = (LZ4F_compressionContext_t)cctxPtr;
339
340 return OK_NoError;
341 }
342
343
LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_compressionContext)344 LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_compressionContext)
345 {
346 LZ4F_cctx_internal_t* cctxPtr = (LZ4F_cctx_internal_t*)LZ4F_compressionContext;
347
348 FREEMEM(cctxPtr->lz4CtxPtr);
349 FREEMEM(cctxPtr->tmpBuff);
350 FREEMEM(LZ4F_compressionContext);
351
352 return OK_NoError;
353 }
354
355
356 /* LZ4F_compressBegin() :
357 * will write the frame header into dstBuffer.
358 * dstBuffer must be large enough to accommodate a header (dstMaxSize). Maximum header size is LZ4F_MAXHEADERFRAME_SIZE bytes.
359 * The result of the function is the number of bytes written into dstBuffer for the header
360 * or an error code (can be tested using LZ4F_isError())
361 */
LZ4F_compressBegin(LZ4F_compressionContext_t compressionContext,void * dstBuffer,size_t dstMaxSize,const LZ4F_preferences_t * preferencesPtr)362 size_t LZ4F_compressBegin(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_preferences_t* preferencesPtr)
363 {
364 LZ4F_preferences_t prefNull = { 0 };
365 LZ4F_cctx_internal_t* cctxPtr = (LZ4F_cctx_internal_t*)compressionContext;
366 BYTE* const dstStart = (BYTE*)dstBuffer;
367 BYTE* dstPtr = dstStart;
368 BYTE* headerStart;
369 size_t requiredBuffSize;
370
371 if (dstMaxSize < LZ4F_MAXHEADERFRAME_SIZE) return (size_t)-ERROR_dstMaxSize_tooSmall;
372 if (cctxPtr->cStage != 0) return (size_t)-ERROR_GENERIC;
373 if (preferencesPtr == NULL) preferencesPtr = &prefNull;
374 cctxPtr->prefs = *preferencesPtr;
375
376 /* ctx Management */
377 {
378 U32 targetCtxLevel = cctxPtr->prefs.compressionLevel<minHClevel ? 1 : 2;
379 if (cctxPtr->lz4CtxLevel < targetCtxLevel)
380 {
381 FREEMEM(cctxPtr->lz4CtxPtr);
382 if (cctxPtr->prefs.compressionLevel<minHClevel)
383 cctxPtr->lz4CtxPtr = (void*)LZ4_createStream();
384 else
385 cctxPtr->lz4CtxPtr = (void*)LZ4_createStreamHC();
386 cctxPtr->lz4CtxLevel = targetCtxLevel;
387 }
388 }
389
390 /* Buffer Management */
391 if (cctxPtr->prefs.frameInfo.blockSizeID == 0) cctxPtr->prefs.frameInfo.blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;
392 cctxPtr->maxBlockSize = LZ4F_getBlockSize(cctxPtr->prefs.frameInfo.blockSizeID);
393
394 requiredBuffSize = cctxPtr->maxBlockSize + ((cctxPtr->prefs.frameInfo.blockMode == blockLinked) * 128 KB);
395 if (preferencesPtr->autoFlush)
396 requiredBuffSize = (cctxPtr->prefs.frameInfo.blockMode == blockLinked) * 64 KB; /* just needs dict */
397
398 if (cctxPtr->maxBufferSize < requiredBuffSize)
399 {
400 cctxPtr->maxBufferSize = requiredBuffSize;
401 FREEMEM(cctxPtr->tmpBuff);
402 cctxPtr->tmpBuff = (BYTE*)ALLOCATOR(requiredBuffSize);
403 if (cctxPtr->tmpBuff == NULL) return (size_t)-ERROR_allocation_failed;
404 }
405 cctxPtr->tmpIn = cctxPtr->tmpBuff;
406 cctxPtr->tmpInSize = 0;
407 XXH32_reset(&(cctxPtr->xxh), 0);
408 if (cctxPtr->prefs.compressionLevel<minHClevel)
409 LZ4_resetStream((LZ4_stream_t*)(cctxPtr->lz4CtxPtr));
410 else
411 LZ4_resetStreamHC((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), cctxPtr->prefs.compressionLevel);
412
413 /* Magic Number */
414 LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER);
415 dstPtr += 4;
416 headerStart = dstPtr;
417
418 /* FLG Byte */
419 *dstPtr++ = ((1 & _2BITS) << 6) /* Version('01') */
420 + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5) /* Block mode */
421 + (char)((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2); /* Stream checksum */
422 /* BD Byte */
423 *dstPtr++ = (char)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4);
424 /* CRC Byte */
425 *dstPtr++ = LZ4F_headerChecksum(headerStart, 2);
426
427 cctxPtr->cStage = 1; /* header written, wait for data block */
428
429 return (dstPtr - dstStart);
430 }
431
432
433 /* LZ4F_compressBound() : gives the size of Dst buffer given a srcSize to handle worst case situations.
434 * The LZ4F_frameInfo_t structure is optional :
435 * you can provide NULL as argument, all preferences will then be set to default.
436 * */
LZ4F_compressBound(size_t srcSize,const LZ4F_preferences_t * preferencesPtr)437 size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
438 {
439 const LZ4F_preferences_t prefsNull = { 0 };
440 const LZ4F_preferences_t* prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr;
441 blockSizeID_t bid = prefsPtr->frameInfo.blockSizeID;
442 size_t blockSize = LZ4F_getBlockSize(bid);
443 unsigned nbBlocks = (unsigned)(srcSize / blockSize) + 1;
444 size_t lastBlockSize = prefsPtr->autoFlush ? srcSize % blockSize : blockSize;
445 size_t blockInfo = 4; /* default, without block CRC option */
446 size_t frameEnd = 4 + (prefsPtr->frameInfo.contentChecksumFlag*4);
447 size_t result = (blockInfo * nbBlocks) + (blockSize * (nbBlocks-1)) + lastBlockSize + frameEnd;
448
449 return result;
450 }
451
452
453 typedef int (*compressFunc_t)(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level);
454
LZ4F_compressBlock(void * dst,const void * src,size_t srcSize,compressFunc_t compress,void * lz4ctx,int level)455 static size_t LZ4F_compressBlock(void* dst, const void* src, size_t srcSize, compressFunc_t compress, void* lz4ctx, int level)
456 {
457 /* compress one block */
458 BYTE* cSizePtr = (BYTE*)dst;
459 U32 cSize;
460 cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+4), (int)(srcSize), (int)(srcSize-1), level);
461 LZ4F_writeLE32(cSizePtr, cSize);
462 if (cSize == 0) /* compression failed */
463 {
464 cSize = (U32)srcSize;
465 LZ4F_writeLE32(cSizePtr, cSize + LZ4F_BLOCKUNCOMPRESSED_FLAG);
466 memcpy(cSizePtr+4, src, srcSize);
467 }
468 return cSize + 4;
469 }
470
471
LZ4F_localLZ4_compress_limitedOutput_withState(void * ctx,const char * src,char * dst,int srcSize,int dstSize,int level)472 static int LZ4F_localLZ4_compress_limitedOutput_withState(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level)
473 {
474 (void) level;
475 return LZ4_compress_limitedOutput_withState(ctx, src, dst, srcSize, dstSize);
476 }
477
LZ4F_localLZ4_compress_limitedOutput_continue(void * ctx,const char * src,char * dst,int srcSize,int dstSize,int level)478 static int LZ4F_localLZ4_compress_limitedOutput_continue(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level)
479 {
480 (void) level;
481 return LZ4_compress_limitedOutput_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstSize);
482 }
483
LZ4F_localLZ4_compressHC_limitedOutput_continue(void * ctx,const char * src,char * dst,int srcSize,int dstSize,int level)484 static int LZ4F_localLZ4_compressHC_limitedOutput_continue(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level)
485 {
486 (void) level;
487 return LZ4_compressHC_limitedOutput_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstSize);
488 }
489
LZ4F_selectCompression(blockMode_t blockMode,U32 level)490 static compressFunc_t LZ4F_selectCompression(blockMode_t blockMode, U32 level)
491 {
492 if (level < minHClevel)
493 {
494 if (blockMode == blockIndependent) return LZ4F_localLZ4_compress_limitedOutput_withState;
495 return LZ4F_localLZ4_compress_limitedOutput_continue;
496 }
497 if (blockMode == blockIndependent) return LZ4_compressHC2_limitedOutput_withStateHC;
498 return LZ4F_localLZ4_compressHC_limitedOutput_continue;
499 }
500
LZ4F_localSaveDict(LZ4F_cctx_internal_t * cctxPtr)501 static int LZ4F_localSaveDict(LZ4F_cctx_internal_t* cctxPtr)
502 {
503 if (cctxPtr->prefs.compressionLevel < minHClevel)
504 return LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);
505 return LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);
506 }
507
508 typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus;
509
510 /* LZ4F_compressUpdate()
511 * LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.
512 * The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure compression completion even in worst case.
513 * If this condition is not respected, LZ4F_compress() will fail (result is an errorCode)
514 * You can get the minimum value of dstMaxSize by using LZ4F_compressBound()
515 * The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
516 * The result of the function is the number of bytes written into dstBuffer : it can be zero, meaning input data was just buffered.
517 * The function outputs an error code if it fails (can be tested using LZ4F_isError())
518 */
LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext,void * dstBuffer,size_t dstMaxSize,const void * srcBuffer,size_t srcSize,const LZ4F_compressOptions_t * compressOptionsPtr)519 size_t LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* compressOptionsPtr)
520 {
521 LZ4F_compressOptions_t cOptionsNull = { 0 };
522 LZ4F_cctx_internal_t* cctxPtr = (LZ4F_cctx_internal_t*)compressionContext;
523 size_t blockSize = cctxPtr->maxBlockSize;
524 const BYTE* srcPtr = (const BYTE*)srcBuffer;
525 const BYTE* const srcEnd = srcPtr + srcSize;
526 BYTE* const dstStart = (BYTE*)dstBuffer;
527 BYTE* dstPtr = dstStart;
528 LZ4F_lastBlockStatus lastBlockCompressed = notDone;
529 compressFunc_t compress;
530
531
532 if (cctxPtr->cStage != 1) return (size_t)-ERROR_GENERIC;
533 if (dstMaxSize < LZ4F_compressBound(srcSize, &(cctxPtr->prefs))) return (size_t)-ERROR_dstMaxSize_tooSmall;
534 if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull;
535
536 /* select compression function */
537 compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel);
538
539 /* complete tmp buffer */
540 if (cctxPtr->tmpInSize > 0) /* some data already within tmp buffer */
541 {
542 size_t sizeToCopy = blockSize - cctxPtr->tmpInSize;
543 if (sizeToCopy > srcSize)
544 {
545 /* add src to tmpIn buffer */
546 memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize);
547 srcPtr = srcEnd;
548 cctxPtr->tmpInSize += srcSize;
549 /* still needs some CRC */
550 }
551 else
552 {
553 /* complete tmpIn block and then compress it */
554 lastBlockCompressed = fromTmpBuffer;
555 memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, sizeToCopy);
556 srcPtr += sizeToCopy;
557
558 dstPtr += LZ4F_compressBlock(dstPtr, cctxPtr->tmpIn, blockSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
559
560 if (cctxPtr->prefs.frameInfo.blockMode==blockLinked) cctxPtr->tmpIn += blockSize;
561 cctxPtr->tmpInSize = 0;
562 }
563 }
564
565 while ((size_t)(srcEnd - srcPtr) >= blockSize)
566 {
567 /* compress full block */
568 lastBlockCompressed = fromSrcBuffer;
569 dstPtr += LZ4F_compressBlock(dstPtr, srcPtr, blockSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
570 srcPtr += blockSize;
571 }
572
573 if ((cctxPtr->prefs.autoFlush) && (srcPtr < srcEnd))
574 {
575 /* compress remaining input < blockSize */
576 lastBlockCompressed = fromSrcBuffer;
577 dstPtr += LZ4F_compressBlock(dstPtr, srcPtr, srcEnd - srcPtr, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
578 srcPtr = srcEnd;
579 }
580
581 /* preserve dictionary if necessary */
582 if ((cctxPtr->prefs.frameInfo.blockMode==blockLinked) && (lastBlockCompressed==fromSrcBuffer))
583 {
584 if (compressOptionsPtr->stableSrc)
585 {
586 cctxPtr->tmpIn = cctxPtr->tmpBuff;
587 }
588 else
589 {
590 int realDictSize = LZ4F_localSaveDict(cctxPtr);
591 if (realDictSize==0) return (size_t)-ERROR_GENERIC;
592 cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;
593 }
594 }
595
596 /* keep tmpIn within limits */
597 if ((cctxPtr->tmpIn + blockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize) /* necessarily blockLinked && lastBlockCompressed==fromTmpBuffer */
598 && !(cctxPtr->prefs.autoFlush))
599 {
600 LZ4F_localSaveDict(cctxPtr);
601 cctxPtr->tmpIn = cctxPtr->tmpBuff + 64 KB;
602 }
603
604 /* some input data left, necessarily < blockSize */
605 if (srcPtr < srcEnd)
606 {
607 /* fill tmp buffer */
608 size_t sizeToCopy = srcEnd - srcPtr;
609 memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy);
610 cctxPtr->tmpInSize = sizeToCopy;
611 }
612
613 if (cctxPtr->prefs.frameInfo.contentChecksumFlag == contentChecksumEnabled)
614 XXH32_update(&(cctxPtr->xxh), srcBuffer, (unsigned)srcSize);
615
616 return dstPtr - dstStart;
617 }
618
619
620 /* LZ4F_flush()
621 * Should you need to create compressed data immediately, without waiting for a block to be filled,
622 * you can call LZ4_flush(), which will immediately compress any remaining data stored within compressionContext.
623 * The result of the function is the number of bytes written into dstBuffer
624 * (it can be zero, this means there was no data left within compressionContext)
625 * The function outputs an error code if it fails (can be tested using LZ4F_isError())
626 * The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
627 */
LZ4F_flush(LZ4F_compressionContext_t compressionContext,void * dstBuffer,size_t dstMaxSize,const LZ4F_compressOptions_t * compressOptionsPtr)628 size_t LZ4F_flush(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr)
629 {
630 LZ4F_compressOptions_t cOptionsNull = { 0 };
631 LZ4F_cctx_internal_t* cctxPtr = (LZ4F_cctx_internal_t*)compressionContext;
632 BYTE* const dstStart = (BYTE*)dstBuffer;
633 BYTE* dstPtr = dstStart;
634 compressFunc_t compress;
635
636
637 if (cctxPtr->tmpInSize == 0) return 0; /* nothing to flush */
638 if (cctxPtr->cStage != 1) return (size_t)-ERROR_GENERIC;
639 if (dstMaxSize < (cctxPtr->tmpInSize + 16)) return (size_t)-ERROR_dstMaxSize_tooSmall;
640 if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull;
641 (void)compressOptionsPtr; /* not yet useful */
642
643 /* select compression function */
644 compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel);
645
646 /* compress tmp buffer */
647 dstPtr += LZ4F_compressBlock(dstPtr, cctxPtr->tmpIn, cctxPtr->tmpInSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
648 if (cctxPtr->prefs.frameInfo.blockMode==blockLinked) cctxPtr->tmpIn += cctxPtr->tmpInSize;
649 cctxPtr->tmpInSize = 0;
650
651 /* keep tmpIn within limits */
652 if ((cctxPtr->tmpIn + cctxPtr->maxBlockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)) /* necessarily blockLinked */
653 {
654 LZ4F_localSaveDict(cctxPtr);
655 cctxPtr->tmpIn = cctxPtr->tmpBuff + 64 KB;
656 }
657
658 return dstPtr - dstStart;
659 }
660
661
662 /* LZ4F_compressEnd()
663 * When you want to properly finish the compressed frame, just call LZ4F_compressEnd().
664 * It will flush whatever data remained within compressionContext (like LZ4_flush())
665 * but also properly finalize the frame, with an endMark and a checksum.
666 * The result of the function is the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))
667 * The function outputs an error code if it fails (can be tested using LZ4F_isError())
668 * The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
669 * compressionContext can then be used again, starting with LZ4F_compressBegin(). The preferences will remain the same.
670 */
LZ4F_compressEnd(LZ4F_compressionContext_t compressionContext,void * dstBuffer,size_t dstMaxSize,const LZ4F_compressOptions_t * compressOptionsPtr)671 size_t LZ4F_compressEnd(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr)
672 {
673 LZ4F_cctx_internal_t* cctxPtr = (LZ4F_cctx_internal_t*)compressionContext;
674 BYTE* const dstStart = (BYTE*)dstBuffer;
675 BYTE* dstPtr = dstStart;
676 size_t errorCode;
677
678 errorCode = LZ4F_flush(compressionContext, dstBuffer, dstMaxSize, compressOptionsPtr);
679 if (LZ4F_isError(errorCode)) return errorCode;
680 dstPtr += errorCode;
681
682 LZ4F_writeLE32(dstPtr, 0);
683 dstPtr+=4; /* endMark */
684
685 if (cctxPtr->prefs.frameInfo.contentChecksumFlag == contentChecksumEnabled)
686 {
687 U32 xxh = XXH32_digest(&(cctxPtr->xxh));
688 LZ4F_writeLE32(dstPtr, xxh);
689 dstPtr+=4; /* content Checksum */
690 }
691
692 cctxPtr->cStage = 0; /* state is now re-usable (with identical preferences) */
693
694 return dstPtr - dstStart;
695 }
696
697
698 /***********************************
699 * Decompression functions
700 * *********************************/
701
702 /* Resource management */
703
704 /* LZ4F_createDecompressionContext() :
705 * The first thing to do is to create a decompressionContext object, which will be used in all decompression operations.
706 * This is achieved using LZ4F_createDecompressionContext().
707 * The function will provide a pointer to a fully allocated and initialized LZ4F_decompressionContext object.
708 * If the result LZ4F_errorCode_t is not zero, there was an error during context creation.
709 * Object can release its memory using LZ4F_freeDecompressionContext();
710 */
LZ4F_createDecompressionContext(LZ4F_compressionContext_t * LZ4F_decompressionContextPtr,unsigned versionNumber)711 LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_compressionContext_t* LZ4F_decompressionContextPtr, unsigned versionNumber)
712 {
713 LZ4F_dctx_internal_t* dctxPtr;
714
715 dctxPtr = ALLOCATOR(sizeof(LZ4F_dctx_internal_t));
716 if (dctxPtr==NULL) return (LZ4F_errorCode_t)-ERROR_GENERIC;
717
718 dctxPtr->version = versionNumber;
719 *LZ4F_decompressionContextPtr = (LZ4F_compressionContext_t)dctxPtr;
720 return OK_NoError;
721 }
722
LZ4F_freeDecompressionContext(LZ4F_compressionContext_t LZ4F_decompressionContext)723 LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_compressionContext_t LZ4F_decompressionContext)
724 {
725 LZ4F_dctx_internal_t* dctxPtr = (LZ4F_dctx_internal_t*)LZ4F_decompressionContext;
726 FREEMEM(dctxPtr->tmpIn);
727 FREEMEM(dctxPtr->tmpOutBuffer);
728 FREEMEM(dctxPtr);
729 return OK_NoError;
730 }
731
732
733 /* Decompression */
734
LZ4F_decodeHeader(LZ4F_dctx_internal_t * dctxPtr,const BYTE * srcPtr,size_t srcSize)735 static size_t LZ4F_decodeHeader(LZ4F_dctx_internal_t* dctxPtr, const BYTE* srcPtr, size_t srcSize)
736 {
737 BYTE FLG, BD, HC;
738 unsigned version, blockMode, blockChecksumFlag, contentSizeFlag, contentChecksumFlag, dictFlag, blockSizeID;
739 size_t bufferNeeded;
740
741 /* need to decode header to get frameInfo */
742 if (srcSize < 7) return (size_t)-ERROR_GENERIC; /* minimal header size */
743
744 /* control magic number */
745 if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) return (size_t)-ERROR_GENERIC;
746 srcPtr += 4;
747
748 /* Flags */
749 FLG = srcPtr[0];
750 version = (FLG>>6)&_2BITS;
751 blockMode = (FLG>>5) & _1BIT;
752 blockChecksumFlag = (FLG>>4) & _1BIT;
753 contentSizeFlag = (FLG>>3) & _1BIT;
754 contentChecksumFlag = (FLG>>2) & _1BIT;
755 dictFlag = (FLG>>0) & _1BIT;
756 BD = srcPtr[1];
757 blockSizeID = (BD>>4) & _3BITS;
758
759 /* check */
760 HC = LZ4F_headerChecksum(srcPtr, 2);
761 if (HC != srcPtr[2]) return (size_t)-ERROR_GENERIC; /* Bad header checksum error */
762
763 /* validate */
764 if (version != 1) return (size_t)-ERROR_GENERIC; /* Version Number, only supported value */
765 if (blockChecksumFlag != 0) return (size_t)-ERROR_GENERIC; /* Only supported value for the time being */
766 if (contentSizeFlag != 0) return (size_t)-ERROR_GENERIC; /* Only supported value for the time being */
767 if (((FLG>>1)&_1BIT) != 0) return (size_t)-ERROR_GENERIC; /* Reserved bit */
768 if (dictFlag != 0) return (size_t)-ERROR_GENERIC; /* Only supported value for the time being */
769 if (((BD>>7)&_1BIT) != 0) return (size_t)-ERROR_GENERIC; /* Reserved bit */
770 if (blockSizeID < 4) return (size_t)-ERROR_GENERIC; /* Only supported values for the time being */
771 if (((BD>>0)&_4BITS) != 0) return (size_t)-ERROR_GENERIC; /* Reserved bits */
772
773 /* save */
774 dctxPtr->frameInfo.blockMode = blockMode;
775 dctxPtr->frameInfo.contentChecksumFlag = contentChecksumFlag;
776 dctxPtr->frameInfo.blockSizeID = blockSizeID;
777 dctxPtr->maxBlockSize = LZ4F_getBlockSize(blockSizeID);
778
779 /* init */
780 if (contentChecksumFlag) XXH32_reset(&(dctxPtr->xxh), 0);
781
782 /* alloc */
783 bufferNeeded = dctxPtr->maxBlockSize + ((dctxPtr->frameInfo.blockMode==blockLinked) * 128 KB);
784 if (bufferNeeded > dctxPtr->maxBufferSize) /* tmp buffers too small */
785 {
786 FREEMEM(dctxPtr->tmpIn);
787 FREEMEM(dctxPtr->tmpOutBuffer);
788 dctxPtr->maxBufferSize = bufferNeeded;
789 dctxPtr->tmpIn = ALLOCATOR(dctxPtr->maxBlockSize);
790 if (dctxPtr->tmpIn == NULL) return (size_t)-ERROR_GENERIC;
791 dctxPtr->tmpOutBuffer= ALLOCATOR(dctxPtr->maxBufferSize);
792 if (dctxPtr->tmpOutBuffer== NULL) return (size_t)-ERROR_GENERIC;
793 }
794 dctxPtr->tmpInSize = 0;
795 dctxPtr->tmpInTarget = 0;
796 dctxPtr->dict = dctxPtr->tmpOutBuffer;
797 dctxPtr->dictSize = 0;
798 dctxPtr->tmpOut = dctxPtr->tmpOutBuffer;
799 dctxPtr->tmpOutStart = 0;
800 dctxPtr->tmpOutSize = 0;
801
802 return 7;
803 }
804
805
806 typedef enum { dstage_getHeader=0, dstage_storeHeader, dstage_decodeHeader,
807 dstage_getCBlockSize, dstage_storeCBlockSize, dstage_decodeCBlockSize,
808 dstage_copyDirect,
809 dstage_getCBlock, dstage_storeCBlock, dstage_decodeCBlock,
810 dstage_decodeCBlock_intoDst, dstage_decodeCBlock_intoTmp, dstage_flushOut,
811 dstage_getSuffix, dstage_storeSuffix, dstage_checkSuffix
812 } dStage_t;
813
814
815 /* LZ4F_getFrameInfo()
816 * This function decodes frame header information, such as blockSize.
817 * It is optional : you could start by calling directly LZ4F_decompress() instead.
818 * The objective is to extract header information without starting decompression, typically for allocation purposes.
819 * LZ4F_getFrameInfo() can also be used *after* starting decompression, on a valid LZ4F_decompressionContext_t.
820 * The number of bytes read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
821 * You are expected to resume decompression from where it stopped (srcBuffer + *srcSizePtr)
822 * The function result is an hint of the better srcSize to use for next call to LZ4F_decompress,
823 * or an error code which can be tested using LZ4F_isError().
824 */
LZ4F_getFrameInfo(LZ4F_decompressionContext_t decompressionContext,LZ4F_frameInfo_t * frameInfoPtr,const void * srcBuffer,size_t * srcSizePtr)825 LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_decompressionContext_t decompressionContext, LZ4F_frameInfo_t* frameInfoPtr, const void* srcBuffer, size_t* srcSizePtr)
826 {
827 LZ4F_dctx_internal_t* dctxPtr = (LZ4F_dctx_internal_t*)decompressionContext;
828
829 if (dctxPtr->dStage == dstage_getHeader)
830 {
831 LZ4F_errorCode_t errorCode = LZ4F_decodeHeader(dctxPtr, srcBuffer, *srcSizePtr);
832 if (LZ4F_isError(errorCode)) return errorCode;
833 *srcSizePtr = errorCode;
834 *frameInfoPtr = dctxPtr->frameInfo;
835 dctxPtr->srcExpect = NULL;
836 dctxPtr->dStage = dstage_getCBlockSize;
837 return 4;
838 }
839
840 /* frameInfo already decoded */
841 *srcSizePtr = 0;
842 *frameInfoPtr = dctxPtr->frameInfo;
843 return 0;
844 }
845
846
LZ4F_decompress_safe(const char * source,char * dest,int compressedSize,int maxDecompressedSize,const char * dictStart,int dictSize)847 static int LZ4F_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize)
848 {
849 (void)dictStart;
850 (void)dictSize;
851 return LZ4_decompress_safe (source, dest, compressedSize, maxDecompressedSize);
852 }
853
854
855
LZ4F_updateDict(LZ4F_dctx_internal_t * dctxPtr,const BYTE * dstPtr,size_t dstSize,const BYTE * dstPtr0,unsigned withinTmp)856 static void LZ4F_updateDict(LZ4F_dctx_internal_t* dctxPtr, const BYTE* dstPtr, size_t dstSize, const BYTE* dstPtr0, unsigned withinTmp)
857 {
858 if (dctxPtr->dictSize==0)
859 dctxPtr->dict = (BYTE*)dstPtr; /* priority to dictionary continuity */
860
861 if (dctxPtr->dict + dctxPtr->dictSize == dstPtr) /* dictionary continuity */
862 {
863 dctxPtr->dictSize += dstSize;
864 return;
865 }
866
867 if (dstPtr - dstPtr0 + dstSize >= 64 KB) /* dstBuffer large enough to become dictionary */
868 {
869 dctxPtr->dict = (BYTE*)dstPtr0;
870 dctxPtr->dictSize = dstPtr - dstPtr0 + dstSize;
871 return;
872 }
873
874 if ((withinTmp) && (dctxPtr->dict == dctxPtr->tmpOutBuffer))
875 {
876 /* assumption : dctxPtr->dict + dctxPtr->dictSize == dctxPtr->tmpOut + dctxPtr->tmpOutStart */
877 dctxPtr->dictSize += dstSize;
878 return;
879 }
880
881 if (withinTmp) /* copy relevant dict portion in front of tmpOut within tmpOutBuffer */
882 {
883 #if 0
884 size_t savedDictSize = dctxPtr->tmpOut - dctxPtr->tmpOutBuffer;
885 memcpy(dctxPtr->tmpOutBuffer, dctxPtr->dict + dctxPtr->dictSize - dctxPtr->tmpOutStart- savedDictSize, savedDictSize);
886 dctxPtr->dict = dctxPtr->tmpOutBuffer;
887 dctxPtr->dictSize = savedDictSize + dctxPtr->tmpOutStart + dstSize;
888 return;
889
890 #else
891
892 size_t preserveSize = dctxPtr->tmpOut - dctxPtr->tmpOutBuffer;
893 size_t copySize = 64 KB - dctxPtr->tmpOutSize;
894 BYTE* oldDictEnd = dctxPtr->dict + dctxPtr->dictSize - dctxPtr->tmpOutStart;
895 if (dctxPtr->tmpOutSize > 64 KB) copySize = 0;
896 if (copySize > preserveSize) copySize = preserveSize;
897
898 memcpy(dctxPtr->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);
899
900 dctxPtr->dict = dctxPtr->tmpOutBuffer;
901 dctxPtr->dictSize = preserveSize + dctxPtr->tmpOutStart + dstSize;
902 return;
903 #endif
904 }
905
906 if (dctxPtr->dict == dctxPtr->tmpOutBuffer) /* copy dst into tmp to complete dict */
907 {
908 if (dctxPtr->dictSize + dstSize > dctxPtr->maxBufferSize) /* tmp buffer not large enough */
909 {
910 size_t preserveSize = 64 KB - dstSize; /* note : dstSize < 64 KB */
911 memcpy(dctxPtr->dict, dctxPtr->dict + dctxPtr->dictSize - preserveSize, preserveSize);
912 dctxPtr->dictSize = preserveSize;
913 }
914 memcpy(dctxPtr->dict + dctxPtr->dictSize, dstPtr, dstSize);
915 dctxPtr->dictSize += dstSize;
916 return;
917 }
918
919 /* join dict & dest into tmp */
920 {
921 size_t preserveSize = 64 KB - dstSize; /* note : dstSize < 64 KB */
922 if (preserveSize > dctxPtr->dictSize) preserveSize = dctxPtr->dictSize;
923 memcpy(dctxPtr->tmpOutBuffer, dctxPtr->dict + dctxPtr->dictSize - preserveSize, preserveSize);
924 memcpy(dctxPtr->tmpOutBuffer + preserveSize, dstPtr, dstSize);
925 dctxPtr->dict = dctxPtr->tmpOutBuffer;
926 dctxPtr->dictSize = preserveSize + dstSize;
927 }
928 }
929
930
931
932 /* LZ4F_decompress()
933 * Call this function repetitively to regenerate data compressed within srcBuffer.
934 * The function will attempt to decode *srcSizePtr from srcBuffer, into dstBuffer of maximum size *dstSizePtr.
935 *
936 * The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value).
937 *
938 * The number of bytes effectively read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
939 * If the number of bytes read is < number of bytes provided, then the decompression operation is not complete.
940 * You will have to call it again, continuing from where it stopped.
941 *
942 * The function result is an hint of the better srcSize to use for next call to LZ4F_decompress.
943 * Basically, it's the size of the current (or remaining) compressed block + header of next block.
944 * Respecting the hint provides some boost to performance, since it allows less buffer shuffling.
945 * Note that this is just a hint, you can always provide any srcSize you want.
946 * When a frame is fully decoded, the function result will be 0.
947 * If decompression failed, function result is an error code which can be tested using LZ4F_isError().
948 */
LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext,void * dstBuffer,size_t * dstSizePtr,const void * srcBuffer,size_t * srcSizePtr,const LZ4F_decompressOptions_t * decompressOptionsPtr)949 size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext,
950 void* dstBuffer, size_t* dstSizePtr,
951 const void* srcBuffer, size_t* srcSizePtr,
952 const LZ4F_decompressOptions_t* decompressOptionsPtr)
953 {
954 LZ4F_dctx_internal_t* dctxPtr = (LZ4F_dctx_internal_t*)decompressionContext;
955 static const LZ4F_decompressOptions_t optionsNull = { 0 };
956 const BYTE* const srcStart = (const BYTE*)srcBuffer;
957 const BYTE* const srcEnd = srcStart + *srcSizePtr;
958 const BYTE* srcPtr = srcStart;
959 BYTE* const dstStart = (BYTE*)dstBuffer;
960 BYTE* const dstEnd = dstStart + *dstSizePtr;
961 BYTE* dstPtr = dstStart;
962 const BYTE* selectedIn=NULL;
963 unsigned doAnotherStage = 1;
964 size_t nextSrcSizeHint = 1;
965
966
967 if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull;
968 *srcSizePtr = 0;
969 *dstSizePtr = 0;
970
971 /* expect to continue decoding src buffer where it left previously */
972 if (dctxPtr->srcExpect != NULL)
973 {
974 if (srcStart != dctxPtr->srcExpect) return (size_t)-ERROR_GENERIC;
975 }
976
977 /* programmed as a state machine */
978
979 while (doAnotherStage)
980 {
981
982 switch(dctxPtr->dStage)
983 {
984
985 case dstage_getHeader:
986 {
987 if (srcEnd-srcPtr >= 7)
988 {
989 selectedIn = srcPtr;
990 srcPtr += 7;
991 dctxPtr->dStage = dstage_decodeHeader;
992 break;
993 }
994 dctxPtr->tmpInSize = 0;
995 dctxPtr->dStage = dstage_storeHeader;
996 break;
997 }
998
999 case dstage_storeHeader:
1000 {
1001 size_t sizeToCopy = 7 - dctxPtr->tmpInSize;
1002 if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
1003 memcpy(dctxPtr->header + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
1004 dctxPtr->tmpInSize += sizeToCopy;
1005 srcPtr += sizeToCopy;
1006 if (dctxPtr->tmpInSize < 7)
1007 {
1008 nextSrcSizeHint = (7 - dctxPtr->tmpInSize) + 4;
1009 doAnotherStage = 0; /* no enough src, wait to get some more */
1010 break;
1011 }
1012 selectedIn = dctxPtr->header;
1013 dctxPtr->dStage = dstage_decodeHeader;
1014 break;
1015 }
1016
1017 case dstage_decodeHeader:
1018 {
1019 LZ4F_errorCode_t errorCode = LZ4F_decodeHeader(dctxPtr, selectedIn, 7);
1020 if (LZ4F_isError(errorCode)) return errorCode;
1021 dctxPtr->dStage = dstage_getCBlockSize;
1022 break;
1023 }
1024
1025 case dstage_getCBlockSize:
1026 {
1027 if ((srcEnd - srcPtr) >= 4)
1028 {
1029 selectedIn = srcPtr;
1030 srcPtr += 4;
1031 dctxPtr->dStage = dstage_decodeCBlockSize;
1032 break;
1033 }
1034 /* not enough input to read cBlockSize field */
1035 dctxPtr->tmpInSize = 0;
1036 dctxPtr->dStage = dstage_storeCBlockSize;
1037 break;
1038 }
1039
1040 case dstage_storeCBlockSize:
1041 {
1042 size_t sizeToCopy = 4 - dctxPtr->tmpInSize;
1043 if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
1044 memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
1045 srcPtr += sizeToCopy;
1046 dctxPtr->tmpInSize += sizeToCopy;
1047 if (dctxPtr->tmpInSize < 4) /* not enough input to get full cBlockSize; wait for more */
1048 {
1049 nextSrcSizeHint = 4 - dctxPtr->tmpInSize;
1050 doAnotherStage=0;
1051 break;
1052 }
1053 selectedIn = dctxPtr->tmpIn;
1054 dctxPtr->dStage = dstage_decodeCBlockSize;
1055 break;
1056 }
1057
1058 case dstage_decodeCBlockSize:
1059 {
1060 size_t nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU;
1061 if (nextCBlockSize==0) /* frameEnd signal, no more CBlock */
1062 {
1063 dctxPtr->dStage = dstage_getSuffix;
1064 break;
1065 }
1066 if (nextCBlockSize > dctxPtr->maxBlockSize) return (size_t)-ERROR_GENERIC; /* invalid cBlockSize */
1067 dctxPtr->tmpInTarget = nextCBlockSize;
1068 if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG)
1069 {
1070 dctxPtr->dStage = dstage_copyDirect;
1071 break;
1072 }
1073 dctxPtr->dStage = dstage_getCBlock;
1074 if (dstPtr==dstEnd)
1075 {
1076 nextSrcSizeHint = nextCBlockSize + 4;
1077 doAnotherStage = 0;
1078 }
1079 break;
1080 }
1081
1082 case dstage_copyDirect: /* uncompressed block */
1083 {
1084 size_t sizeToCopy = dctxPtr->tmpInTarget;
1085 if ((size_t)(srcEnd-srcPtr) < sizeToCopy) sizeToCopy = srcEnd - srcPtr; /* not enough input to read full block */
1086 if ((size_t)(dstEnd-dstPtr) < sizeToCopy) sizeToCopy = dstEnd - dstPtr;
1087 memcpy(dstPtr, srcPtr, sizeToCopy);
1088 if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), srcPtr, (U32)sizeToCopy);
1089
1090 /* dictionary management */
1091 if (dctxPtr->frameInfo.blockMode==blockLinked)
1092 LZ4F_updateDict(dctxPtr, dstPtr, sizeToCopy, dstStart, 0);
1093
1094 srcPtr += sizeToCopy;
1095 dstPtr += sizeToCopy;
1096 if (sizeToCopy == dctxPtr->tmpInTarget) /* all copied */
1097 {
1098 dctxPtr->dStage = dstage_getCBlockSize;
1099 break;
1100 }
1101 dctxPtr->tmpInTarget -= sizeToCopy; /* still need to copy more */
1102 nextSrcSizeHint = dctxPtr->tmpInTarget + 4;
1103 doAnotherStage = 0;
1104 break;
1105 }
1106
1107 case dstage_getCBlock: /* entry from dstage_decodeCBlockSize */
1108 {
1109 if ((size_t)(srcEnd-srcPtr) < dctxPtr->tmpInTarget)
1110 {
1111 dctxPtr->tmpInSize = 0;
1112 dctxPtr->dStage = dstage_storeCBlock;
1113 break;
1114 }
1115 selectedIn = srcPtr;
1116 srcPtr += dctxPtr->tmpInTarget;
1117 dctxPtr->dStage = dstage_decodeCBlock;
1118 break;
1119 }
1120
1121 case dstage_storeCBlock:
1122 {
1123 size_t sizeToCopy = dctxPtr->tmpInTarget - dctxPtr->tmpInSize;
1124 if (sizeToCopy > (size_t)(srcEnd-srcPtr)) sizeToCopy = srcEnd-srcPtr;
1125 memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
1126 dctxPtr->tmpInSize += sizeToCopy;
1127 srcPtr += sizeToCopy;
1128 if (dctxPtr->tmpInSize < dctxPtr->tmpInTarget) /* need more input */
1129 {
1130 nextSrcSizeHint = (dctxPtr->tmpInTarget - dctxPtr->tmpInSize) + 4;
1131 doAnotherStage=0;
1132 break;
1133 }
1134 selectedIn = dctxPtr->tmpIn;
1135 dctxPtr->dStage = dstage_decodeCBlock;
1136 break;
1137 }
1138
1139 case dstage_decodeCBlock:
1140 {
1141 if ((size_t)(dstEnd-dstPtr) < dctxPtr->maxBlockSize) /* not enough place into dst : decode into tmpOut */
1142 dctxPtr->dStage = dstage_decodeCBlock_intoTmp;
1143 else
1144 dctxPtr->dStage = dstage_decodeCBlock_intoDst;
1145 break;
1146 }
1147
1148 case dstage_decodeCBlock_intoDst:
1149 {
1150 int (*decoder)(const char*, char*, int, int, const char*, int);
1151 int decodedSize;
1152
1153 if (dctxPtr->frameInfo.blockMode == blockLinked)
1154 decoder = LZ4_decompress_safe_usingDict;
1155 else
1156 decoder = LZ4F_decompress_safe;
1157
1158 decodedSize = decoder((const char*)selectedIn, (char*)dstPtr, (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize, (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
1159 if (decodedSize < 0) return (size_t)-ERROR_GENERIC; /* decompression failed */
1160 if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dstPtr, decodedSize);
1161
1162 /* dictionary management */
1163 if (dctxPtr->frameInfo.blockMode==blockLinked)
1164 LZ4F_updateDict(dctxPtr, dstPtr, decodedSize, dstStart, 0);
1165
1166 dstPtr += decodedSize;
1167 dctxPtr->dStage = dstage_getCBlockSize;
1168 break;
1169 }
1170
1171 case dstage_decodeCBlock_intoTmp:
1172 {
1173 /* not enough place into dst : decode into tmpOut */
1174 int (*decoder)(const char*, char*, int, int, const char*, int);
1175 int decodedSize;
1176
1177 if (dctxPtr->frameInfo.blockMode == blockLinked)
1178 decoder = LZ4_decompress_safe_usingDict;
1179 else
1180 decoder = LZ4F_decompress_safe;
1181
1182 /* ensure enough place for tmpOut */
1183 if (dctxPtr->frameInfo.blockMode == blockLinked)
1184 {
1185 if (dctxPtr->dict == dctxPtr->tmpOutBuffer)
1186 {
1187 if (dctxPtr->dictSize > 128 KB)
1188 {
1189 memcpy(dctxPtr->dict, dctxPtr->dict + dctxPtr->dictSize - 64 KB, 64 KB);
1190 dctxPtr->dictSize = 64 KB;
1191 }
1192 dctxPtr->tmpOut = dctxPtr->dict + dctxPtr->dictSize;
1193 }
1194 else /* dict not within tmp */
1195 {
1196 size_t reservedDictSpace = dctxPtr->dictSize;
1197 if (reservedDictSpace > 64 KB) reservedDictSpace = 64 KB;
1198 dctxPtr->tmpOut = dctxPtr->tmpOutBuffer + reservedDictSpace;
1199 }
1200 }
1201
1202 /* Decode */
1203 decodedSize = decoder((const char*)selectedIn, (char*)dctxPtr->tmpOut, (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize, (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
1204 if (decodedSize < 0) return (size_t)-ERROR_decompressionFailed; /* decompression failed */
1205 if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dctxPtr->tmpOut, decodedSize);
1206 dctxPtr->tmpOutSize = decodedSize;
1207 dctxPtr->tmpOutStart = 0;
1208 dctxPtr->dStage = dstage_flushOut;
1209 break;
1210 }
1211
1212 case dstage_flushOut: /* flush decoded data from tmpOut to dstBuffer */
1213 {
1214 size_t sizeToCopy = dctxPtr->tmpOutSize - dctxPtr->tmpOutStart;
1215 if (sizeToCopy > (size_t)(dstEnd-dstPtr)) sizeToCopy = dstEnd-dstPtr;
1216 memcpy(dstPtr, dctxPtr->tmpOut + dctxPtr->tmpOutStart, sizeToCopy);
1217
1218 /* dictionary management */
1219 if (dctxPtr->frameInfo.blockMode==blockLinked)
1220 LZ4F_updateDict(dctxPtr, dstPtr, sizeToCopy, dstStart, 1);
1221
1222 dctxPtr->tmpOutStart += sizeToCopy;
1223 dstPtr += sizeToCopy;
1224
1225 /* end of flush ? */
1226 if (dctxPtr->tmpOutStart == dctxPtr->tmpOutSize)
1227 {
1228 dctxPtr->dStage = dstage_getCBlockSize;
1229 break;
1230 }
1231 nextSrcSizeHint = 4;
1232 doAnotherStage = 0; /* still some data to flush */
1233 break;
1234 }
1235
1236 case dstage_getSuffix:
1237 {
1238 size_t suffixSize = dctxPtr->frameInfo.contentChecksumFlag * 4;
1239 if (suffixSize == 0) /* frame completed */
1240 {
1241 nextSrcSizeHint = 0;
1242 dctxPtr->dStage = dstage_getHeader;
1243 doAnotherStage = 0;
1244 break;
1245 }
1246 if ((srcEnd - srcPtr) >= 4) /* CRC present */
1247 {
1248 selectedIn = srcPtr;
1249 srcPtr += 4;
1250 dctxPtr->dStage = dstage_checkSuffix;
1251 break;
1252 }
1253 dctxPtr->tmpInSize = 0;
1254 dctxPtr->dStage = dstage_storeSuffix;
1255 break;
1256 }
1257
1258 case dstage_storeSuffix:
1259 {
1260 size_t sizeToCopy = 4 - dctxPtr->tmpInSize;
1261 if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
1262 memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
1263 srcPtr += sizeToCopy;
1264 dctxPtr->tmpInSize += sizeToCopy;
1265 if (dctxPtr->tmpInSize < 4) /* not enough input to read complete suffix */
1266 {
1267 nextSrcSizeHint = 4 - dctxPtr->tmpInSize;
1268 doAnotherStage=0;
1269 break;
1270 }
1271 selectedIn = dctxPtr->tmpIn;
1272 dctxPtr->dStage = dstage_checkSuffix;
1273 break;
1274 }
1275
1276 case dstage_checkSuffix:
1277 {
1278 U32 readCRC = LZ4F_readLE32(selectedIn);
1279 U32 resultCRC = XXH32_digest(&(dctxPtr->xxh));
1280 if (readCRC != resultCRC) return (size_t)-ERROR_checksum_invalid;
1281 nextSrcSizeHint = 0;
1282 dctxPtr->dStage = dstage_getHeader;
1283 doAnotherStage = 0;
1284 break;
1285 }
1286 }
1287 }
1288
1289 /* preserve dictionary within tmp if necessary */
1290 if ( (dctxPtr->frameInfo.blockMode==blockLinked)
1291 &&(dctxPtr->dict != dctxPtr->tmpOutBuffer)
1292 &&(!decompressOptionsPtr->stableDst)
1293 &&((unsigned)(dctxPtr->dStage-1) < (unsigned)(dstage_getSuffix-1))
1294 )
1295 {
1296 if (dctxPtr->dStage == dstage_flushOut)
1297 {
1298 size_t preserveSize = dctxPtr->tmpOut - dctxPtr->tmpOutBuffer;
1299 size_t copySize = 64 KB - dctxPtr->tmpOutSize;
1300 BYTE* oldDictEnd = dctxPtr->dict + dctxPtr->dictSize - dctxPtr->tmpOutStart;
1301 if (dctxPtr->tmpOutSize > 64 KB) copySize = 0;
1302 if (copySize > preserveSize) copySize = preserveSize;
1303
1304 memcpy(dctxPtr->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);
1305
1306 dctxPtr->dict = dctxPtr->tmpOutBuffer;
1307 dctxPtr->dictSize = preserveSize + dctxPtr->tmpOutStart;
1308 }
1309 else
1310 {
1311 size_t newDictSize = dctxPtr->dictSize;
1312 BYTE* oldDictEnd = dctxPtr->dict + dctxPtr->dictSize;
1313 if ((newDictSize) > 64 KB) newDictSize = 64 KB;
1314
1315 memcpy(dctxPtr->tmpOutBuffer, oldDictEnd - newDictSize, newDictSize);
1316
1317 dctxPtr->dict = dctxPtr->tmpOutBuffer;
1318 dctxPtr->dictSize = newDictSize;
1319 dctxPtr->tmpOut = dctxPtr->tmpOutBuffer + newDictSize;
1320 }
1321 }
1322
1323 if (srcPtr<srcEnd) /* function must be called again with following source data */
1324 dctxPtr->srcExpect = srcPtr;
1325 else
1326 dctxPtr->srcExpect = NULL;
1327 *srcSizePtr = (srcPtr - srcStart);
1328 *dstSizePtr = (dstPtr - dstStart);
1329 return nextSrcSizeHint;
1330 }
1331