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