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