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