diff options
-rw-r--r-- | lib/Makefile | 4 | ||||
-rw-r--r-- | lib/lz4.c | 25 | ||||
-rw-r--r-- | lib/lz4frame.c | 298 | ||||
-rw-r--r-- | lib/lz4frame.h | 152 | ||||
-rw-r--r-- | lib/lz4frame_static.h | 21 | ||||
-rw-r--r-- | lib/lz4hc.c | 4 | ||||
-rw-r--r-- | tests/.gitignore | 9 |
7 files changed, 252 insertions, 261 deletions
diff --git a/lib/Makefile b/lib/Makefile index bd47ee3..8b2cbff 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -46,7 +46,9 @@ DESTDIR?= PREFIX ?= /usr/local CPPFLAGS= -DXXH_NAMESPACE=LZ4_ -DLZ4_DLL_EXPORT=1 CFLAGS ?= -O3 -CFLAGS += -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wcast-qual -Wstrict-prototypes +CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \ + -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef \ + -Wpointer-arith # -Wstrict-aliasing=1 FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) LIBDIR?= $(PREFIX)/lib @@ -85,9 +85,10 @@ /*-************************************ -* Includes +* Dependency **************************************/ #include "lz4.h" +/* see also "memory routines" below */ /*-************************************ @@ -99,15 +100,13 @@ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ #else -# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ -# if defined(__GNUC__) || defined(__clang__) -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif +# if defined(__GNUC__) || defined(__clang__) +# define FORCE_INLINE static inline __attribute__((always_inline)) +# elif defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define FORCE_INLINE static inline # else # define FORCE_INLINE static -# endif /* __STDC_VERSION__ */ +# endif #endif /* _MSC_VER */ /* LZ4_GCC_VERSION is defined into lz4.h */ @@ -134,7 +133,7 @@ /*-************************************ * Basic Types **************************************/ -#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) # include <stdint.h> typedef uint8_t BYTE; typedef uint16_t U16; @@ -165,6 +164,7 @@ static unsigned LZ4_isLittleEndian(void) #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) +/* lie to the compiler about data alignment; use with caution */ static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; } static U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; } @@ -186,7 +186,7 @@ static size_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uAr static void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; } -#else +#else /* safe and portable access through memcpy() */ static U16 LZ4_read16(const void* memPtr) { @@ -242,7 +242,7 @@ static void LZ4_copy8(void* dst, const void* src) memcpy(dst,src,8); } -/* customized variant of memcpy, which can overwrite up to 7 bytes beyond dstEnd */ +/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) { BYTE* d = (BYTE*)dstPtr; @@ -354,7 +354,7 @@ static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLi const BYTE* const pStart = pIn; while (likely(pIn<pInLimit-(STEPSIZE-1))) { - size_t diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); + size_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; } pIn += LZ4_NbCommonBytes(diff); return (unsigned)(pIn - pStart); @@ -1475,4 +1475,3 @@ int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int origin } #endif /* LZ4_COMMONDEFS_ONLY */ - diff --git a/lib/lz4frame.c b/lib/lz4frame.c index 6bb76a1..08b7050 100644 --- a/lib/lz4frame.c +++ b/lib/lz4frame.c @@ -84,6 +84,7 @@ You can contact the author at : typedef unsigned long long U64; #endif + /* unoptimized version; solves endianess & alignment issues */ static U32 LZ4F_readLE32 (const void* src) { @@ -95,16 +96,18 @@ static U32 LZ4F_readLE32 (const void* src) return value32; } -static void LZ4F_writeLE32 (BYTE* dstPtr, U32 value32) +static void LZ4F_writeLE32 (void* dst, U32 value32) { + BYTE* const dstPtr = (BYTE*)dst; dstPtr[0] = (BYTE)value32; dstPtr[1] = (BYTE)(value32 >> 8); dstPtr[2] = (BYTE)(value32 >> 16); dstPtr[3] = (BYTE)(value32 >> 24); } -static U64 LZ4F_readLE64 (const BYTE* srcPtr) +static U64 LZ4F_readLE64 (const void* src) { + const BYTE* const srcPtr = (const BYTE*)src; U64 value64 = srcPtr[0]; value64 += ((U64)srcPtr[1]<<8); value64 += ((U64)srcPtr[2]<<16); @@ -116,8 +119,9 @@ static U64 LZ4F_readLE64 (const BYTE* srcPtr) return value64; } -static void LZ4F_writeLE64 (BYTE* dstPtr, U64 value64) +static void LZ4F_writeLE64 (void* dst, U64 value64) { + BYTE* const dstPtr = (BYTE*)dst; dstPtr[0] = (BYTE)value64; dstPtr[1] = (BYTE)(value64 >> 8); dstPtr[2] = (BYTE)(value64 >> 16); @@ -171,28 +175,6 @@ typedef struct LZ4F_cctx_s U32 lz4CtxLevel; /* 0: unallocated; 1: LZ4_stream_t; 3: LZ4_streamHC_t */ } LZ4F_cctx_t; -typedef struct LZ4F_dctx_s -{ - LZ4F_frameInfo_t frameInfo; - U32 version; - U32 dStage; - U64 frameRemainingSize; - size_t maxBlockSize; - size_t maxBufferSize; - const BYTE* srcExpect; - BYTE* tmpIn; - size_t tmpInSize; - size_t tmpInTarget; - BYTE* tmpOutBuffer; - const BYTE* dict; - size_t dictSize; - BYTE* tmpOut; - size_t tmpOutSize; - size_t tmpOutStart; - XXH32_state_t xxh; - BYTE header[16]; -} LZ4F_dctx_t; - /*-************************************ * Error management @@ -213,6 +195,10 @@ const char* LZ4F_getErrorName(LZ4F_errorCode_t code) return codeError; } +static LZ4F_errorCode_t err0r(LZ4F_errorCodes code) { return (LZ4F_errorCode_t)-(LZ4F_errorCode_t)code; } + +unsigned LZ4F_getVersion(void) { return LZ4F_VERSION; } + /*-************************************ * Private functions @@ -223,14 +209,14 @@ static size_t LZ4F_getBlockSize(unsigned blockSizeID) if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT; blockSizeID -= 4; - if (blockSizeID > 3) return (size_t)-LZ4F_ERROR_maxBlockSize_invalid; + if (blockSizeID > 3) return err0r(LZ4F_ERROR_maxBlockSize_invalid); return blockSizes[blockSizeID]; } static BYTE LZ4F_headerChecksum (const void* header, size_t length) { - U32 xxh = XXH32(header, length, 0); + U32 const xxh = XXH32(header, length, 0); return (BYTE)(xxh >> 8); } @@ -281,16 +267,15 @@ size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* prefere * 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) +size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr) { LZ4F_cctx_t cctxI; LZ4_stream_t lz4ctx; LZ4F_preferences_t prefs; LZ4F_compressOptions_t options; - LZ4F_errorCode_t errorCode; BYTE* const dstStart = (BYTE*) dstBuffer; BYTE* dstPtr = dstStart; - BYTE* const dstEnd = dstStart + dstMaxSize; + BYTE* const dstEnd = dstStart + dstCapacity; memset(&cctxI, 0, sizeof(cctxI)); /* works because no allocation */ memset(&options, 0, sizeof(options)); @@ -317,22 +302,22 @@ size_t LZ4F_compressFrame(void* dstBuffer, size_t dstMaxSize, const void* srcBuf options.stableSrc = 1; - if (dstMaxSize < LZ4F_compressFrameBound(srcSize, &prefs)) - return (size_t)-LZ4F_ERROR_dstMaxSize_tooSmall; + if (dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs)) + return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); - errorCode = LZ4F_compressBegin(&cctxI, dstBuffer, dstMaxSize, &prefs); /* write header */ - if (LZ4F_isError(errorCode)) return errorCode; - dstPtr += errorCode; /* header size */ + { size_t const headerSize = LZ4F_compressBegin(&cctxI, dstBuffer, dstCapacity, &prefs); /* write header */ + if (LZ4F_isError(headerSize)) return headerSize; + dstPtr += headerSize; /* header size */ } - errorCode = LZ4F_compressUpdate(&cctxI, dstPtr, dstEnd-dstPtr, srcBuffer, srcSize, &options); - if (LZ4F_isError(errorCode)) return errorCode; - dstPtr += errorCode; + { size_t const cSize = LZ4F_compressUpdate(&cctxI, dstPtr, dstEnd-dstPtr, srcBuffer, srcSize, &options); + if (LZ4F_isError(cSize)) return cSize; + dstPtr += cSize; } - errorCode = LZ4F_compressEnd(&cctxI, dstPtr, dstEnd-dstPtr, &options); /* flush last block, and generate suffix */ - if (LZ4F_isError(errorCode)) return errorCode; - dstPtr += errorCode; + { size_t const tailSize = LZ4F_compressEnd(&cctxI, dstPtr, dstEnd-dstPtr, &options); /* flush last block, and generate suffix */ + if (LZ4F_isError(tailSize)) return tailSize; + dstPtr += tailSize; } - if (prefs.compressionLevel >= LZ4HC_MIN_CLEVEL) /* no allocation necessary with lz4 fast */ + if (prefs.compressionLevel >= LZ4HC_MIN_CLEVEL) /* no allocation done with lz4 fast */ FREEMEM(cctxI.lz4CtxPtr); return (dstPtr - dstStart); @@ -343,20 +328,18 @@ size_t LZ4F_compressFrame(void* dstBuffer, size_t dstMaxSize, const void* srcBuf * 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_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_t* cctxPtr; - - cctxPtr = (LZ4F_cctx_t*)ALLOCATOR(sizeof(LZ4F_cctx_t)); - if (cctxPtr==NULL) return (LZ4F_errorCode_t)(-LZ4F_ERROR_allocation_failed); + LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)ALLOCATOR(sizeof(LZ4F_cctx_t)); + if (cctxPtr==NULL) return err0r(LZ4F_ERROR_allocation_failed); cctxPtr->version = version; cctxPtr->cStage = 0; /* Next stage : write header */ @@ -369,7 +352,7 @@ LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* LZ4F_c LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_compressionContext) { - LZ4F_cctx_t* cctxPtr = (LZ4F_cctx_t*)LZ4F_compressionContext; + LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)LZ4F_compressionContext; if (cctxPtr != NULL) { /* null pointers can be safely provided to this function, like free() */ FREEMEM(cctxPtr->lz4CtxPtr); @@ -382,22 +365,21 @@ LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_comp /*! 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) + * 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. + * @return : number of bytes written into dstBuffer for the header + * or an error code (can be tested using LZ4F_isError()) + */ +size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstMaxSize, const LZ4F_preferences_t* preferencesPtr) { LZ4F_preferences_t prefNull; - LZ4F_cctx_t* cctxPtr = (LZ4F_cctx_t*)compressionContext; BYTE* const dstStart = (BYTE*)dstBuffer; BYTE* dstPtr = dstStart; BYTE* headerStart; size_t requiredBuffSize; - if (dstMaxSize < maxFHSize) return (size_t)-LZ4F_ERROR_dstMaxSize_tooSmall; - if (cctxPtr->cStage != 0) return (size_t)-LZ4F_ERROR_GENERIC; + if (dstMaxSize < maxFHSize) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); + if (cctxPtr->cStage != 0) return err0r(LZ4F_ERROR_GENERIC); memset(&prefNull, 0, sizeof(prefNull)); if (preferencesPtr == NULL) preferencesPtr = &prefNull; cctxPtr->prefs = *preferencesPtr; @@ -426,7 +408,7 @@ size_t LZ4F_compressBegin(LZ4F_compressionContext_t compressionContext, void* ds cctxPtr->maxBufferSize = requiredBuffSize; FREEMEM(cctxPtr->tmpBuff); cctxPtr->tmpBuff = (BYTE*)ALLOCATOR(requiredBuffSize); - if (cctxPtr->tmpBuff == NULL) return (size_t)-LZ4F_ERROR_allocation_failed; + if (cctxPtr->tmpBuff == NULL) return err0r(LZ4F_ERROR_allocation_failed); } cctxPtr->tmpIn = cctxPtr->tmpBuff; cctxPtr->tmpInSize = 0; @@ -473,13 +455,13 @@ size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesP LZ4F_preferences_t prefsNull; memset(&prefsNull, 0, sizeof(prefsNull)); prefsNull.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; /* worst case */ - { const LZ4F_preferences_t* prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr; - LZ4F_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); + { const LZ4F_preferences_t* const prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr; + LZ4F_blockSizeID_t const bid = prefsPtr->frameInfo.blockSizeID; + size_t const blockSize = LZ4F_getBlockSize(bid); + unsigned const nbBlocks = (unsigned)(srcSize / blockSize) + 1; + size_t const lastBlockSize = prefsPtr->autoFlush ? srcSize % blockSize : blockSize; + size_t const blockInfo = 4; /* default, without block CRC option */ + size_t const frameEnd = 4 + (prefsPtr->frameInfo.contentChecksumFlag*4); return (blockInfo * nbBlocks) + (blockSize * (nbBlocks-1)) + lastBlockSize + frameEnd;; } @@ -491,9 +473,8 @@ typedef int (*compressFunc_t)(void* ctx, const char* src, char* dst, int srcSize 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); + BYTE* const cSizePtr = (BYTE*)dst; + U32 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; @@ -550,11 +531,10 @@ typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus; * 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) +size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* compressOptionsPtr) { LZ4F_compressOptions_t cOptionsNull; - LZ4F_cctx_t* cctxPtr = (LZ4F_cctx_t*)compressionContext; - size_t blockSize = cctxPtr->maxBlockSize; + size_t const blockSize = cctxPtr->maxBlockSize; const BYTE* srcPtr = (const BYTE*)srcBuffer; const BYTE* const srcEnd = srcPtr + srcSize; BYTE* const dstStart = (BYTE*)dstBuffer; @@ -563,8 +543,8 @@ size_t LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext, void* d compressFunc_t compress; - if (cctxPtr->cStage != 1) return (size_t)-LZ4F_ERROR_GENERIC; - if (dstMaxSize < LZ4F_compressBound(srcSize, &(cctxPtr->prefs))) return (size_t)-LZ4F_ERROR_dstMaxSize_tooSmall; + if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC); + if (dstMaxSize < LZ4F_compressBound(srcSize, &(cctxPtr->prefs))) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); memset(&cOptionsNull, 0, sizeof(cOptionsNull)); if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull; @@ -573,7 +553,7 @@ size_t LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext, void* d /* complete tmp buffer */ if (cctxPtr->tmpInSize > 0) { /* some data already within tmp buffer */ - size_t sizeToCopy = blockSize - cctxPtr->tmpInSize; + size_t const sizeToCopy = blockSize - cctxPtr->tmpInSize; if (sizeToCopy > srcSize) { /* add src to tmpIn buffer */ memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize); @@ -613,7 +593,7 @@ size_t LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext, void* d cctxPtr->tmpIn = cctxPtr->tmpBuff; } else { int realDictSize = LZ4F_localSaveDict(cctxPtr); - if (realDictSize==0) return (size_t)-LZ4F_ERROR_GENERIC; + if (realDictSize==0) return err0r(LZ4F_ERROR_GENERIC); cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; } } @@ -629,7 +609,7 @@ size_t LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext, void* d /* some input data left, necessarily < blockSize */ if (srcPtr < srcEnd) { /* fill tmp buffer */ - size_t sizeToCopy = srcEnd - srcPtr; + size_t const sizeToCopy = srcEnd - srcPtr; memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy); cctxPtr->tmpInSize = sizeToCopy; } @@ -650,17 +630,15 @@ size_t LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext, void* d * 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) +size_t LZ4F_flush(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr) { - LZ4F_cctx_t* cctxPtr = (LZ4F_cctx_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)-LZ4F_ERROR_GENERIC; - if (dstMaxSize < (cctxPtr->tmpInSize + 8)) return (size_t)-LZ4F_ERROR_dstMaxSize_tooSmall; /* +8 : block header(4) + block checksum(4) */ + if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC); + if (dstMaxSize < (cctxPtr->tmpInSize + 8)) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall); /* +8 : block header(4) + block checksum(4) */ (void)compressOptionsPtr; /* not yet useful */ /* select compression function */ @@ -690,22 +668,20 @@ size_t LZ4F_flush(LZ4F_compressionContext_t compressionContext, void* dstBuffer, * 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) +size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr) { - LZ4F_cctx_t* cctxPtr = (LZ4F_cctx_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; + size_t const flushSize = LZ4F_flush(cctxPtr, dstBuffer, dstMaxSize, compressOptionsPtr); + if (LZ4F_isError(flushSize)) return flushSize; + dstPtr += flushSize; LZ4F_writeLE32(dstPtr, 0); dstPtr+=4; /* endMark */ if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) { - U32 xxh = XXH32_digest(&(cctxPtr->xxh)); + U32 const xxh = XXH32_digest(&(cctxPtr->xxh)); LZ4F_writeLE32(dstPtr, xxh); dstPtr+=4; /* content Checksum */ } @@ -715,7 +691,7 @@ size_t LZ4F_compressEnd(LZ4F_compressionContext_t compressionContext, void* dstB if (cctxPtr->prefs.frameInfo.contentSize) { if (cctxPtr->prefs.frameInfo.contentSize != cctxPtr->totalInSize) - return (size_t)-LZ4F_ERROR_frameSize_wrong; + return err0r(LZ4F_ERROR_frameSize_wrong); } return dstPtr - dstStart; @@ -726,7 +702,26 @@ size_t LZ4F_compressEnd(LZ4F_compressionContext_t compressionContext, void* dstB * Frame Decompression *****************************************************/ -/* Resource management */ +struct LZ4F_dctx_s { + LZ4F_frameInfo_t frameInfo; + U32 version; + U32 dStage; + U64 frameRemainingSize; + size_t maxBlockSize; + size_t maxBufferSize; + BYTE* tmpIn; + size_t tmpInSize; + size_t tmpInTarget; + BYTE* tmpOutBuffer; + const BYTE* dict; + size_t dictSize; + BYTE* tmpOut; + size_t tmpOutSize; + size_t tmpOutStart; + XXH32_state_t xxh; + BYTE header[16]; +}; /* typedef'd to LZ4F_dctx in lz4frame.h */ + /*! LZ4F_createDecompressionContext() : * Create a decompressionContext object, which will track all decompression operations. @@ -734,20 +729,19 @@ size_t LZ4F_compressEnd(LZ4F_compressionContext_t compressionContext, void* dstB * Object can later be released using LZ4F_freeDecompressionContext(). * @return : if != 0, there was an error during context creation. */ -LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_decompressionContext_t* LZ4F_decompressionContextPtr, unsigned versionNumber) +LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber) { - LZ4F_dctx_t* const dctxPtr = (LZ4F_dctx_t*)ALLOCATOR(sizeof(LZ4F_dctx_t)); - if (dctxPtr==NULL) return (LZ4F_errorCode_t)-LZ4F_ERROR_GENERIC; + LZ4F_dctx* const dctxPtr = (LZ4F_dctx*)ALLOCATOR(sizeof(LZ4F_dctx)); + if (dctxPtr==NULL) return err0r(LZ4F_ERROR_GENERIC); dctxPtr->version = versionNumber; - *LZ4F_decompressionContextPtr = (LZ4F_decompressionContext_t)dctxPtr; + *LZ4F_decompressionContextPtr = dctxPtr; return LZ4F_OK_NoError; } -LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_decompressionContext_t LZ4F_decompressionContext) +LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* const dctxPtr) { LZ4F_errorCode_t result = LZ4F_OK_NoError; - LZ4F_dctx_t* const dctxPtr = (LZ4F_dctx_t*)LZ4F_decompressionContext; if (dctxPtr != NULL) { /* can accept NULL input, like free() */ result = (LZ4F_errorCode_t)dctxPtr->dStage; FREEMEM(dctxPtr->tmpIn); @@ -758,9 +752,7 @@ LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_decompressionContext_t LZ4F_ } -/* ******************************************************************** */ -/* ********************* Decompression ******************************** */ -/* ******************************************************************** */ +/*==--- Streaming Decompression operations ---==*/ typedef enum { dstage_getHeader=0, dstage_storeHeader, dstage_getCBlockSize, dstage_storeCBlockSize, @@ -781,13 +773,13 @@ typedef enum { dstage_getHeader=0, dstage_storeHeader, static size_t LZ4F_headerSize(const void* src, size_t srcSize) { /* minimal srcSize to determine header size */ - if (srcSize < 5) return (size_t)-LZ4F_ERROR_frameHeader_incomplete; + if (srcSize < 5) return err0r(LZ4F_ERROR_frameHeader_incomplete); /* special case : skippable frames */ if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) return 8; /* control magic number */ - if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER) return (size_t)-LZ4F_ERROR_frameType_unknown; + if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER) return err0r(LZ4F_ERROR_frameType_unknown); /* Frame Header Size */ { BYTE const FLG = ((const BYTE*)src)[4]; @@ -798,29 +790,29 @@ static size_t LZ4F_headerSize(const void* src, size_t srcSize) /*! LZ4F_decodeHeader() : - input : `srcVoidPtr` points at the **beginning of the frame** + input : `src` points at the **beginning of the frame** output : set internal values of dctx, such as dctxPtr->frameInfo and dctxPtr->dStage. Also allocates internal buffers. @return : nb Bytes read from srcVoidPtr (necessarily <= srcSize) or an error code (testable with LZ4F_isError()) */ -static size_t LZ4F_decodeHeader(LZ4F_dctx_t* dctxPtr, const void* srcVoidPtr, size_t srcSize) +static size_t LZ4F_decodeHeader(LZ4F_dctx* dctxPtr, const void* src, size_t srcSize) { BYTE FLG, BD, HC; unsigned version, blockMode, blockChecksumFlag, contentSizeFlag, contentChecksumFlag, blockSizeID; size_t bufferNeeded; size_t frameHeaderSize; - const BYTE* srcPtr = (const BYTE*)srcVoidPtr; + const BYTE* srcPtr = (const BYTE*)src; /* need to decode header to get frameInfo */ - if (srcSize < minFHSize) return (size_t)-LZ4F_ERROR_frameHeader_incomplete; /* minimal frame header size */ + if (srcSize < minFHSize) return err0r(LZ4F_ERROR_frameHeader_incomplete); /* minimal frame header size */ memset(&(dctxPtr->frameInfo), 0, sizeof(dctxPtr->frameInfo)); /* special case : skippable frames */ if ((LZ4F_readLE32(srcPtr) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) { dctxPtr->frameInfo.frameType = LZ4F_skippableFrame; - if (srcVoidPtr == (void*)(dctxPtr->header)) { + if (src == (void*)(dctxPtr->header)) { dctxPtr->tmpInSize = srcSize; dctxPtr->tmpInTarget = 8; dctxPtr->dStage = dstage_storeSFrameSize; @@ -832,7 +824,7 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx_t* dctxPtr, const void* srcVoidPtr, si } /* control magic number */ - if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) return (size_t)-LZ4F_ERROR_frameType_unknown; + if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) return err0r(LZ4F_ERROR_frameType_unknown); dctxPtr->frameInfo.frameType = LZ4F_frame; /* Flags */ @@ -860,16 +852,16 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx_t* dctxPtr, const void* srcVoidPtr, si blockSizeID = (BD>>4) & _3BITS; /* validate */ - if (version != 1) return (size_t)-LZ4F_ERROR_headerVersion_wrong; /* Version Number, only supported value */ - if (blockChecksumFlag != 0) return (size_t)-LZ4F_ERROR_blockChecksum_unsupported; /* Not supported for the time being */ - if (((FLG>>0)&_2BITS) != 0) return (size_t)-LZ4F_ERROR_reservedFlag_set; /* Reserved bits */ - if (((BD>>7)&_1BIT) != 0) return (size_t)-LZ4F_ERROR_reservedFlag_set; /* Reserved bit */ - if (blockSizeID < 4) return (size_t)-LZ4F_ERROR_maxBlockSize_invalid; /* 4-7 only supported values for the time being */ - if (((BD>>0)&_4BITS) != 0) return (size_t)-LZ4F_ERROR_reservedFlag_set; /* Reserved bits */ + if (version != 1) return err0r(LZ4F_ERROR_headerVersion_wrong); /* Version Number, only supported value */ + if (blockChecksumFlag != 0) return err0r(LZ4F_ERROR_blockChecksum_unsupported); /* Not supported for the time being */ + if (((FLG>>0)&_2BITS) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bits */ + if (((BD>>7)&_1BIT) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bit */ + if (blockSizeID < 4) return err0r(LZ4F_ERROR_maxBlockSize_invalid); /* 4-7 only supported values for the time being */ + if (((BD>>0)&_4BITS) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bits */ /* check */ HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5); - if (HC != srcPtr[frameHeaderSize-1]) return (size_t)-LZ4F_ERROR_headerChecksum_invalid; /* Bad header checksum error */ + if (HC != srcPtr[frameHeaderSize-1]) return err0r(LZ4F_ERROR_headerChecksum_invalid); /* Bad header checksum error */ /* save */ dctxPtr->frameInfo.blockMode = (LZ4F_blockMode_t)blockMode; @@ -889,9 +881,9 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx_t* dctxPtr, const void* srcVoidPtr, si FREEMEM(dctxPtr->tmpOutBuffer); dctxPtr->maxBufferSize = bufferNeeded; dctxPtr->tmpIn = (BYTE*)ALLOCATOR(dctxPtr->maxBlockSize); - if (dctxPtr->tmpIn == NULL) return (size_t)-LZ4F_ERROR_GENERIC; + if (dctxPtr->tmpIn == NULL) return err0r(LZ4F_ERROR_GENERIC); dctxPtr->tmpOutBuffer= (BYTE*)ALLOCATOR(dctxPtr->maxBufferSize); - if (dctxPtr->tmpOutBuffer== NULL) return (size_t)-LZ4F_ERROR_GENERIC; + if (dctxPtr->tmpOutBuffer== NULL) return err0r(LZ4F_ERROR_GENERIC); } dctxPtr->tmpInSize = 0; dctxPtr->tmpInTarget = 0; @@ -908,35 +900,32 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx_t* dctxPtr, const void* srcVoidPtr, si /*! LZ4F_getFrameInfo() : -* 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. +* Decodes frame header information, such as blockSize. Usage is optional. +* The objective is to extract header information before receiving decompressed data, 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 number of bytes consumed from srcBuffer will be provided within *srcSizePtr (necessarily <= original value). +* Decompression must resume from where it stopped (srcBuffer + *srcSizePtr) * @return : 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 dCtx, LZ4F_frameInfo_t* frameInfoPtr, +LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctxPtr, LZ4F_frameInfo_t* frameInfoPtr, const void* srcBuffer, size_t* srcSizePtr) { - LZ4F_dctx_t* dctxPtr = (LZ4F_dctx_t*)dCtx; - if (dctxPtr->dStage > dstage_storeHeader) { /* note : requires dstage_* header related to be at beginning of enum */ /* frameInfo already decoded */ size_t o=0, i=0; *srcSizePtr = 0; *frameInfoPtr = dctxPtr->frameInfo; - return LZ4F_decompress(dCtx, NULL, &o, NULL, &i, NULL); /* returns : recommended nb of bytes for LZ4F_decompress() */ + return LZ4F_decompress(dctxPtr, NULL, &o, NULL, &i, NULL); /* returns : recommended nb of bytes for LZ4F_decompress() */ } else { size_t nextSrcSize, o=0; size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr); if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; } - if (*srcSizePtr < hSize) { *srcSizePtr=0; return (size_t)-LZ4F_ERROR_frameHeader_incomplete; } + if (*srcSizePtr < hSize) { *srcSizePtr=0; return err0r(LZ4F_ERROR_frameHeader_incomplete); } *srcSizePtr = hSize; - nextSrcSize = LZ4F_decompress(dCtx, NULL, &o, srcBuffer, srcSizePtr, NULL); - if (dctxPtr->dStage <= dstage_storeHeader) return (size_t)-LZ4F_ERROR_frameHeader_incomplete; /* should not happen, already checked */ + nextSrcSize = LZ4F_decompress(dctxPtr, NULL, &o, srcBuffer, srcSizePtr, NULL); + if (dctxPtr->dStage <= dstage_storeHeader) return err0r(LZ4F_ERROR_frameHeader_incomplete); /* should not happen, already checked */ *frameInfoPtr = dctxPtr->frameInfo; return nextSrcSize; } @@ -951,7 +940,7 @@ static int LZ4F_decompress_safe (const char* source, char* dest, int compressedS } -static void LZ4F_updateDict(LZ4F_dctx_t* dctxPtr, const BYTE* dstPtr, size_t dstSize, const BYTE* dstPtr0, unsigned withinTmp) +static void LZ4F_updateDict(LZ4F_dctx* dctxPtr, const BYTE* dstPtr, size_t dstSize, const BYTE* dstPtr0, unsigned withinTmp) { if (dctxPtr->dictSize==0) dctxPtr->dict = (const BYTE*)dstPtr; /* priority to dictionary continuity */ @@ -1012,27 +1001,26 @@ static void LZ4F_updateDict(LZ4F_dctx_t* dctxPtr, const BYTE* dstPtr, size_t dst /*! 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 function will attempt to decode up to *srcSizePtr bytes from srcBuffer, into dstBuffer of capacity *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. +* Remaining data will have to be presented again in a subsequent invocation. * * 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(). +* Note that this is just a hint, it's always possible to any srcSize value. +* When a frame is fully decoded, @return will be 0. +* If decompression failed, @return is an error code which can be tested using LZ4F_isError(). */ -size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, +size_t LZ4F_decompress(LZ4F_dctx* dctxPtr, void* dstBuffer, size_t* dstSizePtr, const void* srcBuffer, size_t* srcSizePtr, const LZ4F_decompressOptions_t* decompressOptionsPtr) { - LZ4F_dctx_t* dctxPtr = (LZ4F_dctx_t*)decompressionContext; LZ4F_decompressOptions_t optionsNull; const BYTE* const srcStart = (const BYTE*)srcBuffer; const BYTE* const srcEnd = srcStart + *srcSizePtr; @@ -1050,11 +1038,6 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, *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)-LZ4F_ERROR_srcPtr_wrong; - } - /* programmed as a state machine */ while (doAnotherStage) { @@ -1103,8 +1086,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, if (dctxPtr->dStage == dstage_storeCBlockSize) /* can be skipped */ case dstage_storeCBlockSize: - { - size_t sizeToCopy = BHSize - dctxPtr->tmpInSize; + { size_t sizeToCopy = BHSize - dctxPtr->tmpInSize; if (sizeToCopy > (size_t)(srcEnd - srcPtr)) sizeToCopy = srcEnd - srcPtr; memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy); srcPtr += sizeToCopy; @@ -1123,7 +1105,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, dctxPtr->dStage = dstage_getSuffix; break; } - if (nextCBlockSize > dctxPtr->maxBlockSize) return (size_t)-LZ4F_ERROR_GENERIC; /* invalid cBlockSize */ + if (nextCBlockSize > dctxPtr->maxBlockSize) return err0r(LZ4F_ERROR_GENERIC); /* invalid cBlockSize */ dctxPtr->tmpInTarget = nextCBlockSize; if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG) { dctxPtr->dStage = dstage_copyDirect; @@ -1205,7 +1187,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, 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)-LZ4F_ERROR_GENERIC; /* decompression failed */ + if (decodedSize < 0) return err0r(LZ4F_ERROR_GENERIC); /* decompression failed */ if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dstPtr, decodedSize); if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= decodedSize; @@ -1245,7 +1227,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, /* 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)-LZ4F_ERROR_decompressionFailed; /* decompression failed */ + if (decodedSize < 0) return err0r(LZ4F_ERROR_decompressionFailed); /* decompression failed */ if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dctxPtr->tmpOut, decodedSize); if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= decodedSize; dctxPtr->tmpOutSize = decodedSize; @@ -1278,7 +1260,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, case dstage_getSuffix: { size_t const suffixSize = dctxPtr->frameInfo.contentChecksumFlag * 4; - if (dctxPtr->frameRemainingSize) return (size_t)-LZ4F_ERROR_frameSize_wrong; /* incorrect frame size decoded */ + if (dctxPtr->frameRemainingSize) return err0r(LZ4F_ERROR_frameSize_wrong); /* incorrect frame size decoded */ if (suffixSize == 0) { /* frame completed */ nextSrcSizeHint = 0; dctxPtr->dStage = dstage_getHeader; @@ -1313,7 +1295,7 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, /* case dstage_checkSuffix: */ /* no direct call, to avoid scan-build warning */ { U32 const readCRC = LZ4F_readLE32(selectedIn); U32 const resultCRC = XXH32_digest(&(dctxPtr->xxh)); - if (readCRC != resultCRC) return (size_t)-LZ4F_ERROR_contentChecksum_invalid; + if (readCRC != resultCRC) return err0r(LZ4F_ERROR_contentChecksum_invalid); nextSrcSizeHint = 0; dctxPtr->dStage = dstage_getHeader; doAnotherStage = 0; @@ -1400,12 +1382,6 @@ size_t LZ4F_decompress(LZ4F_decompressionContext_t decompressionContext, } } - /* require function to be called again from position where it stopped */ - if (srcPtr<srcEnd) - dctxPtr->srcExpect = srcPtr; - else - dctxPtr->srcExpect = NULL; - *srcSizePtr = (srcPtr - srcStart); *dstSizePtr = (dstPtr - dstStart); return nextSrcSizeHint; diff --git a/lib/lz4frame.h b/lib/lz4frame.h index 79164b8..63abc60 100644 --- a/lib/lz4frame.h +++ b/lib/lz4frame.h @@ -34,18 +34,19 @@ /* LZ4F is a stand-alone API to create LZ4-compressed frames * conformant with specification v1.5.1. - * All related operations, including memory management, are handled internally by the library. - * You don't need lz4.h when using lz4frame.h. + * It also offers streaming capabilities. + * lz4.h is not required when using lz4frame.h. * */ -#pragma once +#ifndef LZ4F_H_09782039843 +#define LZ4F_H_09782039843 #if defined (__cplusplus) extern "C" { #endif /*-************************************ -* Includes +* Dependency **************************************/ #include <stddef.h> /* size_t */ @@ -78,7 +79,7 @@ LZ4FLIB_API const char* LZ4F_getErrorName(LZ4F_errorCode_t code); /* return er /*-************************************ * Frame compression types **************************************/ -//#define LZ4F_DISABLE_OBSOLETE_ENUMS +/* #define LZ4F_DISABLE_OBSOLETE_ENUMS */ /* uncomment to disable obsolete enums */ #ifndef LZ4F_DISABLE_OBSOLETE_ENUMS # define LZ4F_OBSOLETE_ENUM(x) ,x #else @@ -136,7 +137,7 @@ typedef struct { typedef struct { LZ4F_frameInfo_t frameInfo; int compressionLevel; /* 0 == default (fast mode); values above 16 count as 16; values below 0 count as 0 */ - unsigned autoFlush; /* 1 == always flush (reduce need for tmp buffer) */ + unsigned autoFlush; /* 1 == always flush (reduce usage of tmp buffer) */ unsigned reserved[4]; /* must be zero for forward compatibility */ } LZ4F_preferences_t; @@ -144,55 +145,60 @@ typedef struct { /*-********************************* * Simple compression function ***********************************/ +/*!LZ4F_compressFrameBound() : + * Returns the maximum possible size of a frame given srcSize content and preferences. + */ LZ4FLIB_API size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr); /*!LZ4F_compressFrame() : * Compress an entire srcBuffer into a valid LZ4 frame, as defined by specification v1.5.1 - * 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) + * An important rule is that dstBuffer MUST be large enough (dstCapacity) to store the result in worst case situation. + * This value is supplied by 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()) + * @return : number of bytes written into dstBuffer. + * or an error code if it fails (can be tested using LZ4F_isError()) */ -LZ4FLIB_API size_t LZ4F_compressFrame(void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr); +LZ4FLIB_API size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr); /*-*********************************** * Advanced compression functions *************************************/ -typedef struct LZ4F_cctx_s* LZ4F_compressionContext_t; /* must be aligned on 8-bytes */ +typedef struct LZ4F_cctx_s LZ4F_cctx; /* incomplete type */ +typedef LZ4F_cctx* LZ4F_compressionContext_t; /* for compatibility with previous API version */ typedef struct { - unsigned stableSrc; /* 1 == src content will remain available on future calls to LZ4F_compress(); avoid saving src content within tmp buffer as future dictionary */ + unsigned stableSrc; /* 1 == src content remain present on future calls to LZ4F_compress(); avoid saving src content within tmp buffer as future dictionary */ unsigned reserved[3]; } LZ4F_compressOptions_t; /* Resource Management */ #define LZ4F_VERSION 100 -LZ4FLIB_API LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* cctxPtr, unsigned version); -LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t cctx); +LZ4FLIB_API unsigned LZ4F_getVersion(void); +LZ4FLIB_API LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** cctxPtr, unsigned version); +LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx); /* 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 a fully allocated LZ4F_compressionContext_t object. - * If the result LZ4F_errorCode_t is not zero, there was an error during context creation. + * The version provided MUST be LZ4F_VERSION. It is intended to track potential version mismatch, notably when using DLL. + * The function will provide a pointer to a fully allocated LZ4F_cctx object. + * If @return != zero, there was an error during context creation. * Object can release its memory using LZ4F_freeCompressionContext(); */ /* Compression */ -LZ4FLIB_API size_t LZ4F_compressBegin(LZ4F_compressionContext_t cctx, void* dstBuffer, size_t dstMaxSize, const LZ4F_preferences_t* prefsPtr); +LZ4FLIB_API size_t LZ4F_compressBegin(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const LZ4F_preferences_t* prefsPtr); /* LZ4F_compressBegin() : * will write the frame header into dstBuffer. - * dstBuffer must be large enough to accommodate a header (dstMaxSize). Maximum header size is 15 bytes. - * The LZ4F_preferences_t structure is optional : you can provide NULL as argument, all preferences will then be set to default. - * 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()) + * dstBuffer must be large enough to accommodate a header. Maximum header size is 15 bytes. + * `prefsPtr` is optional : you can provide NULL as argument, all preferences will then be set to default. + * @return : number of bytes written into dstBuffer for the header + * or an error code (which can be tested using LZ4F_isError()) */ LZ4FLIB_API size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* prefsPtr); @@ -203,46 +209,45 @@ LZ4FLIB_API size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* * This function includes frame termination cost (4 bytes, or 8 if frame checksum is enabled) */ -LZ4FLIB_API size_t LZ4F_compressUpdate(LZ4F_compressionContext_t cctx, void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* cOptPtr); -/* LZ4F_compressUpdate() +LZ4FLIB_API size_t LZ4F_compressUpdate(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* cOptPtr); +/* 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. - * You can get the minimum value of dstMaxSize by using LZ4F_compressBound(). + * An important rule is that dstBuffer MUST be large enough (dstCapacity) to ensure compression completion even in worst case. + * This value is provided by using LZ4F_compressBound(). * If this condition is not respected, LZ4F_compress() will fail (result is an errorCode). - * LZ4F_compressUpdate() doesn't guarantee error recovery, so you have to reset compression context when an error occurs. - * 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()) + * LZ4F_compressUpdate() doesn't guarantee error recovery. When an error occurs, compression context must be freed or resized. + * `cOptPtr` is optional : it's possible to provide NULL, all options will be set to default. + * @return : number of bytes written into `dstBuffer` (it can be zero, meaning input data was just buffered). + * or an error code if it fails (which can be tested using LZ4F_isError()) */ -LZ4FLIB_API size_t LZ4F_flush(LZ4F_compressionContext_t cctx, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* cOptPtr); -/* LZ4F_flush() - * Should you need to generate compressed data immediately, without waiting for the current block to be filled, - * you can call LZ4_flush(), which will immediately compress any remaining data buffered within cctx. - * Note that dstMaxSize must be large enough to ensure the operation will be successful. - * 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, this means there was no data left within cctx) - * The function outputs an error code if it fails (can be tested using LZ4F_isError()) +LZ4FLIB_API size_t LZ4F_flush(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* cOptPtr); +/* LZ4F_flush() : + * When data must be generated and sent immediately, without waiting for a block to be completely filled, + * it's possible to call LZ4_flush(). It will immediately compress any data buffered within cctx. + * `dstCapacity` must be large enough to ensure the operation will be successful. + * `cOptPtr` is optional : it's possible to provide NULL, all options will be set to default. + * @return : number of bytes written into dstBuffer (it can be zero, which means there was no data stored within cctx) + * or an error code if it fails (which can be tested using LZ4F_isError()) */ -LZ4FLIB_API size_t LZ4F_compressEnd(LZ4F_compressionContext_t cctx, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* cOptPtr); -/* 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), or 8 if optional frame checksum is enabled) - * 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. - * A successful call to LZ4F_compressEnd() makes cctx available again for next compression task. +LZ4FLIB_API size_t LZ4F_compressEnd(LZ4F_cctx* cctx, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* cOptPtr); +/* LZ4F_compressEnd() : + * To properly finish the compressed frame, invoke LZ4F_compressEnd(). + * It will flush whatever data remained within `cctx` (like LZ4_flush()) + * and properly finalize the frame, with an endMark and a checksum. + * `cOptPtr` is optional : it's possible to provide NULL, all options will be set to default. + * @return : number of bytes written into dstBuffer (necessarily >= 4 (endMark), or 8 if optional frame checksum is enabled) + * or an error code if it fails (which can be tested using LZ4F_isError()) + * A successful call to LZ4F_compressEnd() makes `cctx` available again for another compression task. */ /*-********************************* * Decompression functions ***********************************/ - -typedef struct LZ4F_dctx_s* LZ4F_decompressionContext_t; /* must be aligned on 8-bytes */ +typedef struct LZ4F_dctx_s LZ4F_dctx; /* incomplete type */ +typedef LZ4F_dctx* LZ4F_decompressionContext_t; /* compatibility with previous API versions */ typedef struct { unsigned stableDst; /* guarantee that decompressed data will still be there on next function calls (avoid storage into tmp buffers) */ @@ -261,8 +266,8 @@ typedef struct { * The result of LZ4F_freeDecompressionContext() is indicative of the current state of decompressionContext when being released. * That is, it should be == 0 if decompression has been completed fully and correctly. */ -LZ4FLIB_API LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_decompressionContext_t* dctxPtr, unsigned version); -LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_decompressionContext_t dctx); +LZ4FLIB_API LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** dctxPtr, unsigned version); +LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx); /*====== Decompression ======*/ @@ -270,44 +275,43 @@ LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_decompressionCon /*!LZ4F_getFrameInfo() : * This function decodes frame header information (such as max blockSize, frame checksum, etc.). * Its usage is optional. The objective is to extract frame header information, typically for allocation purposes. - * A header size is variable and can be from 7 to 15 bytes. It's also possible to input more bytes than that. - * The number of bytes read from srcBuffer will be updated within *srcSizePtr (necessarily <= original value). - * (note that LZ4F_getFrameInfo() can also be used anytime *after* starting decompression, in this case 0 input byte is enough) + * A header size is variable and can length from 7 to 15 bytes. It's possible to provide more input bytes than that. + * The number of bytes consumed from srcBuffer will be updated within *srcSizePtr (necessarily <= original value). + * Decompression must resume from this point (srcBuffer + *srcSizePtr). + * Note that LZ4F_getFrameInfo() can also be used anytime *after* decompression is started, in which case 0 input byte can be enough. * Frame header info is *copied into* an already allocated LZ4F_frameInfo_t structure. - * The function result is an hint about how many srcSize bytes LZ4F_decompress() expects for next call, - * or an error code which can be tested using LZ4F_isError() - * (typically, when there is not enough src bytes to fully decode the frame header) - * Decompression is expected to resume from where it stopped (srcBuffer + *srcSizePtr) + * @return : an hint about how many srcSize bytes LZ4F_decompress() expects for next call, + * or an error code which can be tested using LZ4F_isError() + * (typically, when there is not enough src bytes to fully decode the frame header) */ -LZ4FLIB_API size_t LZ4F_getFrameInfo(LZ4F_decompressionContext_t dctx, +LZ4FLIB_API size_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, LZ4F_frameInfo_t* frameInfoPtr, const void* srcBuffer, size_t* srcSizePtr); /*!LZ4F_decompress() : - * Call this function repetitively to regenerate data compressed within srcBuffer. - * The function will attempt to decode *srcSizePtr bytes from srcBuffer, into dstBuffer of maximum size *dstSizePtr. + * Call this function repetitively to regenerate data compressed within `srcBuffer`. + * The function will attempt to decode up to *srcSizePtr bytes from srcBuffer, into dstBuffer of capacity *dstSizePtr. * * The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value). * * The number of bytes read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value). - * If number of bytes read is < number of bytes provided, then decompression operation is not completed. + * Number of bytes read can be < number of bytes provided, meaning there is some more data to decode. * It typically happens when dstBuffer is not large enough to contain all decoded data. - * LZ4F_decompress() must be called again, starting from where it stopped (srcBuffer + *srcSizePtr) - * The function will check this condition, and refuse to continue if it is not respected. + * Remaining data will have to be presented again in a subsequent invocation. * - * `dstBuffer` is expected to be flushed between each call to the function, its content will be overwritten. - * `dst` arguments can be changed at will at each consecutive call to the function. + * `dstBuffer` content is expected to be flushed between each invocation, as its content will be overwritten. + * `dstBuffer` can be changed at will between each consecutive function invocation. * - * The function result is an hint of how many `srcSize` bytes LZ4F_decompress() expects for next call. + * @return is an hint of how many `srcSize` bytes LZ4F_decompress() expects for next call. * Schematically, 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 does skip intermediate buffers. * This is just a hint though, it's always possible to provide any srcSize. - * When a frame is fully decoded, the function result will be 0 (no more data expected). - * If decompression failed, function result is an error code, which can be tested using LZ4F_isError(). + * When a frame is fully decoded, @return will be 0 (no more data expected). + * If decompression failed, @return is an error code, which can be tested using LZ4F_isError(). * * After a frame is fully decoded, dctx can be used again to decompress another frame. */ -LZ4FLIB_API size_t LZ4F_decompress(LZ4F_decompressionContext_t dctx, +LZ4FLIB_API size_t LZ4F_decompress(LZ4F_dctx* dctx, void* dstBuffer, size_t* dstSizePtr, const void* srcBuffer, size_t* srcSizePtr, const LZ4F_decompressOptions_t* dOptPtr); @@ -317,3 +321,5 @@ LZ4FLIB_API size_t LZ4F_decompress(LZ4F_decompressionContext_t dctx, #if defined (__cplusplus) } #endif + +#endif /* LZ4F_H_09782039843 */ diff --git a/lib/lz4frame_static.h b/lib/lz4frame_static.h index 79e481c..fab3def 100644 --- a/lib/lz4frame_static.h +++ b/lib/lz4frame_static.h @@ -33,27 +33,24 @@ - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ -#pragma once +#ifndef LZ4FRAME_STATIC_H_0398209384 +#define LZ4FRAME_STATIC_H_0398209384 #if defined (__cplusplus) extern "C" { #endif /* lz4frame_static.h should be used solely in the context of static linking. - * It contains definitions which may still change overtime. + * It contains definitions which are not stable and may change in the future. * Never use it in the context of DLL linking. * */ -/************************************** -* Includes -**************************************/ +/* --- Dependency --- */ #include "lz4frame.h" -/************************************** - * Error management - * ************************************/ +/* --- Error List --- */ #define LZ4F_LIST_ERRORS(ITEM) \ ITEM(OK_NoError) ITEM(ERROR_GENERIC) \ ITEM(ERROR_maxBlockSize_invalid) ITEM(ERROR_blockMode_invalid) ITEM(ERROR_contentChecksumFlag_invalid) \ @@ -67,11 +64,11 @@ extern "C" { ITEM(ERROR_headerChecksum_invalid) ITEM(ERROR_contentChecksum_invalid) \ ITEM(ERROR_maxCode) -//#define LZ4F_DISABLE_OLD_ENUMS +//#define LZ4F_DISABLE_OLD_ENUMS /* uncomment to disable deprecated enums */ #ifndef LZ4F_DISABLE_OLD_ENUMS -#define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM, ENUM = LZ4F_##ENUM, +# define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM, ENUM = LZ4F_##ENUM, #else -#define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM, +# define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM, #endif typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM) } LZ4F_errorCodes; /* enum is exposed, to handle specific errors; compare function result to -enum value */ @@ -79,3 +76,5 @@ typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM) } LZ4F_errorCodes; /* enum #if defined (__cplusplus) } #endif + +#endif /* LZ4FRAME_STATIC_H_0398209384 */ diff --git a/lib/lz4hc.c b/lib/lz4hc.c index a1d1a55..f109622 100644 --- a/lib/lz4hc.c +++ b/lib/lz4hc.c @@ -108,7 +108,7 @@ typedef struct * Local Macros **************************************/ #define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-HASH_LOG)) -//#define DELTANEXTU16(p) chainTable[(p) & MAXD_MASK] /* flexible, MAXD dependent */ +/* #define DELTANEXTU16(p) chainTable[(p) & MAXD_MASK] */ /* flexible, MAXD dependent */ #define DELTANEXTU16(p) chainTable[(U16)(p)] /* faster */ static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); } @@ -252,7 +252,7 @@ FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch ( } } } else { - const BYTE* matchPtr = dictBase + matchIndex; + const BYTE* const matchPtr = dictBase + matchIndex; if (LZ4_read32(matchPtr) == LZ4_read32(ip)) { size_t mlt; int back=0; diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..8861e67 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,9 @@ + +# test build artefacts +datagen +frametest +frametest32 +fullbench +fullbench32 +fuzzer +fuzzer32 |