File Coverage

lz4frame.c
Criterion Covered Total %
statement 428 786 54.4
branch 135 366 36.8
condition n/a
subroutine n/a
pod n/a
total 563 1152 48.8


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