diff options
Diffstat (limited to 'lz4frame.c')
-rw-r--r-- | lz4frame.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/lz4frame.c b/lz4frame.c new file mode 100644 index 0000000..8af9c28 --- /dev/null +++ b/lz4frame.c @@ -0,0 +1,265 @@ +/* + 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. + * You don't need lz4.h when using lz4frame.h. + * */ + + +/************************************** + CPU Feature Detection +**************************************/ +/* 32 or 64 bits ? */ +static const int LZ4F_32bits = (sizeof(void*)==4); +static const int LZ4F_64bits = (sizeof(void*)==8); + +/* Little Endian or Big Endian ? */ +typedef union { + int num; + char bytes[4]; + } endian_t; +static const endian_t endianTest = { .num = 1 }; +#define LZ4F_isLittleEndian (endianTest.bytes[0]) + + +/************************************** + 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__) + + +/************************************** + Memory routines +**************************************/ +#include <stdlib.h> /* malloc, calloc, free */ +#define ALLOCATOR(n,s) calloc(n,s) +#define FREEMEM free +#include <string.h> /* memset, memcpy */ +#define MEM_INIT memset + + +/************************************** + Includes +**************************************/ +#include "lz4frame.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 + +#if defined(__GNUC__) +# define _PACKED __attribute__ ((packed)) +#else +# define _PACKED +#endif + +#if !defined(__GNUC__) +# if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# pragma pack(1) +# else +# pragma pack(push, 1) +# endif +#endif + +typedef struct { U16 v; } _PACKED U16_S; +typedef struct { U32 v; } _PACKED U32_S; +typedef struct { U64 v; } _PACKED U64_S; +typedef struct {size_t v;} _PACKED size_t_S; + +#if !defined(__GNUC__) +# if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# pragma pack(0) +# else +# pragma pack(pop) +# endif +#endif + +#define A16(x) (((U16_S *)(x))->v) +#define A32(x) (((U32_S *)(x))->v) +#define A64(x) (((U64_S *)(x))->v) +#define AARCH(x) (((size_t_S *)(x))->v) + + +/************************************** + Constants +**************************************/ +#define KB *(1<<10) +#define MB *(1<<20) +#define GB *(1<<30) + + +/************************************** + Structures and local types +**************************************/ + + +/************************************** + Macros +**************************************/ + + +/************************************** + Private functions +**************************************/ +static size_t LZ4F_getBlockSize(unsigned blockSizeID) +{ + static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB }; + + blockSizeID -= 4; + if (blockSizeID > 3) return ERROR_maxBlockSize_invalid; + return blockSizes[blockSizeID]; +} + + +/************************************** + Error management +**************************************/ +int LZ4F_isError(LZ4F_errorCode_t code) +{ + return (code > (LZ4F_errorCode_t)(-ERROR_maxCode)); +} + + +/************************************** + Compression functions +**************************************/ +size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_frameInfo_t* frameInfoPtr) +{ + const LZ4F_frameInfo_t frameInfoNull = { 0 }; + size_t headerSize; + size_t blockInfoSize; + size_t blockSize; + unsigned nbBlocks; + size_t frameSuffixSize; + size_t totalBound; + + if (frameInfoPtr==NULL) frameInfoPtr = &frameInfoNull; /* all parameters set to default */ + + headerSize = 7; /* basic header size (no option) including magic number */ + blockInfoSize = 4; /* basic blockInfo size (no option) for one block */ + + blockSize = LZ4F_getBlockSize(frameInfoPtr->maxBlockSizeID); + nbBlocks = (srcSize + (blockSize-1)) / blockSize; + blockInfoSize *= nbBlocks; /* total block info size */ + + frameSuffixSize = 4; /* basic frameSuffixSize (no option) */ + if (frameInfoPtr->contentChecksumFlag == contentChecksumEnabled) frameSuffixSize += 4; + + totalBound = headerSize + srcSize + blockInfoSize + frameSuffixSize; + if (totalBound < srcSize) return ERROR_srcSize_tooLarge; /* overflow error */ + + return totalBound; +} + + +/* 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) +{ + const LZ4F_frameInfo_t frameInfoNull = { 0 }; + const LZ4F_frameInfo_t* const frameInfoPtr = (preferencesPtr==NULL) ? &frameInfoNull : &(preferencesPtr->frameInfo); + LZ4F_compressionContext_t cctx; + LZ4F_errorCode_t errorCode; + BYTE* const dstStart = (BYTE*) dstBuffer; + BYTE* dstPtr = dstStart; + size_t blockSize = LZ4F_getBlockSize(frameInfoPtr->maxBlockSizeID); + unsigned nbBlocks = (srcSize + (blockSize-1)) / blockSize; + unsigned blockNb; + const BYTE* srcPtr = (const BYTE*) srcBuffer; + const size_t dstBlockSize = LZ4F_compressBound(blockSize, frameInfoPtr); + + + if (dstMaxSize < LZ4F_compressFrameBound(srcSize, frameInfoPtr)) + return ERROR_maxDstSize_tooSmall; + + errorCode = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION, preferencesPtr); + if (LZ4F_isError(errorCode)) return errorCode; + + errorCode = LZ4F_compressBegin(cctx, dstBuffer, dstMaxSize); /* write header */ + if (LZ4F_isError(errorCode)) return errorCode; + dstPtr += errorCode; /* header size */ + + for (blockNb=1; blockNb<nbBlocks; blockNb++) + { + errorCode = LZ4F_compress(cctx, dstPtr, dstBlockSize, srcPtr, blockSize, NULL); + if (LZ4F_isError(errorCode)) return errorCode; + srcPtr += blockSize; + dstPtr += errorCode; + } + + /* last block */ + blockSize = srcSize % blockSize; + errorCode = LZ4F_compress(cctx, dstPtr, dstBlockSize, srcPtr, blockSize, NULL); + if (LZ4F_isError(errorCode)) return errorCode; + dstPtr += errorCode; + + errorCode = LZ4F_compressEnd(cctx, dstPtr, dstMaxSize, NULL); /* flush last block, and generate suffix */ + if (LZ4F_isError(errorCode)) return errorCode; + dstPtr += errorCode; + + errorCode = LZ4F_freeCompressionContext(cctx); + if (LZ4F_isError(errorCode)) return errorCode; + + return (dstPtr - dstStart); +} |