1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330 |
- /*
- LZ4 auto-framing library
- Copyright (C) 2011-2014, Yann Collet.
- BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following disclaimer
- in the documentation and/or other materials provided with the
- distribution.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- You can contact the author at :
- - LZ4 source repository : http://code.google.com/p/lz4/
- - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
- */
- /* LZ4F is a stand-alone API to create LZ4-compressed Frames
- * fully conformant to specification v1.4.1.
- * All related operations, including memory management, are handled by the library.
- * */
- /**************************************
- Compiler Options
- **************************************/
- #ifdef _MSC_VER /* Visual Studio */
- # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
- #endif
- #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
- #ifdef __GNUC__
- # 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) */
- # 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) */
- #endif
- /**************************************
- Memory routines
- **************************************/
- #include <stdlib.h> /* malloc, calloc, free */
- #define ALLOCATOR(s) calloc(1,s)
- #define FREEMEM free
- #include <string.h> /* memset, memcpy, memmove */
- #define MEM_INIT memset
- /**************************************
- Includes
- **************************************/
- #include "lz4frame_static.h"
- #include "lz4.h"
- #include "lz4hc.h"
- #include "xxhash.h"
- /**************************************
- Basic Types
- **************************************/
- #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
- # include <stdint.h>
- typedef uint8_t BYTE;
- typedef uint16_t U16;
- typedef uint32_t U32;
- typedef int32_t S32;
- typedef uint64_t U64;
- #else
- typedef unsigned char BYTE;
- typedef unsigned short U16;
- typedef unsigned int U32;
- typedef signed int S32;
- typedef unsigned long long U64;
- #endif
- /**************************************
- Constants
- **************************************/
- #define KB *(1<<10)
- #define MB *(1<<20)
- #define GB *(1<<30)
- #define _1BIT 0x01
- #define _2BITS 0x03
- #define _3BITS 0x07
- #define _4BITS 0x0F
- #define _8BITS 0xFF
- #define LZ4F_MAGICNUMBER 0x184D2204U
- #define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U
- #define LZ4F_MAXHEADERFRAME_SIZE 7
- #define LZ4F_BLOCKSIZEID_DEFAULT max64KB
- static const U32 minHClevel = 3;
- /**************************************
- Structures and local types
- **************************************/
- typedef struct
- {
- LZ4F_preferences_t prefs;
- U32 version;
- U32 cStage;
- size_t maxBlockSize;
- size_t maxBufferSize;
- BYTE* tmpBuff;
- BYTE* tmpIn;
- size_t tmpInSize;
- XXH32_state_t xxh;
- void* lz4CtxPtr;
- U32 lz4CtxLevel; /* 0: unallocated; 1: LZ4_stream_t; 3: LZ4_streamHC_t */
- } LZ4F_cctx_internal_t;
- typedef struct
- {
- LZ4F_frameInfo_t frameInfo;
- unsigned version;
- unsigned dStage;
- size_t maxBlockSize;
- size_t maxBufferSize;
- const BYTE* srcExpect;
- BYTE* tmpIn;
- size_t tmpInSize;
- size_t tmpInTarget;
- BYTE* tmpOutBuffer;
- BYTE* dict;
- size_t dictSize;
- BYTE* tmpOut;
- size_t tmpOutSize;
- size_t tmpOutStart;
- XXH32_state_t xxh;
- BYTE header[8];
- } LZ4F_dctx_internal_t;
- /**************************************
- Macros
- **************************************/
- /**************************************
- Error management
- **************************************/
- #define LZ4F_GENERATE_STRING(STRING) #STRING,
- static const char* LZ4F_errorStrings[] = { LZ4F_LIST_ERRORS(LZ4F_GENERATE_STRING) };
- U32 LZ4F_isError(LZ4F_errorCode_t code)
- {
- return (code > (LZ4F_errorCode_t)(-ERROR_maxCode));
- }
- const char* LZ4F_getErrorName(LZ4F_errorCode_t code)
- {
- static const char* codeError = "Unspecified error code";
- if (LZ4F_isError(code)) return LZ4F_errorStrings[-(int)(code)];
- return codeError;
- }
- /**************************************
- Private functions
- **************************************/
- static size_t LZ4F_getBlockSize(unsigned blockSizeID)
- {
- static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB };
- if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;
- blockSizeID -= 4;
- if (blockSizeID > 3) return (size_t)-ERROR_maxBlockSize_invalid;
- return blockSizes[blockSizeID];
- }
- /* unoptimized version; solves endianess & alignment issues */
- static void LZ4F_writeLE32 (BYTE* dstPtr, U32 value32)
- {
- dstPtr[0] = (BYTE)value32;
- dstPtr[1] = (BYTE)(value32 >> 8);
- dstPtr[2] = (BYTE)(value32 >> 16);
- dstPtr[3] = (BYTE)(value32 >> 24);
- }
- static U32 LZ4F_readLE32 (const BYTE* srcPtr)
- {
- U32 value32 = srcPtr[0];
- value32 += (srcPtr[1]<<8);
- value32 += (srcPtr[2]<<16);
- value32 += (srcPtr[3]<<24);
- return value32;
- }
- static BYTE LZ4F_headerChecksum (const BYTE* header, size_t length)
- {
- U32 xxh = XXH32(header, (U32)length, 0);
- return (BYTE)(xxh >> 8);
- }
- /**************************************
- Simple compression functions
- **************************************/
- size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
- {
- LZ4F_preferences_t prefs = { 0 };
- size_t headerSize;
- size_t streamSize;
- if (preferencesPtr!=NULL) prefs = *preferencesPtr;
- {
- blockSizeID_t proposedBSID = max64KB;
- size_t maxBlockSize = 64 KB;
- while (prefs.frameInfo.blockSizeID > proposedBSID)
- {
- if (srcSize <= maxBlockSize)
- {
- prefs.frameInfo.blockSizeID = proposedBSID;
- break;
- }
- proposedBSID++;
- maxBlockSize <<= 2;
- }
- }
- prefs.autoFlush = 1;
- headerSize = 7; /* basic header size (no option) including magic number */
- streamSize = LZ4F_compressBound(srcSize, &prefs);
- return headerSize + streamSize;
- }
- /* LZ4F_compressFrame()
- * Compress an entire srcBuffer into a valid LZ4 frame, as defined by specification v1.4.1, in a single step.
- * The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure compression completion even in worst case.
- * You can get the minimum value of dstMaxSize by using LZ4F_compressFrameBound()
- * If this condition is not respected, LZ4F_compressFrame() will fail (result is an errorCode)
- * The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will be set to default.
- * The result of the function is the number of bytes written into dstBuffer.
- * The function outputs an error code if it fails (can be tested using LZ4F_isError())
- */
- size_t LZ4F_compressFrame(void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
- {
- LZ4F_cctx_internal_t cctxI = { 0 }; /* works because no allocation */
- LZ4F_preferences_t prefs = { 0 };
- LZ4F_compressOptions_t options = { 0 };
- LZ4F_errorCode_t errorCode;
- BYTE* const dstStart = (BYTE*) dstBuffer;
- BYTE* dstPtr = dstStart;
- BYTE* const dstEnd = dstStart + dstMaxSize;
- cctxI.version = LZ4F_VERSION;
- cctxI.maxBufferSize = 5 MB; /* mess with real buffer size to prevent allocation; works because autoflush==1 & stableSrc==1 */
- if (preferencesPtr!=NULL) prefs = *preferencesPtr;
- {
- blockSizeID_t proposedBSID = max64KB;
- size_t maxBlockSize = 64 KB;
- while (prefs.frameInfo.blockSizeID > proposedBSID)
- {
- if (srcSize <= maxBlockSize)
- {
- prefs.frameInfo.blockSizeID = proposedBSID;
- break;
- }
- proposedBSID++;
- maxBlockSize <<= 2;
- }
- }
- prefs.autoFlush = 1;
- if (srcSize <= LZ4F_getBlockSize(prefs.frameInfo.blockSizeID))
- prefs.frameInfo.blockMode = blockIndependent; /* no need for linked blocks */
- options.stableSrc = 1;
- if (dstMaxSize < LZ4F_compressFrameBound(srcSize, &prefs))
- return (size_t)-ERROR_dstMaxSize_tooSmall;
- errorCode = LZ4F_compressBegin(&cctxI, dstBuffer, dstMaxSize, &prefs); /* write header */
- if (LZ4F_isError(errorCode)) return errorCode;
- dstPtr += errorCode; /* header size */
- dstMaxSize -= errorCode;
- errorCode = LZ4F_compressUpdate(&cctxI, dstPtr, dstMaxSize, srcBuffer, srcSize, &options);
- if (LZ4F_isError(errorCode)) return errorCode;
- dstPtr += errorCode;
- errorCode = LZ4F_compressEnd(&cctxI, dstPtr, dstEnd-dstPtr, &options); /* flush last block, and generate suffix */
- if (LZ4F_isError(errorCode)) return errorCode;
- dstPtr += errorCode;
- FREEMEM(cctxI.lz4CtxPtr);
- return (dstPtr - dstStart);
- }
- /***********************************
- * Advanced compression functions
- * *********************************/
- /* LZ4F_createCompressionContext() :
- * The first thing to do is to create a compressionContext object, which will be used in all compression operations.
- * This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure.
- * The version provided MUST be LZ4F_VERSION. It is intended to track potential version differences between different binaries.
- * The function will provide a pointer to an allocated LZ4F_compressionContext_t object.
- * If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation.
- * Object can release its memory using LZ4F_freeCompressionContext();
- */
- LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* LZ4F_compressionContextPtr, unsigned version)
- {
- LZ4F_cctx_internal_t* cctxPtr;
- cctxPtr = (LZ4F_cctx_internal_t*)ALLOCATOR(sizeof(LZ4F_cctx_internal_t));
- if (cctxPtr==NULL) return (LZ4F_errorCode_t)(-ERROR_allocation_failed);
- cctxPtr->version = version;
- cctxPtr->cStage = 0; /* Next stage : write header */
- *LZ4F_compressionContextPtr = (LZ4F_compressionContext_t)cctxPtr;
- return OK_NoError;
- }
- LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_compressionContext)
- {
- LZ4F_cctx_internal_t* cctxPtr = (LZ4F_cctx_internal_t*)LZ4F_compressionContext;
- FREEMEM(cctxPtr->lz4CtxPtr);
- FREEMEM(cctxPtr->tmpBuff);
- FREEMEM(LZ4F_compressionContext);
- return OK_NoError;
- }
- /* LZ4F_compressBegin() :
- * will write the frame header into dstBuffer.
- * dstBuffer must be large enough to accommodate a header (dstMaxSize). Maximum header size is LZ4F_MAXHEADERFRAME_SIZE bytes.
- * The result of the function is the number of bytes written into dstBuffer for the header
- * or an error code (can be tested using LZ4F_isError())
- */
- size_t LZ4F_compressBegin(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_preferences_t* preferencesPtr)
- {
- LZ4F_preferences_t prefNull = { 0 };
- LZ4F_cctx_internal_t* cctxPtr = (LZ4F_cctx_internal_t*)compressionContext;
- BYTE* const dstStart = (BYTE*)dstBuffer;
- BYTE* dstPtr = dstStart;
- BYTE* headerStart;
- size_t requiredBuffSize;
- if (dstMaxSize < LZ4F_MAXHEADERFRAME_SIZE) return (size_t)-ERROR_dstMaxSize_tooSmall;
- if (cctxPtr->cStage != 0) return (size_t)-ERROR_GENERIC;
- if (preferencesPtr == NULL) preferencesPtr = &prefNull;
- cctxPtr->prefs = *preferencesPtr;
- /* ctx Management */
- {
- U32 targetCtxLevel = cctxPtr->prefs.compressionLevel<minHClevel ? 1 : 2;
- if (cctxPtr->lz4CtxLevel < targetCtxLevel)
- {
- FREEMEM(cctxPtr->lz4CtxPtr);
- if (cctxPtr->prefs.compressionLevel<minHClevel)
- cctxPtr->lz4CtxPtr = (void*)LZ4_createStream();
- else
- cctxPtr->lz4CtxPtr = (void*)LZ4_createStreamHC();
- cctxPtr->lz4CtxLevel = targetCtxLevel;
- }
- }
- /* Buffer Management */
- if (cctxPtr->prefs.frameInfo.blockSizeID == 0) cctxPtr->prefs.frameInfo.blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;
- cctxPtr->maxBlockSize = LZ4F_getBlockSize(cctxPtr->prefs.frameInfo.blockSizeID);
- requiredBuffSize = cctxPtr->maxBlockSize + ((cctxPtr->prefs.frameInfo.blockMode == blockLinked) * 128 KB);
- if (preferencesPtr->autoFlush)
- requiredBuffSize = (cctxPtr->prefs.frameInfo.blockMode == blockLinked) * 64 KB; /* just needs dict */
- if (cctxPtr->maxBufferSize < requiredBuffSize)
- {
- cctxPtr->maxBufferSize = requiredBuffSize;
- FREEMEM(cctxPtr->tmpBuff);
- cctxPtr->tmpBuff = (BYTE*)ALLOCATOR(requiredBuffSize);
- if (cctxPtr->tmpBuff == NULL) return (size_t)-ERROR_allocation_failed;
- }
- cctxPtr->tmpIn = cctxPtr->tmpBuff;
- cctxPtr->tmpInSize = 0;
- XXH32_reset(&(cctxPtr->xxh), 0);
- if (cctxPtr->prefs.compressionLevel<minHClevel)
- LZ4_resetStream((LZ4_stream_t*)(cctxPtr->lz4CtxPtr));
- else
- LZ4_resetStreamHC((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), cctxPtr->prefs.compressionLevel);
- /* Magic Number */
- LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER);
- dstPtr += 4;
- headerStart = dstPtr;
- /* FLG Byte */
- *dstPtr++ = ((1 & _2BITS) << 6) /* Version('01') */
- + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5) /* Block mode */
- + (char)((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2); /* Stream checksum */
- /* BD Byte */
- *dstPtr++ = (char)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4);
- /* CRC Byte */
- *dstPtr++ = LZ4F_headerChecksum(headerStart, 2);
- cctxPtr->cStage = 1; /* header written, wait for data block */
- return (dstPtr - dstStart);
- }
- /* LZ4F_compressBound() : gives the size of Dst buffer given a srcSize to handle worst case situations.
- * The LZ4F_frameInfo_t structure is optional :
- * you can provide NULL as argument, all preferences will then be set to default.
- * */
- size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
- {
- const LZ4F_preferences_t prefsNull = { 0 };
- const LZ4F_preferences_t* prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr;
- blockSizeID_t bid = prefsPtr->frameInfo.blockSizeID;
- size_t blockSize = LZ4F_getBlockSize(bid);
- unsigned nbBlocks = (unsigned)(srcSize / blockSize) + 1;
- size_t lastBlockSize = prefsPtr->autoFlush ? srcSize % blockSize : blockSize;
- size_t blockInfo = 4; /* default, without block CRC option */
- size_t frameEnd = 4 + (prefsPtr->frameInfo.contentChecksumFlag*4);
- size_t result = (blockInfo * nbBlocks) + (blockSize * (nbBlocks-1)) + lastBlockSize + frameEnd;
- return result;
- }
- typedef int (*compressFunc_t)(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level);
- static size_t LZ4F_compressBlock(void* dst, const void* src, size_t srcSize, compressFunc_t compress, void* lz4ctx, int level)
- {
- /* compress one block */
- BYTE* cSizePtr = (BYTE*)dst;
- U32 cSize;
- cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+4), (int)(srcSize), (int)(srcSize-1), level);
- LZ4F_writeLE32(cSizePtr, cSize);
- if (cSize == 0) /* compression failed */
- {
- cSize = (U32)srcSize;
- LZ4F_writeLE32(cSizePtr, cSize + LZ4F_BLOCKUNCOMPRESSED_FLAG);
- memcpy(cSizePtr+4, src, srcSize);
- }
- return cSize + 4;
- }
- static int LZ4F_localLZ4_compress_limitedOutput_withState(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level)
- {
- (void) level;
- return LZ4_compress_limitedOutput_withState(ctx, src, dst, srcSize, dstSize);
- }
- static int LZ4F_localLZ4_compress_limitedOutput_continue(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level)
- {
- (void) level;
- return LZ4_compress_limitedOutput_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstSize);
- }
- static int LZ4F_localLZ4_compressHC_limitedOutput_continue(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level)
- {
- (void) level;
- return LZ4_compressHC_limitedOutput_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstSize);
- }
- static compressFunc_t LZ4F_selectCompression(blockMode_t blockMode, U32 level)
- {
- if (level < minHClevel)
- {
- if (blockMode == blockIndependent) return LZ4F_localLZ4_compress_limitedOutput_withState;
- return LZ4F_localLZ4_compress_limitedOutput_continue;
- }
- if (blockMode == blockIndependent) return LZ4_compressHC2_limitedOutput_withStateHC;
- return LZ4F_localLZ4_compressHC_limitedOutput_continue;
- }
- static int LZ4F_localSaveDict(LZ4F_cctx_internal_t* cctxPtr)
- {
- if (cctxPtr->prefs.compressionLevel < minHClevel)
- return LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);
- return LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);
- }
- typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus;
- /* LZ4F_compressUpdate()
- * LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.
- * The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure compression completion even in worst case.
- * If this condition is not respected, LZ4F_compress() will fail (result is an errorCode)
- * You can get the minimum value of dstMaxSize by using LZ4F_compressBound()
- * The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
- * The result of the function is the number of bytes written into dstBuffer : it can be zero, meaning input data was just buffered.
- * The function outputs an error code if it fails (can be tested using LZ4F_isError())
- */
- size_t LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* compressOptionsPtr)
- {
- LZ4F_compressOptions_t cOptionsNull = { 0 };
- LZ4F_cctx_internal_t* cctxPtr = (LZ4F_cctx_internal_t*)compressionContext;
- size_t blockSize = cctxPtr->maxBlockSize;
- const BYTE* srcPtr = (const BYTE*)srcBuffer;
- const BYTE* const srcEnd = srcPtr + srcSize;
- BYTE* const dstStart = (BYTE*)dstBuffer;
- BYTE* dstPtr = dstStart;
- LZ4F_lastBlockStatus lastBlockCompressed = notDone;
- compressFunc_t compress;
- if (cctxPtr->cStage != 1) return (size_t)-ERROR_GENERIC;
- if (dstMaxSize < LZ4F_compressBound(srcSize, &(cctxPtr->prefs))) return (size_t)-ERROR_dstMaxSize_tooSmall;
- if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull;
- /* select compression function */
- compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel);
- /* complete tmp buffer */
- if (cctxPtr->tmpInSize > 0) /* some data already within tmp buffer */
- {
- size_t sizeToCopy = blockSize - cctxPtr->tmpInSize;
- if (sizeToCopy > srcSize)
- {
- /* add src to tmpIn buffer */
- memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize);
- srcPtr = srcEnd;
- cctxPtr->tmpInSize += srcSize;
- /* still needs some CRC */
- }
- else
- {
- /* complete tmpIn block and then compress it */
- lastBlockCompressed = fromTmpBuffer;
- memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, sizeToCopy);
- srcPtr += sizeToCopy;
- dstPtr += LZ4F_compressBlock(dstPtr, cctxPtr->tmpIn, blockSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
- if (cctxPtr->prefs.frameInfo.blockMode==blockLinked) cctxPtr->tmpIn += blockSize;
- cctxPtr->tmpInSize = 0;
- }
- }
- while ((size_t)(srcEnd - srcPtr) >= blockSize)
- {
- /* compress full block */
- lastBlockCompressed = fromSrcBuffer;
- dstPtr += LZ4F_compressBlock(dstPtr, srcPtr, blockSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
- srcPtr += blockSize;
- }
- if ((cctxPtr->prefs.autoFlush) && (srcPtr < srcEnd))
- {
- /* compress remaining input < blockSize */
- lastBlockCompressed = fromSrcBuffer;
- dstPtr += LZ4F_compressBlock(dstPtr, srcPtr, srcEnd - srcPtr, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
- srcPtr = srcEnd;
- }
- /* preserve dictionary if necessary */
- if ((cctxPtr->prefs.frameInfo.blockMode==blockLinked) && (lastBlockCompressed==fromSrcBuffer))
- {
- if (compressOptionsPtr->stableSrc)
- {
- cctxPtr->tmpIn = cctxPtr->tmpBuff;
- }
- else
- {
- int realDictSize = LZ4F_localSaveDict(cctxPtr);
- if (realDictSize==0) return (size_t)-ERROR_GENERIC;
- cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;
- }
- }
- /* keep tmpIn within limits */
- if ((cctxPtr->tmpIn + blockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize) /* necessarily blockLinked && lastBlockCompressed==fromTmpBuffer */
- && !(cctxPtr->prefs.autoFlush))
- {
- LZ4F_localSaveDict(cctxPtr);
- cctxPtr->tmpIn = cctxPtr->tmpBuff + 64 KB;
- }
- /* some input data left, necessarily < blockSize */
- if (srcPtr < srcEnd)
- {
- /* fill tmp buffer */
- size_t sizeToCopy = srcEnd - srcPtr;
- memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy);
- cctxPtr->tmpInSize = sizeToCopy;
- }
- if (cctxPtr->prefs.frameInfo.contentChecksumFlag == contentChecksumEnabled)
- XXH32_update(&(cctxPtr->xxh), srcBuffer, (unsigned)srcSize);
- return dstPtr - dstStart;
- }
- /* LZ4F_flush()
- * Should you need to create compressed data immediately, without waiting for a block to be filled,
- * you can call LZ4_flush(), which will immediately compress any remaining data stored within compressionContext.
- * The result of the function is the number of bytes written into dstBuffer
- * (it can be zero, this means there was no data left within compressionContext)
- * The function outputs an error code if it fails (can be tested using LZ4F_isError())
- * The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
- */
- size_t LZ4F_flush(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr)
- {
- LZ4F_compressOptions_t cOptionsNull = { 0 };
- LZ4F_cctx_internal_t* cctxPtr = (LZ4F_cctx_internal_t*)compressionContext;
- BYTE* const dstStart = (BYTE*)dstBuffer;
- BYTE* dstPtr = dstStart;
- compressFunc_t compress;
- if (cctxPtr->tmpInSize == 0) return 0; /* nothing to flush */
- if (cctxPtr->cStage != 1) return (size_t)-ERROR_GENERIC;
- if (dstMaxSize < (cctxPtr->tmpInSize + 16)) return (size_t)-ERROR_dstMaxSize_tooSmall;
- if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull;
- (void)compressOptionsPtr; /* not yet useful */
- /* select compression function */
- compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel);
- /* compress tmp buffer */
- dstPtr += LZ4F_compressBlock(dstPtr, cctxPtr->tmpIn, cctxPtr->tmpInSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);
- if (cctxPtr->prefs.frameInfo.blockMode==blockLinked) cctxPtr->tmpIn += cctxPtr->tmpInSize;
- cctxPtr->tmpInSize = 0;
- /* keep tmpIn within limits */
- if ((cctxPtr->tmpIn + cctxPtr->maxBlockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)) /* necessarily blockLinked */
- {
- LZ4F_localSaveDict(cctxPtr);
- cctxPtr->tmpIn = cctxPtr->tmpBuff + 64 KB;
- }
- return dstPtr - dstStart;
- }
- /* LZ4F_compressEnd()
- * When you want to properly finish the compressed frame, just call LZ4F_compressEnd().
- * It will flush whatever data remained within compressionContext (like LZ4_flush())
- * but also properly finalize the frame, with an endMark and a checksum.
- * The result of the function is the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))
- * The function outputs an error code if it fails (can be tested using LZ4F_isError())
- * The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
- * compressionContext can then be used again, starting with LZ4F_compressBegin(). The preferences will remain the same.
- */
- size_t LZ4F_compressEnd(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr)
- {
- LZ4F_cctx_internal_t* cctxPtr = (LZ4F_cctx_internal_t*)compressionContext;
- BYTE* const dstStart = (BYTE*)dstBuffer;
- BYTE* dstPtr = dstStart;
- size_t errorCode;
- errorCode = LZ4F_flush(compressionContext, dstBuffer, dstMaxSize, compressOptionsPtr);
- if (LZ4F_isError(errorCode)) return errorCode;
- dstPtr += errorCode;
- LZ4F_writeLE32(dstPtr, 0);
- dstPtr+=4; /* endMark */
- if (cctxPtr->prefs.frameInfo.contentChecksumFlag == contentChecksumEnabled)
- {
- U32 xxh = XXH32_digest(&(cctxPtr->xxh));
- LZ4F_writeLE32(dstPtr, xxh);
- dstPtr+=4; /* content Checksum */
- }
- cctxPtr->cStage = 0; /* state is now re-usable (with identical preferences) */
- return dstPtr - dstStart;
- }
- /***********************************
- * Decompression functions
- * *********************************/
- /* Resource management */
- /* LZ4F_createDecompressionContext() :
- * The first thing to do is to create a decompressionContext object, which will be used in all decompression operations.
- * This is achieved using LZ4F_createDecompressionContext().
- * The function will provide a pointer to a fully allocated and initialized LZ4F_decompressionContext object.
- * If the result LZ4F_errorCode_t is not zero, there was an error during context creation.
- * Object can release its memory using LZ4F_freeDecompressionContext();
- */
- LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_compressionContext_t* LZ4F_decompressionContextPtr, unsigned versionNumber)
- {
- LZ4F_dctx_internal_t* dctxPtr;
- dctxPtr = ALLOCATOR(sizeof(LZ4F_dctx_internal_t));
- if (dctxPtr==NULL) return (LZ4F_errorCode_t)-ERROR_GENERIC;
- dctxPtr->version = versionNumber;
- *LZ4F_decompressionContextPtr = (LZ4F_compressionContext_t)dctxPtr;
- return OK_NoError;
- }
- LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_compressionContext_t LZ4F_decompressionContext)
- {
- LZ4F_dctx_internal_t* dctxPtr = (LZ4F_dctx_internal_t*)LZ4F_decompressionContext;
- FREEMEM(dctxPtr->tmpIn);
- FREEMEM(dctxPtr->tmpOutBuffer);
- FREEMEM(dctxPtr);
- return OK_NoError;
- }
- /* Decompression */
- static size_t LZ4F_decodeHeader(LZ4F_dctx_internal_t* dctxPtr, const BYTE* srcPtr, size_t srcSize)
- {
- BYTE FLG, BD, HC;
- unsigned version, blockMode, blockChecksumFlag, contentSizeFlag, contentChecksumFlag, dictFlag, blockSizeID;
- size_t bufferNeeded;
- /* need to decode header to get frameInfo */
- if (srcSize < 7) return (size_t)-ERROR_GENERIC; /* minimal header size */
- /* control magic number */
- if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) return (size_t)-ERROR_GENERIC;
- srcPtr += 4;
- /* Flags */
- FLG = srcPtr[0];
- version = (FLG>>6)&_2BITS;
- blockMode = (FLG>>5) & _1BIT;
- blockChecksumFlag = (FLG>>4) & _1BIT;
- contentSizeFlag = (FLG>>3) & _1BIT;
- contentChecksumFlag = (FLG>>2) & _1BIT;
- dictFlag = (FLG>>0) & _1BIT;
- BD = srcPtr[1];
- blockSizeID = (BD>>4) & _3BITS;
- /* check */
- HC = LZ4F_headerChecksum(srcPtr, 2);
- if (HC != srcPtr[2]) return (size_t)-ERROR_GENERIC; /* Bad header checksum error */
- /* validate */
- if (version != 1) return (size_t)-ERROR_GENERIC; /* Version Number, only supported value */
- if (blockChecksumFlag != 0) return (size_t)-ERROR_GENERIC; /* Only supported value for the time being */
- if (contentSizeFlag != 0) return (size_t)-ERROR_GENERIC; /* Only supported value for the time being */
- if (((FLG>>1)&_1BIT) != 0) return (size_t)-ERROR_GENERIC; /* Reserved bit */
- if (dictFlag != 0) return (size_t)-ERROR_GENERIC; /* Only supported value for the time being */
- if (((BD>>7)&_1BIT) != 0) return (size_t)-ERROR_GENERIC; /* Reserved bit */
- if (blockSizeID < 4) return (size_t)-ERROR_GENERIC; /* Only supported values for the time being */
- if (((BD>>0)&_4BITS) != 0) return (size_t)-ERROR_GENERIC; /* Reserved bits */
- /* save */
- dctxPtr->frameInfo.blockMode = blockMode;
- dctxPtr->frameInfo.contentChecksumFlag = contentChecksumFlag;
- dctxPtr->frameInfo.blockSizeID = blockSizeID;
- dctxPtr->maxBlockSize = LZ4F_getBlockSize(blockSizeID);
- /* init */
- if (contentChecksumFlag) XXH32_reset(&(dctxPtr->xxh), 0);
- /* alloc */
- bufferNeeded = dctxPtr->maxBlockSize + ((dctxPtr->frameInfo.blockMode==blockLinked) * 128 KB);
- if (bufferNeeded > dctxPtr->maxBufferSize) /* tmp buffers too small */
- {
- FREEMEM(dctxPtr->tmpIn);
- FREEMEM(dctxPtr->tmpOutBuffer);
- dctxPtr->maxBufferSize = bufferNeeded;
- dctxPtr->tmpIn = ALLOCATOR(dctxPtr->maxBlockSize);
- if (dctxPtr->tmpIn == NULL) return (size_t)-ERROR_GENERIC;
- dctxPtr->tmpOutBuffer= ALLOCATOR(dctxPtr->maxBufferSize);
- if (dctxPtr->tmpOutBuffer== NULL) return (size_t)-ERROR_GENERIC;
- }
- dctxPtr->tmpInSize = 0;
- dctxPtr->tmpInTarget = 0;
- dctxPtr->dict = dctxPtr->tmpOutBuffer;
- dctxPtr->dictSize = 0;
- dctxPtr->tmpOut = dctxPtr->tmpOutBuffer;
- dctxPtr->tmpOutStart = 0;
- dctxPtr->tmpOutSize = 0;
- return 7;
- }
- typedef enum { dstage_getHeader=0, dstage_storeHeader, dstage_decodeHeader,
- dstage_getCBlockSize, dstage_storeCBlockSize, dstage_decodeCBlockSize,
- dstage_copyDirect,
- dstage_getCBlock, dstage_storeCBlock, dstage_decodeCBlock,
- dstage_decodeCBlock_intoDst, dstage_decodeCBlock_intoTmp, dstage_flushOut,
- dstage_getSuffix, dstage_storeSuffix, dstage_checkSuffix
- } dStage_t;
- /* LZ4F_getFrameInfo()
- * This function decodes frame header information, such as blockSize.
- * It is optional : you could start by calling directly LZ4F_decompress() instead.
- * The objective is to extract header information without starting decompression, typically for allocation purposes.
- * LZ4F_getFrameInfo() can also be used *after* starting decompression, on a valid LZ4F_decompressionContext_t.
- * The number of bytes read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
- * You are expected to resume decompression from where it stopped (srcBuffer + *srcSizePtr)
- * The function result is an hint of the better srcSize to use for next call to LZ4F_decompress,
- * or an error code which can be tested using LZ4F_isError().
- */
- LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_decompressionContext_t decompressionContext, LZ4F_frameInfo_t* frameInfoPtr, const void* srcBuffer, size_t* srcSizePtr)
- {
- LZ4F_dctx_internal_t* dctxPtr = (LZ4F_dctx_internal_t*)decompressionContext;
- if (dctxPtr->dStage == dstage_getHeader)
- {
- LZ4F_errorCode_t errorCode = LZ4F_decodeHeader(dctxPtr, srcBuffer, *srcSizePtr);
- if (LZ4F_isError(errorCode)) return errorCode;
- *srcSizePtr = errorCode;
- *frameInfoPtr = dctxPtr->frameInfo;
- dctxPtr->srcExpect = NULL;
- dctxPtr->dStage = dstage_getCBlockSize;
- return 4;
- }
- /* frameInfo already decoded */
- *srcSizePtr = 0;
- *frameInfoPtr = dctxPtr->frameInfo;
- return 0;
- }
- static int LZ4F_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize)
- {
- (void)dictStart;
- (void)dictSize;
- return LZ4_decompress_safe (source, dest, compressedSize, maxDecompressedSize);
- }
- static void LZ4F_updateDict(LZ4F_dctx_internal_t* dctxPtr, const BYTE* dstPtr, size_t dstSize, const BYTE* dstPtr0, unsigned withinTmp)
- {
- if (dctxPtr->dictSize==0)
- dctxPtr->dict = (BYTE*)dstPtr; /* priority to dictionary continuity */
- if (dctxPtr->dict + dctxPtr->dictSize == dstPtr) /* dictionary continuity */
- {
- dctxPtr->dictSize += dstSize;
- return;
- }
- if (dstPtr - dstPtr0 + dstSize >= 64 KB) /* dstBuffer large enough to become dictionary */
- {
- dctxPtr->dict = (BYTE*)dstPtr0;
- dctxPtr->dictSize = dstPtr - dstPtr0 + dstSize;
- return;
- }
- if ((withinTmp) && (dctxPtr->dict == dctxPtr->tmpOutBuffer))
- {
- /* assumption : dctxPtr->dict + dctxPtr->dictSize == dctxPtr->tmpOut + dctxPtr->tmpOutStart */
- dctxPtr->dictSize += dstSize;
- return;
- }
- if (withinTmp) /* copy relevant dict portion in front of tmpOut within tmpOutBuffer */
- {
- #if 0
- size_t savedDictSize = dctxPtr->tmpOut - dctxPtr->tmpOutBuffer;
- memcpy(dctxPtr->tmpOutBuffer, dctxPtr->dict + dctxPtr->dictSize - dctxPtr->tmpOutStart- savedDictSize, savedDictSize);
- dctxPtr->dict = dctxPtr->tmpOutBuffer;
- dctxPtr->dictSize = savedDictSize + dctxPtr->tmpOutStart + dstSize;
- return;
- #else
- size_t preserveSize = dctxPtr->tmpOut - dctxPtr->tmpOutBuffer;
- size_t copySize = 64 KB - dctxPtr->tmpOutSize;
- BYTE* oldDictEnd = dctxPtr->dict + dctxPtr->dictSize - dctxPtr->tmpOutStart;
- if (dctxPtr->tmpOutSize > 64 KB) copySize = 0;
- if (copySize > preserveSize) copySize = preserveSize;
- memcpy(dctxPtr->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);
- dctxPtr->dict = dctxPtr->tmpOutBuffer;
- dctxPtr->dictSize = preserveSize + dctxPtr->tmpOutStart + dstSize;
- return;
- #endif
- }
- if (dctxPtr->dict == dctxPtr->tmpOutBuffer) /* copy dst into tmp to complete dict */
- {
- if (dctxPtr->dictSize + dstSize > dctxPtr->maxBufferSize) /* tmp buffer not large enough */
- {
- size_t preserveSize = 64 KB - dstSize; /* note : dstSize < 64 KB */
- memcpy(dctxPtr->dict, dctxPtr->dict + dctxPtr->dictSize - preserveSize, preserveSize);
- dctxPtr->dictSize = preserveSize;
- }
- memcpy(dctxPtr->dict + dctxPtr->dictSize, dstPtr, dstSize);
- dctxPtr->dictSize += dstSize;
- return;
- }
- /* join dict & dest into tmp */
- {
- size_t preserveSize = 64 KB - dstSize; /* note : dstSize < 64 KB */
- if (preserveSize > dctxPtr->dictSize) preserveSize = dctxPtr->dictSize;
- memcpy(dctxPtr->tmpOutBuffer, dctxPtr->dict + dctxPtr->dictSize - preserveSize, preserveSize);
- memcpy(dctxPtr->tmpOutBuffer + preserveSize, dstPtr, dstSize);
- dctxPtr->dict = dctxPtr->tmpOutBuffer;
- dctxPtr->dictSize = preserveSize + dstSize;
- }
- }
- /* LZ4F_decompress()
- * Call this function repetitively to regenerate data compressed within srcBuffer.
- * The function will attempt to decode *srcSizePtr from srcBuffer, into dstBuffer of maximum size *dstSizePtr.
- *
- * The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value).
- *
- * The number of bytes effectively read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
- * If the number of bytes read is < number of bytes provided, then the decompression operation is not complete.
- * You will have to call it again, continuing from where it stopped.
- *
- * The function result is an hint of the better srcSize to use for next call to LZ4F_decompress.
- * Basically, it's the size of the current (or remaining) compressed block + header of next block.
- * Respecting the hint provides some boost to performance, since it allows less buffer shuffling.
- * Note that this is just a hint, you can always provide any srcSize you want.
- * When a frame is fully decoded, the function result will be 0.
- * If decompression failed, function result is an error code which can be tested using LZ4F_isError().
- */
- size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext,
- void* dstBuffer, size_t* dstSizePtr,
- const void* srcBuffer, size_t* srcSizePtr,
- const LZ4F_decompressOptions_t* decompressOptionsPtr)
- {
- LZ4F_dctx_internal_t* dctxPtr = (LZ4F_dctx_internal_t*)decompressionContext;
- static const LZ4F_decompressOptions_t optionsNull = { 0 };
- const BYTE* const srcStart = (const BYTE*)srcBuffer;
- const BYTE* const srcEnd = srcStart + *srcSizePtr;
- const BYTE* srcPtr = srcStart;
- BYTE* const dstStart = (BYTE*)dstBuffer;
- BYTE* const dstEnd = dstStart + *dstSizePtr;
- BYTE* dstPtr = dstStart;
- const BYTE* selectedIn=NULL;
- unsigned doAnotherStage = 1;
- size_t nextSrcSizeHint = 1;
- if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull;
- *srcSizePtr = 0;
- *dstSizePtr = 0;
- /* expect to continue decoding src buffer where it left previously */
- if (dctxPtr->srcExpect != NULL)
- {
- if (srcStart != dctxPtr->srcExpect) return (size_t)-ERROR_GENERIC;
- }
- /* programmed as a state machine */
- while (doAnotherStage)
- {
- switch(dctxPtr->dStage)
- {
- case dstage_getHeader:
- {
- if (srcEnd-srcPtr >= 7)
- {
- selectedIn = srcPtr;
- srcPtr += 7;
- dctxPtr->dStage = dstage_decodeHeader;
- break;
- }
- dctxPtr->tmpInSize = 0;
- dctxPtr->dStage = dstage_storeHeader;
- break;
- }
- case dstage_storeHeader:
- {
- size_t sizeToCopy = 7 - dctxPtr->tmpInSize;
- if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
- memcpy(dctxPtr->header + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
- dctxPtr->tmpInSize += sizeToCopy;
- srcPtr += sizeToCopy;
- if (dctxPtr->tmpInSize < 7)
- {
- nextSrcSizeHint = (7 - dctxPtr->tmpInSize) + 4;
- doAnotherStage = 0; /* no enough src, wait to get some more */
- break;
- }
- selectedIn = dctxPtr->header;
- dctxPtr->dStage = dstage_decodeHeader;
- break;
- }
- case dstage_decodeHeader:
- {
- LZ4F_errorCode_t errorCode = LZ4F_decodeHeader(dctxPtr, selectedIn, 7);
- if (LZ4F_isError(errorCode)) return errorCode;
- dctxPtr->dStage = dstage_getCBlockSize;
- break;
- }
- case dstage_getCBlockSize:
- {
- if ((srcEnd - srcPtr) >= 4)
- {
- selectedIn = srcPtr;
- srcPtr += 4;
- dctxPtr->dStage = dstage_decodeCBlockSize;
- break;
- }
- /* not enough input to read cBlockSize field */
- dctxPtr->tmpInSize = 0;
- dctxPtr->dStage = dstage_storeCBlockSize;
- break;
- }
- case dstage_storeCBlockSize:
- {
- size_t sizeToCopy = 4 - dctxPtr->tmpInSize;
- if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
- memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
- srcPtr += sizeToCopy;
- dctxPtr->tmpInSize += sizeToCopy;
- if (dctxPtr->tmpInSize < 4) /* not enough input to get full cBlockSize; wait for more */
- {
- nextSrcSizeHint = 4 - dctxPtr->tmpInSize;
- doAnotherStage=0;
- break;
- }
- selectedIn = dctxPtr->tmpIn;
- dctxPtr->dStage = dstage_decodeCBlockSize;
- break;
- }
- case dstage_decodeCBlockSize:
- {
- size_t nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU;
- if (nextCBlockSize==0) /* frameEnd signal, no more CBlock */
- {
- dctxPtr->dStage = dstage_getSuffix;
- break;
- }
- if (nextCBlockSize > dctxPtr->maxBlockSize) return (size_t)-ERROR_GENERIC; /* invalid cBlockSize */
- dctxPtr->tmpInTarget = nextCBlockSize;
- if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG)
- {
- dctxPtr->dStage = dstage_copyDirect;
- break;
- }
- dctxPtr->dStage = dstage_getCBlock;
- if (dstPtr==dstEnd)
- {
- nextSrcSizeHint = nextCBlockSize + 4;
- doAnotherStage = 0;
- }
- break;
- }
- case dstage_copyDirect: /* uncompressed block */
- {
- size_t sizeToCopy = dctxPtr->tmpInTarget;
- if ((size_t)(srcEnd-srcPtr) < sizeToCopy) sizeToCopy = srcEnd - srcPtr; /* not enough input to read full block */
- if ((size_t)(dstEnd-dstPtr) < sizeToCopy) sizeToCopy = dstEnd - dstPtr;
- memcpy(dstPtr, srcPtr, sizeToCopy);
- if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), srcPtr, (U32)sizeToCopy);
- /* dictionary management */
- if (dctxPtr->frameInfo.blockMode==blockLinked)
- LZ4F_updateDict(dctxPtr, dstPtr, sizeToCopy, dstStart, 0);
- srcPtr += sizeToCopy;
- dstPtr += sizeToCopy;
- if (sizeToCopy == dctxPtr->tmpInTarget) /* all copied */
- {
- dctxPtr->dStage = dstage_getCBlockSize;
- break;
- }
- dctxPtr->tmpInTarget -= sizeToCopy; /* still need to copy more */
- nextSrcSizeHint = dctxPtr->tmpInTarget + 4;
- doAnotherStage = 0;
- break;
- }
- case dstage_getCBlock: /* entry from dstage_decodeCBlockSize */
- {
- if ((size_t)(srcEnd-srcPtr) < dctxPtr->tmpInTarget)
- {
- dctxPtr->tmpInSize = 0;
- dctxPtr->dStage = dstage_storeCBlock;
- break;
- }
- selectedIn = srcPtr;
- srcPtr += dctxPtr->tmpInTarget;
- dctxPtr->dStage = dstage_decodeCBlock;
- break;
- }
- case dstage_storeCBlock:
- {
- size_t sizeToCopy = dctxPtr->tmpInTarget - dctxPtr->tmpInSize;
- if (sizeToCopy > (size_t)(srcEnd-srcPtr)) sizeToCopy = srcEnd-srcPtr;
- memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
- dctxPtr->tmpInSize += sizeToCopy;
- srcPtr += sizeToCopy;
- if (dctxPtr->tmpInSize < dctxPtr->tmpInTarget) /* need more input */
- {
- nextSrcSizeHint = (dctxPtr->tmpInTarget - dctxPtr->tmpInSize) + 4;
- doAnotherStage=0;
- break;
- }
- selectedIn = dctxPtr->tmpIn;
- dctxPtr->dStage = dstage_decodeCBlock;
- break;
- }
- case dstage_decodeCBlock:
- {
- if ((size_t)(dstEnd-dstPtr) < dctxPtr->maxBlockSize) /* not enough place into dst : decode into tmpOut */
- dctxPtr->dStage = dstage_decodeCBlock_intoTmp;
- else
- dctxPtr->dStage = dstage_decodeCBlock_intoDst;
- break;
- }
- case dstage_decodeCBlock_intoDst:
- {
- int (*decoder)(const char*, char*, int, int, const char*, int);
- int decodedSize;
- if (dctxPtr->frameInfo.blockMode == blockLinked)
- decoder = LZ4_decompress_safe_usingDict;
- else
- decoder = LZ4F_decompress_safe;
- decodedSize = decoder((const char*)selectedIn, (char*)dstPtr, (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize, (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
- if (decodedSize < 0) return (size_t)-ERROR_GENERIC; /* decompression failed */
- if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dstPtr, decodedSize);
- /* dictionary management */
- if (dctxPtr->frameInfo.blockMode==blockLinked)
- LZ4F_updateDict(dctxPtr, dstPtr, decodedSize, dstStart, 0);
- dstPtr += decodedSize;
- dctxPtr->dStage = dstage_getCBlockSize;
- break;
- }
- case dstage_decodeCBlock_intoTmp:
- {
- /* not enough place into dst : decode into tmpOut */
- int (*decoder)(const char*, char*, int, int, const char*, int);
- int decodedSize;
- if (dctxPtr->frameInfo.blockMode == blockLinked)
- decoder = LZ4_decompress_safe_usingDict;
- else
- decoder = LZ4F_decompress_safe;
- /* ensure enough place for tmpOut */
- if (dctxPtr->frameInfo.blockMode == blockLinked)
- {
- if (dctxPtr->dict == dctxPtr->tmpOutBuffer)
- {
- if (dctxPtr->dictSize > 128 KB)
- {
- memcpy(dctxPtr->dict, dctxPtr->dict + dctxPtr->dictSize - 64 KB, 64 KB);
- dctxPtr->dictSize = 64 KB;
- }
- dctxPtr->tmpOut = dctxPtr->dict + dctxPtr->dictSize;
- }
- else /* dict not within tmp */
- {
- size_t reservedDictSpace = dctxPtr->dictSize;
- if (reservedDictSpace > 64 KB) reservedDictSpace = 64 KB;
- dctxPtr->tmpOut = dctxPtr->tmpOutBuffer + reservedDictSpace;
- }
- }
- /* Decode */
- decodedSize = decoder((const char*)selectedIn, (char*)dctxPtr->tmpOut, (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize, (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
- if (decodedSize < 0) return (size_t)-ERROR_decompressionFailed; /* decompression failed */
- if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dctxPtr->tmpOut, decodedSize);
- dctxPtr->tmpOutSize = decodedSize;
- dctxPtr->tmpOutStart = 0;
- dctxPtr->dStage = dstage_flushOut;
- break;
- }
- case dstage_flushOut: /* flush decoded data from tmpOut to dstBuffer */
- {
- size_t sizeToCopy = dctxPtr->tmpOutSize - dctxPtr->tmpOutStart;
- if (sizeToCopy > (size_t)(dstEnd-dstPtr)) sizeToCopy = dstEnd-dstPtr;
- memcpy(dstPtr, dctxPtr->tmpOut + dctxPtr->tmpOutStart, sizeToCopy);
- /* dictionary management */
- if (dctxPtr->frameInfo.blockMode==blockLinked)
- LZ4F_updateDict(dctxPtr, dstPtr, sizeToCopy, dstStart, 1);
- dctxPtr->tmpOutStart += sizeToCopy;
- dstPtr += sizeToCopy;
- /* end of flush ? */
- if (dctxPtr->tmpOutStart == dctxPtr->tmpOutSize)
- {
- dctxPtr->dStage = dstage_getCBlockSize;
- break;
- }
- nextSrcSizeHint = 4;
- doAnotherStage = 0; /* still some data to flush */
- break;
- }
- case dstage_getSuffix:
- {
- size_t suffixSize = dctxPtr->frameInfo.contentChecksumFlag * 4;
- if (suffixSize == 0) /* frame completed */
- {
- nextSrcSizeHint = 0;
- dctxPtr->dStage = dstage_getHeader;
- doAnotherStage = 0;
- break;
- }
- if ((srcEnd - srcPtr) >= 4) /* CRC present */
- {
- selectedIn = srcPtr;
- srcPtr += 4;
- dctxPtr->dStage = dstage_checkSuffix;
- break;
- }
- dctxPtr->tmpInSize = 0;
- dctxPtr->dStage = dstage_storeSuffix;
- break;
- }
- case dstage_storeSuffix:
- {
- size_t sizeToCopy = 4 - dctxPtr->tmpInSize;
- if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr;
- memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
- srcPtr += sizeToCopy;
- dctxPtr->tmpInSize += sizeToCopy;
- if (dctxPtr->tmpInSize < 4) /* not enough input to read complete suffix */
- {
- nextSrcSizeHint = 4 - dctxPtr->tmpInSize;
- doAnotherStage=0;
- break;
- }
- selectedIn = dctxPtr->tmpIn;
- dctxPtr->dStage = dstage_checkSuffix;
- break;
- }
- case dstage_checkSuffix:
- {
- U32 readCRC = LZ4F_readLE32(selectedIn);
- U32 resultCRC = XXH32_digest(&(dctxPtr->xxh));
- if (readCRC != resultCRC) return (size_t)-ERROR_checksum_invalid;
- nextSrcSizeHint = 0;
- dctxPtr->dStage = dstage_getHeader;
- doAnotherStage = 0;
- break;
- }
- }
- }
- /* preserve dictionary within tmp if necessary */
- if ( (dctxPtr->frameInfo.blockMode==blockLinked)
- &&(dctxPtr->dict != dctxPtr->tmpOutBuffer)
- &&(!decompressOptionsPtr->stableDst)
- &&((unsigned)(dctxPtr->dStage-1) < (unsigned)(dstage_getSuffix-1))
- )
- {
- if (dctxPtr->dStage == dstage_flushOut)
- {
- size_t preserveSize = dctxPtr->tmpOut - dctxPtr->tmpOutBuffer;
- size_t copySize = 64 KB - dctxPtr->tmpOutSize;
- BYTE* oldDictEnd = dctxPtr->dict + dctxPtr->dictSize - dctxPtr->tmpOutStart;
- if (dctxPtr->tmpOutSize > 64 KB) copySize = 0;
- if (copySize > preserveSize) copySize = preserveSize;
- memcpy(dctxPtr->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);
- dctxPtr->dict = dctxPtr->tmpOutBuffer;
- dctxPtr->dictSize = preserveSize + dctxPtr->tmpOutStart;
- }
- else
- {
- size_t newDictSize = dctxPtr->dictSize;
- BYTE* oldDictEnd = dctxPtr->dict + dctxPtr->dictSize;
- if ((newDictSize) > 64 KB) newDictSize = 64 KB;
- memcpy(dctxPtr->tmpOutBuffer, oldDictEnd - newDictSize, newDictSize);
- dctxPtr->dict = dctxPtr->tmpOutBuffer;
- dctxPtr->dictSize = newDictSize;
- dctxPtr->tmpOut = dctxPtr->tmpOutBuffer + newDictSize;
- }
- }
- if (srcPtr<srcEnd) /* function must be called again with following source data */
- dctxPtr->srcExpect = srcPtr;
- else
- dctxPtr->srcExpect = NULL;
- *srcSizePtr = (srcPtr - srcStart);
- *dstSizePtr = (dstPtr - dstStart);
- return nextSrcSizeHint;
- }
|