michael@0: /* michael@0: LZ4 - Fast LZ compression algorithm michael@0: Copyright (C) 2011-2014, Yann Collet. michael@0: BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) michael@0: michael@0: Redistribution and use in source and binary forms, with or without michael@0: modification, are permitted provided that the following conditions are michael@0: met: michael@0: michael@0: * Redistributions of source code must retain the above copyright michael@0: notice, this list of conditions and the following disclaimer. michael@0: * Redistributions in binary form must reproduce the above michael@0: copyright notice, this list of conditions and the following disclaimer michael@0: in the documentation and/or other materials provided with the michael@0: distribution. michael@0: michael@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: You can contact the author at : michael@0: - LZ4 source repository : http://code.google.com/p/lz4/ michael@0: - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c michael@0: */ michael@0: michael@0: /************************************** michael@0: Tuning parameters michael@0: **************************************/ michael@0: /* michael@0: * HEAPMODE : michael@0: * Select how default compression functions will allocate memory for their hash table, michael@0: * in memory stack (0:default, fastest), or in memory heap (1:requires memory allocation (malloc)). michael@0: */ michael@0: #define HEAPMODE 0 michael@0: michael@0: michael@0: /************************************** michael@0: CPU Feature Detection michael@0: **************************************/ michael@0: /* 32 or 64 bits ? */ michael@0: #if (defined(__x86_64__) || defined(_M_X64) || defined(_WIN64) \ michael@0: || defined(__powerpc64__) || defined(__powerpc64le__) \ michael@0: || defined(__ppc64__) || defined(__ppc64le__) \ michael@0: || defined(__PPC64__) || defined(__PPC64LE__) \ michael@0: || defined(__ia64) || defined(__itanium__) || defined(_M_IA64) ) /* Detects 64 bits mode */ michael@0: # define LZ4_ARCH64 1 michael@0: #else michael@0: # define LZ4_ARCH64 0 michael@0: #endif michael@0: michael@0: /* michael@0: * Little Endian or Big Endian ? michael@0: * Overwrite the #define below if you know your architecture endianess michael@0: */ michael@0: #include /* Apparently required to detect endianess */ michael@0: #if defined (__GLIBC__) michael@0: # include michael@0: # if (__BYTE_ORDER == __BIG_ENDIAN) michael@0: # define LZ4_BIG_ENDIAN 1 michael@0: # endif michael@0: #elif (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN)) michael@0: # define LZ4_BIG_ENDIAN 1 michael@0: #elif defined(__sparc) || defined(__sparc__) \ michael@0: || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \ michael@0: || defined(__hpux) || defined(__hppa) \ michael@0: || defined(_MIPSEB) || defined(__s390__) michael@0: # define LZ4_BIG_ENDIAN 1 michael@0: #else michael@0: /* Little Endian assumed. PDP Endian and other very rare endian format are unsupported. */ michael@0: #endif michael@0: michael@0: /* michael@0: * Unaligned memory access is automatically enabled for "common" CPU, such as x86. michael@0: * For others CPU, such as ARM, the compiler may be more cautious, inserting unnecessary extra code to ensure aligned access property michael@0: * If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance michael@0: */ michael@0: #if defined(__ARM_FEATURE_UNALIGNED) michael@0: # define LZ4_FORCE_UNALIGNED_ACCESS 1 michael@0: #endif michael@0: michael@0: /* Define this parameter if your target system or compiler does not support hardware bit count */ michael@0: #if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */ michael@0: # define LZ4_FORCE_SW_BITCOUNT michael@0: #endif michael@0: michael@0: /* michael@0: * BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE : michael@0: * This option may provide a small boost to performance for some big endian cpu, although probably modest. michael@0: * You may set this option to 1 if data will remain within closed environment. michael@0: * This option is useless on Little_Endian CPU (such as x86) michael@0: */ michael@0: michael@0: /* #define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 */ michael@0: michael@0: michael@0: /************************************** michael@0: Compiler Options michael@0: **************************************/ michael@0: #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ michael@0: /* "restrict" is a known keyword */ michael@0: #else michael@0: # define restrict /* Disable restrict */ michael@0: #endif michael@0: michael@0: #ifdef _MSC_VER /* Visual Studio */ michael@0: # define FORCE_INLINE static __forceinline michael@0: # include /* For Visual 2005 */ michael@0: # if LZ4_ARCH64 /* 64-bits */ michael@0: # pragma intrinsic(_BitScanForward64) /* For Visual 2005 */ michael@0: # pragma intrinsic(_BitScanReverse64) /* For Visual 2005 */ michael@0: # else /* 32-bits */ michael@0: # pragma intrinsic(_BitScanForward) /* For Visual 2005 */ michael@0: # pragma intrinsic(_BitScanReverse) /* For Visual 2005 */ michael@0: # endif michael@0: # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ michael@0: #else michael@0: # ifdef __GNUC__ michael@0: # define FORCE_INLINE static inline __attribute__((always_inline)) michael@0: # else michael@0: # define FORCE_INLINE static inline michael@0: # endif michael@0: #endif michael@0: michael@0: #ifdef _MSC_VER /* Visual Studio */ michael@0: # define lz4_bswap16(x) _byteswap_ushort(x) michael@0: #else michael@0: # define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))) michael@0: #endif michael@0: michael@0: #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) michael@0: michael@0: #if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) michael@0: # define expect(expr,value) (__builtin_expect ((expr),(value)) ) michael@0: #else michael@0: # define expect(expr,value) (expr) michael@0: #endif michael@0: michael@0: #define likely(expr) expect((expr) != 0, 1) michael@0: #define unlikely(expr) expect((expr) != 0, 0) michael@0: michael@0: michael@0: /************************************** michael@0: Memory routines michael@0: **************************************/ michael@0: #include /* malloc, calloc, free */ michael@0: #define ALLOCATOR(n,s) calloc(n,s) michael@0: #define FREEMEM free michael@0: #include /* memset, memcpy */ michael@0: #define MEM_INIT memset michael@0: michael@0: michael@0: /************************************** michael@0: Includes michael@0: **************************************/ michael@0: #include "lz4.h" michael@0: michael@0: michael@0: /************************************** michael@0: Basic Types michael@0: **************************************/ michael@0: #if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ michael@0: # include michael@0: typedef uint8_t BYTE; michael@0: typedef uint16_t U16; michael@0: typedef uint32_t U32; michael@0: typedef int32_t S32; michael@0: typedef uint64_t U64; michael@0: #else michael@0: typedef unsigned char BYTE; michael@0: typedef unsigned short U16; michael@0: typedef unsigned int U32; michael@0: typedef signed int S32; michael@0: typedef unsigned long long U64; michael@0: #endif michael@0: michael@0: #if defined(__GNUC__) && !defined(LZ4_FORCE_UNALIGNED_ACCESS) michael@0: # define _PACKED __attribute__ ((packed)) michael@0: #else michael@0: # define _PACKED michael@0: #endif michael@0: michael@0: #if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) michael@0: # if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) michael@0: # pragma pack(1) michael@0: # else michael@0: # pragma pack(push, 1) michael@0: # endif michael@0: #endif michael@0: michael@0: typedef struct { U16 v; } _PACKED U16_S; michael@0: typedef struct { U32 v; } _PACKED U32_S; michael@0: typedef struct { U64 v; } _PACKED U64_S; michael@0: typedef struct {size_t v;} _PACKED size_t_S; michael@0: michael@0: #if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) michael@0: # if defined(__SUNPRO_C) || defined(__SUNPRO_CC) michael@0: # pragma pack(0) michael@0: # else michael@0: # pragma pack(pop) michael@0: # endif michael@0: #endif michael@0: michael@0: #define A16(x) (((U16_S *)(x))->v) michael@0: #define A32(x) (((U32_S *)(x))->v) michael@0: #define A64(x) (((U64_S *)(x))->v) michael@0: #define AARCH(x) (((size_t_S *)(x))->v) michael@0: michael@0: michael@0: /************************************** michael@0: Constants michael@0: **************************************/ michael@0: #define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) michael@0: #define HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) michael@0: #define HASH_SIZE_U32 (1 << LZ4_HASHLOG) michael@0: michael@0: #define MINMATCH 4 michael@0: michael@0: #define COPYLENGTH 8 michael@0: #define LASTLITERALS 5 michael@0: #define MFLIMIT (COPYLENGTH+MINMATCH) michael@0: static const int LZ4_minLength = (MFLIMIT+1); michael@0: michael@0: #define KB *(1U<<10) michael@0: #define MB *(1U<<20) michael@0: #define GB *(1U<<30) michael@0: michael@0: #define LZ4_64KLIMIT ((64 KB) + (MFLIMIT-1)) michael@0: #define SKIPSTRENGTH 6 /* Increasing this value will make the compression run slower on incompressible data */ michael@0: michael@0: #define MAXD_LOG 16 michael@0: #define MAX_DISTANCE ((1 << MAXD_LOG) - 1) michael@0: michael@0: #define ML_BITS 4 michael@0: #define ML_MASK ((1U<=e; */ michael@0: #else michael@0: # define LZ4_WILDCOPY(d,s,e) { if (likely(e-d <= 8)) LZ4_COPY8(d,s) else do { LZ4_COPY8(d,s) } while (d>3); michael@0: # elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) michael@0: return (__builtin_clzll(val) >> 3); michael@0: # else michael@0: int r; michael@0: if (!(val>>32)) { r=4; } else { r=0; val>>=32; } michael@0: if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } michael@0: r += (!val); michael@0: return r; michael@0: # endif michael@0: # else michael@0: # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) michael@0: unsigned long r = 0; michael@0: _BitScanForward64( &r, val ); michael@0: return (int)(r>>3); michael@0: # elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) michael@0: return (__builtin_ctzll(val) >> 3); michael@0: # else michael@0: static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; michael@0: return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; michael@0: # endif michael@0: # endif michael@0: } michael@0: michael@0: #else michael@0: michael@0: int LZ4_NbCommonBytes (register U32 val) michael@0: { michael@0: # if defined(LZ4_BIG_ENDIAN) michael@0: # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) michael@0: unsigned long r = 0; michael@0: _BitScanReverse( &r, val ); michael@0: return (int)(r>>3); michael@0: # elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) michael@0: return (__builtin_clz(val) >> 3); michael@0: # else michael@0: int r; michael@0: if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } michael@0: r += (!val); michael@0: return r; michael@0: # endif michael@0: # else michael@0: # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) michael@0: unsigned long r; michael@0: _BitScanForward( &r, val ); michael@0: return (int)(r>>3); michael@0: # elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) michael@0: return (__builtin_ctz(val) >> 3); michael@0: # else michael@0: static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; michael@0: return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; michael@0: # endif michael@0: # endif michael@0: } michael@0: michael@0: #endif michael@0: michael@0: michael@0: /******************************** michael@0: Compression functions michael@0: ********************************/ michael@0: int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } michael@0: michael@0: static int LZ4_hashSequence(U32 sequence, tableType_t tableType) michael@0: { michael@0: if (tableType == byU16) michael@0: return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); michael@0: else michael@0: return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); michael@0: } michael@0: michael@0: static int LZ4_hashPosition(const BYTE* p, tableType_t tableType) { return LZ4_hashSequence(A32(p), tableType); } michael@0: michael@0: static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) michael@0: { michael@0: switch (tableType) michael@0: { michael@0: case byPtr: { const BYTE** hashTable = (const BYTE**) tableBase; hashTable[h] = p; break; } michael@0: case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); break; } michael@0: case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); break; } michael@0: } michael@0: } michael@0: michael@0: static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) michael@0: { michael@0: U32 h = LZ4_hashPosition(p, tableType); michael@0: LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); michael@0: } michael@0: michael@0: static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) michael@0: { michael@0: if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } michael@0: if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } michael@0: { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ michael@0: } michael@0: michael@0: static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) michael@0: { michael@0: U32 h = LZ4_hashPosition(p, tableType); michael@0: return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); michael@0: } michael@0: michael@0: static unsigned LZ4_count(const BYTE* pIn, const BYTE* pRef, const BYTE* pInLimit) michael@0: { michael@0: const BYTE* const pStart = pIn; michael@0: michael@0: while (likely(pIndictSize; michael@0: const BYTE* const dictionary = dictPtr->dictionary; michael@0: const BYTE* const dictEnd = dictionary + dictPtr->dictSize; michael@0: const size_t dictDelta = dictEnd - (const BYTE*)source; michael@0: const BYTE* anchor = (const BYTE*) source; michael@0: const BYTE* const iend = ip + inputSize; michael@0: const BYTE* const mflimit = iend - MFLIMIT; michael@0: const BYTE* const matchlimit = iend - LASTLITERALS; michael@0: michael@0: BYTE* op = (BYTE*) dest; michael@0: BYTE* const olimit = op + maxOutputSize; michael@0: michael@0: const int skipStrength = SKIPSTRENGTH; michael@0: U32 forwardH; michael@0: size_t refDelta=0; michael@0: michael@0: /* Init conditions */ michael@0: if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ michael@0: switch(dict) michael@0: { michael@0: case noDict: michael@0: default: michael@0: base = (const BYTE*)source; michael@0: lowLimit = (const BYTE*)source; michael@0: break; michael@0: case withPrefix64k: michael@0: base = (const BYTE*)source - dictPtr->currentOffset; michael@0: lowLimit = (const BYTE*)source - dictPtr->dictSize; michael@0: break; michael@0: case usingExtDict: michael@0: base = (const BYTE*)source - dictPtr->currentOffset; michael@0: lowLimit = (const BYTE*)source; michael@0: break; michael@0: } michael@0: if ((tableType == byU16) && (inputSize>=(int)LZ4_64KLIMIT)) return 0; /* Size too large (not within 64K limit) */ michael@0: if (inputSize> skipStrength; michael@0: //if (step>8) step=8; // required for valid forwardIp ; slows down uncompressible data a bit michael@0: michael@0: if (unlikely(forwardIp > mflimit)) goto _last_literals; michael@0: michael@0: ref = LZ4_getPositionOnHash(h, ctx, tableType, base); michael@0: if (dict==usingExtDict) michael@0: { michael@0: if (ref<(const BYTE*)source) michael@0: { michael@0: refDelta = dictDelta; michael@0: lowLimit = dictionary; michael@0: } michael@0: else michael@0: { michael@0: refDelta = 0; michael@0: lowLimit = (const BYTE*)source; michael@0: } michael@0: } michael@0: forwardH = LZ4_hashPosition(forwardIp, tableType); michael@0: LZ4_putPositionOnHash(ip, h, ctx, tableType, base); michael@0: michael@0: } while ( ((dictIssue==dictSmall) ? (ref < lowRefLimit) : 0) michael@0: || ((tableType==byU16) ? 0 : (ref + MAX_DISTANCE < ip)) michael@0: || (A32(ref+refDelta) != A32(ip)) ); michael@0: } michael@0: michael@0: /* Catch up */ michael@0: while ((ip>anchor) && (ref+refDelta > lowLimit) && (unlikely(ip[-1]==ref[refDelta-1]))) { ip--; ref--; } michael@0: michael@0: { michael@0: /* Encode Literal length */ michael@0: unsigned litLength = (unsigned)(ip - anchor); michael@0: token = op++; michael@0: if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) michael@0: return 0; /* Check output limit */ michael@0: if (litLength>=RUN_MASK) michael@0: { michael@0: int len = (int)litLength-RUN_MASK; michael@0: *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; michael@0: *op++ = (BYTE)len; michael@0: } michael@0: else *token = (BYTE)(litLength< matchlimit) limit = matchlimit; michael@0: matchLength = LZ4_count(ip+MINMATCH, ref+MINMATCH, limit); michael@0: ip += MINMATCH + matchLength; michael@0: if (ip==limit) michael@0: { michael@0: unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit); michael@0: matchLength += more; michael@0: ip += more; michael@0: } michael@0: } michael@0: else michael@0: { michael@0: matchLength = LZ4_count(ip+MINMATCH, ref+MINMATCH, matchlimit); michael@0: ip += MINMATCH + matchLength; michael@0: } michael@0: michael@0: if (matchLength>=ML_MASK) michael@0: { michael@0: if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit))) michael@0: return 0; /* Check output limit */ michael@0: *token += ML_MASK; michael@0: matchLength -= ML_MASK; michael@0: for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; } michael@0: if (matchLength >= 255) { matchLength-=255; *op++ = 255; } michael@0: *op++ = (BYTE)matchLength; michael@0: } michael@0: else *token += (BYTE)(matchLength); michael@0: } michael@0: michael@0: anchor = ip; michael@0: michael@0: /* Test end of chunk */ michael@0: if (ip > mflimit) break; michael@0: michael@0: /* Fill table */ michael@0: LZ4_putPosition(ip-2, ctx, tableType, base); michael@0: michael@0: /* Test next position */ michael@0: ref = LZ4_getPosition(ip, ctx, tableType, base); michael@0: if (dict==usingExtDict) michael@0: { michael@0: if (ref<(const BYTE*)source) michael@0: { michael@0: refDelta = dictDelta; michael@0: lowLimit = dictionary; michael@0: } michael@0: else michael@0: { michael@0: refDelta = 0; michael@0: lowLimit = (const BYTE*)source; michael@0: } michael@0: } michael@0: LZ4_putPosition(ip, ctx, tableType, base); michael@0: if ( ((dictIssue==dictSmall) ? (ref>=lowRefLimit) : 1) michael@0: && (ref+MAX_DISTANCE>=ip) michael@0: && (A32(ref+refDelta)==A32(ip)) ) michael@0: { token=op++; *token=0; goto _next_match; } michael@0: michael@0: /* Prepare next loop */ michael@0: forwardH = LZ4_hashPosition(++ip, tableType); michael@0: } michael@0: michael@0: _last_literals: michael@0: /* Encode Last Literals */ michael@0: { michael@0: int lastRun = (int)(iend - anchor); michael@0: if ((outputLimited) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) michael@0: return 0; /* Check output limit */ michael@0: if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<= 255 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } michael@0: else *op++ = (BYTE)(lastRun<= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ michael@0: if (dict->initCheck) MEM_INIT(dict, 0, sizeof(LZ4_stream_t_internal)); /* Uninitialized structure detected */ michael@0: michael@0: if (dictSize < MINMATCH) michael@0: { michael@0: dict->dictionary = NULL; michael@0: dict->dictSize = 0; michael@0: return 1; michael@0: } michael@0: michael@0: if (p <= dictEnd - 64 KB) p = dictEnd - 64 KB; michael@0: base = p - dict->currentOffset; michael@0: dict->dictionary = p; michael@0: dict->dictSize = (U32)(dictEnd - p); michael@0: dict->currentOffset += dict->dictSize; michael@0: michael@0: while (p <= dictEnd-MINMATCH) michael@0: { michael@0: LZ4_putPosition(p, dict, byU32, base); michael@0: p+=3; michael@0: } michael@0: michael@0: return 1; michael@0: } michael@0: michael@0: michael@0: void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) michael@0: { michael@0: if ((LZ4_dict->currentOffset > 0x80000000) || michael@0: ((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */ michael@0: { michael@0: /* rescale hash table */ michael@0: U32 delta = LZ4_dict->currentOffset - 64 KB; michael@0: const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; michael@0: int i; michael@0: for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; michael@0: else LZ4_dict->hashTable[i] -= delta; michael@0: } michael@0: LZ4_dict->currentOffset = 64 KB; michael@0: if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; michael@0: LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; michael@0: } michael@0: } michael@0: michael@0: michael@0: FORCE_INLINE int LZ4_compress_continue_generic (void* LZ4_stream, const char* source, char* dest, int inputSize, michael@0: int maxOutputSize, limitedOutput_directive limit) michael@0: { michael@0: LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream; michael@0: const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; michael@0: michael@0: const BYTE* smallest = (const BYTE*) source; michael@0: if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ michael@0: if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; michael@0: LZ4_renormDictT(streamPtr, smallest); michael@0: michael@0: /* Check overlapping input/dictionary space */ michael@0: { michael@0: const BYTE* sourceEnd = (const BYTE*) source + inputSize; michael@0: if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) michael@0: { michael@0: streamPtr->dictSize = (U32)(dictEnd - sourceEnd); michael@0: if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; michael@0: if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; michael@0: streamPtr->dictionary = dictEnd - streamPtr->dictSize; michael@0: } michael@0: } michael@0: michael@0: /* prefix mode : source data follows dictionary */ michael@0: if (dictEnd == (const BYTE*)source) michael@0: { michael@0: int result; michael@0: if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) michael@0: result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, withPrefix64k, dictSmall); michael@0: else michael@0: result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, withPrefix64k, noDictIssue); michael@0: streamPtr->dictSize += (U32)inputSize; michael@0: streamPtr->currentOffset += (U32)inputSize; michael@0: return result; michael@0: } michael@0: michael@0: /* external dictionary mode */ michael@0: { michael@0: int result; michael@0: if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) michael@0: result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, usingExtDict, dictSmall); michael@0: else michael@0: result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, usingExtDict, noDictIssue); michael@0: streamPtr->dictionary = (const BYTE*)source; michael@0: streamPtr->dictSize = (U32)inputSize; michael@0: streamPtr->currentOffset += (U32)inputSize; michael@0: return result; michael@0: } michael@0: } michael@0: michael@0: michael@0: int LZ4_compress_continue (void* LZ4_stream, const char* source, char* dest, int inputSize) michael@0: { michael@0: return LZ4_compress_continue_generic(LZ4_stream, source, dest, inputSize, 0, notLimited); michael@0: } michael@0: michael@0: int LZ4_compress_limitedOutput_continue (void* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize) michael@0: { michael@0: return LZ4_compress_continue_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput); michael@0: } michael@0: michael@0: michael@0: // Hidden debug function, to force separate dictionary mode michael@0: int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize) michael@0: { michael@0: LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict; michael@0: int result; michael@0: const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; michael@0: michael@0: const BYTE* smallest = dictEnd; michael@0: if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; michael@0: LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest); michael@0: michael@0: result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue); michael@0: michael@0: streamPtr->dictionary = (const BYTE*)source; michael@0: streamPtr->dictSize = (U32)inputSize; michael@0: streamPtr->currentOffset += (U32)inputSize; michael@0: michael@0: return result; michael@0: } michael@0: michael@0: michael@0: int LZ4_saveDict (void* LZ4_dict, char* safeBuffer, int dictSize) michael@0: { michael@0: LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; michael@0: const BYTE* previousDictEnd = dict->dictionary + dict->dictSize; michael@0: michael@0: if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ michael@0: if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; michael@0: michael@0: memcpy(safeBuffer, previousDictEnd - dictSize, dictSize); michael@0: michael@0: dict->dictionary = (const BYTE*)safeBuffer; michael@0: dict->dictSize = (U32)dictSize; michael@0: michael@0: return 1; michael@0: } michael@0: michael@0: michael@0: michael@0: /**************************** michael@0: Decompression functions michael@0: ****************************/ michael@0: /* michael@0: * This generic decompression function cover all use cases. michael@0: * It shall be instanciated several times, using different sets of directives michael@0: * Note that it is essential this generic function is really inlined, michael@0: * in order to remove useless branches during compilation optimisation. michael@0: */ michael@0: FORCE_INLINE int LZ4_decompress_generic( michael@0: const char* source, michael@0: char* dest, michael@0: int inputSize, michael@0: int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ michael@0: michael@0: int endOnInput, /* endOnOutputSize, endOnInputSize */ michael@0: int partialDecoding, /* full, partial */ michael@0: int targetOutputSize, /* only used if partialDecoding==partial */ michael@0: int dict, /* noDict, withPrefix64k, usingExtDict */ michael@0: const char* dictStart, /* only if dict==usingExtDict */ michael@0: int dictSize /* note : = 0 if noDict */ michael@0: ) michael@0: { michael@0: /* Local Variables */ michael@0: const BYTE* restrict ip = (const BYTE*) source; michael@0: const BYTE* ref; michael@0: const BYTE* const iend = ip + inputSize; michael@0: michael@0: BYTE* op = (BYTE*) dest; michael@0: BYTE* const oend = op + outputSize; michael@0: BYTE* cpy; michael@0: BYTE* oexit = op + targetOutputSize; michael@0: const BYTE* const lowLimit = (const BYTE*)dest - dictSize; michael@0: michael@0: const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; michael@0: //#define OLD michael@0: #ifdef OLD michael@0: const size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; /* static reduces speed for LZ4_decompress_safe() on GCC64 */ michael@0: #else michael@0: const size_t dec32table[] = {4-0, 4-3, 4-2, 4-3, 4-0, 4-0, 4-0, 4-0}; /* static reduces speed for LZ4_decompress_safe() on GCC64 */ michael@0: #endif michael@0: static const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; michael@0: michael@0: const int checkOffset = (endOnInput) && (dictSize < (int)(64 KB)); michael@0: michael@0: michael@0: /* Special cases */ michael@0: if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ michael@0: if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ michael@0: if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); michael@0: michael@0: michael@0: /* Main Loop */ michael@0: while (1) michael@0: { michael@0: unsigned token; michael@0: size_t length; michael@0: michael@0: /* get runlength */ michael@0: token = *ip++; michael@0: if ((length=(token>>ML_BITS)) == RUN_MASK) michael@0: { michael@0: unsigned s; michael@0: do michael@0: { michael@0: s = *ip++; michael@0: length += s; michael@0: } michael@0: while (likely((endOnInput)?ipLZ4_MAX_INPUT_SIZE)) goto _output_error; /* overflow detection */ michael@0: if ((sizeof(void*)==4) && unlikely((size_t)(op+length)<(size_t)(op))) goto _output_error; /* quickfix issue 134 */ michael@0: if ((endOnInput) && (sizeof(void*)==4) && unlikely((size_t)(ip+length)<(size_t)(ip))) goto _output_error; /* quickfix issue 134 */ michael@0: } michael@0: michael@0: /* copy literals */ michael@0: cpy = op+length; michael@0: if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) michael@0: || ((!endOnInput) && (cpy>oend-COPYLENGTH))) michael@0: { michael@0: if (partialDecoding) michael@0: { michael@0: if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ michael@0: if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ michael@0: } michael@0: else michael@0: { michael@0: if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ michael@0: if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ michael@0: } michael@0: memcpy(op, ip, length); michael@0: ip += length; michael@0: op += length; michael@0: break; /* Necessarily EOF, due to parsing restrictions */ michael@0: } michael@0: LZ4_WILDCOPY(op, ip, cpy); ip -= (op-cpy); op = cpy; michael@0: michael@0: /* get offset */ michael@0: LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2; michael@0: if ((checkOffset) && (unlikely(ref < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */ michael@0: michael@0: /* get matchlength */ michael@0: if ((length=(token&ML_MASK)) == ML_MASK) michael@0: { michael@0: unsigned s; michael@0: do michael@0: { michael@0: if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; michael@0: s = *ip++; michael@0: length += s; michael@0: } while (s==255); michael@0: //if ((sizeof(void*)==4) && unlikely(length>LZ4_MAX_INPUT_SIZE)) goto _output_error; /* overflow detection */ michael@0: if ((sizeof(void*)==4) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* quickfix issue 134 */ michael@0: } michael@0: michael@0: /* check external dictionary */ michael@0: if ((dict==usingExtDict) && (ref < (BYTE* const)dest)) michael@0: { michael@0: if (unlikely(op+length+MINMATCH > oend-LASTLITERALS)) goto _output_error; michael@0: michael@0: if (length+MINMATCH <= (size_t)(dest-(char*)ref)) michael@0: { michael@0: ref = dictEnd - (dest-(char*)ref); michael@0: memcpy(op, ref, length+MINMATCH); michael@0: op += length+MINMATCH; michael@0: } michael@0: else michael@0: { michael@0: size_t copySize = (size_t)(dest-(char*)ref); michael@0: memcpy(op, dictEnd - copySize, copySize); michael@0: op += copySize; michael@0: copySize = length+MINMATCH - copySize; michael@0: if (copySize > (size_t)((char*)op-dest)) /* overlap */ michael@0: { michael@0: BYTE* const cpy = op + copySize; michael@0: const BYTE* ref = (BYTE*)dest; michael@0: while (op < cpy) *op++ = *ref++; michael@0: } michael@0: else michael@0: { michael@0: memcpy(op, dest, copySize); michael@0: op += copySize; michael@0: } michael@0: } michael@0: continue; michael@0: } michael@0: michael@0: /* copy repeated sequence */ michael@0: if (unlikely((op-ref)<(int)STEPSIZE)) michael@0: { michael@0: const size_t dec64 = dec64table[(sizeof(void*)==4) ? 0 : op-ref]; michael@0: op[0] = ref[0]; michael@0: op[1] = ref[1]; michael@0: op[2] = ref[2]; michael@0: op[3] = ref[3]; michael@0: #ifdef OLD michael@0: op += 4, ref += 4; ref -= dec32table[op-ref]; michael@0: A32(op) = A32(ref); michael@0: op += STEPSIZE-4; ref -= dec64; michael@0: #else michael@0: ref += dec32table[op-ref]; michael@0: A32(op+4) = A32(ref); michael@0: op += STEPSIZE; ref -= dec64; michael@0: #endif michael@0: } else { LZ4_COPYSTEP(op,ref); } michael@0: cpy = op + length - (STEPSIZE-4); michael@0: michael@0: if (unlikely(cpy>oend-COPYLENGTH-(STEPSIZE-4))) michael@0: { michael@0: if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last 5 bytes must be literals */ michael@0: if (opdictionary = dictionary; michael@0: lz4sd->dictSize = dictSize; michael@0: return 1; michael@0: } michael@0: michael@0: /* michael@0: *_continue() : michael@0: These decoding functions allow decompression of multiple blocks in "streaming" mode. michael@0: Previously decoded blocks must still be available at the memory position where they were decoded. michael@0: If it's not possible, save the relevant part of decoded data into a safe buffer, michael@0: and indicate where it stands using LZ4_setDictDecode() michael@0: */ michael@0: int LZ4_decompress_safe_continue (void* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) michael@0: { michael@0: LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; michael@0: int result; michael@0: michael@0: result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, lz4sd->dictionary, lz4sd->dictSize); michael@0: if (result <= 0) return result; michael@0: if (lz4sd->dictionary + lz4sd->dictSize == dest) michael@0: { michael@0: lz4sd->dictSize += result; michael@0: } michael@0: else michael@0: { michael@0: lz4sd->dictionary = dest; michael@0: lz4sd->dictSize = result; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: int LZ4_decompress_fast_continue (void* LZ4_streamDecode, const char* source, char* dest, int originalSize) michael@0: { michael@0: LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; michael@0: int result; michael@0: michael@0: result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, lz4sd->dictionary, lz4sd->dictSize); michael@0: if (result <= 0) return result; michael@0: if (lz4sd->dictionary + lz4sd->dictSize == dest) michael@0: { michael@0: lz4sd->dictSize += result; michael@0: } michael@0: else michael@0: { michael@0: lz4sd->dictionary = dest; michael@0: lz4sd->dictSize = result; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: michael@0: /* michael@0: Advanced decoding functions : michael@0: *_usingDict() : michael@0: These decoding functions work the same as "_continue" ones, michael@0: the dictionary must be explicitly provided within parameters michael@0: */ michael@0: michael@0: int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) michael@0: { michael@0: return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, dictStart, dictSize); michael@0: } michael@0: michael@0: int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) michael@0: { michael@0: return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, dictStart, dictSize); michael@0: }