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