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