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