packages feed

lz4-hs 0.1.5.2 → 0.1.5.3

raw patch · 11 files changed

+2882/−2049 lines, 11 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Codec.Lz4.Foreign: Lz4fBlocklinked :: BlockMode
- Codec.Lz4.Foreign: Lz4fDefault :: BlockSize
- Codec.Lz4.Foreign: Lz4fFrame :: FrameType
- Codec.Lz4.Foreign: Lz4fNoblockchecksum :: BlockChecksum
- Codec.Lz4.Foreign: Lz4fNocontentchecksum :: ContentChecksum
- Codec.Lz4.Foreign: data BlockChecksum
- Codec.Lz4.Foreign: data BlockMode
- Codec.Lz4.Foreign: data BlockSize
- Codec.Lz4.Foreign: data ContentChecksum
- Codec.Lz4.Foreign: data FrameType
- Codec.Lz4.Foreign: data LzCtx
- Codec.Lz4.Foreign: data LzDecompressionCtx
- Codec.Lz4.Foreign: instance GHC.Enum.Enum Codec.Lz4.Foreign.BlockChecksum
- Codec.Lz4.Foreign: instance GHC.Enum.Enum Codec.Lz4.Foreign.BlockMode
- Codec.Lz4.Foreign: instance GHC.Enum.Enum Codec.Lz4.Foreign.BlockSize
- Codec.Lz4.Foreign: instance GHC.Enum.Enum Codec.Lz4.Foreign.ContentChecksum
- Codec.Lz4.Foreign: instance GHC.Enum.Enum Codec.Lz4.Foreign.FrameType
- Codec.Lz4.Foreign: lZ4CompressBound :: CInt -> CInt
- Codec.Lz4.Foreign: lZ4CompressDefault :: CString -> CString -> CInt -> CInt -> IO CInt
- Codec.Lz4.Foreign: lZ4CompressHC :: CString -> CString -> CInt -> CInt -> CInt -> IO CInt
- Codec.Lz4.Foreign: lZ4DecompressSafe :: CString -> CString -> CInt -> CInt -> IO CInt
- Codec.Lz4.Foreign: lZ4FCompressBegin :: LzCtxPtr -> Ptr a -> CSize -> LzPreferencesPtr -> IO CSize
- Codec.Lz4.Foreign: lZ4FCompressBound :: CSize -> LzPreferencesPtr -> CSize
- Codec.Lz4.Foreign: lZ4FCompressEnd :: LzCtxPtr -> Ptr a -> CSize -> LzCompressOptionsPtr -> IO CSize
- Codec.Lz4.Foreign: lZ4FCompressUpdate :: LzCtxPtr -> Ptr a -> CSize -> Ptr b -> CSize -> LzCompressOptionsPtr -> IO CSize
- Codec.Lz4.Foreign: lZ4FCreateCompressionContext :: CUInt -> IO (LZ4FErrorCode, Ptr LzCtx)
- Codec.Lz4.Foreign: lZ4FCreateDecompressionContext :: CUInt -> IO (LZ4FErrorCode, Ptr LzDecompressionCtx)
- Codec.Lz4.Foreign: lZ4FDecompress :: LzDecompressionCtxPtr -> Ptr a -> Ptr CSize -> Ptr b -> Ptr CSize -> LzDecompressOptionsPtr -> IO CSize
- Codec.Lz4.Foreign: lZ4FFreeCompressionContext :: FinalizerPtr ()
- Codec.Lz4.Foreign: lZ4FFreeDecompressionContext :: FinalizerPtr ()
- Codec.Lz4.Foreign: lZ4FGetErrorName :: LZ4FErrorCode -> String
- Codec.Lz4.Foreign: lZ4FGetVersion :: CUInt
- Codec.Lz4.Foreign: lZ4FHeaderSizeMax :: Integral a => a
- Codec.Lz4.Foreign: lZ4FIsError :: LZ4FErrorCode -> Bool
- Codec.Lz4.Foreign: lZ4HCClevelMax :: Integral a => a
- Codec.Lz4.Foreign: lZ4MaxInputSize :: Integral a => a
- Codec.Lz4.Foreign: lZ4VersionNumber :: CInt
- Codec.Lz4.Foreign: lZ4VersionString :: String
- Codec.Lz4.Foreign: type LZ4FErrorCode = CSize
- Codec.Lz4.Foreign: type LzCtxPtr = ForeignPtr LzCtx
- Codec.Lz4.Foreign: type LzDecompressionCtxPtr = ForeignPtr LzDecompressionCtx
- Codec.Lz4.Foreign: type LzPreferencesPtr = ForeignPtr LzPreferences

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # lz4 +## 0.1.5.3++  * Upgrade bundled sources to 1.10.0+  * Tiny efficiency gain+ ## 0.1.5.2    * Upgrade bundled sources to 1.9.4
cbits/lz4.c view
@@ -1,6 +1,6 @@ /*    LZ4 - Fast LZ compression algorithm-   Copyright (C) 2011-2020, Yann Collet.+   Copyright (C) 2011-2023, Yann Collet.     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -37,7 +37,8 @@ **************************************/ /*  * LZ4_HEAPMODE :- * Select how default compression functions will allocate memory for their hash table,+ * Select how stateless compression functions like `LZ4_compress_default()`+ * allocate memory for their hash table,  * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).  */ #ifndef LZ4_HEAPMODE@@ -78,7 +79,7 @@   ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) \   || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) #    define LZ4_FORCE_MEMORY_ACCESS 2-#  elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__)+#  elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__) || defined(_MSC_VER) #    define LZ4_FORCE_MEMORY_ACCESS 1 #  endif #endif@@ -105,15 +106,13 @@ #  define LZ4_SRC_INCLUDED 1 #endif -#ifndef LZ4_STATIC_LINKING_ONLY-#define LZ4_STATIC_LINKING_ONLY-#endif- #ifndef LZ4_DISABLE_DEPRECATE_WARNINGS-#define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */+#  define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */ #endif -#define LZ4_STATIC_LINKING_ONLY  /* LZ4_DISTANCE_MAX */+#ifndef LZ4_STATIC_LINKING_ONLY+#  define LZ4_STATIC_LINKING_ONLY+#endif #include "lz4.h" /* see also "memory routines" below */ @@ -125,14 +124,17 @@ #  include <intrin.h>               /* only present in VS2005+ */ #  pragma warning(disable : 4127)   /* disable: C4127: conditional expression is constant */ #  pragma warning(disable : 6237)   /* disable: C6237: conditional expression is always 0 */+#  pragma warning(disable : 6239)   /* disable: C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression> */+#  pragma warning(disable : 6240)   /* disable: C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression> */+#  pragma warning(disable : 6326)   /* disable: C6326: Potential comparison of a constant with another constant */ #endif  /* _MSC_VER */  #ifndef LZ4_FORCE_INLINE-#  ifdef _MSC_VER    /* Visual Studio */+#  if defined (_MSC_VER) && !defined (__clang__)    /* MSVC */ #    define LZ4_FORCE_INLINE static __forceinline #  else #    if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */-#      ifdef __GNUC__+#      if defined (__GNUC__) || defined (__clang__) #        define LZ4_FORCE_INLINE static inline __attribute__((always_inline)) #      else #        define LZ4_FORCE_INLINE static inline@@ -279,7 +281,7 @@    static int g_debuglog_enable = 1; #  define DEBUGLOG(l, ...) {                          \         if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) {  \-            fprintf(stderr, __FILE__ ": ");           \+            fprintf(stderr, __FILE__  " %i: ", __LINE__); \             fprintf(stderr, __VA_ARGS__);             \             fprintf(stderr, " \n");                   \     }   }@@ -364,6 +366,11 @@     return one.c[0]; } +#if defined(__GNUC__) || defined(__INTEL_COMPILER)+#define LZ4_PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))+#elif defined(_MSC_VER)+#define LZ4_PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop))+#endif  #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) /* lie to the compiler about data alignment; use with caution */@@ -379,14 +386,16 @@  /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ /* currently only defined for gcc and icc */-typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) LZ4_unalign;+LZ4_PACK(typedef struct { U16 u16; }) LZ4_unalign16;+LZ4_PACK(typedef struct { U32 u32; }) LZ4_unalign32;+LZ4_PACK(typedef struct { reg_t uArch; }) LZ4_unalignST; -static U16 LZ4_read16(const void* ptr) { return ((const LZ4_unalign*)ptr)->u16; }-static U32 LZ4_read32(const void* ptr) { return ((const LZ4_unalign*)ptr)->u32; }-static reg_t LZ4_read_ARCH(const void* ptr) { return ((const LZ4_unalign*)ptr)->uArch; }+static U16 LZ4_read16(const void* ptr) { return ((const LZ4_unalign16*)ptr)->u16; }+static U32 LZ4_read32(const void* ptr) { return ((const LZ4_unalign32*)ptr)->u32; }+static reg_t LZ4_read_ARCH(const void* ptr) { return ((const LZ4_unalignST*)ptr)->uArch; } -static void LZ4_write16(void* memPtr, U16 value) { ((LZ4_unalign*)memPtr)->u16 = value; }-static void LZ4_write32(void* memPtr, U32 value) { ((LZ4_unalign*)memPtr)->u32 = value; }+static void LZ4_write16(void* memPtr, U16 value) { ((LZ4_unalign16*)memPtr)->u16 = value; }+static void LZ4_write32(void* memPtr, U32 value) { ((LZ4_unalign32*)memPtr)->u32 = value; }  #else  /* safe and portable access using memcpy() */ @@ -424,10 +433,22 @@         return LZ4_read16(memPtr);     } else {         const BYTE* p = (const BYTE*)memPtr;-        return (U16)((U16)p[0] + (p[1]<<8));+        return (U16)((U16)p[0] | (p[1]<<8));     } } +#ifdef LZ4_STATIC_LINKING_ONLY_ENDIANNESS_INDEPENDENT_OUTPUT+static U32 LZ4_readLE32(const void* memPtr)+{+    if (LZ4_isLittleEndian()) {+        return LZ4_read32(memPtr);+    } else {+        const BYTE* p = (const BYTE*)memPtr;+        return (U32)p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);+    }+}+#endif+ static void LZ4_writeLE16(void* memPtr, U16 value) {     if (LZ4_isLittleEndian()) {@@ -509,7 +530,7 @@  /* LZ4_memcpy_using_offset()  presumes :  * - dstEnd >= dstPtr + MINMATCH- * - there is at least 8 bytes available to write after dstEnd */+ * - there is at least 12 bytes available to write after dstEnd */ LZ4_FORCE_INLINE void LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset) {@@ -524,12 +545,12 @@     case 2:         LZ4_memcpy(v, srcPtr, 2);         LZ4_memcpy(&v[2], srcPtr, 2);-#if defined(_MSC_VER) && (_MSC_VER <= 1933) /* MSVC 2022 ver 17.3 or earlier */+#if defined(_MSC_VER) && (_MSC_VER <= 1937) /* MSVC 2022 ver 17.7 or earlier */ #  pragma warning(push) #  pragma warning(disable : 6385) /* warning C6385: Reading invalid data from 'v'. */ #endif         LZ4_memcpy(&v[4], v, 4);-#if defined(_MSC_VER) && (_MSC_VER <= 1933) /* MSVC 2022 ver 17.3 or earlier */+#if defined(_MSC_VER) && (_MSC_VER <= 1937) /* MSVC 2022 ver 17.7 or earlier */ #  pragma warning(pop) #endif         break;@@ -776,7 +797,12 @@ LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) {     if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType);++#ifdef LZ4_STATIC_LINKING_ONLY_ENDIANNESS_INDEPENDENT_OUTPUT+    return LZ4_hash4(LZ4_readLE32(p), tableType);+#else     return LZ4_hash4(LZ4_read32(p), tableType);+#endif }  LZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType)@@ -803,23 +829,19 @@     } } +/* LZ4_putPosition*() : only used in byPtr mode */ LZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h,-                                  void* tableBase, tableType_t const tableType,-                            const BYTE* srcBase)+                                  void* tableBase, tableType_t const tableType) {-    switch (tableType)-    {-    case clearedTable: { /* illegal! */ assert(0); return; }-    case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }-    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }-    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }-    }+    const BYTE** const hashTable = (const BYTE**)tableBase;+    assert(tableType == byPtr); (void)tableType;+    hashTable[h] = p; } -LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)+LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType) {     U32 const h = LZ4_hashPosition(p, tableType);-    LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);+    LZ4_putPositionOnHash(p, h, tableBase, tableType); }  /* LZ4_getIndexOnHash() :@@ -844,20 +866,18 @@     assert(0); return 0;  /* forbidden case */ } -static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType, const BYTE* srcBase)+static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType) {-    if (tableType == byPtr) { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; }-    if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h] + srcBase; }-    { const U16* const hashTable = (const U16*) tableBase; return hashTable[h] + srcBase; }   /* default, to ensure a return */+    assert(tableType == byPtr); (void)tableType;+    { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; } }  LZ4_FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p,-                const void* tableBase, tableType_t tableType,-                const BYTE* srcBase)+                const void* tableBase, tableType_t tableType) {     U32 const h = LZ4_hashPosition(p, tableType);-    return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);+    return LZ4_getPositionOnHash(h, tableBase, tableType); }  LZ4_FORCE_INLINE void@@ -901,9 +921,9 @@     cctx->dictSize = 0; } -/** LZ4_compress_generic() :+/** LZ4_compress_generic_validated() :  *  inlined, to ensure branches are decided at compilation time.- *  Presumed already validated at this stage:+ *  The following conditions are presumed already validated:  *  - source != NULL  *  - inputSize > 0  */@@ -921,10 +941,10 @@                  const int acceleration) {     int result;-    const BYTE* ip = (const BYTE*) source;+    const BYTE* ip = (const BYTE*)source;      U32 const startIndex = cctx->currentOffset;-    const BYTE* base = (const BYTE*) source - startIndex;+    const BYTE* base = (const BYTE*)source - startIndex;     const BYTE* lowLimit;      const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx;@@ -932,7 +952,8 @@         dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary;     const U32 dictSize =         dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize;-    const U32 dictDelta = (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0;   /* make indexes in dictCtx comparable with index in current context */+    const U32 dictDelta =+        (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0;   /* make indexes in dictCtx comparable with indexes in current context */      int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx);     U32 const prefixIdxLimit = startIndex - dictSize;   /* used when dictDirective == dictSmall */@@ -957,11 +978,11 @@      DEBUGLOG(5, "LZ4_compress_generic_validated: srcSize=%i, tableType=%u", inputSize, tableType);     assert(ip != NULL);+    if (tableType == byU16) assert(inputSize<LZ4_64Klimit);  /* Size too large (not within 64K limit) */+    if (tableType == byPtr) assert(dictDirective==noDict);   /* only supported use case with byPtr */     /* If init conditions are not met, we don't have to mark stream      * as having dirty context, since no action was taken yet */     if (outputDirective == fillOutput && maxOutputSize < 1) { return 0; } /* Impossible to store anything */-    if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) { return 0; }  /* Size too large (not within 64K limit) */-    if (tableType==byPtr) assert(dictDirective==noDict);      /* only supported use case with byPtr */     assert(acceleration >= 1);      lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0);@@ -981,7 +1002,12 @@     if (inputSize<LZ4_minLength) goto _last_literals;        /* Input too small, no compression (all literals) */      /* First Byte */-    LZ4_putPosition(ip, cctx->hashTable, tableType, base);+    {   U32 const h = LZ4_hashPosition(ip, tableType);+        if (tableType == byPtr) {+            LZ4_putPositionOnHash(ip, h, cctx->hashTable, byPtr);+        } else {+            LZ4_putIndexOnHash(startIndex, h, cctx->hashTable, tableType);+    }   }     ip++; forwardH = LZ4_hashPosition(ip, tableType);      /* Main Loop */@@ -1004,9 +1030,9 @@                 if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;                 assert(ip < mflimitPlusOne); -                match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);+                match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType);                 forwardH = LZ4_hashPosition(forwardIp, tableType);-                LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);+                LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType);              } while ( (match+LZ4_DISTANCE_MAX < ip)                    || (LZ4_read32(match) != LZ4_read32(ip)) );@@ -1077,7 +1103,10 @@          /* Catch up */         filledIp = ip;-        while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }+        assert(ip > anchor); /* this is always true as ip has been advanced before entering the main loop */+        if ((match > lowLimit) && unlikely(ip[-1] == match[-1])) {+            do { ip--; match--; } while (((ip > anchor) & (match > lowLimit)) && (unlikely(ip[-1] == match[-1])));+        }          /* Encode Literals */         {   unsigned const litLength = (unsigned)(ip - anchor);@@ -1092,7 +1121,7 @@                 goto _last_literals;             }             if (litLength >= RUN_MASK) {-                int len = (int)(litLength - RUN_MASK);+                unsigned len = litLength - RUN_MASK;                 *token = (RUN_MASK<<ML_BITS);                 for(; len >= 255 ; len-=255) *op++ = 255;                 *op++ = (BYTE)len;@@ -1204,13 +1233,19 @@         if (ip >= mflimitPlusOne) break;          /* Fill table */-        LZ4_putPosition(ip-2, cctx->hashTable, tableType, base);+        {   U32 const h = LZ4_hashPosition(ip-2, tableType);+            if (tableType == byPtr) {+                LZ4_putPositionOnHash(ip-2, h, cctx->hashTable, byPtr);+            } else {+                U32 const idx = (U32)((ip-2) - base);+                LZ4_putIndexOnHash(idx, h, cctx->hashTable, tableType);+        }   }          /* Test next position */         if (tableType == byPtr) { -            match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);-            LZ4_putPosition(ip, cctx->hashTable, tableType, base);+            match = LZ4_getPosition(ip, cctx->hashTable, tableType);+            LZ4_putPosition(ip, cctx->hashTable, tableType);             if ( (match+LZ4_DISTANCE_MAX >= ip)               && (LZ4_read32(match) == LZ4_read32(ip)) )             { token=op++; *token=0; goto _next_match; }@@ -1224,6 +1259,7 @@             if (dictDirective == usingDictCtx) {                 if (matchIndex < startIndex) {                     /* there was no match, try the dictionary */+                    assert(tableType == byU32);                     matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);                     match = dictBase + matchIndex;                     lowLimit = dictionary;   /* required for match length counter */@@ -1377,9 +1413,10 @@  */ int LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration) {-    LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse;+    LZ4_stream_t_internal* const ctx = &((LZ4_stream_t*)state)->internal_donotuse;     if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;     if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;+    assert(ctx != NULL);      if (dstCapacity >= LZ4_compressBound(srcSize)) {         if (srcSize < LZ4_64Klimit) {@@ -1413,17 +1450,17 @@ }  -int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)+int LZ4_compress_fast(const char* src, char* dest, int srcSize, int dstCapacity, int acceleration) {     int result; #if (LZ4_HEAPMODE)-    LZ4_stream_t* ctxPtr = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));   /* malloc-calloc always properly aligned */+    LZ4_stream_t* const ctxPtr = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));   /* malloc-calloc always properly aligned */     if (ctxPtr == NULL) return 0; #else     LZ4_stream_t ctx;     LZ4_stream_t* const ctxPtr = &ctx; #endif-    result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);+    result = LZ4_compress_fast_extState(ctxPtr, src, dest, srcSize, dstCapacity, acceleration);  #if (LZ4_HEAPMODE)     FREEMEM(ctxPtr);@@ -1432,43 +1469,51 @@ }  -int LZ4_compress_default(const char* src, char* dst, int srcSize, int maxOutputSize)+int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity) {-    return LZ4_compress_fast(src, dst, srcSize, maxOutputSize, 1);+    return LZ4_compress_fast(src, dst, srcSize, dstCapacity, 1); }   /* Note!: This function leaves the stream in an unclean/broken state!  * It is not safe to subsequently use the same state with a _fastReset() or  * _continue() call without resetting it. */-static int LZ4_compress_destSize_extState (LZ4_stream_t* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize)+static int LZ4_compress_destSize_extState_internal(LZ4_stream_t* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize, int acceleration) {     void* const s = LZ4_initStream(state, sizeof (*state));     assert(s != NULL); (void)s;      if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) {  /* compression success is guaranteed */-        return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);+        return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, acceleration);     } else {         if (*srcSizePtr < LZ4_64Klimit) {-            return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, byU16, noDict, noDictIssue, 1);+            return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, byU16, noDict, noDictIssue, acceleration);         } else {             tableType_t const addrMode = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;-            return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, addrMode, noDict, noDictIssue, 1);+            return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, addrMode, noDict, noDictIssue, acceleration);     }   } } +int LZ4_compress_destSize_extState(void* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize, int acceleration)+{+    int const r = LZ4_compress_destSize_extState_internal((LZ4_stream_t*)state, src, dst, srcSizePtr, targetDstSize, acceleration);+    /* clean the state on exit */+    LZ4_initStream(state, sizeof (LZ4_stream_t));+    return r;+} + int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) { #if (LZ4_HEAPMODE)-    LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));   /* malloc-calloc always properly aligned */+    LZ4_stream_t* const ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));   /* malloc-calloc always properly aligned */     if (ctx == NULL) return 0; #else     LZ4_stream_t ctxBody;-    LZ4_stream_t* ctx = &ctxBody;+    LZ4_stream_t* const ctx = &ctxBody; #endif -    int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);+    int result = LZ4_compress_destSize_extState_internal(ctx, src, dst, srcSizePtr, targetDstSize, 1);  #if (LZ4_HEAPMODE)     FREEMEM(ctx);@@ -1537,14 +1582,17 @@ #endif  +typedef enum { _ld_fast, _ld_slow } LoadDict_mode_e; #define HASH_UNIT sizeof(reg_t)-int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)+int LZ4_loadDict_internal(LZ4_stream_t* LZ4_dict,+                    const char* dictionary, int dictSize,+                    LoadDict_mode_e _ld) {-    LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse;+    LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse;     const tableType_t tableType = byU32;     const BYTE* p = (const BYTE*)dictionary;     const BYTE* const dictEnd = p + dictSize;-    const BYTE* base;+    U32 idx32;      DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict); @@ -1567,19 +1615,46 @@     }      if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;-    base = dictEnd - dict->currentOffset;     dict->dictionary = p;     dict->dictSize = (U32)(dictEnd - p);     dict->tableType = (U32)tableType;+    idx32 = dict->currentOffset - dict->dictSize;      while (p <= dictEnd-HASH_UNIT) {-        LZ4_putPosition(p, dict->hashTable, tableType, base);-        p+=3;+        U32 const h = LZ4_hashPosition(p, tableType);+        /* Note: overwriting => favors positions end of dictionary */+        LZ4_putIndexOnHash(idx32, h, dict->hashTable, tableType);+        p+=3; idx32+=3;     } +    if (_ld == _ld_slow) {+        /* Fill hash table with additional references, to improve compression capability */+        p = dict->dictionary;+        idx32 = dict->currentOffset - dict->dictSize;+        while (p <= dictEnd-HASH_UNIT) {+            U32 const h = LZ4_hashPosition(p, tableType);+            U32 const limit = dict->currentOffset - 64 KB;+            if (LZ4_getIndexOnHash(h, dict->hashTable, tableType) <= limit) {+                /* Note: not overwriting => favors positions beginning of dictionary */+                LZ4_putIndexOnHash(idx32, h, dict->hashTable, tableType);+            }+            p++; idx32++;+        }+    }+     return (int)dict->dictSize; } +int LZ4_loadDict(LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)+{+    return LZ4_loadDict_internal(LZ4_dict, dictionary, dictSize, _ld_fast);+}++int LZ4_loadDictSlow(LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)+{+    return LZ4_loadDict_internal(LZ4_dict, dictionary, dictSize, _ld_slow);+}+ void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream) {     const LZ4_stream_t_internal* dictCtx = (dictionaryStream == NULL) ? NULL :@@ -1711,7 +1786,7 @@ /* Hidden debug function, to force-test external dictionary mode */ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize) {-    LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse;+    LZ4_stream_t_internal* const streamPtr = &LZ4_dict->internal_donotuse;     int result;      LZ4_renormDictT(streamPtr, srcSize);@@ -1774,7 +1849,7 @@  * does not know end of input  * presumes input is well formed  * note : will consume at least one byte */-size_t read_long_length_no_check(const BYTE** pp)+static size_t read_long_length_no_check(const BYTE** pp) {     size_t b, l = 0;     do { b = **pp; (*pp)++; l += b; } while (b==255);@@ -1911,6 +1986,17 @@     if (initial_check && unlikely((*ip) >= ilimit)) {    /* read limit reached */         return rvl_error;     }+    s = **ip;+    (*ip)++;+    length += s;+    if (unlikely((*ip) > ilimit)) {    /* read limit reached */+        return rvl_error;+    }+    /* accumulator overflow detection (32-bit mode only) */+    if ((sizeof(length) < 8) && unlikely(length > ((Rvl_t)(-1)/2)) ) {+        return rvl_error;+    }+    if (likely(s != 255)) return length;     do {         s = **ip;         (*ip)++;@@ -1919,10 +2005,10 @@             return rvl_error;         }         /* accumulator overflow detection (32-bit mode only) */-        if ((sizeof(length)<8) && unlikely(length > ((Rvl_t)(-1)/2)) ) {+        if ((sizeof(length) < 8) && unlikely(length > ((Rvl_t)(-1)/2)) ) {             return rvl_error;         }-    } while (s==255);+    } while (s == 255);      return length; }@@ -1988,63 +2074,73 @@      * note : fast loop may show a regression for some client arm chips. */ #if LZ4_FAST_DEC_LOOP         if ((oend - op) < FASTLOOP_SAFE_DISTANCE) {-            DEBUGLOG(6, "skip fast decode loop");+            DEBUGLOG(6, "move to safe decode loop");             goto safe_decode;         }          /* Fast loop : decode sequences as long as output < oend-FASTLOOP_SAFE_DISTANCE */+        DEBUGLOG(6, "using fast decode loop");         while (1) {             /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */             assert(oend - op >= FASTLOOP_SAFE_DISTANCE);             assert(ip < iend);             token = *ip++;             length = token >> ML_BITS;  /* literal length */+            DEBUGLOG(7, "blockPos%6u: litLength token = %u", (unsigned)(op-(BYTE*)dst), (unsigned)length);              /* decode literal length */             if (length == RUN_MASK) {                 size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1);-                if (addl == rvl_error) { goto _output_error; }+                if (addl == rvl_error) {+                    DEBUGLOG(6, "error reading long literal length");+                    goto _output_error;+                }                 length += addl;                 if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */                 if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */                  /* copy literals */-                cpy = op+length;                 LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);-                if ((cpy>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; }-                LZ4_wildCopy32(op, ip, cpy);-                ip += length; op = cpy;-            } else {-                cpy = op+length;-                DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length);+                if ((op+length>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; }+                LZ4_wildCopy32(op, ip, op+length);+                ip += length; op += length;+            } else if (ip <= iend-(16 + 1/*max lit + offset + nextToken*/)) {                 /* We don't need to check oend, since we check it once for each loop below */-                if (ip > iend-(16 + 1/*max lit + offset + nextToken*/)) { goto safe_literal_copy; }+                DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length);                 /* Literals can only be <= 14, but hope compilers optimize better when copy by a register size */                 LZ4_memcpy(op, ip, 16);-                ip += length; op = cpy;+                ip += length; op += length;+            } else {+                goto safe_literal_copy;             }              /* get offset */             offset = LZ4_readLE16(ip); ip+=2;+            DEBUGLOG(6, "blockPos%6u: offset = %u", (unsigned)(op-(BYTE*)dst), (unsigned)offset);             match = op - offset;             assert(match <= op);  /* overflow check */              /* get matchlength */             length = token & ML_MASK;+            DEBUGLOG(7, "  match length token = %u (len==%u)", (unsigned)length, (unsigned)length+MINMATCH);              if (length == ML_MASK) {                 size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0);-                if (addl == rvl_error) { goto _output_error; }+                if (addl == rvl_error) {+                    DEBUGLOG(5, "error reading long match length");+                    goto _output_error;+                }                 length += addl;                 length += MINMATCH;+                DEBUGLOG(7, "  long match length == %u", (unsigned)length);                 if (unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */-                if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */                 if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {                     goto safe_match_copy;                 }             } else {                 length += MINMATCH;                 if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {+                    DEBUGLOG(7, "moving to safe_match_copy (ml==%u)", (unsigned)length);                     goto safe_match_copy;                 } @@ -2062,7 +2158,10 @@                         continue;             }   }   } -            if (checkOffset && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */+            if ( checkOffset && (unlikely(match + dictSize < lowPrefix)) ) {+                DEBUGLOG(5, "Error : pos=%zi, offset=%zi => outside buffers", op-lowPrefix, op-match);+                goto _output_error;+            }             /* match starting within external dictionary */             if ((dict==usingExtDict) && (match < lowPrefix)) {                 assert(dictEnd != NULL);@@ -2071,7 +2170,8 @@                         DEBUGLOG(7, "partialDecoding: dictionary match, close to dstEnd");                         length = MIN(length, (size_t)(oend-op));                     } else {-                        goto _output_error;  /* end-of-block condition violated */+                        DEBUGLOG(6, "end-of-block condition violated")+                        goto _output_error;                 }   }                  if (length <= (size_t)(lowPrefix-match)) {@@ -2111,10 +2211,12 @@ #endif          /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */+        DEBUGLOG(6, "using safe decode loop");         while (1) {             assert(ip < iend);             token = *ip++;             length = token >> ML_BITS;  /* literal length */+            DEBUGLOG(7, "blockPos%6u: litLength token = %u", (unsigned)(op-(BYTE*)dst), (unsigned)length);              /* A two-stage shortcut for the most common case:              * 1) If the literal length is 0..14, and there is enough space,@@ -2135,6 +2237,7 @@                 /* The second stage: prepare for match copying, decode full info.                  * If it doesn't work out, the info won't be wasted. */                 length = token & ML_MASK; /* match length */+                DEBUGLOG(7, "blockPos%6u: matchLength token = %u (len=%u)", (unsigned)(op-(BYTE*)dst), (unsigned)length, (unsigned)length + 4);                 offset = LZ4_readLE16(ip); ip += 2;                 match = op - offset;                 assert(match <= op); /* check overflow */@@ -2166,11 +2269,12 @@                 if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */             } -            /* copy literals */-            cpy = op+length; #if LZ4_FAST_DEC_LOOP         safe_literal_copy: #endif+            /* copy literals */+            cpy = op+length;+             LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);             if ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) {                 /* We've either hit the input parsing restriction or the output parsing restriction.@@ -2206,9 +2310,10 @@                       * so check that we exactly consume the input and don't overrun the output buffer.                       */                     if ((ip+length != iend) || (cpy > oend)) {-                        DEBUGLOG(6, "should have been last run of literals")-                        DEBUGLOG(6, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend);-                        DEBUGLOG(6, "or cpy(%p) > oend(%p)", cpy, oend);+                        DEBUGLOG(5, "should have been last run of literals")+                        DEBUGLOG(5, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend);+                        DEBUGLOG(5, "or cpy(%p) > (oend-MFLIMIT)(%p)", cpy, oend-MFLIMIT);+                        DEBUGLOG(5, "after writing %u bytes / %i bytes available", (unsigned)(op-(BYTE*)dst), outputSize);                         goto _output_error;                     }                 }@@ -2234,6 +2339,7 @@              /* get matchlength */             length = token & ML_MASK;+            DEBUGLOG(7, "blockPos%6u: matchLength token = %u", (unsigned)(op-(BYTE*)dst), (unsigned)length);      _copy_match:             if (length == ML_MASK) {@@ -2323,7 +2429,7 @@                 while (op < cpy) { *op++ = *match++; }             } else {                 LZ4_memcpy(op, match, 8);-                if (length > 16)  { LZ4_wildCopy8(op+8, match+8, cpy); }+                if (length > 16) { LZ4_wildCopy8(op+8, match+8, cpy); }             }             op = cpy;   /* wildcopy correction */         }@@ -2418,6 +2524,7 @@                                      int compressedSize, int maxOutputSize,                                      const void* dictStart, size_t dictSize) {+    DEBUGLOG(5, "LZ4_decompress_safe_forceExtDict");     return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,                                   decode_full_block, usingExtDict,                                   (BYTE*)dest, (const BYTE*)dictStart, dictSize);
cbits/lz4.h view
@@ -1,7 +1,7 @@ /*  *  LZ4 - Fast LZ compression algorithm  *  Header File- *  Copyright (C) 2011-2020, Yann Collet.+ *  Copyright (C) 2011-2023, Yann Collet.     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -129,8 +129,8 @@  /*------   Version   ------*/ #define LZ4_VERSION_MAJOR    1    /* for breaking interface changes  */-#define LZ4_VERSION_MINOR    9    /* for new (non-breaking) interface capabilities */-#define LZ4_VERSION_RELEASE  4    /* for tweaks, bug-fixes, or development */+#define LZ4_VERSION_MINOR   10    /* for new (non-breaking) interface capabilities */+#define LZ4_VERSION_RELEASE  0    /* for tweaks, bug-fixes, or development */  #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) @@ -144,23 +144,25 @@   /*-************************************-*  Tuning parameter+*  Tuning memory usage **************************************/-#define LZ4_MEMORY_USAGE_MIN 10-#define LZ4_MEMORY_USAGE_DEFAULT 14-#define LZ4_MEMORY_USAGE_MAX 20- /*!  * LZ4_MEMORY_USAGE :- * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; )- * Increasing memory usage improves compression ratio, at the cost of speed.+ * Can be selected at compile time, by setting LZ4_MEMORY_USAGE.+ * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB)+ * Increasing memory usage improves compression ratio, generally at the cost of speed.  * Reduced memory usage may improve speed at the cost of ratio, thanks to better cache locality.- * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache+ * Default value is 14, for 16KB, which nicely fits into most L1 caches.  */ #ifndef LZ4_MEMORY_USAGE # define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT #endif +/* These are absolute limits, they should not be changed by users */+#define LZ4_MEMORY_USAGE_MIN 10+#define LZ4_MEMORY_USAGE_DEFAULT 14+#define LZ4_MEMORY_USAGE_MAX 20+ #if (LZ4_MEMORY_USAGE < LZ4_MEMORY_USAGE_MIN) #  error "LZ4_MEMORY_USAGE is too small !" #endif@@ -189,8 +191,9 @@ LZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity);  /*! LZ4_decompress_safe() :- *  compressedSize : is the exact complete size of the compressed block.- *  dstCapacity : is the size of destination buffer (which must be already allocated), presumed an upper bound of decompressed size.+ * @compressedSize : is the exact complete size of the compressed block.+ * @dstCapacity : is the size of destination buffer (which must be already allocated),+ *                presumed an upper bound of decompressed size.  * @return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity)  *           If destination buffer is not large enough, decoding will stop and output an error code (negative value).  *           If the source stream is detected malformed, the function will stop decoding and return a negative result.@@ -242,20 +245,20 @@ LZ4LIB_API int LZ4_sizeofState(void); LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); - /*! LZ4_compress_destSize() :  *  Reverse the logic : compresses as much data as possible from 'src' buffer- *  into already allocated buffer 'dst', of size >= 'targetDestSize'.+ *  into already allocated buffer 'dst', of size >= 'dstCapacity'.  *  This function either compresses the entire 'src' content into 'dst' if it's large enough,  *  or fill 'dst' buffer completely with as much data as possible from 'src'.  *  note: acceleration parameter is fixed to "default".  *- * *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'.+ * *srcSizePtr : in+out parameter. Initially contains size of input.+ *               Will be modified to indicate how many bytes where read from 'src' to fill 'dst'.  *               New value is necessarily <= input value.- * @return : Nb bytes written into 'dst' (necessarily <= targetDestSize)+ * @return : Nb bytes written into 'dst' (necessarily <= dstCapacity)  *           or 0 if compression fails.  *- * Note : from v1.8.2 to v1.9.1, this function had a bug (fixed un v1.9.2+):+ * Note : from v1.8.2 to v1.9.1, this function had a bug (fixed in v1.9.2+):  *        the produced compressed content could, in specific circumstances,  *        require to be decompressed into a destination buffer larger  *        by at least 1 byte than the content to decompress.@@ -266,8 +269,7 @@  *        a dstCapacity which is > decompressedSize, by at least 1 byte.  *        See https://github.com/lz4/lz4/issues/859 for details  */-LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize);-+LZ4LIB_API int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize);  /*! LZ4_decompress_safe_partial() :  *  Decompress an LZ4 compressed block, of size 'srcSize' at position 'src',@@ -311,7 +313,7 @@ ***********************************************/ typedef union LZ4_stream_u LZ4_stream_t;  /* incomplete type (defined later) */ -/**+/*!  Note about RC_INVOKED   - RC_INVOKED is predefined symbol of rc.exe (the resource compiler which is part of MSVC/Visual Studio).@@ -361,13 +363,58 @@  *  LZ4_loadDict() triggers a reset, so any previous data will be forgotten.  *  The same dictionary will have to be loaded on decompression side for successful decoding.  *  Dictionary are useful for better compression of small data (KB range).- *  While LZ4 accept any input as dictionary,- *  results are generally better when using Zstandard's Dictionary Builder.+ *  While LZ4 itself accepts any input as dictionary, dictionary efficiency is also a topic.+ *  When in doubt, employ the Zstandard's Dictionary Builder.  *  Loading a size of 0 is allowed, and is the same as reset.- * @return : loaded dictionary size, in bytes (necessarily <= 64 KB)+ * @return : loaded dictionary size, in bytes (note: only the last 64 KB are loaded)  */ LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); +/*! LZ4_loadDictSlow() : v1.10.0++ *  Same as LZ4_loadDict(),+ *  but uses a bit more cpu to reference the dictionary content more thoroughly.+ *  This is expected to slightly improve compression ratio.+ *  The extra-cpu cost is likely worth it if the dictionary is re-used across multiple sessions.+ * @return : loaded dictionary size, in bytes (note: only the last 64 KB are loaded)+ */+LZ4LIB_API int LZ4_loadDictSlow(LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);++/*! LZ4_attach_dictionary() : stable since v1.10.0+ *+ *  This allows efficient re-use of a static dictionary multiple times.+ *+ *  Rather than re-loading the dictionary buffer into a working context before+ *  each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a+ *  working LZ4_stream_t, this function introduces a no-copy setup mechanism,+ *  in which the working stream references @dictionaryStream in-place.+ *+ *  Several assumptions are made about the state of @dictionaryStream.+ *  Currently, only states which have been prepared by LZ4_loadDict() or+ *  LZ4_loadDictSlow() should be expected to work.+ *+ *  Alternatively, the provided @dictionaryStream may be NULL,+ *  in which case any existing dictionary stream is unset.+ *+ *  If a dictionary is provided, it replaces any pre-existing stream history.+ *  The dictionary contents are the only history that can be referenced and+ *  logically immediately precede the data compressed in the first subsequent+ *  compression call.+ *+ *  The dictionary will only remain attached to the working stream through the+ *  first compression call, at the end of which it is cleared.+ * @dictionaryStream stream (and source buffer) must remain in-place / accessible / unchanged+ *  through the completion of the compression session.+ *+ *  Note: there is no equivalent LZ4_attach_*() method on the decompression side+ *  because there is no initialization cost, hence no need to share the cost across multiple sessions.+ *  To decompress LZ4 blocks using dictionary, attached or not,+ *  just employ the regular LZ4_setStreamDecode() for streaming,+ *  or the stateless LZ4_decompress_safe_usingDict() for one-shot decompression.+ */+LZ4LIB_API void+LZ4_attach_dictionary(LZ4_stream_t* workingStream,+                const LZ4_stream_t* dictionaryStream);+ /*! LZ4_compress_fast_continue() :  *  Compress 'src' content using data from previously compressed blocks, for better compression ratio.  * 'dst' buffer must be already allocated.@@ -443,11 +490,24 @@ LZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize); #define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) (65536 + 14 + (maxBlockSize))  /* for static allocation; maxBlockSize presumed valid */ -/*! LZ4_decompress_*_continue() :- *  These decoding functions allow decompression of consecutive blocks in "streaming" mode.- *  A block is an unsplittable entity, it must be presented entirely to a decompression function.- *  Decompression functions only accepts one block at a time.- *  The last 64KB of previously decoded data *must* remain available and unmodified at the memory position where they were decoded.+/*! LZ4_decompress_safe_continue() :+ *  This decoding function allows decompression of consecutive blocks in "streaming" mode.+ *  The difference with the usual independent blocks is that+ *  new blocks are allowed to find references into former blocks.+ *  A block is an unsplittable entity, and must be presented entirely to the decompression function.+ *  LZ4_decompress_safe_continue() only accepts one block at a time.+ *  It's modeled after `LZ4_decompress_safe()` and behaves similarly.+ *+ * @LZ4_streamDecode : decompression state, tracking the position in memory of past data+ * @compressedSize : exact complete size of one compressed block.+ * @dstCapacity : size of destination buffer (which must be already allocated),+ *                must be an upper bound of decompressed size.+ * @return : number of bytes decompressed into destination buffer (necessarily <= dstCapacity)+ *           If destination buffer is not large enough, decoding will stop and output an error code (negative value).+ *           If the source stream is detected malformed, the function will stop decoding and return a negative result.+ *+ *  The last 64KB of previously decoded data *must* remain available and unmodified+ *  at the memory position where they were previously decoded.  *  If less than 64KB of data has been decoded, all the data must be present.  *  *  Special : if decompression side sets a ring buffer, it must respect one of the following conditions :@@ -474,10 +534,10 @@                         int srcSize, int dstCapacity);  -/*! LZ4_decompress_*_usingDict() :- *  These decoding functions work the same as- *  a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue()- *  They are stand-alone, and don't need an LZ4_streamDecode_t structure.+/*! LZ4_decompress_safe_usingDict() :+ *  Works the same as+ *  a combination of LZ4_setStreamDecode() followed by LZ4_decompress_safe_continue()+ *  However, it's stateless: it doesn't need any LZ4_streamDecode_t state.  *  Dictionary is presumed stable : it must remain accessible and unmodified during decompression.  *  Performance tip : Decompression speed can be substantially increased  *                    when dst == dictStart + dictSize.@@ -487,6 +547,12 @@                               int srcSize, int dstCapacity,                               const char* dictStart, int dictSize); +/*! LZ4_decompress_safe_partial_usingDict() :+ *  Behaves the same as LZ4_decompress_safe_partial()+ *  with the added ability to specify a memory segment for past data.+ *  Performance tip : Decompression speed can be substantially increased+ *                    when dst == dictStart + dictSize.+ */ LZ4LIB_API int LZ4_decompress_safe_partial_usingDict(const char* src, char* dst,                                       int compressedSize,@@ -526,9 +592,9 @@ #define LZ4_STATIC_3504398509  #ifdef LZ4_PUBLISH_STATIC_FUNCTIONS-#define LZ4LIB_STATIC_API LZ4LIB_API+# define LZ4LIB_STATIC_API LZ4LIB_API #else-#define LZ4LIB_STATIC_API+# define LZ4LIB_STATIC_API #endif  @@ -544,36 +610,11 @@  */ LZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); -/*! LZ4_attach_dictionary() :- *  This is an experimental API that allows- *  efficient use of a static dictionary many times.- *- *  Rather than re-loading the dictionary buffer into a working context before- *  each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a- *  working LZ4_stream_t, this function introduces a no-copy setup mechanism,- *  in which the working stream references the dictionary stream in-place.- *- *  Several assumptions are made about the state of the dictionary stream.- *  Currently, only streams which have been prepared by LZ4_loadDict() should- *  be expected to work.- *- *  Alternatively, the provided dictionaryStream may be NULL,- *  in which case any existing dictionary stream is unset.- *- *  If a dictionary is provided, it replaces any pre-existing stream history.- *  The dictionary contents are the only history that can be referenced and- *  logically immediately precede the data compressed in the first subsequent- *  compression call.- *- *  The dictionary will only remain attached to the working stream through the- *  first compression call, at the end of which it is cleared. The dictionary- *  stream (and source buffer) must remain in-place / accessible / unchanged- *  through the completion of the first compression call on the stream.+/*! LZ4_compress_destSize_extState() : introduced in v1.10.0+ *  Same as LZ4_compress_destSize(), but using an externally allocated state.+ *  Also: exposes @acceleration  */-LZ4LIB_STATIC_API void-LZ4_attach_dictionary(LZ4_stream_t* workingStream,-                const LZ4_stream_t* dictionaryStream);-+int LZ4_compress_destSize_extState(void* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize, int acceleration);  /*! In-place compression and decompression  *@@ -685,7 +726,7 @@     /* Implicit padding to ensure structure is aligned */ }; -#define LZ4_STREAM_MINSIZE  ((1UL << LZ4_MEMORY_USAGE) + 32)  /* static size, for inter-version compatibility */+#define LZ4_STREAM_MINSIZE  ((1UL << (LZ4_MEMORY_USAGE)) + 32)  /* static size, for inter-version compatibility */ union LZ4_stream_u {     char minStateSize[LZ4_STREAM_MINSIZE];     LZ4_stream_t_internal internal_donotuse;@@ -706,7 +747,7 @@  *  Note2: An LZ4_stream_t structure guarantees correct alignment and size.  *  Note3: Before v1.9.0, use LZ4_resetStream() instead **/-LZ4LIB_API LZ4_stream_t* LZ4_initStream (void* buffer, size_t size);+LZ4LIB_API LZ4_stream_t* LZ4_initStream (void* stateBuffer, size_t size);   /*! LZ4_streamDecode_t :@@ -818,11 +859,12 @@  *         But they may happen if input data is invalid (error or intentional tampering).  *         As a consequence, use these functions in trusted environments with trusted data **only**.  */-LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead")+LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_partial() instead") LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize);-LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead")+LZ4_DEPRECATED("This function is deprecated and unsafe. Consider migrating towards LZ4_decompress_safe_continue() instead. "+               "Note that the contract will change (requires block's compressed size, instead of decompressed size)") LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize);-LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead")+LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_partial_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize);  /*! LZ4_resetStream() :
cbits/lz4frame.c view
@@ -44,6 +44,7 @@ /*-************************************ *  Compiler Options **************************************/+#include <limits.h> #ifdef _MSC_VER    /* Visual Studio */ #  pragma warning(disable : 4127)   /* disable: C4127: conditional expression is constant */ #endif@@ -54,8 +55,8 @@ **************************************/ /*  * LZ4F_HEAPMODE :- * Select how default compression functions will allocate memory for their hash table,- * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).+ * Control how LZ4F_compressFrame allocates the Compression State,+ * either on stack (0:default, fastest), or in memory heap (1:requires malloc()).  */ #ifndef LZ4F_HEAPMODE #  define LZ4F_HEAPMODE 0@@ -125,8 +126,9 @@  static void LZ4F_free(void* p, LZ4F_CustomMem cmem) {-    /* custom malloc defined : use it */+    if (p == NULL) return;     if (cmem.customFree != NULL) {+        /* custom allocation defined : use it */         cmem.customFree(cmem.opaqueState, p);         return;     }@@ -153,7 +155,7 @@ static int g_debuglog_enable = 1; #  define DEBUGLOG(l, ...) {                                  \                 if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) {  \-                    fprintf(stderr, __FILE__ ": ");           \+                    fprintf(stderr, __FILE__ " (%i): ", __LINE__ );  \                     fprintf(stderr, __VA_ARGS__);             \                     fprintf(stderr, " \n");                   \             }   }@@ -186,9 +188,9 @@ {     const BYTE* const srcPtr = (const BYTE*)src;     U32 value32 = srcPtr[0];-    value32 += ((U32)srcPtr[1])<< 8;-    value32 += ((U32)srcPtr[2])<<16;-    value32 += ((U32)srcPtr[3])<<24;+    value32 |= ((U32)srcPtr[1])<< 8;+    value32 |= ((U32)srcPtr[2])<<16;+    value32 |= ((U32)srcPtr[3])<<24;     return value32; } @@ -205,13 +207,13 @@ {     const BYTE* const srcPtr = (const BYTE*)src;     U64 value64 = srcPtr[0];-    value64 += ((U64)srcPtr[1]<<8);-    value64 += ((U64)srcPtr[2]<<16);-    value64 += ((U64)srcPtr[3]<<24);-    value64 += ((U64)srcPtr[4]<<32);-    value64 += ((U64)srcPtr[5]<<40);-    value64 += ((U64)srcPtr[6]<<48);-    value64 += ((U64)srcPtr[7]<<56);+    value64 |= ((U64)srcPtr[1]<<8);+    value64 |= ((U64)srcPtr[2]<<16);+    value64 |= ((U64)srcPtr[3]<<24);+    value64 |= ((U64)srcPtr[4]<<32);+    value64 |= ((U64)srcPtr[5]<<40);+    value64 |= ((U64)srcPtr[6]<<48);+    value64 |= ((U64)srcPtr[7]<<56);     return value64; } @@ -257,14 +259,15 @@ *  Structures and local types **************************************/ -typedef enum { LZ4B_COMPRESSED, LZ4B_UNCOMPRESSED} LZ4F_blockCompression_t;+typedef enum { LZ4B_COMPRESSED, LZ4B_UNCOMPRESSED} LZ4F_BlockCompressMode_e;+typedef enum { ctxNone, ctxFast, ctxHC } LZ4F_CtxType_e;  typedef struct LZ4F_cctx_s {     LZ4F_CustomMem cmem;     LZ4F_preferences_t prefs;     U32    version;-    U32    cStage;+    U32    cStage;     /* 0 : compression uninitialized ; 1 : initialized, can compress */     const LZ4F_CDict* cdict;     size_t maxBlockSize;     size_t maxBufferSize;@@ -275,8 +278,8 @@     XXH32_state_t xxh;     void*  lz4CtxPtr;     U16    lz4CtxAlloc; /* sized for: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */-    U16    lz4CtxState; /* in use as: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */-    LZ4F_blockCompression_t  blockCompression;+    U16    lz4CtxType;  /* in use as: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */+    LZ4F_BlockCompressMode_e  blockCompressMode; } LZ4F_cctx_t;  @@ -314,9 +317,14 @@  #define RETURN_ERROR(e) return LZ4F_returnErrorCode(LZ4F_ERROR_ ## e) -#define RETURN_ERROR_IF(c,e) if (c) RETURN_ERROR(e)+#define RETURN_ERROR_IF(c,e) do {  \+        if (c) {                   \+            DEBUGLOG(3, "Error: " #c); \+            RETURN_ERROR(e);       \+        }                          \+    } while (0) -#define FORWARD_IF_ERROR(r)  if (LZ4F_isError(r)) return (r)+#define FORWARD_IF_ERROR(r) do { if (LZ4F_isError(r)) return (r); } while (0)  unsigned LZ4F_getVersion(void) { return LZ4F_VERSION; } @@ -429,6 +437,7 @@     BYTE* dstPtr = dstStart;     BYTE* const dstEnd = dstStart + dstCapacity; +    DEBUGLOG(4, "LZ4F_compressFrame_usingCDict (srcSize=%u)", (unsigned)srcSize);     if (preferencesPtr!=NULL)         prefs = *preferencesPtr;     else@@ -494,7 +503,7 @@         LZ4_initStream(&lz4ctx, sizeof(lz4ctx));         cctxPtr->lz4CtxPtr = &lz4ctx;         cctxPtr->lz4CtxAlloc = 1;-        cctxPtr->lz4CtxState = 1;+        cctxPtr->lz4CtxType = ctxFast;     } #endif     DEBUGLOG(4, "LZ4F_compressFrame");@@ -539,18 +548,19 @@         dictSize = 64 KB;     }     cdict->dictContent = LZ4F_malloc(dictSize, cmem);+    /* note: using @cmem to allocate => can't use default create */     cdict->fastCtx = (LZ4_stream_t*)LZ4F_malloc(sizeof(LZ4_stream_t), cmem);-    if (cdict->fastCtx)-        LZ4_initStream(cdict->fastCtx, sizeof(LZ4_stream_t));     cdict->HCCtx = (LZ4_streamHC_t*)LZ4F_malloc(sizeof(LZ4_streamHC_t), cmem);-    if (cdict->HCCtx)-        LZ4_initStream(cdict->HCCtx, sizeof(LZ4_streamHC_t));     if (!cdict->dictContent || !cdict->fastCtx || !cdict->HCCtx) {         LZ4F_freeCDict(cdict);         return NULL;     }     memcpy(cdict->dictContent, dictStart, dictSize);-    LZ4_loadDict (cdict->fastCtx, (const char*)cdict->dictContent, (int)dictSize);+    LZ4_initStream(cdict->fastCtx, sizeof(LZ4_stream_t));+    LZ4_loadDictSlow(cdict->fastCtx, (const char*)cdict->dictContent, (int)dictSize);+    LZ4_initStreamHC(cdict->HCCtx, sizeof(LZ4_streamHC_t));+    /* note: we don't know at this point which compression level is going to be used+     * as a consequence, HCCtx is created for the more common HC mode */     LZ4_setCompressionLevel(cdict->HCCtx, LZ4HC_CLEVEL_DEFAULT);     LZ4_loadDictHC(cdict->HCCtx, (const char*)cdict->dictContent, (int)dictSize);     return cdict;@@ -616,7 +626,6 @@     return LZ4F_OK_NoError; } - LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctxPtr) {     if (cctxPtr != NULL) {  /* support free on NULL */@@ -641,7 +650,7 @@                             int level,                             LZ4F_blockMode_t blockMode) {     if (level < LZ4HC_CLEVEL_MIN) {-        if (cdict != NULL || blockMode == LZ4F_blockLinked) {+        if (cdict || blockMode == LZ4F_blockLinked) {             /* In these cases, we will call LZ4_compress_fast_continue(),              * which needs an already reset context. Otherwise, we'll call a              * one-shot API. The non-continued APIs internally perform their own@@ -649,11 +658,18 @@              * tableType they need the context to be in. So in that case this              * would be misguided / wasted work. */             LZ4_resetStream_fast((LZ4_stream_t*)ctx);+            if (cdict)+                LZ4_attach_dictionary((LZ4_stream_t*)ctx, cdict->fastCtx);         }-        LZ4_attach_dictionary((LZ4_stream_t *)ctx, cdict ? cdict->fastCtx : NULL);+        /* In these cases, we'll call a one-shot API.+         * The non-continued APIs internally perform their own resets+         * at the beginning of their calls, where they know+         * which tableType they need the context to be in.+         * Therefore, a reset here would be wasted work. */     } else {         LZ4_resetStreamHC_fast((LZ4_streamHC_t*)ctx, level);-        LZ4_attach_HC_dictionary((LZ4_streamHC_t *)ctx, cdict ? cdict->HCCtx : NULL);+        if (cdict)+            LZ4_attach_HC_dictionary((LZ4_streamHC_t*)ctx, cdict->HCCtx);     } } @@ -668,14 +684,12 @@     } } -/*! LZ4F_compressBegin_usingCDict() :- *  init streaming compression AND writes frame header into @dstBuffer.- * @dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.- * @return : number of bytes written into @dstBuffer for the header- *           or an error code (can be tested using LZ4F_isError())+/* LZ4F_compressBegin_internal()+ * Note: only accepts @cdict _or_ @dictBuffer as non NULL.  */-size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,+size_t LZ4F_compressBegin_internal(LZ4F_cctx* cctx,                           void* dstBuffer, size_t dstCapacity,+                          const void* dictBuffer, size_t dictSize,                           const LZ4F_CDict* cdict,                           const LZ4F_preferences_t* preferencesPtr) {@@ -685,71 +699,85 @@      RETURN_ERROR_IF(dstCapacity < maxFHSize, dstMaxSize_tooSmall);     if (preferencesPtr == NULL) preferencesPtr = &prefNull;-    cctxPtr->prefs = *preferencesPtr;+    cctx->prefs = *preferencesPtr;      /* cctx Management */-    {   U16 const ctxTypeID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2;+    {   U16 const ctxTypeID = (cctx->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2;         int requiredSize = ctxTypeID_to_size(ctxTypeID);-        int allocatedSize = ctxTypeID_to_size(cctxPtr->lz4CtxAlloc);+        int allocatedSize = ctxTypeID_to_size(cctx->lz4CtxAlloc);         if (allocatedSize < requiredSize) {             /* not enough space allocated */-            LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem);-            if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {+            LZ4F_free(cctx->lz4CtxPtr, cctx->cmem);+            if (cctx->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {                 /* must take ownership of memory allocation,                  * in order to respect custom allocator contract */-                cctxPtr->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_stream_t), cctxPtr->cmem);-                if (cctxPtr->lz4CtxPtr)-                    LZ4_initStream(cctxPtr->lz4CtxPtr, sizeof(LZ4_stream_t));+                cctx->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_stream_t), cctx->cmem);+                if (cctx->lz4CtxPtr)+                    LZ4_initStream(cctx->lz4CtxPtr, sizeof(LZ4_stream_t));             } else {-                cctxPtr->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_streamHC_t), cctxPtr->cmem);-                if (cctxPtr->lz4CtxPtr)-                    LZ4_initStreamHC(cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t));+                cctx->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_streamHC_t), cctx->cmem);+                if (cctx->lz4CtxPtr)+                    LZ4_initStreamHC(cctx->lz4CtxPtr, sizeof(LZ4_streamHC_t));             }-            RETURN_ERROR_IF(cctxPtr->lz4CtxPtr == NULL, allocation_failed);-            cctxPtr->lz4CtxAlloc = ctxTypeID;-            cctxPtr->lz4CtxState = ctxTypeID;-        } else if (cctxPtr->lz4CtxState != ctxTypeID) {+            RETURN_ERROR_IF(cctx->lz4CtxPtr == NULL, allocation_failed);+            cctx->lz4CtxAlloc = ctxTypeID;+            cctx->lz4CtxType = ctxTypeID;+        } else if (cctx->lz4CtxType != ctxTypeID) {             /* otherwise, a sufficient buffer is already allocated,              * but we need to reset it to the correct context type */-            if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {-                LZ4_initStream((LZ4_stream_t*)cctxPtr->lz4CtxPtr, sizeof(LZ4_stream_t));+            if (cctx->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {+                LZ4_initStream((LZ4_stream_t*)cctx->lz4CtxPtr, sizeof(LZ4_stream_t));             } else {-                LZ4_initStreamHC((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t));-                LZ4_setCompressionLevel((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);+                LZ4_initStreamHC((LZ4_streamHC_t*)cctx->lz4CtxPtr, sizeof(LZ4_streamHC_t));+                LZ4_setCompressionLevel((LZ4_streamHC_t*)cctx->lz4CtxPtr, cctx->prefs.compressionLevel);             }-            cctxPtr->lz4CtxState = ctxTypeID;+            cctx->lz4CtxType = ctxTypeID;     }   }      /* Buffer Management */-    if (cctxPtr->prefs.frameInfo.blockSizeID == 0)-        cctxPtr->prefs.frameInfo.blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;-    cctxPtr->maxBlockSize = LZ4F_getBlockSize(cctxPtr->prefs.frameInfo.blockSizeID);+    if (cctx->prefs.frameInfo.blockSizeID == 0)+        cctx->prefs.frameInfo.blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;+    cctx->maxBlockSize = LZ4F_getBlockSize(cctx->prefs.frameInfo.blockSizeID);      {   size_t const requiredBuffSize = preferencesPtr->autoFlush ?-                ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) ? 64 KB : 0) :  /* only needs past data up to window size */-                cctxPtr->maxBlockSize + ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) ? 128 KB : 0);+                ((cctx->prefs.frameInfo.blockMode == LZ4F_blockLinked) ? 64 KB : 0) :  /* only needs past data up to window size */+                cctx->maxBlockSize + ((cctx->prefs.frameInfo.blockMode == LZ4F_blockLinked) ? 128 KB : 0); -        if (cctxPtr->maxBufferSize < requiredBuffSize) {-            cctxPtr->maxBufferSize = 0;-            LZ4F_free(cctxPtr->tmpBuff, cctxPtr->cmem);-            cctxPtr->tmpBuff = (BYTE*)LZ4F_calloc(requiredBuffSize, cctxPtr->cmem);-            RETURN_ERROR_IF(cctxPtr->tmpBuff == NULL, allocation_failed);-            cctxPtr->maxBufferSize = requiredBuffSize;+        if (cctx->maxBufferSize < requiredBuffSize) {+            cctx->maxBufferSize = 0;+            LZ4F_free(cctx->tmpBuff, cctx->cmem);+            cctx->tmpBuff = (BYTE*)LZ4F_malloc(requiredBuffSize, cctx->cmem);+            RETURN_ERROR_IF(cctx->tmpBuff == NULL, allocation_failed);+            cctx->maxBufferSize = requiredBuffSize;     }   }-    cctxPtr->tmpIn = cctxPtr->tmpBuff;-    cctxPtr->tmpInSize = 0;-    (void)XXH32_reset(&(cctxPtr->xxh), 0);+    cctx->tmpIn = cctx->tmpBuff;+    cctx->tmpInSize = 0;+    (void)XXH32_reset(&(cctx->xxh), 0);      /* context init */-    cctxPtr->cdict = cdict;-    if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) {+    cctx->cdict = cdict;+    if (cctx->prefs.frameInfo.blockMode == LZ4F_blockLinked) {         /* frame init only for blockLinked : blockIndependent will be init at each block */-        LZ4F_initStream(cctxPtr->lz4CtxPtr, cdict, cctxPtr->prefs.compressionLevel, LZ4F_blockLinked);+        LZ4F_initStream(cctx->lz4CtxPtr, cdict, cctx->prefs.compressionLevel, LZ4F_blockLinked);     }     if (preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN) {-        LZ4_favorDecompressionSpeed((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, (int)preferencesPtr->favorDecSpeed);+        LZ4_favorDecompressionSpeed((LZ4_streamHC_t*)cctx->lz4CtxPtr, (int)preferencesPtr->favorDecSpeed);     }+    if (dictBuffer) {+        assert(cdict == NULL);+        RETURN_ERROR_IF(dictSize > INT_MAX, parameter_invalid);+        if (cctx->lz4CtxType == ctxFast) {+            /* lz4 fast*/+            LZ4_loadDict((LZ4_stream_t*)cctx->lz4CtxPtr, (const char*)dictBuffer, (int)dictSize);+        } else {+            /* lz4hc */+            assert(cctx->lz4CtxType == ctxHC);+            LZ4_loadDictHC((LZ4_streamHC_t*)cctx->lz4CtxPtr, (const char*)dictBuffer, (int)dictSize);+        }+    } +    /* Stage 2 : Write Frame Header */+     /* Magic Number */     LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER);     dstPtr += 4;@@ -757,22 +785,22 @@          /* FLG Byte */         *dstPtr++ = (BYTE)(((1 & _2BITS) << 6)    /* Version('01') */-            + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5)-            + ((cctxPtr->prefs.frameInfo.blockChecksumFlag & _1BIT ) << 4)-            + ((unsigned)(cctxPtr->prefs.frameInfo.contentSize > 0) << 3)-            + ((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2)-            +  (cctxPtr->prefs.frameInfo.dictID > 0) );+            + ((cctx->prefs.frameInfo.blockMode & _1BIT ) << 5)+            + ((cctx->prefs.frameInfo.blockChecksumFlag & _1BIT ) << 4)+            + ((unsigned)(cctx->prefs.frameInfo.contentSize > 0) << 3)+            + ((cctx->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2)+            +  (cctx->prefs.frameInfo.dictID > 0) );         /* BD Byte */-        *dstPtr++ = (BYTE)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4);+        *dstPtr++ = (BYTE)((cctx->prefs.frameInfo.blockSizeID & _3BITS) << 4);         /* Optional Frame content size field */-        if (cctxPtr->prefs.frameInfo.contentSize) {-            LZ4F_writeLE64(dstPtr, cctxPtr->prefs.frameInfo.contentSize);+        if (cctx->prefs.frameInfo.contentSize) {+            LZ4F_writeLE64(dstPtr, cctx->prefs.frameInfo.contentSize);             dstPtr += 8;-            cctxPtr->totalInSize = 0;+            cctx->totalInSize = 0;         }         /* Optional dictionary ID field */-        if (cctxPtr->prefs.frameInfo.dictID) {-            LZ4F_writeLE32(dstPtr, cctxPtr->prefs.frameInfo.dictID);+        if (cctx->prefs.frameInfo.dictID) {+            LZ4F_writeLE32(dstPtr, cctx->prefs.frameInfo.dictID);             dstPtr += 4;         }         /* Header CRC Byte */@@ -780,27 +808,57 @@         dstPtr++;     } -    cctxPtr->cStage = 1;   /* header written, now request input data block */+    cctx->cStage = 1;   /* header written, now request input data block */     return (size_t)(dstPtr - dstStart); } +size_t LZ4F_compressBegin(LZ4F_cctx* cctx,+                          void* dstBuffer, size_t dstCapacity,+                          const LZ4F_preferences_t* preferencesPtr)+{+    return LZ4F_compressBegin_internal(cctx, dstBuffer, dstCapacity,+                                        NULL, 0,+                                        NULL, preferencesPtr);+} -/*! LZ4F_compressBegin() :- *  init streaming compression AND writes frame header into @dstBuffer.- * @dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.- * @preferencesPtr can be NULL, in which case default parameters are selected.- * @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,+/* LZ4F_compressBegin_usingDictOnce:+ * Hidden implementation,+ * employed for multi-threaded compression+ * when frame defines linked blocks */+size_t LZ4F_compressBegin_usingDictOnce(LZ4F_cctx* cctx,                           void* dstBuffer, size_t dstCapacity,+                          const void* dict, size_t dictSize,                           const LZ4F_preferences_t* preferencesPtr) {-    return LZ4F_compressBegin_usingCDict(cctxPtr, dstBuffer, dstCapacity,-                                         NULL, preferencesPtr);+    return LZ4F_compressBegin_internal(cctx, dstBuffer, dstCapacity,+                                        dict, dictSize,+                                        NULL, preferencesPtr); } +size_t LZ4F_compressBegin_usingDict(LZ4F_cctx* cctx,+                          void* dstBuffer, size_t dstCapacity,+                          const void* dict, size_t dictSize,+                          const LZ4F_preferences_t* preferencesPtr)+{+    /* note : incorrect implementation :+     * this will only use the dictionary once,+     * instead of once *per* block when frames defines independent blocks */+    return LZ4F_compressBegin_usingDictOnce(cctx, dstBuffer, dstCapacity,+                                        dict, dictSize,+                                        preferencesPtr);+} +size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctx,+                          void* dstBuffer, size_t dstCapacity,+                          const LZ4F_CDict* cdict,+                          const LZ4F_preferences_t* preferencesPtr)+{+    return LZ4F_compressBegin_internal(cctx, dstBuffer, dstCapacity,+                                        NULL, 0,+                                       cdict, preferencesPtr);+}++ /*  LZ4F_compressBound() :  * @return minimum capacity of dstBuffer for a given srcSize to handle worst case scenario.  *  LZ4F_preferences_t structure is optional : if NULL, preferences will be set to cover worst case scenario.@@ -891,9 +949,10 @@     return 0; } -static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int level, LZ4F_blockCompression_t  compressMode)+static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int level, LZ4F_BlockCompressMode_e  compressMode) {-    if (compressMode == LZ4B_UNCOMPRESSED) return LZ4F_doNotCompressBlock;+    if (compressMode == LZ4B_UNCOMPRESSED)+        return LZ4F_doNotCompressBlock;     if (level < LZ4HC_CLEVEL_MIN) {         if (blockMode == LZ4F_blockIndependent) return LZ4F_compressBlock;         return LZ4F_compressBlock_continue;@@ -931,7 +990,7 @@                      void* dstBuffer, size_t dstCapacity,                      const void* srcBuffer, size_t srcSize,                      const LZ4F_compressOptions_t* compressOptionsPtr,-                     LZ4F_blockCompression_t blockCompression)+                     LZ4F_BlockCompressMode_e blockCompression)   {     size_t const blockSize = cctxPtr->maxBlockSize;     const BYTE* srcPtr = (const BYTE*)srcBuffer;@@ -951,10 +1010,10 @@         RETURN_ERROR(dstMaxSize_tooSmall);      /* flush currently written block, to continue with new block compression */-    if (cctxPtr->blockCompression != blockCompression) {+    if (cctxPtr->blockCompressMode != blockCompression) {         bytesWritten = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr);         dstPtr += bytesWritten;-        cctxPtr->blockCompression = blockCompression;+        cctxPtr->blockCompressMode = blockCompression;     }      if (compressOptionsPtr == NULL) compressOptionsPtr = &k_cOptionsNull;@@ -1068,13 +1127,9 @@                                    compressOptionsPtr, LZ4B_COMPRESSED); } -/*! LZ4F_compressUpdate() :- *  LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.- *  When successful, the function always entirely consumes @srcBuffer.- *  src data is either buffered or compressed into @dstBuffer.- *  If previously an uncompressed block was written, buffered data is flushed- *  before appending compressed data is continued.- *  This is only supported when LZ4F_blockIndependent is used+/*! LZ4F_uncompressedUpdate() :+ *  Same as LZ4F_compressUpdate(), but requests blocks to be sent uncompressed.+ *  This symbol is only supported when LZ4F_blockIndependent is used  * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr).  * @compressOptionsPtr is optional : provide NULL to mean "default".  * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered.@@ -1084,8 +1139,8 @@ size_t LZ4F_uncompressedUpdate(LZ4F_cctx* cctxPtr,                                void* dstBuffer, size_t dstCapacity,                          const void* srcBuffer, size_t srcSize,-                         const LZ4F_compressOptions_t* compressOptionsPtr) {-    RETURN_ERROR_IF(cctxPtr->prefs.frameInfo.blockMode != LZ4F_blockIndependent, blockMode_invalid);+                         const LZ4F_compressOptions_t* compressOptionsPtr)+{     return LZ4F_compressUpdateImpl(cctxPtr,                                    dstBuffer, dstCapacity,                                    srcBuffer, srcSize,@@ -1115,7 +1170,7 @@     (void)compressOptionsPtr;   /* not useful (yet) */      /* select compression function */-    compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, cctxPtr->blockCompression);+    compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, cctxPtr->blockCompressMode);      /* compress tmp buffer */     dstPtr += LZ4F_makeBlock(dstPtr,@@ -1170,13 +1225,12 @@     if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) {         U32 const xxh = XXH32_digest(&(cctxPtr->xxh));         RETURN_ERROR_IF(dstCapacity < 8, dstMaxSize_tooSmall);-        DEBUGLOG(5,"Writing 32-bit content checksum");+        DEBUGLOG(5,"Writing 32-bit content checksum (0x%0X)", xxh);         LZ4F_writeLE32(dstPtr, xxh);         dstPtr+=4;   /* content Checksum */     }      cctxPtr->cStage = 0;   /* state is now re-usable (with identical preferences) */-    cctxPtr->maxBufferSize = 0;  /* reuse HC context */      if (cctxPtr->prefs.frameInfo.contentSize) {         if (cctxPtr->prefs.frameInfo.contentSize != cctxPtr->totalInSize)@@ -1270,13 +1324,14 @@   /*==---   Streaming Decompression operations   ---==*/- void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx) {+    DEBUGLOG(5, "LZ4F_resetDecompressionContext");     dctx->dStage = dstage_getFrameHeader;     dctx->dict = NULL;     dctx->dictSize = 0;     dctx->skipChecksum = 0;+    dctx->frameRemainingSize = 0; }  @@ -1333,6 +1388,7 @@         if (((FLG>>1)&_1BIT) != 0) RETURN_ERROR(reservedFlag_set); /* Reserved bit */         if (version != 1) RETURN_ERROR(headerVersion_wrong);       /* Version Number, only supported value */     }+    DEBUGLOG(6, "contentSizeFlag: %u", contentSizeFlag);      /* Frame Header Size */     frameHeaderSize = minFHSize + (contentSizeFlag?8:0) + (dictIDFlag?4:0);@@ -1369,8 +1425,9 @@     dctx->frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)contentChecksumFlag;     dctx->frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID;     dctx->maxBlockSize = LZ4F_getBlockSize((LZ4F_blockSizeID_t)blockSizeID);-    if (contentSizeFlag)+    if (contentSizeFlag) {         dctx->frameRemainingSize = dctx->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6);+    }     if (dictIDFlag)         dctx->frameInfo.dictID = LZ4F_readLE32(srcPtr + frameHeaderSize - 5); @@ -1570,7 +1627,7 @@     size_t nextSrcSizeHint = 1;  -    DEBUGLOG(5, "LZ4F_decompress : %p,%u => %p,%u",+    DEBUGLOG(5, "LZ4F_decompress: src[%p](%u) => dst[%p](%u)",             srcBuffer, (unsigned)*srcSizePtr, dstBuffer, (unsigned)*dstSizePtr);     if (dstBuffer == NULL) assert(*dstSizePtr == 0);     MEM_INIT(&optionsNull, 0, sizeof(optionsNull));@@ -1722,10 +1779,10 @@                     /* history management (linked blocks only)*/                     if (dctx->frameInfo.blockMode == LZ4F_blockLinked) {                         LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0);-                }   }--                srcPtr += sizeToCopy;-                dstPtr += sizeToCopy;+                    }+                    srcPtr += sizeToCopy;+                    dstPtr += sizeToCopy;+                }                 if (sizeToCopy == dctx->tmpInTarget) {   /* all done */                     if (dctx->frameInfo.blockChecksumFlag) {                         dctx->tmpInSize = 0;@@ -1959,6 +2016,7 @@             if (!dctx->skipChecksum) {                 U32 const readCRC = LZ4F_readLE32(selectedIn);                 U32 const resultCRC = XXH32_digest(&(dctx->xxh));+                DEBUGLOG(4, "frame checksum: stored 0x%0X vs 0x%0X processed", readCRC, resultCRC); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION                 RETURN_ERROR_IF(readCRC != resultCRC, contentChecksum_invalid); #else
cbits/lz4frame.h view
@@ -173,16 +173,16 @@  *  setting all parameters to default.  *  It's then possible to update selectively some parameters */ typedef struct {-  LZ4F_blockSizeID_t     blockSizeID;         /* max64KB, max256KB, max1MB, max4MB; 0 == default */-  LZ4F_blockMode_t       blockMode;           /* LZ4F_blockLinked, LZ4F_blockIndependent; 0 == default */-  LZ4F_contentChecksum_t contentChecksumFlag; /* 1: frame terminated with 32-bit checksum of decompressed data; 0: disabled (default) */+  LZ4F_blockSizeID_t     blockSizeID;         /* max64KB, max256KB, max1MB, max4MB; 0 == default (LZ4F_max64KB) */+  LZ4F_blockMode_t       blockMode;           /* LZ4F_blockLinked, LZ4F_blockIndependent; 0 == default (LZ4F_blockLinked) */+  LZ4F_contentChecksum_t contentChecksumFlag; /* 1: add a 32-bit checksum of frame's decompressed data; 0 == default (disabled) */   LZ4F_frameType_t       frameType;           /* read-only field : LZ4F_frame or LZ4F_skippableFrame */   unsigned long long     contentSize;         /* Size of uncompressed content ; 0 == unknown */   unsigned               dictID;              /* Dictionary ID, sent by compressor to help decoder select correct dictionary; 0 == no dictID provided */-  LZ4F_blockChecksum_t   blockChecksumFlag;   /* 1: each block followed by a checksum of block's compressed data; 0: disabled (default) */+  LZ4F_blockChecksum_t   blockChecksumFlag;   /* 1: each block followed by a checksum of block's compressed data; 0 == default (disabled) */ } LZ4F_frameInfo_t; -#define LZ4F_INIT_FRAMEINFO   { LZ4F_default, LZ4F_blockLinked, LZ4F_noContentChecksum, LZ4F_frame, 0ULL, 0U, LZ4F_noBlockChecksum }    /* v1.8.3+ */+#define LZ4F_INIT_FRAMEINFO   { LZ4F_max64KB, LZ4F_blockLinked, LZ4F_noContentChecksum, LZ4F_frame, 0ULL, 0U, LZ4F_noBlockChecksum }    /* v1.8.3+ */  /*! LZ4F_preferences_t :  *  makes it possible to supply advanced compression instructions to streaming interface.@@ -204,7 +204,26 @@ *  Simple compression function ***********************************/ -LZ4FLIB_API int LZ4F_compressionLevel_max(void);   /* v1.8.0+ */+/*! LZ4F_compressFrame() :+ *  Compress srcBuffer content into an LZ4-compressed frame.+ *  It's a one shot operation, all input content is consumed, and all output is generated.+ *+ *  Note : it's a stateless operation (no LZ4F_cctx state needed).+ *  In order to reduce load on the allocator, LZ4F_compressFrame(), by default,+ *  uses the stack to allocate space for the compression state and some table.+ *  If this usage of the stack is too much for your application,+ *  consider compiling `lz4frame.c` with compile-time macro LZ4F_HEAPMODE set to 1 instead.+ *  All state allocations will use the Heap.+ *  It also means each invocation of LZ4F_compressFrame() will trigger several internal alloc/free invocations.+ *+ * @dstCapacity MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).+ * @preferencesPtr is optional : one can provide NULL, in which case all preferences are set to default.+ * @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 dstCapacity,+                                const void* srcBuffer, size_t srcSize,+                                const LZ4F_preferences_t* preferencesPtr);  /*! LZ4F_compressFrameBound() :  *  Returns the maximum possible compressed size with LZ4F_compressFrame() given srcSize and preferences.@@ -214,16 +233,11 @@  */ 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.- *  dstCapacity MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).- *  The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will be set to default.- * @return : number of bytes written into dstBuffer.- *           or an error code if it fails (can be tested using LZ4F_isError())++/*! LZ4F_compressionLevel_max() :+ * @return maximum allowed compression level (currently: 12)  */-LZ4FLIB_API size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity,-                                const void* srcBuffer, size_t srcSize,-                                const LZ4F_preferences_t* preferencesPtr);+LZ4FLIB_API int LZ4F_compressionLevel_max(void);   /* v1.8.0+ */   /*-***********************************@@ -278,7 +292,7 @@ /*! LZ4F_compressBegin() :  *  will write the frame header into dstBuffer.  *  dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.- * `prefsPtr` is optional : you can provide NULL as argument, all preferences will then be set to default.+ * `prefsPtr` is optional : NULL can be provided to set all preferences to default.  * @return : number of bytes written into dstBuffer for the header  *           or an error code (which can be tested using LZ4F_isError())  */@@ -355,8 +369,9 @@ typedef LZ4F_dctx* LZ4F_decompressionContext_t;   /* compatibility with previous API versions */  typedef struct {-  unsigned stableDst;     /* pledges that last 64KB decompressed data will remain available unmodified between invocations.-                           * This optimization skips storage operations in tmp buffers. */+  unsigned stableDst;     /* pledges that last 64KB decompressed data is present right before @dstBuffer pointer.+                           * This optimization skips internal storage operations.+                           * Once set, this pledge must remain valid up to the end of current frame. */   unsigned skipChecksums; /* disable checksum calculation and verification, even when one is present in frame, to save CPU time.                            * Setting this option to 1 once disables all checksums for the rest of the frame. */   unsigned reserved1;     /* must be set to zero for forward compatibility */@@ -463,6 +478,11 @@  * `dstBuffer` can freely change between each consecutive function invocation.  * `dstBuffer` content will be overwritten.  *+ *  Note: if `LZ4F_getFrameInfo()` is called before `LZ4F_decompress()`, srcBuffer must be updated to reflect+ *  the number of bytes consumed after reading the frame header. Failure to update srcBuffer before calling+ *  `LZ4F_decompress()` will cause decompression failure or, even worse, successful but incorrect decompression.+ *  See the `LZ4F_getFrameInfo()` docs for details.+ *  * @return : 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 small speed benefit, because it skips intermediate buffers.@@ -493,7 +513,110 @@ LZ4FLIB_API void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx);   /* always successful */  +/**********************************+ *  Dictionary compression API+ *********************************/ +/* A Dictionary is useful for the compression of small messages (KB range).+ * It dramatically improves compression efficiency.+ *+ * LZ4 can ingest any input as dictionary, though only the last 64 KB are useful.+ * Better results are generally achieved by using Zstandard's Dictionary Builder+ * to generate a high-quality dictionary from a set of samples.+ *+ * The same dictionary will have to be used on the decompression side+ * for decoding to be successful.+ * To help identify the correct dictionary at decoding stage,+ * the frame header allows optional embedding of a dictID field.+ */++/*! LZ4F_compressBegin_usingDict() : stable since v1.10+ *  Inits dictionary compression streaming, and writes the frame header into dstBuffer.+ * @dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.+ * @prefsPtr is optional : one may provide NULL as argument,+ *  however, it's the only way to provide dictID in the frame header.+ * @dictBuffer must outlive the compression session.+ * @return : number of bytes written into dstBuffer for the header,+ *           or an error code (which can be tested using LZ4F_isError())+ *  NOTE: The LZ4Frame spec allows each independent block to be compressed with the dictionary,+ *        but this entry supports a more limited scenario, where only the first block uses the dictionary.+ *        This is still useful for small data, which only need one block anyway.+ *        For larger inputs, one may be more interested in LZ4F_compressFrame_usingCDict() below.+ */+LZ4FLIB_API size_t+LZ4F_compressBegin_usingDict(LZ4F_cctx* cctx,+                            void* dstBuffer, size_t dstCapacity,+                      const void* dictBuffer, size_t dictSize,+                      const LZ4F_preferences_t* prefsPtr);++/*! LZ4F_decompress_usingDict() : stable since v1.10+ *  Same as LZ4F_decompress(), using a predefined dictionary.+ *  Dictionary is used "in place", without any preprocessing.+**  It must remain accessible throughout the entire frame decoding. */+LZ4FLIB_API size_t+LZ4F_decompress_usingDict(LZ4F_dctx* dctxPtr,+                          void* dstBuffer, size_t* dstSizePtr,+                    const void* srcBuffer, size_t* srcSizePtr,+                    const void* dict, size_t dictSize,+                    const LZ4F_decompressOptions_t* decompressOptionsPtr);++/*****************************************+ *  Bulk processing dictionary compression+ *****************************************/++/* Loading a dictionary has a cost, since it involves construction of tables.+ * The Bulk processing dictionary API makes it possible to share this cost+ * over an arbitrary number of compression jobs, even concurrently,+ * markedly improving compression latency for these cases.+ *+ * Note that there is no corresponding bulk API for the decompression side,+ * because dictionary does not carry any initialization cost for decompression.+ * Use the regular LZ4F_decompress_usingDict() there.+ */+typedef struct LZ4F_CDict_s LZ4F_CDict;++/*! LZ4_createCDict() : stable since v1.10+ *  When compressing multiple messages / blocks using the same dictionary, it's recommended to initialize it just once.+ *  LZ4_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay.+ *  LZ4_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.+ * @dictBuffer can be released after LZ4_CDict creation, since its content is copied within CDict. */+LZ4FLIB_API LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize);+LZ4FLIB_API void        LZ4F_freeCDict(LZ4F_CDict* CDict);++/*! LZ4_compressFrame_usingCDict() : stable since v1.10+ *  Compress an entire srcBuffer into a valid LZ4 frame using a digested Dictionary.+ * @cctx must point to a context created by LZ4F_createCompressionContext().+ *  If @cdict==NULL, compress without a dictionary.+ * @dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).+ *  If this condition is not respected, function will fail (@return an errorCode).+ *  The LZ4F_preferences_t structure is optional : one may provide NULL as argument,+ *  but it's not recommended, as it's the only way to provide @dictID in the frame header.+ * @return : number of bytes written into dstBuffer.+ *           or an error code if it fails (can be tested using LZ4F_isError())+ *  Note: for larger inputs generating multiple independent blocks,+ *        this entry point uses the dictionary for each block. */+LZ4FLIB_API size_t+LZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx,+                              void* dst, size_t dstCapacity,+                        const void* src, size_t srcSize,+                        const LZ4F_CDict* cdict,+                        const LZ4F_preferences_t* preferencesPtr);++/*! LZ4F_compressBegin_usingCDict() : stable since v1.10+ *  Inits streaming dictionary compression, and writes the frame header into dstBuffer.+ * @dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.+ * @prefsPtr is optional : one may provide NULL as argument,+ *  note however that it's the only way to insert a @dictID in the frame header.+ * @cdict must outlive the compression session.+ * @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_compressBegin_usingCDict(LZ4F_cctx* cctx,+                              void* dstBuffer, size_t dstCapacity,+                        const LZ4F_CDict* cdict,+                        const LZ4F_preferences_t* prefsPtr);++ #if defined (__cplusplus) } #endif@@ -503,11 +626,8 @@ #if defined(LZ4F_STATIC_LINKING_ONLY) && !defined(LZ4F_H_STATIC_09782039843) #define LZ4F_H_STATIC_09782039843 -#if defined (__cplusplus)-extern "C" {-#endif--/* These declarations are not stable and may change in the future.+/* Note :+ * The below declarations are not stable and may change in the future.  * They are therefore only safe to depend on  * when the caller is statically linked against the library.  * To access their declarations, define LZ4F_STATIC_LINKING_ONLY.@@ -517,6 +637,11 @@  * by defining LZ4F_PUBLISH_STATIC_FUNCTIONS.  * Use at your own risk.  */++#if defined (__cplusplus)+extern "C" {+#endif+ #ifdef LZ4F_PUBLISH_STATIC_FUNCTIONS # define LZ4FLIB_STATIC_API LZ4FLIB_API #else@@ -530,7 +655,7 @@         ITEM(ERROR_GENERIC) \         ITEM(ERROR_maxBlockSize_invalid) \         ITEM(ERROR_blockMode_invalid) \-        ITEM(ERROR_contentChecksumFlag_invalid) \+        ITEM(ERROR_parameter_invalid) \         ITEM(ERROR_compressionLevel_invalid) \         ITEM(ERROR_headerVersion_wrong) \         ITEM(ERROR_blockChecksum_invalid) \@@ -548,6 +673,8 @@         ITEM(ERROR_frameDecoding_alreadyStarted) \         ITEM(ERROR_compressionState_uninitialized) \         ITEM(ERROR_parameter_null) \+        ITEM(ERROR_io_write) \+        ITEM(ERROR_io_read) \         ITEM(ERROR_maxCode)  #define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM,@@ -558,22 +685,26 @@  LZ4FLIB_STATIC_API LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult); +/**********************************+ *  Advanced compression operations+ *********************************/  /*! LZ4F_getBlockSize() :- *  Return, in scalar format (size_t),- *  the maximum block size associated with blockSizeID.+ * @return, in scalar format (size_t),+ *          the maximum block size associated with @blockSizeID,+ *          or an error code (can be tested using LZ4F_isError()) if @blockSizeID is invalid. **/ LZ4FLIB_STATIC_API size_t LZ4F_getBlockSize(LZ4F_blockSizeID_t blockSizeID);  /*! LZ4F_uncompressedUpdate() :- *  LZ4F_uncompressedUpdate() can be called repetitively to add as much data uncompressed data as necessary.+ *  LZ4F_uncompressedUpdate() can be called repetitively to add data stored as uncompressed blocks.  *  Important rule: dstCapacity MUST be large enough to store the entire source buffer as  *  no compression is done for this operation  *  If this condition is not respected, LZ4F_uncompressedUpdate() will fail (result is an errorCode).  *  After an error, the state is left in a UB state, and must be re-initialized or freed.- *  If previously a compressed block was written, buffered data is flushed+ *  If previously a compressed block was written, buffered data is flushed first,  *  before appending uncompressed data is continued.- *  This is only supported when LZ4F_blockIndependent is used+ *  This operation is only supported when LZ4F_blockIndependent is used.  * `cOptPtr` is optional : NULL can be provided, in which case all options are 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())@@ -585,82 +716,10 @@                   const LZ4F_compressOptions_t* cOptPtr);  /**********************************- *  Bulk processing dictionary API+ *  Custom memory allocation  *********************************/ -/* A Dictionary is useful for the compression of small messages (KB range).- * It dramatically improves compression efficiency.- *- * LZ4 can ingest any input as dictionary, though only the last 64 KB are useful.- * Best results are generally achieved by using Zstandard's Dictionary Builder- * to generate a high-quality dictionary from a set of samples.- *- * Loading a dictionary has a cost, since it involves construction of tables.- * The Bulk processing dictionary API makes it possible to share this cost- * over an arbitrary number of compression jobs, even concurrently,- * markedly improving compression latency for these cases.- *- * The same dictionary will have to be used on the decompression side- * for decoding to be successful.- * To help identify the correct dictionary at decoding stage,- * the frame header allows optional embedding of a dictID field.- */-typedef struct LZ4F_CDict_s LZ4F_CDict;--/*! LZ4_createCDict() :- *  When compressing multiple messages / blocks using the same dictionary, it's recommended to load it just once.- *  LZ4_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay.- *  LZ4_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.- * `dictBuffer` can be released after LZ4_CDict creation, since its content is copied within CDict */-LZ4FLIB_STATIC_API LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize);-LZ4FLIB_STATIC_API void        LZ4F_freeCDict(LZ4F_CDict* CDict);---/*! LZ4_compressFrame_usingCDict() :- *  Compress an entire srcBuffer into a valid LZ4 frame using a digested Dictionary.- *  cctx must point to a context created by LZ4F_createCompressionContext().- *  If cdict==NULL, compress without a dictionary.- *  dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).- *  If this condition is not respected, function will fail (@return an errorCode).- *  The LZ4F_preferences_t structure is optional : you may provide NULL as argument,- *  but it's not recommended, as it's the only way to provide dictID in the frame header.- * @return : number of bytes written into dstBuffer.- *           or an error code if it fails (can be tested using LZ4F_isError()) */-LZ4FLIB_STATIC_API size_t-LZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx,-                              void* dst, size_t dstCapacity,-                        const void* src, size_t srcSize,-                        const LZ4F_CDict* cdict,-                        const LZ4F_preferences_t* preferencesPtr);---/*! LZ4F_compressBegin_usingCDict() :- *  Inits streaming dictionary compression, and writes the frame header into dstBuffer.- *  dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.- * `prefsPtr` is optional : you may provide NULL as argument,- *  however, it's the only way to provide dictID in the frame header.- * @return : number of bytes written into dstBuffer for the header,- *           or an error code (which can be tested using LZ4F_isError()) */-LZ4FLIB_STATIC_API size_t-LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctx,-                              void* dstBuffer, size_t dstCapacity,-                        const LZ4F_CDict* cdict,-                        const LZ4F_preferences_t* prefsPtr);---/*! LZ4F_decompress_usingDict() :- *  Same as LZ4F_decompress(), using a predefined dictionary.- *  Dictionary is used "in place", without any preprocessing.-**  It must remain accessible throughout the entire frame decoding. */-LZ4FLIB_STATIC_API size_t-LZ4F_decompress_usingDict(LZ4F_dctx* dctxPtr,-                          void* dstBuffer, size_t* dstSizePtr,-                    const void* srcBuffer, size_t* srcSizePtr,-                    const void* dict, size_t dictSize,-                    const LZ4F_decompressOptions_t* decompressOptionsPtr);---/*! Custom memory allocation :+/*! Custom memory allocation : v1.9.4+  *  These prototypes make it possible to pass custom allocation/free functions.  *  LZ4F_customMem is provided at state creation time, using LZ4F_create*_advanced() listed below.  *  All allocation/free operations will be completed using these custom variants instead of regular <stdlib.h> ones.
cbits/lz4hc.c view
@@ -39,1593 +39,2154 @@ ***************************************/  /*! HEAPMODE :- *  Select how default compression function will allocate workplace memory,- *  in stack (0:fastest), or in heap (1:requires malloc()).- *  Since workplace is rather large, heap mode is recommended.-**/-#ifndef LZ4HC_HEAPMODE-#  define LZ4HC_HEAPMODE 1-#endif---/*===    Dependency    ===*/-#define LZ4_HC_STATIC_LINKING_ONLY-#include "lz4hc.h"---/*===   Common definitions   ===*/-#if defined(__GNUC__)-#  pragma GCC diagnostic ignored "-Wunused-function"-#endif-#if defined (__clang__)-#  pragma clang diagnostic ignored "-Wunused-function"-#endif--#define LZ4_COMMONDEFS_ONLY-#ifndef LZ4_SRC_INCLUDED-#include "lz4.c"   /* LZ4_count, constants, mem */-#endif---/*===   Enums   ===*/-typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;---/*===   Constants   ===*/-#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)-#define LZ4_OPT_NUM   (1<<12)---/*===   Macros   ===*/-#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )-#define MAX(a,b)   ( (a) > (b) ? (a) : (b) )-#define HASH_FUNCTION(i)         (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))-#define DELTANEXTMAXD(p)         chainTable[(p) & LZ4HC_MAXD_MASK]    /* flexible, LZ4HC_MAXD dependent */-#define DELTANEXTU16(table, pos) table[(U16)(pos)]   /* faster */-/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */-#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor--static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }---/**************************************-*  HC Compression-**************************************/-static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)-{-    MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable));-    MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));-}--static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)-{-    size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart);-    size_t newStartingOffset = bufferSize + hc4->dictLimit;-    assert(newStartingOffset >= bufferSize);  /* check overflow */-    if (newStartingOffset > 1 GB) {-        LZ4HC_clearTables(hc4);-        newStartingOffset = 0;-    }-    newStartingOffset += 64 KB;-    hc4->nextToUpdate = (U32)newStartingOffset;-    hc4->prefixStart = start;-    hc4->end = start;-    hc4->dictStart = start;-    hc4->dictLimit = (U32)newStartingOffset;-    hc4->lowLimit = (U32)newStartingOffset;-}---/* Update chains up to ip (excluded) */-LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)-{-    U16* const chainTable = hc4->chainTable;-    U32* const hashTable  = hc4->hashTable;-    const BYTE* const prefixPtr = hc4->prefixStart;-    U32 const prefixIdx = hc4->dictLimit;-    U32 const target = (U32)(ip - prefixPtr) + prefixIdx;-    U32 idx = hc4->nextToUpdate;-    assert(ip >= prefixPtr);-    assert(target >= prefixIdx);--    while (idx < target) {-        U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx);-        size_t delta = idx - hashTable[h];-        if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;-        DELTANEXTU16(chainTable, idx) = (U16)delta;-        hashTable[h] = idx;-        idx++;-    }--    hc4->nextToUpdate = target;-}--/** LZ4HC_countBack() :- * @return : negative value, nb of common bytes before ip/match */-LZ4_FORCE_INLINE-int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,-                    const BYTE* const iMin, const BYTE* const mMin)-{-    int back = 0;-    int const min = (int)MAX(iMin - ip, mMin - match);-    assert(min <= 0);-    assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));-    assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));-    while ( (back > min)-         && (ip[back-1] == match[back-1]) )-            back--;-    return back;-}--#if defined(_MSC_VER)-#  define LZ4HC_rotl32(x,r) _rotl(x,r)-#else-#  define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r)))-#endif---static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern)-{-    size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;-    if (bitsToRotate == 0) return pattern;-    return LZ4HC_rotl32(pattern, (int)bitsToRotate);-}--/* LZ4HC_countPattern() :- * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */-static unsigned-LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)-{-    const BYTE* const iStart = ip;-    reg_t const pattern = (sizeof(pattern)==8) ?-        (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32;--    while (likely(ip < iEnd-(sizeof(pattern)-1))) {-        reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;-        if (!diff) { ip+=sizeof(pattern); continue; }-        ip += LZ4_NbCommonBytes(diff);-        return (unsigned)(ip - iStart);-    }--    if (LZ4_isLittleEndian()) {-        reg_t patternByte = pattern;-        while ((ip<iEnd) && (*ip == (BYTE)patternByte)) {-            ip++; patternByte >>= 8;-        }-    } else {  /* big endian */-        U32 bitOffset = (sizeof(pattern)*8) - 8;-        while (ip < iEnd) {-            BYTE const byte = (BYTE)(pattern >> bitOffset);-            if (*ip != byte) break;-            ip ++; bitOffset -= 8;-    }   }--    return (unsigned)(ip - iStart);-}--/* LZ4HC_reverseCountPattern() :- * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)- * read using natural platform endianness */-static unsigned-LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)-{-    const BYTE* const iStart = ip;--    while (likely(ip >= iLow+4)) {-        if (LZ4_read32(ip-4) != pattern) break;-        ip -= 4;-    }-    {   const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */-        while (likely(ip>iLow)) {-            if (ip[-1] != *bytePtr) break;-            ip--; bytePtr--;-    }   }-    return (unsigned)(iStart - ip);-}--/* LZ4HC_protectDictEnd() :- * Checks if the match is in the last 3 bytes of the dictionary, so reading the- * 4 byte MINMATCH would overflow.- * @returns true if the match index is okay.- */-static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)-{-    return ((U32)((dictLimit - 1) - matchIndex) >= 3);-}--typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;-typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;--LZ4_FORCE_INLINE int-LZ4HC_InsertAndGetWiderMatch (-        LZ4HC_CCtx_internal* const hc4,-        const BYTE* const ip,-        const BYTE* const iLowLimit, const BYTE* const iHighLimit,-        int longest,-        const BYTE** matchpos,-        const BYTE** startpos,-        const int maxNbAttempts,-        const int patternAnalysis, const int chainSwap,-        const dictCtx_directive dict,-        const HCfavor_e favorDecSpeed)-{-    U16* const chainTable = hc4->chainTable;-    U32* const HashTable = hc4->hashTable;-    const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;-    const BYTE* const prefixPtr = hc4->prefixStart;-    const U32 prefixIdx = hc4->dictLimit;-    const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;-    const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex);-    const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;-    const BYTE* const dictStart = hc4->dictStart;-    const U32 dictIdx = hc4->lowLimit;-    const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx;-    int const lookBackLength = (int)(ip-iLowLimit);-    int nbAttempts = maxNbAttempts;-    U32 matchChainPos = 0;-    U32 const pattern = LZ4_read32(ip);-    U32 matchIndex;-    repeat_state_e repeat = rep_untested;-    size_t srcPatternLength = 0;--    DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");-    /* First Match */-    LZ4HC_Insert(hc4, ip);-    matchIndex = HashTable[LZ4HC_hashPtr(ip)];-    DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",-                matchIndex, lowestMatchIndex);--    while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {-        int matchLength=0;-        nbAttempts--;-        assert(matchIndex < ipIndex);-        if (favorDecSpeed && (ipIndex - matchIndex < 8)) {-            /* do nothing */-        } else if (matchIndex >= prefixIdx) {   /* within current Prefix */-            const BYTE* const matchPtr = prefixPtr + matchIndex - prefixIdx;-            assert(matchPtr < ip);-            assert(longest >= 1);-            if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {-                if (LZ4_read32(matchPtr) == pattern) {-                    int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;-                    matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);-                    matchLength -= back;-                    if (matchLength > longest) {-                        longest = matchLength;-                        *matchpos = matchPtr + back;-                        *startpos = ip + back;-            }   }   }-        } else {   /* lowestMatchIndex <= matchIndex < dictLimit */-            const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);-            assert(matchIndex >= dictIdx);-            if ( likely(matchIndex <= prefixIdx - 4)-              && (LZ4_read32(matchPtr) == pattern) ) {-                int back = 0;-                const BYTE* vLimit = ip + (prefixIdx - matchIndex);-                if (vLimit > iHighLimit) vLimit = iHighLimit;-                matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;-                if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))-                    matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);-                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;-                matchLength -= back;-                if (matchLength > longest) {-                    longest = matchLength;-                    *matchpos = prefixPtr - prefixIdx + matchIndex + back;   /* virtual pos, relative to ip, to retrieve offset */-                    *startpos = ip + back;-        }   }   }--        if (chainSwap && matchLength==longest) {   /* better match => select a better chain */-            assert(lookBackLength==0);   /* search forward only */-            if (matchIndex + (U32)longest <= ipIndex) {-                int const kTrigger = 4;-                U32 distanceToNextMatch = 1;-                int const end = longest - MINMATCH + 1;-                int step = 1;-                int accel = 1 << kTrigger;-                int pos;-                for (pos = 0; pos < end; pos += step) {-                    U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);-                    step = (accel++ >> kTrigger);-                    if (candidateDist > distanceToNextMatch) {-                        distanceToNextMatch = candidateDist;-                        matchChainPos = (U32)pos;-                        accel = 1 << kTrigger;-                }   }-                if (distanceToNextMatch > 1) {-                    if (distanceToNextMatch > matchIndex) break;   /* avoid overflow */-                    matchIndex -= distanceToNextMatch;-                    continue;-        }   }   }--        {   U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);-            if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {-                U32 const matchCandidateIdx = matchIndex-1;-                /* may be a repeated pattern */-                if (repeat == rep_untested) {-                    if ( ((pattern & 0xFFFF) == (pattern >> 16))-                      &  ((pattern & 0xFF)   == (pattern >> 24)) ) {-                        repeat = rep_confirmed;-                        srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);-                    } else {-                        repeat = rep_not;-                }   }-                if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)-                  && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) {-                    const int extDict = matchCandidateIdx < prefixIdx;-                    const BYTE* const matchPtr = (extDict ? dictStart - dictIdx : prefixPtr - prefixIdx) + matchCandidateIdx;-                    if (LZ4_read32(matchPtr) == pattern) {  /* good candidate */-                        const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;-                        size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);-                        if (extDict && matchPtr + forwardPatternLength == iLimit) {-                            U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);-                            forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);-                        }-                        {   const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;-                            size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);-                            size_t currentSegmentLength;-                            if (!extDict-                              && matchPtr - backLength == prefixPtr-                              && dictIdx < prefixIdx) {-                                U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);-                                backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);-                            }-                            /* Limit backLength not go further than lowestMatchIndex */-                            backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);-                            assert(matchCandidateIdx - backLength >= lowestMatchIndex);-                            currentSegmentLength = backLength + forwardPatternLength;-                            /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */-                            if ( (currentSegmentLength >= srcPatternLength)   /* current pattern segment large enough to contain full srcPatternLength */-                              && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */-                                U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength;  /* best position, full pattern, might be followed by more match */-                                if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))-                                    matchIndex = newMatchIndex;-                                else {-                                    /* Can only happen if started in the prefix */-                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);-                                    matchIndex = prefixIdx;-                                }-                            } else {-                                U32 const newMatchIndex = matchCandidateIdx - (U32)backLength;   /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */-                                if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {-                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);-                                    matchIndex = prefixIdx;-                                } else {-                                    matchIndex = newMatchIndex;-                                    if (lookBackLength==0) {  /* no back possible */-                                        size_t const maxML = MIN(currentSegmentLength, srcPatternLength);-                                        if ((size_t)longest < maxML) {-                                            assert(prefixPtr - prefixIdx + matchIndex != ip);-                                            if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;-                                            assert(maxML < 2 GB);-                                            longest = (int)maxML;-                                            *matchpos = prefixPtr - prefixIdx + matchIndex;   /* virtual pos, relative to ip, to retrieve offset */-                                            *startpos = ip;-                                        }-                                        {   U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);-                                            if (distToNextPattern > matchIndex) break;  /* avoid overflow */-                                            matchIndex -= distToNextPattern;-                        }   }   }   }   }-                        continue;-                }   }-        }   }   /* PA optimization */--        /* follow current chain */-        matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);--    }  /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */--    if ( dict == usingDictCtxHc-      && nbAttempts > 0-      && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {-        size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;-        U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];-        assert(dictEndOffset <= 1 GB);-        matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;-        while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {-            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;--            if (LZ4_read32(matchPtr) == pattern) {-                int mlt;-                int back = 0;-                const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);-                if (vLimit > iHighLimit) vLimit = iHighLimit;-                mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;-                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;-                mlt -= back;-                if (mlt > longest) {-                    longest = mlt;-                    *matchpos = prefixPtr - prefixIdx + matchIndex + back;-                    *startpos = ip + back;-            }   }--            {   U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);-                dictMatchIndex -= nextOffset;-                matchIndex -= nextOffset;-    }   }   }--    return longest;-}--LZ4_FORCE_INLINE int-LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4,   /* Index table will be updated */-                       const BYTE* const ip, const BYTE* const iLimit,-                       const BYTE** matchpos,-                       const int maxNbAttempts,-                       const int patternAnalysis,-                       const dictCtx_directive dict)-{-    const BYTE* uselessPtr = ip;-    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),-     * but this won't be the case here, as we define iLowLimit==ip,-     * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */-    return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);-}--/* LZ4HC_encodeSequence() :- * @return : 0 if ok,- *           1 if buffer issue detected */-LZ4_FORCE_INLINE int LZ4HC_encodeSequence (-    const BYTE** _ip,-    BYTE** _op,-    const BYTE** _anchor,-    int matchLength,-    const BYTE* const match,-    limitedOutput_directive limit,-    BYTE* oend)-{-#define ip      (*_ip)-#define op      (*_op)-#define anchor  (*_anchor)--    size_t length;-    BYTE* const token = op++;--#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)-    static const BYTE* start = NULL;-    static U32 totalCost = 0;-    U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);-    U32 const ll = (U32)(ip - anchor);-    U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;-    U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;-    U32 const cost = 1 + llAdd + ll + 2 + mlAdd;-    if (start==NULL) start = anchor;  /* only works for single segment */-    /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */-    DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u",-                pos,-                (U32)(ip - anchor), matchLength, (U32)(ip-match),-                cost, totalCost);-    totalCost += cost;-#endif--    /* Encode Literal length */-    length = (size_t)(ip - anchor);-    LZ4_STATIC_ASSERT(notLimited == 0);-    /* Check output limit */-    if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {-        DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",-                (int)length, (int)(oend - op));-        return 1;-    }-    if (length >= RUN_MASK) {-        size_t len = length - RUN_MASK;-        *token = (RUN_MASK << ML_BITS);-        for(; len >= 255 ; len -= 255) *op++ = 255;-        *op++ = (BYTE)len;-    } else {-        *token = (BYTE)(length << ML_BITS);-    }--    /* Copy Literals */-    LZ4_wildCopy8(op, anchor, op + length);-    op += length;--    /* Encode Offset */-    assert( (ip - match) <= LZ4_DISTANCE_MAX );   /* note : consider providing offset as a value, rather than as a pointer difference */-    LZ4_writeLE16(op, (U16)(ip - match)); op += 2;--    /* Encode MatchLength */-    assert(matchLength >= MINMATCH);-    length = (size_t)matchLength - MINMATCH;-    if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {-        DEBUGLOG(6, "Not enough room to write match length");-        return 1;   /* Check output limit */-    }-    if (length >= ML_MASK) {-        *token += ML_MASK;-        length -= ML_MASK;-        for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }-        if (length >= 255) { length -= 255; *op++ = 255; }-        *op++ = (BYTE)length;-    } else {-        *token += (BYTE)(length);-    }--    /* Prepare next loop */-    ip += matchLength;-    anchor = ip;--    return 0;-}-#undef ip-#undef op-#undef anchor--LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (-    LZ4HC_CCtx_internal* const ctx,-    const char* const source,-    char* const dest,-    int* srcSizePtr,-    int const maxOutputSize,-    int maxNbAttempts,-    const limitedOutput_directive limit,-    const dictCtx_directive dict-    )-{-    const int inputSize = *srcSizePtr;-    const int patternAnalysis = (maxNbAttempts > 128);   /* levels 9+ */--    const BYTE* ip = (const BYTE*) source;-    const BYTE* anchor = ip;-    const BYTE* const iend = ip + inputSize;-    const BYTE* const mflimit = iend - MFLIMIT;-    const BYTE* const matchlimit = (iend - LASTLITERALS);--    BYTE* optr = (BYTE*) dest;-    BYTE* op = (BYTE*) dest;-    BYTE* oend = op + maxOutputSize;--    int   ml0, ml, ml2, ml3;-    const BYTE* start0;-    const BYTE* ref0;-    const BYTE* ref = NULL;-    const BYTE* start2 = NULL;-    const BYTE* ref2 = NULL;-    const BYTE* start3 = NULL;-    const BYTE* ref3 = NULL;--    /* init */-    *srcSizePtr = 0;-    if (limit == fillOutput) oend -= LASTLITERALS;                  /* Hack for support LZ4 format restriction */-    if (inputSize < LZ4_minLength) goto _last_literals;             /* Input too small, no compression (all literals) */--    /* Main Loop */-    while (ip <= mflimit) {-        ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis, dict);-        if (ml<MINMATCH) { ip++; continue; }--        /* saved, in case we would skip too much */-        start0 = ip; ref0 = ref; ml0 = ml;--_Search2:-        if (ip+ml <= mflimit) {-            ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,-                            ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2,-                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);-        } else {-            ml2 = ml;-        }--        if (ml2 == ml) { /* No better match => encode ML1 */-            optr = op;-            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;-            continue;-        }--        if (start0 < ip) {   /* first match was skipped at least once */-            if (start2 < ip + ml0) {  /* squeezing ML1 between ML0(original ML1) and ML2 */-                ip = start0; ref = ref0; ml = ml0;  /* restore initial ML1 */-        }   }--        /* Here, start0==ip */-        if ((start2 - ip) < 3) {  /* First Match too small : removed */-            ml = ml2;-            ip = start2;-            ref =ref2;-            goto _Search2;-        }--_Search3:-        /* At this stage, we have :-        *  ml2 > ml1, and-        *  ip1+3 <= ip2 (usually < ip1+ml1) */-        if ((start2 - ip) < OPTIMAL_ML) {-            int correction;-            int new_ml = ml;-            if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;-            if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;-            correction = new_ml - (int)(start2 - ip);-            if (correction > 0) {-                start2 += correction;-                ref2 += correction;-                ml2 -= correction;-            }-        }-        /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */--        if (start2 + ml2 <= mflimit) {-            ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,-                            start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3,-                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);-        } else {-            ml3 = ml2;-        }--        if (ml3 == ml2) {  /* No better match => encode ML1 and ML2 */-            /* ip & ref are known; Now for ml */-            if (start2 < ip+ml)  ml = (int)(start2 - ip);-            /* Now, encode 2 sequences */-            optr = op;-            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;-            ip = start2;-            optr = op;-            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) {-                ml  = ml2;-                ref = ref2;-                goto _dest_overflow;-            }-            continue;-        }--        if (start3 < ip+ml+3) {  /* Not enough space for match 2 : remove it */-            if (start3 >= (ip+ml)) {  /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */-                if (start2 < ip+ml) {-                    int correction = (int)(ip+ml - start2);-                    start2 += correction;-                    ref2 += correction;-                    ml2 -= correction;-                    if (ml2 < MINMATCH) {-                        start2 = start3;-                        ref2 = ref3;-                        ml2 = ml3;-                    }-                }--                optr = op;-                if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;-                ip  = start3;-                ref = ref3;-                ml  = ml3;--                start0 = start2;-                ref0 = ref2;-                ml0 = ml2;-                goto _Search2;-            }--            start2 = start3;-            ref2 = ref3;-            ml2 = ml3;-            goto _Search3;-        }--        /*-        * OK, now we have 3 ascending matches;-        * let's write the first one ML1.-        * ip & ref are known; Now decide ml.-        */-        if (start2 < ip+ml) {-            if ((start2 - ip) < OPTIMAL_ML) {-                int correction;-                if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;-                if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;-                correction = ml - (int)(start2 - ip);-                if (correction > 0) {-                    start2 += correction;-                    ref2 += correction;-                    ml2 -= correction;-                }-            } else {-                ml = (int)(start2 - ip);-            }-        }-        optr = op;-        if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;--        /* ML2 becomes ML1 */-        ip = start2; ref = ref2; ml = ml2;--        /* ML3 becomes ML2 */-        start2 = start3; ref2 = ref3; ml2 = ml3;--        /* let's find a new ML3 */-        goto _Search3;-    }--_last_literals:-    /* Encode Last Literals */-    {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */-        size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;-        size_t const totalSize = 1 + llAdd + lastRunSize;-        if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */-        if (limit && (op + totalSize > oend)) {-            if (limit == limitedOutput) return 0;-            /* adapt lastRunSize to fill 'dest' */-            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;-            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;-            lastRunSize -= llAdd;-        }-        DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);-        ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */--        if (lastRunSize >= RUN_MASK) {-            size_t accumulator = lastRunSize - RUN_MASK;-            *op++ = (RUN_MASK << ML_BITS);-            for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;-            *op++ = (BYTE) accumulator;-        } else {-            *op++ = (BYTE)(lastRunSize << ML_BITS);-        }-        LZ4_memcpy(op, anchor, lastRunSize);-        op += lastRunSize;-    }--    /* End */-    *srcSizePtr = (int) (((const char*)ip) - source);-    return (int) (((char*)op)-dest);--_dest_overflow:-    if (limit == fillOutput) {-        /* Assumption : ip, anchor, ml and ref must be set correctly */-        size_t const ll = (size_t)(ip - anchor);-        size_t const ll_addbytes = (ll + 240) / 255;-        size_t const ll_totalCost = 1 + ll_addbytes + ll;-        BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */-        DEBUGLOG(6, "Last sequence overflowing");-        op = optr;  /* restore correct out pointer */-        if (op + ll_totalCost <= maxLitPos) {-            /* ll validated; now adjust match length */-            size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));-            size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);-            assert(maxMlSize < INT_MAX); assert(ml >= 0);-            if ((size_t)ml > maxMlSize) ml = (int)maxMlSize;-            if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ml >= MFLIMIT) {-                LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, notLimited, oend);-        }   }-        goto _last_literals;-    }-    /* compression failed */-    return 0;-}---static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,-    const char* const source, char* dst,-    int* srcSizePtr, int dstCapacity,-    int const nbSearches, size_t sufficient_len,-    const limitedOutput_directive limit, int const fullUpdate,-    const dictCtx_directive dict,-    const HCfavor_e favorDecSpeed);---LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (-    LZ4HC_CCtx_internal* const ctx,-    const char* const src,-    char* const dst,-    int* const srcSizePtr,-    int const dstCapacity,-    int cLevel,-    const limitedOutput_directive limit,-    const dictCtx_directive dict-    )-{-    typedef enum { lz4hc, lz4opt } lz4hc_strat_e;-    typedef struct {-        lz4hc_strat_e strat;-        int nbSearches;-        U32 targetLength;-    } cParams_t;-    static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = {-        { lz4hc,     2, 16 },  /* 0, unused */-        { lz4hc,     2, 16 },  /* 1, unused */-        { lz4hc,     2, 16 },  /* 2, unused */-        { lz4hc,     4, 16 },  /* 3 */-        { lz4hc,     8, 16 },  /* 4 */-        { lz4hc,    16, 16 },  /* 5 */-        { lz4hc,    32, 16 },  /* 6 */-        { lz4hc,    64, 16 },  /* 7 */-        { lz4hc,   128, 16 },  /* 8 */-        { lz4hc,   256, 16 },  /* 9 */-        { lz4opt,   96, 64 },  /*10==LZ4HC_CLEVEL_OPT_MIN*/-        { lz4opt,  512,128 },  /*11 */-        { lz4opt,16384,LZ4_OPT_NUM },  /* 12==LZ4HC_CLEVEL_MAX */-    };--    DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",-                ctx, src, *srcSizePtr, limit);--    if (limit == fillOutput && dstCapacity < 1) return 0;   /* Impossible to store anything */-    if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;    /* Unsupported input size (too large or negative) */--    ctx->end += *srcSizePtr;-    if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT;   /* note : convention is different from lz4frame, maybe something to review */-    cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);-    {   cParams_t const cParam = clTable[cLevel];-        HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;-        int result;--        if (cParam.strat == lz4hc) {-            result = LZ4HC_compress_hashChain(ctx,-                                src, dst, srcSizePtr, dstCapacity,-                                cParam.nbSearches, limit, dict);-        } else {-            assert(cParam.strat == lz4opt);-            result = LZ4HC_compress_optimal(ctx,-                                src, dst, srcSizePtr, dstCapacity,-                                cParam.nbSearches, cParam.targetLength, limit,-                                cLevel == LZ4HC_CLEVEL_MAX,   /* ultra mode */-                                dict, favor);-        }-        if (result <= 0) ctx->dirty = 1;-        return result;-    }-}--static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock);--static int-LZ4HC_compress_generic_noDictCtx (-        LZ4HC_CCtx_internal* const ctx,-        const char* const src,-        char* const dst,-        int* const srcSizePtr,-        int const dstCapacity,-        int cLevel,-        limitedOutput_directive limit-        )-{-    assert(ctx->dictCtx == NULL);-    return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);-}--static int-LZ4HC_compress_generic_dictCtx (-        LZ4HC_CCtx_internal* const ctx,-        const char* const src,-        char* const dst,-        int* const srcSizePtr,-        int const dstCapacity,-        int cLevel,-        limitedOutput_directive limit-        )-{-    const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit);-    assert(ctx->dictCtx != NULL);-    if (position >= 64 KB) {-        ctx->dictCtx = NULL;-        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);-    } else if (position == 0 && *srcSizePtr > 4 KB) {-        LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));-        LZ4HC_setExternalDict(ctx, (const BYTE *)src);-        ctx->compressionLevel = (short)cLevel;-        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);-    } else {-        return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);-    }-}--static int-LZ4HC_compress_generic (-        LZ4HC_CCtx_internal* const ctx,-        const char* const src,-        char* const dst,-        int* const srcSizePtr,-        int const dstCapacity,-        int cLevel,-        limitedOutput_directive limit-        )-{-    if (ctx->dictCtx == NULL) {-        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);-    } else {-        return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);-    }-}---int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }--static size_t LZ4_streamHC_t_alignment(void)-{-#if LZ4_ALIGN_TEST-    typedef struct { char c; LZ4_streamHC_t t; } t_a;-    return sizeof(t_a) - sizeof(LZ4_streamHC_t);-#else-    return 1;  /* effectively disabled */-#endif-}--/* state is presumed correctly initialized,- * in which case its size and alignment have already been validate */-int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)-{-    LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;-    if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0;-    LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);-    LZ4HC_init_internal (ctx, (const BYTE*)src);-    if (dstCapacity < LZ4_compressBound(srcSize))-        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);-    else-        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);-}--int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)-{-    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));-    if (ctx==NULL) return 0;   /* init failure */-    return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);-}--int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)-{-    int cSize;-#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1-    LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));-    if (statePtr==NULL) return 0;-#else-    LZ4_streamHC_t state;-    LZ4_streamHC_t* const statePtr = &state;-#endif-    cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);-#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1-    FREEMEM(statePtr);-#endif-    return cSize;-}--/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */-int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)-{-    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));-    if (ctx==NULL) return 0;   /* init failure */-    LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);-    LZ4_setCompressionLevel(ctx, cLevel);-    return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);-}----/**************************************-*  Streaming Functions-**************************************/-/* allocation */-#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)-LZ4_streamHC_t* LZ4_createStreamHC(void)-{-    LZ4_streamHC_t* const state =-        (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t));-    if (state == NULL) return NULL;-    LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT);-    return state;-}--int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)-{-    DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);-    if (!LZ4_streamHCPtr) return 0;  /* support free on NULL */-    FREEMEM(LZ4_streamHCPtr);-    return 0;-}-#endif---LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)-{-    LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;-    DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);-    /* check conditions */-    if (buffer == NULL) return NULL;-    if (size < sizeof(LZ4_streamHC_t)) return NULL;-    if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;-    /* init */-    { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);-      MEM_INIT(hcstate, 0, sizeof(*hcstate)); }-    LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);-    return LZ4_streamHCPtr;-}--/* just a stub */-void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)-{-    LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));-    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);-}--void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)-{-    DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);-    if (LZ4_streamHCPtr->internal_donotuse.dirty) {-        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));-    } else {-        /* preserve end - prefixStart : can trigger clearTable's threshold */-        if (LZ4_streamHCPtr->internal_donotuse.end != NULL) {-            LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.prefixStart;-        } else {-            assert(LZ4_streamHCPtr->internal_donotuse.prefixStart == NULL);-        }-        LZ4_streamHCPtr->internal_donotuse.prefixStart = NULL;-        LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;-    }-    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);-}--void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)-{-    DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);-    if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;-    if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;-    LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;-}--void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)-{-    LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);-}--/* LZ4_loadDictHC() :- * LZ4_streamHCPtr is presumed properly initialized */-int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,-              const char* dictionary, int dictSize)-{-    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;-    DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize);-    assert(LZ4_streamHCPtr != NULL);-    if (dictSize > 64 KB) {-        dictionary += (size_t)dictSize - 64 KB;-        dictSize = 64 KB;-    }-    /* need a full initialization, there are bad side-effects when using resetFast() */-    {   int const cLevel = ctxPtr->compressionLevel;-        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));-        LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);-    }-    LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);-    ctxPtr->end = (const BYTE*)dictionary + dictSize;-    if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);-    return dictSize;-}--void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {-    working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;-}--/* compression */--static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)-{-    DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);-    if (ctxPtr->end >= ctxPtr->prefixStart + 4)-        LZ4HC_Insert (ctxPtr, ctxPtr->end-3);   /* Referencing remaining dictionary content */--    /* Only one memory segment for extDict, so any previous extDict is lost at this stage */-    ctxPtr->lowLimit  = ctxPtr->dictLimit;-    ctxPtr->dictStart  = ctxPtr->prefixStart;-    ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);-    ctxPtr->prefixStart = newBlock;-    ctxPtr->end  = newBlock;-    ctxPtr->nextToUpdate = ctxPtr->dictLimit;   /* match referencing will resume from there */--    /* cannot reference an extDict and a dictCtx at the same time */-    ctxPtr->dictCtx = NULL;-}--static int-LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,-                                 const char* src, char* dst,-                                 int* srcSizePtr, int dstCapacity,-                                 limitedOutput_directive limit)-{-    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;-    DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",-                LZ4_streamHCPtr, src, *srcSizePtr, limit);-    assert(ctxPtr != NULL);-    /* auto-init if forgotten */-    if (ctxPtr->prefixStart == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);--    /* Check overflow */-    if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) {-        size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart);-        if (dictSize > 64 KB) dictSize = 64 KB;-        LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);-    }--    /* Check if blocks follow each other */-    if ((const BYTE*)src != ctxPtr->end)-        LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);--    /* Check overlapping input/dictionary space */-    {   const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;-        const BYTE* const dictBegin = ctxPtr->dictStart;-        const BYTE* const dictEnd   = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit);-        if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {-            if (sourceEnd > dictEnd) sourceEnd = dictEnd;-            ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart);-            ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart);-            if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) {-                ctxPtr->lowLimit = ctxPtr->dictLimit;-                ctxPtr->dictStart = ctxPtr->prefixStart;-    }   }   }--    return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);-}--int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)-{-    if (dstCapacity < LZ4_compressBound(srcSize))-        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);-    else-        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);-}--int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)-{-    return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);-}----/* LZ4_saveDictHC :- * save history content- * into a user-provided buffer- * which is then used to continue compression- */-int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)-{-    LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;-    int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);-    DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);-    assert(prefixSize >= 0);-    if (dictSize > 64 KB) dictSize = 64 KB;-    if (dictSize < 4) dictSize = 0;-    if (dictSize > prefixSize) dictSize = prefixSize;-    if (safeBuffer == NULL) assert(dictSize == 0);-    if (dictSize > 0)-        LZ4_memmove(safeBuffer, streamPtr->end - dictSize, dictSize);-    {   U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit;-        streamPtr->end = (const BYTE*)safeBuffer + dictSize;-        streamPtr->prefixStart = streamPtr->end - dictSize;-        streamPtr->dictLimit = endIndex - (U32)dictSize;-        streamPtr->lowLimit = endIndex - (U32)dictSize;-        streamPtr->dictStart = streamPtr->prefixStart;-        if (streamPtr->nextToUpdate < streamPtr->dictLimit)-            streamPtr->nextToUpdate = streamPtr->dictLimit;-    }-    return dictSize;-}---/***************************************************-*  Deprecated Functions-***************************************************/--/* These functions currently generate deprecation warnings */--/* Wrappers for deprecated compression functions */-int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }-int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }-int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }-int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }-int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }-int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }-int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }-int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }-int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }-int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }---/* Deprecated streaming functions */-int LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); }--/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)- * @return : 0 on success, !=0 if error */-int LZ4_resetStreamStateHC(void* state, char* inputBuffer)-{-    LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));-    if (hc4 == NULL) return 1;   /* init failed */-    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);-    return 0;-}--#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)-void* LZ4_createHC (const char* inputBuffer)-{-    LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();-    if (hc4 == NULL) return NULL;   /* not enough memory */-    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);-    return hc4;-}--int LZ4_freeHC (void* LZ4HC_Data)-{-    if (!LZ4HC_Data) return 0;  /* support free on NULL */-    FREEMEM(LZ4HC_Data);-    return 0;-}-#endif--int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)-{-    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);-}--int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)-{-    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);-}--char* LZ4_slideInputBufferHC(void* LZ4HC_Data)-{-    LZ4_streamHC_t* const ctx = (LZ4_streamHC_t*)LZ4HC_Data;-    const BYTE* bufferStart = ctx->internal_donotuse.prefixStart - ctx->internal_donotuse.dictLimit + ctx->internal_donotuse.lowLimit;-    LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel);-    /* avoid const char * -> char * conversion warning :( */-    return (char*)(uptrval)bufferStart;-}---/* ================================================- *  LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])- * ===============================================*/-typedef struct {-    int price;-    int off;-    int mlen;-    int litlen;-} LZ4HC_optimal_t;--/* price in bytes */-LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)-{-    int price = litlen;-    assert(litlen >= 0);-    if (litlen >= (int)RUN_MASK)-        price += 1 + ((litlen-(int)RUN_MASK) / 255);-    return price;-}---/* requires mlen >= MINMATCH */-LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)-{-    int price = 1 + 2 ; /* token + 16-bit offset */-    assert(litlen >= 0);-    assert(mlen >= MINMATCH);--    price += LZ4HC_literalsPrice(litlen);--    if (mlen >= (int)(ML_MASK+MINMATCH))-        price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);--    return price;-}---typedef struct {-    int off;-    int len;-} LZ4HC_match_t;--LZ4_FORCE_INLINE LZ4HC_match_t-LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,-                      const BYTE* ip, const BYTE* const iHighLimit,-                      int minLen, int nbSearches,-                      const dictCtx_directive dict,-                      const HCfavor_e favorDecSpeed)-{-    LZ4HC_match_t match = { 0 , 0 };-    const BYTE* matchPtr = NULL;-    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),-     * but this won't be the case here, as we define iLowLimit==ip,-     * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */-    int matchLength = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, &matchPtr, &ip, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);-    if (matchLength <= minLen) return match;-    if (favorDecSpeed) {-        if ((matchLength>18) & (matchLength<=36)) matchLength=18;   /* favor shortcut */-    }-    match.len = matchLength;-    match.off = (int)(ip-matchPtr);-    return match;-}---static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,-                                    const char* const source,-                                    char* dst,-                                    int* srcSizePtr,-                                    int dstCapacity,-                                    int const nbSearches,-                                    size_t sufficient_len,-                                    const limitedOutput_directive limit,-                                    int const fullUpdate,-                                    const dictCtx_directive dict,-                                    const HCfavor_e favorDecSpeed)-{-    int retval = 0;-#define TRAILING_LITERALS 3-#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1-    LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));-#else-    LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS];   /* ~64 KB, which is a bit large for stack... */-#endif--    const BYTE* ip = (const BYTE*) source;-    const BYTE* anchor = ip;-    const BYTE* const iend = ip + *srcSizePtr;-    const BYTE* const mflimit = iend - MFLIMIT;-    const BYTE* const matchlimit = iend - LASTLITERALS;-    BYTE* op = (BYTE*) dst;-    BYTE* opSaved = (BYTE*) dst;-    BYTE* oend = op + dstCapacity;-    int ovml = MINMATCH;  /* overflow - last sequence */-    const BYTE* ovref = NULL;--    /* init */-#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1-    if (opt == NULL) goto _return_label;-#endif-    DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);-    *srcSizePtr = 0;-    if (limit == fillOutput) oend -= LASTLITERALS;   /* Hack for support LZ4 format restriction */-    if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;--    /* Main Loop */-    while (ip <= mflimit) {-         int const llen = (int)(ip - anchor);-         int best_mlen, best_off;-         int cur, last_match_pos = 0;--         LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);-         if (firstMatch.len==0) { ip++; continue; }--         if ((size_t)firstMatch.len > sufficient_len) {-             /* good enough solution : immediate encoding */-             int const firstML = firstMatch.len;-             const BYTE* const matchPos = ip - firstMatch.off;-             opSaved = op;-             if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) {  /* updates ip, op and anchor */-                 ovml = firstML;-                 ovref = matchPos;-                 goto _dest_overflow;-             }-             continue;-         }--         /* set prices for first positions (literals) */-         {   int rPos;-             for (rPos = 0 ; rPos < MINMATCH ; rPos++) {-                 int const cost = LZ4HC_literalsPrice(llen + rPos);-                 opt[rPos].mlen = 1;-                 opt[rPos].off = 0;-                 opt[rPos].litlen = llen + rPos;-                 opt[rPos].price = cost;-                 DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",-                             rPos, cost, opt[rPos].litlen);-         }   }-         /* set prices using initial match */-         {   int mlen = MINMATCH;-             int const matchML = firstMatch.len;   /* necessarily < sufficient_len < LZ4_OPT_NUM */-             int const offset = firstMatch.off;-             assert(matchML < LZ4_OPT_NUM);-             for ( ; mlen <= matchML ; mlen++) {-                 int const cost = LZ4HC_sequencePrice(llen, mlen);-                 opt[mlen].mlen = mlen;-                 opt[mlen].off = offset;-                 opt[mlen].litlen = llen;-                 opt[mlen].price = cost;-                 DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup",-                             mlen, cost, mlen);-         }   }-         last_match_pos = firstMatch.len;-         {   int addLit;-             for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {-                 opt[last_match_pos+addLit].mlen = 1; /* literal */-                 opt[last_match_pos+addLit].off = 0;-                 opt[last_match_pos+addLit].litlen = addLit;-                 opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);-                 DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",-                             last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);-         }   }--         /* check further positions */-         for (cur = 1; cur < last_match_pos; cur++) {-             const BYTE* const curPtr = ip + cur;-             LZ4HC_match_t newMatch;--             if (curPtr > mflimit) break;-             DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u",-                     cur, opt[cur].price, opt[cur+1].price, cur+1);-             if (fullUpdate) {-                 /* not useful to search here if next position has same (or lower) cost */-                 if ( (opt[cur+1].price <= opt[cur].price)-                   /* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */-                   && (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )-                     continue;-             } else {-                 /* not useful to search here if next position has same (or lower) cost */-                 if (opt[cur+1].price <= opt[cur].price) continue;-             }--             DEBUGLOG(7, "search at rPos:%u", cur);-             if (fullUpdate)-                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);-             else-                 /* only test matches of minimum length; slightly faster, but misses a few bytes */-                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);-             if (!newMatch.len) continue;--             if ( ((size_t)newMatch.len > sufficient_len)-               || (newMatch.len + cur >= LZ4_OPT_NUM) ) {-                 /* immediate encoding */-                 best_mlen = newMatch.len;-                 best_off = newMatch.off;-                 last_match_pos = cur + 1;-                 goto encode;-             }--             /* before match : set price with literals at beginning */-             {   int const baseLitlen = opt[cur].litlen;-                 int litlen;-                 for (litlen = 1; litlen < MINMATCH; litlen++) {-                     int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);-                     int const pos = cur + litlen;-                     if (price < opt[pos].price) {-                         opt[pos].mlen = 1; /* literal */-                         opt[pos].off = 0;-                         opt[pos].litlen = baseLitlen+litlen;-                         opt[pos].price = price;-                         DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)",-                                     pos, price, opt[pos].litlen);-             }   }   }--             /* set prices using match at position = cur */-             {   int const matchML = newMatch.len;-                 int ml = MINMATCH;--                 assert(cur + newMatch.len < LZ4_OPT_NUM);-                 for ( ; ml <= matchML ; ml++) {-                     int const pos = cur + ml;-                     int const offset = newMatch.off;-                     int price;-                     int ll;-                     DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)",-                                 pos, last_match_pos);-                     if (opt[cur].mlen == 1) {-                         ll = opt[cur].litlen;-                         price = ((cur > ll) ? opt[cur - ll].price : 0)-                               + LZ4HC_sequencePrice(ll, ml);-                     } else {-                         ll = 0;-                         price = opt[cur].price + LZ4HC_sequencePrice(0, ml);-                     }--                    assert((U32)favorDecSpeed <= 1);-                     if (pos > last_match_pos+TRAILING_LITERALS-                      || price <= opt[pos].price - (int)favorDecSpeed) {-                         DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)",-                                     pos, price, ml);-                         assert(pos < LZ4_OPT_NUM);-                         if ( (ml == matchML)  /* last pos of last match */-                           && (last_match_pos < pos) )-                             last_match_pos = pos;-                         opt[pos].mlen = ml;-                         opt[pos].off = offset;-                         opt[pos].litlen = ll;-                         opt[pos].price = price;-             }   }   }-             /* complete following positions with literals */-             {   int addLit;-                 for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {-                     opt[last_match_pos+addLit].mlen = 1; /* literal */-                     opt[last_match_pos+addLit].off = 0;-                     opt[last_match_pos+addLit].litlen = addLit;-                     opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);-                     DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);-             }   }-         }  /* for (cur = 1; cur <= last_match_pos; cur++) */--         assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);-         best_mlen = opt[last_match_pos].mlen;-         best_off = opt[last_match_pos].off;-         cur = last_match_pos - best_mlen;--encode: /* cur, last_match_pos, best_mlen, best_off must be set */-         assert(cur < LZ4_OPT_NUM);-         assert(last_match_pos >= 1);  /* == 1 when only one candidate */-         DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos);-         {   int candidate_pos = cur;-             int selected_matchLength = best_mlen;-             int selected_offset = best_off;-             while (1) {  /* from end to beginning */-                 int const next_matchLength = opt[candidate_pos].mlen;  /* can be 1, means literal */-                 int const next_offset = opt[candidate_pos].off;-                 DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength);-                 opt[candidate_pos].mlen = selected_matchLength;-                 opt[candidate_pos].off = selected_offset;-                 selected_matchLength = next_matchLength;-                 selected_offset = next_offset;-                 if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */-                 assert(next_matchLength > 0);  /* can be 1, means literal */-                 candidate_pos -= next_matchLength;-         }   }--         /* encode all recorded sequences in order */-         {   int rPos = 0;  /* relative position (to ip) */-             while (rPos < last_match_pos) {-                 int const ml = opt[rPos].mlen;-                 int const offset = opt[rPos].off;-                 if (ml == 1) { ip++; rPos++; continue; }  /* literal; note: can end up with several literals, in which case, skip them */-                 rPos += ml;-                 assert(ml >= MINMATCH);-                 assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));-                 opSaved = op;-                 if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) {  /* updates ip, op and anchor */-                     ovml = ml;-                     ovref = ip - offset;-                     goto _dest_overflow;-         }   }   }-     }  /* while (ip <= mflimit) */--_last_literals:-     /* Encode Last Literals */-     {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */-         size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;-         size_t const totalSize = 1 + llAdd + lastRunSize;-         if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */-         if (limit && (op + totalSize > oend)) {-             if (limit == limitedOutput) { /* Check output limit */-                retval = 0;-                goto _return_label;-             }-             /* adapt lastRunSize to fill 'dst' */-             lastRunSize  = (size_t)(oend - op) - 1 /*token*/;-             llAdd = (lastRunSize + 256 - RUN_MASK) / 256;-             lastRunSize -= llAdd;-         }-         DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);-         ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */--         if (lastRunSize >= RUN_MASK) {-             size_t accumulator = lastRunSize - RUN_MASK;-             *op++ = (RUN_MASK << ML_BITS);-             for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;-             *op++ = (BYTE) accumulator;-         } else {-             *op++ = (BYTE)(lastRunSize << ML_BITS);-         }-         LZ4_memcpy(op, anchor, lastRunSize);-         op += lastRunSize;-     }--     /* End */-     *srcSizePtr = (int) (((const char*)ip) - source);-     retval = (int) ((char*)op-dst);-     goto _return_label;--_dest_overflow:-if (limit == fillOutput) {-     /* Assumption : ip, anchor, ovml and ovref must be set correctly */-     size_t const ll = (size_t)(ip - anchor);-     size_t const ll_addbytes = (ll + 240) / 255;-     size_t const ll_totalCost = 1 + ll_addbytes + ll;-     BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */-     DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend-1-opSaved));-     op = opSaved;  /* restore correct out pointer */-     if (op + ll_totalCost <= maxLitPos) {-         /* ll validated; now adjust match length */-         size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));-         size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);-         assert(maxMlSize < INT_MAX); assert(ovml >= 0);-         if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize;-         if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {-             DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);-             DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor);-             LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovref, notLimited, oend);-             DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor);-     }   }-     goto _last_literals;-}-_return_label:-#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1-     FREEMEM(opt);-#endif-     return retval;+ *  Select how stateless HC compression functions like `LZ4_compress_HC()`+ *  allocate memory for their workspace:+ *  in stack (0:fastest), or in heap (1:default, requires malloc()).+ *  Since workspace is rather large, heap mode is recommended.+**/+#ifndef LZ4HC_HEAPMODE+#  define LZ4HC_HEAPMODE 1+#endif+++/*===    Dependency    ===*/+#define LZ4_HC_STATIC_LINKING_ONLY+#include "lz4hc.h"+#include <limits.h>+++/*===   Shared lz4.c code   ===*/+#ifndef LZ4_SRC_INCLUDED+# if defined(__GNUC__)+#  pragma GCC diagnostic ignored "-Wunused-function"+# endif+# if defined (__clang__)+#  pragma clang diagnostic ignored "-Wunused-function"+# endif+# define LZ4_COMMONDEFS_ONLY+# include "lz4.c"   /* LZ4_count, constants, mem */+#endif+++/*===   Enums   ===*/+typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;+++/*===   Constants   ===*/+#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)+#define LZ4_OPT_NUM   (1<<12)+++/*===   Macros   ===*/+#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )+#define MAX(a,b)   ( (a) > (b) ? (a) : (b) )+++/*===   Levels definition   ===*/+typedef enum { lz4mid, lz4hc, lz4opt } lz4hc_strat_e;+typedef struct {+    lz4hc_strat_e strat;+    int nbSearches;+    U32 targetLength;+} cParams_t;+static const cParams_t k_clTable[LZ4HC_CLEVEL_MAX+1] = {+    { lz4mid,    2, 16 },  /* 0, unused */+    { lz4mid,    2, 16 },  /* 1, unused */+    { lz4mid,    2, 16 },  /* 2 */+    { lz4hc,     4, 16 },  /* 3 */+    { lz4hc,     8, 16 },  /* 4 */+    { lz4hc,    16, 16 },  /* 5 */+    { lz4hc,    32, 16 },  /* 6 */+    { lz4hc,    64, 16 },  /* 7 */+    { lz4hc,   128, 16 },  /* 8 */+    { lz4hc,   256, 16 },  /* 9 */+    { lz4opt,   96, 64 },  /*10==LZ4HC_CLEVEL_OPT_MIN*/+    { lz4opt,  512,128 },  /*11 */+    { lz4opt,16384,LZ4_OPT_NUM },  /* 12==LZ4HC_CLEVEL_MAX */+};++static cParams_t LZ4HC_getCLevelParams(int cLevel)+{+    /* note : clevel convention is a bit different from lz4frame,+     * possibly something worth revisiting for consistency */+    if (cLevel < 1)+        cLevel = LZ4HC_CLEVEL_DEFAULT;+    cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);+    return k_clTable[cLevel];+}+++/*===   Hashing   ===*/+#define LZ4HC_HASHSIZE 4+#define HASH_FUNCTION(i)      (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))+static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }++#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)+/* lie to the compiler about data alignment; use with caution */+static U64 LZ4_read64(const void* memPtr) { return *(const U64*) memPtr; }++#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1)+/* __pack instructions are safer, but compiler specific */+LZ4_PACK(typedef struct { U64 u64; }) LZ4_unalign64;+static U64 LZ4_read64(const void* ptr) { return ((const LZ4_unalign64*)ptr)->u64; }++#else  /* safe and portable access using memcpy() */+static U64 LZ4_read64(const void* memPtr)+{+    U64 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;+}++#endif /* LZ4_FORCE_MEMORY_ACCESS */++#define LZ4MID_HASHSIZE 8+#define LZ4MID_HASHLOG (LZ4HC_HASH_LOG-1)+#define LZ4MID_HASHTABLESIZE (1 << LZ4MID_HASHLOG)++static U32 LZ4MID_hash4(U32 v) { return (v * 2654435761U) >> (32-LZ4MID_HASHLOG); }+static U32 LZ4MID_hash4Ptr(const void* ptr) { return LZ4MID_hash4(LZ4_read32(ptr)); }+/* note: hash7 hashes the lower 56-bits.+ * It presumes input was read using little endian.*/+static U32 LZ4MID_hash7(U64 v) { return (U32)(((v  << (64-56)) * 58295818150454627ULL) >> (64-LZ4MID_HASHLOG)) ; }+static U64 LZ4_readLE64(const void* memPtr);+static U32 LZ4MID_hash8Ptr(const void* ptr) { return LZ4MID_hash7(LZ4_readLE64(ptr)); }++static U64 LZ4_readLE64(const void* memPtr)+{+    if (LZ4_isLittleEndian()) {+        return LZ4_read64(memPtr);+    } else {+        const BYTE* p = (const BYTE*)memPtr;+        /* note: relies on the compiler to simplify this expression */+        return (U64)p[0] | ((U64)p[1]<<8) | ((U64)p[2]<<16) | ((U64)p[3]<<24)+            | ((U64)p[4]<<32) | ((U64)p[5]<<40) | ((U64)p[6]<<48) | ((U64)p[7]<<56);+    }+}+++/*===   Count match length   ===*/+LZ4_FORCE_INLINE+unsigned LZ4HC_NbCommonBytes32(U32 val)+{+    assert(val != 0);+    if (LZ4_isLittleEndian()) {+#     if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)+        unsigned long r;+        _BitScanReverse(&r, val);+        return (unsigned)((31 - r) >> 3);+#     elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \+                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \+                                        !defined(LZ4_FORCE_SW_BITCOUNT)+        return (unsigned)__builtin_clz(val) >> 3;+#     else+        val >>= 8;+        val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) |+              (val + 0x00FF0000)) >> 24;+        return (unsigned)val ^ 3;+#     endif+    } else {+#     if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)+        unsigned long r;+        _BitScanForward(&r, val);+        return (unsigned)(r >> 3);+#     elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \+                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \+                                        !defined(LZ4_FORCE_SW_BITCOUNT)+        return (unsigned)__builtin_ctz(val) >> 3;+#     else+        const U32 m = 0x01010101;+        return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24;+#     endif+    }+}++/** LZ4HC_countBack() :+ * @return : negative value, nb of common bytes before ip/match */+LZ4_FORCE_INLINE+int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,+                    const BYTE* const iMin, const BYTE* const mMin)+{+    int back = 0;+    int const min = (int)MAX(iMin - ip, mMin - match);+    assert(min <= 0);+    assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));+    assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));++    while ((back - min) > 3) {+        U32 const v = LZ4_read32(ip + back - 4) ^ LZ4_read32(match + back - 4);+        if (v) {+            return (back - (int)LZ4HC_NbCommonBytes32(v));+        } else back -= 4; /* 4-byte step */+    }+    /* check remainder if any */+    while ( (back > min)+         && (ip[back-1] == match[back-1]) )+            back--;+    return back;+}++/*===   Chain table updates   ===*/+#define DELTANEXTU16(table, pos) table[(U16)(pos)]   /* faster */+/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */+#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor+++/**************************************+*  Init+**************************************/+static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)+{+    MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable));+    MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));+}++static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)+{+    size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart);+    size_t newStartingOffset = bufferSize + hc4->dictLimit;+    DEBUGLOG(5, "LZ4HC_init_internal");+    assert(newStartingOffset >= bufferSize);  /* check overflow */+    if (newStartingOffset > 1 GB) {+        LZ4HC_clearTables(hc4);+        newStartingOffset = 0;+    }+    newStartingOffset += 64 KB;+    hc4->nextToUpdate = (U32)newStartingOffset;+    hc4->prefixStart = start;+    hc4->end = start;+    hc4->dictStart = start;+    hc4->dictLimit = (U32)newStartingOffset;+    hc4->lowLimit = (U32)newStartingOffset;+}+++/**************************************+*  Encode+**************************************/+/* LZ4HC_encodeSequence() :+ * @return : 0 if ok,+ *           1 if buffer issue detected */+LZ4_FORCE_INLINE int LZ4HC_encodeSequence (+    const BYTE** _ip,+    BYTE** _op,+    const BYTE** _anchor,+    int matchLength,+    int offset,+    limitedOutput_directive limit,+    BYTE* oend)+{+#define ip      (*_ip)+#define op      (*_op)+#define anchor  (*_anchor)++    size_t length;+    BYTE* const token = op++;++#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)+    static const BYTE* start = NULL;+    static U32 totalCost = 0;+    U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);+    U32 const ll = (U32)(ip - anchor);+    U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;+    U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;+    U32 const cost = 1 + llAdd + ll + 2 + mlAdd;+    if (start==NULL) start = anchor;  /* only works for single segment */+    /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */+    DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5i, cost:%4u + %5u",+                pos,+                (U32)(ip - anchor), matchLength, offset,+                cost, totalCost);+    totalCost += cost;+#endif++    /* Encode Literal length */+    length = (size_t)(ip - anchor);+    LZ4_STATIC_ASSERT(notLimited == 0);+    /* Check output limit */+    if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {+        DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",+                (int)length, (int)(oend - op));+        return 1;+    }+    if (length >= RUN_MASK) {+        size_t len = length - RUN_MASK;+        *token = (RUN_MASK << ML_BITS);+        for(; len >= 255 ; len -= 255) *op++ = 255;+        *op++ = (BYTE)len;+    } else {+        *token = (BYTE)(length << ML_BITS);+    }++    /* Copy Literals */+    LZ4_wildCopy8(op, anchor, op + length);+    op += length;++    /* Encode Offset */+    assert(offset <= LZ4_DISTANCE_MAX );+    assert(offset > 0);+    LZ4_writeLE16(op, (U16)(offset)); op += 2;++    /* Encode MatchLength */+    assert(matchLength >= MINMATCH);+    length = (size_t)matchLength - MINMATCH;+    if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {+        DEBUGLOG(6, "Not enough room to write match length");+        return 1;   /* Check output limit */+    }+    if (length >= ML_MASK) {+        *token += ML_MASK;+        length -= ML_MASK;+        for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }+        if (length >= 255) { length -= 255; *op++ = 255; }+        *op++ = (BYTE)length;+    } else {+        *token += (BYTE)(length);+    }++    /* Prepare next loop */+    ip += matchLength;+    anchor = ip;++    return 0;++#undef ip+#undef op+#undef anchor+}+++typedef struct {+    int off;+    int len;+    int back;  /* negative value */+} LZ4HC_match_t;++LZ4HC_match_t LZ4HC_searchExtDict(const BYTE* ip, U32 ipIndex,+        const BYTE* const iLowLimit, const BYTE* const iHighLimit,+        const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex,+        int currentBestML, int nbAttempts)+{+    size_t const lDictEndIndex = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;+    U32 lDictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];+    U32 matchIndex = lDictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;+    int offset = 0, sBack = 0;+    assert(lDictEndIndex <= 1 GB);+    if (lDictMatchIndex>0)+        DEBUGLOG(7, "lDictEndIndex = %zu, lDictMatchIndex = %u", lDictEndIndex, lDictMatchIndex);+    while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {+        const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + lDictMatchIndex;++        if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {+            int mlt;+            int back = 0;+            const BYTE* vLimit = ip + (lDictEndIndex - lDictMatchIndex);+            if (vLimit > iHighLimit) vLimit = iHighLimit;+            mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;+            back = (ip > iLowLimit) ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;+            mlt -= back;+            if (mlt > currentBestML) {+                currentBestML = mlt;+                offset = (int)(ipIndex - matchIndex);+                sBack = back;+                DEBUGLOG(7, "found match of length %i within extDictCtx", currentBestML);+        }   }++        {   U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, lDictMatchIndex);+            lDictMatchIndex -= nextOffset;+            matchIndex -= nextOffset;+    }   }++    {   LZ4HC_match_t md;+        md.len = currentBestML;+        md.off = offset;+        md.back = sBack;+        return md;+    }+}++typedef LZ4HC_match_t (*LZ4MID_searchIntoDict_f)(const BYTE* ip, U32 ipIndex,+        const BYTE* const iHighLimit,+        const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex);++static LZ4HC_match_t LZ4MID_searchHCDict(const BYTE* ip, U32 ipIndex,+        const BYTE* const iHighLimit,+        const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex)+{+    return LZ4HC_searchExtDict(ip,ipIndex,+                            ip, iHighLimit,+                            dictCtx, gDictEndIndex,+                            MINMATCH-1, 2);+}++static LZ4HC_match_t LZ4MID_searchExtDict(const BYTE* ip, U32 ipIndex,+        const BYTE* const iHighLimit,+        const LZ4HC_CCtx_internal* dictCtx, U32 gDictEndIndex)+{+    size_t const lDictEndIndex = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;+    const U32* const hash4Table = dictCtx->hashTable;+    const U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;+    DEBUGLOG(7, "LZ4MID_searchExtDict (ipIdx=%u)", ipIndex);++    /* search long match first */+    {   U32 l8DictMatchIndex = hash8Table[LZ4MID_hash8Ptr(ip)];+        U32 m8Index = l8DictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;+        assert(lDictEndIndex <= 1 GB);+        if (ipIndex - m8Index <= LZ4_DISTANCE_MAX) {+            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + l8DictMatchIndex;+            const size_t safeLen = MIN(lDictEndIndex - l8DictMatchIndex, (size_t)(iHighLimit - ip));+            int mlt = (int)LZ4_count(ip, matchPtr, ip + safeLen);+            if (mlt >= MINMATCH) {+                LZ4HC_match_t md;+                DEBUGLOG(7, "Found long ExtDict match of len=%u", mlt);+                md.len = mlt;+                md.off = (int)(ipIndex - m8Index);+                md.back = 0;+                return md;+            }+        }+    }++    /* search for short match second */+    {   U32 l4DictMatchIndex = hash4Table[LZ4MID_hash4Ptr(ip)];+        U32 m4Index = l4DictMatchIndex + gDictEndIndex - (U32)lDictEndIndex;+        if (ipIndex - m4Index <= LZ4_DISTANCE_MAX) {+            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + l4DictMatchIndex;+            const size_t safeLen = MIN(lDictEndIndex - l4DictMatchIndex, (size_t)(iHighLimit - ip));+            int mlt = (int)LZ4_count(ip, matchPtr, ip + safeLen);+            if (mlt >= MINMATCH) {+                LZ4HC_match_t md;+                DEBUGLOG(7, "Found short ExtDict match of len=%u", mlt);+                md.len = mlt;+                md.off = (int)(ipIndex - m4Index);+                md.back = 0;+                return md;+            }+        }+    }++    /* nothing found */+    {   LZ4HC_match_t const md = {0, 0, 0 };+        return md;+    }+}++/**************************************+*  Mid Compression (level 2)+**************************************/++LZ4_FORCE_INLINE void+LZ4MID_addPosition(U32* hTable, U32 hValue, U32 index)+{+    hTable[hValue] = index;+}++#define ADDPOS8(_p, _idx) LZ4MID_addPosition(hash8Table, LZ4MID_hash8Ptr(_p), _idx)+#define ADDPOS4(_p, _idx) LZ4MID_addPosition(hash4Table, LZ4MID_hash4Ptr(_p), _idx)++/* Fill hash tables with references into dictionary.+ * The resulting table is only exploitable by LZ4MID (level 2) */+static void+LZ4MID_fillHTable (LZ4HC_CCtx_internal* cctx, const void* dict, size_t size)+{+    U32* const hash4Table = cctx->hashTable;+    U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;+    const BYTE* const prefixPtr = (const BYTE*)dict;+    U32 const prefixIdx = cctx->dictLimit;+    U32 const target = prefixIdx + (U32)size - LZ4MID_HASHSIZE;+    U32 idx = cctx->nextToUpdate;+    assert(dict == cctx->prefixStart);+    DEBUGLOG(4, "LZ4MID_fillHTable (size:%zu)", size);+    if (size <= LZ4MID_HASHSIZE)+        return;++    for (; idx < target; idx += 3) {+        ADDPOS4(prefixPtr+idx-prefixIdx, idx);+        ADDPOS8(prefixPtr+idx+1-prefixIdx, idx+1);+    }++    idx = (size > 32 KB + LZ4MID_HASHSIZE) ? target - 32 KB : cctx->nextToUpdate;+    for (; idx < target; idx += 1) {+        ADDPOS8(prefixPtr+idx-prefixIdx, idx);+    }++    cctx->nextToUpdate = target;+}++static LZ4MID_searchIntoDict_f select_searchDict_function(const LZ4HC_CCtx_internal* dictCtx)+{+    if (dictCtx == NULL) return NULL;+    if (LZ4HC_getCLevelParams(dictCtx->compressionLevel).strat == lz4mid)+        return LZ4MID_searchExtDict;+    return LZ4MID_searchHCDict;+}++static int LZ4MID_compress (+    LZ4HC_CCtx_internal* const ctx,+    const char* const src,+    char* const dst,+    int* srcSizePtr,+    int const maxOutputSize,+    const limitedOutput_directive limit,+    const dictCtx_directive dict+    )+{+    U32* const hash4Table = ctx->hashTable;+    U32* const hash8Table = hash4Table + LZ4MID_HASHTABLESIZE;+    const BYTE* ip = (const BYTE*)src;+    const BYTE* anchor = ip;+    const BYTE* const iend = ip + *srcSizePtr;+    const BYTE* const mflimit = iend - MFLIMIT;+    const BYTE* const matchlimit = (iend - LASTLITERALS);+    const BYTE* const ilimit = (iend - LZ4MID_HASHSIZE);+    BYTE* op = (BYTE*)dst;+    BYTE* oend = op + maxOutputSize;++    const BYTE* const prefixPtr = ctx->prefixStart;+    const U32 prefixIdx = ctx->dictLimit;+    const U32 ilimitIdx = (U32)(ilimit - prefixPtr) + prefixIdx;+    const BYTE* const dictStart = ctx->dictStart;+    const U32 dictIdx = ctx->lowLimit;+    const U32 gDictEndIndex = ctx->lowLimit;+    const LZ4MID_searchIntoDict_f searchIntoDict = (dict == usingDictCtxHc) ? select_searchDict_function(ctx->dictCtx) : NULL;+    unsigned matchLength;+    unsigned matchDistance;++    /* input sanitization */+    DEBUGLOG(5, "LZ4MID_compress (%i bytes)", *srcSizePtr);+    if (dict == usingDictCtxHc) DEBUGLOG(5, "usingDictCtxHc");+    assert(*srcSizePtr >= 0);+    if (*srcSizePtr) assert(src != NULL);+    if (maxOutputSize) assert(dst != NULL);+    if (*srcSizePtr < 0) return 0;  /* invalid */+    if (maxOutputSize < 0) return 0; /* invalid */+    if (*srcSizePtr > LZ4_MAX_INPUT_SIZE) {+        /* forbidden: no input is allowed to be that large */+        return 0;+    }+    if (limit == fillOutput) oend -= LASTLITERALS;  /* Hack for support LZ4 format restriction */+    if (*srcSizePtr < LZ4_minLength)+        goto _lz4mid_last_literals;  /* Input too small, no compression (all literals) */++    /* main loop */+    while (ip <= mflimit) {+        const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;+        /* search long match */+        {   U32 const h8 = LZ4MID_hash8Ptr(ip);+            U32 const pos8 = hash8Table[h8];+            assert(h8 < LZ4MID_HASHTABLESIZE);+            assert(pos8 < ipIndex);+            LZ4MID_addPosition(hash8Table, h8, ipIndex);+            if (ipIndex - pos8 <= LZ4_DISTANCE_MAX) {+                /* match candidate found */+                if (pos8 >= prefixIdx) {+                    const BYTE* const matchPtr = prefixPtr + pos8 - prefixIdx;+                    assert(matchPtr < ip);+                    matchLength = LZ4_count(ip, matchPtr, matchlimit);+                    if (matchLength >= MINMATCH) {+                        DEBUGLOG(7, "found long match at pos %u (len=%u)", pos8, matchLength);+                        matchDistance = ipIndex - pos8;+                        goto _lz4mid_encode_sequence;+                    }+                } else {+                    if (pos8 >= dictIdx) {+                        /* extDict match candidate */+                        const BYTE* const matchPtr = dictStart + (pos8 - dictIdx);+                        const size_t safeLen = MIN(prefixIdx - pos8, (size_t)(matchlimit - ip));+                        matchLength = LZ4_count(ip, matchPtr, ip + safeLen);+                        if (matchLength >= MINMATCH) {+                            DEBUGLOG(7, "found long match at ExtDict pos %u (len=%u)", pos8, matchLength);+                            matchDistance = ipIndex - pos8;+                            goto _lz4mid_encode_sequence;+                        }+                    }+                }+        }   }+        /* search short match */+        {   U32 const h4 = LZ4MID_hash4Ptr(ip);+            U32 const pos4 = hash4Table[h4];+            assert(h4 < LZ4MID_HASHTABLESIZE);+            assert(pos4 < ipIndex);+            LZ4MID_addPosition(hash4Table, h4, ipIndex);+            if (ipIndex - pos4 <= LZ4_DISTANCE_MAX) {+                /* match candidate found */+                if (pos4 >= prefixIdx) {+                /* only search within prefix */+                    const BYTE* const matchPtr = prefixPtr + (pos4 - prefixIdx);+                    assert(matchPtr < ip);+                    assert(matchPtr >= prefixPtr);+                    matchLength = LZ4_count(ip, matchPtr, matchlimit);+                    if (matchLength >= MINMATCH) {+                        /* short match found, let's just check ip+1 for longer */+                        U32 const h8 = LZ4MID_hash8Ptr(ip+1);+                        U32 const pos8 = hash8Table[h8];+                        U32 const m2Distance = ipIndex + 1 - pos8;+                        matchDistance = ipIndex - pos4;+                        if ( m2Distance <= LZ4_DISTANCE_MAX+                        && pos8 >= prefixIdx /* only search within prefix */+                        && likely(ip < mflimit)+                        ) {+                            const BYTE* const m2Ptr = prefixPtr + (pos8 - prefixIdx);+                            unsigned ml2 = LZ4_count(ip+1, m2Ptr, matchlimit);+                            if (ml2 > matchLength) {+                                LZ4MID_addPosition(hash8Table, h8, ipIndex+1);+                                ip++;+                                matchLength = ml2;+                                matchDistance = m2Distance;+                        }   }+                        goto _lz4mid_encode_sequence;+                    }+                } else {+                    if (pos4 >= dictIdx) {+                        /* extDict match candidate */+                        const BYTE* const matchPtr = dictStart + (pos4 - dictIdx);+                        const size_t safeLen = MIN(prefixIdx - pos4, (size_t)(matchlimit - ip));+                        matchLength = LZ4_count(ip, matchPtr, ip + safeLen);+                        if (matchLength >= MINMATCH) {+                            DEBUGLOG(7, "found match at ExtDict pos %u (len=%u)", pos4, matchLength);+                            matchDistance = ipIndex - pos4;+                            goto _lz4mid_encode_sequence;+                        }+                    }+                }+        }   }+        /* no match found in prefix */+        if ( (dict == usingDictCtxHc)+          && (ipIndex - gDictEndIndex < LZ4_DISTANCE_MAX - 8) ) {+            /* search a match into external dictionary */+            LZ4HC_match_t dMatch = searchIntoDict(ip, ipIndex,+                    matchlimit,+                    ctx->dictCtx, gDictEndIndex);+            if (dMatch.len >= MINMATCH) {+                DEBUGLOG(7, "found Dictionary match (offset=%i)", dMatch.off);+                assert(dMatch.back == 0);+                matchLength = (unsigned)dMatch.len;+                matchDistance = (unsigned)dMatch.off;+                goto _lz4mid_encode_sequence;+            }+        }+        /* no match found */+        ip += 1 + ((ip-anchor) >> 9);  /* skip faster over incompressible data */+        continue;++_lz4mid_encode_sequence:+        /* catch back */+        while (((ip > anchor) & ((U32)(ip-prefixPtr) > matchDistance)) && (unlikely(ip[-1] == ip[-(int)matchDistance-1]))) {+            ip--;  matchLength++;+        };++        /* fill table with beginning of match */+        ADDPOS8(ip+1, ipIndex+1);+        ADDPOS8(ip+2, ipIndex+2);+        ADDPOS4(ip+1, ipIndex+1);++        /* encode */+        {   BYTE* const saved_op = op;+            /* LZ4HC_encodeSequence always updates @op; on success, it updates @ip and @anchor */+            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),+                    (int)matchLength, (int)matchDistance,+                    limit, oend) ) {+                op = saved_op;  /* restore @op value before failed LZ4HC_encodeSequence */+                goto _lz4mid_dest_overflow;+            }+        }++        /* fill table with end of match */+        {   U32 endMatchIdx = (U32)(ip-prefixPtr) + prefixIdx;+            U32 pos_m2 = endMatchIdx - 2;+            if (pos_m2 < ilimitIdx) {+                if (likely(ip - prefixPtr > 5)) {+                    ADDPOS8(ip-5, endMatchIdx - 5);+                }+                ADDPOS8(ip-3, endMatchIdx - 3);+                ADDPOS8(ip-2, endMatchIdx - 2);+                ADDPOS4(ip-2, endMatchIdx - 2);+                ADDPOS4(ip-1, endMatchIdx - 1);+            }+        }+    }++_lz4mid_last_literals:+    /* Encode Last Literals */+    {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */+        size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;+        size_t const totalSize = 1 + llAdd + lastRunSize;+        if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */+        if (limit && (op + totalSize > oend)) {+            if (limit == limitedOutput) return 0;  /* not enough space in @dst */+            /* adapt lastRunSize to fill 'dest' */+            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;+            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;+            lastRunSize -= llAdd;+        }+        DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);+        ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */++        if (lastRunSize >= RUN_MASK) {+            size_t accumulator = lastRunSize - RUN_MASK;+            *op++ = (RUN_MASK << ML_BITS);+            for(; accumulator >= 255 ; accumulator -= 255)+                *op++ = 255;+            *op++ = (BYTE) accumulator;+        } else {+            *op++ = (BYTE)(lastRunSize << ML_BITS);+        }+        assert(lastRunSize <= (size_t)(oend - op));+        LZ4_memcpy(op, anchor, lastRunSize);+        op += lastRunSize;+    }++    /* End */+    DEBUGLOG(5, "compressed %i bytes into %i bytes", *srcSizePtr, (int)((char*)op - dst));+    assert(ip >= (const BYTE*)src);+    assert(ip <= iend);+    *srcSizePtr = (int)(ip - (const BYTE*)src);+    assert((char*)op >= dst);+    assert(op <= oend);+    assert((char*)op - dst < INT_MAX);+    return (int)((char*)op - dst);++_lz4mid_dest_overflow:+    if (limit == fillOutput) {+        /* Assumption : @ip, @anchor, @optr and @matchLength must be set correctly */+        size_t const ll = (size_t)(ip - anchor);+        size_t const ll_addbytes = (ll + 240) / 255;+        size_t const ll_totalCost = 1 + ll_addbytes + ll;+        BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */+        DEBUGLOG(6, "Last sequence is overflowing : %u literals, %u remaining space",+                (unsigned)ll, (unsigned)(oend-op));+        if (op + ll_totalCost <= maxLitPos) {+            /* ll validated; now adjust match length */+            size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));+            size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);+            assert(maxMlSize < INT_MAX);+            if ((size_t)matchLength > maxMlSize) matchLength= (unsigned)maxMlSize;+            if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + matchLength >= MFLIMIT) {+            DEBUGLOG(6, "Let's encode a last sequence (ll=%u, ml=%u)", (unsigned)ll, matchLength);+                LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),+                        (int)matchLength, (int)matchDistance,+                        notLimited, oend);+        }   }+        DEBUGLOG(6, "Let's finish with a run of literals (%u bytes left)", (unsigned)(oend-op));+        goto _lz4mid_last_literals;+    }+    /* compression failed */+    return 0;+}+++/**************************************+*  HC Compression - Search+**************************************/++/* Update chains up to ip (excluded) */+LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)+{+    U16* const chainTable = hc4->chainTable;+    U32* const hashTable  = hc4->hashTable;+    const BYTE* const prefixPtr = hc4->prefixStart;+    U32 const prefixIdx = hc4->dictLimit;+    U32 const target = (U32)(ip - prefixPtr) + prefixIdx;+    U32 idx = hc4->nextToUpdate;+    assert(ip >= prefixPtr);+    assert(target >= prefixIdx);++    while (idx < target) {+        U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx);+        size_t delta = idx - hashTable[h];+        if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;+        DELTANEXTU16(chainTable, idx) = (U16)delta;+        hashTable[h] = idx;+        idx++;+    }++    hc4->nextToUpdate = target;+}++#if defined(_MSC_VER)+#  define LZ4HC_rotl32(x,r) _rotl(x,r)+#else+#  define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r)))+#endif+++static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern)+{+    size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;+    if (bitsToRotate == 0) return pattern;+    return LZ4HC_rotl32(pattern, (int)bitsToRotate);+}++/* LZ4HC_countPattern() :+ * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */+static unsigned+LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)+{+    const BYTE* const iStart = ip;+    reg_t const pattern = (sizeof(pattern)==8) ?+        (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32;++    while (likely(ip < iEnd-(sizeof(pattern)-1))) {+        reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;+        if (!diff) { ip+=sizeof(pattern); continue; }+        ip += LZ4_NbCommonBytes(diff);+        return (unsigned)(ip - iStart);+    }++    if (LZ4_isLittleEndian()) {+        reg_t patternByte = pattern;+        while ((ip<iEnd) && (*ip == (BYTE)patternByte)) {+            ip++; patternByte >>= 8;+        }+    } else {  /* big endian */+        U32 bitOffset = (sizeof(pattern)*8) - 8;+        while (ip < iEnd) {+            BYTE const byte = (BYTE)(pattern >> bitOffset);+            if (*ip != byte) break;+            ip ++; bitOffset -= 8;+    }   }++    return (unsigned)(ip - iStart);+}++/* LZ4HC_reverseCountPattern() :+ * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)+ * read using natural platform endianness */+static unsigned+LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)+{+    const BYTE* const iStart = ip;++    while (likely(ip >= iLow+4)) {+        if (LZ4_read32(ip-4) != pattern) break;+        ip -= 4;+    }+    {   const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */+        while (likely(ip>iLow)) {+            if (ip[-1] != *bytePtr) break;+            ip--; bytePtr--;+    }   }+    return (unsigned)(iStart - ip);+}++/* LZ4HC_protectDictEnd() :+ * Checks if the match is in the last 3 bytes of the dictionary, so reading the+ * 4 byte MINMATCH would overflow.+ * @returns true if the match index is okay.+ */+static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)+{+    return ((U32)((dictLimit - 1) - matchIndex) >= 3);+}++typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;+typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;+++LZ4_FORCE_INLINE LZ4HC_match_t+LZ4HC_InsertAndGetWiderMatch (+        LZ4HC_CCtx_internal* const hc4,+        const BYTE* const ip,+        const BYTE* const iLowLimit, const BYTE* const iHighLimit,+        int longest,+        const int maxNbAttempts,+        const int patternAnalysis, const int chainSwap,+        const dictCtx_directive dict,+        const HCfavor_e favorDecSpeed)+{+    U16* const chainTable = hc4->chainTable;+    U32* const hashTable = hc4->hashTable;+    const LZ4HC_CCtx_internal* const dictCtx = hc4->dictCtx;+    const BYTE* const prefixPtr = hc4->prefixStart;+    const U32 prefixIdx = hc4->dictLimit;+    const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;+    const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex);+    const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;+    const BYTE* const dictStart = hc4->dictStart;+    const U32 dictIdx = hc4->lowLimit;+    const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx;+    int const lookBackLength = (int)(ip-iLowLimit);+    int nbAttempts = maxNbAttempts;+    U32 matchChainPos = 0;+    U32 const pattern = LZ4_read32(ip);+    U32 matchIndex;+    repeat_state_e repeat = rep_untested;+    size_t srcPatternLength = 0;+    int offset = 0, sBack = 0;++    DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");+    /* First Match */+    LZ4HC_Insert(hc4, ip);  /* insert all prior positions up to ip (excluded) */+    matchIndex = hashTable[LZ4HC_hashPtr(ip)];+    DEBUGLOG(7, "First candidate match for pos %u found at index %u / %u (lowestMatchIndex)",+                ipIndex, matchIndex, lowestMatchIndex);++    while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {+        int matchLength=0;+        nbAttempts--;+        assert(matchIndex < ipIndex);+        if (favorDecSpeed && (ipIndex - matchIndex < 8)) {+            /* do nothing:+             * favorDecSpeed intentionally skips matches with offset < 8 */+        } else if (matchIndex >= prefixIdx) {   /* within current Prefix */+            const BYTE* const matchPtr = prefixPtr + (matchIndex - prefixIdx);+            assert(matchPtr < ip);+            assert(longest >= 1);+            if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {+                if (LZ4_read32(matchPtr) == pattern) {+                    int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;+                    matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);+                    matchLength -= back;+                    if (matchLength > longest) {+                        longest = matchLength;+                        offset = (int)(ipIndex - matchIndex);+                        sBack = back;+                        DEBUGLOG(7, "Found match of len=%i within prefix, offset=%i, back=%i", longest, offset, -back);+            }   }   }+        } else {   /* lowestMatchIndex <= matchIndex < dictLimit : within Ext Dict */+            const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);+            assert(matchIndex >= dictIdx);+            if ( likely(matchIndex <= prefixIdx - 4)+              && (LZ4_read32(matchPtr) == pattern) ) {+                int back = 0;+                const BYTE* vLimit = ip + (prefixIdx - matchIndex);+                if (vLimit > iHighLimit) vLimit = iHighLimit;+                matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;+                if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))+                    matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);+                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;+                matchLength -= back;+                if (matchLength > longest) {+                    longest = matchLength;+                    offset = (int)(ipIndex - matchIndex);+                    sBack = back;+                    DEBUGLOG(7, "Found match of len=%i within dict, offset=%i, back=%i", longest, offset, -back);+        }   }   }++        if (chainSwap && matchLength==longest) {   /* better match => select a better chain */+            assert(lookBackLength==0);   /* search forward only */+            if (matchIndex + (U32)longest <= ipIndex) {+                int const kTrigger = 4;+                U32 distanceToNextMatch = 1;+                int const end = longest - MINMATCH + 1;+                int step = 1;+                int accel = 1 << kTrigger;+                int pos;+                for (pos = 0; pos < end; pos += step) {+                    U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);+                    step = (accel++ >> kTrigger);+                    if (candidateDist > distanceToNextMatch) {+                        distanceToNextMatch = candidateDist;+                        matchChainPos = (U32)pos;+                        accel = 1 << kTrigger;+                }   }+                if (distanceToNextMatch > 1) {+                    if (distanceToNextMatch > matchIndex) break;   /* avoid overflow */+                    matchIndex -= distanceToNextMatch;+                    continue;+        }   }   }++        {   U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);+            if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {+                U32 const matchCandidateIdx = matchIndex-1;+                /* may be a repeated pattern */+                if (repeat == rep_untested) {+                    if ( ((pattern & 0xFFFF) == (pattern >> 16))+                      &  ((pattern & 0xFF)   == (pattern >> 24)) ) {+                        DEBUGLOG(7, "Repeat pattern detected, char %02X", pattern >> 24);+                        repeat = rep_confirmed;+                        srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);+                    } else {+                        repeat = rep_not;+                }   }+                if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)+                  && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) {+                    const int extDict = matchCandidateIdx < prefixIdx;+                    const BYTE* const matchPtr = extDict ? dictStart + (matchCandidateIdx - dictIdx) : prefixPtr + (matchCandidateIdx - prefixIdx);+                    if (LZ4_read32(matchPtr) == pattern) {  /* good candidate */+                        const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;+                        size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);+                        if (extDict && matchPtr + forwardPatternLength == iLimit) {+                            U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);+                            forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);+                        }+                        {   const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;+                            size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);+                            size_t currentSegmentLength;+                            if (!extDict+                              && matchPtr - backLength == prefixPtr+                              && dictIdx < prefixIdx) {+                                U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);+                                backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);+                            }+                            /* Limit backLength not go further than lowestMatchIndex */+                            backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);+                            assert(matchCandidateIdx - backLength >= lowestMatchIndex);+                            currentSegmentLength = backLength + forwardPatternLength;+                            /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */+                            if ( (currentSegmentLength >= srcPatternLength)   /* current pattern segment large enough to contain full srcPatternLength */+                              && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */+                                U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength;  /* best position, full pattern, might be followed by more match */+                                if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))+                                    matchIndex = newMatchIndex;+                                else {+                                    /* Can only happen if started in the prefix */+                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);+                                    matchIndex = prefixIdx;+                                }+                            } else {+                                U32 const newMatchIndex = matchCandidateIdx - (U32)backLength;   /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */+                                if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {+                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);+                                    matchIndex = prefixIdx;+                                } else {+                                    matchIndex = newMatchIndex;+                                    if (lookBackLength==0) {  /* no back possible */+                                        size_t const maxML = MIN(currentSegmentLength, srcPatternLength);+                                        if ((size_t)longest < maxML) {+                                            assert(prefixPtr - prefixIdx + matchIndex != ip);+                                            if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;+                                            assert(maxML < 2 GB);+                                            longest = (int)maxML;+                                            offset = (int)(ipIndex - matchIndex);+                                            assert(sBack == 0);+                                            DEBUGLOG(7, "Found repeat pattern match of len=%i, offset=%i", longest, offset);+                                        }+                                        {   U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);+                                            if (distToNextPattern > matchIndex) break;  /* avoid overflow */+                                            matchIndex -= distToNextPattern;+                        }   }   }   }   }+                        continue;+                }   }+        }   }   /* PA optimization */++        /* follow current chain */+        matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);++    }  /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */++    if ( dict == usingDictCtxHc+      && nbAttempts > 0+      && withinStartDistance) {+        size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;+        U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];+        assert(dictEndOffset <= 1 GB);+        matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;+        if (dictMatchIndex>0) DEBUGLOG(7, "dictEndOffset = %zu, dictMatchIndex = %u => relative matchIndex = %i", dictEndOffset, dictMatchIndex, (int)dictMatchIndex - (int)dictEndOffset);+        while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {+            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;++            if (LZ4_read32(matchPtr) == pattern) {+                int mlt;+                int back = 0;+                const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);+                if (vLimit > iHighLimit) vLimit = iHighLimit;+                mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;+                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;+                mlt -= back;+                if (mlt > longest) {+                    longest = mlt;+                    offset = (int)(ipIndex - matchIndex);+                    sBack = back;+                    DEBUGLOG(7, "found match of length %i within extDictCtx", longest);+            }   }++            {   U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);+                dictMatchIndex -= nextOffset;+                matchIndex -= nextOffset;+    }   }   }++    {   LZ4HC_match_t md;+        assert(longest >= 0);+        md.len = longest;+        md.off = offset;+        md.back = sBack;+        return md;+    }+}++LZ4_FORCE_INLINE LZ4HC_match_t+LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4,   /* Index table will be updated */+                       const BYTE* const ip, const BYTE* const iLimit,+                       const int maxNbAttempts,+                       const int patternAnalysis,+                       const dictCtx_directive dict)+{+    DEBUGLOG(7, "LZ4HC_InsertAndFindBestMatch");+    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),+     * but this won't be the case here, as we define iLowLimit==ip,+     * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */+    return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);+}+++LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (+    LZ4HC_CCtx_internal* const ctx,+    const char* const source,+    char* const dest,+    int* srcSizePtr,+    int const maxOutputSize,+    int maxNbAttempts,+    const limitedOutput_directive limit,+    const dictCtx_directive dict+    )+{+    const int inputSize = *srcSizePtr;+    const int patternAnalysis = (maxNbAttempts > 128);   /* levels 9+ */++    const BYTE* ip = (const BYTE*) source;+    const BYTE* anchor = ip;+    const BYTE* const iend = ip + inputSize;+    const BYTE* const mflimit = iend - MFLIMIT;+    const BYTE* const matchlimit = (iend - LASTLITERALS);++    BYTE* optr = (BYTE*) dest;+    BYTE* op = (BYTE*) dest;+    BYTE* oend = op + maxOutputSize;++    const BYTE* start0;+    const BYTE* start2 = NULL;+    const BYTE* start3 = NULL;+    LZ4HC_match_t m0, m1, m2, m3;+    const LZ4HC_match_t nomatch = {0, 0, 0};++    /* init */+    DEBUGLOG(5, "LZ4HC_compress_hashChain (dict?=>%i)", dict);+    *srcSizePtr = 0;+    if (limit == fillOutput) oend -= LASTLITERALS;                  /* Hack for support LZ4 format restriction */+    if (inputSize < LZ4_minLength) goto _last_literals;             /* Input too small, no compression (all literals) */++    /* Main Loop */+    while (ip <= mflimit) {+        m1 = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, maxNbAttempts, patternAnalysis, dict);+        if (m1.len<MINMATCH) { ip++; continue; }++        /* saved, in case we would skip too much */+        start0 = ip; m0 = m1;++_Search2:+        DEBUGLOG(7, "_Search2 (currently found match of size %i)", m1.len);+        if (ip+m1.len <= mflimit) {+            start2 = ip + m1.len - 2;+            m2 = LZ4HC_InsertAndGetWiderMatch(ctx,+                            start2, ip + 0, matchlimit, m1.len,+                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);+            start2 += m2.back;+        } else {+            m2 = nomatch;  /* do not search further */+        }++        if (m2.len <= m1.len) { /* No better match => encode ML1 immediately */+            optr = op;+            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),+                    m1.len, m1.off,+                    limit, oend) )+                goto _dest_overflow;+            continue;+        }++        if (start0 < ip) {   /* first match was skipped at least once */+            if (start2 < ip + m0.len) {  /* squeezing ML1 between ML0(original ML1) and ML2 */+                ip = start0; m1 = m0;  /* restore initial Match1 */+        }   }++        /* Here, start0==ip */+        if ((start2 - ip) < 3) {  /* First Match too small : removed */+            ip = start2;+            m1 = m2;+            goto _Search2;+        }++_Search3:+        if ((start2 - ip) < OPTIMAL_ML) {+            int correction;+            int new_ml = m1.len;+            if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;+            if (ip+new_ml > start2 + m2.len - MINMATCH)+                new_ml = (int)(start2 - ip) + m2.len - MINMATCH;+            correction = new_ml - (int)(start2 - ip);+            if (correction > 0) {+                start2 += correction;+                m2.len -= correction;+            }+        }++        if (start2 + m2.len <= mflimit) {+            start3 = start2 + m2.len - 3;+            m3 = LZ4HC_InsertAndGetWiderMatch(ctx,+                            start3, start2, matchlimit, m2.len,+                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);+            start3 += m3.back;+        } else {+            m3 = nomatch;  /* do not search further */+        }++        if (m3.len <= m2.len) {  /* No better match => encode ML1 and ML2 */+            /* ip & ref are known; Now for ml */+            if (start2 < ip+m1.len) m1.len = (int)(start2 - ip);+            /* Now, encode 2 sequences */+            optr = op;+            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),+                    m1.len, m1.off,+                    limit, oend) )+                goto _dest_overflow;+            ip = start2;+            optr = op;+            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),+                    m2.len, m2.off,+                    limit, oend) ) {+                m1 = m2;+                goto _dest_overflow;+            }+            continue;+        }++        if (start3 < ip+m1.len+3) {  /* Not enough space for match 2 : remove it */+            if (start3 >= (ip+m1.len)) {  /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */+                if (start2 < ip+m1.len) {+                    int correction = (int)(ip+m1.len - start2);+                    start2 += correction;+                    m2.len -= correction;+                    if (m2.len < MINMATCH) {+                        start2 = start3;+                        m2 = m3;+                    }+                }++                optr = op;+                if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),+                        m1.len, m1.off,+                        limit, oend) )+                    goto _dest_overflow;+                ip  = start3;+                m1 = m3;++                start0 = start2;+                m0 = m2;+                goto _Search2;+            }++            start2 = start3;+            m2 = m3;+            goto _Search3;+        }++        /*+        * OK, now we have 3 ascending matches;+        * let's write the first one ML1.+        * ip & ref are known; Now decide ml.+        */+        if (start2 < ip+m1.len) {+            if ((start2 - ip) < OPTIMAL_ML) {+                int correction;+                if (m1.len > OPTIMAL_ML) m1.len = OPTIMAL_ML;+                if (ip + m1.len > start2 + m2.len - MINMATCH)+                    m1.len = (int)(start2 - ip) + m2.len - MINMATCH;+                correction = m1.len - (int)(start2 - ip);+                if (correction > 0) {+                    start2 += correction;+                    m2.len -= correction;+                }+            } else {+                m1.len = (int)(start2 - ip);+            }+        }+        optr = op;+        if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor),+                m1.len, m1.off,+                limit, oend) )+            goto _dest_overflow;++        /* ML2 becomes ML1 */+        ip = start2; m1 = m2;++        /* ML3 becomes ML2 */+        start2 = start3; m2 = m3;++        /* let's find a new ML3 */+        goto _Search3;+    }++_last_literals:+    /* Encode Last Literals */+    {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */+        size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;+        size_t const totalSize = 1 + llAdd + lastRunSize;+        if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */+        if (limit && (op + totalSize > oend)) {+            if (limit == limitedOutput) return 0;+            /* adapt lastRunSize to fill 'dest' */+            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;+            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;+            lastRunSize -= llAdd;+        }+        DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);+        ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */++        if (lastRunSize >= RUN_MASK) {+            size_t accumulator = lastRunSize - RUN_MASK;+            *op++ = (RUN_MASK << ML_BITS);+            for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;+            *op++ = (BYTE) accumulator;+        } else {+            *op++ = (BYTE)(lastRunSize << ML_BITS);+        }+        LZ4_memcpy(op, anchor, lastRunSize);+        op += lastRunSize;+    }++    /* End */+    *srcSizePtr = (int) (((const char*)ip) - source);+    return (int) (((char*)op)-dest);++_dest_overflow:+    if (limit == fillOutput) {+        /* Assumption : @ip, @anchor, @optr and @m1 must be set correctly */+        size_t const ll = (size_t)(ip - anchor);+        size_t const ll_addbytes = (ll + 240) / 255;+        size_t const ll_totalCost = 1 + ll_addbytes + ll;+        BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */+        DEBUGLOG(6, "Last sequence overflowing");+        op = optr;  /* restore correct out pointer */+        if (op + ll_totalCost <= maxLitPos) {+            /* ll validated; now adjust match length */+            size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));+            size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);+            assert(maxMlSize < INT_MAX); assert(m1.len >= 0);+            if ((size_t)m1.len > maxMlSize) m1.len = (int)maxMlSize;+            if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + m1.len >= MFLIMIT) {+                LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, notLimited, oend);+        }   }+        goto _last_literals;+    }+    /* compression failed */+    return 0;+}+++static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,+    const char* const source, char* dst,+    int* srcSizePtr, int dstCapacity,+    int const nbSearches, size_t sufficient_len,+    const limitedOutput_directive limit, int const fullUpdate,+    const dictCtx_directive dict,+    const HCfavor_e favorDecSpeed);++LZ4_FORCE_INLINE int+LZ4HC_compress_generic_internal (+            LZ4HC_CCtx_internal* const ctx,+            const char* const src,+            char* const dst,+            int* const srcSizePtr,+            int const dstCapacity,+            int cLevel,+            const limitedOutput_directive limit,+            const dictCtx_directive dict+            )+{+    DEBUGLOG(5, "LZ4HC_compress_generic_internal(src=%p, srcSize=%d)",+                src, *srcSizePtr);++    if (limit == fillOutput && dstCapacity < 1) return 0;   /* Impossible to store anything */+    if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;  /* Unsupported input size (too large or negative) */++    ctx->end += *srcSizePtr;+    {   cParams_t const cParam = LZ4HC_getCLevelParams(cLevel);+        HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;+        int result;++        if (cParam.strat == lz4mid) {+            result = LZ4MID_compress(ctx,+                                src, dst, srcSizePtr, dstCapacity,+                                limit, dict);+        } else if (cParam.strat == lz4hc) {+            result = LZ4HC_compress_hashChain(ctx,+                                src, dst, srcSizePtr, dstCapacity,+                                cParam.nbSearches, limit, dict);+        } else {+            assert(cParam.strat == lz4opt);+            result = LZ4HC_compress_optimal(ctx,+                                src, dst, srcSizePtr, dstCapacity,+                                cParam.nbSearches, cParam.targetLength, limit,+                                cLevel >= LZ4HC_CLEVEL_MAX,   /* ultra mode */+                                dict, favor);+        }+        if (result <= 0) ctx->dirty = 1;+        return result;+    }+}++static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock);++static int+LZ4HC_compress_generic_noDictCtx (+        LZ4HC_CCtx_internal* const ctx,+        const char* const src,+        char* const dst,+        int* const srcSizePtr,+        int const dstCapacity,+        int cLevel,+        limitedOutput_directive limit+        )+{+    assert(ctx->dictCtx == NULL);+    return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);+}++static int isStateCompatible(const LZ4HC_CCtx_internal* ctx1, const LZ4HC_CCtx_internal* ctx2)+{+    int const isMid1 = LZ4HC_getCLevelParams(ctx1->compressionLevel).strat == lz4mid;+    int const isMid2 = LZ4HC_getCLevelParams(ctx2->compressionLevel).strat == lz4mid;+    return !(isMid1 ^ isMid2);+}++static int+LZ4HC_compress_generic_dictCtx (+        LZ4HC_CCtx_internal* const ctx,+        const char* const src,+        char* const dst,+        int* const srcSizePtr,+        int const dstCapacity,+        int cLevel,+        limitedOutput_directive limit+        )+{+    const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit);+    assert(ctx->dictCtx != NULL);+    if (position >= 64 KB) {+        ctx->dictCtx = NULL;+        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);+    } else if (position == 0 && *srcSizePtr > 4 KB && isStateCompatible(ctx, ctx->dictCtx)) {+        LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));+        LZ4HC_setExternalDict(ctx, (const BYTE *)src);+        ctx->compressionLevel = (short)cLevel;+        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);+    } else {+        return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);+    }+}++static int+LZ4HC_compress_generic (+        LZ4HC_CCtx_internal* const ctx,+        const char* const src,+        char* const dst,+        int* const srcSizePtr,+        int const dstCapacity,+        int cLevel,+        limitedOutput_directive limit+        )+{+    if (ctx->dictCtx == NULL) {+        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);+    } else {+        return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);+    }+}+++int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }++static size_t LZ4_streamHC_t_alignment(void)+{+#if LZ4_ALIGN_TEST+    typedef struct { char c; LZ4_streamHC_t t; } t_a;+    return sizeof(t_a) - sizeof(LZ4_streamHC_t);+#else+    return 1;  /* effectively disabled */+#endif+}++/* state is presumed correctly initialized,+ * in which case its size and alignment have already been validate */+int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)+{+    LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;+    if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0;+    LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);+    LZ4HC_init_internal (ctx, (const BYTE*)src);+    if (dstCapacity < LZ4_compressBound(srcSize))+        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);+    else+        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);+}++int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)+{+    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));+    if (ctx==NULL) return 0;   /* init failure */+    return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);+}++int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)+{+    int cSize;+#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1+    LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));+    if (statePtr==NULL) return 0;+#else+    LZ4_streamHC_t state;+    LZ4_streamHC_t* const statePtr = &state;+#endif+    DEBUGLOG(5, "LZ4_compress_HC")+    cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);+#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1+    FREEMEM(statePtr);+#endif+    return cSize;+}++/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */+int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)+{+    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));+    if (ctx==NULL) return 0;   /* init failure */+    LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);+    LZ4_setCompressionLevel(ctx, cLevel);+    return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);+}++++/**************************************+*  Streaming Functions+**************************************/+/* allocation */+#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)+LZ4_streamHC_t* LZ4_createStreamHC(void)+{+    LZ4_streamHC_t* const state =+        (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t));+    if (state == NULL) return NULL;+    LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT);+    return state;+}++int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)+{+    DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);+    if (!LZ4_streamHCPtr) return 0;  /* support free on NULL */+    FREEMEM(LZ4_streamHCPtr);+    return 0;+}+#endif+++LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)+{+    LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;+    DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);+    /* check conditions */+    if (buffer == NULL) return NULL;+    if (size < sizeof(LZ4_streamHC_t)) return NULL;+    if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;+    /* init */+    { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);+      MEM_INIT(hcstate, 0, sizeof(*hcstate)); }+    LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);+    return LZ4_streamHCPtr;+}++/* just a stub */+void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)+{+    LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));+    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);+}++void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)+{+    LZ4HC_CCtx_internal* const s = &LZ4_streamHCPtr->internal_donotuse;+    DEBUGLOG(5, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);+    if (s->dirty) {+        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));+    } else {+        assert(s->end >= s->prefixStart);+        s->dictLimit += (U32)(s->end - s->prefixStart);+        s->prefixStart = NULL;+        s->end = NULL;+        s->dictCtx = NULL;+    }+    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);+}++void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)+{+    DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);+    if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;+    if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;+    LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;+}++void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)+{+    LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);+}++/* LZ4_loadDictHC() :+ * LZ4_streamHCPtr is presumed properly initialized */+int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,+              const char* dictionary, int dictSize)+{+    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;+    cParams_t cp;+    DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d, clevel=%d)", LZ4_streamHCPtr, dictionary, dictSize, ctxPtr->compressionLevel);+    assert(dictSize >= 0);+    assert(LZ4_streamHCPtr != NULL);+    if (dictSize > 64 KB) {+        dictionary += (size_t)dictSize - 64 KB;+        dictSize = 64 KB;+    }+    /* need a full initialization, there are bad side-effects when using resetFast() */+    {   int const cLevel = ctxPtr->compressionLevel;+        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));+        LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);+        cp = LZ4HC_getCLevelParams(cLevel);+    }+    LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);+    ctxPtr->end = (const BYTE*)dictionary + dictSize;+    if (cp.strat == lz4mid) {+        LZ4MID_fillHTable (ctxPtr, dictionary, (size_t)dictSize);+    } else {+        if (dictSize >= LZ4HC_HASHSIZE) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);+    }+    return dictSize;+}++void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {+    working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;+}++/* compression */++static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)+{+    DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);+    if ( (ctxPtr->end >= ctxPtr->prefixStart + 4)+      && (LZ4HC_getCLevelParams(ctxPtr->compressionLevel).strat != lz4mid) ) {+        LZ4HC_Insert (ctxPtr, ctxPtr->end-3);  /* Referencing remaining dictionary content */+    }++    /* Only one memory segment for extDict, so any previous extDict is lost at this stage */+    ctxPtr->lowLimit  = ctxPtr->dictLimit;+    ctxPtr->dictStart  = ctxPtr->prefixStart;+    ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);+    ctxPtr->prefixStart = newBlock;+    ctxPtr->end  = newBlock;+    ctxPtr->nextToUpdate = ctxPtr->dictLimit;   /* match referencing will resume from there */++    /* cannot reference an extDict and a dictCtx at the same time */+    ctxPtr->dictCtx = NULL;+}++static int+LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,+                                 const char* src, char* dst,+                                 int* srcSizePtr, int dstCapacity,+                                 limitedOutput_directive limit)+{+    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;+    DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",+                LZ4_streamHCPtr, src, *srcSizePtr, limit);+    assert(ctxPtr != NULL);+    /* auto-init if forgotten */+    if (ctxPtr->prefixStart == NULL)+        LZ4HC_init_internal (ctxPtr, (const BYTE*) src);++    /* Check overflow */+    if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) {+        size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart);+        if (dictSize > 64 KB) dictSize = 64 KB;+        LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);+    }++    /* Check if blocks follow each other */+    if ((const BYTE*)src != ctxPtr->end)+        LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);++    /* Check overlapping input/dictionary space */+    {   const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;+        const BYTE* const dictBegin = ctxPtr->dictStart;+        const BYTE* const dictEnd   = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit);+        if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {+            if (sourceEnd > dictEnd) sourceEnd = dictEnd;+            ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart);+            ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart);+            /* invalidate dictionary is it's too small */+            if (ctxPtr->dictLimit - ctxPtr->lowLimit < LZ4HC_HASHSIZE) {+                ctxPtr->lowLimit = ctxPtr->dictLimit;+                ctxPtr->dictStart = ctxPtr->prefixStart;+    }   }   }++    return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);+}++int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)+{+    DEBUGLOG(5, "LZ4_compress_HC_continue");+    if (dstCapacity < LZ4_compressBound(srcSize))+        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);+    else+        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);+}++int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)+{+    return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);+}+++/* LZ4_saveDictHC :+ * save history content+ * into a user-provided buffer+ * which is then used to continue compression+ */+int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)+{+    LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;+    int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);+    DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);+    assert(prefixSize >= 0);+    if (dictSize > 64 KB) dictSize = 64 KB;+    if (dictSize < 4) dictSize = 0;+    if (dictSize > prefixSize) dictSize = prefixSize;+    if (safeBuffer == NULL) assert(dictSize == 0);+    if (dictSize > 0)+        LZ4_memmove(safeBuffer, streamPtr->end - dictSize, (size_t)dictSize);+    {   U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit;+        streamPtr->end = (safeBuffer == NULL) ? NULL : (const BYTE*)safeBuffer + dictSize;+        streamPtr->prefixStart = (const BYTE*)safeBuffer;+        streamPtr->dictLimit = endIndex - (U32)dictSize;+        streamPtr->lowLimit = endIndex - (U32)dictSize;+        streamPtr->dictStart = streamPtr->prefixStart;+        if (streamPtr->nextToUpdate < streamPtr->dictLimit)+            streamPtr->nextToUpdate = streamPtr->dictLimit;+    }+    return dictSize;+}+++/* ================================================+ *  LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])+ * ===============================================*/+typedef struct {+    int price;+    int off;+    int mlen;+    int litlen;+} LZ4HC_optimal_t;++/* price in bytes */+LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)+{+    int price = litlen;+    assert(litlen >= 0);+    if (litlen >= (int)RUN_MASK)+        price += 1 + ((litlen-(int)RUN_MASK) / 255);+    return price;+}++/* requires mlen >= MINMATCH */+LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)+{+    int price = 1 + 2 ; /* token + 16-bit offset */+    assert(litlen >= 0);+    assert(mlen >= MINMATCH);++    price += LZ4HC_literalsPrice(litlen);++    if (mlen >= (int)(ML_MASK+MINMATCH))+        price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);++    return price;+}++LZ4_FORCE_INLINE LZ4HC_match_t+LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,+                      const BYTE* ip, const BYTE* const iHighLimit,+                      int minLen, int nbSearches,+                      const dictCtx_directive dict,+                      const HCfavor_e favorDecSpeed)+{+    LZ4HC_match_t const match0 = { 0 , 0, 0 };+    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),+     * but this won't be the case here, as we define iLowLimit==ip,+    ** so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */+    LZ4HC_match_t md = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);+    assert(md.back == 0);+    if (md.len <= minLen) return match0;+    if (favorDecSpeed) {+        if ((md.len>18) & (md.len<=36)) md.len=18;   /* favor dec.speed (shortcut) */+    }+    return md;+}+++static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,+                                    const char* const source,+                                    char* dst,+                                    int* srcSizePtr,+                                    int dstCapacity,+                                    int const nbSearches,+                                    size_t sufficient_len,+                                    const limitedOutput_directive limit,+                                    int const fullUpdate,+                                    const dictCtx_directive dict,+                                    const HCfavor_e favorDecSpeed)+{+    int retval = 0;+#define TRAILING_LITERALS 3+#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1+    LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));+#else+    LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS];   /* ~64 KB, which is a bit large for stack... */+#endif++    const BYTE* ip = (const BYTE*) source;+    const BYTE* anchor = ip;+    const BYTE* const iend = ip + *srcSizePtr;+    const BYTE* const mflimit = iend - MFLIMIT;+    const BYTE* const matchlimit = iend - LASTLITERALS;+    BYTE* op = (BYTE*) dst;+    BYTE* opSaved = (BYTE*) dst;+    BYTE* oend = op + dstCapacity;+    int ovml = MINMATCH;  /* overflow - last sequence */+    int ovoff = 0;++    /* init */+#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1+    if (opt == NULL) goto _return_label;+#endif+    DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);+    *srcSizePtr = 0;+    if (limit == fillOutput) oend -= LASTLITERALS;   /* Hack for support LZ4 format restriction */+    if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;++    /* Main Loop */+    while (ip <= mflimit) {+         int const llen = (int)(ip - anchor);+         int best_mlen, best_off;+         int cur, last_match_pos = 0;++         LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);+         if (firstMatch.len==0) { ip++; continue; }++         if ((size_t)firstMatch.len > sufficient_len) {+             /* good enough solution : immediate encoding */+             int const firstML = firstMatch.len;+             opSaved = op;+             if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, firstMatch.off, limit, oend) ) {  /* updates ip, op and anchor */+                 ovml = firstML;+                 ovoff = firstMatch.off;+                 goto _dest_overflow;+             }+             continue;+         }++         /* set prices for first positions (literals) */+         {   int rPos;+             for (rPos = 0 ; rPos < MINMATCH ; rPos++) {+                 int const cost = LZ4HC_literalsPrice(llen + rPos);+                 opt[rPos].mlen = 1;+                 opt[rPos].off = 0;+                 opt[rPos].litlen = llen + rPos;+                 opt[rPos].price = cost;+                 DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",+                             rPos, cost, opt[rPos].litlen);+         }   }+         /* set prices using initial match */+         {   int const matchML = firstMatch.len;   /* necessarily < sufficient_len < LZ4_OPT_NUM */+             int const offset = firstMatch.off;+             int mlen;+             assert(matchML < LZ4_OPT_NUM);+             for (mlen = MINMATCH ; mlen <= matchML ; mlen++) {+                 int const cost = LZ4HC_sequencePrice(llen, mlen);+                 opt[mlen].mlen = mlen;+                 opt[mlen].off = offset;+                 opt[mlen].litlen = llen;+                 opt[mlen].price = cost;+                 DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup",+                             mlen, cost, mlen);+         }   }+         last_match_pos = firstMatch.len;+         {   int addLit;+             for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {+                 opt[last_match_pos+addLit].mlen = 1; /* literal */+                 opt[last_match_pos+addLit].off = 0;+                 opt[last_match_pos+addLit].litlen = addLit;+                 opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);+                 DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",+                             last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);+         }   }++         /* check further positions */+         for (cur = 1; cur < last_match_pos; cur++) {+             const BYTE* const curPtr = ip + cur;+             LZ4HC_match_t newMatch;++             if (curPtr > mflimit) break;+             DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u",+                     cur, opt[cur].price, opt[cur+1].price, cur+1);+             if (fullUpdate) {+                 /* not useful to search here if next position has same (or lower) cost */+                 if ( (opt[cur+1].price <= opt[cur].price)+                   /* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */+                   && (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )+                     continue;+             } else {+                 /* not useful to search here if next position has same (or lower) cost */+                 if (opt[cur+1].price <= opt[cur].price) continue;+             }++             DEBUGLOG(7, "search at rPos:%u", cur);+             if (fullUpdate)+                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);+             else+                 /* only test matches of minimum length; slightly faster, but misses a few bytes */+                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);+             if (!newMatch.len) continue;++             if ( ((size_t)newMatch.len > sufficient_len)+               || (newMatch.len + cur >= LZ4_OPT_NUM) ) {+                 /* immediate encoding */+                 best_mlen = newMatch.len;+                 best_off = newMatch.off;+                 last_match_pos = cur + 1;+                 goto encode;+             }++             /* before match : set price with literals at beginning */+             {   int const baseLitlen = opt[cur].litlen;+                 int litlen;+                 for (litlen = 1; litlen < MINMATCH; litlen++) {+                     int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);+                     int const pos = cur + litlen;+                     if (price < opt[pos].price) {+                         opt[pos].mlen = 1; /* literal */+                         opt[pos].off = 0;+                         opt[pos].litlen = baseLitlen+litlen;+                         opt[pos].price = price;+                         DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)",+                                     pos, price, opt[pos].litlen);+             }   }   }++             /* set prices using match at position = cur */+             {   int const matchML = newMatch.len;+                 int ml = MINMATCH;++                 assert(cur + newMatch.len < LZ4_OPT_NUM);+                 for ( ; ml <= matchML ; ml++) {+                     int const pos = cur + ml;+                     int const offset = newMatch.off;+                     int price;+                     int ll;+                     DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)",+                                 pos, last_match_pos);+                     if (opt[cur].mlen == 1) {+                         ll = opt[cur].litlen;+                         price = ((cur > ll) ? opt[cur - ll].price : 0)+                               + LZ4HC_sequencePrice(ll, ml);+                     } else {+                         ll = 0;+                         price = opt[cur].price + LZ4HC_sequencePrice(0, ml);+                     }++                    assert((U32)favorDecSpeed <= 1);+                     if (pos > last_match_pos+TRAILING_LITERALS+                      || price <= opt[pos].price - (int)favorDecSpeed) {+                         DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)",+                                     pos, price, ml);+                         assert(pos < LZ4_OPT_NUM);+                         if ( (ml == matchML)  /* last pos of last match */+                           && (last_match_pos < pos) )+                             last_match_pos = pos;+                         opt[pos].mlen = ml;+                         opt[pos].off = offset;+                         opt[pos].litlen = ll;+                         opt[pos].price = price;+             }   }   }+             /* complete following positions with literals */+             {   int addLit;+                 for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {+                     opt[last_match_pos+addLit].mlen = 1; /* literal */+                     opt[last_match_pos+addLit].off = 0;+                     opt[last_match_pos+addLit].litlen = addLit;+                     opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);+                     DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);+             }   }+         }  /* for (cur = 1; cur <= last_match_pos; cur++) */++         assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);+         best_mlen = opt[last_match_pos].mlen;+         best_off = opt[last_match_pos].off;+         cur = last_match_pos - best_mlen;++encode: /* cur, last_match_pos, best_mlen, best_off must be set */+         assert(cur < LZ4_OPT_NUM);+         assert(last_match_pos >= 1);  /* == 1 when only one candidate */+         DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos);+         {   int candidate_pos = cur;+             int selected_matchLength = best_mlen;+             int selected_offset = best_off;+             while (1) {  /* from end to beginning */+                 int const next_matchLength = opt[candidate_pos].mlen;  /* can be 1, means literal */+                 int const next_offset = opt[candidate_pos].off;+                 DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength);+                 opt[candidate_pos].mlen = selected_matchLength;+                 opt[candidate_pos].off = selected_offset;+                 selected_matchLength = next_matchLength;+                 selected_offset = next_offset;+                 if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */+                 assert(next_matchLength > 0);  /* can be 1, means literal */+                 candidate_pos -= next_matchLength;+         }   }++         /* encode all recorded sequences in order */+         {   int rPos = 0;  /* relative position (to ip) */+             while (rPos < last_match_pos) {+                 int const ml = opt[rPos].mlen;+                 int const offset = opt[rPos].off;+                 if (ml == 1) { ip++; rPos++; continue; }  /* literal; note: can end up with several literals, in which case, skip them */+                 rPos += ml;+                 assert(ml >= MINMATCH);+                 assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));+                 opSaved = op;+                 if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, offset, limit, oend) ) {  /* updates ip, op and anchor */+                     ovml = ml;+                     ovoff = offset;+                     goto _dest_overflow;+         }   }   }+     }  /* while (ip <= mflimit) */++_last_literals:+     /* Encode Last Literals */+     {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */+         size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;+         size_t const totalSize = 1 + llAdd + lastRunSize;+         if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */+         if (limit && (op + totalSize > oend)) {+             if (limit == limitedOutput) { /* Check output limit */+                retval = 0;+                goto _return_label;+             }+             /* adapt lastRunSize to fill 'dst' */+             lastRunSize  = (size_t)(oend - op) - 1 /*token*/;+             llAdd = (lastRunSize + 256 - RUN_MASK) / 256;+             lastRunSize -= llAdd;+         }+         DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);+         ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */++         if (lastRunSize >= RUN_MASK) {+             size_t accumulator = lastRunSize - RUN_MASK;+             *op++ = (RUN_MASK << ML_BITS);+             for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;+             *op++ = (BYTE) accumulator;+         } else {+             *op++ = (BYTE)(lastRunSize << ML_BITS);+         }+         LZ4_memcpy(op, anchor, lastRunSize);+         op += lastRunSize;+     }++     /* End */+     *srcSizePtr = (int) (((const char*)ip) - source);+     retval = (int) ((char*)op-dst);+     goto _return_label;++_dest_overflow:+if (limit == fillOutput) {+     /* Assumption : ip, anchor, ovml and ovref must be set correctly */+     size_t const ll = (size_t)(ip - anchor);+     size_t const ll_addbytes = (ll + 240) / 255;+     size_t const ll_totalCost = 1 + ll_addbytes + ll;+     BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */+     DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend-1-opSaved));+     op = opSaved;  /* restore correct out pointer */+     if (op + ll_totalCost <= maxLitPos) {+         /* ll validated; now adjust match length */+         size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));+         size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);+         assert(maxMlSize < INT_MAX); assert(ovml >= 0);+         if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize;+         if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {+             DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);+             DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor);+             LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovoff, notLimited, oend);+             DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor);+     }   }+     goto _last_literals;+}+_return_label:+#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1+     if (opt) FREEMEM(opt);+#endif+     return retval;+}+++/***************************************************+*  Deprecated Functions+***************************************************/++/* These functions currently generate deprecation warnings */++/* Wrappers for deprecated compression functions */+int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }+int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }+int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }+int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }+int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }+int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }+int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }+int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }+int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }+int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }+++/* Deprecated streaming functions */+int LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); }++/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)+ * @return : 0 on success, !=0 if error */+int LZ4_resetStreamStateHC(void* state, char* inputBuffer)+{+    LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));+    if (hc4 == NULL) return 1;   /* init failed */+    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);+    return 0;+}++#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)+void* LZ4_createHC (const char* inputBuffer)+{+    LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();+    if (hc4 == NULL) return NULL;   /* not enough memory */+    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);+    return hc4;+}++int LZ4_freeHC (void* LZ4HC_Data)+{+    if (!LZ4HC_Data) return 0;  /* support free on NULL */+    FREEMEM(LZ4HC_Data);+    return 0;+}+#endif++int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)+{+    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);+}++int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)+{+    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);+}++char* LZ4_slideInputBufferHC(void* LZ4HC_Data)+{+    LZ4HC_CCtx_internal* const s = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse;+    const BYTE* const bufferStart = s->prefixStart - s->dictLimit + s->lowLimit;+    LZ4_resetStreamHC_fast((LZ4_streamHC_t*)LZ4HC_Data, s->compressionLevel);+    /* ugly conversion trick, required to evade (const char*) -> (char*) cast-qual warning :( */+    return (char*)(uptrval)bufferStart; }
cbits/lz4hc.h view
@@ -44,7 +44,7 @@   /* --- Useful constants --- */-#define LZ4HC_CLEVEL_MIN         3+#define LZ4HC_CLEVEL_MIN         2 #define LZ4HC_CLEVEL_DEFAULT     9 #define LZ4HC_CLEVEL_OPT_MIN    10 #define LZ4HC_CLEVEL_MAX        12@@ -126,6 +126,8 @@    After reset, a first "fictional block" can be designated as initial dictionary,   using LZ4_loadDictHC() (Optional).+  Note: In order for LZ4_loadDictHC() to create the correct data structure,+  it is essential to set the compression level _before_ loading the dictionary.    Invoke LZ4_compress_HC_continue() to compress each successive block.   The number of blocks is unlimited.@@ -135,12 +137,12 @@   It's allowed to update compression level anytime between blocks,   using LZ4_setCompressionLevel() (experimental). -  'dst' buffer should be sized to handle worst case scenarios+ @dst buffer should be sized to handle worst case scenarios   (see LZ4_compressBound(), it ensures compression success).   In case of failure, the API does not guarantee recovery,   so the state _must_ be reset.   To ensure compression success-  whenever `dst` buffer size cannot be made >= LZ4_compressBound(),+  whenever @dst buffer size cannot be made >= LZ4_compressBound(),   consider using LZ4_compress_HC_continue_destSize().    Whenever previous input blocks can't be preserved unmodified in-place during compression of next blocks,@@ -176,7 +178,35 @@ LZ4LIB_API int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSize);  +/*! LZ4_attach_HC_dictionary() : stable since v1.10.0+ *  This API allows for the efficient re-use of a static dictionary many times.+ *+ *  Rather than re-loading the dictionary buffer into a working context before+ *  each compression, or copying a pre-loaded dictionary's LZ4_streamHC_t into a+ *  working LZ4_streamHC_t, this function introduces a no-copy setup mechanism,+ *  in which the working stream references the dictionary stream in-place.+ *+ *  Several assumptions are made about the state of the dictionary stream.+ *  Currently, only streams which have been prepared by LZ4_loadDictHC() should+ *  be expected to work.+ *+ *  Alternatively, the provided dictionary stream pointer may be NULL, in which+ *  case any existing dictionary stream is unset.+ *+ *  A dictionary should only be attached to a stream without any history (i.e.,+ *  a stream that has just been reset).+ *+ *  The dictionary will remain attached to the working stream only for the+ *  current stream session. Calls to LZ4_resetStreamHC(_fast) will remove the+ *  dictionary context association from the working stream. The dictionary+ *  stream (and source buffer) must remain in-place / accessible / unchanged+ *  through the lifetime of the stream session.+ */+LZ4LIB_API void+LZ4_attach_HC_dictionary(LZ4_streamHC_t* working_stream,+                   const LZ4_streamHC_t* dictionary_stream); + /*^**********************************************  * !!!!!!   STATIC LINKING ONLY   !!!!!!  ***********************************************/@@ -204,18 +234,18 @@ typedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal; struct LZ4HC_CCtx_internal {-    LZ4_u32   hashTable[LZ4HC_HASHTABLESIZE];-    LZ4_u16   chainTable[LZ4HC_MAXD];-    const LZ4_byte* end;       /* next block here to continue on current prefix */+    LZ4_u32 hashTable[LZ4HC_HASHTABLESIZE];+    LZ4_u16 chainTable[LZ4HC_MAXD];+    const LZ4_byte* end;     /* next block here to continue on current prefix */     const LZ4_byte* prefixStart;  /* Indexes relative to this position */     const LZ4_byte* dictStart; /* alternate reference for extDict */-    LZ4_u32   dictLimit;       /* below that point, need extDict */-    LZ4_u32   lowLimit;        /* below that point, no more dict */-    LZ4_u32   nextToUpdate;    /* index from which to continue dictionary update */-    short     compressionLevel;-    LZ4_i8    favorDecSpeed;   /* favor decompression speed if this flag set,-                                  otherwise, favor compression ratio */-    LZ4_i8    dirty;           /* stream has to be fully reset if this flag is set */+    LZ4_u32 dictLimit;       /* below that point, need extDict */+    LZ4_u32 lowLimit;        /* below that point, no more history */+    LZ4_u32 nextToUpdate;    /* index from which to continue dictionary update */+    short   compressionLevel;+    LZ4_i8  favorDecSpeed;   /* favor decompression speed if this flag set,+                                otherwise, favor compression ratio */+    LZ4_i8  dirty;           /* stream has to be fully reset if this flag is set */     const LZ4HC_CCtx_internal* dictCtx; }; @@ -375,35 +405,6 @@     const char* src, char* dst,     int srcSize, int dstCapacity,     int compressionLevel);--/*! LZ4_attach_HC_dictionary() :- *  This is an experimental API that allows for the efficient use of a- *  static dictionary many times.- *- *  Rather than re-loading the dictionary buffer into a working context before- *  each compression, or copying a pre-loaded dictionary's LZ4_streamHC_t into a- *  working LZ4_streamHC_t, this function introduces a no-copy setup mechanism,- *  in which the working stream references the dictionary stream in-place.- *- *  Several assumptions are made about the state of the dictionary stream.- *  Currently, only streams which have been prepared by LZ4_loadDictHC() should- *  be expected to work.- *- *  Alternatively, the provided dictionary stream pointer may be NULL, in which- *  case any existing dictionary stream is unset.- *- *  A dictionary should only be attached to a stream without any history (i.e.,- *  a stream that has just been reset).- *- *  The dictionary will remain attached to the working stream only for the- *  current stream session. Calls to LZ4_resetStreamHC(_fast) will remove the- *  dictionary context association from the working stream. The dictionary- *  stream (and source buffer) must remain in-place / accessible / unchanged- *  through the lifetime of the stream session.- */-LZ4LIB_STATIC_API void LZ4_attach_HC_dictionary(-          LZ4_streamHC_t *working_stream,-    const LZ4_streamHC_t *dictionary_stream);  #if defined (__cplusplus) }
cbits/xxhash.c view
@@ -120,12 +120,12 @@ /* ************************************* *  Compiler Specific Options ***************************************/-#ifdef _MSC_VER    /* Visual Studio */+#if defined (_MSC_VER) && !defined (__clang__)    /* MSVC */ #  pragma warning(disable : 4127)      /* disable: C4127: conditional expression is constant */ #  define FORCE_INLINE static __forceinline #else #  if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */-#    ifdef __GNUC__+#    if defined (__GNUC__) || defined (__clang__) #      define FORCE_INLINE static inline __attribute__((always_inline)) #    else #      define FORCE_INLINE static inline@@ -213,7 +213,7 @@ /* ************************************* *  Architecture Macros ***************************************/-typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;+typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianness;  /* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */ #ifndef XXH_CPU_LITTLE_ENDIAN@@ -231,7 +231,7 @@ *****************************/ typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; -FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)+FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianness endian, XXH_alignment align) {     if (align==XXH_unaligned)         return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));@@ -239,7 +239,7 @@         return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr); } -FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)+FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianness endian) {     return XXH_readLE32_align(ptr, endian, XXH_unaligned); }@@ -289,7 +289,7 @@  static U32 XXH32_finalize(U32 h32, const void* ptr, size_t len,-                XXH_endianess endian, XXH_alignment align)+                XXH_endianness endian, XXH_alignment align)  {     const BYTE* p = (const BYTE*)ptr;@@ -350,7 +350,7 @@  FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed,-                    XXH_endianess endian, XXH_alignment align)+                    XXH_endianness endian, XXH_alignment align) {     const BYTE* p = (const BYTE*)input;     const BYTE* bEnd = p + len;@@ -398,7 +398,7 @@     XXH32_update(&state, input, len);     return XXH32_digest(&state); #else-    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;+    XXH_endianness endian_detected = (XXH_endianness)XXH_CPU_LITTLE_ENDIAN;      if (XXH_FORCE_ALIGN_CHECK) {         if ((((size_t)input) & 3) == 0) {   /* Input is 4-bytes aligned, leverage the speed benefit */@@ -449,7 +449,7 @@   FORCE_INLINE XXH_errorcode-XXH32_update_endian(XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)+XXH32_update_endian(XXH32_state_t* state, const void* input, size_t len, XXH_endianness endian) {     if (input==NULL) #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)@@ -514,7 +514,7 @@  XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len) {-    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;+    XXH_endianness endian_detected = (XXH_endianness)XXH_CPU_LITTLE_ENDIAN;      if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)         return XXH32_update_endian(state_in, input, len, XXH_littleEndian);@@ -524,7 +524,7 @@   FORCE_INLINE U32-XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)+XXH32_digest_endian (const XXH32_state_t* state, XXH_endianness endian) {     U32 h32; @@ -545,7 +545,7 @@  XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in) {-    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;+    XXH_endianness endian_detected = (XXH_endianness)XXH_CPU_LITTLE_ENDIAN;      if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)         return XXH32_digest_endian(state_in, XXH_littleEndian);@@ -642,7 +642,7 @@ } #endif -FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)+FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianness endian, XXH_alignment align) {     if (align==XXH_unaligned)         return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));@@ -650,7 +650,7 @@         return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr); } -FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)+FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianness endian) {     return XXH_readLE64_align(ptr, endian, XXH_unaligned); }@@ -700,7 +700,7 @@  static U64 XXH64_finalize(U64 h64, const void* ptr, size_t len,-               XXH_endianess endian, XXH_alignment align)+               XXH_endianness endian, XXH_alignment align) {     const BYTE* p = (const BYTE*)ptr; @@ -809,7 +809,7 @@  FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed,-                XXH_endianess endian, XXH_alignment align)+                XXH_endianness endian, XXH_alignment align) {     const BYTE* p = (const BYTE*)input;     const BYTE* bEnd = p + len;@@ -861,7 +861,7 @@     XXH64_update(&state, input, len);     return XXH64_digest(&state); #else-    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;+    XXH_endianness endian_detected = (XXH_endianness)XXH_CPU_LITTLE_ENDIAN;      if (XXH_FORCE_ALIGN_CHECK) {         if ((((size_t)input) & 7)==0) {  /* Input is aligned, let's leverage the speed advantage */@@ -909,7 +909,7 @@ }  FORCE_INLINE XXH_errorcode-XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)+XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianness endian) {     if (input==NULL) #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)@@ -970,7 +970,7 @@  XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len) {-    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;+    XXH_endianness endian_detected = (XXH_endianness)XXH_CPU_LITTLE_ENDIAN;      if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)         return XXH64_update_endian(state_in, input, len, XXH_littleEndian);@@ -978,7 +978,7 @@         return XXH64_update_endian(state_in, input, len, XXH_bigEndian); } -FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)+FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianness endian) {     U64 h64; @@ -1004,7 +1004,7 @@  XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in) {-    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;+    XXH_endianness endian_detected = (XXH_endianness)XXH_CPU_LITTLE_ENDIAN;      if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)         return XXH64_digest_endian(state_in, XXH_littleEndian);
lz4-hs.cabal view
@@ -1,6 +1,6 @@ cabal-version:   2.2 name:            lz4-hs-version:         0.1.5.2+version:         0.1.5.3 license:         BSD-3-Clause license-file:    LICENSE copyright:       Copyright: (c) 2020 Vanessa McHale
mem/Mem.hs view
@@ -8,8 +8,8 @@  main :: IO () main = sequence_-    [ compressDump-    , decompressDump+    [ decompressDump+    -- , compressDump     ]  decompressDump :: IO ()
src/Codec/Lz4.chs view
@@ -86,12 +86,12 @@                             poke szPtr (fromIntegral sz)                             res <- lZ4FDecompress ctx d dSzPtr buf szPtr nullPtr                             check res-                            bRead <- peek szPtr+                            bRead <- fromIntegral <$> peek szPtr                             bWritten <- peek dSzPtr                             outBs <- BS.packCStringLen (castPtr d, fromIntegral bWritten)-                            let remBs = if fromIntegral bRead == sz+                            let remBs = if bRead == sz                                 then Nothing-                                else Just (BS.drop (fromIntegral bRead) b)+                                else Just (BS.drop bRead b)                             pure (remBs, outBs)  -- | Lazily compress a frame.