packages feed

lz4-bytes 0.1.2.0 → 0.2.0.0

raw patch · 14 files changed

+7635/−2821 lines, 14 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Lz4.Frame: decompressU :: Int -> Bytes -> Maybe ByteArray
+ Lz4.Frame: decompressU :: Int -> Bytes -> Either Int ByteArray

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for lz4-bytes +## 0.2.0.0 -- 2025-07-07++* Make it possible to compress much larger buffers as a frame+* Correctly handle frames with multiple blocks during decompression+ ## 0.1.2.0 -- 2025-03-26  * Add `Lz4.Frame.decompressU`.
cbits/hs_lz4.c view
@@ -1,6 +1,8 @@ #include "Rts.h" #include "lz4.h"+#include "lz4frame.h" #include "lz4hc.h"+#include <string.h>  HsInt hs_compress_fast   ( const char* src@@ -42,6 +44,103 @@     r = (HsInt)LZ4_decompress_safe(src + soff, dst + doff, slen, dstCapacity);     return r;   }++// This implementation was copied adapted from the Python lz4.frame subpackage.+// This returns a zero on success. Here are the main changes made to the Python+// code:+// * This function is only called in contexts where the size of the decompressed+//   data is communicated some other way, so we never need to grow the destination.+// * full_frame is removed because it is always true+// * This uses the unsafe FFI, so we can set stableDst to true unconditionally+// * We get rid of return_bytearray and return_bytes_read because we+//   only return an indicator of whether or not the exact number of+//   expected bytes were decompressed.+HsInt hs_decompress_frame(LZ4F_dctx * context, const char* const source, HsInt const source_off, HsInt const source_size, char* const destination, HsInt const decompressed_length)+{+  size_t source_remain = source_size;+  size_t source_read;+  const char * source_cursor;+  const char * source_end;+  char * destination_cursor;+  size_t destination_written;+  size_t result = 0;+  LZ4F_frameInfo_t frame_info;+  LZ4F_decompressOptions_t options = {0};+  int end_of_frame = 0;+  size_t destination_write = decompressed_length;++  options.stableDst = 1;+  options.skipChecksums = 1;++  source_cursor = source + source_off;+  source_end = source + source_off + source_size;+  source_remain = source_size;+  source_read = source_size;++  result = LZ4F_getFrameInfo (context, &frame_info, source_cursor, &source_read);+  if (LZ4F_isError (result)) { return result; }++  /* Advance the source_cursor pointer past the header - the call to+     getFrameInfo above replaces the passed source_read value with the+     number of bytes read. Also reduce source_remain accordingly. */+  source_cursor += source_read;+  source_remain -= source_read;++  /* If the uncompressed content size is available, we'll use that to size+     the destination buffer. Otherwise, guess at twice the remaining source+     source as a starting point, and adjust if needed. */+  if (frame_info.contentSize > 0)+  {+    if (frame_info.contentSize != decompressed_length) {+      return 20000;+    }+  }++  source_read = source_remain;++  destination_cursor = destination;+  destination_written = 0;++  while (1)+    {+      /* Decompress from the source string and write to the destination+         until there's no more source string to read, or until we've reached the+         frame end.++         On calling LZ4F_decompress, source_read is set to the remaining length+         of source available to read. On return, source_read is set to the+         actual number of bytes read from source, which may be less than+         available. NB: LZ4F_decompress does not explicitly fail on empty input.++         On calling LZ4F_decompress, destination_write is the number of bytes in+         destination available for writing. On exit, destination_write is set to+         the actual number of bytes written to destination. */+      result = LZ4F_decompress (context, destination_cursor, &destination_write, source_cursor, &source_read, &options);++      if (LZ4F_isError (result)) { return result; }++      destination_written += destination_write;+      source_cursor += source_read;+      source_read = source_end - source_cursor;++      if (result == 0) {+        end_of_frame = 1;+        break;+      }+      else if (source_cursor == source_end) { break; }+      else if (destination_written == decompressed_length) { break; }+      destination_cursor = destination + destination_written;+      destination_write = decompressed_length - destination_written;+    }++  if (result > 0) { return 20001; }+  if (end_of_frame != 1) { return 20002; }+  if (LZ4F_isError (result)) { return 20003; }++  return 0;+}++  // Started on streaming compression and then realized it has some // restrictions that make it pretty hard to wrap in Haskell. Read
cbits/lz4.c view
@@ -1,2397 +1,2717 @@ /*    LZ4 - Fast LZ compression algorithm-   Copyright (C) 2011-present, Yann Collet.--   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)--   Redistribution and use in source and binary forms, with or without-   modification, are permitted provided that the following conditions are-   met:--       * Redistributions of source code must retain the above copyright-   notice, this list of conditions and the following disclaimer.-       * Redistributions in binary form must reproduce the above-   copyright notice, this list of conditions and the following disclaimer-   in the documentation and/or other materials provided with the-   distribution.--   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS-   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT-   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR-   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT-   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,-   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT-   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE-   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.--   You can contact the author at :-    - LZ4 homepage : http://www.lz4.org-    - LZ4 source repository : https://github.com/lz4/lz4-*/--/*-************************************-*  Tuning parameters-**************************************/-/*- * LZ4_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()).- */-#ifndef LZ4_HEAPMODE-#  define LZ4_HEAPMODE 0-#endif--/*- * ACCELERATION_DEFAULT :- * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0- */-#define ACCELERATION_DEFAULT 1---/*-************************************-*  CPU Feature Detection-**************************************/-/* LZ4_FORCE_MEMORY_ACCESS- * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.- * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.- * The below switch allow to select different access method for improved performance.- * Method 0 (default) : use `memcpy()`. Safe and portable.- * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).- *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.- * Method 2 : direct access. This method is portable but violate C standard.- *            It can generate buggy code on targets which assembly generation depends on alignment.- *            But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)- * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.- * Prefer these methods in priority order (0 > 1 > 2)- */-#ifndef LZ4_FORCE_MEMORY_ACCESS   /* can be defined externally */-#  if defined(__GNUC__) && \-  ( 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__)-#    define LZ4_FORCE_MEMORY_ACCESS 1-#  endif-#endif--/*- * LZ4_FORCE_SW_BITCOUNT- * Define this parameter if your target system or compiler does not support hardware bit count- */-#if defined(_MSC_VER) && defined(_WIN32_WCE)   /* Visual Studio for WinCE doesn't support Hardware bit count */-#  define LZ4_FORCE_SW_BITCOUNT-#endif----/*-************************************-*  Dependency-**************************************/-/*- * LZ4_SRC_INCLUDED:- * Amalgamation flag, whether lz4.c is included- */-#ifndef LZ4_SRC_INCLUDED-#  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 */-#endif--#define LZ4_STATIC_LINKING_ONLY  /* LZ4_DISTANCE_MAX */-#include "lz4.h"-/* see also "memory routines" below */---/*-************************************-*  Compiler Options-**************************************/-#ifdef _MSC_VER    /* Visual Studio */-#  include <intrin.h>-#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */-#  pragma warning(disable : 4293)        /* disable: C4293: too large shift (32-bits) */-#endif  /* _MSC_VER */--#ifndef LZ4_FORCE_INLINE-#  ifdef _MSC_VER    /* Visual Studio */-#    define LZ4_FORCE_INLINE static __forceinline-#  else-#    if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */-#      ifdef __GNUC__-#        define LZ4_FORCE_INLINE static inline __attribute__((always_inline))-#      else-#        define LZ4_FORCE_INLINE static inline-#      endif-#    else-#      define LZ4_FORCE_INLINE static-#    endif /* __STDC_VERSION__ */-#  endif  /* _MSC_VER */-#endif /* LZ4_FORCE_INLINE */--/* LZ4_FORCE_O2_GCC_PPC64LE and LZ4_FORCE_O2_INLINE_GCC_PPC64LE- * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8,- * together with a simple 8-byte copy loop as a fall-back path.- * However, this optimization hurts the decompression speed by >30%,- * because the execution does not go to the optimized loop- * for typical compressible data, and all of the preamble checks- * before going to the fall-back path become useless overhead.- * This optimization happens only with the -O3 flag, and -O2 generates- * a simple 8-byte copy loop.- * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy8- * functions are annotated with __attribute__((optimize("O2"))),- * and also LZ4_wildCopy8 is forcibly inlined, so that the O2 attribute- * of LZ4_wildCopy8 does not affect the compression speed.- */-#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__)-#  define LZ4_FORCE_O2_GCC_PPC64LE __attribute__((optimize("O2")))-#  define LZ4_FORCE_O2_INLINE_GCC_PPC64LE __attribute__((optimize("O2"))) LZ4_FORCE_INLINE-#else-#  define LZ4_FORCE_O2_GCC_PPC64LE-#  define LZ4_FORCE_O2_INLINE_GCC_PPC64LE static-#endif--#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)-#  define expect(expr,value)    (__builtin_expect ((expr),(value)) )-#else-#  define expect(expr,value)    (expr)-#endif--#ifndef likely-#define likely(expr)     expect((expr) != 0, 1)-#endif-#ifndef unlikely-#define unlikely(expr)   expect((expr) != 0, 0)-#endif---/*-************************************-*  Memory routines-**************************************/-#include <stdlib.h>   /* malloc, calloc, free */-#define ALLOC(s)          malloc(s)-#define ALLOC_AND_ZERO(s) calloc(1,s)-#define FREEMEM(p)        free(p)-#include <string.h>   /* memset, memcpy */-#define MEM_INIT(p,v,s)   memset((p),(v),(s))---/*-************************************-*  Common Constants-**************************************/-#define MINMATCH 4--#define WILDCOPYLENGTH 8-#define LASTLITERALS   5   /* see ../doc/lz4_Block_format.md#parsing-restrictions */-#define MFLIMIT       12   /* see ../doc/lz4_Block_format.md#parsing-restrictions */-#define MATCH_SAFEGUARD_DISTANCE  ((2*WILDCOPYLENGTH) - MINMATCH)   /* ensure it's possible to write 2 x wildcopyLength without overflowing output buffer */-#define FASTLOOP_SAFE_DISTANCE 64-static const int LZ4_minLength = (MFLIMIT+1);--#define KB *(1 <<10)-#define MB *(1 <<20)-#define GB *(1U<<30)--#define LZ4_DISTANCE_ABSOLUTE_MAX 65535-#if (LZ4_DISTANCE_MAX > LZ4_DISTANCE_ABSOLUTE_MAX)   /* max supported by LZ4 format */-#  error "LZ4_DISTANCE_MAX is too big : must be <= 65535"-#endif--#define ML_BITS  4-#define ML_MASK  ((1U<<ML_BITS)-1)-#define RUN_BITS (8-ML_BITS)-#define RUN_MASK ((1U<<RUN_BITS)-1)---/*-************************************-*  Error detection-**************************************/-#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=1)-#  include <assert.h>-#else-#  ifndef assert-#    define assert(condition) ((void)0)-#  endif-#endif--#define LZ4_STATIC_ASSERT(c)   { enum { LZ4_static_assert = 1/(int)(!!(c)) }; }   /* use after variable declarations */--#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2)-#  include <stdio.h>-   static int g_debuglog_enable = 1;-#  define DEBUGLOG(l, ...) {                          \-        if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) {  \-            fprintf(stderr, __FILE__ ": ");           \-            fprintf(stderr, __VA_ARGS__);             \-            fprintf(stderr, " \n");                   \-    }   }-#else-#  define DEBUGLOG(l, ...) {}    /* disabled */-#endif---/*-************************************-*  Types-**************************************/-#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)-# include <stdint.h>-  typedef  uint8_t BYTE;-  typedef uint16_t U16;-  typedef uint32_t U32;-  typedef  int32_t S32;-  typedef uint64_t U64;-  typedef uintptr_t uptrval;-#else-# include <limits.h>-# if UINT_MAX != 4294967295UL-#   error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4"-# endif-  typedef unsigned char       BYTE;-  typedef unsigned short      U16;-  typedef unsigned int        U32;-  typedef   signed int        S32;-  typedef unsigned long long  U64;-  typedef size_t              uptrval;   /* generally true, except OpenVMS-64 */-#endif--#if defined(__x86_64__)-  typedef U64    reg_t;   /* 64-bits in x32 mode */-#else-  typedef size_t reg_t;   /* 32-bits in x32 mode */-#endif--typedef enum {-    notLimited = 0,-    limitedOutput = 1,-    fillOutput = 2-} limitedOutput_directive;---/*-************************************-*  Reading and writing into memory-**************************************/-static unsigned LZ4_isLittleEndian(void)-{-    const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental */-    return one.c[0];-}---#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)-/* lie to the compiler about data alignment; use with caution */--static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; }-static U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; }-static reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; }--static void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }-static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }--#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1)--/* __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)) unalign;--static U16 LZ4_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }-static U32 LZ4_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }-static reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArch; }--static void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }-static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }--#else  /* safe and portable access using memcpy() */--static U16 LZ4_read16(const void* memPtr)-{-    U16 val; memcpy(&val, memPtr, sizeof(val)); return val;-}--static U32 LZ4_read32(const void* memPtr)-{-    U32 val; memcpy(&val, memPtr, sizeof(val)); return val;-}--static reg_t LZ4_read_ARCH(const void* memPtr)-{-    reg_t val; memcpy(&val, memPtr, sizeof(val)); return val;-}--static void LZ4_write16(void* memPtr, U16 value)-{-    memcpy(memPtr, &value, sizeof(value));-}--static void LZ4_write32(void* memPtr, U32 value)-{-    memcpy(memPtr, &value, sizeof(value));-}--#endif /* LZ4_FORCE_MEMORY_ACCESS */---static U16 LZ4_readLE16(const void* memPtr)-{-    if (LZ4_isLittleEndian()) {-        return LZ4_read16(memPtr);-    } else {-        const BYTE* p = (const BYTE*)memPtr;-        return (U16)((U16)p[0] + (p[1]<<8));-    }-}--static void LZ4_writeLE16(void* memPtr, U16 value)-{-    if (LZ4_isLittleEndian()) {-        LZ4_write16(memPtr, value);-    } else {-        BYTE* p = (BYTE*)memPtr;-        p[0] = (BYTE) value;-        p[1] = (BYTE)(value>>8);-    }-}--/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */-LZ4_FORCE_O2_INLINE_GCC_PPC64LE-void LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd)-{-    BYTE* d = (BYTE*)dstPtr;-    const BYTE* s = (const BYTE*)srcPtr;-    BYTE* const e = (BYTE*)dstEnd;--    do { memcpy(d,s,8); d+=8; s+=8; } while (d<e);-}--static const unsigned inc32table[8] = {0, 1, 2,  1,  0,  4, 4, 4};-static const int      dec64table[8] = {0, 0, 0, -1, -4,  1, 2, 3};---#ifndef LZ4_FAST_DEC_LOOP-#  if defined __i386__ || defined _M_IX86 || defined __x86_64__ || defined _M_X64-#    define LZ4_FAST_DEC_LOOP 1-#  elif defined(__aarch64__) && !defined(__clang__)-     /* On aarch64, we disable this optimization for clang because on certain-      * mobile chipsets, performance is reduced with clang. For information-      * refer to https://github.com/lz4/lz4/pull/707 */-#    define LZ4_FAST_DEC_LOOP 1-#  else-#    define LZ4_FAST_DEC_LOOP 0-#  endif-#endif--#if LZ4_FAST_DEC_LOOP--LZ4_FORCE_O2_INLINE_GCC_PPC64LE void-LZ4_memcpy_using_offset_base(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)-{-    if (offset < 8) {-        dstPtr[0] = srcPtr[0];-        dstPtr[1] = srcPtr[1];-        dstPtr[2] = srcPtr[2];-        dstPtr[3] = srcPtr[3];-        srcPtr += inc32table[offset];-        memcpy(dstPtr+4, srcPtr, 4);-        srcPtr -= dec64table[offset];-        dstPtr += 8;-    } else {-        memcpy(dstPtr, srcPtr, 8);-        dstPtr += 8;-        srcPtr += 8;-    }--    LZ4_wildCopy8(dstPtr, srcPtr, dstEnd);-}--/* customized variant of memcpy, which can overwrite up to 32 bytes beyond dstEnd- * this version copies two times 16 bytes (instead of one time 32 bytes)- * because it must be compatible with offsets >= 16. */-LZ4_FORCE_O2_INLINE_GCC_PPC64LE void-LZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd)-{-    BYTE* d = (BYTE*)dstPtr;-    const BYTE* s = (const BYTE*)srcPtr;-    BYTE* const e = (BYTE*)dstEnd;--    do { memcpy(d,s,16); memcpy(d+16,s+16,16); d+=32; s+=32; } while (d<e);-}--/* LZ4_memcpy_using_offset()  presumes :- * - dstEnd >= dstPtr + MINMATCH- * - there is at least 8 bytes available to write after dstEnd */-LZ4_FORCE_O2_INLINE_GCC_PPC64LE void-LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)-{-    BYTE v[8];--    assert(dstEnd >= dstPtr + MINMATCH);-    LZ4_write32(dstPtr, 0);   /* silence an msan warning when offset==0 */--    switch(offset) {-    case 1:-        memset(v, *srcPtr, 8);-        break;-    case 2:-        memcpy(v, srcPtr, 2);-        memcpy(&v[2], srcPtr, 2);-        memcpy(&v[4], &v[0], 4);-        break;-    case 4:-        memcpy(v, srcPtr, 4);-        memcpy(&v[4], srcPtr, 4);-        break;-    default:-        LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset);-        return;-    }--    memcpy(dstPtr, v, 8);-    dstPtr += 8;-    while (dstPtr < dstEnd) {-        memcpy(dstPtr, v, 8);-        dstPtr += 8;-    }-}-#endif---/*-************************************-*  Common functions-**************************************/-static unsigned LZ4_NbCommonBytes (reg_t val)-{-    if (LZ4_isLittleEndian()) {-        if (sizeof(val)==8) {-#       if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)-            unsigned long r = 0;-            _BitScanForward64( &r, (U64)val );-            return (int)(r>>3);-#       elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)-            return (unsigned)__builtin_ctzll((U64)val) >> 3;-#       else-            static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,-                                                     0, 3, 1, 3, 1, 4, 2, 7,-                                                     0, 2, 3, 6, 1, 5, 3, 5,-                                                     1, 3, 4, 4, 2, 5, 6, 7,-                                                     7, 0, 1, 2, 3, 3, 4, 6,-                                                     2, 6, 5, 5, 3, 4, 5, 6,-                                                     7, 1, 2, 4, 6, 4, 4, 5,-                                                     7, 2, 6, 5, 7, 6, 7, 7 };-            return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];-#       endif-        } else /* 32 bits */ {-#       if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)-            unsigned long r;-            _BitScanForward( &r, (U32)val );-            return (int)(r>>3);-#       elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)-            return (unsigned)__builtin_ctz((U32)val) >> 3;-#       else-            static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,-                                                     3, 2, 2, 1, 3, 2, 0, 1,-                                                     3, 3, 1, 2, 2, 2, 2, 0,-                                                     3, 1, 2, 0, 1, 0, 1, 1 };-            return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];-#       endif-        }-    } else   /* Big Endian CPU */ {-        if (sizeof(val)==8) {   /* 64-bits */-#       if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)-            unsigned long r = 0;-            _BitScanReverse64( &r, val );-            return (unsigned)(r>>3);-#       elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)-            return (unsigned)__builtin_clzll((U64)val) >> 3;-#       else-            static const U32 by32 = sizeof(val)*4;  /* 32 on 64 bits (goal), 16 on 32 bits.-                Just to avoid some static analyzer complaining about shift by 32 on 32-bits target.-                Note that this code path is never triggered in 32-bits mode. */-            unsigned r;-            if (!(val>>by32)) { r=4; } else { r=0; val>>=by32; }-            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }-            r += (!val);-            return r;-#       endif-        } else /* 32 bits */ {-#       if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)-            unsigned long r = 0;-            _BitScanReverse( &r, (unsigned long)val );-            return (unsigned)(r>>3);-#       elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)-            return (unsigned)__builtin_clz((U32)val) >> 3;-#       else-            unsigned r;-            if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }-            r += (!val);-            return r;-#       endif-        }-    }-}--#define STEPSIZE sizeof(reg_t)-LZ4_FORCE_INLINE-unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)-{-    const BYTE* const pStart = pIn;--    if (likely(pIn < pInLimit-(STEPSIZE-1))) {-        reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);-        if (!diff) {-            pIn+=STEPSIZE; pMatch+=STEPSIZE;-        } else {-            return LZ4_NbCommonBytes(diff);-    }   }--    while (likely(pIn < pInLimit-(STEPSIZE-1))) {-        reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);-        if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }-        pIn += LZ4_NbCommonBytes(diff);-        return (unsigned)(pIn - pStart);-    }--    if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }-    if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }-    if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;-    return (unsigned)(pIn - pStart);-}---#ifndef LZ4_COMMONDEFS_ONLY-/*-************************************-*  Local Constants-**************************************/-static const int LZ4_64Klimit = ((64 KB) + (MFLIMIT-1));-static const U32 LZ4_skipTrigger = 6;  /* Increase this value ==> compression run slower on incompressible data */---/*-************************************-*  Local Structures and types-**************************************/-typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t;--/**- * This enum distinguishes several different modes of accessing previous- * content in the stream.- *- * - noDict        : There is no preceding content.- * - withPrefix64k : Table entries up to ctx->dictSize before the current blob- *                   blob being compressed are valid and refer to the preceding- *                   content (of length ctx->dictSize), which is available- *                   contiguously preceding in memory the content currently- *                   being compressed.- * - usingExtDict  : Like withPrefix64k, but the preceding content is somewhere- *                   else in memory, starting at ctx->dictionary with length- *                   ctx->dictSize.- * - usingDictCtx  : Like usingExtDict, but everything concerning the preceding- *                   content is in a separate context, pointed to by- *                   ctx->dictCtx. ctx->dictionary, ctx->dictSize, and table- *                   entries in the current context that refer to positions- *                   preceding the beginning of the current compression are- *                   ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx- *                   ->dictSize describe the location and size of the preceding- *                   content, and matches are found by looking in the ctx- *                   ->dictCtx->hashTable.- */-typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive;-typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;---/*-************************************-*  Local Utils-**************************************/-int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }-const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; }-int LZ4_compressBound(int isize)  { return LZ4_COMPRESSBOUND(isize); }-int LZ4_sizeofState() { return LZ4_STREAMSIZE; }---/*-************************************-*  Internal Definitions used in Tests-**************************************/-#if defined (__cplusplus)-extern "C" {-#endif--int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize);--int LZ4_decompress_safe_forceExtDict(const char* source, char* dest,-                                     int compressedSize, int maxOutputSize,-                                     const void* dictStart, size_t dictSize);--#if defined (__cplusplus)-}-#endif--/*-******************************-*  Compression functions-********************************/-static U32 LZ4_hash4(U32 sequence, tableType_t const tableType)-{-    if (tableType == byU16)-        return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));-    else-        return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));-}--static U32 LZ4_hash5(U64 sequence, tableType_t const tableType)-{-    const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;-    if (LZ4_isLittleEndian()) {-        const U64 prime5bytes = 889523592379ULL;-        return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));-    } else {-        const U64 prime8bytes = 11400714785074694791ULL;-        return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));-    }-}--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);-    return LZ4_hash4(LZ4_read32(p), tableType);-}--static void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType)-{-    switch (tableType)-    {-    default: /* fallthrough */-    case clearedTable: { /* illegal! */ assert(0); return; }-    case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = NULL; return; }-    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = 0; return; }-    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = 0; return; }-    }-}--static void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType)-{-    switch (tableType)-    {-    default: /* fallthrough */-    case clearedTable: /* fallthrough */-    case byPtr: { /* illegal! */ assert(0); return; }-    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; }-    case byU16: { U16* hashTable = (U16*) tableBase; assert(idx < 65536); hashTable[h] = (U16)idx; return; }-    }-}--static void LZ4_putPositionOnHash(const BYTE* p, U32 h,-                                  void* tableBase, tableType_t const tableType,-                            const BYTE* srcBase)-{-    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; }-    }-}--LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)-{-    U32 const h = LZ4_hashPosition(p, tableType);-    LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);-}--/* LZ4_getIndexOnHash() :- * Index of match position registered in hash table.- * hash position must be calculated by using base+index, or dictBase+index.- * Assumption 1 : only valid if tableType == byU32 or byU16.- * Assumption 2 : h is presumed valid (within limits of hash table)- */-static U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType)-{-    LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2);-    if (tableType == byU32) {-        const U32* const hashTable = (const U32*) tableBase;-        assert(h < (1U << (LZ4_MEMORY_USAGE-2)));-        return hashTable[h];-    }-    if (tableType == byU16) {-        const U16* const hashTable = (const U16*) tableBase;-        assert(h < (1U << (LZ4_MEMORY_USAGE-1)));-        return hashTable[h];-    }-    assert(0); return 0;  /* forbidden case */-}--static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType, const BYTE* srcBase)-{-    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 */-}--LZ4_FORCE_INLINE const BYTE*-LZ4_getPosition(const BYTE* p,-                const void* tableBase, tableType_t tableType,-                const BYTE* srcBase)-{-    U32 const h = LZ4_hashPosition(p, tableType);-    return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);-}--LZ4_FORCE_INLINE void-LZ4_prepareTable(LZ4_stream_t_internal* const cctx,-           const int inputSize,-           const tableType_t tableType) {-    /* If compression failed during the previous step, then the context-     * is marked as dirty, therefore, it has to be fully reset.-     */-    if (cctx->dirty) {-        DEBUGLOG(5, "LZ4_prepareTable: Full reset for %p", cctx);-        MEM_INIT(cctx, 0, sizeof(LZ4_stream_t_internal));-        return;-    }--    /* If the table hasn't been used, it's guaranteed to be zeroed out, and is-     * therefore safe to use no matter what mode we're in. Otherwise, we figure-     * out if it's safe to leave as is or whether it needs to be reset.-     */-    if (cctx->tableType != clearedTable) {-        assert(inputSize >= 0);-        if (cctx->tableType != tableType-          || ((tableType == byU16) && cctx->currentOffset + (unsigned)inputSize >= 0xFFFFU)-          || ((tableType == byU32) && cctx->currentOffset > 1 GB)-          || tableType == byPtr-          || inputSize >= 4 KB)-        {-            DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx);-            MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE);-            cctx->currentOffset = 0;-            cctx->tableType = clearedTable;-        } else {-            DEBUGLOG(4, "LZ4_prepareTable: Re-use hash table (no reset)");-        }-    }--    /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back, is faster-     * than compressing without a gap. However, compressing with-     * currentOffset == 0 is faster still, so we preserve that case.-     */-    if (cctx->currentOffset != 0 && tableType == byU32) {-        DEBUGLOG(5, "LZ4_prepareTable: adding 64KB to currentOffset");-        cctx->currentOffset += 64 KB;-    }--    /* Finally, clear history */-    cctx->dictCtx = NULL;-    cctx->dictionary = NULL;-    cctx->dictSize = 0;-}--/** LZ4_compress_generic() :-    inlined, to ensure branches are decided at compilation time */-LZ4_FORCE_INLINE int LZ4_compress_generic(-                 LZ4_stream_t_internal* const cctx,-                 const char* const source,-                 char* const dest,-                 const int inputSize,-                 int *inputConsumed, /* only written when outputDirective == fillOutput */-                 const int maxOutputSize,-                 const limitedOutput_directive outputDirective,-                 const tableType_t tableType,-                 const dict_directive dictDirective,-                 const dictIssue_directive dictIssue,-                 const int acceleration)-{-    int result;-    const BYTE* ip = (const BYTE*) source;--    U32 const startIndex = cctx->currentOffset;-    const BYTE* base = (const BYTE*) source - startIndex;-    const BYTE* lowLimit;--    const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx;-    const BYTE* const dictionary =-        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 */--    int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx);-    U32 const prefixIdxLimit = startIndex - dictSize;   /* used when dictDirective == dictSmall */-    const BYTE* const dictEnd = dictionary + dictSize;-    const BYTE* anchor = (const BYTE*) source;-    const BYTE* const iend = ip + inputSize;-    const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1;-    const BYTE* const matchlimit = iend - LASTLITERALS;--    /* the dictCtx currentOffset is indexed on the start of the dictionary,-     * while a dictionary in the current context precedes the currentOffset */-    const BYTE* dictBase = (dictDirective == usingDictCtx) ?-                            dictionary + dictSize - dictCtx->currentOffset :-                            dictionary + dictSize - startIndex;--    BYTE* op = (BYTE*) dest;-    BYTE* const olimit = op + maxOutputSize;--    U32 offset = 0;-    U32 forwardH;--    DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, tableType=%u", inputSize, tableType);-    /* 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 ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; }           /* Unsupported inputSize, too large (or negative) */-    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);--    /* Update context state */-    if (dictDirective == usingDictCtx) {-        /* Subsequent linked blocks can't use the dictionary. */-        /* Instead, they use the block we just compressed. */-        cctx->dictCtx = NULL;-        cctx->dictSize = (U32)inputSize;-    } else {-        cctx->dictSize += (U32)inputSize;-    }-    cctx->currentOffset += (U32)inputSize;-    cctx->tableType = (U16)tableType;--    if (inputSize<LZ4_minLength) goto _last_literals;        /* Input too small, no compression (all literals) */--    /* First Byte */-    LZ4_putPosition(ip, cctx->hashTable, tableType, base);-    ip++; forwardH = LZ4_hashPosition(ip, tableType);--    /* Main Loop */-    for ( ; ; ) {-        const BYTE* match;-        BYTE* token;-        const BYTE* filledIp;--        /* Find a match */-        if (tableType == byPtr) {-            const BYTE* forwardIp = ip;-            int step = 1;-            int searchMatchNb = acceleration << LZ4_skipTrigger;-            do {-                U32 const h = forwardH;-                ip = forwardIp;-                forwardIp += step;-                step = (searchMatchNb++ >> LZ4_skipTrigger);--                if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;-                assert(ip < mflimitPlusOne);--                match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);-                forwardH = LZ4_hashPosition(forwardIp, tableType);-                LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);--            } while ( (match+LZ4_DISTANCE_MAX < ip)-                   || (LZ4_read32(match) != LZ4_read32(ip)) );--        } else {   /* byU32, byU16 */--            const BYTE* forwardIp = ip;-            int step = 1;-            int searchMatchNb = acceleration << LZ4_skipTrigger;-            do {-                U32 const h = forwardH;-                U32 const current = (U32)(forwardIp - base);-                U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);-                assert(matchIndex <= current);-                assert(forwardIp - base < (ptrdiff_t)(2 GB - 1));-                ip = forwardIp;-                forwardIp += step;-                step = (searchMatchNb++ >> LZ4_skipTrigger);--                if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;-                assert(ip < mflimitPlusOne);--                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;-                        matchIndex += dictDelta;   /* make dictCtx index comparable with current context */-                        lowLimit = dictionary;-                    } else {-                        match = base + matchIndex;-                        lowLimit = (const BYTE*)source;-                    }-                } else if (dictDirective==usingExtDict) {-                    if (matchIndex < startIndex) {-                        DEBUGLOG(7, "extDict candidate: matchIndex=%5u  <  startIndex=%5u", matchIndex, startIndex);-                        assert(startIndex - matchIndex >= MINMATCH);-                        match = dictBase + matchIndex;-                        lowLimit = dictionary;-                    } else {-                        match = base + matchIndex;-                        lowLimit = (const BYTE*)source;-                    }-                } else {   /* single continuous memory segment */-                    match = base + matchIndex;-                }-                forwardH = LZ4_hashPosition(forwardIp, tableType);-                LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);--                DEBUGLOG(7, "candidate at pos=%u  (offset=%u \n", matchIndex, current - matchIndex);-                if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) { continue; }    /* match outside of valid area */-                assert(matchIndex < current);-                if ( ((tableType != byU16) || (LZ4_DISTANCE_MAX < LZ4_DISTANCE_ABSOLUTE_MAX))-                  && (matchIndex+LZ4_DISTANCE_MAX < current)) {-                    continue;-                } /* too far */-                assert((current - matchIndex) <= LZ4_DISTANCE_MAX);  /* match now expected within distance */--                if (LZ4_read32(match) == LZ4_read32(ip)) {-                    if (maybe_extMem) offset = current - matchIndex;-                    break;   /* match found */-                }--            } while(1);-        }--        /* Catch up */-        filledIp = ip;-        while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }--        /* Encode Literals */-        {   unsigned const litLength = (unsigned)(ip - anchor);-            token = op++;-            if ((outputDirective == limitedOutput) &&  /* Check output buffer overflow */-                (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)) ) {-                return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */-            }-            if ((outputDirective == fillOutput) &&-                (unlikely(op + (litLength+240)/255 /* litlen */ + litLength /* literals */ + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit))) {-                op--;-                goto _last_literals;-            }-            if (litLength >= RUN_MASK) {-                int len = (int)(litLength - RUN_MASK);-                *token = (RUN_MASK<<ML_BITS);-                for(; len >= 255 ; len-=255) *op++ = 255;-                *op++ = (BYTE)len;-            }-            else *token = (BYTE)(litLength<<ML_BITS);--            /* Copy Literals */-            LZ4_wildCopy8(op, anchor, op+litLength);-            op+=litLength;-            DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i",-                        (int)(anchor-(const BYTE*)source), litLength, (int)(ip-(const BYTE*)source));-        }--_next_match:-        /* at this stage, the following variables must be correctly set :-         * - ip : at start of LZ operation-         * - match : at start of previous pattern occurence; can be within current prefix, or within extDict-         * - offset : if maybe_ext_memSegment==1 (constant)-         * - lowLimit : must be == dictionary to mean "match is within extDict"; must be == source otherwise-         * - token and *token : position to write 4-bits for match length; higher 4-bits for literal length supposed already written-         */--        if ((outputDirective == fillOutput) &&-            (op + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit)) {-            /* the match was too close to the end, rewind and go to last literals */-            op = token;-            goto _last_literals;-        }--        /* Encode Offset */-        if (maybe_extMem) {   /* static test */-            DEBUGLOG(6, "             with offset=%u  (ext if > %i)", offset, (int)(ip - (const BYTE*)source));-            assert(offset <= LZ4_DISTANCE_MAX && offset > 0);-            LZ4_writeLE16(op, (U16)offset); op+=2;-        } else  {-            DEBUGLOG(6, "             with offset=%u  (same segment)", (U32)(ip - match));-            assert(ip-match <= LZ4_DISTANCE_MAX);-            LZ4_writeLE16(op, (U16)(ip - match)); op+=2;-        }--        /* Encode MatchLength */-        {   unsigned matchCode;--            if ( (dictDirective==usingExtDict || dictDirective==usingDictCtx)-              && (lowLimit==dictionary) /* match within extDict */ ) {-                const BYTE* limit = ip + (dictEnd-match);-                assert(dictEnd > match);-                if (limit > matchlimit) limit = matchlimit;-                matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);-                ip += (size_t)matchCode + MINMATCH;-                if (ip==limit) {-                    unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit);-                    matchCode += more;-                    ip += more;-                }-                DEBUGLOG(6, "             with matchLength=%u starting in extDict", matchCode+MINMATCH);-            } else {-                matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);-                ip += (size_t)matchCode + MINMATCH;-                DEBUGLOG(6, "             with matchLength=%u", matchCode+MINMATCH);-            }--            if ((outputDirective) &&    /* Check output buffer overflow */-                (unlikely(op + (1 + LASTLITERALS) + (matchCode+240)/255 > olimit)) ) {-                if (outputDirective == fillOutput) {-                    /* Match description too long : reduce it */-                    U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 1 - LASTLITERALS) * 255;-                    ip -= matchCode - newMatchCode;-                    assert(newMatchCode < matchCode);-                    matchCode = newMatchCode;-                    if (unlikely(ip <= filledIp)) {-                        /* We have already filled up to filledIp so if ip ends up less than filledIp-                         * we have positions in the hash table beyond the current position. This is-                         * a problem if we reuse the hash table. So we have to remove these positions-                         * from the hash table.-                         */-                        const BYTE* ptr;-                        DEBUGLOG(5, "Clearing %u positions", (U32)(filledIp - ip));-                        for (ptr = ip; ptr <= filledIp; ++ptr) {-                            U32 const h = LZ4_hashPosition(ptr, tableType);-                            LZ4_clearHash(h, cctx->hashTable, tableType);-                        }-                    }-                } else {-                    assert(outputDirective == limitedOutput);-                    return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */-                }-            }-            if (matchCode >= ML_MASK) {-                *token += ML_MASK;-                matchCode -= ML_MASK;-                LZ4_write32(op, 0xFFFFFFFF);-                while (matchCode >= 4*255) {-                    op+=4;-                    LZ4_write32(op, 0xFFFFFFFF);-                    matchCode -= 4*255;-                }-                op += matchCode / 255;-                *op++ = (BYTE)(matchCode % 255);-            } else-                *token += (BYTE)(matchCode);-        }-        /* Ensure we have enough space for the last literals. */-        assert(!(outputDirective == fillOutput && op + 1 + LASTLITERALS > olimit));--        anchor = ip;--        /* Test end of chunk */-        if (ip >= mflimitPlusOne) break;--        /* Fill table */-        LZ4_putPosition(ip-2, cctx->hashTable, tableType, base);--        /* Test next position */-        if (tableType == byPtr) {--            match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);-            LZ4_putPosition(ip, cctx->hashTable, tableType, base);-            if ( (match+LZ4_DISTANCE_MAX >= ip)-              && (LZ4_read32(match) == LZ4_read32(ip)) )-            { token=op++; *token=0; goto _next_match; }--        } else {   /* byU32, byU16 */--            U32 const h = LZ4_hashPosition(ip, tableType);-            U32 const current = (U32)(ip-base);-            U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);-            assert(matchIndex < current);-            if (dictDirective == usingDictCtx) {-                if (matchIndex < startIndex) {-                    /* there was no match, try the dictionary */-                    matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);-                    match = dictBase + matchIndex;-                    lowLimit = dictionary;   /* required for match length counter */-                    matchIndex += dictDelta;-                } else {-                    match = base + matchIndex;-                    lowLimit = (const BYTE*)source;  /* required for match length counter */-                }-            } else if (dictDirective==usingExtDict) {-                if (matchIndex < startIndex) {-                    match = dictBase + matchIndex;-                    lowLimit = dictionary;   /* required for match length counter */-                } else {-                    match = base + matchIndex;-                    lowLimit = (const BYTE*)source;   /* required for match length counter */-                }-            } else {   /* single memory segment */-                match = base + matchIndex;-            }-            LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);-            assert(matchIndex < current);-            if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1)-              && (((tableType==byU16) && (LZ4_DISTANCE_MAX == LZ4_DISTANCE_ABSOLUTE_MAX)) ? 1 : (matchIndex+LZ4_DISTANCE_MAX >= current))-              && (LZ4_read32(match) == LZ4_read32(ip)) ) {-                token=op++;-                *token=0;-                if (maybe_extMem) offset = current - matchIndex;-                DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i",-                            (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source));-                goto _next_match;-            }-        }--        /* Prepare next loop */-        forwardH = LZ4_hashPosition(++ip, tableType);--    }--_last_literals:-    /* Encode Last Literals */-    {   size_t lastRun = (size_t)(iend - anchor);-        if ( (outputDirective) &&  /* Check output buffer overflow */-            (op + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > olimit)) {-            if (outputDirective == fillOutput) {-                /* adapt lastRun to fill 'dst' */-                assert(olimit >= op);-                lastRun  = (size_t)(olimit-op) - 1;-                lastRun -= (lastRun+240)/255;-            } else {-                assert(outputDirective == limitedOutput);-                return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */-            }-        }-        if (lastRun >= RUN_MASK) {-            size_t accumulator = lastRun - RUN_MASK;-            *op++ = RUN_MASK << ML_BITS;-            for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;-            *op++ = (BYTE) accumulator;-        } else {-            *op++ = (BYTE)(lastRun<<ML_BITS);-        }-        memcpy(op, anchor, lastRun);-        ip = anchor + lastRun;-        op += lastRun;-    }--    if (outputDirective == fillOutput) {-        *inputConsumed = (int) (((const char*)ip)-source);-    }-    DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", inputSize, (int)(((char*)op) - dest));-    result = (int)(((char*)op) - dest);-    assert(result > 0);-    return result;-}---int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)-{-    LZ4_stream_t_internal* const ctx = & LZ4_initStream(state, sizeof(LZ4_stream_t)) -> internal_donotuse;-    assert(ctx != NULL);-    if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;-    if (maxOutputSize >= LZ4_compressBound(inputSize)) {-        if (inputSize < LZ4_64Klimit) {-            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, byU16, noDict, noDictIssue, acceleration);-        } else {-            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;-            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);-        }-    } else {-        if (inputSize < LZ4_64Klimit) {-            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);-        } else {-            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;-            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration);-        }-    }-}--/**- * LZ4_compress_fast_extState_fastReset() :- * A variant of LZ4_compress_fast_extState().- *- * Using this variant avoids an expensive initialization step. It is only safe- * to call if the state buffer is known to be correctly initialized already- * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of- * "correctly initialized").- */-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;-    if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;--    if (dstCapacity >= LZ4_compressBound(srcSize)) {-        if (srcSize < LZ4_64Klimit) {-            const tableType_t tableType = byU16;-            LZ4_prepareTable(ctx, srcSize, tableType);-            if (ctx->currentOffset) {-                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, dictSmall, acceleration);-            } else {-                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);-            }-        } else {-            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;-            LZ4_prepareTable(ctx, srcSize, tableType);-            return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);-        }-    } else {-        if (srcSize < LZ4_64Klimit) {-            const tableType_t tableType = byU16;-            LZ4_prepareTable(ctx, srcSize, tableType);-            if (ctx->currentOffset) {-                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration);-            } else {-                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);-            }-        } else {-            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;-            LZ4_prepareTable(ctx, srcSize, tableType);-            return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);-        }-    }-}---int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)-{-    int result;-#if (LZ4_HEAPMODE)-    LZ4_stream_t* ctxPtr = 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);--#if (LZ4_HEAPMODE)-    FREEMEM(ctxPtr);-#endif-    return result;-}---int LZ4_compress_default(const char* src, char* dst, int srcSize, int maxOutputSize)-{-    return LZ4_compress_fast(src, dst, srcSize, maxOutputSize, 1);-}---/* hidden debug function */-/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */-int LZ4_compress_fast_force(const char* src, char* dst, int srcSize, int dstCapacity, int acceleration)-{-    LZ4_stream_t ctx;-    LZ4_initStream(&ctx, sizeof(ctx));--    if (srcSize < LZ4_64Klimit) {-        return LZ4_compress_generic(&ctx.internal_donotuse, src, dst, srcSize, NULL, dstCapacity, limitedOutput, byU16,    noDict, noDictIssue, acceleration);-    } else {-        tableType_t const addrMode = (sizeof(void*) > 4) ? byU32 : byPtr;-        return LZ4_compress_generic(&ctx.internal_donotuse, src, dst, srcSize, NULL, dstCapacity, limitedOutput, addrMode, noDict, noDictIssue, acceleration);-    }-}---/* 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)-{-    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);-    } else {-        if (*srcSizePtr < LZ4_64Klimit) {-            return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, byU16, noDict, noDictIssue, 1);-        } 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);-    }   }-}---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 */-    if (ctx == NULL) return 0;-#else-    LZ4_stream_t ctxBody;-    LZ4_stream_t* ctx = &ctxBody;-#endif--    int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);--#if (LZ4_HEAPMODE)-    FREEMEM(ctx);-#endif-    return result;-}----/*-******************************-*  Streaming functions-********************************/--LZ4_stream_t* LZ4_createStream(void)-{-    LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));-    LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal));    /* A compilation error here means LZ4_STREAMSIZE is not large enough */-    DEBUGLOG(4, "LZ4_createStream %p", lz4s);-    if (lz4s == NULL) return NULL;-    LZ4_initStream(lz4s, sizeof(*lz4s));-    return lz4s;-}--#ifndef _MSC_VER  /* for some reason, Visual fails the aligment test on 32-bit x86 :-                     it reports an aligment of 8-bytes,-                     while actually aligning LZ4_stream_t on 4 bytes. */-static size_t LZ4_stream_t_alignment(void)-{-    struct { char c; LZ4_stream_t t; } t_a;-    return sizeof(t_a) - sizeof(t_a.t);-}-#endif--LZ4_stream_t* LZ4_initStream (void* buffer, size_t size)-{-    DEBUGLOG(5, "LZ4_initStream");-    if (buffer == NULL) { return NULL; }-    if (size < sizeof(LZ4_stream_t)) { return NULL; }-#ifndef _MSC_VER  /* for some reason, Visual fails the aligment test on 32-bit x86 :-                     it reports an aligment of 8-bytes,-                     while actually aligning LZ4_stream_t on 4 bytes. */-    if (((size_t)buffer) & (LZ4_stream_t_alignment() - 1)) { return NULL; } /* alignment check */-#endif-    MEM_INIT(buffer, 0, sizeof(LZ4_stream_t));-    return (LZ4_stream_t*)buffer;-}--/* resetStream is now deprecated,- * prefer initStream() which is more general */-void LZ4_resetStream (LZ4_stream_t* LZ4_stream)-{-    DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream);-    MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t));-}--void LZ4_resetStream_fast(LZ4_stream_t* ctx) {-    LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32);-}--int LZ4_freeStream (LZ4_stream_t* LZ4_stream)-{-    if (!LZ4_stream) return 0;   /* support free on NULL */-    DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream);-    FREEMEM(LZ4_stream);-    return (0);-}---#define HASH_UNIT sizeof(reg_t)-int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)-{-    LZ4_stream_t_internal* 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;--    DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict);--    /* It's necessary to reset the context,-     * and not just continue it with prepareTable()-     * to avoid any risk of generating overflowing matchIndex-     * when compressing using this dictionary */-    LZ4_resetStream(LZ4_dict);--    /* We always increment the offset by 64 KB, since, if the dict is longer,-     * we truncate it to the last 64k, and if it's shorter, we still want to-     * advance by a whole window length so we can provide the guarantee that-     * there are only valid offsets in the window, which allows an optimization-     * in LZ4_compress_fast_continue() where it uses noDictIssue even when the-     * dictionary isn't a full 64k. */-    dict->currentOffset += 64 KB;--    if (dictSize < (int)HASH_UNIT) {-        return 0;-    }--    if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;-    base = dictEnd - dict->currentOffset;-    dict->dictionary = p;-    dict->dictSize = (U32)(dictEnd - p);-    dict->tableType = tableType;--    while (p <= dictEnd-HASH_UNIT) {-        LZ4_putPosition(p, dict->hashTable, tableType, base);-        p+=3;-    }--    return (int)dict->dictSize;-}--void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream) {-    const LZ4_stream_t_internal* dictCtx = dictionaryStream == NULL ? NULL :-        &(dictionaryStream->internal_donotuse);--    DEBUGLOG(4, "LZ4_attach_dictionary (%p, %p, size %u)",-             workingStream, dictionaryStream,-             dictCtx != NULL ? dictCtx->dictSize : 0);--    /* Calling LZ4_resetStream_fast() here makes sure that changes will not be-     * erased by subsequent calls to LZ4_resetStream_fast() in case stream was-     * marked as having dirty context, e.g. requiring full reset.-     */-    LZ4_resetStream_fast(workingStream);--    if (dictCtx != NULL) {-        /* If the current offset is zero, we will never look in the-         * external dictionary context, since there is no value a table-         * entry can take that indicate a miss. In that case, we need-         * to bump the offset to something non-zero.-         */-        if (workingStream->internal_donotuse.currentOffset == 0) {-            workingStream->internal_donotuse.currentOffset = 64 KB;-        }--        /* Don't actually attach an empty dictionary.-         */-        if (dictCtx->dictSize == 0) {-            dictCtx = NULL;-        }-    }-    workingStream->internal_donotuse.dictCtx = dictCtx;-}---static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize)-{-    assert(nextSize >= 0);-    if (LZ4_dict->currentOffset + (unsigned)nextSize > 0x80000000) {   /* potential ptrdiff_t overflow (32-bits mode) */-        /* rescale hash table */-        U32 const delta = LZ4_dict->currentOffset - 64 KB;-        const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;-        int i;-        DEBUGLOG(4, "LZ4_renormDictT");-        for (i=0; i<LZ4_HASH_SIZE_U32; i++) {-            if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;-            else LZ4_dict->hashTable[i] -= delta;-        }-        LZ4_dict->currentOffset = 64 KB;-        if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;-        LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;-    }-}---int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream,-                                const char* source, char* dest,-                                int inputSize, int maxOutputSize,-                                int acceleration)-{-    const tableType_t tableType = byU32;-    LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse;-    const BYTE* dictEnd = streamPtr->dictionary + streamPtr->dictSize;--    DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i)", inputSize);--    if (streamPtr->dirty) { return 0; } /* Uninitialized structure detected */-    LZ4_renormDictT(streamPtr, inputSize);   /* avoid index overflow */-    if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;--    /* invalidate tiny dictionaries */-    if ( (streamPtr->dictSize-1 < 4-1)   /* intentional underflow */-      && (dictEnd != (const BYTE*)source) ) {-        DEBUGLOG(5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, streamPtr->dictionary);-        streamPtr->dictSize = 0;-        streamPtr->dictionary = (const BYTE*)source;-        dictEnd = (const BYTE*)source;-    }--    /* Check overlapping input/dictionary space */-    {   const BYTE* sourceEnd = (const BYTE*) source + inputSize;-        if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) {-            streamPtr->dictSize = (U32)(dictEnd - sourceEnd);-            if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;-            if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;-            streamPtr->dictionary = dictEnd - streamPtr->dictSize;-        }-    }--    /* prefix mode : source data follows dictionary */-    if (dictEnd == (const BYTE*)source) {-        if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))-            return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration);-        else-            return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration);-    }--    /* external dictionary mode */-    {   int result;-        if (streamPtr->dictCtx) {-            /* We depend here on the fact that dictCtx'es (produced by-             * LZ4_loadDict) guarantee that their tables contain no references-             * to offsets between dictCtx->currentOffset - 64 KB and-             * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe-             * to use noDictIssue even when the dict isn't a full 64 KB.-             */-            if (inputSize > 4 KB) {-                /* For compressing large blobs, it is faster to pay the setup-                 * cost to copy the dictionary's tables into the active context,-                 * so that the compression loop is only looking into one table.-                 */-                memcpy(streamPtr, streamPtr->dictCtx, sizeof(LZ4_stream_t));-                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);-            } else {-                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration);-            }-        } else {-            if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {-                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration);-            } else {-                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);-            }-        }-        streamPtr->dictionary = (const BYTE*)source;-        streamPtr->dictSize = (U32)inputSize;-        return result;-    }-}---/* 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;-    int result;--    LZ4_renormDictT(streamPtr, srcSize);--    if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {-        result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, dictSmall, 1);-    } else {-        result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);-    }--    streamPtr->dictionary = (const BYTE*)source;-    streamPtr->dictSize = (U32)srcSize;--    return result;-}---/*! LZ4_saveDict() :- *  If previously compressed data block is not guaranteed to remain available at its memory location,- *  save it into a safer place (char* safeBuffer).- *  Note : you don't need to call LZ4_loadDict() afterwards,- *         dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue().- *  Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error.- */-int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)-{-    LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse;-    const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize;--    if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */-    if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; }--    memmove(safeBuffer, previousDictEnd - dictSize, dictSize);--    dict->dictionary = (const BYTE*)safeBuffer;-    dict->dictSize = (U32)dictSize;--    return dictSize;-}----/*-*******************************- *  Decompression functions- ********************************/--typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;-typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive;--#undef MIN-#define MIN(a,b)    ( (a) < (b) ? (a) : (b) )--/* Read the variable-length literal or match length.- *- * ip - pointer to use as input.- * lencheck - end ip.  Return an error if ip advances >= lencheck.- * loop_check - check ip >= lencheck in body of loop.  Returns loop_error if so.- * initial_check - check ip >= lencheck before start of loop.  Returns initial_error if so.- * error (output) - error code.  Should be set to 0 before call.- */-typedef enum { loop_error = -2, initial_error = -1, ok = 0 } variable_length_error;-LZ4_FORCE_INLINE unsigned-read_variable_length(const BYTE**ip, const BYTE* lencheck, int loop_check, int initial_check, variable_length_error* error)-{-  U32 length = 0;-  U32 s;-  if (initial_check && unlikely((*ip) >= lencheck)) {    /* overflow detection */-    *error = initial_error;-    return length;-  }-  do {-    s = **ip;-    (*ip)++;-    length += s;-    if (loop_check && unlikely((*ip) >= lencheck)) {    /* overflow detection */-      *error = loop_error;-      return length;-    }-  } while (s==255);--  return length;-}--/*! LZ4_decompress_generic() :- *  This generic decompression function covers all use cases.- *  It shall be instantiated several times, using different sets of directives.- *  Note that it is important for performance that this function really get inlined,- *  in order to remove useless branches during compilation optimization.- */-LZ4_FORCE_INLINE int-LZ4_decompress_generic(-                 const char* const src,-                 char* const dst,-                 int srcSize,-                 int outputSize,         /* If endOnInput==endOnInputSize, this value is `dstCapacity` */--                 endCondition_directive endOnInput,   /* endOnOutputSize, endOnInputSize */-                 earlyEnd_directive partialDecoding,  /* full, partial */-                 dict_directive dict,                 /* noDict, withPrefix64k, usingExtDict */-                 const BYTE* const lowPrefix,  /* always <= dst, == dst when no prefix */-                 const BYTE* const dictStart,  /* only if dict==usingExtDict */-                 const size_t dictSize         /* note : = 0 if noDict */-                 )-{-    if (src == NULL) { return -1; }--    {   const BYTE* ip = (const BYTE*) src;-        const BYTE* const iend = ip + srcSize;--        BYTE* op = (BYTE*) dst;-        BYTE* const oend = op + outputSize;-        BYTE* cpy;--        const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize;--        const int safeDecode = (endOnInput==endOnInputSize);-        const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));---        /* Set up the "end" pointers for the shortcut. */-        const BYTE* const shortiend = iend - (endOnInput ? 14 : 8) /*maxLL*/ - 2 /*offset*/;-        const BYTE* const shortoend = oend - (endOnInput ? 14 : 8) /*maxLL*/ - 18 /*maxML*/;--        const BYTE* match;-        size_t offset;-        unsigned token;-        size_t length;---        DEBUGLOG(5, "LZ4_decompress_generic (srcSize:%i, dstSize:%i)", srcSize, outputSize);--        /* Special cases */-        assert(lowPrefix <= op);-        if ((endOnInput) && (unlikely(outputSize==0))) {-            /* Empty output buffer */-            if (partialDecoding) return 0;-            return ((srcSize==1) && (*ip==0)) ? 0 : -1;-        }-        if ((!endOnInput) && (unlikely(outputSize==0))) { return (*ip==0 ? 1 : -1); }-        if ((endOnInput) && unlikely(srcSize==0)) { return -1; }--	/* Currently the fast loop shows a regression on qualcomm arm chips. */-#if LZ4_FAST_DEC_LOOP-        if ((oend - op) < FASTLOOP_SAFE_DISTANCE) {-            DEBUGLOG(6, "skip fast decode loop");-            goto safe_decode;-        }--        /* Fast loop : decode sequences as long as output < iend-FASTLOOP_SAFE_DISTANCE */-        while (1) {-            /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */-            assert(oend - op >= FASTLOOP_SAFE_DISTANCE);-            if (endOnInput) { assert(ip < iend); }-            token = *ip++;-            length = token >> ML_BITS;  /* literal length */--            assert(!endOnInput || ip <= iend); /* ip < iend before the increment */--            /* decode literal length */-            if (length == RUN_MASK) {-                variable_length_error error = ok;-                length += read_variable_length(&ip, iend-RUN_MASK, endOnInput, endOnInput, &error);-                if (error == initial_error) { goto _output_error; }-                if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */-                if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */--                /* copy literals */-                cpy = op+length;-                LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);-                if (endOnInput) {  /* LZ4_decompress_safe() */-                    if ((cpy>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; }-                    LZ4_wildCopy32(op, ip, cpy);-                } else {   /* LZ4_decompress_fast() */-                    if (cpy>oend-8) { goto safe_literal_copy; }-                    LZ4_wildCopy8(op, ip, cpy); /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time :-                                                 * it doesn't know input length, and only relies on end-of-block properties */-                }-                ip += length; op = cpy;-            } else {-                cpy = op+length;-                if (endOnInput) {  /* LZ4_decompress_safe() */-                    DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length);-                    /* 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; }-                    /* Literals can only be 14, but hope compilers optimize if we copy by a register size */-                    memcpy(op, ip, 16);-                } else {  /* LZ4_decompress_fast() */-                    /* LZ4_decompress_fast() cannot copy more than 8 bytes at a time :-                     * it doesn't know input length, and relies on end-of-block properties */-                    memcpy(op, ip, 8);-                    if (length > 8) { memcpy(op+8, ip+8, 8); }-                }-                ip += length; op = cpy;-            }--            /* get offset */-            offset = LZ4_readLE16(ip); ip+=2;-            match = op - offset;-            assert(match <= op);--            /* get matchlength */-            length = token & ML_MASK;--            if (length == ML_MASK) {-              variable_length_error error = ok;-              if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */-              length += read_variable_length(&ip, iend - LASTLITERALS + 1, endOnInput, 0, &error);-              if (error != ok) { goto _output_error; }-                if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */-                length += MINMATCH;-                if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {-                    goto safe_match_copy;-                }-            } else {-                length += MINMATCH;-                if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {-                    goto safe_match_copy;-                }--                /* Fastpath check: Avoids a branch in LZ4_wildCopy32 if true */-                if ((dict == withPrefix64k) || (match >= lowPrefix)) {-                    if (offset >= 8) {-                        assert(match >= lowPrefix);-                        assert(match <= op);-                        assert(op + 18 <= oend);--                        memcpy(op, match, 8);-                        memcpy(op+8, match+8, 8);-                        memcpy(op+16, match+16, 2);-                        op += length;-                        continue;-            }   }   }--            if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */-            /* match starting within external dictionary */-            if ((dict==usingExtDict) && (match < lowPrefix)) {-                if (unlikely(op+length > oend-LASTLITERALS)) {-                    if (partialDecoding) {-                        length = MIN(length, (size_t)(oend-op));  /* reach end of buffer */-                    } else {-                        goto _output_error;  /* end-of-block condition violated */-                }   }--                if (length <= (size_t)(lowPrefix-match)) {-                    /* match fits entirely within external dictionary : just copy */-                    memmove(op, dictEnd - (lowPrefix-match), length);-                    op += length;-                } else {-                    /* match stretches into both external dictionary and current block */-                    size_t const copySize = (size_t)(lowPrefix - match);-                    size_t const restSize = length - copySize;-                    memcpy(op, dictEnd - copySize, copySize);-                    op += copySize;-                    if (restSize > (size_t)(op - lowPrefix)) {  /* overlap copy */-                        BYTE* const endOfMatch = op + restSize;-                        const BYTE* copyFrom = lowPrefix;-                        while (op < endOfMatch) { *op++ = *copyFrom++; }-                    } else {-                        memcpy(op, lowPrefix, restSize);-                        op += restSize;-                }   }-                continue;-            }--            /* copy match within block */-            cpy = op + length;--            assert((op <= oend) && (oend-op >= 32));-            if (unlikely(offset<16)) {-                LZ4_memcpy_using_offset(op, match, cpy, offset);-            } else {-                LZ4_wildCopy32(op, match, cpy);-            }--            op = cpy;   /* wildcopy correction */-        }-    safe_decode:-#endif--        /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */-        while (1) {-            token = *ip++;-            length = token >> ML_BITS;  /* literal length */--            assert(!endOnInput || ip <= iend); /* ip < iend before the increment */--            /* A two-stage shortcut for the most common case:-             * 1) If the literal length is 0..14, and there is enough space,-             * enter the shortcut and copy 16 bytes on behalf of the literals-             * (in the fast mode, only 8 bytes can be safely copied this way).-             * 2) Further if the match length is 4..18, copy 18 bytes in a similar-             * manner; but we ensure that there's enough space in the output for-             * those 18 bytes earlier, upon entering the shortcut (in other words,-             * there is a combined check for both stages).-             */-            if ( (endOnInput ? length != RUN_MASK : length <= 8)-                /* strictly "less than" on input, to re-enter the loop with at least one byte */-              && likely((endOnInput ? ip < shortiend : 1) & (op <= shortoend)) ) {-                /* Copy the literals */-                memcpy(op, ip, endOnInput ? 16 : 8);-                op += length; ip += length;--                /* 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 */-                offset = LZ4_readLE16(ip); ip += 2;-                match = op - offset;-                assert(match <= op); /* check overflow */--                /* Do not deal with overlapping matches. */-                if ( (length != ML_MASK)-                  && (offset >= 8)-                  && (dict==withPrefix64k || match >= lowPrefix) ) {-                    /* Copy the match. */-                    memcpy(op + 0, match + 0, 8);-                    memcpy(op + 8, match + 8, 8);-                    memcpy(op +16, match +16, 2);-                    op += length + MINMATCH;-                    /* Both stages worked, load the next token. */-                    continue;-                }--                /* The second stage didn't work out, but the info is ready.-                 * Propel it right to the point of match copying. */-                goto _copy_match;-            }--            /* decode literal length */-            if (length == RUN_MASK) {-                variable_length_error error = ok;-                length += read_variable_length(&ip, iend-RUN_MASK, endOnInput, endOnInput, &error);-                if (error == initial_error) { goto _output_error; }-                if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */-                if ((safeDecode) && 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-            LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);-            if ( ((endOnInput) && ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) )-              || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) )-            {-                /* We've either hit the input parsing restriction or the output parsing restriction.-                 * If we've hit the input parsing condition then this must be the last sequence.-                 * If we've hit the output parsing condition then we are either using partialDecoding-                 * or we've hit the output parsing condition.-                 */-                if (partialDecoding) {-                    /* Since we are partial decoding we may be in this block because of the output parsing-                     * restriction, which is not valid since the output buffer is allowed to be undersized.-                     */-                    assert(endOnInput);-                    /* If we're in this block because of the input parsing condition, then we must be on the-                     * last sequence (or invalid), so we must check that we exactly consume the input.-                     */-                    if ((ip+length>iend-(2+1+LASTLITERALS)) && (ip+length != iend)) { goto _output_error; }-                    assert(ip+length <= iend);-                    /* We are finishing in the middle of a literals segment.-                     * Break after the copy.-                     */-                    if (cpy > oend) {-                        cpy = oend;-                        assert(op<=oend);-                        length = (size_t)(oend-op);-                    }-                    assert(ip+length <= iend);-                } else {-                    /* We must be on the last sequence because of the parsing limitations so check-                     * that we exactly regenerate the original size (must be exact when !endOnInput).-                     */-                    if ((!endOnInput) && (cpy != oend)) { goto _output_error; }-                     /* We must be on the last sequence (or invalid) because of the parsing limitations-                      * so check that we exactly consume the input and don't overrun the output buffer.-                      */-                    if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) { goto _output_error; }-                }-                memmove(op, ip, length);  /* supports overlapping memory regions, which only matters for in-place decompression scenarios */-                ip += length;-                op += length;-                /* Necessarily EOF when !partialDecoding. When partialDecoding-                 * it is EOF if we've either filled the output buffer or hit-                 * the input parsing restriction.-                 */-                if (!partialDecoding || (cpy == oend) || (ip == iend)) {-                    break;-                }-            } else {-                LZ4_wildCopy8(op, ip, cpy);   /* may overwrite up to WILDCOPYLENGTH beyond cpy */-                ip += length; op = cpy;-            }--            /* get offset */-            offset = LZ4_readLE16(ip); ip+=2;-            match = op - offset;--            /* get matchlength */-            length = token & ML_MASK;--    _copy_match:-            if (length == ML_MASK) {-              variable_length_error error = ok;-              length += read_variable_length(&ip, iend - LASTLITERALS + 1, endOnInput, 0, &error);-              if (error != ok) goto _output_error;-                if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error;   /* overflow detection */-            }-            length += MINMATCH;--#if LZ4_FAST_DEC_LOOP-        safe_match_copy:-#endif-            if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error;   /* Error : offset outside buffers */-            /* match starting within external dictionary */-            if ((dict==usingExtDict) && (match < lowPrefix)) {-                if (unlikely(op+length > oend-LASTLITERALS)) {-                    if (partialDecoding) length = MIN(length, (size_t)(oend-op));-                    else goto _output_error;   /* doesn't respect parsing restriction */-                }--                if (length <= (size_t)(lowPrefix-match)) {-                    /* match fits entirely within external dictionary : just copy */-                    memmove(op, dictEnd - (lowPrefix-match), length);-                    op += length;-                } else {-                    /* match stretches into both external dictionary and current block */-                    size_t const copySize = (size_t)(lowPrefix - match);-                    size_t const restSize = length - copySize;-                    memcpy(op, dictEnd - copySize, copySize);-                    op += copySize;-                    if (restSize > (size_t)(op - lowPrefix)) {  /* overlap copy */-                        BYTE* const endOfMatch = op + restSize;-                        const BYTE* copyFrom = lowPrefix;-                        while (op < endOfMatch) *op++ = *copyFrom++;-                    } else {-                        memcpy(op, lowPrefix, restSize);-                        op += restSize;-                }   }-                continue;-            }-            assert(match >= lowPrefix);--            /* copy match within block */-            cpy = op + length;--            /* partialDecoding : may end anywhere within the block */-            assert(op<=oend);-            if (partialDecoding && (cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {-                size_t const mlen = MIN(length, (size_t)(oend-op));-                const BYTE* const matchEnd = match + mlen;-                BYTE* const copyEnd = op + mlen;-                if (matchEnd > op) {   /* overlap copy */-                    while (op < copyEnd) { *op++ = *match++; }-                } else {-                    memcpy(op, match, mlen);-                }-                op = copyEnd;-                if (op == oend) { break; }-                continue;-            }--            if (unlikely(offset<8)) {-                LZ4_write32(op, 0);   /* silence msan warning when offset==0 */-                op[0] = match[0];-                op[1] = match[1];-                op[2] = match[2];-                op[3] = match[3];-                match += inc32table[offset];-                memcpy(op+4, match, 4);-                match -= dec64table[offset];-            } else {-                memcpy(op, match, 8);-                match += 8;-            }-            op += 8;--            if (unlikely(cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {-                BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1);-                if (cpy > oend-LASTLITERALS) { goto _output_error; } /* Error : last LASTLITERALS bytes must be literals (uncompressed) */-                if (op < oCopyLimit) {-                    LZ4_wildCopy8(op, match, oCopyLimit);-                    match += oCopyLimit - op;-                    op = oCopyLimit;-                }-                while (op < cpy) { *op++ = *match++; }-            } else {-                memcpy(op, match, 8);-                if (length > 16)  { LZ4_wildCopy8(op+8, match+8, cpy); }-            }-            op = cpy;   /* wildcopy correction */-        }--        /* end of decoding */-        if (endOnInput) {-           return (int) (((char*)op)-dst);     /* Nb of output bytes decoded */-       } else {-           return (int) (((const char*)ip)-src);   /* Nb of input bytes read */-       }--        /* Overflow error detected */-    _output_error:-        return (int) (-(((const char*)ip)-src))-1;-    }-}---/*===== Instantiate the API decoding functions. =====*/--LZ4_FORCE_O2_GCC_PPC64LE-int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)-{-    return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize,-                                  endOnInputSize, decode_full_block, noDict,-                                  (BYTE*)dest, NULL, 0);-}--LZ4_FORCE_O2_GCC_PPC64LE-int LZ4_decompress_safe_partial(const char* src, char* dst, int compressedSize, int targetOutputSize, int dstCapacity)-{-    dstCapacity = MIN(targetOutputSize, dstCapacity);-    return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity,-                                  endOnInputSize, partial_decode,-                                  noDict, (BYTE*)dst, NULL, 0);-}--LZ4_FORCE_O2_GCC_PPC64LE-int LZ4_decompress_fast(const char* source, char* dest, int originalSize)-{-    return LZ4_decompress_generic(source, dest, 0, originalSize,-                                  endOnOutputSize, decode_full_block, withPrefix64k,-                                  (BYTE*)dest - 64 KB, NULL, 0);-}--/*===== Instantiate a few more decoding cases, used more than once. =====*/--LZ4_FORCE_O2_GCC_PPC64LE /* Exported, an obsolete API function. */-int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)-{-    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,-                                  endOnInputSize, decode_full_block, withPrefix64k,-                                  (BYTE*)dest - 64 KB, NULL, 0);-}--/* Another obsolete API function, paired with the previous one. */-int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)-{-    /* LZ4_decompress_fast doesn't validate match offsets,-     * and thus serves well with any prefixed dictionary. */-    return LZ4_decompress_fast(source, dest, originalSize);-}--LZ4_FORCE_O2_GCC_PPC64LE-static int LZ4_decompress_safe_withSmallPrefix(const char* source, char* dest, int compressedSize, int maxOutputSize,-                                               size_t prefixSize)-{-    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,-                                  endOnInputSize, decode_full_block, noDict,-                                  (BYTE*)dest-prefixSize, NULL, 0);-}--LZ4_FORCE_O2_GCC_PPC64LE-int LZ4_decompress_safe_forceExtDict(const char* source, char* dest,-                                     int compressedSize, int maxOutputSize,-                                     const void* dictStart, size_t dictSize)-{-    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,-                                  endOnInputSize, decode_full_block, usingExtDict,-                                  (BYTE*)dest, (const BYTE*)dictStart, dictSize);-}--LZ4_FORCE_O2_GCC_PPC64LE-static int LZ4_decompress_fast_extDict(const char* source, char* dest, int originalSize,-                                       const void* dictStart, size_t dictSize)-{-    return LZ4_decompress_generic(source, dest, 0, originalSize,-                                  endOnOutputSize, decode_full_block, usingExtDict,-                                  (BYTE*)dest, (const BYTE*)dictStart, dictSize);-}--/* The "double dictionary" mode, for use with e.g. ring buffers: the first part- * of the dictionary is passed as prefix, and the second via dictStart + dictSize.- * These routines are used only once, in LZ4_decompress_*_continue().- */-LZ4_FORCE_INLINE-int LZ4_decompress_safe_doubleDict(const char* source, char* dest, int compressedSize, int maxOutputSize,-                                   size_t prefixSize, const void* dictStart, size_t dictSize)-{-    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,-                                  endOnInputSize, decode_full_block, usingExtDict,-                                  (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize);-}--LZ4_FORCE_INLINE-int LZ4_decompress_fast_doubleDict(const char* source, char* dest, int originalSize,-                                   size_t prefixSize, const void* dictStart, size_t dictSize)-{-    return LZ4_decompress_generic(source, dest, 0, originalSize,-                                  endOnOutputSize, decode_full_block, usingExtDict,-                                  (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize);-}--/*===== streaming decompression functions =====*/--LZ4_streamDecode_t* LZ4_createStreamDecode(void)-{-    LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t));-    LZ4_STATIC_ASSERT(LZ4_STREAMDECODESIZE >= sizeof(LZ4_streamDecode_t_internal));    /* A compilation error here means LZ4_STREAMDECODESIZE is not large enough */-    return lz4s;-}--int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)-{-    if (LZ4_stream == NULL) { return 0; }  /* support free on NULL */-    FREEMEM(LZ4_stream);-    return 0;-}--/*! LZ4_setStreamDecode() :- *  Use this function to instruct where to find the dictionary.- *  This function is not necessary if previous data is still available where it was decoded.- *  Loading a size of 0 is allowed (same effect as no dictionary).- * @return : 1 if OK, 0 if error- */-int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)-{-    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;-    lz4sd->prefixSize = (size_t) dictSize;-    lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;-    lz4sd->externalDict = NULL;-    lz4sd->extDictSize  = 0;-    return 1;-}--/*! LZ4_decoderRingBufferSize() :- *  when setting a ring buffer for streaming decompression (optional scenario),- *  provides the minimum size of this ring buffer- *  to be compatible with any source respecting maxBlockSize condition.- *  Note : in a ring buffer scenario,- *  blocks are presumed decompressed next to each other.- *  When not enough space remains for next block (remainingSize < maxBlockSize),- *  decoding resumes from beginning of ring buffer.- * @return : minimum ring buffer size,- *           or 0 if there is an error (invalid maxBlockSize).- */-int LZ4_decoderRingBufferSize(int maxBlockSize)-{-    if (maxBlockSize < 0) return 0;-    if (maxBlockSize > LZ4_MAX_INPUT_SIZE) return 0;-    if (maxBlockSize < 16) maxBlockSize = 16;-    return LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize);-}--/*-*_continue() :-    These decoding functions allow decompression of multiple blocks in "streaming" mode.-    Previously decoded blocks must still be available at the memory position where they were decoded.-    If it's not possible, save the relevant part of decoded data into a safe buffer,-    and indicate where it stands using LZ4_setStreamDecode()-*/-LZ4_FORCE_O2_GCC_PPC64LE-int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)-{-    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;-    int result;--    if (lz4sd->prefixSize == 0) {-        /* The first call, no dictionary yet. */-        assert(lz4sd->extDictSize == 0);-        result = LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);-        if (result <= 0) return result;-        lz4sd->prefixSize = (size_t)result;-        lz4sd->prefixEnd = (BYTE*)dest + result;-    } else if (lz4sd->prefixEnd == (BYTE*)dest) {-        /* They're rolling the current segment. */-        if (lz4sd->prefixSize >= 64 KB - 1)-            result = LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);-        else if (lz4sd->extDictSize == 0)-            result = LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize,-                                                         lz4sd->prefixSize);-        else-            result = LZ4_decompress_safe_doubleDict(source, dest, compressedSize, maxOutputSize,-                                                    lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);-        if (result <= 0) return result;-        lz4sd->prefixSize += (size_t)result;-        lz4sd->prefixEnd  += result;-    } else {-        /* The buffer wraps around, or they're switching to another buffer. */-        lz4sd->extDictSize = lz4sd->prefixSize;-        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;-        result = LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize,-                                                  lz4sd->externalDict, lz4sd->extDictSize);-        if (result <= 0) return result;-        lz4sd->prefixSize = (size_t)result;-        lz4sd->prefixEnd  = (BYTE*)dest + result;-    }--    return result;-}--LZ4_FORCE_O2_GCC_PPC64LE-int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize)-{-    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;-    int result;-    assert(originalSize >= 0);--    if (lz4sd->prefixSize == 0) {-        assert(lz4sd->extDictSize == 0);-        result = LZ4_decompress_fast(source, dest, originalSize);-        if (result <= 0) return result;-        lz4sd->prefixSize = (size_t)originalSize;-        lz4sd->prefixEnd = (BYTE*)dest + originalSize;-    } else if (lz4sd->prefixEnd == (BYTE*)dest) {-        if (lz4sd->prefixSize >= 64 KB - 1 || lz4sd->extDictSize == 0)-            result = LZ4_decompress_fast(source, dest, originalSize);-        else-            result = LZ4_decompress_fast_doubleDict(source, dest, originalSize,-                                                    lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);-        if (result <= 0) return result;-        lz4sd->prefixSize += (size_t)originalSize;-        lz4sd->prefixEnd  += originalSize;-    } else {-        lz4sd->extDictSize = lz4sd->prefixSize;-        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;-        result = LZ4_decompress_fast_extDict(source, dest, originalSize,-                                             lz4sd->externalDict, lz4sd->extDictSize);-        if (result <= 0) return result;-        lz4sd->prefixSize = (size_t)originalSize;-        lz4sd->prefixEnd  = (BYTE*)dest + originalSize;-    }--    return result;-}---/*-Advanced decoding functions :-*_usingDict() :-    These decoding functions work the same as "_continue" ones,-    the dictionary must be explicitly provided within parameters-*/--int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)-{-    if (dictSize==0)-        return LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);-    if (dictStart+dictSize == dest) {-        if (dictSize >= 64 KB - 1) {-            return LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);-        }-        assert(dictSize >= 0);-        return LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, (size_t)dictSize);-    }-    assert(dictSize >= 0);-    return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, dictStart, (size_t)dictSize);-}--int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)-{-    if (dictSize==0 || dictStart+dictSize == dest)-        return LZ4_decompress_fast(source, dest, originalSize);-    assert(dictSize >= 0);-    return LZ4_decompress_fast_extDict(source, dest, originalSize, dictStart, (size_t)dictSize);-}---/*=*************************************************-*  Obsolete Functions-***************************************************/-/* obsolete compression functions */-int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize)-{-    return LZ4_compress_default(source, dest, inputSize, maxOutputSize);-}-int LZ4_compress(const char* src, char* dest, int srcSize)-{-    return LZ4_compress_default(src, dest, srcSize, LZ4_compressBound(srcSize));-}-int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize)-{-    return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1);-}-int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize)-{-    return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1);-}-int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int dstCapacity)-{-    return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, dstCapacity, 1);-}-int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize)-{-    return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1);-}--/*-These decompression functions are deprecated and should no longer be used.-They are only provided here for compatibility with older user programs.-- LZ4_uncompress is totally equivalent to LZ4_decompress_fast-- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe-*/-int LZ4_uncompress (const char* source, char* dest, int outputSize)-{-    return LZ4_decompress_fast(source, dest, outputSize);-}-int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize)-{-    return LZ4_decompress_safe(source, dest, isize, maxOutputSize);-}--/* Obsolete Streaming functions */--int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; }--int LZ4_resetStreamState(void* state, char* inputBuffer)-{-    (void)inputBuffer;-    LZ4_resetStream((LZ4_stream_t*)state);-    return 0;-}--void* LZ4_create (char* inputBuffer)-{-    (void)inputBuffer;-    return LZ4_createStream();-}+   Copyright (C) 2011-2020, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++   You can contact the author at :+    - LZ4 homepage : http://www.lz4.org+    - LZ4 source repository : https://github.com/lz4/lz4+*/++/*-************************************+*  Tuning parameters+**************************************/+/*+ * LZ4_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()).+ */+#ifndef LZ4_HEAPMODE+#  define LZ4_HEAPMODE 0+#endif++/*+ * LZ4_ACCELERATION_DEFAULT :+ * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0+ */+#define LZ4_ACCELERATION_DEFAULT 1+/*+ * LZ4_ACCELERATION_MAX :+ * Any "acceleration" value higher than this threshold+ * get treated as LZ4_ACCELERATION_MAX instead (fix #876)+ */+#define LZ4_ACCELERATION_MAX 65537+++/*-************************************+*  CPU Feature Detection+**************************************/+/* LZ4_FORCE_MEMORY_ACCESS+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.+ * The below switch allow to select different access method for improved performance.+ * Method 0 (default) : use `memcpy()`. Safe and portable.+ * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).+ *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.+ * Method 2 : direct access. This method is portable but violate C standard.+ *            It can generate buggy code on targets which assembly generation depends on alignment.+ *            But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)+ * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.+ * Prefer these methods in priority order (0 > 1 > 2)+ */+#ifndef LZ4_FORCE_MEMORY_ACCESS   /* can be defined externally */+#  if defined(__GNUC__) && \+  ( 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__)+#    define LZ4_FORCE_MEMORY_ACCESS 1+#  endif+#endif++/*+ * LZ4_FORCE_SW_BITCOUNT+ * Define this parameter if your target system or compiler does not support hardware bit count+ */+#if defined(_MSC_VER) && defined(_WIN32_WCE)   /* Visual Studio for WinCE doesn't support Hardware bit count */+#  undef  LZ4_FORCE_SW_BITCOUNT  /* avoid double def */+#  define LZ4_FORCE_SW_BITCOUNT+#endif++++/*-************************************+*  Dependency+**************************************/+/*+ * LZ4_SRC_INCLUDED:+ * Amalgamation flag, whether lz4.c is included+ */+#ifndef LZ4_SRC_INCLUDED+#  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 */+#endif++#define LZ4_STATIC_LINKING_ONLY  /* LZ4_DISTANCE_MAX */+#include "lz4.h"+/* see also "memory routines" below */+++/*-************************************+*  Compiler Options+**************************************/+#if defined(_MSC_VER) && (_MSC_VER >= 1400)  /* Visual Studio 2005+ */+#  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 */+#endif  /* _MSC_VER */++#ifndef LZ4_FORCE_INLINE+#  ifdef _MSC_VER    /* Visual Studio */+#    define LZ4_FORCE_INLINE static __forceinline+#  else+#    if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */+#      ifdef __GNUC__+#        define LZ4_FORCE_INLINE static inline __attribute__((always_inline))+#      else+#        define LZ4_FORCE_INLINE static inline+#      endif+#    else+#      define LZ4_FORCE_INLINE static+#    endif /* __STDC_VERSION__ */+#  endif  /* _MSC_VER */+#endif /* LZ4_FORCE_INLINE */++/* LZ4_FORCE_O2 and LZ4_FORCE_INLINE+ * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8,+ * together with a simple 8-byte copy loop as a fall-back path.+ * However, this optimization hurts the decompression speed by >30%,+ * because the execution does not go to the optimized loop+ * for typical compressible data, and all of the preamble checks+ * before going to the fall-back path become useless overhead.+ * This optimization happens only with the -O3 flag, and -O2 generates+ * a simple 8-byte copy loop.+ * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy8+ * functions are annotated with __attribute__((optimize("O2"))),+ * and also LZ4_wildCopy8 is forcibly inlined, so that the O2 attribute+ * of LZ4_wildCopy8 does not affect the compression speed.+ */+#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__)+#  define LZ4_FORCE_O2  __attribute__((optimize("O2")))+#  undef LZ4_FORCE_INLINE+#  define LZ4_FORCE_INLINE  static __inline __attribute__((optimize("O2"),always_inline))+#else+#  define LZ4_FORCE_O2+#endif++#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)+#  define expect(expr,value)    (__builtin_expect ((expr),(value)) )+#else+#  define expect(expr,value)    (expr)+#endif++#ifndef likely+#define likely(expr)     expect((expr) != 0, 1)+#endif+#ifndef unlikely+#define unlikely(expr)   expect((expr) != 0, 0)+#endif++/* Should the alignment test prove unreliable, for some reason,+ * it can be disabled by setting LZ4_ALIGN_TEST to 0 */+#ifndef LZ4_ALIGN_TEST  /* can be externally provided */+# define LZ4_ALIGN_TEST 1+#endif+++/*-************************************+*  Memory routines+**************************************/++/*! LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION :+ *  Disable relatively high-level LZ4/HC functions that use dynamic memory+ *  allocation functions (malloc(), calloc(), free()).+ *+ *  Note that this is a compile-time switch. And since it disables+ *  public/stable LZ4 v1 API functions, we don't recommend using this+ *  symbol to generate a library for distribution.+ *+ *  The following public functions are removed when this symbol is defined.+ *  - lz4   : LZ4_createStream, LZ4_freeStream,+ *            LZ4_createStreamDecode, LZ4_freeStreamDecode, LZ4_create (deprecated)+ *  - lz4hc : LZ4_createStreamHC, LZ4_freeStreamHC,+ *            LZ4_createHC (deprecated), LZ4_freeHC  (deprecated)+ *  - lz4frame, lz4file : All LZ4F_* functions+ */+#if defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)+#  define ALLOC(s)          lz4_error_memory_allocation_is_disabled+#  define ALLOC_AND_ZERO(s) lz4_error_memory_allocation_is_disabled+#  define FREEMEM(p)        lz4_error_memory_allocation_is_disabled+#elif defined(LZ4_USER_MEMORY_FUNCTIONS)+/* memory management functions can be customized by user project.+ * Below functions must exist somewhere in the Project+ * and be available at link time */+void* LZ4_malloc(size_t s);+void* LZ4_calloc(size_t n, size_t s);+void  LZ4_free(void* p);+# define ALLOC(s)          LZ4_malloc(s)+# define ALLOC_AND_ZERO(s) LZ4_calloc(1,s)+# define FREEMEM(p)        LZ4_free(p)+#else+# include <stdlib.h>   /* malloc, calloc, free */+# define ALLOC(s)          malloc(s)+# define ALLOC_AND_ZERO(s) calloc(1,s)+# define FREEMEM(p)        free(p)+#endif++#if ! LZ4_FREESTANDING+#  include <string.h>   /* memset, memcpy */+#endif+#if !defined(LZ4_memset)+#  define LZ4_memset(p,v,s) memset((p),(v),(s))+#endif+#define MEM_INIT(p,v,s)   LZ4_memset((p),(v),(s))+++/*-************************************+*  Common Constants+**************************************/+#define MINMATCH 4++#define WILDCOPYLENGTH 8+#define LASTLITERALS   5   /* see ../doc/lz4_Block_format.md#parsing-restrictions */+#define MFLIMIT       12   /* see ../doc/lz4_Block_format.md#parsing-restrictions */+#define MATCH_SAFEGUARD_DISTANCE  ((2*WILDCOPYLENGTH) - MINMATCH)   /* ensure it's possible to write 2 x wildcopyLength without overflowing output buffer */+#define FASTLOOP_SAFE_DISTANCE 64+static const int LZ4_minLength = (MFLIMIT+1);++#define KB *(1 <<10)+#define MB *(1 <<20)+#define GB *(1U<<30)++#define LZ4_DISTANCE_ABSOLUTE_MAX 65535+#if (LZ4_DISTANCE_MAX > LZ4_DISTANCE_ABSOLUTE_MAX)   /* max supported by LZ4 format */+#  error "LZ4_DISTANCE_MAX is too big : must be <= 65535"+#endif++#define ML_BITS  4+#define ML_MASK  ((1U<<ML_BITS)-1)+#define RUN_BITS (8-ML_BITS)+#define RUN_MASK ((1U<<RUN_BITS)-1)+++/*-************************************+*  Error detection+**************************************/+#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=1)+#  include <assert.h>+#else+#  ifndef assert+#    define assert(condition) ((void)0)+#  endif+#endif++#define LZ4_STATIC_ASSERT(c)   { enum { LZ4_static_assert = 1/(int)(!!(c)) }; }   /* use after variable declarations */++#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2)+#  include <stdio.h>+   static int g_debuglog_enable = 1;+#  define DEBUGLOG(l, ...) {                          \+        if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) {  \+            fprintf(stderr, __FILE__ ": ");           \+            fprintf(stderr, __VA_ARGS__);             \+            fprintf(stderr, " \n");                   \+    }   }+#else+#  define DEBUGLOG(l, ...) {}    /* disabled */+#endif++static int LZ4_isAligned(const void* ptr, size_t alignment)+{+    return ((size_t)ptr & (alignment -1)) == 0;+}+++/*-************************************+*  Types+**************************************/+#include <limits.h>+#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)+# include <stdint.h>+  typedef  uint8_t BYTE;+  typedef uint16_t U16;+  typedef uint32_t U32;+  typedef  int32_t S32;+  typedef uint64_t U64;+  typedef uintptr_t uptrval;+#else+# if UINT_MAX != 4294967295UL+#   error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4"+# endif+  typedef unsigned char       BYTE;+  typedef unsigned short      U16;+  typedef unsigned int        U32;+  typedef   signed int        S32;+  typedef unsigned long long  U64;+  typedef size_t              uptrval;   /* generally true, except OpenVMS-64 */+#endif++#if defined(__x86_64__)+  typedef U64    reg_t;   /* 64-bits in x32 mode */+#else+  typedef size_t reg_t;   /* 32-bits in x32 mode */+#endif++typedef enum {+    notLimited = 0,+    limitedOutput = 1,+    fillOutput = 2+} limitedOutput_directive;+++/*-************************************+*  Reading and writing into memory+**************************************/++/**+ * LZ4 relies on memcpy with a constant size being inlined. In freestanding+ * environments, the compiler can't assume the implementation of memcpy() is+ * standard compliant, so it can't apply its specialized memcpy() inlining+ * logic. When possible, use __builtin_memcpy() to tell the compiler to analyze+ * memcpy() as if it were standard compliant, so it can inline it in freestanding+ * environments. This is needed when decompressing the Linux Kernel, for example.+ */+#if !defined(LZ4_memcpy)+#  if defined(__GNUC__) && (__GNUC__ >= 4)+#    define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size)+#  else+#    define LZ4_memcpy(dst, src, size) memcpy(dst, src, size)+#  endif+#endif++#if !defined(LZ4_memmove)+#  if defined(__GNUC__) && (__GNUC__ >= 4)+#    define LZ4_memmove __builtin_memmove+#  else+#    define LZ4_memmove memmove+#  endif+#endif++static unsigned LZ4_isLittleEndian(void)+{+    const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental */+    return one.c[0];+}+++#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)+/* lie to the compiler about data alignment; use with caution */++static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; }+static U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; }+static reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; }++static void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }+static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }++#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1)++/* __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;++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 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; }++#else  /* safe and portable access using memcpy() */++static U16 LZ4_read16(const void* memPtr)+{+    U16 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;+}++static U32 LZ4_read32(const void* memPtr)+{+    U32 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;+}++static reg_t LZ4_read_ARCH(const void* memPtr)+{+    reg_t val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;+}++static void LZ4_write16(void* memPtr, U16 value)+{+    LZ4_memcpy(memPtr, &value, sizeof(value));+}++static void LZ4_write32(void* memPtr, U32 value)+{+    LZ4_memcpy(memPtr, &value, sizeof(value));+}++#endif /* LZ4_FORCE_MEMORY_ACCESS */+++static U16 LZ4_readLE16(const void* memPtr)+{+    if (LZ4_isLittleEndian()) {+        return LZ4_read16(memPtr);+    } else {+        const BYTE* p = (const BYTE*)memPtr;+        return (U16)((U16)p[0] + (p[1]<<8));+    }+}++static void LZ4_writeLE16(void* memPtr, U16 value)+{+    if (LZ4_isLittleEndian()) {+        LZ4_write16(memPtr, value);+    } else {+        BYTE* p = (BYTE*)memPtr;+        p[0] = (BYTE) value;+        p[1] = (BYTE)(value>>8);+    }+}++/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */+LZ4_FORCE_INLINE+void LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd)+{+    BYTE* d = (BYTE*)dstPtr;+    const BYTE* s = (const BYTE*)srcPtr;+    BYTE* const e = (BYTE*)dstEnd;++    do { LZ4_memcpy(d,s,8); d+=8; s+=8; } while (d<e);+}++static const unsigned inc32table[8] = {0, 1, 2,  1,  0,  4, 4, 4};+static const int      dec64table[8] = {0, 0, 0, -1, -4,  1, 2, 3};+++#ifndef LZ4_FAST_DEC_LOOP+#  if defined __i386__ || defined _M_IX86 || defined __x86_64__ || defined _M_X64+#    define LZ4_FAST_DEC_LOOP 1+#  elif defined(__aarch64__) && defined(__APPLE__)+#    define LZ4_FAST_DEC_LOOP 1+#  elif defined(__aarch64__) && !defined(__clang__)+     /* On non-Apple aarch64, we disable this optimization for clang because+      * on certain mobile chipsets, performance is reduced with clang. For+      * more information refer to https://github.com/lz4/lz4/pull/707 */+#    define LZ4_FAST_DEC_LOOP 1+#  else+#    define LZ4_FAST_DEC_LOOP 0+#  endif+#endif++#if LZ4_FAST_DEC_LOOP++LZ4_FORCE_INLINE void+LZ4_memcpy_using_offset_base(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)+{+    assert(srcPtr + offset == dstPtr);+    if (offset < 8) {+        LZ4_write32(dstPtr, 0);   /* silence an msan warning when offset==0 */+        dstPtr[0] = srcPtr[0];+        dstPtr[1] = srcPtr[1];+        dstPtr[2] = srcPtr[2];+        dstPtr[3] = srcPtr[3];+        srcPtr += inc32table[offset];+        LZ4_memcpy(dstPtr+4, srcPtr, 4);+        srcPtr -= dec64table[offset];+        dstPtr += 8;+    } else {+        LZ4_memcpy(dstPtr, srcPtr, 8);+        dstPtr += 8;+        srcPtr += 8;+    }++    LZ4_wildCopy8(dstPtr, srcPtr, dstEnd);+}++/* customized variant of memcpy, which can overwrite up to 32 bytes beyond dstEnd+ * this version copies two times 16 bytes (instead of one time 32 bytes)+ * because it must be compatible with offsets >= 16. */+LZ4_FORCE_INLINE void+LZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd)+{+    BYTE* d = (BYTE*)dstPtr;+    const BYTE* s = (const BYTE*)srcPtr;+    BYTE* const e = (BYTE*)dstEnd;++    do { LZ4_memcpy(d,s,16); LZ4_memcpy(d+16,s+16,16); d+=32; s+=32; } while (d<e);+}++/* LZ4_memcpy_using_offset()  presumes :+ * - dstEnd >= dstPtr + MINMATCH+ * - there is at least 8 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)+{+    BYTE v[8];++    assert(dstEnd >= dstPtr + MINMATCH);++    switch(offset) {+    case 1:+        MEM_INIT(v, *srcPtr, 8);+        break;+    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 */+#  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 */+#  pragma warning(pop)+#endif+        break;+    case 4:+        LZ4_memcpy(v, srcPtr, 4);+        LZ4_memcpy(&v[4], srcPtr, 4);+        break;+    default:+        LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset);+        return;+    }++    LZ4_memcpy(dstPtr, v, 8);+    dstPtr += 8;+    while (dstPtr < dstEnd) {+        LZ4_memcpy(dstPtr, v, 8);+        dstPtr += 8;+    }+}+#endif+++/*-************************************+*  Common functions+**************************************/+static unsigned LZ4_NbCommonBytes (reg_t val)+{+    assert(val != 0);+    if (LZ4_isLittleEndian()) {+        if (sizeof(val) == 8) {+#       if defined(_MSC_VER) && (_MSC_VER >= 1800) && (defined(_M_AMD64) && !defined(_M_ARM64EC)) && !defined(LZ4_FORCE_SW_BITCOUNT)+/*-*************************************************************************************************+* ARM64EC is a Microsoft-designed ARM64 ABI compatible with AMD64 applications on ARM64 Windows 11.+* The ARM64EC ABI does not support AVX/AVX2/AVX512 instructions, nor their relevant intrinsics+* including _tzcnt_u64. Therefore, we need to neuter the _tzcnt_u64 code path for ARM64EC.+****************************************************************************************************/+#         if defined(__clang__) && (__clang_major__ < 10)+            /* Avoid undefined clang-cl intrinsics issue.+             * See https://github.com/lz4/lz4/pull/1017 for details. */+            return (unsigned)__builtin_ia32_tzcnt_u64(val) >> 3;+#         else+            /* x64 CPUS without BMI support interpret `TZCNT` as `REP BSF` */+            return (unsigned)_tzcnt_u64(val) >> 3;+#         endif+#       elif defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)+            unsigned long r = 0;+            _BitScanForward64(&r, (U64)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_ctzll((U64)val) >> 3;+#       else+            const U64 m = 0x0101010101010101ULL;+            val ^= val - 1;+            return (unsigned)(((U64)((val & (m - 1)) * m)) >> 56);+#       endif+        } else /* 32 bits */ {+#       if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)+            unsigned long r;+            _BitScanForward(&r, (U32)val);+            return (unsigned)r >> 3;+#       elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \+                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \+                        !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT)+            return (unsigned)__builtin_ctz((U32)val) >> 3;+#       else+            const U32 m = 0x01010101;+            return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24;+#       endif+        }+    } else   /* Big Endian CPU */ {+        if (sizeof(val)==8) {+#       if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \+                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \+                        !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT)+            return (unsigned)__builtin_clzll((U64)val) >> 3;+#       else+#if 1+            /* this method is probably faster,+             * but adds a 128 bytes lookup table */+            static const unsigned char ctz7_tab[128] = {+                7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,+                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,+                5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,+                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,+                6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,+                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,+                5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,+                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,+            };+            U64 const mask = 0x0101010101010101ULL;+            U64 const t = (((val >> 8) - mask) | val) & mask;+            return ctz7_tab[(t * 0x0080402010080402ULL) >> 57];+#else+            /* this method doesn't consume memory space like the previous one,+             * but it contains several branches,+             * that may end up slowing execution */+            static const U32 by32 = sizeof(val)*4;  /* 32 on 64 bits (goal), 16 on 32 bits.+            Just to avoid some static analyzer complaining about shift by 32 on 32-bits target.+            Note that this code path is never triggered in 32-bits mode. */+            unsigned r;+            if (!(val>>by32)) { r=4; } else { r=0; val>>=by32; }+            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }+            r += (!val);+            return r;+#endif+#       endif+        } else /* 32 bits */ {+#       if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \+                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \+                                        !defined(LZ4_FORCE_SW_BITCOUNT)+            return (unsigned)__builtin_clz((U32)val) >> 3;+#       else+            val >>= 8;+            val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) |+              (val + 0x00FF0000)) >> 24;+            return (unsigned)val ^ 3;+#       endif+        }+    }+}+++#define STEPSIZE sizeof(reg_t)+LZ4_FORCE_INLINE+unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)+{+    const BYTE* const pStart = pIn;++    if (likely(pIn < pInLimit-(STEPSIZE-1))) {+        reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);+        if (!diff) {+            pIn+=STEPSIZE; pMatch+=STEPSIZE;+        } else {+            return LZ4_NbCommonBytes(diff);+    }   }++    while (likely(pIn < pInLimit-(STEPSIZE-1))) {+        reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);+        if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }+        pIn += LZ4_NbCommonBytes(diff);+        return (unsigned)(pIn - pStart);+    }++    if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }+    if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }+    if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;+    return (unsigned)(pIn - pStart);+}+++#ifndef LZ4_COMMONDEFS_ONLY+/*-************************************+*  Local Constants+**************************************/+static const int LZ4_64Klimit = ((64 KB) + (MFLIMIT-1));+static const U32 LZ4_skipTrigger = 6;  /* Increase this value ==> compression run slower on incompressible data */+++/*-************************************+*  Local Structures and types+**************************************/+typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t;++/**+ * This enum distinguishes several different modes of accessing previous+ * content in the stream.+ *+ * - noDict        : There is no preceding content.+ * - withPrefix64k : Table entries up to ctx->dictSize before the current blob+ *                   blob being compressed are valid and refer to the preceding+ *                   content (of length ctx->dictSize), which is available+ *                   contiguously preceding in memory the content currently+ *                   being compressed.+ * - usingExtDict  : Like withPrefix64k, but the preceding content is somewhere+ *                   else in memory, starting at ctx->dictionary with length+ *                   ctx->dictSize.+ * - usingDictCtx  : Everything concerning the preceding content is+ *                   in a separate context, pointed to by ctx->dictCtx.+ *                   ctx->dictionary, ctx->dictSize, and table entries+ *                   in the current context that refer to positions+ *                   preceding the beginning of the current compression are+ *                   ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx+ *                   ->dictSize describe the location and size of the preceding+ *                   content, and matches are found by looking in the ctx+ *                   ->dictCtx->hashTable.+ */+typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive;+typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;+++/*-************************************+*  Local Utils+**************************************/+int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }+const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; }+int LZ4_compressBound(int isize)  { return LZ4_COMPRESSBOUND(isize); }+int LZ4_sizeofState(void) { return sizeof(LZ4_stream_t); }+++/*-****************************************+*  Internal Definitions, used only in Tests+*******************************************/+#if defined (__cplusplus)+extern "C" {+#endif++int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize);++int LZ4_decompress_safe_forceExtDict(const char* source, char* dest,+                                     int compressedSize, int maxOutputSize,+                                     const void* dictStart, size_t dictSize);+int LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest,+                                     int compressedSize, int targetOutputSize, int dstCapacity,+                                     const void* dictStart, size_t dictSize);+#if defined (__cplusplus)+}+#endif++/*-******************************+*  Compression functions+********************************/+LZ4_FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType)+{+    if (tableType == byU16)+        return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));+    else+        return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));+}++LZ4_FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType)+{+    const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;+    if (LZ4_isLittleEndian()) {+        const U64 prime5bytes = 889523592379ULL;+        return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));+    } else {+        const U64 prime8bytes = 11400714785074694791ULL;+        return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));+    }+}++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);+    return LZ4_hash4(LZ4_read32(p), tableType);+}++LZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType)+{+    switch (tableType)+    {+    default: /* fallthrough */+    case clearedTable: { /* illegal! */ assert(0); return; }+    case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = NULL; return; }+    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = 0; return; }+    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = 0; return; }+    }+}++LZ4_FORCE_INLINE void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType)+{+    switch (tableType)+    {+    default: /* fallthrough */+    case clearedTable: /* fallthrough */+    case byPtr: { /* illegal! */ assert(0); return; }+    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; }+    case byU16: { U16* hashTable = (U16*) tableBase; assert(idx < 65536); hashTable[h] = (U16)idx; return; }+    }+}++LZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h,+                                  void* tableBase, tableType_t const tableType,+                            const BYTE* srcBase)+{+    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; }+    }+}++LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)+{+    U32 const h = LZ4_hashPosition(p, tableType);+    LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);+}++/* LZ4_getIndexOnHash() :+ * Index of match position registered in hash table.+ * hash position must be calculated by using base+index, or dictBase+index.+ * Assumption 1 : only valid if tableType == byU32 or byU16.+ * Assumption 2 : h is presumed valid (within limits of hash table)+ */+LZ4_FORCE_INLINE U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType)+{+    LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2);+    if (tableType == byU32) {+        const U32* const hashTable = (const U32*) tableBase;+        assert(h < (1U << (LZ4_MEMORY_USAGE-2)));+        return hashTable[h];+    }+    if (tableType == byU16) {+        const U16* const hashTable = (const U16*) tableBase;+        assert(h < (1U << (LZ4_MEMORY_USAGE-1)));+        return hashTable[h];+    }+    assert(0); return 0;  /* forbidden case */+}++static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType, const BYTE* srcBase)+{+    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 */+}++LZ4_FORCE_INLINE const BYTE*+LZ4_getPosition(const BYTE* p,+                const void* tableBase, tableType_t tableType,+                const BYTE* srcBase)+{+    U32 const h = LZ4_hashPosition(p, tableType);+    return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);+}++LZ4_FORCE_INLINE void+LZ4_prepareTable(LZ4_stream_t_internal* const cctx,+           const int inputSize,+           const tableType_t tableType) {+    /* If the table hasn't been used, it's guaranteed to be zeroed out, and is+     * therefore safe to use no matter what mode we're in. Otherwise, we figure+     * out if it's safe to leave as is or whether it needs to be reset.+     */+    if ((tableType_t)cctx->tableType != clearedTable) {+        assert(inputSize >= 0);+        if ((tableType_t)cctx->tableType != tableType+          || ((tableType == byU16) && cctx->currentOffset + (unsigned)inputSize >= 0xFFFFU)+          || ((tableType == byU32) && cctx->currentOffset > 1 GB)+          || tableType == byPtr+          || inputSize >= 4 KB)+        {+            DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx);+            MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE);+            cctx->currentOffset = 0;+            cctx->tableType = (U32)clearedTable;+        } else {+            DEBUGLOG(4, "LZ4_prepareTable: Re-use hash table (no reset)");+        }+    }++    /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back,+     * is faster than compressing without a gap.+     * However, compressing with currentOffset == 0 is faster still,+     * so we preserve that case.+     */+    if (cctx->currentOffset != 0 && tableType == byU32) {+        DEBUGLOG(5, "LZ4_prepareTable: adding 64KB to currentOffset");+        cctx->currentOffset += 64 KB;+    }++    /* Finally, clear history */+    cctx->dictCtx = NULL;+    cctx->dictionary = NULL;+    cctx->dictSize = 0;+}++/** LZ4_compress_generic() :+ *  inlined, to ensure branches are decided at compilation time.+ *  Presumed already validated at this stage:+ *  - source != NULL+ *  - inputSize > 0+ */+LZ4_FORCE_INLINE int LZ4_compress_generic_validated(+                 LZ4_stream_t_internal* const cctx,+                 const char* const source,+                 char* const dest,+                 const int inputSize,+                 int*  inputConsumed, /* only written when outputDirective == fillOutput */+                 const int maxOutputSize,+                 const limitedOutput_directive outputDirective,+                 const tableType_t tableType,+                 const dict_directive dictDirective,+                 const dictIssue_directive dictIssue,+                 const int acceleration)+{+    int result;+    const BYTE* ip = (const BYTE*) source;++    U32 const startIndex = cctx->currentOffset;+    const BYTE* base = (const BYTE*) source - startIndex;+    const BYTE* lowLimit;++    const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx;+    const BYTE* const dictionary =+        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 */++    int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx);+    U32 const prefixIdxLimit = startIndex - dictSize;   /* used when dictDirective == dictSmall */+    const BYTE* const dictEnd = dictionary ? dictionary + dictSize : dictionary;+    const BYTE* anchor = (const BYTE*) source;+    const BYTE* const iend = ip + inputSize;+    const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1;+    const BYTE* const matchlimit = iend - LASTLITERALS;++    /* the dictCtx currentOffset is indexed on the start of the dictionary,+     * while a dictionary in the current context precedes the currentOffset */+    const BYTE* dictBase = (dictionary == NULL) ? NULL :+                           (dictDirective == usingDictCtx) ?+                            dictionary + dictSize - dictCtx->currentOffset :+                            dictionary + dictSize - startIndex;++    BYTE* op = (BYTE*) dest;+    BYTE* const olimit = op + maxOutputSize;++    U32 offset = 0;+    U32 forwardH;++    DEBUGLOG(5, "LZ4_compress_generic_validated: srcSize=%i, tableType=%u", inputSize, tableType);+    assert(ip != NULL);+    /* 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);++    /* Update context state */+    if (dictDirective == usingDictCtx) {+        /* Subsequent linked blocks can't use the dictionary. */+        /* Instead, they use the block we just compressed. */+        cctx->dictCtx = NULL;+        cctx->dictSize = (U32)inputSize;+    } else {+        cctx->dictSize += (U32)inputSize;+    }+    cctx->currentOffset += (U32)inputSize;+    cctx->tableType = (U32)tableType;++    if (inputSize<LZ4_minLength) goto _last_literals;        /* Input too small, no compression (all literals) */++    /* First Byte */+    LZ4_putPosition(ip, cctx->hashTable, tableType, base);+    ip++; forwardH = LZ4_hashPosition(ip, tableType);++    /* Main Loop */+    for ( ; ; ) {+        const BYTE* match;+        BYTE* token;+        const BYTE* filledIp;++        /* Find a match */+        if (tableType == byPtr) {+            const BYTE* forwardIp = ip;+            int step = 1;+            int searchMatchNb = acceleration << LZ4_skipTrigger;+            do {+                U32 const h = forwardH;+                ip = forwardIp;+                forwardIp += step;+                step = (searchMatchNb++ >> LZ4_skipTrigger);++                if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;+                assert(ip < mflimitPlusOne);++                match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);+                forwardH = LZ4_hashPosition(forwardIp, tableType);+                LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);++            } while ( (match+LZ4_DISTANCE_MAX < ip)+                   || (LZ4_read32(match) != LZ4_read32(ip)) );++        } else {   /* byU32, byU16 */++            const BYTE* forwardIp = ip;+            int step = 1;+            int searchMatchNb = acceleration << LZ4_skipTrigger;+            do {+                U32 const h = forwardH;+                U32 const current = (U32)(forwardIp - base);+                U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);+                assert(matchIndex <= current);+                assert(forwardIp - base < (ptrdiff_t)(2 GB - 1));+                ip = forwardIp;+                forwardIp += step;+                step = (searchMatchNb++ >> LZ4_skipTrigger);++                if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;+                assert(ip < mflimitPlusOne);++                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;+                        matchIndex += dictDelta;   /* make dictCtx index comparable with current context */+                        lowLimit = dictionary;+                    } else {+                        match = base + matchIndex;+                        lowLimit = (const BYTE*)source;+                    }+                } else if (dictDirective == usingExtDict) {+                    if (matchIndex < startIndex) {+                        DEBUGLOG(7, "extDict candidate: matchIndex=%5u  <  startIndex=%5u", matchIndex, startIndex);+                        assert(startIndex - matchIndex >= MINMATCH);+                        assert(dictBase);+                        match = dictBase + matchIndex;+                        lowLimit = dictionary;+                    } else {+                        match = base + matchIndex;+                        lowLimit = (const BYTE*)source;+                    }+                } else {   /* single continuous memory segment */+                    match = base + matchIndex;+                }+                forwardH = LZ4_hashPosition(forwardIp, tableType);+                LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);++                DEBUGLOG(7, "candidate at pos=%u  (offset=%u \n", matchIndex, current - matchIndex);+                if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) { continue; }    /* match outside of valid area */+                assert(matchIndex < current);+                if ( ((tableType != byU16) || (LZ4_DISTANCE_MAX < LZ4_DISTANCE_ABSOLUTE_MAX))+                  && (matchIndex+LZ4_DISTANCE_MAX < current)) {+                    continue;+                } /* too far */+                assert((current - matchIndex) <= LZ4_DISTANCE_MAX);  /* match now expected within distance */++                if (LZ4_read32(match) == LZ4_read32(ip)) {+                    if (maybe_extMem) offset = current - matchIndex;+                    break;   /* match found */+                }++            } while(1);+        }++        /* Catch up */+        filledIp = ip;+        while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }++        /* Encode Literals */+        {   unsigned const litLength = (unsigned)(ip - anchor);+            token = op++;+            if ((outputDirective == limitedOutput) &&  /* Check output buffer overflow */+                (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)) ) {+                return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */+            }+            if ((outputDirective == fillOutput) &&+                (unlikely(op + (litLength+240)/255 /* litlen */ + litLength /* literals */ + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit))) {+                op--;+                goto _last_literals;+            }+            if (litLength >= RUN_MASK) {+                int len = (int)(litLength - RUN_MASK);+                *token = (RUN_MASK<<ML_BITS);+                for(; len >= 255 ; len-=255) *op++ = 255;+                *op++ = (BYTE)len;+            }+            else *token = (BYTE)(litLength<<ML_BITS);++            /* Copy Literals */+            LZ4_wildCopy8(op, anchor, op+litLength);+            op+=litLength;+            DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i",+                        (int)(anchor-(const BYTE*)source), litLength, (int)(ip-(const BYTE*)source));+        }++_next_match:+        /* at this stage, the following variables must be correctly set :+         * - ip : at start of LZ operation+         * - match : at start of previous pattern occurrence; can be within current prefix, or within extDict+         * - offset : if maybe_ext_memSegment==1 (constant)+         * - lowLimit : must be == dictionary to mean "match is within extDict"; must be == source otherwise+         * - token and *token : position to write 4-bits for match length; higher 4-bits for literal length supposed already written+         */++        if ((outputDirective == fillOutput) &&+            (op + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit)) {+            /* the match was too close to the end, rewind and go to last literals */+            op = token;+            goto _last_literals;+        }++        /* Encode Offset */+        if (maybe_extMem) {   /* static test */+            DEBUGLOG(6, "             with offset=%u  (ext if > %i)", offset, (int)(ip - (const BYTE*)source));+            assert(offset <= LZ4_DISTANCE_MAX && offset > 0);+            LZ4_writeLE16(op, (U16)offset); op+=2;+        } else  {+            DEBUGLOG(6, "             with offset=%u  (same segment)", (U32)(ip - match));+            assert(ip-match <= LZ4_DISTANCE_MAX);+            LZ4_writeLE16(op, (U16)(ip - match)); op+=2;+        }++        /* Encode MatchLength */+        {   unsigned matchCode;++            if ( (dictDirective==usingExtDict || dictDirective==usingDictCtx)+              && (lowLimit==dictionary) /* match within extDict */ ) {+                const BYTE* limit = ip + (dictEnd-match);+                assert(dictEnd > match);+                if (limit > matchlimit) limit = matchlimit;+                matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);+                ip += (size_t)matchCode + MINMATCH;+                if (ip==limit) {+                    unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit);+                    matchCode += more;+                    ip += more;+                }+                DEBUGLOG(6, "             with matchLength=%u starting in extDict", matchCode+MINMATCH);+            } else {+                matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);+                ip += (size_t)matchCode + MINMATCH;+                DEBUGLOG(6, "             with matchLength=%u", matchCode+MINMATCH);+            }++            if ((outputDirective) &&    /* Check output buffer overflow */+                (unlikely(op + (1 + LASTLITERALS) + (matchCode+240)/255 > olimit)) ) {+                if (outputDirective == fillOutput) {+                    /* Match description too long : reduce it */+                    U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 1 - LASTLITERALS) * 255;+                    ip -= matchCode - newMatchCode;+                    assert(newMatchCode < matchCode);+                    matchCode = newMatchCode;+                    if (unlikely(ip <= filledIp)) {+                        /* We have already filled up to filledIp so if ip ends up less than filledIp+                         * we have positions in the hash table beyond the current position. This is+                         * a problem if we reuse the hash table. So we have to remove these positions+                         * from the hash table.+                         */+                        const BYTE* ptr;+                        DEBUGLOG(5, "Clearing %u positions", (U32)(filledIp - ip));+                        for (ptr = ip; ptr <= filledIp; ++ptr) {+                            U32 const h = LZ4_hashPosition(ptr, tableType);+                            LZ4_clearHash(h, cctx->hashTable, tableType);+                        }+                    }+                } else {+                    assert(outputDirective == limitedOutput);+                    return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */+                }+            }+            if (matchCode >= ML_MASK) {+                *token += ML_MASK;+                matchCode -= ML_MASK;+                LZ4_write32(op, 0xFFFFFFFF);+                while (matchCode >= 4*255) {+                    op+=4;+                    LZ4_write32(op, 0xFFFFFFFF);+                    matchCode -= 4*255;+                }+                op += matchCode / 255;+                *op++ = (BYTE)(matchCode % 255);+            } else+                *token += (BYTE)(matchCode);+        }+        /* Ensure we have enough space for the last literals. */+        assert(!(outputDirective == fillOutput && op + 1 + LASTLITERALS > olimit));++        anchor = ip;++        /* Test end of chunk */+        if (ip >= mflimitPlusOne) break;++        /* Fill table */+        LZ4_putPosition(ip-2, cctx->hashTable, tableType, base);++        /* Test next position */+        if (tableType == byPtr) {++            match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);+            LZ4_putPosition(ip, cctx->hashTable, tableType, base);+            if ( (match+LZ4_DISTANCE_MAX >= ip)+              && (LZ4_read32(match) == LZ4_read32(ip)) )+            { token=op++; *token=0; goto _next_match; }++        } else {   /* byU32, byU16 */++            U32 const h = LZ4_hashPosition(ip, tableType);+            U32 const current = (U32)(ip-base);+            U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);+            assert(matchIndex < current);+            if (dictDirective == usingDictCtx) {+                if (matchIndex < startIndex) {+                    /* there was no match, try the dictionary */+                    matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);+                    match = dictBase + matchIndex;+                    lowLimit = dictionary;   /* required for match length counter */+                    matchIndex += dictDelta;+                } else {+                    match = base + matchIndex;+                    lowLimit = (const BYTE*)source;  /* required for match length counter */+                }+            } else if (dictDirective==usingExtDict) {+                if (matchIndex < startIndex) {+                    assert(dictBase);+                    match = dictBase + matchIndex;+                    lowLimit = dictionary;   /* required for match length counter */+                } else {+                    match = base + matchIndex;+                    lowLimit = (const BYTE*)source;   /* required for match length counter */+                }+            } else {   /* single memory segment */+                match = base + matchIndex;+            }+            LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);+            assert(matchIndex < current);+            if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1)+              && (((tableType==byU16) && (LZ4_DISTANCE_MAX == LZ4_DISTANCE_ABSOLUTE_MAX)) ? 1 : (matchIndex+LZ4_DISTANCE_MAX >= current))+              && (LZ4_read32(match) == LZ4_read32(ip)) ) {+                token=op++;+                *token=0;+                if (maybe_extMem) offset = current - matchIndex;+                DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i",+                            (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source));+                goto _next_match;+            }+        }++        /* Prepare next loop */+        forwardH = LZ4_hashPosition(++ip, tableType);++    }++_last_literals:+    /* Encode Last Literals */+    {   size_t lastRun = (size_t)(iend - anchor);+        if ( (outputDirective) &&  /* Check output buffer overflow */+            (op + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > olimit)) {+            if (outputDirective == fillOutput) {+                /* adapt lastRun to fill 'dst' */+                assert(olimit >= op);+                lastRun  = (size_t)(olimit-op) - 1/*token*/;+                lastRun -= (lastRun + 256 - RUN_MASK) / 256;  /*additional length tokens*/+            } else {+                assert(outputDirective == limitedOutput);+                return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */+            }+        }+        DEBUGLOG(6, "Final literal run : %i literals", (int)lastRun);+        if (lastRun >= RUN_MASK) {+            size_t accumulator = lastRun - RUN_MASK;+            *op++ = RUN_MASK << ML_BITS;+            for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;+            *op++ = (BYTE) accumulator;+        } else {+            *op++ = (BYTE)(lastRun<<ML_BITS);+        }+        LZ4_memcpy(op, anchor, lastRun);+        ip = anchor + lastRun;+        op += lastRun;+    }++    if (outputDirective == fillOutput) {+        *inputConsumed = (int) (((const char*)ip)-source);+    }+    result = (int)(((char*)op) - dest);+    assert(result > 0);+    DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", inputSize, result);+    return result;+}++/** LZ4_compress_generic() :+ *  inlined, to ensure branches are decided at compilation time;+ *  takes care of src == (NULL, 0)+ *  and forward the rest to LZ4_compress_generic_validated */+LZ4_FORCE_INLINE int LZ4_compress_generic(+                 LZ4_stream_t_internal* const cctx,+                 const char* const src,+                 char* const dst,+                 const int srcSize,+                 int *inputConsumed, /* only written when outputDirective == fillOutput */+                 const int dstCapacity,+                 const limitedOutput_directive outputDirective,+                 const tableType_t tableType,+                 const dict_directive dictDirective,+                 const dictIssue_directive dictIssue,+                 const int acceleration)+{+    DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, dstCapacity=%i",+                srcSize, dstCapacity);++    if ((U32)srcSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; }  /* Unsupported srcSize, too large (or negative) */+    if (srcSize == 0) {   /* src == NULL supported if srcSize == 0 */+        if (outputDirective != notLimited && dstCapacity <= 0) return 0;  /* no output, can't write anything */+        DEBUGLOG(5, "Generating an empty block");+        assert(outputDirective == notLimited || dstCapacity >= 1);+        assert(dst != NULL);+        dst[0] = 0;+        if (outputDirective == fillOutput) {+            assert (inputConsumed != NULL);+            *inputConsumed = 0;+        }+        return 1;+    }+    assert(src != NULL);++    return LZ4_compress_generic_validated(cctx, src, dst, srcSize,+                inputConsumed, /* only written into if outputDirective == fillOutput */+                dstCapacity, outputDirective,+                tableType, dictDirective, dictIssue, acceleration);+}+++int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)+{+    LZ4_stream_t_internal* const ctx = & LZ4_initStream(state, sizeof(LZ4_stream_t)) -> internal_donotuse;+    assert(ctx != NULL);+    if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;+    if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;+    if (maxOutputSize >= LZ4_compressBound(inputSize)) {+        if (inputSize < LZ4_64Klimit) {+            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, byU16, noDict, noDictIssue, acceleration);+        } else {+            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;+            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);+        }+    } else {+        if (inputSize < LZ4_64Klimit) {+            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);+        } else {+            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;+            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration);+        }+    }+}++/**+ * LZ4_compress_fast_extState_fastReset() :+ * A variant of LZ4_compress_fast_extState().+ *+ * Using this variant avoids an expensive initialization step. It is only safe+ * to call if the state buffer is known to be correctly initialized already+ * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of+ * "correctly initialized").+ */+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;+    if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;+    if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;++    if (dstCapacity >= LZ4_compressBound(srcSize)) {+        if (srcSize < LZ4_64Klimit) {+            const tableType_t tableType = byU16;+            LZ4_prepareTable(ctx, srcSize, tableType);+            if (ctx->currentOffset) {+                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, dictSmall, acceleration);+            } else {+                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);+            }+        } else {+            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;+            LZ4_prepareTable(ctx, srcSize, tableType);+            return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);+        }+    } else {+        if (srcSize < LZ4_64Klimit) {+            const tableType_t tableType = byU16;+            LZ4_prepareTable(ctx, srcSize, tableType);+            if (ctx->currentOffset) {+                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration);+            } else {+                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);+            }+        } else {+            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;+            LZ4_prepareTable(ctx, srcSize, tableType);+            return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);+        }+    }+}+++int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)+{+    int result;+#if (LZ4_HEAPMODE)+    LZ4_stream_t* 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);++#if (LZ4_HEAPMODE)+    FREEMEM(ctxPtr);+#endif+    return result;+}+++int LZ4_compress_default(const char* src, char* dst, int srcSize, int maxOutputSize)+{+    return LZ4_compress_fast(src, dst, srcSize, maxOutputSize, 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)+{+    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);+    } else {+        if (*srcSizePtr < LZ4_64Klimit) {+            return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, byU16, noDict, noDictIssue, 1);+        } 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);+    }   }+}+++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 */+    if (ctx == NULL) return 0;+#else+    LZ4_stream_t ctxBody;+    LZ4_stream_t* ctx = &ctxBody;+#endif++    int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);++#if (LZ4_HEAPMODE)+    FREEMEM(ctx);+#endif+    return result;+}++++/*-******************************+*  Streaming functions+********************************/++#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)+LZ4_stream_t* LZ4_createStream(void)+{+    LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));+    LZ4_STATIC_ASSERT(sizeof(LZ4_stream_t) >= sizeof(LZ4_stream_t_internal));+    DEBUGLOG(4, "LZ4_createStream %p", lz4s);+    if (lz4s == NULL) return NULL;+    LZ4_initStream(lz4s, sizeof(*lz4s));+    return lz4s;+}+#endif++static size_t LZ4_stream_t_alignment(void)+{+#if LZ4_ALIGN_TEST+    typedef struct { char c; LZ4_stream_t t; } t_a;+    return sizeof(t_a) - sizeof(LZ4_stream_t);+#else+    return 1;  /* effectively disabled */+#endif+}++LZ4_stream_t* LZ4_initStream (void* buffer, size_t size)+{+    DEBUGLOG(5, "LZ4_initStream");+    if (buffer == NULL) { return NULL; }+    if (size < sizeof(LZ4_stream_t)) { return NULL; }+    if (!LZ4_isAligned(buffer, LZ4_stream_t_alignment())) return NULL;+    MEM_INIT(buffer, 0, sizeof(LZ4_stream_t_internal));+    return (LZ4_stream_t*)buffer;+}++/* resetStream is now deprecated,+ * prefer initStream() which is more general */+void LZ4_resetStream (LZ4_stream_t* LZ4_stream)+{+    DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream);+    MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t_internal));+}++void LZ4_resetStream_fast(LZ4_stream_t* ctx) {+    LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32);+}++#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)+int LZ4_freeStream (LZ4_stream_t* LZ4_stream)+{+    if (!LZ4_stream) return 0;   /* support free on NULL */+    DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream);+    FREEMEM(LZ4_stream);+    return (0);+}+#endif+++#define HASH_UNIT sizeof(reg_t)+int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)+{+    LZ4_stream_t_internal* 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;++    DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict);++    /* It's necessary to reset the context,+     * and not just continue it with prepareTable()+     * to avoid any risk of generating overflowing matchIndex+     * when compressing using this dictionary */+    LZ4_resetStream(LZ4_dict);++    /* We always increment the offset by 64 KB, since, if the dict is longer,+     * we truncate it to the last 64k, and if it's shorter, we still want to+     * advance by a whole window length so we can provide the guarantee that+     * there are only valid offsets in the window, which allows an optimization+     * in LZ4_compress_fast_continue() where it uses noDictIssue even when the+     * dictionary isn't a full 64k. */+    dict->currentOffset += 64 KB;++    if (dictSize < (int)HASH_UNIT) {+        return 0;+    }++    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;++    while (p <= dictEnd-HASH_UNIT) {+        LZ4_putPosition(p, dict->hashTable, tableType, base);+        p+=3;+    }++    return (int)dict->dictSize;+}++void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream)+{+    const LZ4_stream_t_internal* dictCtx = (dictionaryStream == NULL) ? NULL :+        &(dictionaryStream->internal_donotuse);++    DEBUGLOG(4, "LZ4_attach_dictionary (%p, %p, size %u)",+             workingStream, dictionaryStream,+             dictCtx != NULL ? dictCtx->dictSize : 0);++    if (dictCtx != NULL) {+        /* If the current offset is zero, we will never look in the+         * external dictionary context, since there is no value a table+         * entry can take that indicate a miss. In that case, we need+         * to bump the offset to something non-zero.+         */+        if (workingStream->internal_donotuse.currentOffset == 0) {+            workingStream->internal_donotuse.currentOffset = 64 KB;+        }++        /* Don't actually attach an empty dictionary.+         */+        if (dictCtx->dictSize == 0) {+            dictCtx = NULL;+        }+    }+    workingStream->internal_donotuse.dictCtx = dictCtx;+}+++static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize)+{+    assert(nextSize >= 0);+    if (LZ4_dict->currentOffset + (unsigned)nextSize > 0x80000000) {   /* potential ptrdiff_t overflow (32-bits mode) */+        /* rescale hash table */+        U32 const delta = LZ4_dict->currentOffset - 64 KB;+        const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;+        int i;+        DEBUGLOG(4, "LZ4_renormDictT");+        for (i=0; i<LZ4_HASH_SIZE_U32; i++) {+            if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;+            else LZ4_dict->hashTable[i] -= delta;+        }+        LZ4_dict->currentOffset = 64 KB;+        if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;+        LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;+    }+}+++int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream,+                                const char* source, char* dest,+                                int inputSize, int maxOutputSize,+                                int acceleration)+{+    const tableType_t tableType = byU32;+    LZ4_stream_t_internal* const streamPtr = &LZ4_stream->internal_donotuse;+    const char* dictEnd = streamPtr->dictSize ? (const char*)streamPtr->dictionary + streamPtr->dictSize : NULL;++    DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i, dictSize=%u)", inputSize, streamPtr->dictSize);++    LZ4_renormDictT(streamPtr, inputSize);   /* fix index overflow */+    if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;+    if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;++    /* invalidate tiny dictionaries */+    if ( (streamPtr->dictSize < 4)     /* tiny dictionary : not enough for a hash */+      && (dictEnd != source)           /* prefix mode */+      && (inputSize > 0)               /* tolerance : don't lose history, in case next invocation would use prefix mode */+      && (streamPtr->dictCtx == NULL)  /* usingDictCtx */+      ) {+        DEBUGLOG(5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, streamPtr->dictionary);+        /* remove dictionary existence from history, to employ faster prefix mode */+        streamPtr->dictSize = 0;+        streamPtr->dictionary = (const BYTE*)source;+        dictEnd = source;+    }++    /* Check overlapping input/dictionary space */+    {   const char* const sourceEnd = source + inputSize;+        if ((sourceEnd > (const char*)streamPtr->dictionary) && (sourceEnd < dictEnd)) {+            streamPtr->dictSize = (U32)(dictEnd - sourceEnd);+            if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;+            if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;+            streamPtr->dictionary = (const BYTE*)dictEnd - streamPtr->dictSize;+        }+    }++    /* prefix mode : source data follows dictionary */+    if (dictEnd == source) {+        if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))+            return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration);+        else+            return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration);+    }++    /* external dictionary mode */+    {   int result;+        if (streamPtr->dictCtx) {+            /* We depend here on the fact that dictCtx'es (produced by+             * LZ4_loadDict) guarantee that their tables contain no references+             * to offsets between dictCtx->currentOffset - 64 KB and+             * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe+             * to use noDictIssue even when the dict isn't a full 64 KB.+             */+            if (inputSize > 4 KB) {+                /* For compressing large blobs, it is faster to pay the setup+                 * cost to copy the dictionary's tables into the active context,+                 * so that the compression loop is only looking into one table.+                 */+                LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr));+                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);+            } else {+                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration);+            }+        } else {  /* small data <= 4 KB */+            if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {+                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration);+            } else {+                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);+            }+        }+        streamPtr->dictionary = (const BYTE*)source;+        streamPtr->dictSize = (U32)inputSize;+        return result;+    }+}+++/* 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;+    int result;++    LZ4_renormDictT(streamPtr, srcSize);++    if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {+        result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, dictSmall, 1);+    } else {+        result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);+    }++    streamPtr->dictionary = (const BYTE*)source;+    streamPtr->dictSize = (U32)srcSize;++    return result;+}+++/*! LZ4_saveDict() :+ *  If previously compressed data block is not guaranteed to remain available at its memory location,+ *  save it into a safer place (char* safeBuffer).+ *  Note : no need to call LZ4_loadDict() afterwards, dictionary is immediately usable,+ *         one can therefore call LZ4_compress_fast_continue() right after.+ * @return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error.+ */+int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)+{+    LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse;++    DEBUGLOG(5, "LZ4_saveDict : dictSize=%i, safeBuffer=%p", dictSize, safeBuffer);++    if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */+    if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; }++    if (safeBuffer == NULL) assert(dictSize == 0);+    if (dictSize > 0) {+        const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize;+        assert(dict->dictionary);+        LZ4_memmove(safeBuffer, previousDictEnd - dictSize, (size_t)dictSize);+    }++    dict->dictionary = (const BYTE*)safeBuffer;+    dict->dictSize = (U32)dictSize;++    return dictSize;+}++++/*-*******************************+ *  Decompression functions+ ********************************/++typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive;++#undef MIN+#define MIN(a,b)    ( (a) < (b) ? (a) : (b) )+++/* variant for decompress_unsafe()+ * 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)+{+    size_t b, l = 0;+    do { b = **pp; (*pp)++; l += b; } while (b==255);+    DEBUGLOG(6, "read_long_length_no_check: +length=%zu using %zu input bytes", l, l/255 + 1)+    return l;+}++/* core decoder variant for LZ4_decompress_fast*()+ * for legacy support only : these entry points are deprecated.+ * - Presumes input is correctly formed (no defense vs malformed inputs)+ * - Does not know input size (presume input buffer is "large enough")+ * - Decompress a full block (only)+ * @return : nb of bytes read from input.+ * Note : this variant is not optimized for speed, just for maintenance.+ *        the goal is to remove support of decompress_fast*() variants by v2.0+**/+LZ4_FORCE_INLINE int+LZ4_decompress_unsafe_generic(+                 const BYTE* const istart,+                 BYTE* const ostart,+                 int decompressedSize,++                 size_t prefixSize,+                 const BYTE* const dictStart,  /* only if dict==usingExtDict */+                 const size_t dictSize         /* note: =0 if dictStart==NULL */+                 )+{+    const BYTE* ip = istart;+    BYTE* op = (BYTE*)ostart;+    BYTE* const oend = ostart + decompressedSize;+    const BYTE* const prefixStart = ostart - prefixSize;++    DEBUGLOG(5, "LZ4_decompress_unsafe_generic");+    if (dictStart == NULL) assert(dictSize == 0);++    while (1) {+        /* start new sequence */+        unsigned token = *ip++;++        /* literals */+        {   size_t ll = token >> ML_BITS;+            if (ll==15) {+                /* long literal length */+                ll += read_long_length_no_check(&ip);+            }+            if ((size_t)(oend-op) < ll) return -1; /* output buffer overflow */+            LZ4_memmove(op, ip, ll); /* support in-place decompression */+            op += ll;+            ip += ll;+            if ((size_t)(oend-op) < MFLIMIT) {+                if (op==oend) break;  /* end of block */+                DEBUGLOG(5, "invalid: literals end at distance %zi from end of block", oend-op);+                /* incorrect end of block :+                 * last match must start at least MFLIMIT==12 bytes before end of output block */+                return -1;+        }   }++        /* match */+        {   size_t ml = token & 15;+            size_t const offset = LZ4_readLE16(ip);+            ip+=2;++            if (ml==15) {+                /* long literal length */+                ml += read_long_length_no_check(&ip);+            }+            ml += MINMATCH;++            if ((size_t)(oend-op) < ml) return -1; /* output buffer overflow */++            {   const BYTE* match = op - offset;++                /* out of range */+                if (offset > (size_t)(op - prefixStart) + dictSize) {+                    DEBUGLOG(6, "offset out of range");+                    return -1;+                }++                /* check special case : extDict */+                if (offset > (size_t)(op - prefixStart)) {+                    /* extDict scenario */+                    const BYTE* const dictEnd = dictStart + dictSize;+                    const BYTE* extMatch = dictEnd - (offset - (size_t)(op-prefixStart));+                    size_t const extml = (size_t)(dictEnd - extMatch);+                    if (extml > ml) {+                        /* match entirely within extDict */+                        LZ4_memmove(op, extMatch, ml);+                        op += ml;+                        ml = 0;+                    } else {+                        /* match split between extDict & prefix */+                        LZ4_memmove(op, extMatch, extml);+                        op += extml;+                        ml -= extml;+                    }+                    match = prefixStart;+                }++                /* match copy - slow variant, supporting overlap copy */+                {   size_t u;+                    for (u=0; u<ml; u++) {+                        op[u] = match[u];+            }   }   }+            op += ml;+            if ((size_t)(oend-op) < LASTLITERALS) {+                DEBUGLOG(5, "invalid: match ends at distance %zi from end of block", oend-op);+                /* incorrect end of block :+                 * last match must stop at least LASTLITERALS==5 bytes before end of output block */+                return -1;+            }+        } /* match */+    } /* main loop */+    return (int)(ip - istart);+}+++/* Read the variable-length literal or match length.+ *+ * @ip : input pointer+ * @ilimit : position after which if length is not decoded, the input is necessarily corrupted.+ * @initial_check - check ip >= ipmax before start of loop.  Returns initial_error if so.+ * @error (output) - error code.  Must be set to 0 before call.+**/+typedef size_t Rvl_t;+static const Rvl_t rvl_error = (Rvl_t)(-1);+LZ4_FORCE_INLINE Rvl_t+read_variable_length(const BYTE** ip, const BYTE* ilimit,+                     int initial_check)+{+    Rvl_t s, length = 0;+    assert(ip != NULL);+    assert(*ip !=  NULL);+    assert(ilimit != NULL);+    if (initial_check && unlikely((*ip) >= ilimit)) {    /* read limit reached */+        return rvl_error;+    }+    do {+        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;+        }+    } while (s==255);++    return length;+}++/*! LZ4_decompress_generic() :+ *  This generic decompression function covers all use cases.+ *  It shall be instantiated several times, using different sets of directives.+ *  Note that it is important for performance that this function really get inlined,+ *  in order to remove useless branches during compilation optimization.+ */+LZ4_FORCE_INLINE int+LZ4_decompress_generic(+                 const char* const src,+                 char* const dst,+                 int srcSize,+                 int outputSize,         /* If endOnInput==endOnInputSize, this value is `dstCapacity` */++                 earlyEnd_directive partialDecoding,  /* full, partial */+                 dict_directive dict,                 /* noDict, withPrefix64k, usingExtDict */+                 const BYTE* const lowPrefix,  /* always <= dst, == dst when no prefix */+                 const BYTE* const dictStart,  /* only if dict==usingExtDict */+                 const size_t dictSize         /* note : = 0 if noDict */+                 )+{+    if ((src == NULL) || (outputSize < 0)) { return -1; }++    {   const BYTE* ip = (const BYTE*) src;+        const BYTE* const iend = ip + srcSize;++        BYTE* op = (BYTE*) dst;+        BYTE* const oend = op + outputSize;+        BYTE* cpy;++        const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize;++        const int checkOffset = (dictSize < (int)(64 KB));+++        /* Set up the "end" pointers for the shortcut. */+        const BYTE* const shortiend = iend - 14 /*maxLL*/ - 2 /*offset*/;+        const BYTE* const shortoend = oend - 14 /*maxLL*/ - 18 /*maxML*/;++        const BYTE* match;+        size_t offset;+        unsigned token;+        size_t length;+++        DEBUGLOG(5, "LZ4_decompress_generic (srcSize:%i, dstSize:%i)", srcSize, outputSize);++        /* Special cases */+        assert(lowPrefix <= op);+        if (unlikely(outputSize==0)) {+            /* Empty output buffer */+            if (partialDecoding) return 0;+            return ((srcSize==1) && (*ip==0)) ? 0 : -1;+        }+        if (unlikely(srcSize==0)) { return -1; }++    /* LZ4_FAST_DEC_LOOP:+     * designed for modern OoO performance cpus,+     * where copying reliably 32-bytes is preferable to an unpredictable branch.+     * 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");+            goto safe_decode;+        }++        /* Fast loop : decode sequences as long as output < oend-FASTLOOP_SAFE_DISTANCE */+        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 */++            /* 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; }+                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);+                /* 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; }+                /* 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;+            }++            /* get offset */+            offset = LZ4_readLE16(ip); ip+=2;+            match = op - offset;+            assert(match <= op);  /* overflow check */++            /* get matchlength */+            length = token & ML_MASK;++            if (length == ML_MASK) {+                size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0);+                if (addl == rvl_error) { goto _output_error; }+                length += addl;+                length += MINMATCH;+                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) {+                    goto safe_match_copy;+                }++                /* Fastpath check: skip LZ4_wildCopy32 when true */+                if ((dict == withPrefix64k) || (match >= lowPrefix)) {+                    if (offset >= 8) {+                        assert(match >= lowPrefix);+                        assert(match <= op);+                        assert(op + 18 <= oend);++                        LZ4_memcpy(op, match, 8);+                        LZ4_memcpy(op+8, match+8, 8);+                        LZ4_memcpy(op+16, match+16, 2);+                        op += length;+                        continue;+            }   }   }++            if (checkOffset && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */+            /* match starting within external dictionary */+            if ((dict==usingExtDict) && (match < lowPrefix)) {+                assert(dictEnd != NULL);+                if (unlikely(op+length > oend-LASTLITERALS)) {+                    if (partialDecoding) {+                        DEBUGLOG(7, "partialDecoding: dictionary match, close to dstEnd");+                        length = MIN(length, (size_t)(oend-op));+                    } else {+                        goto _output_error;  /* end-of-block condition violated */+                }   }++                if (length <= (size_t)(lowPrefix-match)) {+                    /* match fits entirely within external dictionary : just copy */+                    LZ4_memmove(op, dictEnd - (lowPrefix-match), length);+                    op += length;+                } else {+                    /* match stretches into both external dictionary and current block */+                    size_t const copySize = (size_t)(lowPrefix - match);+                    size_t const restSize = length - copySize;+                    LZ4_memcpy(op, dictEnd - copySize, copySize);+                    op += copySize;+                    if (restSize > (size_t)(op - lowPrefix)) {  /* overlap copy */+                        BYTE* const endOfMatch = op + restSize;+                        const BYTE* copyFrom = lowPrefix;+                        while (op < endOfMatch) { *op++ = *copyFrom++; }+                    } else {+                        LZ4_memcpy(op, lowPrefix, restSize);+                        op += restSize;+                }   }+                continue;+            }++            /* copy match within block */+            cpy = op + length;++            assert((op <= oend) && (oend-op >= 32));+            if (unlikely(offset<16)) {+                LZ4_memcpy_using_offset(op, match, cpy, offset);+            } else {+                LZ4_wildCopy32(op, match, cpy);+            }++            op = cpy;   /* wildcopy correction */+        }+    safe_decode:+#endif++        /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */+        while (1) {+            assert(ip < iend);+            token = *ip++;+            length = token >> ML_BITS;  /* literal length */++            /* A two-stage shortcut for the most common case:+             * 1) If the literal length is 0..14, and there is enough space,+             * enter the shortcut and copy 16 bytes on behalf of the literals+             * (in the fast mode, only 8 bytes can be safely copied this way).+             * 2) Further if the match length is 4..18, copy 18 bytes in a similar+             * manner; but we ensure that there's enough space in the output for+             * those 18 bytes earlier, upon entering the shortcut (in other words,+             * there is a combined check for both stages).+             */+            if ( (length != RUN_MASK)+                /* strictly "less than" on input, to re-enter the loop with at least one byte */+              && likely((ip < shortiend) & (op <= shortoend)) ) {+                /* Copy the literals */+                LZ4_memcpy(op, ip, 16);+                op += length; ip += length;++                /* 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 */+                offset = LZ4_readLE16(ip); ip += 2;+                match = op - offset;+                assert(match <= op); /* check overflow */++                /* Do not deal with overlapping matches. */+                if ( (length != ML_MASK)+                  && (offset >= 8)+                  && (dict==withPrefix64k || match >= lowPrefix) ) {+                    /* Copy the match. */+                    LZ4_memcpy(op + 0, match + 0, 8);+                    LZ4_memcpy(op + 8, match + 8, 8);+                    LZ4_memcpy(op +16, match +16, 2);+                    op += length + MINMATCH;+                    /* Both stages worked, load the next token. */+                    continue;+                }++                /* The second stage didn't work out, but the info is ready.+                 * Propel it right to the point of match copying. */+                goto _copy_match;+            }++            /* 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; }+                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;+#if LZ4_FAST_DEC_LOOP+        safe_literal_copy:+#endif+            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.+                 * In the normal scenario, decoding a full block, it must be the last sequence,+                 * otherwise it's an error (invalid input or dimensions).+                 * In partialDecoding scenario, it's necessary to ensure there is no buffer overflow.+                 */+                if (partialDecoding) {+                    /* Since we are partial decoding we may be in this block because of the output parsing+                     * restriction, which is not valid since the output buffer is allowed to be undersized.+                     */+                    DEBUGLOG(7, "partialDecoding: copying literals, close to input or output end")+                    DEBUGLOG(7, "partialDecoding: literal length = %u", (unsigned)length);+                    DEBUGLOG(7, "partialDecoding: remaining space in dstBuffer : %i", (int)(oend - op));+                    DEBUGLOG(7, "partialDecoding: remaining space in srcBuffer : %i", (int)(iend - ip));+                    /* Finishing in the middle of a literals segment,+                     * due to lack of input.+                     */+                    if (ip+length > iend) {+                        length = (size_t)(iend-ip);+                        cpy = op + length;+                    }+                    /* Finishing in the middle of a literals segment,+                     * due to lack of output space.+                     */+                    if (cpy > oend) {+                        cpy = oend;+                        assert(op<=oend);+                        length = (size_t)(oend-op);+                    }+                } else {+                     /* We must be on the last sequence (or invalid) because of the parsing limitations+                      * 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);+                        goto _output_error;+                    }+                }+                LZ4_memmove(op, ip, length);  /* supports overlapping memory regions, for in-place decompression scenarios */+                ip += length;+                op += length;+                /* Necessarily EOF when !partialDecoding.+                 * When partialDecoding, it is EOF if we've either+                 * filled the output buffer or+                 * can't proceed with reading an offset for following match.+                 */+                if (!partialDecoding || (cpy == oend) || (ip >= (iend-2))) {+                    break;+                }+            } else {+                LZ4_wildCopy8(op, ip, cpy);   /* can overwrite up to 8 bytes beyond cpy */+                ip += length; op = cpy;+            }++            /* get offset */+            offset = LZ4_readLE16(ip); ip+=2;+            match = op - offset;++            /* get matchlength */+            length = token & ML_MASK;++    _copy_match:+            if (length == ML_MASK) {+                size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0);+                if (addl == rvl_error) { goto _output_error; }+                length += addl;+                if (unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error;   /* overflow detection */+            }+            length += MINMATCH;++#if LZ4_FAST_DEC_LOOP+        safe_match_copy:+#endif+            if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error;   /* Error : offset outside buffers */+            /* match starting within external dictionary */+            if ((dict==usingExtDict) && (match < lowPrefix)) {+                assert(dictEnd != NULL);+                if (unlikely(op+length > oend-LASTLITERALS)) {+                    if (partialDecoding) length = MIN(length, (size_t)(oend-op));+                    else goto _output_error;   /* doesn't respect parsing restriction */+                }++                if (length <= (size_t)(lowPrefix-match)) {+                    /* match fits entirely within external dictionary : just copy */+                    LZ4_memmove(op, dictEnd - (lowPrefix-match), length);+                    op += length;+                } else {+                    /* match stretches into both external dictionary and current block */+                    size_t const copySize = (size_t)(lowPrefix - match);+                    size_t const restSize = length - copySize;+                    LZ4_memcpy(op, dictEnd - copySize, copySize);+                    op += copySize;+                    if (restSize > (size_t)(op - lowPrefix)) {  /* overlap copy */+                        BYTE* const endOfMatch = op + restSize;+                        const BYTE* copyFrom = lowPrefix;+                        while (op < endOfMatch) *op++ = *copyFrom++;+                    } else {+                        LZ4_memcpy(op, lowPrefix, restSize);+                        op += restSize;+                }   }+                continue;+            }+            assert(match >= lowPrefix);++            /* copy match within block */+            cpy = op + length;++            /* partialDecoding : may end anywhere within the block */+            assert(op<=oend);+            if (partialDecoding && (cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {+                size_t const mlen = MIN(length, (size_t)(oend-op));+                const BYTE* const matchEnd = match + mlen;+                BYTE* const copyEnd = op + mlen;+                if (matchEnd > op) {   /* overlap copy */+                    while (op < copyEnd) { *op++ = *match++; }+                } else {+                    LZ4_memcpy(op, match, mlen);+                }+                op = copyEnd;+                if (op == oend) { break; }+                continue;+            }++            if (unlikely(offset<8)) {+                LZ4_write32(op, 0);   /* silence msan warning when offset==0 */+                op[0] = match[0];+                op[1] = match[1];+                op[2] = match[2];+                op[3] = match[3];+                match += inc32table[offset];+                LZ4_memcpy(op+4, match, 4);+                match -= dec64table[offset];+            } else {+                LZ4_memcpy(op, match, 8);+                match += 8;+            }+            op += 8;++            if (unlikely(cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {+                BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1);+                if (cpy > oend-LASTLITERALS) { goto _output_error; } /* Error : last LASTLITERALS bytes must be literals (uncompressed) */+                if (op < oCopyLimit) {+                    LZ4_wildCopy8(op, match, oCopyLimit);+                    match += oCopyLimit - op;+                    op = oCopyLimit;+                }+                while (op < cpy) { *op++ = *match++; }+            } else {+                LZ4_memcpy(op, match, 8);+                if (length > 16)  { LZ4_wildCopy8(op+8, match+8, cpy); }+            }+            op = cpy;   /* wildcopy correction */+        }++        /* end of decoding */+        DEBUGLOG(5, "decoded %i bytes", (int) (((char*)op)-dst));+        return (int) (((char*)op)-dst);     /* Nb of output bytes decoded */++        /* Overflow error detected */+    _output_error:+        return (int) (-(((const char*)ip)-src))-1;+    }+}+++/*===== Instantiate the API decoding functions. =====*/++LZ4_FORCE_O2+int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)+{+    return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize,+                                  decode_full_block, noDict,+                                  (BYTE*)dest, NULL, 0);+}++LZ4_FORCE_O2+int LZ4_decompress_safe_partial(const char* src, char* dst, int compressedSize, int targetOutputSize, int dstCapacity)+{+    dstCapacity = MIN(targetOutputSize, dstCapacity);+    return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity,+                                  partial_decode,+                                  noDict, (BYTE*)dst, NULL, 0);+}++LZ4_FORCE_O2+int LZ4_decompress_fast(const char* source, char* dest, int originalSize)+{+    DEBUGLOG(5, "LZ4_decompress_fast");+    return LZ4_decompress_unsafe_generic(+                (const BYTE*)source, (BYTE*)dest, originalSize,+                0, NULL, 0);+}++/*===== Instantiate a few more decoding cases, used more than once. =====*/++LZ4_FORCE_O2 /* Exported, an obsolete API function. */+int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)+{+    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,+                                  decode_full_block, withPrefix64k,+                                  (BYTE*)dest - 64 KB, NULL, 0);+}++LZ4_FORCE_O2+static int LZ4_decompress_safe_partial_withPrefix64k(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity)+{+    dstCapacity = MIN(targetOutputSize, dstCapacity);+    return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity,+                                  partial_decode, withPrefix64k,+                                  (BYTE*)dest - 64 KB, NULL, 0);+}++/* Another obsolete API function, paired with the previous one. */+int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)+{+    return LZ4_decompress_unsafe_generic(+                (const BYTE*)source, (BYTE*)dest, originalSize,+                64 KB, NULL, 0);+}++LZ4_FORCE_O2+static int LZ4_decompress_safe_withSmallPrefix(const char* source, char* dest, int compressedSize, int maxOutputSize,+                                               size_t prefixSize)+{+    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,+                                  decode_full_block, noDict,+                                  (BYTE*)dest-prefixSize, NULL, 0);+}++LZ4_FORCE_O2+static int LZ4_decompress_safe_partial_withSmallPrefix(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity,+                                               size_t prefixSize)+{+    dstCapacity = MIN(targetOutputSize, dstCapacity);+    return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity,+                                  partial_decode, noDict,+                                  (BYTE*)dest-prefixSize, NULL, 0);+}++LZ4_FORCE_O2+int LZ4_decompress_safe_forceExtDict(const char* source, char* dest,+                                     int compressedSize, int maxOutputSize,+                                     const void* dictStart, size_t dictSize)+{+    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,+                                  decode_full_block, usingExtDict,+                                  (BYTE*)dest, (const BYTE*)dictStart, dictSize);+}++LZ4_FORCE_O2+int LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest,+                                     int compressedSize, int targetOutputSize, int dstCapacity,+                                     const void* dictStart, size_t dictSize)+{+    dstCapacity = MIN(targetOutputSize, dstCapacity);+    return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity,+                                  partial_decode, usingExtDict,+                                  (BYTE*)dest, (const BYTE*)dictStart, dictSize);+}++LZ4_FORCE_O2+static int LZ4_decompress_fast_extDict(const char* source, char* dest, int originalSize,+                                       const void* dictStart, size_t dictSize)+{+    return LZ4_decompress_unsafe_generic(+                (const BYTE*)source, (BYTE*)dest, originalSize,+                0, (const BYTE*)dictStart, dictSize);+}++/* The "double dictionary" mode, for use with e.g. ring buffers: the first part+ * of the dictionary is passed as prefix, and the second via dictStart + dictSize.+ * These routines are used only once, in LZ4_decompress_*_continue().+ */+LZ4_FORCE_INLINE+int LZ4_decompress_safe_doubleDict(const char* source, char* dest, int compressedSize, int maxOutputSize,+                                   size_t prefixSize, const void* dictStart, size_t dictSize)+{+    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,+                                  decode_full_block, usingExtDict,+                                  (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize);+}++/*===== streaming decompression functions =====*/++#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)+LZ4_streamDecode_t* LZ4_createStreamDecode(void)+{+    LZ4_STATIC_ASSERT(sizeof(LZ4_streamDecode_t) >= sizeof(LZ4_streamDecode_t_internal));+    return (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t));+}++int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)+{+    if (LZ4_stream == NULL) { return 0; }  /* support free on NULL */+    FREEMEM(LZ4_stream);+    return 0;+}+#endif++/*! LZ4_setStreamDecode() :+ *  Use this function to instruct where to find the dictionary.+ *  This function is not necessary if previous data is still available where it was decoded.+ *  Loading a size of 0 is allowed (same effect as no dictionary).+ * @return : 1 if OK, 0 if error+ */+int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)+{+    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;+    lz4sd->prefixSize = (size_t)dictSize;+    if (dictSize) {+        assert(dictionary != NULL);+        lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;+    } else {+        lz4sd->prefixEnd = (const BYTE*) dictionary;+    }+    lz4sd->externalDict = NULL;+    lz4sd->extDictSize  = 0;+    return 1;+}++/*! LZ4_decoderRingBufferSize() :+ *  when setting a ring buffer for streaming decompression (optional scenario),+ *  provides the minimum size of this ring buffer+ *  to be compatible with any source respecting maxBlockSize condition.+ *  Note : in a ring buffer scenario,+ *  blocks are presumed decompressed next to each other.+ *  When not enough space remains for next block (remainingSize < maxBlockSize),+ *  decoding resumes from beginning of ring buffer.+ * @return : minimum ring buffer size,+ *           or 0 if there is an error (invalid maxBlockSize).+ */+int LZ4_decoderRingBufferSize(int maxBlockSize)+{+    if (maxBlockSize < 0) return 0;+    if (maxBlockSize > LZ4_MAX_INPUT_SIZE) return 0;+    if (maxBlockSize < 16) maxBlockSize = 16;+    return LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize);+}++/*+*_continue() :+    These decoding functions allow decompression of multiple blocks in "streaming" mode.+    Previously decoded blocks must still be available at the memory position where they were decoded.+    If it's not possible, save the relevant part of decoded data into a safe buffer,+    and indicate where it stands using LZ4_setStreamDecode()+*/+LZ4_FORCE_O2+int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)+{+    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;+    int result;++    if (lz4sd->prefixSize == 0) {+        /* The first call, no dictionary yet. */+        assert(lz4sd->extDictSize == 0);+        result = LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);+        if (result <= 0) return result;+        lz4sd->prefixSize = (size_t)result;+        lz4sd->prefixEnd = (BYTE*)dest + result;+    } else if (lz4sd->prefixEnd == (BYTE*)dest) {+        /* They're rolling the current segment. */+        if (lz4sd->prefixSize >= 64 KB - 1)+            result = LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);+        else if (lz4sd->extDictSize == 0)+            result = LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize,+                                                         lz4sd->prefixSize);+        else+            result = LZ4_decompress_safe_doubleDict(source, dest, compressedSize, maxOutputSize,+                                                    lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);+        if (result <= 0) return result;+        lz4sd->prefixSize += (size_t)result;+        lz4sd->prefixEnd  += result;+    } else {+        /* The buffer wraps around, or they're switching to another buffer. */+        lz4sd->extDictSize = lz4sd->prefixSize;+        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;+        result = LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize,+                                                  lz4sd->externalDict, lz4sd->extDictSize);+        if (result <= 0) return result;+        lz4sd->prefixSize = (size_t)result;+        lz4sd->prefixEnd  = (BYTE*)dest + result;+    }++    return result;+}++LZ4_FORCE_O2 int+LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode,+                        const char* source, char* dest, int originalSize)+{+    LZ4_streamDecode_t_internal* const lz4sd =+        (assert(LZ4_streamDecode!=NULL), &LZ4_streamDecode->internal_donotuse);+    int result;++    DEBUGLOG(5, "LZ4_decompress_fast_continue (toDecodeSize=%i)", originalSize);+    assert(originalSize >= 0);++    if (lz4sd->prefixSize == 0) {+        DEBUGLOG(5, "first invocation : no prefix nor extDict");+        assert(lz4sd->extDictSize == 0);+        result = LZ4_decompress_fast(source, dest, originalSize);+        if (result <= 0) return result;+        lz4sd->prefixSize = (size_t)originalSize;+        lz4sd->prefixEnd = (BYTE*)dest + originalSize;+    } else if (lz4sd->prefixEnd == (BYTE*)dest) {+        DEBUGLOG(5, "continue using existing prefix");+        result = LZ4_decompress_unsafe_generic(+                        (const BYTE*)source, (BYTE*)dest, originalSize,+                        lz4sd->prefixSize,+                        lz4sd->externalDict, lz4sd->extDictSize);+        if (result <= 0) return result;+        lz4sd->prefixSize += (size_t)originalSize;+        lz4sd->prefixEnd  += originalSize;+    } else {+        DEBUGLOG(5, "prefix becomes extDict");+        lz4sd->extDictSize = lz4sd->prefixSize;+        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;+        result = LZ4_decompress_fast_extDict(source, dest, originalSize,+                                             lz4sd->externalDict, lz4sd->extDictSize);+        if (result <= 0) return result;+        lz4sd->prefixSize = (size_t)originalSize;+        lz4sd->prefixEnd  = (BYTE*)dest + originalSize;+    }++    return result;+}+++/*+Advanced decoding functions :+*_usingDict() :+    These decoding functions work the same as "_continue" ones,+    the dictionary must be explicitly provided within parameters+*/++int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)+{+    if (dictSize==0)+        return LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);+    if (dictStart+dictSize == dest) {+        if (dictSize >= 64 KB - 1) {+            return LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);+        }+        assert(dictSize >= 0);+        return LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, (size_t)dictSize);+    }+    assert(dictSize >= 0);+    return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, dictStart, (size_t)dictSize);+}++int LZ4_decompress_safe_partial_usingDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, const char* dictStart, int dictSize)+{+    if (dictSize==0)+        return LZ4_decompress_safe_partial(source, dest, compressedSize, targetOutputSize, dstCapacity);+    if (dictStart+dictSize == dest) {+        if (dictSize >= 64 KB - 1) {+            return LZ4_decompress_safe_partial_withPrefix64k(source, dest, compressedSize, targetOutputSize, dstCapacity);+        }+        assert(dictSize >= 0);+        return LZ4_decompress_safe_partial_withSmallPrefix(source, dest, compressedSize, targetOutputSize, dstCapacity, (size_t)dictSize);+    }+    assert(dictSize >= 0);+    return LZ4_decompress_safe_partial_forceExtDict(source, dest, compressedSize, targetOutputSize, dstCapacity, dictStart, (size_t)dictSize);+}++int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)+{+    if (dictSize==0 || dictStart+dictSize == dest)+        return LZ4_decompress_unsafe_generic(+                        (const BYTE*)source, (BYTE*)dest, originalSize,+                        (size_t)dictSize, NULL, 0);+    assert(dictSize >= 0);+    return LZ4_decompress_fast_extDict(source, dest, originalSize, dictStart, (size_t)dictSize);+}+++/*=*************************************************+*  Obsolete Functions+***************************************************/+/* obsolete compression functions */+int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize)+{+    return LZ4_compress_default(source, dest, inputSize, maxOutputSize);+}+int LZ4_compress(const char* src, char* dest, int srcSize)+{+    return LZ4_compress_default(src, dest, srcSize, LZ4_compressBound(srcSize));+}+int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize)+{+    return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1);+}+int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize)+{+    return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1);+}+int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int dstCapacity)+{+    return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, dstCapacity, 1);+}+int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize)+{+    return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1);+}++/*+These decompression functions are deprecated and should no longer be used.+They are only provided here for compatibility with older user programs.+- LZ4_uncompress is totally equivalent to LZ4_decompress_fast+- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe+*/+int LZ4_uncompress (const char* source, char* dest, int outputSize)+{+    return LZ4_decompress_fast(source, dest, outputSize);+}+int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize)+{+    return LZ4_decompress_safe(source, dest, isize, maxOutputSize);+}++/* Obsolete Streaming functions */++int LZ4_sizeofStreamState(void) { return sizeof(LZ4_stream_t); }++int LZ4_resetStreamState(void* state, char* inputBuffer)+{+    (void)inputBuffer;+    LZ4_resetStream((LZ4_stream_t*)state);+    return 0;+}++#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)+void* LZ4_create (char* inputBuffer)+{+    (void)inputBuffer;+    return LZ4_createStream();+}+#endif  char* LZ4_slideInputBuffer (void* state) {
cbits/lz4.h view
@@ -1,7 +1,7 @@ /*  *  LZ4 - Fast LZ compression algorithm  *  Header File- *  Copyright (C) 2011-present, Yann Collet.+ *  Copyright (C) 2011-2020, Yann Collet.     BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -97,37 +97,78 @@ #  define LZ4LIB_API LZ4LIB_VISIBILITY #endif +/*! LZ4_FREESTANDING :+ *  When this macro is set to 1, it enables "freestanding mode" that is+ *  suitable for typical freestanding environment which doesn't support+ *  standard C library.+ *+ *  - LZ4_FREESTANDING is a compile-time switch.+ *  - It requires the following macros to be defined:+ *    LZ4_memcpy, LZ4_memmove, LZ4_memset.+ *  - It only enables LZ4/HC functions which don't use heap.+ *    All LZ4F_* functions are not supported.+ *  - See tests/freestanding.c to check its basic setup.+ */+#if defined(LZ4_FREESTANDING) && (LZ4_FREESTANDING == 1)+#  define LZ4_HEAPMODE 0+#  define LZ4HC_HEAPMODE 0+#  define LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION 1+#  if !defined(LZ4_memcpy)+#    error "LZ4_FREESTANDING requires macro 'LZ4_memcpy'."+#  endif+#  if !defined(LZ4_memset)+#    error "LZ4_FREESTANDING requires macro 'LZ4_memset'."+#  endif+#  if !defined(LZ4_memmove)+#    error "LZ4_FREESTANDING requires macro 'LZ4_memmove'."+#  endif+#elif ! defined(LZ4_FREESTANDING)+#  define LZ4_FREESTANDING 0+#endif++ /*------   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  2    /* for tweaks, bug-fixes, or development */+#define LZ4_VERSION_RELEASE  4    /* for tweaks, bug-fixes, or development */  #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)  #define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE #define LZ4_QUOTE(str) #str #define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str)-#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)+#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)  /* requires v1.7.3+ */ -LZ4LIB_API int LZ4_versionNumber (void);  /**< library version number; useful to check dll version */-LZ4LIB_API const char* LZ4_versionString (void);   /**< library version string; useful to check dll version */+LZ4LIB_API int LZ4_versionNumber (void);  /**< library version number; useful to check dll version; requires v1.3.0+ */+LZ4LIB_API const char* LZ4_versionString (void);   /**< library version string; useful to check dll version; requires v1.7.5+ */   /*-************************************ *  Tuning parameter **************************************/+#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; etc.)- * Increasing memory usage improves compression ratio.- * Reduced memory usage may improve speed, thanks to better cache locality.+ * 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.+ * 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  */ #ifndef LZ4_MEMORY_USAGE-# define LZ4_MEMORY_USAGE 14+# define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT #endif +#if (LZ4_MEMORY_USAGE < LZ4_MEMORY_USAGE_MIN)+#  error "LZ4_MEMORY_USAGE is too small !"+#endif +#if (LZ4_MEMORY_USAGE > LZ4_MEMORY_USAGE_MAX)+#  error "LZ4_MEMORY_USAGE is too large !"+#endif+ /*-************************************ *  Simple Functions **************************************/@@ -186,7 +227,8 @@     The larger the acceleration value, the faster the algorithm, but also the lesser the compression.     It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.     An acceleration value of "1" is the same as regular LZ4_compress_default()-    Values <= 0 will be replaced by ACCELERATION_DEFAULT (currently == 1, see lz4.c).+    Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c).+    Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c). */ LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); @@ -212,7 +254,18 @@  *               New value is necessarily <= input value.  * @return : Nb bytes written into 'dst' (necessarily <= targetDestSize)  *           or 0 if compression fails.-*/+ *+ * Note : from v1.8.2 to v1.9.1, this function had a bug (fixed un 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.+ *        If an application uses `LZ4_compress_destSize()`,+ *        it's highly recommended to update liblz4 to v1.9.2 or better.+ *        If this can't be done or ensured,+ *        the receiving decompression function should provide+ *        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);  @@ -220,25 +273,35 @@  *  Decompress an LZ4 compressed block, of size 'srcSize' at position 'src',  *  into destination buffer 'dst' of size 'dstCapacity'.  *  Up to 'targetOutputSize' bytes will be decoded.- *  The function stops decoding on reaching this objective,- *  which can boost performance when only the beginning of a block is required.+ *  The function stops decoding on reaching this objective.+ *  This can be useful to boost performance+ *  whenever only the beginning of a block is required.  *- * @return : the number of bytes decoded in `dst` (necessarily <= dstCapacity)+ * @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize)  *           If source stream is detected malformed, function returns a negative result.  *- *  Note : @return can be < targetOutputSize, if compressed block contains less data.+ *  Note 1 : @return can be < targetOutputSize, if compressed block contains less data.  *- *  Note 2 : this function features 2 parameters, targetOutputSize and dstCapacity,- *           and expects targetOutputSize <= dstCapacity.- *           It effectively stops decoding on reaching targetOutputSize,+ *  Note 2 : targetOutputSize must be <= dstCapacity+ *+ *  Note 3 : this function effectively stops decoding on reaching targetOutputSize,  *           so dstCapacity is kind of redundant.- *           This is because in a previous version of this function,- *           decoding operation would not "break" a sequence in the middle.- *           As a consequence, there was no guarantee that decoding would stop at exactly targetOutputSize,+ *           This is because in older versions of this function,+ *           decoding operation would still write complete sequences.+ *           Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize,  *           it could write more bytes, though only up to dstCapacity.  *           Some "margin" used to be required for this operation to work properly.- *           This is no longer necessary.- *           The function nonetheless keeps its signature, in an effort to not break API.+ *           Thankfully, this is no longer necessary.+ *           The function nonetheless keeps the same signature, in an effort to preserve API compatibility.+ *+ *  Note 4 : If srcSize is the exact size of the block,+ *           then targetOutputSize can be any value,+ *           including larger than the block's decompressed size.+ *           The function will, at most, generate block's decompressed size.+ *+ *  Note 5 : If srcSize is _larger_ than block's compressed size,+ *           then targetOutputSize **MUST** be <= block's decompressed size.+ *           Otherwise, *silent corruption will occur*.  */ LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity); @@ -248,8 +311,25 @@ ***********************************************/ 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).+   https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros++ - Since rc.exe is a legacy compiler, it truncates long symbol (> 30 chars)+   and reports warning "RC4011: identifier truncated".++ - To eliminate the warning, we surround long preprocessor symbol with+   "#if !defined(RC_INVOKED) ... #endif" block that means+   "skip this block when rc.exe is trying to read it".+*/+#if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */+#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4LIB_API LZ4_stream_t* LZ4_createStream(void); LZ4LIB_API int           LZ4_freeStream (LZ4_stream_t* streamPtr);+#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */+#endif  /*! LZ4_resetStream_fast() : v1.9.0+  *  Use this to prepare an LZ4_stream_t for a new chain of dependent blocks@@ -333,8 +413,12 @@  *  creation / destruction of streaming decompression tracking context.  *  A tracking context can be re-used multiple times.  */+#if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */+#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void); LZ4LIB_API int                 LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);+#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */+#endif  /*! LZ4_setStreamDecode() :  *  An LZ4_streamDecode_t context can be allocated once and re-used multiple times.@@ -384,7 +468,10 @@  *  save the last 64KB of decoded data into a safe buffer where it can't be modified during decompression,  *  then indicate where this data is saved using LZ4_setStreamDecode(), before decompressing next block. */-LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int srcSize, int dstCapacity);+LZ4LIB_API int+LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode,+                        const char* src, char* dst,+                        int srcSize, int dstCapacity);   /*! LZ4_decompress_*_usingDict() :@@ -395,8 +482,17 @@  *  Performance tip : Decompression speed can be substantially increased  *                    when dst == dictStart + dictSize.  */-LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* src, char* dst, int srcSize, int dstCapcity, const char* dictStart, int dictSize);+LZ4LIB_API int+LZ4_decompress_safe_usingDict(const char* src, char* dst,+                              int srcSize, int dstCapacity,+                              const char* dictStart, int dictSize); +LZ4LIB_API int+LZ4_decompress_safe_partial_usingDict(const char* src, char* dst,+                                      int compressedSize,+                                      int targetOutputSize, int maxOutputSize,+                                      const char* dictStart, int dictSize);+ #endif /* LZ4_H_2983827168210 */  @@ -474,13 +570,15 @@  *  stream (and source buffer) must remain in-place / accessible / unchanged  *  through the completion of the first compression call on the stream.  */-LZ4LIB_STATIC_API void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream);+LZ4LIB_STATIC_API void+LZ4_attach_dictionary(LZ4_stream_t* workingStream,+                const LZ4_stream_t* dictionaryStream);   /*! In-place compression and decompression  *  * It's possible to have input and output sharing the same buffer,- * for highly contrained memory environments.+ * for highly constrained memory environments.  * In both cases, it requires input to lay at the end of the buffer,  * and decompression to start at beginning of the buffer.  * Buffer size must feature some margin, hence be larger than final size.@@ -547,75 +645,53 @@ #define LZ4_H_98237428734687  /*-************************************************************- *  PRIVATE DEFINITIONS+ *  Private Definitions  **************************************************************  * Do not use these definitions directly.  * They are only exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`.- * Accessing members will expose code to API and/or ABI break in future versions of the library.+ * Accessing members will expose user code to API and/or ABI break in future versions of the library.  **************************************************************/ #define LZ4_HASHLOG   (LZ4_MEMORY_USAGE-2) #define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) #define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG)       /* required as macro for static allocation */  #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)-#include <stdint.h>--typedef struct LZ4_stream_t_internal LZ4_stream_t_internal;-struct LZ4_stream_t_internal {-    uint32_t hashTable[LZ4_HASH_SIZE_U32];-    uint32_t currentOffset;-    uint16_t dirty;-    uint16_t tableType;-    const uint8_t* dictionary;-    const LZ4_stream_t_internal* dictCtx;-    uint32_t dictSize;-};--typedef struct {-    const uint8_t* externalDict;-    size_t extDictSize;-    const uint8_t* prefixEnd;-    size_t prefixSize;-} LZ4_streamDecode_t_internal;-+# include <stdint.h>+  typedef  int8_t  LZ4_i8;+  typedef uint8_t  LZ4_byte;+  typedef uint16_t LZ4_u16;+  typedef uint32_t LZ4_u32; #else+  typedef   signed char  LZ4_i8;+  typedef unsigned char  LZ4_byte;+  typedef unsigned short LZ4_u16;+  typedef unsigned int   LZ4_u32;+#endif +/*! LZ4_stream_t :+ *  Never ever use below internal definitions directly !+ *  These definitions are not API/ABI safe, and may change in future versions.+ *  If you need static allocation, declare or allocate an LZ4_stream_t object.+**/+ typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; struct LZ4_stream_t_internal {-    unsigned int hashTable[LZ4_HASH_SIZE_U32];-    unsigned int currentOffset;-    unsigned short dirty;-    unsigned short tableType;-    const unsigned char* dictionary;+    LZ4_u32 hashTable[LZ4_HASH_SIZE_U32];+    const LZ4_byte* dictionary;     const LZ4_stream_t_internal* dictCtx;-    unsigned int dictSize;+    LZ4_u32 currentOffset;+    LZ4_u32 tableType;+    LZ4_u32 dictSize;+    /* Implicit padding to ensure structure is aligned */ }; -typedef struct {-    const unsigned char* externalDict;-    const unsigned char* prefixEnd;-    size_t extDictSize;-    size_t prefixSize;-} LZ4_streamDecode_t_internal;--#endif--/*! LZ4_stream_t :- *  information structure to track an LZ4 stream.- *  LZ4_stream_t can also be created using LZ4_createStream(), which is recommended.- *  The structure definition can be convenient for static allocation- *  (on stack, or as part of larger structure).- *  Init this structure with LZ4_initStream() before first use.- *  note : only use this definition in association with static linking !- *    this definition is not API/ABI safe, and may change in a future version.- */-#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4 + ((sizeof(void*)==16) ? 4 : 0) /*AS-400*/ )-#define LZ4_STREAMSIZE     (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long))+#define LZ4_STREAM_MINSIZE  ((1UL << LZ4_MEMORY_USAGE) + 32)  /* static size, for inter-version compatibility */ union LZ4_stream_u {-    unsigned long long table[LZ4_STREAMSIZE_U64];+    char minStateSize[LZ4_STREAM_MINSIZE];     LZ4_stream_t_internal internal_donotuse;-} ;  /* previously typedef'd to LZ4_stream_t */+}; /* previously typedef'd to LZ4_stream_t */ + /*! LZ4_initStream() : v1.9.0+  *  An LZ4_stream_t structure must be initialized at least once.  *  This is automatically done when invoking LZ4_createStream(),@@ -629,21 +705,25 @@  *         In which case, the function will @return NULL.  *  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);   /*! LZ4_streamDecode_t :- *  information structure to track an LZ4 stream during decompression.- *  init this structure  using LZ4_setStreamDecode() before first use.- *  note : only use in association with static linking !- *         this definition is not API/ABI safe,- *         and may change in a future version !- */-#define LZ4_STREAMDECODESIZE_U64 (4 + ((sizeof(void*)==16) ? 2 : 0) /*AS-400*/ )-#define LZ4_STREAMDECODESIZE     (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))+ *  Never ever use below internal definitions directly !+ *  These definitions are not API/ABI safe, and may change in future versions.+ *  If you need static allocation, declare or allocate an LZ4_streamDecode_t object.+**/+typedef struct {+    const LZ4_byte* externalDict;+    const LZ4_byte* prefixEnd;+    size_t extDictSize;+    size_t prefixSize;+} LZ4_streamDecode_t_internal;++#define LZ4_STREAMDECODE_MINSIZE 32 union LZ4_streamDecode_u {-    unsigned long long table[LZ4_STREAMDECODESIZE_U64];+    char minStateSize[LZ4_STREAMDECODE_MINSIZE];     LZ4_streamDecode_t_internal internal_donotuse; } ;   /* previously typedef'd to LZ4_streamDecode_t */ @@ -667,22 +747,21 @@ #ifdef LZ4_DISABLE_DEPRECATE_WARNINGS #  define LZ4_DEPRECATED(message)   /* disable deprecation warnings */ #else-#  define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #  if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ #    define LZ4_DEPRECATED(message) [[deprecated(message)]]-#  elif (LZ4_GCC_VERSION >= 405) || defined(__clang__)-#    define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))-#  elif (LZ4_GCC_VERSION >= 301)-#    define LZ4_DEPRECATED(message) __attribute__((deprecated)) #  elif defined(_MSC_VER) #    define LZ4_DEPRECATED(message) __declspec(deprecated(message))+#  elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45))+#    define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))+#  elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31)+#    define LZ4_DEPRECATED(message) __attribute__((deprecated)) #  else-#    pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler")-#    define LZ4_DEPRECATED(message)+#    pragma message("WARNING: LZ4_DEPRECATED needs custom implementation for this compiler")+#    define LZ4_DEPRECATED(message)   /* disabled */ #  endif #endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */ -/* Obsolete compression functions */+/*! Obsolete compression functions (since v1.7.3) */ LZ4_DEPRECATED("use LZ4_compress_default() instead")       LZ4LIB_API int LZ4_compress               (const char* src, char* dest, int srcSize); LZ4_DEPRECATED("use LZ4_compress_default() instead")       LZ4LIB_API int LZ4_compress_limitedOutput (const char* src, char* dest, int srcSize, int maxOutputSize); LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_withState               (void* state, const char* source, char* dest, int inputSize);@@ -690,11 +769,12 @@ LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_continue                (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_limitedOutput_continue  (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); -/* Obsolete decompression functions */+/*! Obsolete decompression functions (since v1.8.0) */ LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize); LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); -/* Obsolete streaming functions; degraded functionality; do not use!+/* Obsolete streaming functions (since v1.7.0)+ * degraded functionality; do not use!  *  * In order to perform streaming compression, these functions depended on data  * that is no longer tracked in the state. They have been preserved as well as@@ -708,23 +788,22 @@ LZ4_DEPRECATED("Use LZ4_resetStream() instead")  LZ4LIB_API int   LZ4_resetStreamState(void* state, char* inputBuffer); LZ4_DEPRECATED("Use LZ4_saveDict() instead")     LZ4LIB_API char* LZ4_slideInputBuffer (void* state); -/* Obsolete streaming decoding functions */+/*! Obsolete streaming decoding functions (since v1.7.0) */ LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); -/*! LZ4_decompress_fast() : **unsafe!**+/*! Obsolete LZ4_decompress_fast variants (since v1.9.0) :  *  These functions used to be faster than LZ4_decompress_safe(),- *  but it has changed, and they are now slower than LZ4_decompress_safe().+ *  but this is no longer the case. They are now slower.  *  This is because LZ4_decompress_fast() doesn't know the input size,- *  and therefore must progress more cautiously in the input buffer to not read beyond the end of block.+ *  and therefore must progress more cautiously into the input buffer to not read beyond the end of block.  *  On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability.  *  As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated.  *  *  The last remaining LZ4_decompress_fast() specificity is that  *  it can decompress a block without knowing its compressed size.- *  Such functionality could be achieved in a more secure manner,- *  by also providing the maximum size of input buffer,- *  but it would require new prototypes, and adaptation of the implementation to this new use case.+ *  Such functionality can be achieved in a more secure manner+ *  by employing LZ4_decompress_safe_partial().  *  *  Parameters:  *  originalSize : is the uncompressed size to regenerate.@@ -739,7 +818,6 @@  *         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") 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")
+ cbits/lz4frame.c view
@@ -0,0 +1,2078 @@+/*+ * LZ4 auto-framing library+ * Copyright (C) 2011-2016, Yann Collet.+ *+ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions are+ * met:+ *+ * - Redistributions of source code must retain the above copyright+ *   notice, this list of conditions and the following disclaimer.+ * - Redistributions in binary form must reproduce the above+ *   copyright notice, this list of conditions and the following disclaimer+ *   in the documentation and/or other materials provided with the+ *   distribution.+ *+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+ *+ * You can contact the author at :+ * - LZ4 homepage : http://www.lz4.org+ * - LZ4 source repository : https://github.com/lz4/lz4+ */++/* LZ4F is a stand-alone API to create LZ4-compressed Frames+ * in full conformance with specification v1.6.1 .+ * This library rely upon memory management capabilities (malloc, free)+ * provided either by <stdlib.h>,+ * or redirected towards another library of user's choice+ * (see Memory Routines below).+ */+++/*-************************************+*  Compiler Options+**************************************/+#ifdef _MSC_VER    /* Visual Studio */+#  pragma warning(disable : 4127)   /* disable: C4127: conditional expression is constant */+#endif+++/*-************************************+*  Tuning parameters+**************************************/+/*+ * 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()).+ */+#ifndef LZ4F_HEAPMODE+#  define LZ4F_HEAPMODE 0+#endif+++/*-************************************+*  Library declarations+**************************************/+#define LZ4F_STATIC_LINKING_ONLY+#include "lz4frame.h"+#define LZ4_STATIC_LINKING_ONLY+#include "lz4.h"+#define LZ4_HC_STATIC_LINKING_ONLY+#include "lz4hc.h"+#define XXH_STATIC_LINKING_ONLY+#include "xxhash.h"+++/*-************************************+*  Memory routines+**************************************/+/*+ * User may redirect invocations of+ * malloc(), calloc() and free()+ * towards another library or solution of their choice+ * by modifying below section.+**/++#include <string.h>   /* memset, memcpy, memmove */+#ifndef LZ4_SRC_INCLUDED  /* avoid redefinition when sources are coalesced */+#  define MEM_INIT(p,v,s)   memset((p),(v),(s))+#endif++#ifndef LZ4_SRC_INCLUDED   /* avoid redefinition when sources are coalesced */+#  include <stdlib.h>   /* malloc, calloc, free */+#  define ALLOC(s)          malloc(s)+#  define ALLOC_AND_ZERO(s) calloc(1,(s))+#  define FREEMEM(p)        free(p)+#endif++static void* LZ4F_calloc(size_t s, LZ4F_CustomMem cmem)+{+    /* custom calloc defined : use it */+    if (cmem.customCalloc != NULL) {+        return cmem.customCalloc(cmem.opaqueState, s);+    }+    /* nothing defined : use default <stdlib.h>'s calloc() */+    if (cmem.customAlloc == NULL) {+        return ALLOC_AND_ZERO(s);+    }+    /* only custom alloc defined : use it, and combine it with memset() */+    {   void* const p = cmem.customAlloc(cmem.opaqueState, s);+        if (p != NULL) MEM_INIT(p, 0, s);+        return p;+}   }++static void* LZ4F_malloc(size_t s, LZ4F_CustomMem cmem)+{+    /* custom malloc defined : use it */+    if (cmem.customAlloc != NULL) {+        return cmem.customAlloc(cmem.opaqueState, s);+    }+    /* nothing defined : use default <stdlib.h>'s malloc() */+    return ALLOC(s);+}++static void LZ4F_free(void* p, LZ4F_CustomMem cmem)+{+    /* custom malloc defined : use it */+    if (cmem.customFree != NULL) {+        cmem.customFree(cmem.opaqueState, p);+        return;+    }+    /* nothing defined : use default <stdlib.h>'s free() */+    FREEMEM(p);+}+++/*-************************************+*  Debug+**************************************/+#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=1)+#  include <assert.h>+#else+#  ifndef assert+#    define assert(condition) ((void)0)+#  endif+#endif++#define LZ4F_STATIC_ASSERT(c)    { enum { LZ4F_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */++#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2) && !defined(DEBUGLOG)+#  include <stdio.h>+static int g_debuglog_enable = 1;+#  define DEBUGLOG(l, ...) {                                  \+                if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) {  \+                    fprintf(stderr, __FILE__ ": ");           \+                    fprintf(stderr, __VA_ARGS__);             \+                    fprintf(stderr, " \n");                   \+            }   }+#else+#  define DEBUGLOG(l, ...)      {}    /* disabled */+#endif+++/*-************************************+*  Basic Types+**************************************/+#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )+# include <stdint.h>+  typedef  uint8_t BYTE;+  typedef uint16_t U16;+  typedef uint32_t U32;+  typedef  int32_t S32;+  typedef uint64_t U64;+#else+  typedef unsigned char       BYTE;+  typedef unsigned short      U16;+  typedef unsigned int        U32;+  typedef   signed int        S32;+  typedef unsigned long long  U64;+#endif+++/* unoptimized version; solves endianness & alignment issues */+static U32 LZ4F_readLE32 (const void* src)+{+    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;+    return value32;+}++static void LZ4F_writeLE32 (void* dst, U32 value32)+{+    BYTE* const dstPtr = (BYTE*)dst;+    dstPtr[0] = (BYTE)value32;+    dstPtr[1] = (BYTE)(value32 >> 8);+    dstPtr[2] = (BYTE)(value32 >> 16);+    dstPtr[3] = (BYTE)(value32 >> 24);+}++static U64 LZ4F_readLE64 (const void* src)+{+    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);+    return value64;+}++static void LZ4F_writeLE64 (void* dst, U64 value64)+{+    BYTE* const dstPtr = (BYTE*)dst;+    dstPtr[0] = (BYTE)value64;+    dstPtr[1] = (BYTE)(value64 >> 8);+    dstPtr[2] = (BYTE)(value64 >> 16);+    dstPtr[3] = (BYTE)(value64 >> 24);+    dstPtr[4] = (BYTE)(value64 >> 32);+    dstPtr[5] = (BYTE)(value64 >> 40);+    dstPtr[6] = (BYTE)(value64 >> 48);+    dstPtr[7] = (BYTE)(value64 >> 56);+}+++/*-************************************+*  Constants+**************************************/+#ifndef LZ4_SRC_INCLUDED   /* avoid double definition */+#  define KB *(1<<10)+#  define MB *(1<<20)+#  define GB *(1<<30)+#endif++#define _1BIT  0x01+#define _2BITS 0x03+#define _3BITS 0x07+#define _4BITS 0x0F+#define _8BITS 0xFF++#define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U+#define LZ4F_BLOCKSIZEID_DEFAULT LZ4F_max64KB++static const size_t minFHSize = LZ4F_HEADER_SIZE_MIN;   /*  7 */+static const size_t maxFHSize = LZ4F_HEADER_SIZE_MAX;   /* 19 */+static const size_t BHSize = LZ4F_BLOCK_HEADER_SIZE;  /* block header : size, and compress flag */+static const size_t BFSize = LZ4F_BLOCK_CHECKSUM_SIZE;  /* block footer : checksum (optional) */+++/*-************************************+*  Structures and local types+**************************************/++typedef enum { LZ4B_COMPRESSED, LZ4B_UNCOMPRESSED} LZ4F_blockCompression_t;++typedef struct LZ4F_cctx_s+{+    LZ4F_CustomMem cmem;+    LZ4F_preferences_t prefs;+    U32    version;+    U32    cStage;+    const LZ4F_CDict* cdict;+    size_t maxBlockSize;+    size_t maxBufferSize;+    BYTE*  tmpBuff;    /* internal buffer, for streaming */+    BYTE*  tmpIn;      /* starting position of data compress within internal buffer (>= tmpBuff) */+    size_t tmpInSize;  /* amount of data to compress after tmpIn */+    U64    totalInSize;+    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;+} LZ4F_cctx_t;+++/*-************************************+*  Error management+**************************************/+#define LZ4F_GENERATE_STRING(STRING) #STRING,+static const char* LZ4F_errorStrings[] = { LZ4F_LIST_ERRORS(LZ4F_GENERATE_STRING) };+++unsigned LZ4F_isError(LZ4F_errorCode_t code)+{+    return (code > (LZ4F_errorCode_t)(-LZ4F_ERROR_maxCode));+}++const char* LZ4F_getErrorName(LZ4F_errorCode_t code)+{+    static const char* codeError = "Unspecified error code";+    if (LZ4F_isError(code)) return LZ4F_errorStrings[-(int)(code)];+    return codeError;+}++LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult)+{+    if (!LZ4F_isError(functionResult)) return LZ4F_OK_NoError;+    return (LZ4F_errorCodes)(-(ptrdiff_t)functionResult);+}++static LZ4F_errorCode_t LZ4F_returnErrorCode(LZ4F_errorCodes code)+{+    /* A compilation error here means sizeof(ptrdiff_t) is not large enough */+    LZ4F_STATIC_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t));+    return (LZ4F_errorCode_t)-(ptrdiff_t)code;+}++#define RETURN_ERROR(e) return LZ4F_returnErrorCode(LZ4F_ERROR_ ## e)++#define RETURN_ERROR_IF(c,e) if (c) RETURN_ERROR(e)++#define FORWARD_IF_ERROR(r)  if (LZ4F_isError(r)) return (r)++unsigned LZ4F_getVersion(void) { return LZ4F_VERSION; }++int LZ4F_compressionLevel_max(void) { return LZ4HC_CLEVEL_MAX; }++size_t LZ4F_getBlockSize(LZ4F_blockSizeID_t blockSizeID)+{+    static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB };++    if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;+    if (blockSizeID < LZ4F_max64KB || blockSizeID > LZ4F_max4MB)+        RETURN_ERROR(maxBlockSize_invalid);+    {   int const blockSizeIdx = (int)blockSizeID - (int)LZ4F_max64KB;+        return blockSizes[blockSizeIdx];+}   }++/*-************************************+*  Private functions+**************************************/+#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )++static BYTE LZ4F_headerChecksum (const void* header, size_t length)+{+    U32 const xxh = XXH32(header, length, 0);+    return (BYTE)(xxh >> 8);+}+++/*-************************************+*  Simple-pass compression functions+**************************************/+static LZ4F_blockSizeID_t LZ4F_optimalBSID(const LZ4F_blockSizeID_t requestedBSID,+                                           const size_t srcSize)+{+    LZ4F_blockSizeID_t proposedBSID = LZ4F_max64KB;+    size_t maxBlockSize = 64 KB;+    while (requestedBSID > proposedBSID) {+        if (srcSize <= maxBlockSize)+            return proposedBSID;+        proposedBSID = (LZ4F_blockSizeID_t)((int)proposedBSID + 1);+        maxBlockSize <<= 2;+    }+    return requestedBSID;+}++/*! LZ4F_compressBound_internal() :+ *  Provides dstCapacity given a srcSize to guarantee operation success in worst case situations.+ *  prefsPtr is optional : if NULL is provided, preferences will be set to cover worst case scenario.+ * @return is always the same for a srcSize and prefsPtr, so it can be relied upon to size reusable buffers.+ *  When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() operations.+ */+static size_t LZ4F_compressBound_internal(size_t srcSize,+                                    const LZ4F_preferences_t* preferencesPtr,+                                          size_t alreadyBuffered)+{+    LZ4F_preferences_t prefsNull = LZ4F_INIT_PREFERENCES;+    prefsNull.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;   /* worst case */+    prefsNull.frameInfo.blockChecksumFlag = LZ4F_blockChecksumEnabled;   /* worst case */+    {   const LZ4F_preferences_t* const prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr;+        U32 const flush = prefsPtr->autoFlush | (srcSize==0);+        LZ4F_blockSizeID_t const blockID = prefsPtr->frameInfo.blockSizeID;+        size_t const blockSize = LZ4F_getBlockSize(blockID);+        size_t const maxBuffered = blockSize - 1;+        size_t const bufferedSize = MIN(alreadyBuffered, maxBuffered);+        size_t const maxSrcSize = srcSize + bufferedSize;+        unsigned const nbFullBlocks = (unsigned)(maxSrcSize / blockSize);+        size_t const partialBlockSize = maxSrcSize & (blockSize-1);+        size_t const lastBlockSize = flush ? partialBlockSize : 0;+        unsigned const nbBlocks = nbFullBlocks + (lastBlockSize>0);++        size_t const blockCRCSize = BFSize * prefsPtr->frameInfo.blockChecksumFlag;+        size_t const frameEnd = BHSize + (prefsPtr->frameInfo.contentChecksumFlag*BFSize);++        return ((BHSize + blockCRCSize) * nbBlocks) ++               (blockSize * nbFullBlocks) + lastBlockSize + frameEnd;+    }+}++size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)+{+    LZ4F_preferences_t prefs;+    size_t const headerSize = maxFHSize;      /* max header size, including optional fields */++    if (preferencesPtr!=NULL) prefs = *preferencesPtr;+    else MEM_INIT(&prefs, 0, sizeof(prefs));+    prefs.autoFlush = 1;++    return headerSize + LZ4F_compressBound_internal(srcSize, &prefs, 0);;+}+++/*! LZ4F_compressFrame_usingCDict() :+ *  Compress srcBuffer using a dictionary, in a single step.+ *  cdict can be NULL, in which case, no dictionary is used.+ *  dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).+ *  The LZ4F_preferences_t structure is optional : you may provide NULL as argument,+ *  however, it's the only way to provide a dictID, so it's not recommended.+ * @return : number of bytes written into dstBuffer,+ *           or an error code if it fails (can be tested using LZ4F_isError())+ */+size_t LZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx,+                                     void* dstBuffer, size_t dstCapacity,+                               const void* srcBuffer, size_t srcSize,+                               const LZ4F_CDict* cdict,+                               const LZ4F_preferences_t* preferencesPtr)+{+    LZ4F_preferences_t prefs;+    LZ4F_compressOptions_t options;+    BYTE* const dstStart = (BYTE*) dstBuffer;+    BYTE* dstPtr = dstStart;+    BYTE* const dstEnd = dstStart + dstCapacity;++    if (preferencesPtr!=NULL)+        prefs = *preferencesPtr;+    else+        MEM_INIT(&prefs, 0, sizeof(prefs));+    if (prefs.frameInfo.contentSize != 0)+        prefs.frameInfo.contentSize = (U64)srcSize;   /* auto-correct content size if selected (!=0) */++    prefs.frameInfo.blockSizeID = LZ4F_optimalBSID(prefs.frameInfo.blockSizeID, srcSize);+    prefs.autoFlush = 1;+    if (srcSize <= LZ4F_getBlockSize(prefs.frameInfo.blockSizeID))+        prefs.frameInfo.blockMode = LZ4F_blockIndependent;   /* only one block => no need for inter-block link */++    MEM_INIT(&options, 0, sizeof(options));+    options.stableSrc = 1;++    RETURN_ERROR_IF(dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs), dstMaxSize_tooSmall);++    { size_t const headerSize = LZ4F_compressBegin_usingCDict(cctx, dstBuffer, dstCapacity, cdict, &prefs);  /* write header */+      FORWARD_IF_ERROR(headerSize);+      dstPtr += headerSize;   /* header size */ }++    assert(dstEnd >= dstPtr);+    { size_t const cSize = LZ4F_compressUpdate(cctx, dstPtr, (size_t)(dstEnd-dstPtr), srcBuffer, srcSize, &options);+      FORWARD_IF_ERROR(cSize);+      dstPtr += cSize; }++    assert(dstEnd >= dstPtr);+    { size_t const tailSize = LZ4F_compressEnd(cctx, dstPtr, (size_t)(dstEnd-dstPtr), &options);   /* flush last block, and generate suffix */+      FORWARD_IF_ERROR(tailSize);+      dstPtr += tailSize; }++    assert(dstEnd >= dstStart);+    return (size_t)(dstPtr - dstStart);+}+++/*! LZ4F_compressFrame() :+ *  Compress an entire srcBuffer into a valid LZ4 frame, in a single step.+ *  dstBuffer 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())+ */+size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity,+                    const void* srcBuffer, size_t srcSize,+                    const LZ4F_preferences_t* preferencesPtr)+{+    size_t result;+#if (LZ4F_HEAPMODE)+    LZ4F_cctx_t* cctxPtr;+    result = LZ4F_createCompressionContext(&cctxPtr, LZ4F_VERSION);+    FORWARD_IF_ERROR(result);+#else+    LZ4F_cctx_t cctx;+    LZ4_stream_t lz4ctx;+    LZ4F_cctx_t* const cctxPtr = &cctx;++    MEM_INIT(&cctx, 0, sizeof(cctx));+    cctx.version = LZ4F_VERSION;+    cctx.maxBufferSize = 5 MB;   /* mess with real buffer size to prevent dynamic allocation; works only because autoflush==1 & stableSrc==1 */+    if ( preferencesPtr == NULL+      || preferencesPtr->compressionLevel < LZ4HC_CLEVEL_MIN ) {+        LZ4_initStream(&lz4ctx, sizeof(lz4ctx));+        cctxPtr->lz4CtxPtr = &lz4ctx;+        cctxPtr->lz4CtxAlloc = 1;+        cctxPtr->lz4CtxState = 1;+    }+#endif+    DEBUGLOG(4, "LZ4F_compressFrame");++    result = LZ4F_compressFrame_usingCDict(cctxPtr, dstBuffer, dstCapacity,+                                           srcBuffer, srcSize,+                                           NULL, preferencesPtr);++#if (LZ4F_HEAPMODE)+    LZ4F_freeCompressionContext(cctxPtr);+#else+    if ( preferencesPtr != NULL+      && preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN ) {+        LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem);+    }+#endif+    return result;+}+++/*-***************************************************+*   Dictionary compression+*****************************************************/++struct LZ4F_CDict_s {+    LZ4F_CustomMem cmem;+    void* dictContent;+    LZ4_stream_t* fastCtx;+    LZ4_streamHC_t* HCCtx;+}; /* typedef'd to LZ4F_CDict within lz4frame_static.h */++LZ4F_CDict*+LZ4F_createCDict_advanced(LZ4F_CustomMem cmem, const void* dictBuffer, size_t dictSize)+{+    const char* dictStart = (const char*)dictBuffer;+    LZ4F_CDict* const cdict = (LZ4F_CDict*)LZ4F_malloc(sizeof(*cdict), cmem);+    DEBUGLOG(4, "LZ4F_createCDict_advanced");+    if (!cdict) return NULL;+    cdict->cmem = cmem;+    if (dictSize > 64 KB) {+        dictStart += dictSize - 64 KB;+        dictSize = 64 KB;+    }+    cdict->dictContent = LZ4F_malloc(dictSize, cmem);+    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_setCompressionLevel(cdict->HCCtx, LZ4HC_CLEVEL_DEFAULT);+    LZ4_loadDictHC(cdict->HCCtx, (const char*)cdict->dictContent, (int)dictSize);+    return cdict;+}++/*! LZ4F_createCDict() :+ *  When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once.+ *  LZ4F_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay.+ *  LZ4F_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.+ * @dictBuffer can be released after LZ4F_CDict creation, since its content is copied within CDict+ * @return : digested dictionary for compression, or NULL if failed */+LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize)+{+    DEBUGLOG(4, "LZ4F_createCDict");+    return LZ4F_createCDict_advanced(LZ4F_defaultCMem, dictBuffer, dictSize);+}++void LZ4F_freeCDict(LZ4F_CDict* cdict)+{+    if (cdict==NULL) return;  /* support free on NULL */+    LZ4F_free(cdict->dictContent, cdict->cmem);+    LZ4F_free(cdict->fastCtx, cdict->cmem);+    LZ4F_free(cdict->HCCtx, cdict->cmem);+    LZ4F_free(cdict, cdict->cmem);+}+++/*-*********************************+*  Advanced compression functions+***********************************/++LZ4F_cctx*+LZ4F_createCompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version)+{+    LZ4F_cctx* const cctxPtr =+        (LZ4F_cctx*)LZ4F_calloc(sizeof(LZ4F_cctx), customMem);+    if (cctxPtr==NULL) return NULL;++    cctxPtr->cmem = customMem;+    cctxPtr->version = version;+    cctxPtr->cStage = 0;   /* Uninitialized. Next stage : init cctx */++    return cctxPtr;+}++/*! LZ4F_createCompressionContext() :+ *  The first thing to do is to create a compressionContext object, which will be used in all compression operations.+ *  This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure.+ *  The version provided MUST be LZ4F_VERSION. It is intended to track potential incompatible differences between different binaries.+ *  The function will provide a pointer to an allocated LZ4F_compressionContext_t object.+ *  If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation.+ *  Object can release its memory using LZ4F_freeCompressionContext();+**/+LZ4F_errorCode_t+LZ4F_createCompressionContext(LZ4F_cctx** LZ4F_compressionContextPtr, unsigned version)+{+    assert(LZ4F_compressionContextPtr != NULL); /* considered a violation of narrow contract */+    /* in case it nonetheless happen in production */+    RETURN_ERROR_IF(LZ4F_compressionContextPtr == NULL, parameter_null);++    *LZ4F_compressionContextPtr = LZ4F_createCompressionContext_advanced(LZ4F_defaultCMem, version);+    RETURN_ERROR_IF(*LZ4F_compressionContextPtr==NULL, allocation_failed);+    return LZ4F_OK_NoError;+}+++LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctxPtr)+{+    if (cctxPtr != NULL) {  /* support free on NULL */+       LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem);  /* note: LZ4_streamHC_t and LZ4_stream_t are simple POD types */+       LZ4F_free(cctxPtr->tmpBuff, cctxPtr->cmem);+       LZ4F_free(cctxPtr, cctxPtr->cmem);+    }+    return LZ4F_OK_NoError;+}+++/**+ * This function prepares the internal LZ4(HC) stream for a new compression,+ * resetting the context and attaching the dictionary, if there is one.+ *+ * It needs to be called at the beginning of each independent compression+ * stream (i.e., at the beginning of a frame in blockLinked mode, or at the+ * beginning of each block in blockIndependent mode).+ */+static void LZ4F_initStream(void* ctx,+                            const LZ4F_CDict* cdict,+                            int level,+                            LZ4F_blockMode_t blockMode) {+    if (level < LZ4HC_CLEVEL_MIN) {+        if (cdict != NULL || 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+             * resets at the beginning of their calls, where they know what+             * 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);+        }+        LZ4_attach_dictionary((LZ4_stream_t *)ctx, cdict ? cdict->fastCtx : NULL);+    } else {+        LZ4_resetStreamHC_fast((LZ4_streamHC_t*)ctx, level);+        LZ4_attach_HC_dictionary((LZ4_streamHC_t *)ctx, cdict ? cdict->HCCtx : NULL);+    }+}++static int ctxTypeID_to_size(int ctxTypeID) {+    switch(ctxTypeID) {+    case 1:+        return LZ4_sizeofState();+    case 2:+        return LZ4_sizeofStateHC();+    default:+        return 0;+    }+}++/*! 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())+ */+size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,+                          void* dstBuffer, size_t dstCapacity,+                          const LZ4F_CDict* cdict,+                          const LZ4F_preferences_t* preferencesPtr)+{+    LZ4F_preferences_t const prefNull = LZ4F_INIT_PREFERENCES;+    BYTE* const dstStart = (BYTE*)dstBuffer;+    BYTE* dstPtr = dstStart;++    RETURN_ERROR_IF(dstCapacity < maxFHSize, dstMaxSize_tooSmall);+    if (preferencesPtr == NULL) preferencesPtr = &prefNull;+    cctxPtr->prefs = *preferencesPtr;++    /* cctx Management */+    {   U16 const ctxTypeID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2;+        int requiredSize = ctxTypeID_to_size(ctxTypeID);+        int allocatedSize = ctxTypeID_to_size(cctxPtr->lz4CtxAlloc);+        if (allocatedSize < requiredSize) {+            /* not enough space allocated */+            LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem);+            if (cctxPtr->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));+            } else {+                cctxPtr->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_streamHC_t), cctxPtr->cmem);+                if (cctxPtr->lz4CtxPtr)+                    LZ4_initStreamHC(cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t));+            }+            RETURN_ERROR_IF(cctxPtr->lz4CtxPtr == NULL, allocation_failed);+            cctxPtr->lz4CtxAlloc = ctxTypeID;+            cctxPtr->lz4CtxState = ctxTypeID;+        } else if (cctxPtr->lz4CtxState != 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));+            } else {+                LZ4_initStreamHC((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t));+                LZ4_setCompressionLevel((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);+            }+            cctxPtr->lz4CtxState = ctxTypeID;+    }   }++    /* Buffer Management */+    if (cctxPtr->prefs.frameInfo.blockSizeID == 0)+        cctxPtr->prefs.frameInfo.blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;+    cctxPtr->maxBlockSize = LZ4F_getBlockSize(cctxPtr->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);++        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;+    }   }+    cctxPtr->tmpIn = cctxPtr->tmpBuff;+    cctxPtr->tmpInSize = 0;+    (void)XXH32_reset(&(cctxPtr->xxh), 0);++    /* context init */+    cctxPtr->cdict = cdict;+    if (cctxPtr->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);+    }+    if (preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN) {+        LZ4_favorDecompressionSpeed((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, (int)preferencesPtr->favorDecSpeed);+    }++    /* Magic Number */+    LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER);+    dstPtr += 4;+    {   BYTE* const headerStart = dstPtr;++        /* 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) );+        /* BD Byte */+        *dstPtr++ = (BYTE)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4);+        /* Optional Frame content size field */+        if (cctxPtr->prefs.frameInfo.contentSize) {+            LZ4F_writeLE64(dstPtr, cctxPtr->prefs.frameInfo.contentSize);+            dstPtr += 8;+            cctxPtr->totalInSize = 0;+        }+        /* Optional dictionary ID field */+        if (cctxPtr->prefs.frameInfo.dictID) {+            LZ4F_writeLE32(dstPtr, cctxPtr->prefs.frameInfo.dictID);+            dstPtr += 4;+        }+        /* Header CRC Byte */+        *dstPtr = LZ4F_headerChecksum(headerStart, (size_t)(dstPtr - headerStart));+        dstPtr++;+    }++    cctxPtr->cStage = 1;   /* header written, now request input data block */+    return (size_t)(dstPtr - dstStart);+}+++/*! 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,+                          void* dstBuffer, size_t dstCapacity,+                          const LZ4F_preferences_t* preferencesPtr)+{+    return LZ4F_compressBegin_usingCDict(cctxPtr, dstBuffer, dstCapacity,+                                         NULL, 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.+ *  This function cannot fail.+ */+size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)+{+    if (preferencesPtr && preferencesPtr->autoFlush) {+        return LZ4F_compressBound_internal(srcSize, preferencesPtr, 0);+    }+    return LZ4F_compressBound_internal(srcSize, preferencesPtr, (size_t)-1);+}+++typedef int (*compressFunc_t)(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level, const LZ4F_CDict* cdict);+++/*! LZ4F_makeBlock():+ *  compress a single block, add header and optional checksum.+ *  assumption : dst buffer capacity is >= BHSize + srcSize + crcSize+ */+static size_t LZ4F_makeBlock(void* dst,+                       const void* src, size_t srcSize,+                             compressFunc_t compress, void* lz4ctx, int level,+                       const LZ4F_CDict* cdict,+                             LZ4F_blockChecksum_t crcFlag)+{+    BYTE* const cSizePtr = (BYTE*)dst;+    U32 cSize;+    assert(compress != NULL);+    cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+BHSize),+                          (int)(srcSize), (int)(srcSize-1),+                          level, cdict);++    if (cSize == 0 || cSize >= srcSize) {+        cSize = (U32)srcSize;+        LZ4F_writeLE32(cSizePtr, cSize | LZ4F_BLOCKUNCOMPRESSED_FLAG);+        memcpy(cSizePtr+BHSize, src, srcSize);+    } else {+        LZ4F_writeLE32(cSizePtr, cSize);+    }+    if (crcFlag) {+        U32 const crc32 = XXH32(cSizePtr+BHSize, cSize, 0);  /* checksum of compressed data */+        LZ4F_writeLE32(cSizePtr+BHSize+cSize, crc32);+    }+    return BHSize + cSize + ((U32)crcFlag)*BFSize;+}+++static int LZ4F_compressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)+{+    int const acceleration = (level < 0) ? -level + 1 : 1;+    DEBUGLOG(5, "LZ4F_compressBlock (srcSize=%i)", srcSize);+    LZ4F_initStream(ctx, cdict, level, LZ4F_blockIndependent);+    if (cdict) {+        return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration);+    } else {+        return LZ4_compress_fast_extState_fastReset(ctx, src, dst, srcSize, dstCapacity, acceleration);+    }+}++static int LZ4F_compressBlock_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)+{+    int const acceleration = (level < 0) ? -level + 1 : 1;+    (void)cdict; /* init once at beginning of frame */+    DEBUGLOG(5, "LZ4F_compressBlock_continue (srcSize=%i)", srcSize);+    return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration);+}++static int LZ4F_compressBlockHC(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)+{+    LZ4F_initStream(ctx, cdict, level, LZ4F_blockIndependent);+    if (cdict) {+        return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity);+    }+    return LZ4_compress_HC_extStateHC_fastReset(ctx, src, dst, srcSize, dstCapacity, level);+}++static int LZ4F_compressBlockHC_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)+{+    (void)level; (void)cdict; /* init once at beginning of frame */+    return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity);+}++static int LZ4F_doNotCompressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)+{+    (void)ctx; (void)src; (void)dst; (void)srcSize; (void)dstCapacity; (void)level; (void)cdict;+    return 0;+}++static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int level, LZ4F_blockCompression_t  compressMode)+{+    if (compressMode == LZ4B_UNCOMPRESSED) return LZ4F_doNotCompressBlock;+    if (level < LZ4HC_CLEVEL_MIN) {+        if (blockMode == LZ4F_blockIndependent) return LZ4F_compressBlock;+        return LZ4F_compressBlock_continue;+    }+    if (blockMode == LZ4F_blockIndependent) return LZ4F_compressBlockHC;+    return LZ4F_compressBlockHC_continue;+}++/* Save history (up to 64KB) into @tmpBuff */+static int LZ4F_localSaveDict(LZ4F_cctx_t* cctxPtr)+{+    if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN)+        return LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);+    return LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);+}++typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus;++static const LZ4F_compressOptions_t k_cOptionsNull = { 0, { 0, 0, 0 } };+++ /*! LZ4F_compressUpdateImpl() :+ *  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 the block compression does not match the compression of the previous block, the old data is flushed+ *  and operations continue with the new compression mode.+ * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr) when block compression is turned on.+ * @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.+ *           or an error code if it fails (which can be tested using LZ4F_isError())+ *  After an error, the state is left in a UB state, and must be re-initialized.+ */+static size_t LZ4F_compressUpdateImpl(LZ4F_cctx* cctxPtr,+                     void* dstBuffer, size_t dstCapacity,+                     const void* srcBuffer, size_t srcSize,+                     const LZ4F_compressOptions_t* compressOptionsPtr,+                     LZ4F_blockCompression_t blockCompression)+  {+    size_t const blockSize = cctxPtr->maxBlockSize;+    const BYTE* srcPtr = (const BYTE*)srcBuffer;+    const BYTE* const srcEnd = srcPtr + srcSize;+    BYTE* const dstStart = (BYTE*)dstBuffer;+    BYTE* dstPtr = dstStart;+    LZ4F_lastBlockStatus lastBlockCompressed = notDone;+    compressFunc_t const compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, blockCompression);+    size_t bytesWritten;+    DEBUGLOG(4, "LZ4F_compressUpdate (srcSize=%zu)", srcSize);++    RETURN_ERROR_IF(cctxPtr->cStage != 1, compressionState_uninitialized);   /* state must be initialized and waiting for next block */+    if (dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize))+        RETURN_ERROR(dstMaxSize_tooSmall);++    if (blockCompression == LZ4B_UNCOMPRESSED && dstCapacity < srcSize)+        RETURN_ERROR(dstMaxSize_tooSmall);++    /* flush currently written block, to continue with new block compression */+    if (cctxPtr->blockCompression != blockCompression) {+        bytesWritten = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr);+        dstPtr += bytesWritten;+        cctxPtr->blockCompression = blockCompression;+    }++    if (compressOptionsPtr == NULL) compressOptionsPtr = &k_cOptionsNull;++    /* complete tmp buffer */+    if (cctxPtr->tmpInSize > 0) {   /* some data already within tmp buffer */+        size_t const sizeToCopy = blockSize - cctxPtr->tmpInSize;+        assert(blockSize > cctxPtr->tmpInSize);+        if (sizeToCopy > srcSize) {+            /* add src to tmpIn buffer */+            memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize);+            srcPtr = srcEnd;+            cctxPtr->tmpInSize += srcSize;+            /* still needs some CRC */+        } else {+            /* complete tmpIn block and then compress it */+            lastBlockCompressed = fromTmpBuffer;+            memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, sizeToCopy);+            srcPtr += sizeToCopy;++            dstPtr += LZ4F_makeBlock(dstPtr,+                                     cctxPtr->tmpIn, blockSize,+                                     compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,+                                     cctxPtr->cdict,+                                     cctxPtr->prefs.frameInfo.blockChecksumFlag);+            if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += blockSize;+            cctxPtr->tmpInSize = 0;+    }   }++    while ((size_t)(srcEnd - srcPtr) >= blockSize) {+        /* compress full blocks */+        lastBlockCompressed = fromSrcBuffer;+        dstPtr += LZ4F_makeBlock(dstPtr,+                                 srcPtr, blockSize,+                                 compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,+                                 cctxPtr->cdict,+                                 cctxPtr->prefs.frameInfo.blockChecksumFlag);+        srcPtr += blockSize;+    }++    if ((cctxPtr->prefs.autoFlush) && (srcPtr < srcEnd)) {+        /* autoFlush : remaining input (< blockSize) is compressed */+        lastBlockCompressed = fromSrcBuffer;+        dstPtr += LZ4F_makeBlock(dstPtr,+                                 srcPtr, (size_t)(srcEnd - srcPtr),+                                 compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,+                                 cctxPtr->cdict,+                                 cctxPtr->prefs.frameInfo.blockChecksumFlag);+        srcPtr = srcEnd;+    }++    /* preserve dictionary within @tmpBuff whenever necessary */+    if ((cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) && (lastBlockCompressed==fromSrcBuffer)) {+        /* linked blocks are only supported in compressed mode, see LZ4F_uncompressedUpdate */+        assert(blockCompression == LZ4B_COMPRESSED);+        if (compressOptionsPtr->stableSrc) {+            cctxPtr->tmpIn = cctxPtr->tmpBuff;  /* src is stable : dictionary remains in src across invocations */+        } else {+            int const realDictSize = LZ4F_localSaveDict(cctxPtr);+            assert(0 <= realDictSize && realDictSize <= 64 KB);+            cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;+        }+    }++    /* keep tmpIn within limits */+    if (!(cctxPtr->prefs.autoFlush)  /* no autoflush : there may be some data left within internal buffer */+      && (cctxPtr->tmpIn + blockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize) )  /* not enough room to store next block */+    {+        /* only preserve 64KB within internal buffer. Ensures there is enough room for next block.+         * note: this situation necessarily implies lastBlockCompressed==fromTmpBuffer */+        int const realDictSize = LZ4F_localSaveDict(cctxPtr);+        cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;+        assert((cctxPtr->tmpIn + blockSize) <= (cctxPtr->tmpBuff + cctxPtr->maxBufferSize));+    }++    /* some input data left, necessarily < blockSize */+    if (srcPtr < srcEnd) {+        /* fill tmp buffer */+        size_t const sizeToCopy = (size_t)(srcEnd - srcPtr);+        memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy);+        cctxPtr->tmpInSize = sizeToCopy;+    }++    if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled)+        (void)XXH32_update(&(cctxPtr->xxh), srcBuffer, srcSize);++    cctxPtr->totalInSize += srcSize;+    return (size_t)(dstPtr - dstStart);+}++/*! 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.+ * @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.+ *           or an error code if it fails (which can be tested using LZ4F_isError())+ *  After an error, the state is left in a UB state, and must be re-initialized.+ */+size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr,+                           void* dstBuffer, size_t dstCapacity,+                     const void* srcBuffer, size_t srcSize,+                     const LZ4F_compressOptions_t* compressOptionsPtr)+{+     return LZ4F_compressUpdateImpl(cctxPtr,+                                   dstBuffer, dstCapacity,+                                   srcBuffer, srcSize,+                                   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+ * @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.+ *           or an error code if it fails (which can be tested using LZ4F_isError())+ *  After an error, the state is left in a UB state, and must be re-initialized.+ */+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);+    return LZ4F_compressUpdateImpl(cctxPtr,+                                   dstBuffer, dstCapacity,+                                   srcBuffer, srcSize,+                                   compressOptionsPtr, LZ4B_UNCOMPRESSED);+}+++/*! LZ4F_flush() :+ *  When compressed data must be sent immediately, without waiting for a block to be filled,+ *  invoke LZ4_flush(), which will immediately compress any remaining data stored within LZ4F_cctx.+ *  The result of the function is the number of bytes written into dstBuffer.+ *  It can be zero, this means there was no data left within LZ4F_cctx.+ *  The function outputs an error code if it fails (can be tested using LZ4F_isError())+ *  LZ4F_compressOptions_t* is optional. NULL is a valid argument.+ */+size_t LZ4F_flush(LZ4F_cctx* cctxPtr,+                  void* dstBuffer, size_t dstCapacity,+            const LZ4F_compressOptions_t* compressOptionsPtr)+{+    BYTE* const dstStart = (BYTE*)dstBuffer;+    BYTE* dstPtr = dstStart;+    compressFunc_t compress;++    if (cctxPtr->tmpInSize == 0) return 0;   /* nothing to flush */+    RETURN_ERROR_IF(cctxPtr->cStage != 1, compressionState_uninitialized);+    RETURN_ERROR_IF(dstCapacity < (cctxPtr->tmpInSize + BHSize + BFSize), dstMaxSize_tooSmall);+    (void)compressOptionsPtr;   /* not useful (yet) */++    /* select compression function */+    compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, cctxPtr->blockCompression);++    /* compress tmp buffer */+    dstPtr += LZ4F_makeBlock(dstPtr,+                             cctxPtr->tmpIn, cctxPtr->tmpInSize,+                             compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,+                             cctxPtr->cdict,+                             cctxPtr->prefs.frameInfo.blockChecksumFlag);+    assert(((void)"flush overflows dstBuffer!", (size_t)(dstPtr - dstStart) <= dstCapacity));++    if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked)+        cctxPtr->tmpIn += cctxPtr->tmpInSize;+    cctxPtr->tmpInSize = 0;++    /* keep tmpIn within limits */+    if ((cctxPtr->tmpIn + cctxPtr->maxBlockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)) {  /* necessarily LZ4F_blockLinked */+        int const realDictSize = LZ4F_localSaveDict(cctxPtr);+        cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;+    }++    return (size_t)(dstPtr - dstStart);+}+++/*! LZ4F_compressEnd() :+ *  When you want to properly finish the compressed frame, just call LZ4F_compressEnd().+ *  It will flush whatever data remained within compressionContext (like LZ4_flush())+ *  but also properly finalize the frame, with an endMark and an (optional) checksum.+ *  LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.+ * @return: the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))+ *       or an error code if it fails (can be tested using LZ4F_isError())+ *  The context can then be used again to compress a new frame, starting with LZ4F_compressBegin().+ */+size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr,+                        void* dstBuffer, size_t dstCapacity,+                  const LZ4F_compressOptions_t* compressOptionsPtr)+{+    BYTE* const dstStart = (BYTE*)dstBuffer;+    BYTE* dstPtr = dstStart;++    size_t const flushSize = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr);+    DEBUGLOG(5,"LZ4F_compressEnd: dstCapacity=%u", (unsigned)dstCapacity);+    FORWARD_IF_ERROR(flushSize);+    dstPtr += flushSize;++    assert(flushSize <= dstCapacity);+    dstCapacity -= flushSize;++    RETURN_ERROR_IF(dstCapacity < 4, dstMaxSize_tooSmall);+    LZ4F_writeLE32(dstPtr, 0);+    dstPtr += 4;   /* endMark */++    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");+        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)+            RETURN_ERROR(frameSize_wrong);+    }++    return (size_t)(dstPtr - dstStart);+}+++/*-***************************************************+*   Frame Decompression+*****************************************************/++typedef enum {+    dstage_getFrameHeader=0, dstage_storeFrameHeader,+    dstage_init,+    dstage_getBlockHeader, dstage_storeBlockHeader,+    dstage_copyDirect, dstage_getBlockChecksum,+    dstage_getCBlock, dstage_storeCBlock,+    dstage_flushOut,+    dstage_getSuffix, dstage_storeSuffix,+    dstage_getSFrameSize, dstage_storeSFrameSize,+    dstage_skipSkippable+} dStage_t;++struct LZ4F_dctx_s {+    LZ4F_CustomMem cmem;+    LZ4F_frameInfo_t frameInfo;+    U32    version;+    dStage_t dStage;+    U64    frameRemainingSize;+    size_t maxBlockSize;+    size_t maxBufferSize;+    BYTE*  tmpIn;+    size_t tmpInSize;+    size_t tmpInTarget;+    BYTE*  tmpOutBuffer;+    const BYTE* dict;+    size_t dictSize;+    BYTE*  tmpOut;+    size_t tmpOutSize;+    size_t tmpOutStart;+    XXH32_state_t xxh;+    XXH32_state_t blockChecksum;+    int    skipChecksum;+    BYTE   header[LZ4F_HEADER_SIZE_MAX];+};  /* typedef'd to LZ4F_dctx in lz4frame.h */+++LZ4F_dctx* LZ4F_createDecompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version)+{+    LZ4F_dctx* const dctx = (LZ4F_dctx*)LZ4F_calloc(sizeof(LZ4F_dctx), customMem);+    if (dctx == NULL) return NULL;++    dctx->cmem = customMem;+    dctx->version = version;+    return dctx;+}++/*! LZ4F_createDecompressionContext() :+ *  Create a decompressionContext object, which will track all decompression operations.+ *  Provides a pointer to a fully allocated and initialized LZ4F_decompressionContext object.+ *  Object can later be released using LZ4F_freeDecompressionContext().+ * @return : if != 0, there was an error during context creation.+ */+LZ4F_errorCode_t+LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber)+{+    assert(LZ4F_decompressionContextPtr != NULL);  /* violation of narrow contract */+    RETURN_ERROR_IF(LZ4F_decompressionContextPtr == NULL, parameter_null);  /* in case it nonetheless happen in production */++    *LZ4F_decompressionContextPtr = LZ4F_createDecompressionContext_advanced(LZ4F_defaultCMem, versionNumber);+    if (*LZ4F_decompressionContextPtr == NULL) {  /* failed allocation */+        RETURN_ERROR(allocation_failed);+    }+    return LZ4F_OK_NoError;+}++LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx)+{+    LZ4F_errorCode_t result = LZ4F_OK_NoError;+    if (dctx != NULL) {   /* can accept NULL input, like free() */+      result = (LZ4F_errorCode_t)dctx->dStage;+      LZ4F_free(dctx->tmpIn, dctx->cmem);+      LZ4F_free(dctx->tmpOutBuffer, dctx->cmem);+      LZ4F_free(dctx, dctx->cmem);+    }+    return result;+}+++/*==---   Streaming Decompression operations   ---==*/++void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx)+{+    dctx->dStage = dstage_getFrameHeader;+    dctx->dict = NULL;+    dctx->dictSize = 0;+    dctx->skipChecksum = 0;+}+++/*! LZ4F_decodeHeader() :+ *  input   : `src` points at the **beginning of the frame**+ *  output  : set internal values of dctx, such as+ *            dctx->frameInfo and dctx->dStage.+ *            Also allocates internal buffers.+ *  @return : nb Bytes read from src (necessarily <= srcSize)+ *            or an error code (testable with LZ4F_isError())+ */+static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize)+{+    unsigned blockMode, blockChecksumFlag, contentSizeFlag, contentChecksumFlag, dictIDFlag, blockSizeID;+    size_t frameHeaderSize;+    const BYTE* srcPtr = (const BYTE*)src;++    DEBUGLOG(5, "LZ4F_decodeHeader");+    /* need to decode header to get frameInfo */+    RETURN_ERROR_IF(srcSize < minFHSize, frameHeader_incomplete);   /* minimal frame header size */+    MEM_INIT(&(dctx->frameInfo), 0, sizeof(dctx->frameInfo));++    /* special case : skippable frames */+    if ((LZ4F_readLE32(srcPtr) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) {+        dctx->frameInfo.frameType = LZ4F_skippableFrame;+        if (src == (void*)(dctx->header)) {+            dctx->tmpInSize = srcSize;+            dctx->tmpInTarget = 8;+            dctx->dStage = dstage_storeSFrameSize;+            return srcSize;+        } else {+            dctx->dStage = dstage_getSFrameSize;+            return 4;+    }   }++    /* control magic number */+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION+    if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) {+        DEBUGLOG(4, "frame header error : unknown magic number");+        RETURN_ERROR(frameType_unknown);+    }+#endif+    dctx->frameInfo.frameType = LZ4F_frame;++    /* Flags */+    {   U32 const FLG = srcPtr[4];+        U32 const version = (FLG>>6) & _2BITS;+        blockChecksumFlag = (FLG>>4) & _1BIT;+        blockMode = (FLG>>5) & _1BIT;+        contentSizeFlag = (FLG>>3) & _1BIT;+        contentChecksumFlag = (FLG>>2) & _1BIT;+        dictIDFlag = FLG & _1BIT;+        /* validate */+        if (((FLG>>1)&_1BIT) != 0) RETURN_ERROR(reservedFlag_set); /* Reserved bit */+        if (version != 1) RETURN_ERROR(headerVersion_wrong);       /* Version Number, only supported value */+    }++    /* Frame Header Size */+    frameHeaderSize = minFHSize + (contentSizeFlag?8:0) + (dictIDFlag?4:0);++    if (srcSize < frameHeaderSize) {+        /* not enough input to fully decode frame header */+        if (srcPtr != dctx->header)+            memcpy(dctx->header, srcPtr, srcSize);+        dctx->tmpInSize = srcSize;+        dctx->tmpInTarget = frameHeaderSize;+        dctx->dStage = dstage_storeFrameHeader;+        return srcSize;+    }++    {   U32 const BD = srcPtr[5];+        blockSizeID = (BD>>4) & _3BITS;+        /* validate */+        if (((BD>>7)&_1BIT) != 0) RETURN_ERROR(reservedFlag_set);   /* Reserved bit */+        if (blockSizeID < 4) RETURN_ERROR(maxBlockSize_invalid);    /* 4-7 only supported values for the time being */+        if (((BD>>0)&_4BITS) != 0) RETURN_ERROR(reservedFlag_set);  /* Reserved bits */+    }++    /* check header */+    assert(frameHeaderSize > 5);+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION+    {   BYTE const HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5);+        RETURN_ERROR_IF(HC != srcPtr[frameHeaderSize-1], headerChecksum_invalid);+    }+#endif++    /* save */+    dctx->frameInfo.blockMode = (LZ4F_blockMode_t)blockMode;+    dctx->frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)blockChecksumFlag;+    dctx->frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)contentChecksumFlag;+    dctx->frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID;+    dctx->maxBlockSize = LZ4F_getBlockSize((LZ4F_blockSizeID_t)blockSizeID);+    if (contentSizeFlag)+        dctx->frameRemainingSize = dctx->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6);+    if (dictIDFlag)+        dctx->frameInfo.dictID = LZ4F_readLE32(srcPtr + frameHeaderSize - 5);++    dctx->dStage = dstage_init;++    return frameHeaderSize;+}+++/*! LZ4F_headerSize() :+ * @return : size of frame header+ *           or an error code, which can be tested using LZ4F_isError()+ */+size_t LZ4F_headerSize(const void* src, size_t srcSize)+{+    RETURN_ERROR_IF(src == NULL, srcPtr_wrong);++    /* minimal srcSize to determine header size */+    if (srcSize < LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH)+        RETURN_ERROR(frameHeader_incomplete);++    /* special case : skippable frames */+    if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START)+        return 8;++    /* control magic number */+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION+    if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER)+        RETURN_ERROR(frameType_unknown);+#endif++    /* Frame Header Size */+    {   BYTE const FLG = ((const BYTE*)src)[4];+        U32 const contentSizeFlag = (FLG>>3) & _1BIT;+        U32 const dictIDFlag = FLG & _1BIT;+        return minFHSize + (contentSizeFlag?8:0) + (dictIDFlag?4:0);+    }+}++/*! LZ4F_getFrameInfo() :+ *  This function extracts frame parameters (max blockSize, frame checksum, etc.).+ *  Usage is optional. Objective is to provide relevant information for allocation purposes.+ *  This function works in 2 situations :+ *   - At the beginning of a new frame, in which case it will decode this information from `srcBuffer`, and start the decoding process.+ *     Amount of input data provided must be large enough to successfully decode the frame header.+ *     A header size is variable, but is guaranteed to be <= LZ4F_HEADER_SIZE_MAX bytes. It's possible to provide more input data than this minimum.+ *   - After decoding has been started. In which case, no input is read, frame parameters are extracted from dctx.+ *  The number of bytes consumed from srcBuffer will be updated within *srcSizePtr (necessarily <= original value).+ *  Decompression must resume from (srcBuffer + *srcSizePtr).+ * @return : an hint about how many srcSize bytes LZ4F_decompress() expects for next call,+ *           or an error code which can be tested using LZ4F_isError()+ *  note 1 : in case of error, dctx is not modified. Decoding operations can resume from where they stopped.+ *  note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure.+ */+LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx,+                                   LZ4F_frameInfo_t* frameInfoPtr,+                             const void* srcBuffer, size_t* srcSizePtr)+{+    LZ4F_STATIC_ASSERT(dstage_getFrameHeader < dstage_storeFrameHeader);+    if (dctx->dStage > dstage_storeFrameHeader) {+        /* frameInfo already decoded */+        size_t o=0, i=0;+        *srcSizePtr = 0;+        *frameInfoPtr = dctx->frameInfo;+        /* returns : recommended nb of bytes for LZ4F_decompress() */+        return LZ4F_decompress(dctx, NULL, &o, NULL, &i, NULL);+    } else {+        if (dctx->dStage == dstage_storeFrameHeader) {+            /* frame decoding already started, in the middle of header => automatic fail */+            *srcSizePtr = 0;+            RETURN_ERROR(frameDecoding_alreadyStarted);+        } else {+            size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr);+            if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; }+            if (*srcSizePtr < hSize) {+                *srcSizePtr=0;+                RETURN_ERROR(frameHeader_incomplete);+            }++            {   size_t decodeResult = LZ4F_decodeHeader(dctx, srcBuffer, hSize);+                if (LZ4F_isError(decodeResult)) {+                    *srcSizePtr = 0;+                } else {+                    *srcSizePtr = decodeResult;+                    decodeResult = BHSize;   /* block header size */+                }+                *frameInfoPtr = dctx->frameInfo;+                return decodeResult;+    }   }   }+}+++/* LZ4F_updateDict() :+ * only used for LZ4F_blockLinked mode+ * Condition : @dstPtr != NULL+ */+static void LZ4F_updateDict(LZ4F_dctx* dctx,+                      const BYTE* dstPtr, size_t dstSize, const BYTE* dstBufferStart,+                      unsigned withinTmp)+{+    assert(dstPtr != NULL);+    if (dctx->dictSize==0) dctx->dict = (const BYTE*)dstPtr;  /* will lead to prefix mode */+    assert(dctx->dict != NULL);++    if (dctx->dict + dctx->dictSize == dstPtr) {  /* prefix mode, everything within dstBuffer */+        dctx->dictSize += dstSize;+        return;+    }++    assert(dstPtr >= dstBufferStart);+    if ((size_t)(dstPtr - dstBufferStart) + dstSize >= 64 KB) {  /* history in dstBuffer becomes large enough to become dictionary */+        dctx->dict = (const BYTE*)dstBufferStart;+        dctx->dictSize = (size_t)(dstPtr - dstBufferStart) + dstSize;+        return;+    }++    assert(dstSize < 64 KB);   /* if dstSize >= 64 KB, dictionary would be set into dstBuffer directly */++    /* dstBuffer does not contain whole useful history (64 KB), so it must be saved within tmpOutBuffer */+    assert(dctx->tmpOutBuffer != NULL);++    if (withinTmp && (dctx->dict == dctx->tmpOutBuffer)) {   /* continue history within tmpOutBuffer */+        /* withinTmp expectation : content of [dstPtr,dstSize] is same as [dict+dictSize,dstSize], so we just extend it */+        assert(dctx->dict + dctx->dictSize == dctx->tmpOut + dctx->tmpOutStart);+        dctx->dictSize += dstSize;+        return;+    }++    if (withinTmp) { /* copy relevant dict portion in front of tmpOut within tmpOutBuffer */+        size_t const preserveSize = (size_t)(dctx->tmpOut - dctx->tmpOutBuffer);+        size_t copySize = 64 KB - dctx->tmpOutSize;+        const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart;+        if (dctx->tmpOutSize > 64 KB) copySize = 0;+        if (copySize > preserveSize) copySize = preserveSize;++        memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);++        dctx->dict = dctx->tmpOutBuffer;+        dctx->dictSize = preserveSize + dctx->tmpOutStart + dstSize;+        return;+    }++    if (dctx->dict == dctx->tmpOutBuffer) {    /* copy dst into tmp to complete dict */+        if (dctx->dictSize + dstSize > dctx->maxBufferSize) {  /* tmp buffer not large enough */+            size_t const preserveSize = 64 KB - dstSize;+            memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - preserveSize, preserveSize);+            dctx->dictSize = preserveSize;+        }+        memcpy(dctx->tmpOutBuffer + dctx->dictSize, dstPtr, dstSize);+        dctx->dictSize += dstSize;+        return;+    }++    /* join dict & dest into tmp */+    {   size_t preserveSize = 64 KB - dstSize;+        if (preserveSize > dctx->dictSize) preserveSize = dctx->dictSize;+        memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - preserveSize, preserveSize);+        memcpy(dctx->tmpOutBuffer + preserveSize, dstPtr, dstSize);+        dctx->dict = dctx->tmpOutBuffer;+        dctx->dictSize = preserveSize + dstSize;+    }+}+++/*! LZ4F_decompress() :+ *  Call this function repetitively to regenerate compressed data in srcBuffer.+ *  The function will attempt to decode up to *srcSizePtr bytes from srcBuffer+ *  into dstBuffer of capacity *dstSizePtr.+ *+ *  The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value).+ *+ *  The number of bytes effectively read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).+ *  If number of bytes read is < number of bytes provided, then decompression operation is not complete.+ *  Remaining data will have to be presented again in a subsequent invocation.+ *+ *  The function result is an hint of the better srcSize to use for next call to LZ4F_decompress.+ *  Schematically, it's the size of the current (or remaining) compressed block + header of next block.+ *  Respecting the hint provides a small boost to performance, since it allows less buffer shuffling.+ *  Note that this is just a hint, and it's always possible to any srcSize value.+ *  When a frame is fully decoded, @return will be 0.+ *  If decompression failed, @return is an error code which can be tested using LZ4F_isError().+ */+size_t LZ4F_decompress(LZ4F_dctx* dctx,+                       void* dstBuffer, size_t* dstSizePtr,+                       const void* srcBuffer, size_t* srcSizePtr,+                       const LZ4F_decompressOptions_t* decompressOptionsPtr)+{+    LZ4F_decompressOptions_t optionsNull;+    const BYTE* const srcStart = (const BYTE*)srcBuffer;+    const BYTE* const srcEnd = srcStart + *srcSizePtr;+    const BYTE* srcPtr = srcStart;+    BYTE* const dstStart = (BYTE*)dstBuffer;+    BYTE* const dstEnd = dstStart ? dstStart + *dstSizePtr : NULL;+    BYTE* dstPtr = dstStart;+    const BYTE* selectedIn = NULL;+    unsigned doAnotherStage = 1;+    size_t nextSrcSizeHint = 1;+++    DEBUGLOG(5, "LZ4F_decompress : %p,%u => %p,%u",+            srcBuffer, (unsigned)*srcSizePtr, dstBuffer, (unsigned)*dstSizePtr);+    if (dstBuffer == NULL) assert(*dstSizePtr == 0);+    MEM_INIT(&optionsNull, 0, sizeof(optionsNull));+    if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull;+    *srcSizePtr = 0;+    *dstSizePtr = 0;+    assert(dctx != NULL);+    dctx->skipChecksum |= (decompressOptionsPtr->skipChecksums != 0); /* once set, disable for the remainder of the frame */++    /* behaves as a state machine */++    while (doAnotherStage) {++        switch(dctx->dStage)+        {++        case dstage_getFrameHeader:+            DEBUGLOG(6, "dstage_getFrameHeader");+            if ((size_t)(srcEnd-srcPtr) >= maxFHSize) {  /* enough to decode - shortcut */+                size_t const hSize = LZ4F_decodeHeader(dctx, srcPtr, (size_t)(srcEnd-srcPtr));  /* will update dStage appropriately */+                FORWARD_IF_ERROR(hSize);+                srcPtr += hSize;+                break;+            }+            dctx->tmpInSize = 0;+            if (srcEnd-srcPtr == 0) return minFHSize;   /* 0-size input */+            dctx->tmpInTarget = minFHSize;   /* minimum size to decode header */+            dctx->dStage = dstage_storeFrameHeader;+            /* fall-through */++        case dstage_storeFrameHeader:+            DEBUGLOG(6, "dstage_storeFrameHeader");+            {   size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize, (size_t)(srcEnd - srcPtr));+                memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy);+                dctx->tmpInSize += sizeToCopy;+                srcPtr += sizeToCopy;+            }+            if (dctx->tmpInSize < dctx->tmpInTarget) {+                nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize) + BHSize;   /* rest of header + nextBlockHeader */+                doAnotherStage = 0;   /* not enough src data, ask for some more */+                break;+            }+            FORWARD_IF_ERROR( LZ4F_decodeHeader(dctx, dctx->header, dctx->tmpInTarget) ); /* will update dStage appropriately */+            break;++        case dstage_init:+            DEBUGLOG(6, "dstage_init");+            if (dctx->frameInfo.contentChecksumFlag) (void)XXH32_reset(&(dctx->xxh), 0);+            /* internal buffers allocation */+            {   size_t const bufferNeeded = dctx->maxBlockSize+                    + ((dctx->frameInfo.blockMode==LZ4F_blockLinked) ? 128 KB : 0);+                if (bufferNeeded > dctx->maxBufferSize) {   /* tmp buffers too small */+                    dctx->maxBufferSize = 0;   /* ensure allocation will be re-attempted on next entry*/+                    LZ4F_free(dctx->tmpIn, dctx->cmem);+                    dctx->tmpIn = (BYTE*)LZ4F_malloc(dctx->maxBlockSize + BFSize /* block checksum */, dctx->cmem);+                    RETURN_ERROR_IF(dctx->tmpIn == NULL, allocation_failed);+                    LZ4F_free(dctx->tmpOutBuffer, dctx->cmem);+                    dctx->tmpOutBuffer= (BYTE*)LZ4F_malloc(bufferNeeded, dctx->cmem);+                    RETURN_ERROR_IF(dctx->tmpOutBuffer== NULL, allocation_failed);+                    dctx->maxBufferSize = bufferNeeded;+            }   }+            dctx->tmpInSize = 0;+            dctx->tmpInTarget = 0;+            dctx->tmpOut = dctx->tmpOutBuffer;+            dctx->tmpOutStart = 0;+            dctx->tmpOutSize = 0;++            dctx->dStage = dstage_getBlockHeader;+            /* fall-through */++        case dstage_getBlockHeader:+            if ((size_t)(srcEnd - srcPtr) >= BHSize) {+                selectedIn = srcPtr;+                srcPtr += BHSize;+            } else {+                /* not enough input to read cBlockSize field */+                dctx->tmpInSize = 0;+                dctx->dStage = dstage_storeBlockHeader;+            }++            if (dctx->dStage == dstage_storeBlockHeader)   /* can be skipped */+        case dstage_storeBlockHeader:+            {   size_t const remainingInput = (size_t)(srcEnd - srcPtr);+                size_t const wantedData = BHSize - dctx->tmpInSize;+                size_t const sizeToCopy = MIN(wantedData, remainingInput);+                memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy);+                srcPtr += sizeToCopy;+                dctx->tmpInSize += sizeToCopy;++                if (dctx->tmpInSize < BHSize) {   /* not enough input for cBlockSize */+                    nextSrcSizeHint = BHSize - dctx->tmpInSize;+                    doAnotherStage  = 0;+                    break;+                }+                selectedIn = dctx->tmpIn;+            }   /* if (dctx->dStage == dstage_storeBlockHeader) */++        /* decode block header */+            {   U32 const blockHeader = LZ4F_readLE32(selectedIn);+                size_t const nextCBlockSize = blockHeader & 0x7FFFFFFFU;+                size_t const crcSize = dctx->frameInfo.blockChecksumFlag * BFSize;+                if (blockHeader==0) {  /* frameEnd signal, no more block */+                    DEBUGLOG(5, "end of frame");+                    dctx->dStage = dstage_getSuffix;+                    break;+                }+                if (nextCBlockSize > dctx->maxBlockSize) {+                    RETURN_ERROR(maxBlockSize_invalid);+                }+                if (blockHeader & LZ4F_BLOCKUNCOMPRESSED_FLAG) {+                    /* next block is uncompressed */+                    dctx->tmpInTarget = nextCBlockSize;+                    DEBUGLOG(5, "next block is uncompressed (size %u)", (U32)nextCBlockSize);+                    if (dctx->frameInfo.blockChecksumFlag) {+                        (void)XXH32_reset(&dctx->blockChecksum, 0);+                    }+                    dctx->dStage = dstage_copyDirect;+                    break;+                }+                /* next block is a compressed block */+                dctx->tmpInTarget = nextCBlockSize + crcSize;+                dctx->dStage = dstage_getCBlock;+                if (dstPtr==dstEnd || srcPtr==srcEnd) {+                    nextSrcSizeHint = BHSize + nextCBlockSize + crcSize;+                    doAnotherStage = 0;+                }+                break;+            }++        case dstage_copyDirect:   /* uncompressed block */+            DEBUGLOG(6, "dstage_copyDirect");+            {   size_t sizeToCopy;+                if (dstPtr == NULL) {+                    sizeToCopy = 0;+                } else {+                    size_t const minBuffSize = MIN((size_t)(srcEnd-srcPtr), (size_t)(dstEnd-dstPtr));+                    sizeToCopy = MIN(dctx->tmpInTarget, minBuffSize);+                    memcpy(dstPtr, srcPtr, sizeToCopy);+                    if (!dctx->skipChecksum) {+                        if (dctx->frameInfo.blockChecksumFlag) {+                            (void)XXH32_update(&dctx->blockChecksum, srcPtr, sizeToCopy);+                        }+                        if (dctx->frameInfo.contentChecksumFlag)+                            (void)XXH32_update(&dctx->xxh, srcPtr, sizeToCopy);+                    }+                    if (dctx->frameInfo.contentSize)+                        dctx->frameRemainingSize -= sizeToCopy;++                    /* history management (linked blocks only)*/+                    if (dctx->frameInfo.blockMode == LZ4F_blockLinked) {+                        LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0);+                }   }++                srcPtr += sizeToCopy;+                dstPtr += sizeToCopy;+                if (sizeToCopy == dctx->tmpInTarget) {   /* all done */+                    if (dctx->frameInfo.blockChecksumFlag) {+                        dctx->tmpInSize = 0;+                        dctx->dStage = dstage_getBlockChecksum;+                    } else+                        dctx->dStage = dstage_getBlockHeader;  /* new block */+                    break;+                }+                dctx->tmpInTarget -= sizeToCopy;  /* need to copy more */+            }+            nextSrcSizeHint = dctx->tmpInTarget ++                            +(dctx->frameInfo.blockChecksumFlag ? BFSize : 0)+                            + BHSize /* next header size */;+            doAnotherStage = 0;+            break;++        /* check block checksum for recently transferred uncompressed block */+        case dstage_getBlockChecksum:+            DEBUGLOG(6, "dstage_getBlockChecksum");+            {   const void* crcSrc;+                if ((srcEnd-srcPtr >= 4) && (dctx->tmpInSize==0)) {+                    crcSrc = srcPtr;+                    srcPtr += 4;+                } else {+                    size_t const stillToCopy = 4 - dctx->tmpInSize;+                    size_t const sizeToCopy = MIN(stillToCopy, (size_t)(srcEnd-srcPtr));+                    memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy);+                    dctx->tmpInSize += sizeToCopy;+                    srcPtr += sizeToCopy;+                    if (dctx->tmpInSize < 4) {  /* all input consumed */+                        doAnotherStage = 0;+                        break;+                    }+                    crcSrc = dctx->header;+                }+                if (!dctx->skipChecksum) {+                    U32 const readCRC = LZ4F_readLE32(crcSrc);+                    U32 const calcCRC = XXH32_digest(&dctx->blockChecksum);+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION+                    DEBUGLOG(6, "compare block checksum");+                    if (readCRC != calcCRC) {+                        DEBUGLOG(4, "incorrect block checksum: %08X != %08X",+                                readCRC, calcCRC);+                        RETURN_ERROR(blockChecksum_invalid);+                    }+#else+                    (void)readCRC;+                    (void)calcCRC;+#endif+            }   }+            dctx->dStage = dstage_getBlockHeader;  /* new block */+            break;++        case dstage_getCBlock:+            DEBUGLOG(6, "dstage_getCBlock");+            if ((size_t)(srcEnd-srcPtr) < dctx->tmpInTarget) {+                dctx->tmpInSize = 0;+                dctx->dStage = dstage_storeCBlock;+                break;+            }+            /* input large enough to read full block directly */+            selectedIn = srcPtr;+            srcPtr += dctx->tmpInTarget;++            if (0)  /* always jump over next block */+        case dstage_storeCBlock:+            {   size_t const wantedData = dctx->tmpInTarget - dctx->tmpInSize;+                size_t const inputLeft = (size_t)(srcEnd-srcPtr);+                size_t const sizeToCopy = MIN(wantedData, inputLeft);+                memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy);+                dctx->tmpInSize += sizeToCopy;+                srcPtr += sizeToCopy;+                if (dctx->tmpInSize < dctx->tmpInTarget) { /* need more input */+                    nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize)+                                    + (dctx->frameInfo.blockChecksumFlag ? BFSize : 0)+                                    + BHSize /* next header size */;+                    doAnotherStage = 0;+                    break;+                }+                selectedIn = dctx->tmpIn;+            }++            /* At this stage, input is large enough to decode a block */++            /* First, decode and control block checksum if it exists */+            if (dctx->frameInfo.blockChecksumFlag) {+                assert(dctx->tmpInTarget >= 4);+                dctx->tmpInTarget -= 4;+                assert(selectedIn != NULL);  /* selectedIn is defined at this stage (either srcPtr, or dctx->tmpIn) */+                {   U32 const readBlockCrc = LZ4F_readLE32(selectedIn + dctx->tmpInTarget);+                    U32 const calcBlockCrc = XXH32(selectedIn, dctx->tmpInTarget, 0);+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION+                    RETURN_ERROR_IF(readBlockCrc != calcBlockCrc, blockChecksum_invalid);+#else+                    (void)readBlockCrc;+                    (void)calcBlockCrc;+#endif+            }   }++            /* decode directly into destination buffer if there is enough room */+            if ( ((size_t)(dstEnd-dstPtr) >= dctx->maxBlockSize)+                 /* unless the dictionary is stored in tmpOut:+                  * in which case it's faster to decode within tmpOut+                  * to benefit from prefix speedup */+              && !(dctx->dict!= NULL && (const BYTE*)dctx->dict + dctx->dictSize == dctx->tmpOut) )+            {+                const char* dict = (const char*)dctx->dict;+                size_t dictSize = dctx->dictSize;+                int decodedSize;+                assert(dstPtr != NULL);+                if (dict && dictSize > 1 GB) {+                    /* overflow control : dctx->dictSize is an int, avoid truncation / sign issues */+                    dict += dictSize - 64 KB;+                    dictSize = 64 KB;+                }+                decodedSize = LZ4_decompress_safe_usingDict(+                        (const char*)selectedIn, (char*)dstPtr,+                        (int)dctx->tmpInTarget, (int)dctx->maxBlockSize,+                        dict, (int)dictSize);+                RETURN_ERROR_IF(decodedSize < 0, decompressionFailed);+                if ((dctx->frameInfo.contentChecksumFlag) && (!dctx->skipChecksum))+                    XXH32_update(&(dctx->xxh), dstPtr, (size_t)decodedSize);+                if (dctx->frameInfo.contentSize)+                    dctx->frameRemainingSize -= (size_t)decodedSize;++                /* dictionary management */+                if (dctx->frameInfo.blockMode==LZ4F_blockLinked) {+                    LZ4F_updateDict(dctx, dstPtr, (size_t)decodedSize, dstStart, 0);+                }++                dstPtr += decodedSize;+                dctx->dStage = dstage_getBlockHeader;  /* end of block, let's get another one */+                break;+            }++            /* not enough place into dst : decode into tmpOut */++            /* manage dictionary */+            if (dctx->frameInfo.blockMode == LZ4F_blockLinked) {+                if (dctx->dict == dctx->tmpOutBuffer) {+                    /* truncate dictionary to 64 KB if too big */+                    if (dctx->dictSize > 128 KB) {+                        memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - 64 KB, 64 KB);+                        dctx->dictSize = 64 KB;+                    }+                    dctx->tmpOut = dctx->tmpOutBuffer + dctx->dictSize;+                } else {  /* dict not within tmpOut */+                    size_t const reservedDictSpace = MIN(dctx->dictSize, 64 KB);+                    dctx->tmpOut = dctx->tmpOutBuffer + reservedDictSpace;+            }   }++            /* Decode block into tmpOut */+            {   const char* dict = (const char*)dctx->dict;+                size_t dictSize = dctx->dictSize;+                int decodedSize;+                if (dict && dictSize > 1 GB) {+                    /* the dictSize param is an int, avoid truncation / sign issues */+                    dict += dictSize - 64 KB;+                    dictSize = 64 KB;+                }+                decodedSize = LZ4_decompress_safe_usingDict(+                        (const char*)selectedIn, (char*)dctx->tmpOut,+                        (int)dctx->tmpInTarget, (int)dctx->maxBlockSize,+                        dict, (int)dictSize);+                RETURN_ERROR_IF(decodedSize < 0, decompressionFailed);+                if (dctx->frameInfo.contentChecksumFlag && !dctx->skipChecksum)+                    XXH32_update(&(dctx->xxh), dctx->tmpOut, (size_t)decodedSize);+                if (dctx->frameInfo.contentSize)+                    dctx->frameRemainingSize -= (size_t)decodedSize;+                dctx->tmpOutSize = (size_t)decodedSize;+                dctx->tmpOutStart = 0;+                dctx->dStage = dstage_flushOut;+            }+            /* fall-through */++        case dstage_flushOut:  /* flush decoded data from tmpOut to dstBuffer */+            DEBUGLOG(6, "dstage_flushOut");+            if (dstPtr != NULL) {+                size_t const sizeToCopy = MIN(dctx->tmpOutSize - dctx->tmpOutStart, (size_t)(dstEnd-dstPtr));+                memcpy(dstPtr, dctx->tmpOut + dctx->tmpOutStart, sizeToCopy);++                /* dictionary management */+                if (dctx->frameInfo.blockMode == LZ4F_blockLinked)+                    LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 1 /*withinTmp*/);++                dctx->tmpOutStart += sizeToCopy;+                dstPtr += sizeToCopy;+            }+            if (dctx->tmpOutStart == dctx->tmpOutSize) { /* all flushed */+                dctx->dStage = dstage_getBlockHeader;  /* get next block */+                break;+            }+            /* could not flush everything : stop there, just request a block header */+            doAnotherStage = 0;+            nextSrcSizeHint = BHSize;+            break;++        case dstage_getSuffix:+            RETURN_ERROR_IF(dctx->frameRemainingSize, frameSize_wrong);   /* incorrect frame size decoded */+            if (!dctx->frameInfo.contentChecksumFlag) {  /* no checksum, frame is completed */+                nextSrcSizeHint = 0;+                LZ4F_resetDecompressionContext(dctx);+                doAnotherStage = 0;+                break;+            }+            if ((srcEnd - srcPtr) < 4) {  /* not enough size for entire CRC */+                dctx->tmpInSize = 0;+                dctx->dStage = dstage_storeSuffix;+            } else {+                selectedIn = srcPtr;+                srcPtr += 4;+            }++            if (dctx->dStage == dstage_storeSuffix)   /* can be skipped */+        case dstage_storeSuffix:+            {   size_t const remainingInput = (size_t)(srcEnd - srcPtr);+                size_t const wantedData = 4 - dctx->tmpInSize;+                size_t const sizeToCopy = MIN(wantedData, remainingInput);+                memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy);+                srcPtr += sizeToCopy;+                dctx->tmpInSize += sizeToCopy;+                if (dctx->tmpInSize < 4) { /* not enough input to read complete suffix */+                    nextSrcSizeHint = 4 - dctx->tmpInSize;+                    doAnotherStage=0;+                    break;+                }+                selectedIn = dctx->tmpIn;+            }   /* if (dctx->dStage == dstage_storeSuffix) */++        /* case dstage_checkSuffix: */   /* no direct entry, avoid initialization risks */+            if (!dctx->skipChecksum) {+                U32 const readCRC = LZ4F_readLE32(selectedIn);+                U32 const resultCRC = XXH32_digest(&(dctx->xxh));+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION+                RETURN_ERROR_IF(readCRC != resultCRC, contentChecksum_invalid);+#else+                (void)readCRC;+                (void)resultCRC;+#endif+            }+            nextSrcSizeHint = 0;+            LZ4F_resetDecompressionContext(dctx);+            doAnotherStage = 0;+            break;++        case dstage_getSFrameSize:+            if ((srcEnd - srcPtr) >= 4) {+                selectedIn = srcPtr;+                srcPtr += 4;+            } else {+                /* not enough input to read cBlockSize field */+                dctx->tmpInSize = 4;+                dctx->tmpInTarget = 8;+                dctx->dStage = dstage_storeSFrameSize;+            }++            if (dctx->dStage == dstage_storeSFrameSize)+        case dstage_storeSFrameSize:+            {   size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize,+                                             (size_t)(srcEnd - srcPtr) );+                memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy);+                srcPtr += sizeToCopy;+                dctx->tmpInSize += sizeToCopy;+                if (dctx->tmpInSize < dctx->tmpInTarget) {+                    /* not enough input to get full sBlockSize; wait for more */+                    nextSrcSizeHint = dctx->tmpInTarget - dctx->tmpInSize;+                    doAnotherStage = 0;+                    break;+                }+                selectedIn = dctx->header + 4;+            }   /* if (dctx->dStage == dstage_storeSFrameSize) */++        /* case dstage_decodeSFrameSize: */   /* no direct entry */+            {   size_t const SFrameSize = LZ4F_readLE32(selectedIn);+                dctx->frameInfo.contentSize = SFrameSize;+                dctx->tmpInTarget = SFrameSize;+                dctx->dStage = dstage_skipSkippable;+                break;+            }++        case dstage_skipSkippable:+            {   size_t const skipSize = MIN(dctx->tmpInTarget, (size_t)(srcEnd-srcPtr));+                srcPtr += skipSize;+                dctx->tmpInTarget -= skipSize;+                doAnotherStage = 0;+                nextSrcSizeHint = dctx->tmpInTarget;+                if (nextSrcSizeHint) break;  /* still more to skip */+                /* frame fully skipped : prepare context for a new frame */+                LZ4F_resetDecompressionContext(dctx);+                break;+            }+        }   /* switch (dctx->dStage) */+    }   /* while (doAnotherStage) */++    /* preserve history within tmpOut whenever necessary */+    LZ4F_STATIC_ASSERT((unsigned)dstage_init == 2);+    if ( (dctx->frameInfo.blockMode==LZ4F_blockLinked)  /* next block will use up to 64KB from previous ones */+      && (dctx->dict != dctx->tmpOutBuffer)             /* dictionary is not already within tmp */+      && (dctx->dict != NULL)                           /* dictionary exists */+      && (!decompressOptionsPtr->stableDst)             /* cannot rely on dst data to remain there for next call */+      && ((unsigned)(dctx->dStage)-2 < (unsigned)(dstage_getSuffix)-2) )  /* valid stages : [init ... getSuffix[ */+    {+        if (dctx->dStage == dstage_flushOut) {+            size_t const preserveSize = (size_t)(dctx->tmpOut - dctx->tmpOutBuffer);+            size_t copySize = 64 KB - dctx->tmpOutSize;+            const BYTE* oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart;+            if (dctx->tmpOutSize > 64 KB) copySize = 0;+            if (copySize > preserveSize) copySize = preserveSize;+            assert(dctx->tmpOutBuffer != NULL);++            memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);++            dctx->dict = dctx->tmpOutBuffer;+            dctx->dictSize = preserveSize + dctx->tmpOutStart;+        } else {+            const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize;+            size_t const newDictSize = MIN(dctx->dictSize, 64 KB);++            memcpy(dctx->tmpOutBuffer, oldDictEnd - newDictSize, newDictSize);++            dctx->dict = dctx->tmpOutBuffer;+            dctx->dictSize = newDictSize;+            dctx->tmpOut = dctx->tmpOutBuffer + newDictSize;+        }+    }++    *srcSizePtr = (size_t)(srcPtr - srcStart);+    *dstSizePtr = (size_t)(dstPtr - dstStart);+    return nextSrcSizeHint;+}++/*! 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.+ */+size_t LZ4F_decompress_usingDict(LZ4F_dctx* dctx,+                       void* dstBuffer, size_t* dstSizePtr,+                       const void* srcBuffer, size_t* srcSizePtr,+                       const void* dict, size_t dictSize,+                       const LZ4F_decompressOptions_t* decompressOptionsPtr)+{+    if (dctx->dStage <= dstage_init) {+        dctx->dict = (const BYTE*)dict;+        dctx->dictSize = dictSize;+    }+    return LZ4F_decompress(dctx, dstBuffer, dstSizePtr,+                           srcBuffer, srcSizePtr,+                           decompressOptionsPtr);+}
+ cbits/lz4frame.h view
@@ -0,0 +1,692 @@+/*+   LZ4F - LZ4-Frame library+   Header File+   Copyright (C) 2011-2020, Yann Collet.+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++   You can contact the author at :+   - LZ4 source repository : https://github.com/lz4/lz4+   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c+*/++/* LZ4F is a stand-alone API able to create and decode LZ4 frames+ * conformant with specification v1.6.1 in doc/lz4_Frame_format.md .+ * Generated frames are compatible with `lz4` CLI.+ *+ * LZ4F also offers streaming capabilities.+ *+ * lz4.h is not required when using lz4frame.h,+ * except to extract common constants such as LZ4_VERSION_NUMBER.+ * */++#ifndef LZ4F_H_09782039843+#define LZ4F_H_09782039843++#if defined (__cplusplus)+extern "C" {+#endif++/* ---   Dependency   --- */+#include <stddef.h>   /* size_t */+++/**+ * Introduction+ *+ * lz4frame.h implements LZ4 frame specification: see doc/lz4_Frame_format.md .+ * LZ4 Frames are compatible with `lz4` CLI,+ * and designed to be interoperable with any system.+**/++/*-***************************************************************+ *  Compiler specifics+ *****************************************************************/+/*  LZ4_DLL_EXPORT :+ *  Enable exporting of functions when building a Windows DLL+ *  LZ4FLIB_VISIBILITY :+ *  Control library symbols visibility.+ */+#ifndef LZ4FLIB_VISIBILITY+#  if defined(__GNUC__) && (__GNUC__ >= 4)+#    define LZ4FLIB_VISIBILITY __attribute__ ((visibility ("default")))+#  else+#    define LZ4FLIB_VISIBILITY+#  endif+#endif+#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)+#  define LZ4FLIB_API __declspec(dllexport) LZ4FLIB_VISIBILITY+#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)+#  define LZ4FLIB_API __declspec(dllimport) LZ4FLIB_VISIBILITY+#else+#  define LZ4FLIB_API LZ4FLIB_VISIBILITY+#endif++#ifdef LZ4F_DISABLE_DEPRECATE_WARNINGS+#  define LZ4F_DEPRECATE(x) x+#else+#  if defined(_MSC_VER)+#    define LZ4F_DEPRECATE(x) x   /* __declspec(deprecated) x - only works with C++ */+#  elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))+#    define LZ4F_DEPRECATE(x) x __attribute__((deprecated))+#  else+#    define LZ4F_DEPRECATE(x) x   /* no deprecation warning for this compiler */+#  endif+#endif+++/*-************************************+ *  Error management+ **************************************/+typedef size_t LZ4F_errorCode_t;++LZ4FLIB_API unsigned    LZ4F_isError(LZ4F_errorCode_t code);   /**< tells when a function result is an error code */+LZ4FLIB_API const char* LZ4F_getErrorName(LZ4F_errorCode_t code);   /**< return error code string; for debugging */+++/*-************************************+ *  Frame compression types+ ************************************* */+/* #define LZ4F_ENABLE_OBSOLETE_ENUMS   // uncomment to enable obsolete enums */+#ifdef LZ4F_ENABLE_OBSOLETE_ENUMS+#  define LZ4F_OBSOLETE_ENUM(x) , LZ4F_DEPRECATE(x) = LZ4F_##x+#else+#  define LZ4F_OBSOLETE_ENUM(x)+#endif++/* The larger the block size, the (slightly) better the compression ratio,+ * though there are diminishing returns.+ * Larger blocks also increase memory usage on both compression and decompression sides.+ */+typedef enum {+    LZ4F_default=0,+    LZ4F_max64KB=4,+    LZ4F_max256KB=5,+    LZ4F_max1MB=6,+    LZ4F_max4MB=7+    LZ4F_OBSOLETE_ENUM(max64KB)+    LZ4F_OBSOLETE_ENUM(max256KB)+    LZ4F_OBSOLETE_ENUM(max1MB)+    LZ4F_OBSOLETE_ENUM(max4MB)+} LZ4F_blockSizeID_t;++/* Linked blocks sharply reduce inefficiencies when using small blocks,+ * they compress better.+ * However, some LZ4 decoders are only compatible with independent blocks */+typedef enum {+    LZ4F_blockLinked=0,+    LZ4F_blockIndependent+    LZ4F_OBSOLETE_ENUM(blockLinked)+    LZ4F_OBSOLETE_ENUM(blockIndependent)+} LZ4F_blockMode_t;++typedef enum {+    LZ4F_noContentChecksum=0,+    LZ4F_contentChecksumEnabled+    LZ4F_OBSOLETE_ENUM(noContentChecksum)+    LZ4F_OBSOLETE_ENUM(contentChecksumEnabled)+} LZ4F_contentChecksum_t;++typedef enum {+    LZ4F_noBlockChecksum=0,+    LZ4F_blockChecksumEnabled+} LZ4F_blockChecksum_t;++typedef enum {+    LZ4F_frame=0,+    LZ4F_skippableFrame+    LZ4F_OBSOLETE_ENUM(skippableFrame)+} LZ4F_frameType_t;++#ifdef LZ4F_ENABLE_OBSOLETE_ENUMS+typedef LZ4F_blockSizeID_t blockSizeID_t;+typedef LZ4F_blockMode_t blockMode_t;+typedef LZ4F_frameType_t frameType_t;+typedef LZ4F_contentChecksum_t contentChecksum_t;+#endif++/*! LZ4F_frameInfo_t :+ *  makes it possible to set or read frame parameters.+ *  Structure must be first init to 0, using memset() or LZ4F_INIT_FRAMEINFO,+ *  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_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_frameInfo_t;++#define LZ4F_INIT_FRAMEINFO   { LZ4F_default, 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.+ *  Structure must be first init to 0, using memset() or LZ4F_INIT_PREFERENCES,+ *  setting all parameters to default.+ *  All reserved fields must be set to zero. */+typedef struct {+  LZ4F_frameInfo_t frameInfo;+  int      compressionLevel;    /* 0: default (fast mode); values > LZ4HC_CLEVEL_MAX count as LZ4HC_CLEVEL_MAX; values < 0 trigger "fast acceleration" */+  unsigned autoFlush;           /* 1: always flush; reduces usage of internal buffers */+  unsigned favorDecSpeed;       /* 1: parser favors decompression speed vs compression ratio. Only works for high compression modes (>= LZ4HC_CLEVEL_OPT_MIN) */  /* v1.8.2+ */+  unsigned reserved[3];         /* must be zero for forward compatibility */+} LZ4F_preferences_t;++#define LZ4F_INIT_PREFERENCES   { LZ4F_INIT_FRAMEINFO, 0, 0u, 0u, { 0u, 0u, 0u } }    /* v1.8.3+ */+++/*-*********************************+*  Simple compression function+***********************************/++LZ4FLIB_API int LZ4F_compressionLevel_max(void);   /* v1.8.0+ */++/*! LZ4F_compressFrameBound() :+ *  Returns the maximum possible compressed size with LZ4F_compressFrame() given srcSize and preferences.+ * `preferencesPtr` is optional. It can be replaced by NULL, in which case, the function will assume default preferences.+ *  Note : this result is only usable with LZ4F_compressFrame().+ *         It may also be relevant to LZ4F_compressUpdate() _only if_ no flush() operation is ever performed.+ */+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())+ */+LZ4FLIB_API size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity,+                                const void* srcBuffer, size_t srcSize,+                                const LZ4F_preferences_t* preferencesPtr);+++/*-***********************************+*  Advanced compression functions+*************************************/+typedef struct LZ4F_cctx_s LZ4F_cctx;   /* incomplete type */+typedef LZ4F_cctx* LZ4F_compressionContext_t;  /* for compatibility with older APIs, prefer using LZ4F_cctx */++typedef struct {+  unsigned stableSrc;    /* 1 == src content will remain present on future calls to LZ4F_compress(); skip copying src content within tmp buffer */+  unsigned reserved[3];+} LZ4F_compressOptions_t;++/*---   Resource Management   ---*/++#define LZ4F_VERSION 100    /* This number can be used to check for an incompatible API breaking change */+LZ4FLIB_API unsigned LZ4F_getVersion(void);++/*! LZ4F_createCompressionContext() :+ *  The first thing to do is to create a compressionContext object,+ *  which will keep track of operation state during streaming compression.+ *  This is achieved using LZ4F_createCompressionContext(), which takes as argument a version,+ *  and a pointer to LZ4F_cctx*, to write the resulting pointer into.+ *  @version provided MUST be LZ4F_VERSION. It is intended to track potential version mismatch, notably when using DLL.+ *  The function provides a pointer to a fully allocated LZ4F_cctx object.+ *  @cctxPtr MUST be != NULL.+ *  If @return != zero, context creation failed.+ *  A created compression context can be employed multiple times for consecutive streaming operations.+ *  Once all streaming compression jobs are completed,+ *  the state object can be released using LZ4F_freeCompressionContext().+ *  Note1 : LZ4F_freeCompressionContext() is always successful. Its return value can be ignored.+ *  Note2 : LZ4F_freeCompressionContext() works fine with NULL input pointers (do nothing).+**/+LZ4FLIB_API LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** cctxPtr, unsigned version);+LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx);+++/*----    Compression    ----*/++#define LZ4F_HEADER_SIZE_MIN  7   /* LZ4 Frame header size can vary, depending on selected parameters */+#define LZ4F_HEADER_SIZE_MAX 19++/* Size in bytes of a block header in little-endian format. Highest bit indicates if block data is uncompressed */+#define LZ4F_BLOCK_HEADER_SIZE 4++/* Size in bytes of a block checksum footer in little-endian format. */+#define LZ4F_BLOCK_CHECKSUM_SIZE 4++/* Size in bytes of the content checksum. */+#define LZ4F_CONTENT_CHECKSUM_SIZE 4++/*! 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.+ * @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(LZ4F_cctx* cctx,+                                      void* dstBuffer, size_t dstCapacity,+                                      const LZ4F_preferences_t* prefsPtr);++/*! LZ4F_compressBound() :+ *  Provides minimum dstCapacity required to guarantee success of+ *  LZ4F_compressUpdate(), given a srcSize and preferences, for a worst case scenario.+ *  When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() instead.+ *  Note that the result is only valid for a single invocation of LZ4F_compressUpdate().+ *  When invoking LZ4F_compressUpdate() multiple times,+ *  if the output buffer is gradually filled up instead of emptied and re-used from its start,+ *  one must check if there is enough remaining capacity before each invocation, using LZ4F_compressBound().+ * @return is always the same for a srcSize and prefsPtr.+ *  prefsPtr is optional : when NULL is provided, preferences will be set to cover worst case scenario.+ *  tech details :+ * @return if automatic flushing is not enabled, includes the possibility that internal buffer might already be filled by up to (blockSize-1) bytes.+ *  It also includes frame footer (ending + checksum), since it might be generated by LZ4F_compressEnd().+ * @return doesn't include frame header, as it was already generated by LZ4F_compressBegin().+ */+LZ4FLIB_API size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* prefsPtr);++/*! LZ4F_compressUpdate() :+ *  LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.+ *  Important rule: dstCapacity MUST be large enough to ensure operation success even in worst case situations.+ *  This value is provided by LZ4F_compressBound().+ *  If this condition is not respected, LZ4F_compress() 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 an uncompressed block was written, buffered data is flushed+ *  before appending compressed data is continued.+ * `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())+ */+LZ4FLIB_API size_t LZ4F_compressUpdate(LZ4F_cctx* cctx,+                                       void* dstBuffer, size_t dstCapacity,+                                 const void* srcBuffer, size_t srcSize,+                                 const LZ4F_compressOptions_t* cOptPtr);++/*! LZ4F_flush() :+ *  When data must be generated and sent immediately, without waiting for a block to be completely filled,+ *  it's possible to call LZ4_flush(). It will immediately compress any data buffered within cctx.+ * `dstCapacity` must be large enough to ensure the operation will be successful.+ * `cOptPtr` is optional : it's possible to provide NULL, all options will be set to default.+ * @return : nb of bytes written into dstBuffer (can be zero, when there is no data stored within cctx)+ *           or an error code if it fails (which can be tested using LZ4F_isError())+ *  Note : LZ4F_flush() is guaranteed to be successful when dstCapacity >= LZ4F_compressBound(0, prefsPtr).+ */+LZ4FLIB_API size_t LZ4F_flush(LZ4F_cctx* cctx,+                              void* dstBuffer, size_t dstCapacity,+                        const LZ4F_compressOptions_t* cOptPtr);++/*! LZ4F_compressEnd() :+ *  To properly finish an LZ4 frame, invoke LZ4F_compressEnd().+ *  It will flush whatever data remained within `cctx` (like LZ4_flush())+ *  and properly finalize the frame, with an endMark and a checksum.+ * `cOptPtr` is optional : NULL can be provided, in which case all options will be set to default.+ * @return : nb of bytes written into dstBuffer, necessarily >= 4 (endMark),+ *           or an error code if it fails (which can be tested using LZ4F_isError())+ *  Note : LZ4F_compressEnd() is guaranteed to be successful when dstCapacity >= LZ4F_compressBound(0, prefsPtr).+ *  A successful call to LZ4F_compressEnd() makes `cctx` available again for another compression task.+ */+LZ4FLIB_API size_t LZ4F_compressEnd(LZ4F_cctx* cctx,+                                    void* dstBuffer, size_t dstCapacity,+                              const LZ4F_compressOptions_t* cOptPtr);+++/*-*********************************+*  Decompression functions+***********************************/+typedef struct LZ4F_dctx_s LZ4F_dctx;   /* incomplete type */+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 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 */+  unsigned reserved0;     /* idem */+} LZ4F_decompressOptions_t;+++/* Resource management */++/*! LZ4F_createDecompressionContext() :+ *  Create an LZ4F_dctx object, to track all decompression operations.+ *  @version provided MUST be LZ4F_VERSION.+ *  @dctxPtr MUST be valid.+ *  The function fills @dctxPtr with the value of a pointer to an allocated and initialized LZ4F_dctx object.+ *  The @return is an errorCode, which can be tested using LZ4F_isError().+ *  dctx memory can be released using LZ4F_freeDecompressionContext();+ *  Result of LZ4F_freeDecompressionContext() indicates current state of decompressionContext when being released.+ *  That is, it should be == 0 if decompression has been completed fully and correctly.+ */+LZ4FLIB_API LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** dctxPtr, unsigned version);+LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx);+++/*-***********************************+*  Streaming decompression functions+*************************************/++#define LZ4F_MAGICNUMBER 0x184D2204U+#define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U+#define LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH 5++/*! LZ4F_headerSize() : v1.9.0++ *  Provide the header size of a frame starting at `src`.+ * `srcSize` must be >= LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH,+ *  which is enough to decode the header length.+ * @return : size of frame header+ *           or an error code, which can be tested using LZ4F_isError()+ *  note : Frame header size is variable, but is guaranteed to be+ *         >= LZ4F_HEADER_SIZE_MIN bytes, and <= LZ4F_HEADER_SIZE_MAX bytes.+ */+LZ4FLIB_API size_t LZ4F_headerSize(const void* src, size_t srcSize);++/*! LZ4F_getFrameInfo() :+ *  This function extracts frame parameters (max blockSize, dictID, etc.).+ *  Its usage is optional: user can also invoke LZ4F_decompress() directly.+ *+ *  Extracted information will fill an existing LZ4F_frameInfo_t structure.+ *  This can be useful for allocation and dictionary identification purposes.+ *+ *  LZ4F_getFrameInfo() can work in the following situations :+ *+ *  1) At the beginning of a new frame, before any invocation of LZ4F_decompress().+ *     It will decode header from `srcBuffer`,+ *     consuming the header and starting the decoding process.+ *+ *     Input size must be large enough to contain the full frame header.+ *     Frame header size can be known beforehand by LZ4F_headerSize().+ *     Frame header size is variable, but is guaranteed to be >= LZ4F_HEADER_SIZE_MIN bytes,+ *     and not more than <= LZ4F_HEADER_SIZE_MAX bytes.+ *     Hence, blindly providing LZ4F_HEADER_SIZE_MAX bytes or more will always work.+ *     It's allowed to provide more input data than the header size,+ *     LZ4F_getFrameInfo() will only consume the header.+ *+ *     If input size is not large enough,+ *     aka if it's smaller than header size,+ *     function will fail and return an error code.+ *+ *  2) After decoding has been started,+ *     it's possible to invoke LZ4F_getFrameInfo() anytime+ *     to extract already decoded frame parameters stored within dctx.+ *+ *     Note that, if decoding has barely started,+ *     and not yet read enough information to decode the header,+ *     LZ4F_getFrameInfo() will fail.+ *+ *  The number of bytes consumed from srcBuffer will be updated in *srcSizePtr (necessarily <= original value).+ *  LZ4F_getFrameInfo() only consumes bytes when decoding has not yet started,+ *  and when decoding the header has been successful.+ *  Decompression must then resume from (srcBuffer + *srcSizePtr).+ *+ * @return : a hint about how many srcSize bytes LZ4F_decompress() expects for next call,+ *           or an error code which can be tested using LZ4F_isError().+ *  note 1 : in case of error, dctx is not modified. Decoding operation can resume from beginning safely.+ *  note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure.+ */+LZ4FLIB_API size_t+LZ4F_getFrameInfo(LZ4F_dctx* dctx,+                  LZ4F_frameInfo_t* frameInfoPtr,+            const void* srcBuffer, size_t* srcSizePtr);++/*! LZ4F_decompress() :+ *  Call this function repetitively to regenerate data compressed in `srcBuffer`.+ *+ *  The function requires a valid dctx state.+ *  It will read up to *srcSizePtr bytes from srcBuffer,+ *  and decompress data into dstBuffer, of capacity *dstSizePtr.+ *+ *  The nb of bytes consumed from srcBuffer will be written into *srcSizePtr (necessarily <= original value).+ *  The nb of bytes decompressed into dstBuffer will be written into *dstSizePtr (necessarily <= original value).+ *+ *  The function does not necessarily read all input bytes, so always check value in *srcSizePtr.+ *  Unconsumed source data must be presented again in subsequent invocations.+ *+ * `dstBuffer` can freely change between each consecutive function invocation.+ * `dstBuffer` content will be overwritten.+ *+ * @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.+ *  This is just a hint though, it's always possible to provide any srcSize.+ *+ *  When a frame is fully decoded, @return will be 0 (no more data expected).+ *  When provided with more bytes than necessary to decode a frame,+ *  LZ4F_decompress() will stop reading exactly at end of current frame, and @return 0.+ *+ *  If decompression failed, @return is an error code, which can be tested using LZ4F_isError().+ *  After a decompression error, the `dctx` context is not resumable.+ *  Use LZ4F_resetDecompressionContext() to return to clean state.+ *+ *  After a frame is fully decoded, dctx can be used again to decompress another frame.+ */+LZ4FLIB_API size_t+LZ4F_decompress(LZ4F_dctx* dctx,+                void* dstBuffer, size_t* dstSizePtr,+          const void* srcBuffer, size_t* srcSizePtr,+          const LZ4F_decompressOptions_t* dOptPtr);+++/*! LZ4F_resetDecompressionContext() : added in v1.8.0+ *  In case of an error, the context is left in "undefined" state.+ *  In which case, it's necessary to reset it, before re-using it.+ *  This method can also be used to abruptly stop any unfinished decompression,+ *  and start a new one using same context resources. */+LZ4FLIB_API void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx);   /* always successful */++++#if defined (__cplusplus)+}+#endif++#endif  /* LZ4F_H_09782039843 */++#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.+ * 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.+ *+ * By default, these symbols aren't published into shared/dynamic libraries.+ * You can override this behavior and force them to be published+ * by defining LZ4F_PUBLISH_STATIC_FUNCTIONS.+ * Use at your own risk.+ */+#ifdef LZ4F_PUBLISH_STATIC_FUNCTIONS+# define LZ4FLIB_STATIC_API LZ4FLIB_API+#else+# define LZ4FLIB_STATIC_API+#endif+++/* ---   Error List   --- */+#define LZ4F_LIST_ERRORS(ITEM) \+        ITEM(OK_NoError) \+        ITEM(ERROR_GENERIC) \+        ITEM(ERROR_maxBlockSize_invalid) \+        ITEM(ERROR_blockMode_invalid) \+        ITEM(ERROR_contentChecksumFlag_invalid) \+        ITEM(ERROR_compressionLevel_invalid) \+        ITEM(ERROR_headerVersion_wrong) \+        ITEM(ERROR_blockChecksum_invalid) \+        ITEM(ERROR_reservedFlag_set) \+        ITEM(ERROR_allocation_failed) \+        ITEM(ERROR_srcSize_tooLarge) \+        ITEM(ERROR_dstMaxSize_tooSmall) \+        ITEM(ERROR_frameHeader_incomplete) \+        ITEM(ERROR_frameType_unknown) \+        ITEM(ERROR_frameSize_wrong) \+        ITEM(ERROR_srcPtr_wrong) \+        ITEM(ERROR_decompressionFailed) \+        ITEM(ERROR_headerChecksum_invalid) \+        ITEM(ERROR_contentChecksum_invalid) \+        ITEM(ERROR_frameDecoding_alreadyStarted) \+        ITEM(ERROR_compressionState_uninitialized) \+        ITEM(ERROR_parameter_null) \+        ITEM(ERROR_maxCode)++#define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM,++/* enum list is exposed, to handle specific errors */+typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM)+              _LZ4F_dummy_error_enum_for_c89_never_used } LZ4F_errorCodes;++LZ4FLIB_STATIC_API LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult);+++/*! LZ4F_getBlockSize() :+ *  Return, in scalar format (size_t),+ *  the maximum block size associated with blockSizeID.+**/+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.+ *  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+ *  before appending uncompressed data is continued.+ *  This 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())+ */+LZ4FLIB_STATIC_API size_t+LZ4F_uncompressedUpdate(LZ4F_cctx* cctx,+                        void* dstBuffer, size_t dstCapacity,+                  const void* srcBuffer, size_t srcSize,+                  const LZ4F_compressOptions_t* cOptPtr);++/**********************************+ *  Bulk processing dictionary 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.+ * 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 :+ *  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.+ */+typedef void* (*LZ4F_AllocFunction) (void* opaqueState, size_t size);+typedef void* (*LZ4F_CallocFunction) (void* opaqueState, size_t size);+typedef void  (*LZ4F_FreeFunction) (void* opaqueState, void* address);+typedef struct {+    LZ4F_AllocFunction customAlloc;+    LZ4F_CallocFunction customCalloc; /* optional; when not defined, uses customAlloc + memset */+    LZ4F_FreeFunction customFree;+    void* opaqueState;+} LZ4F_CustomMem;+static+#ifdef __GNUC__+__attribute__((__unused__))+#endif+LZ4F_CustomMem const LZ4F_defaultCMem = { NULL, NULL, NULL, NULL };  /**< this constant defers to stdlib's functions */++LZ4FLIB_STATIC_API LZ4F_cctx* LZ4F_createCompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version);+LZ4FLIB_STATIC_API LZ4F_dctx* LZ4F_createDecompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version);+LZ4FLIB_STATIC_API LZ4F_CDict* LZ4F_createCDict_advanced(LZ4F_CustomMem customMem, const void* dictBuffer, size_t dictSize);+++#if defined (__cplusplus)+}+#endif++#endif  /* defined(LZ4F_STATIC_LINKING_ONLY) && !defined(LZ4F_H_STATIC_09782039843) */
cbits/lz4hc.c view
@@ -1,6 +1,6 @@ /*     LZ4 HC - High Compression Mode of LZ4-    Copyright (C) 2011-2017, Yann Collet.+    Copyright (C) 2011-2020, Yann Collet.      BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -42,7 +42,7 @@  *  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@@ -53,7 +53,7 @@ #include "lz4hc.h"  -/*===   Common LZ4 definitions   ===*/+/*===   Common definitions   ===*/ #if defined(__GNUC__) #  pragma GCC diagnostic ignored "-Wunused-function" #endif@@ -61,15 +61,16 @@ #  pragma clang diagnostic ignored "-Wunused-function" #endif -/*===   Enums   ===*/-typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;-- #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)@@ -92,24 +93,26 @@ **************************************/ static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4) {-    MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));+    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) {-    uptrval startingOffset = (uptrval)(hc4->end - hc4->base);-    if (startingOffset > 1 GB) {+    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);-        startingOffset = 0;+        newStartingOffset = 0;     }-    startingOffset += 64 KB;-    hc4->nextToUpdate = (U32) startingOffset;-    hc4->base = start - startingOffset;+    newStartingOffset += 64 KB;+    hc4->nextToUpdate = (U32)newStartingOffset;+    hc4->prefixStart = start;     hc4->end = start;-    hc4->dictBase = start - startingOffset;-    hc4->dictLimit = (U32) startingOffset;-    hc4->lowLimit = (U32) startingOffset;+    hc4->dictStart = start;+    hc4->dictLimit = (U32)newStartingOffset;+    hc4->lowLimit = (U32)newStartingOffset; }  @@ -118,12 +121,15 @@ {     U16* const chainTable = hc4->chainTable;     U32* const hashTable  = hc4->hashTable;-    const BYTE* const base = hc4->base;-    U32 const target = (U32)(ip - base);+    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(base+idx);+        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;@@ -161,8 +167,7 @@ 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;+    if (bitsToRotate == 0) return pattern;     return LZ4HC_rotl32(pattern, (int)bitsToRotate); } @@ -172,7 +177,8 @@ 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) << 32) : pattern32;+    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;@@ -192,15 +198,14 @@             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 endianess */+ * read using natural platform endianness */ static unsigned LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern) {@@ -210,7 +215,7 @@         if (LZ4_read32(ip-4) != pattern) break;         ip -= 4;     }-    {   const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianess */+    {   const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */         while (likely(ip>iLow)) {             if (ip[-1] != *bytePtr) break;             ip--; bytePtr--;@@ -233,28 +238,28 @@  LZ4_FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (-    LZ4HC_CCtx_internal* 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)+        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 base = hc4->base;-    const U32 dictLimit = hc4->dictLimit;-    const BYTE* const lowPrefixPtr = base + dictLimit;-    const U32 ipIndex = (U32)(ip - base);-    const U32 lowestMatchIndex = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;-    const BYTE* const dictBase = hc4->dictBase;+    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;@@ -270,20 +275,19 @@     DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",                 matchIndex, lowestMatchIndex); -    while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) {+    while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {         int matchLength=0;         nbAttempts--;         assert(matchIndex < ipIndex);         if (favorDecSpeed && (ipIndex - matchIndex < 8)) {             /* do nothing */-        } else if (matchIndex >= dictLimit) {   /* within current Prefix */-            const BYTE* const matchPtr = base + matchIndex;-            assert(matchPtr >= lowPrefixPtr);+        } 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, lowPrefixPtr) : 0;+                    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) {@@ -292,24 +296,25 @@                         *startpos = ip + back;             }   }   }         } else {   /* lowestMatchIndex <= matchIndex < dictLimit */-            const BYTE* const matchPtr = dictBase + matchIndex;-            if (LZ4_read32(matchPtr) == pattern) {-                const BYTE* const dictStart = dictBase + hc4->lowLimit;+            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 + (dictLimit - matchIndex);+                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, lowPrefixPtr, 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 = base + matchIndex + back;   /* virtual pos, relative to ip, to retrieve offset */+                    *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 */+        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;@@ -325,8 +330,7 @@                         distanceToNextMatch = candidateDist;                         matchChainPos = (U32)pos;                         accel = 1 << kTrigger;-                    }-                }+                }   }                 if (distanceToNextMatch > 1) {                     if (distanceToNextMatch > matchIndex) break;   /* avoid overflow */                     matchIndex -= distanceToNextMatch;@@ -346,23 +350,24 @@                         repeat = rep_not;                 }   }                 if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)-                  && LZ4HC_protectDictEnd(dictLimit, matchCandidateIdx) ) {-                    const int extDict = matchCandidateIdx < dictLimit;-                    const BYTE* const matchPtr = (extDict ? dictBase : base) + matchCandidateIdx;+                  && 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 dictStart = dictBase + hc4->lowLimit;-                        const BYTE* const iLimit = extDict ? dictBase + dictLimit : iHighLimit;+                        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(lowPrefixPtr, iHighLimit, rotatedPattern);+                            forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);                         }-                        {   const BYTE* const lowestMatchPtr = extDict ? dictStart : lowPrefixPtr;+                        {   const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;                             size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);                             size_t currentSegmentLength;-                            if (!extDict && matchPtr - backLength == lowPrefixPtr && hc4->lowLimit < dictLimit) {+                            if (!extDict+                              && matchPtr - backLength == prefixPtr+                              && dictIdx < prefixIdx) {                                 U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);-                                backLength += LZ4HC_reverseCountPattern(dictBase + dictLimit, dictStart, rotatedPattern);+                                backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);                             }                             /* Limit backLength not go further than lowestMatchIndex */                             backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);@@ -372,28 +377,28 @@                             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(dictLimit, newMatchIndex))+                                if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))                                     matchIndex = newMatchIndex;                                 else {                                     /* Can only happen if started in the prefix */-                                    assert(newMatchIndex >= dictLimit - 3 && newMatchIndex < dictLimit && !extDict);-                                    matchIndex = dictLimit;+                                    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(dictLimit, newMatchIndex)) {-                                    assert(newMatchIndex >= dictLimit - 3 && newMatchIndex < dictLimit && !extDict);-                                    matchIndex = dictLimit;+                                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(base + matchIndex != ip);-                                            if ((size_t)(ip - base) - matchIndex > LZ4_DISTANCE_MAX) break;+                                            assert(prefixPtr - prefixIdx + matchIndex != ip);+                                            if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;                                             assert(maxML < 2 GB);                                             longest = (int)maxML;-                                            *matchpos = base + matchIndex;   /* virtual pos, relative to ip, to retrieve offset */+                                            *matchpos = prefixPtr - prefixIdx + matchIndex;   /* virtual pos, relative to ip, to retrieve offset */                                             *startpos = ip;                                         }                                         {   U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);@@ -410,14 +415,14 @@     }  /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */      if ( dict == usingDictCtxHc-      && nbAttempts+      && nbAttempts > 0       && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {-        size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->base);+        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->base + dictMatchIndex;+            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;              if (LZ4_read32(matchPtr) == pattern) {                 int mlt;@@ -425,11 +430,11 @@                 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->base + dictCtx->dictLimit) : 0;+                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;                 mlt -= back;                 if (mlt > longest) {                     longest = mlt;-                    *matchpos = base + matchIndex + back;+                    *matchpos = prefixPtr - prefixIdx + matchIndex + back;                     *startpos = ip + back;             }   } @@ -441,13 +446,13 @@     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)+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),@@ -460,74 +465,90 @@  * @return : 0 if ok,  *           1 if buffer issue detected */ LZ4_FORCE_INLINE int LZ4HC_encodeSequence (-    const BYTE** ip,-    BYTE** op,-    const BYTE** anchor,+    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)++;+    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 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 */+    if (start==NULL) start = anchor;  /* only works for single segment */     /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */-    DEBUGLOG(6, "pos:%7u -- literals:%3u, match:%4i, offset:%5u, cost:%3u + %u",+    DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u",                 pos,-                (U32)(*ip - *anchor), matchLength, (U32)(*ip-match),+                (U32)(ip - anchor), matchLength, (U32)(ip-match),                 cost, totalCost);     totalCost += cost; #endif      /* Encode Literal length */-    length = (size_t)(*ip - *anchor);-    if ((limit) && ((*op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1;   /* Check output limit */+    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;+        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;+    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;+    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)) return 1;   /* Check output limit */+    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;+        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;+    ip += matchLength;+    anchor = ip;      return 0; }+#undef ip+#undef op+#undef anchor  LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (     LZ4HC_CCtx_internal* const ctx,@@ -535,7 +556,7 @@     char* const dest,     int* srcSizePtr,     int const maxOutputSize,-    unsigned maxNbAttempts,+    int maxNbAttempts,     const limitedOutput_directive limit,     const dictCtx_directive dict     )@@ -565,7 +586,7 @@     /* 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) */+    if (inputSize < LZ4_minLength) goto _last_literals;             /* Input too small, no compression (all literals) */      /* Main Loop */     while (ip <= mflimit) {@@ -637,7 +658,11 @@             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)) goto _dest_overflow;+            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) {+                ml  = ml2;+                ref = ref2;+                goto _dest_overflow;+            }             continue;         } @@ -709,17 +734,18 @@ _last_literals:     /* Encode Last Literals */     {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */-        size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;-        size_t const totalSize = 1 + litLength + lastRunSize;+        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;  /* Check output limit */+            if (limit == limitedOutput) return 0;             /* adapt lastRunSize to fill 'dest' */-            lastRunSize  = (size_t)(oend - op) - 1;-            litLength = (lastRunSize + 255 - RUN_MASK) / 255;-            lastRunSize -= litLength;+            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;+            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;+            lastRunSize -= llAdd;         }-        ip = anchor + lastRunSize;+        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;@@ -729,7 +755,7 @@         } else {             *op++ = (BYTE)(lastRunSize << ML_BITS);         }-        memcpy(op, anchor, lastRunSize);+        LZ4_memcpy(op, anchor, lastRunSize);         op += lastRunSize;     } @@ -739,9 +765,25 @@  _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; } @@ -752,7 +794,7 @@     int const nbSearches, size_t sufficient_len,     const limitedOutput_directive limit, int const fullUpdate,     const dictCtx_directive dict,-    HCfavor_e favorDecSpeed);+    const HCfavor_e favorDecSpeed);   LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (@@ -769,7 +811,7 @@     typedef enum { lz4hc, lz4opt } lz4hc_strat_e;     typedef struct {         lz4hc_strat_e strat;-        U32 nbSearches;+        int nbSearches;         U32 targetLength;     } cParams_t;     static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = {@@ -788,7 +830,8 @@         { lz4opt,16384,LZ4_OPT_NUM },  /* 12==LZ4HC_CLEVEL_MAX */     }; -    DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d)", ctx, src, *srcSizePtr);+    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) */@@ -808,7 +851,7 @@             assert(cParam.strat == lz4opt);             result = LZ4HC_compress_optimal(ctx,                                 src, dst, srcSizePtr, dstCapacity,-                                (int)cParam.nbSearches, cParam.targetLength, limit,+                                cParam.nbSearches, cParam.targetLength, limit,                                 cLevel == LZ4HC_CLEVEL_MAX,   /* ultra mode */                                 dict, favor);         }@@ -845,13 +888,13 @@         limitedOutput_directive limit         ) {-    const size_t position = (size_t)(ctx->end - ctx->base) - ctx->lowLimit;+    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) {-        memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));+        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);@@ -881,27 +924,22 @@  int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); } -#ifndef _MSC_VER  /* for some reason, Visual fails the aligment test on 32-bit x86 :-                   * it reports an aligment of 8-bytes,-                   * while actually aligning LZ4_streamHC_t on 4 bytes. */ static size_t LZ4_streamHC_t_alignment(void) {-    struct { char c; LZ4_streamHC_t t; } t_a;-    return sizeof(t_a) - sizeof(t_a.t);-}+#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;-#ifndef _MSC_VER  /* for some reason, Visual fails the aligment test on 32-bit x86 :-                   * it reports an aligment of 8-bytes,-                   * while actually aligning LZ4_streamHC_t on 4 bytes. */-    assert(((size_t)state & (LZ4_streamHC_t_alignment() - 1)) == 0);  /* check alignment */-#endif-    if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0;   /* Error : state is not aligned for pointers (32 or 64 bits) */+    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))@@ -919,13 +957,15 @@  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-    int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);+    cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel); #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1     FREEMEM(statePtr); #endif@@ -948,12 +988,14 @@ *  Streaming Functions **************************************/ /* allocation */+#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_streamHC_t* LZ4_createStreamHC(void) {-    LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));-    if (LZ4_streamHCPtr==NULL) return NULL;-    LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));  /* full initialization, malloc'ed buffer can be full of garbage */-    return LZ4_streamHCPtr;+    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)@@ -963,27 +1005,20 @@     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;-#ifndef _MSC_VER  /* for some reason, Visual fails the aligment test on 32-bit x86 :-                   * it reports an aligment of 8-bytes,-                   * while actually aligning LZ4_streamHC_t on 4 bytes. */-    if (((size_t)buffer) & (LZ4_streamHC_t_alignment() - 1)) return NULL;  /* alignment check */-#endif-    /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */-    LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= LZ4_STREAMHCSIZE);-    DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", LZ4_streamHCPtr, (unsigned)size);-    /* end-base will trigger a clearTable on starting compression */-    LZ4_streamHCPtr->internal_donotuse.end = (const BYTE *)(ptrdiff_t)-1;-    LZ4_streamHCPtr->internal_donotuse.base = NULL;-    LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;-    LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = 0;-    LZ4_streamHCPtr->internal_donotuse.dirty = 0;+    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; }@@ -1001,9 +1036,13 @@     if (LZ4_streamHCPtr->internal_donotuse.dirty) {         LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));     } else {-        /* preserve end - base : can trigger clearTable's threshold */-        LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.base;-        LZ4_streamHCPtr->internal_donotuse.base = NULL;+        /* 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);@@ -1054,14 +1093,14 @@ static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock) {     DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);-    if (ctxPtr->end >= ctxPtr->base + ctxPtr->dictLimit + 4)+    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->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);-    ctxPtr->dictBase  = ctxPtr->base;-    ctxPtr->base = newBlock - 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 */ @@ -1069,21 +1108,22 @@     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)+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(4, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d)",-                LZ4_streamHCPtr, src, *srcSizePtr);+    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->base == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);+    if (ctxPtr->prefixStart == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);      /* Check overflow */-    if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) {-        size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;+    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);     }@@ -1094,14 +1134,16 @@      /* Check overlapping input/dictionary space */     {   const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;-        const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;-        const BYTE* const dictEnd   = ctxPtr->dictBase + ctxPtr->dictLimit;+        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->dictBase);-            if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;-        }-    }+            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); }@@ -1121,23 +1163,31 @@   -/* dictionary saving */-+/* 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->base + streamPtr->dictLimit));-    DEBUGLOG(4, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);+    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;-    memmove(safeBuffer, streamPtr->end - dictSize, dictSize);-    {   U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);+    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->base = streamPtr->end - endIndex;+        streamPtr->prefixStart = streamPtr->end - dictSize;         streamPtr->dictLimit = endIndex - (U32)dictSize;         streamPtr->lowLimit = endIndex - (U32)dictSize;-        if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit;+        streamPtr->dictStart = streamPtr->prefixStart;+        if (streamPtr->nextToUpdate < streamPtr->dictLimit)+            streamPtr->nextToUpdate = streamPtr->dictLimit;     }     return dictSize; }@@ -1163,7 +1213,7 @@   /* Deprecated streaming functions */-int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }+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 */@@ -1175,6 +1225,7 @@     return 0; } +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) void* LZ4_createHC (const char* inputBuffer) {     LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();@@ -1189,6 +1240,7 @@     FREEMEM(LZ4HC_Data);     return 0; }+#endif  int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel) {@@ -1202,11 +1254,11 @@  char* LZ4_slideInputBufferHC(void* LZ4HC_Data) {-    LZ4_streamHC_t *ctx = (LZ4_streamHC_t*)LZ4HC_Data;-    const BYTE *bufferStart = ctx->internal_donotuse.base + ctx->internal_donotuse.lowLimit;+    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;+    return (char*)(uptrval)bufferStart; }  @@ -1287,8 +1339,13 @@                                     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;@@ -1298,15 +1355,19 @@     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 */-    assert(ip - anchor < LZ4_MAX_INPUT_SIZE);     while (ip <= mflimit) {          int const llen = (int)(ip - anchor);          int best_mlen, best_off;@@ -1320,8 +1381,11 @@              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 */+             if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) {  /* updates ip, op and anchor */+                 ovml = firstML;+                 ovref = matchPos;                  goto _dest_overflow;+             }              continue;          } @@ -1463,7 +1527,7 @@          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 */+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);@@ -1493,25 +1557,31 @@                  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 */+                 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:+_last_literals:      /* Encode Last Literals */      {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */-         size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;-         size_t const totalSize = 1 + litLength + lastRunSize;+         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;  /* Check output limit */+             if (limit == limitedOutput) { /* Check output limit */+                retval = 0;+                goto _return_label;+             }              /* adapt lastRunSize to fill 'dst' */-             lastRunSize  = (size_t)(oend - op) - 1;-             litLength = (lastRunSize + 255 - RUN_MASK) / 255;-             lastRunSize -= litLength;+             lastRunSize  = (size_t)(oend - op) - 1 /*token*/;+             llAdd = (lastRunSize + 256 - RUN_MASK) / 256;+             lastRunSize -= llAdd;          }-         ip = anchor + lastRunSize;+         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;@@ -1521,18 +1591,41 @@          } else {              *op++ = (BYTE)(lastRunSize << ML_BITS);          }-         memcpy(op, anchor, lastRunSize);+         LZ4_memcpy(op, anchor, lastRunSize);          op += lastRunSize;      }       /* End */      *srcSizePtr = (int) (((const char*)ip) - source);-     return (int) ((char*)op-dst);+     retval = (int) ((char*)op-dst);+     goto _return_label; - _dest_overflow:-     if (limit == fillOutput) {-         op = opSaved;  /* restore correct out pointer */-         goto _last_literals;-     }-     return 0;- }+_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;+}
cbits/lz4hc.h view
@@ -1,7 +1,7 @@ /*    LZ4 HC - High Compression Mode of LZ4    Header File-   Copyright (C) 2011-2017, Yann Collet.+   Copyright (C) 2011-2020, Yann Collet.    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)     Redistribution and use in source and binary forms, with or without@@ -198,63 +198,36 @@ #define LZ4HC_HASH_MASK (LZ4HC_HASHTABLESIZE - 1)  -#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)-#include <stdint.h>--typedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal;-struct LZ4HC_CCtx_internal-{-    uint32_t   hashTable[LZ4HC_HASHTABLESIZE];-    uint16_t   chainTable[LZ4HC_MAXD];-    const uint8_t* end;         /* next block here to continue on current prefix */-    const uint8_t* base;        /* All index relative to this position */-    const uint8_t* dictBase;    /* alternate base for extDict */-    uint32_t   dictLimit;       /* below that point, need extDict */-    uint32_t   lowLimit;        /* below that point, no more dict */-    uint32_t   nextToUpdate;    /* index from which to continue dictionary update */-    short      compressionLevel;-    int8_t     favorDecSpeed;   /* favor decompression speed if this flag set,-                                   otherwise, favor compression ratio */-    int8_t     dirty;           /* stream has to be fully reset if this flag is set */-    const LZ4HC_CCtx_internal* dictCtx;-};--#else-+/* Never ever use these definitions directly !+ * Declare or allocate an LZ4_streamHC_t instead.+**/ typedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal; struct LZ4HC_CCtx_internal {-    unsigned int   hashTable[LZ4HC_HASHTABLESIZE];-    unsigned short chainTable[LZ4HC_MAXD];-    const unsigned char* end;        /* next block here to continue on current prefix */-    const unsigned char* base;       /* All index relative to this position */-    const unsigned char* dictBase;   /* alternate base for extDict */-    unsigned int   dictLimit;        /* below that point, need extDict */-    unsigned int   lowLimit;         /* below that point, no more dict */-    unsigned int   nextToUpdate;     /* index from which to continue dictionary update */-    short          compressionLevel;-    char           favorDecSpeed;    /* favor decompression speed if this flag set,-                                        otherwise, favor compression ratio */-    char           dirty;            /* stream has to be fully reset if this flag is set */+    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 */     const LZ4HC_CCtx_internal* dictCtx; }; -#endif---/* Do not use these definitions directly !- * Declare or allocate an LZ4_streamHC_t instead.- */-#define LZ4_STREAMHCSIZE       (4*LZ4HC_HASHTABLESIZE + 2*LZ4HC_MAXD + 56 + ((sizeof(void*)==16) ? 56 : 0) /* AS400*/ ) /* 262200 or 262256*/-#define LZ4_STREAMHCSIZE_SIZET (LZ4_STREAMHCSIZE / sizeof(size_t))+#define LZ4_STREAMHC_MINSIZE  262200  /* static size, for inter-version compatibility */ union LZ4_streamHC_u {-    size_t table[LZ4_STREAMHCSIZE_SIZET];+    char minStateSize[LZ4_STREAMHC_MINSIZE];     LZ4HC_CCtx_internal internal_donotuse; }; /* previously typedef'd to LZ4_streamHC_t */  /* LZ4_streamHC_t :  * This structure allows static allocation of LZ4 HC streaming state.- * This can be used to allocate statically, on state, or as part of a larger structure.+ * This can be used to allocate statically on stack, or as part of a larger structure.  *  * Such state **must** be initialized using LZ4_initStreamHC() before first use.  *@@ -269,7 +242,7 @@  * Required before first use of a statically allocated LZ4_streamHC_t.  * Before v1.9.0 : use LZ4_resetStreamHC() instead  */-LZ4LIB_API LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size);+LZ4LIB_API LZ4_streamHC_t* LZ4_initStreamHC(void* buffer, size_t size);   /*-************************************@@ -297,9 +270,11 @@  * LZ4_slideInputBufferHC() will truncate the history of the stream, rather  * than preserve a window-sized chunk of history.  */+#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_DEPRECATED("use LZ4_createStreamHC() instead") LZ4LIB_API void* LZ4_createHC (const char* inputBuffer);-LZ4_DEPRECATED("use LZ4_saveDictHC() instead") LZ4LIB_API     char* LZ4_slideInputBufferHC (void* LZ4HC_Data); LZ4_DEPRECATED("use LZ4_freeStreamHC() instead") LZ4LIB_API   int   LZ4_freeHC (void* LZ4HC_Data);+#endif+LZ4_DEPRECATED("use LZ4_saveDictHC() instead") LZ4LIB_API     char* LZ4_slideInputBufferHC (void* LZ4HC_Data); LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_compressHC2_continue               (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel); LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); LZ4_DEPRECATED("use LZ4_createStreamHC() instead") LZ4LIB_API int   LZ4_sizeofStreamStateHC(void);@@ -330,7 +305,7 @@  * They should not be linked from DLL,  * as there is no guarantee of API stability yet.  * Prototypes will be promoted to "stable" status- * after successfull usage in real-life scenarios.+ * after successful usage in real-life scenarios.  ***************************************************/ #ifdef LZ4_HC_STATIC_LINKING_ONLY   /* protection macro */ #ifndef LZ4_HC_SLO_098092834
+ cbits/xxhash.c view
@@ -0,0 +1,1030 @@+/*+*  xxHash - Fast Hash algorithm+*  Copyright (C) 2012-2016, Yann Collet+*+*  BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)+*+*  Redistribution and use in source and binary forms, with or without+*  modification, are permitted provided that the following conditions are+*  met:+*+*  * Redistributions of source code must retain the above copyright+*  notice, this list of conditions and the following disclaimer.+*  * Redistributions in binary form must reproduce the above+*  copyright notice, this list of conditions and the following disclaimer+*  in the documentation and/or other materials provided with the+*  distribution.+*+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+*+*  You can contact the author at :+*  - xxHash homepage: http://www.xxhash.com+*  - xxHash source repository : https://github.com/Cyan4973/xxHash+*/+++/* *************************************+*  Tuning parameters+***************************************/+/*!XXH_FORCE_MEMORY_ACCESS :+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.+ * The below switch allow to select different access method for improved performance.+ * Method 0 (default) : use `memcpy()`. Safe and portable.+ * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).+ *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.+ * Method 2 : direct access. This method doesn't depend on compiler but violate C standard.+ *            It can generate buggy code on targets which do not support unaligned memory accesses.+ *            But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)+ * See http://stackoverflow.com/a/32095106/646947 for details.+ * Prefer these methods in priority order (0 > 1 > 2)+ */+#ifndef XXH_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */+#  if defined(__GNUC__) && ( 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 XXH_FORCE_MEMORY_ACCESS 2+#  elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \+  (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \+                    || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \+                    || defined(__ARM_ARCH_7S__) ))+#    define XXH_FORCE_MEMORY_ACCESS 1+#  endif+#endif++/*!XXH_ACCEPT_NULL_INPUT_POINTER :+ * If input pointer is NULL, xxHash default behavior is to dereference it, triggering a segfault.+ * When this macro is enabled, xxHash actively checks input for null pointer.+ * It it is, result for null input pointers is the same as a null-length input.+ */+#ifndef XXH_ACCEPT_NULL_INPUT_POINTER   /* can be defined externally */+#  define XXH_ACCEPT_NULL_INPUT_POINTER 0+#endif++/*!XXH_FORCE_NATIVE_FORMAT :+ * By default, xxHash library provides endian-independent Hash values, based on little-endian convention.+ * Results are therefore identical for little-endian and big-endian CPU.+ * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.+ * Should endian-independence be of no importance for your application, you may set the #define below to 1,+ * to improve speed for Big-endian CPU.+ * This option has no impact on Little_Endian CPU.+ */+#ifndef XXH_FORCE_NATIVE_FORMAT   /* can be defined externally */+#  define XXH_FORCE_NATIVE_FORMAT 0+#endif++/*!XXH_FORCE_ALIGN_CHECK :+ * This is a minor performance trick, only useful with lots of very small keys.+ * It means : check for aligned/unaligned input.+ * The check costs one initial branch per hash;+ * set it to 0 when the input is guaranteed to be aligned,+ * or when alignment doesn't matter for performance.+ */+#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */+#  if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)+#    define XXH_FORCE_ALIGN_CHECK 0+#  else+#    define XXH_FORCE_ALIGN_CHECK 1+#  endif+#endif+++/* *************************************+*  Includes & Memory related functions+***************************************/+/*! Modify the local functions below should you wish to use some other memory routines+*   for malloc(), free() */+#include <stdlib.h>+static void* XXH_malloc(size_t s) { return malloc(s); }+static void  XXH_free  (void* p)  { free(p); }+/*! and for memcpy() */+#include <string.h>+static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }++#include <assert.h>   /* assert */++#define XXH_STATIC_LINKING_ONLY+#include "xxhash.h"+++/* *************************************+*  Compiler Specific Options+***************************************/+#ifdef _MSC_VER    /* Visual Studio */+#  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__+#      define FORCE_INLINE static inline __attribute__((always_inline))+#    else+#      define FORCE_INLINE static inline+#    endif+#  else+#    define FORCE_INLINE static+#  endif /* __STDC_VERSION__ */+#endif+++/* *************************************+*  Basic Types+***************************************/+#ifndef MEM_MODULE+# if !defined (__VMS) \+  && (defined (__cplusplus) \+  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )+#   include <stdint.h>+    typedef uint8_t  BYTE;+    typedef uint16_t U16;+    typedef uint32_t U32;+# else+    typedef unsigned char      BYTE;+    typedef unsigned short     U16;+    typedef unsigned int       U32;+# endif+#endif++#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))++/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */+static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }++#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))++/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */+/* currently only defined for gcc and icc */+typedef union { U32 u32; } __attribute__((packed)) unalign;+static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }++#else++/* portable and safe solution. Generally efficient.+ * see : http://stackoverflow.com/a/32095106/646947+ */+static U32 XXH_read32(const void* memPtr)+{+    U32 val;+    memcpy(&val, memPtr, sizeof(val));+    return val;+}++#endif   /* XXH_FORCE_DIRECT_MEMORY_ACCESS */+++/* ****************************************+*  Compiler-specific Functions and Macros+******************************************/+#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)++/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */+#if defined(_MSC_VER)+#  define XXH_rotl32(x,r) _rotl(x,r)+#  define XXH_rotl64(x,r) _rotl64(x,r)+#else+#  define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))+#  define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))+#endif++#if defined(_MSC_VER)     /* Visual Studio */+#  define XXH_swap32 _byteswap_ulong+#elif XXH_GCC_VERSION >= 403+#  define XXH_swap32 __builtin_bswap32+#else+static U32 XXH_swap32 (U32 x)+{+    return  ((x << 24) & 0xff000000 ) |+            ((x <<  8) & 0x00ff0000 ) |+            ((x >>  8) & 0x0000ff00 ) |+            ((x >> 24) & 0x000000ff );+}+#endif+++/* *************************************+*  Architecture Macros+***************************************/+typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;++/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */+#ifndef XXH_CPU_LITTLE_ENDIAN+static int XXH_isLittleEndian(void)+{+    const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental  */+    return one.c[0];+}+#   define XXH_CPU_LITTLE_ENDIAN   XXH_isLittleEndian()+#endif+++/* ***************************+*  Memory reads+*****************************/+typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;++FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)+{+    if (align==XXH_unaligned)+        return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));+    else+        return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);+}++FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)+{+    return XXH_readLE32_align(ptr, endian, XXH_unaligned);+}++static U32 XXH_readBE32(const void* ptr)+{+    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);+}+++/* *************************************+*  Macros+***************************************/+#define XXH_STATIC_ASSERT(c)  { enum { XXH_sa = 1/(int)(!!(c)) }; }  /* use after variable declarations */+XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }+++/* *******************************************************************+*  32-bit hash functions+*********************************************************************/+static const U32 PRIME32_1 = 2654435761U;+static const U32 PRIME32_2 = 2246822519U;+static const U32 PRIME32_3 = 3266489917U;+static const U32 PRIME32_4 =  668265263U;+static const U32 PRIME32_5 =  374761393U;++static U32 XXH32_round(U32 seed, U32 input)+{+    seed += input * PRIME32_2;+    seed  = XXH_rotl32(seed, 13);+    seed *= PRIME32_1;+    return seed;+}++/* mix all bits */+static U32 XXH32_avalanche(U32 h32)+{+    h32 ^= h32 >> 15;+    h32 *= PRIME32_2;+    h32 ^= h32 >> 13;+    h32 *= PRIME32_3;+    h32 ^= h32 >> 16;+    return(h32);+}++#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)++static U32+XXH32_finalize(U32 h32, const void* ptr, size_t len,+                XXH_endianess endian, XXH_alignment align)++{+    const BYTE* p = (const BYTE*)ptr;++#define PROCESS1               \+    h32 += (*p++) * PRIME32_5; \+    h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;++#define PROCESS4                         \+    h32 += XXH_get32bits(p) * PRIME32_3; \+    p+=4;                                \+    h32  = XXH_rotl32(h32, 17) * PRIME32_4 ;++    switch(len&15)  /* or switch(bEnd - p) */+    {+      case 12:      PROCESS4;+                    /* fallthrough */+      case 8:       PROCESS4;+                    /* fallthrough */+      case 4:       PROCESS4;+                    return XXH32_avalanche(h32);++      case 13:      PROCESS4;+                    /* fallthrough */+      case 9:       PROCESS4;+                    /* fallthrough */+      case 5:       PROCESS4;+                    PROCESS1;+                    return XXH32_avalanche(h32);++      case 14:      PROCESS4;+                    /* fallthrough */+      case 10:      PROCESS4;+                    /* fallthrough */+      case 6:       PROCESS4;+                    PROCESS1;+                    PROCESS1;+                    return XXH32_avalanche(h32);++      case 15:      PROCESS4;+                    /* fallthrough */+      case 11:      PROCESS4;+                    /* fallthrough */+      case 7:       PROCESS4;+                    /* fallthrough */+      case 3:       PROCESS1;+                    /* fallthrough */+      case 2:       PROCESS1;+                    /* fallthrough */+      case 1:       PROCESS1;+                    /* fallthrough */+      case 0:       return XXH32_avalanche(h32);+    }+    assert(0);+    return h32;   /* reaching this point is deemed impossible */+}+++FORCE_INLINE U32+XXH32_endian_align(const void* input, size_t len, U32 seed,+                    XXH_endianess endian, XXH_alignment align)+{+    const BYTE* p = (const BYTE*)input;+    const BYTE* bEnd = p + len;+    U32 h32;++#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)+    if (p==NULL) {+        len=0;+        bEnd=p=(const BYTE*)(size_t)16;+    }+#endif++    if (len>=16) {+        const BYTE* const limit = bEnd - 15;+        U32 v1 = seed + PRIME32_1 + PRIME32_2;+        U32 v2 = seed + PRIME32_2;+        U32 v3 = seed + 0;+        U32 v4 = seed - PRIME32_1;++        do {+            v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;+            v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;+            v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;+            v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;+        } while (p < limit);++        h32 = XXH_rotl32(v1, 1)  + XXH_rotl32(v2, 7)+            + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);+    } else {+        h32  = seed + PRIME32_5;+    }++    h32 += (U32)len;++    return XXH32_finalize(h32, p, len&15, endian, align);+}+++XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)+{+#if 0+    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */+    XXH32_state_t state;+    XXH32_reset(&state, seed);+    XXH32_update(&state, input, len);+    return XXH32_digest(&state);+#else+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++    if (XXH_FORCE_ALIGN_CHECK) {+        if ((((size_t)input) & 3) == 0) {   /* Input is 4-bytes aligned, leverage the speed benefit */+            if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+                return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);+            else+                return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);+    }   }++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);+    else+        return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);+#endif+}++++/*======   Hash streaming   ======*/++XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)+{+    return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));+}+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)+{+    XXH_free(statePtr);+    return XXH_OK;+}++XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)+{+    memcpy(dstState, srcState, sizeof(*dstState));+}++XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)+{+    XXH32_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */+    memset(&state, 0, sizeof(state));+    state.v1 = seed + PRIME32_1 + PRIME32_2;+    state.v2 = seed + PRIME32_2;+    state.v3 = seed + 0;+    state.v4 = seed - PRIME32_1;+    /* do not write into reserved, planned to be removed in a future version */+    memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));+    return XXH_OK;+}+++FORCE_INLINE XXH_errorcode+XXH32_update_endian(XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)+{+    if (input==NULL)+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)+        return XXH_OK;+#else+        return XXH_ERROR;+#endif++    {   const BYTE* p = (const BYTE*)input;+        const BYTE* const bEnd = p + len;++        state->total_len_32 += (unsigned)len;+        state->large_len |= (len>=16) | (state->total_len_32>=16);++        if (state->memsize + len < 16)  {   /* fill in tmp buffer */+            XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);+            state->memsize += (unsigned)len;+            return XXH_OK;+        }++        if (state->memsize) {   /* some data left from previous update */+            XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);+            {   const U32* p32 = state->mem32;+                state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;+                state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;+                state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;+                state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian));+            }+            p += 16-state->memsize;+            state->memsize = 0;+        }++        if (p <= bEnd-16) {+            const BYTE* const limit = bEnd - 16;+            U32 v1 = state->v1;+            U32 v2 = state->v2;+            U32 v3 = state->v3;+            U32 v4 = state->v4;++            do {+                v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;+                v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;+                v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;+                v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;+            } while (p<=limit);++            state->v1 = v1;+            state->v2 = v2;+            state->v3 = v3;+            state->v4 = v4;+        }++        if (p < bEnd) {+            XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));+            state->memsize = (unsigned)(bEnd-p);+        }+    }++    return XXH_OK;+}+++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;++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH32_update_endian(state_in, input, len, XXH_littleEndian);+    else+        return XXH32_update_endian(state_in, input, len, XXH_bigEndian);+}+++FORCE_INLINE U32+XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)+{+    U32 h32;++    if (state->large_len) {+        h32 = XXH_rotl32(state->v1, 1)+            + XXH_rotl32(state->v2, 7)+            + XXH_rotl32(state->v3, 12)+            + XXH_rotl32(state->v4, 18);+    } else {+        h32 = state->v3 /* == seed */ + PRIME32_5;+    }++    h32 += state->total_len_32;++    return XXH32_finalize(h32, state->mem32, state->memsize, endian, XXH_aligned);+}+++XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)+{+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH32_digest_endian(state_in, XXH_littleEndian);+    else+        return XXH32_digest_endian(state_in, XXH_bigEndian);+}+++/*======   Canonical representation   ======*/++/*! Default XXH result types are basic unsigned 32 and 64 bits.+*   The canonical representation follows human-readable write convention, aka big-endian (large digits first).+*   These functions allow transformation of hash result into and from its canonical format.+*   This way, hash values can be written into a file or buffer, remaining comparable across different systems.+*/++XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)+{+    XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));+    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);+    memcpy(dst, &hash, sizeof(*dst));+}++XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)+{+    return XXH_readBE32(src);+}+++#ifndef XXH_NO_LONG_LONG++/* *******************************************************************+*  64-bit hash functions+*********************************************************************/++/*======   Memory access   ======*/++#ifndef MEM_MODULE+# define MEM_MODULE+# if !defined (__VMS) \+  && (defined (__cplusplus) \+  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )+#   include <stdint.h>+    typedef uint64_t U64;+# else+    /* if compiler doesn't support unsigned long long, replace by another 64-bit type */+    typedef unsigned long long U64;+# endif+#endif+++#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))++/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */+static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }++#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))++/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */+/* currently only defined for gcc and icc */+typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64;+static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; }++#else++/* portable and safe solution. Generally efficient.+ * see : http://stackoverflow.com/a/32095106/646947+ */++static U64 XXH_read64(const void* memPtr)+{+    U64 val;+    memcpy(&val, memPtr, sizeof(val));+    return val;+}++#endif   /* XXH_FORCE_DIRECT_MEMORY_ACCESS */++#if defined(_MSC_VER)     /* Visual Studio */+#  define XXH_swap64 _byteswap_uint64+#elif XXH_GCC_VERSION >= 403+#  define XXH_swap64 __builtin_bswap64+#else+static U64 XXH_swap64 (U64 x)+{+    return  ((x << 56) & 0xff00000000000000ULL) |+            ((x << 40) & 0x00ff000000000000ULL) |+            ((x << 24) & 0x0000ff0000000000ULL) |+            ((x << 8)  & 0x000000ff00000000ULL) |+            ((x >> 8)  & 0x00000000ff000000ULL) |+            ((x >> 24) & 0x0000000000ff0000ULL) |+            ((x >> 40) & 0x000000000000ff00ULL) |+            ((x >> 56) & 0x00000000000000ffULL);+}+#endif++FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)+{+    if (align==XXH_unaligned)+        return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));+    else+        return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);+}++FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)+{+    return XXH_readLE64_align(ptr, endian, XXH_unaligned);+}++static U64 XXH_readBE64(const void* ptr)+{+    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);+}+++/*======   xxh64   ======*/++static const U64 PRIME64_1 = 11400714785074694791ULL;+static const U64 PRIME64_2 = 14029467366897019727ULL;+static const U64 PRIME64_3 =  1609587929392839161ULL;+static const U64 PRIME64_4 =  9650029242287828579ULL;+static const U64 PRIME64_5 =  2870177450012600261ULL;++static U64 XXH64_round(U64 acc, U64 input)+{+    acc += input * PRIME64_2;+    acc  = XXH_rotl64(acc, 31);+    acc *= PRIME64_1;+    return acc;+}++static U64 XXH64_mergeRound(U64 acc, U64 val)+{+    val  = XXH64_round(0, val);+    acc ^= val;+    acc  = acc * PRIME64_1 + PRIME64_4;+    return acc;+}++static U64 XXH64_avalanche(U64 h64)+{+    h64 ^= h64 >> 33;+    h64 *= PRIME64_2;+    h64 ^= h64 >> 29;+    h64 *= PRIME64_3;+    h64 ^= h64 >> 32;+    return h64;+}+++#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)++static U64+XXH64_finalize(U64 h64, const void* ptr, size_t len,+               XXH_endianess endian, XXH_alignment align)+{+    const BYTE* p = (const BYTE*)ptr;++#define PROCESS1_64            \+    h64 ^= (*p++) * PRIME64_5; \+    h64 = XXH_rotl64(h64, 11) * PRIME64_1;++#define PROCESS4_64          \+    h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; \+    p+=4;                    \+    h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;++#define PROCESS8_64 {        \+    U64 const k1 = XXH64_round(0, XXH_get64bits(p)); \+    p+=8;                    \+    h64 ^= k1;               \+    h64  = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; \+}++    switch(len&31) {+      case 24: PROCESS8_64;+                    /* fallthrough */+      case 16: PROCESS8_64;+                    /* fallthrough */+      case  8: PROCESS8_64;+               return XXH64_avalanche(h64);++      case 28: PROCESS8_64;+                    /* fallthrough */+      case 20: PROCESS8_64;+                    /* fallthrough */+      case 12: PROCESS8_64;+                    /* fallthrough */+      case  4: PROCESS4_64;+               return XXH64_avalanche(h64);++      case 25: PROCESS8_64;+                    /* fallthrough */+      case 17: PROCESS8_64;+                    /* fallthrough */+      case  9: PROCESS8_64;+               PROCESS1_64;+               return XXH64_avalanche(h64);++      case 29: PROCESS8_64;+                    /* fallthrough */+      case 21: PROCESS8_64;+                    /* fallthrough */+      case 13: PROCESS8_64;+                    /* fallthrough */+      case  5: PROCESS4_64;+               PROCESS1_64;+               return XXH64_avalanche(h64);++      case 26: PROCESS8_64;+                    /* fallthrough */+      case 18: PROCESS8_64;+                    /* fallthrough */+      case 10: PROCESS8_64;+               PROCESS1_64;+               PROCESS1_64;+               return XXH64_avalanche(h64);++      case 30: PROCESS8_64;+                    /* fallthrough */+      case 22: PROCESS8_64;+                    /* fallthrough */+      case 14: PROCESS8_64;+                    /* fallthrough */+      case  6: PROCESS4_64;+               PROCESS1_64;+               PROCESS1_64;+               return XXH64_avalanche(h64);++      case 27: PROCESS8_64;+                    /* fallthrough */+      case 19: PROCESS8_64;+                    /* fallthrough */+      case 11: PROCESS8_64;+               PROCESS1_64;+               PROCESS1_64;+               PROCESS1_64;+               return XXH64_avalanche(h64);++      case 31: PROCESS8_64;+                    /* fallthrough */+      case 23: PROCESS8_64;+                    /* fallthrough */+      case 15: PROCESS8_64;+                    /* fallthrough */+      case  7: PROCESS4_64;+                    /* fallthrough */+      case  3: PROCESS1_64;+                    /* fallthrough */+      case  2: PROCESS1_64;+                    /* fallthrough */+      case  1: PROCESS1_64;+                    /* fallthrough */+      case  0: return XXH64_avalanche(h64);+    }++    /* impossible to reach */+    assert(0);+    return 0;  /* unreachable, but some compilers complain without it */+}++FORCE_INLINE U64+XXH64_endian_align(const void* input, size_t len, U64 seed,+                XXH_endianess endian, XXH_alignment align)+{+    const BYTE* p = (const BYTE*)input;+    const BYTE* bEnd = p + len;+    U64 h64;++#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)+    if (p==NULL) {+        len=0;+        bEnd=p=(const BYTE*)(size_t)32;+    }+#endif++    if (len>=32) {+        const BYTE* const limit = bEnd - 32;+        U64 v1 = seed + PRIME64_1 + PRIME64_2;+        U64 v2 = seed + PRIME64_2;+        U64 v3 = seed + 0;+        U64 v4 = seed - PRIME64_1;++        do {+            v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;+            v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;+            v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;+            v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;+        } while (p<=limit);++        h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);+        h64 = XXH64_mergeRound(h64, v1);+        h64 = XXH64_mergeRound(h64, v2);+        h64 = XXH64_mergeRound(h64, v3);+        h64 = XXH64_mergeRound(h64, v4);++    } else {+        h64  = seed + PRIME64_5;+    }++    h64 += (U64) len;++    return XXH64_finalize(h64, p, len, endian, align);+}+++XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)+{+#if 0+    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */+    XXH64_state_t state;+    XXH64_reset(&state, seed);+    XXH64_update(&state, input, len);+    return XXH64_digest(&state);+#else+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++    if (XXH_FORCE_ALIGN_CHECK) {+        if ((((size_t)input) & 7)==0) {  /* Input is aligned, let's leverage the speed advantage */+            if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+                return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);+            else+                return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);+    }   }++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);+    else+        return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);+#endif+}++/*======   Hash Streaming   ======*/++XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)+{+    return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));+}+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)+{+    XXH_free(statePtr);+    return XXH_OK;+}++XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)+{+    memcpy(dstState, srcState, sizeof(*dstState));+}++XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)+{+    XXH64_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */+    memset(&state, 0, sizeof(state));+    state.v1 = seed + PRIME64_1 + PRIME64_2;+    state.v2 = seed + PRIME64_2;+    state.v3 = seed + 0;+    state.v4 = seed - PRIME64_1;+     /* do not write into reserved, planned to be removed in a future version */+    memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));+    return XXH_OK;+}++FORCE_INLINE XXH_errorcode+XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)+{+    if (input==NULL)+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)+        return XXH_OK;+#else+        return XXH_ERROR;+#endif++    {   const BYTE* p = (const BYTE*)input;+        const BYTE* const bEnd = p + len;++        state->total_len += len;++        if (state->memsize + len < 32) {  /* fill in tmp buffer */+            XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);+            state->memsize += (U32)len;+            return XXH_OK;+        }++        if (state->memsize) {   /* tmp buffer is full */+            XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);+            state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));+            state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));+            state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));+            state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));+            p += 32-state->memsize;+            state->memsize = 0;+        }++        if (p+32 <= bEnd) {+            const BYTE* const limit = bEnd - 32;+            U64 v1 = state->v1;+            U64 v2 = state->v2;+            U64 v3 = state->v3;+            U64 v4 = state->v4;++            do {+                v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;+                v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;+                v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;+                v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;+            } while (p<=limit);++            state->v1 = v1;+            state->v2 = v2;+            state->v3 = v3;+            state->v4 = v4;+        }++        if (p < bEnd) {+            XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));+            state->memsize = (unsigned)(bEnd-p);+        }+    }++    return XXH_OK;+}++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;++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH64_update_endian(state_in, input, len, XXH_littleEndian);+    else+        return XXH64_update_endian(state_in, input, len, XXH_bigEndian);+}++FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)+{+    U64 h64;++    if (state->total_len >= 32) {+        U64 const v1 = state->v1;+        U64 const v2 = state->v2;+        U64 const v3 = state->v3;+        U64 const v4 = state->v4;++        h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);+        h64 = XXH64_mergeRound(h64, v1);+        h64 = XXH64_mergeRound(h64, v2);+        h64 = XXH64_mergeRound(h64, v3);+        h64 = XXH64_mergeRound(h64, v4);+    } else {+        h64  = state->v3 /*seed*/ + PRIME64_5;+    }++    h64 += (U64) state->total_len;++    return XXH64_finalize(h64, state->mem64, (size_t)state->total_len, endian, XXH_aligned);+}++XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)+{+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH64_digest_endian(state_in, XXH_littleEndian);+    else+        return XXH64_digest_endian(state_in, XXH_bigEndian);+}+++/*====== Canonical representation   ======*/++XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)+{+    XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));+    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);+    memcpy(dst, &hash, sizeof(*dst));+}++XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)+{+    return XXH_readBE64(src);+}++#endif  /* XXH_NO_LONG_LONG */
+ cbits/xxhash.h view
@@ -0,0 +1,328 @@+/*+   xxHash - Extremely Fast Hash algorithm+   Header File+   Copyright (C) 2012-2016, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++   You can contact the author at :+   - xxHash source repository : https://github.com/Cyan4973/xxHash+*/++/* Notice extracted from xxHash homepage :++xxHash is an extremely fast Hash algorithm, running at RAM speed limits.+It also successfully passes all tests from the SMHasher suite.++Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)++Name            Speed       Q.Score   Author+xxHash          5.4 GB/s     10+CrapWow         3.2 GB/s      2       Andrew+MumurHash 3a    2.7 GB/s     10       Austin Appleby+SpookyHash      2.0 GB/s     10       Bob Jenkins+SBox            1.4 GB/s      9       Bret Mulvey+Lookup3         1.2 GB/s      9       Bob Jenkins+SuperFastHash   1.2 GB/s      1       Paul Hsieh+CityHash64      1.05 GB/s    10       Pike & Alakuijala+FNV             0.55 GB/s     5       Fowler, Noll, Vo+CRC32           0.43 GB/s     9+MD5-32          0.33 GB/s    10       Ronald L. Rivest+SHA1-32         0.28 GB/s    10++Q.Score is a measure of quality of the hash function.+It depends on successfully passing SMHasher test set.+10 is a perfect score.++A 64-bit version, named XXH64, is available since r35.+It offers much better speed, but for 64-bit applications only.+Name     Speed on 64 bits    Speed on 32 bits+XXH64       13.8 GB/s            1.9 GB/s+XXH32        6.8 GB/s            6.0 GB/s+*/++#ifndef XXHASH_H_5627135585666179+#define XXHASH_H_5627135585666179 1++#if defined (__cplusplus)+extern "C" {+#endif+++/* ****************************+*  Definitions+******************************/+#include <stddef.h>   /* size_t */+typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;+++/* ****************************+ *  API modifier+ ******************************/+/** XXH_INLINE_ALL (and XXH_PRIVATE_API)+ *  This is useful to include xxhash functions in `static` mode+ *  in order to inline them, and remove their symbol from the public list.+ *  Inlining can offer dramatic performance improvement on small keys.+ *  Methodology :+ *     #define XXH_INLINE_ALL+ *     #include "xxhash.h"+ * `xxhash.c` is automatically included.+ *  It's not useful to compile and link it as a separate module.+ */+#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)+#  ifndef XXH_STATIC_LINKING_ONLY+#    define XXH_STATIC_LINKING_ONLY+#  endif+#  if defined(__GNUC__)+#    define XXH_PUBLIC_API static __inline __attribute__((unused))+#  elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)+#    define XXH_PUBLIC_API static inline+#  elif defined(_MSC_VER)+#    define XXH_PUBLIC_API static __inline+#  else+     /* this version may generate warnings for unused static functions */+#    define XXH_PUBLIC_API static+#  endif+#else+#  define XXH_PUBLIC_API   /* do nothing */+#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */++/*! XXH_NAMESPACE, aka Namespace Emulation :+ *+ * If you want to include _and expose_ xxHash functions from within your own library,+ * but also want to avoid symbol collisions with other libraries which may also include xxHash,+ *+ * you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library+ * with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values).+ *+ * Note that no change is required within the calling program as long as it includes `xxhash.h` :+ * regular symbol name will be automatically translated by this header.+ */+#ifdef XXH_NAMESPACE+#  define XXH_CAT(A,B) A##B+#  define XXH_NAME2(A,B) XXH_CAT(A,B)+#  define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)+#  define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)+#  define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)+#  define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)+#  define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)+#  define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)+#  define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)+#  define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)+#  define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)+#  define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)+#  define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)+#  define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)+#  define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)+#  define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)+#  define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)+#  define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)+#  define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)+#  define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)+#  define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)+#endif+++/* *************************************+*  Version+***************************************/+#define XXH_VERSION_MAJOR    0+#define XXH_VERSION_MINOR    6+#define XXH_VERSION_RELEASE  5+#define XXH_VERSION_NUMBER  (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)+XXH_PUBLIC_API unsigned XXH_versionNumber (void);+++/*-**********************************************************************+*  32-bit hash+************************************************************************/+typedef unsigned int XXH32_hash_t;++/*! XXH32() :+    Calculate the 32-bit hash of sequence "length" bytes stored at memory address "input".+    The memory between input & input+length must be valid (allocated and read-accessible).+    "seed" can be used to alter the result predictably.+    Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */+XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);++/*======   Streaming   ======*/+typedef struct XXH32_state_s XXH32_state_t;   /* incomplete type */+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);+XXH_PUBLIC_API XXH_errorcode  XXH32_freeState(XXH32_state_t* statePtr);+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);++XXH_PUBLIC_API XXH_errorcode XXH32_reset  (XXH32_state_t* statePtr, unsigned int seed);+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);+XXH_PUBLIC_API XXH32_hash_t  XXH32_digest (const XXH32_state_t* statePtr);++/*+ * Streaming functions generate the xxHash of an input provided in multiple segments.+ * Note that, for small input, they are slower than single-call functions, due to state management.+ * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized.+ *+ * XXH state must first be allocated, using XXH*_createState() .+ *+ * Start a new hash by initializing state with a seed, using XXH*_reset().+ *+ * Then, feed the hash state by calling XXH*_update() as many times as necessary.+ * The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.+ *+ * Finally, a hash value can be produced anytime, by using XXH*_digest().+ * This function returns the nn-bits hash as an int or long long.+ *+ * It's still possible to continue inserting input into the hash state after a digest,+ * and generate some new hashes later on, by calling again XXH*_digest().+ *+ * When done, free XXH state space if it was allocated dynamically.+ */++/*======   Canonical representation   ======*/++typedef struct { unsigned char digest[4]; } XXH32_canonical_t;+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);++/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.+ * The canonical representation uses human-readable write convention, aka big-endian (large digits first).+ * These functions allow transformation of hash result into and from its canonical format.+ * This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.+ */+++#ifndef XXH_NO_LONG_LONG+/*-**********************************************************************+*  64-bit hash+************************************************************************/+typedef unsigned long long XXH64_hash_t;++/*! XXH64() :+    Calculate the 64-bit hash of sequence of length "len" stored at memory address "input".+    "seed" can be used to alter the result predictably.+    This function runs faster on 64-bit systems, but slower on 32-bit systems (see benchmark).+*/+XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);++/*======   Streaming   ======*/+typedef struct XXH64_state_s XXH64_state_t;   /* incomplete type */+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);+XXH_PUBLIC_API XXH_errorcode  XXH64_freeState(XXH64_state_t* statePtr);+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);++XXH_PUBLIC_API XXH_errorcode XXH64_reset  (XXH64_state_t* statePtr, unsigned long long seed);+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);+XXH_PUBLIC_API XXH64_hash_t  XXH64_digest (const XXH64_state_t* statePtr);++/*======   Canonical representation   ======*/+typedef struct { unsigned char digest[8]; } XXH64_canonical_t;+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);+#endif  /* XXH_NO_LONG_LONG */++++#ifdef XXH_STATIC_LINKING_ONLY++/* ================================================================================================+   This section contains declarations which are not guaranteed to remain stable.+   They may change in future versions, becoming incompatible with a different version of the library.+   These declarations should only be used with static linking.+   Never use them in association with dynamic linking !+=================================================================================================== */++/* These definitions are only present to allow+ * static allocation of XXH state, on stack or in a struct for example.+ * Never **ever** use members directly. */++#if !defined (__VMS) \+  && (defined (__cplusplus) \+  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )+#   include <stdint.h>++struct XXH32_state_s {+   uint32_t total_len_32;+   uint32_t large_len;+   uint32_t v1;+   uint32_t v2;+   uint32_t v3;+   uint32_t v4;+   uint32_t mem32[4];+   uint32_t memsize;+   uint32_t reserved;   /* never read nor write, might be removed in a future version */+};   /* typedef'd to XXH32_state_t */++struct XXH64_state_s {+   uint64_t total_len;+   uint64_t v1;+   uint64_t v2;+   uint64_t v3;+   uint64_t v4;+   uint64_t mem64[4];+   uint32_t memsize;+   uint32_t reserved[2];          /* never read nor write, might be removed in a future version */+};   /* typedef'd to XXH64_state_t */++# else++struct XXH32_state_s {+   unsigned total_len_32;+   unsigned large_len;+   unsigned v1;+   unsigned v2;+   unsigned v3;+   unsigned v4;+   unsigned mem32[4];+   unsigned memsize;+   unsigned reserved;   /* never read nor write, might be removed in a future version */+};   /* typedef'd to XXH32_state_t */++#   ifndef XXH_NO_LONG_LONG  /* remove 64-bit support */+struct XXH64_state_s {+   unsigned long long total_len;+   unsigned long long v1;+   unsigned long long v2;+   unsigned long long v3;+   unsigned long long v4;+   unsigned long long mem64[4];+   unsigned memsize;+   unsigned reserved[2];     /* never read nor write, might be removed in a future version */+};   /* typedef'd to XXH64_state_t */+#    endif++# endif+++#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)+#  include "xxhash.c"   /* include xxhash function bodies as `static`, for inlining */+#endif++#endif /* XXH_STATIC_LINKING_ONLY */+++#if defined (__cplusplus)+}+#endif++#endif /* XXHASH_H_5627135585666179 */
lz4-bytes.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.2 name:               lz4-bytes-version:            0.1.2.0+version:            0.2.0.0 synopsis:           Bindings to LZ4 description:   This library is similar to the @lz4@ library except that it works@@ -17,6 +17,8 @@ build-type:         Simple extra-source-files:   cbits/lz4.h+  cbits/lz4frame.h+  cbits/xxhash.h   cbits/lz4hc.h  extra-doc-files:    CHANGELOG.md@@ -41,12 +43,15 @@     , run-st      >=0.1.1 && <0.2    hs-source-dirs:  src-  include-dirs:    cbits-  ghc-options:     -O2+  include-dirs: cbits+  ghc-options: -O2 -Wall+  cc-options: -Wall   c-sources:     cbits/hs_lz4.c     cbits/lz4.c+    cbits/lz4frame.c     cbits/lz4hc.c+    cbits/xxhash.c  test-suite test   import:         build-settings
src/Lz4/Frame.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE BinaryLiterals #-} {-# LANGUAGE BlockArguments #-} {-# LANGUAGE DerivingStrategies #-}@@ -17,16 +18,22 @@   , decompressU   ) where -import Lz4.Internal (requiredBufferSize,c_hs_compress_HC,c_hs_decompress_safe)+import Lz4.Internal (requiredBufferSize,c_hs_compress_HC,c_hs_decompress_safe,DecompressionContext)+import Lz4.Internal (c_LZ4F_createDecompressionContext, c_hs_decompress_frame)+import Lz4.Internal (c_LZ4F_freeDecompressionContext)+import Foreign.C.Types (CSize) +import Foreign.Ptr (Ptr)+import Foreign.Storable (peek)+import GHC.Exts (RealWorld) import Control.Monad (when) import Control.Monad.ST (runST) import Data.Bits ((.&.)) import Data.Bytes.Types (Bytes (Bytes)) import Data.Int (Int32)-import Data.Primitive (ByteArray (..), MutableByteArray (..))+import Data.Primitive (ByteArray (..), MutableByteArray (..), MutablePrimArray) import Data.Word (Word8, Word32)-import GHC.IO (unsafeIOToST)+import GHC.IO (unsafeIOToST,unsafeDupablePerformIO)  import qualified Data.Primitive as PM import qualified Data.Primitive.ByteArray.LittleEndian as LE@@ -39,18 +46,21 @@ -- It is difficult to find examples of lz4 frames that actually use -- any of these. Open a PR with an example of an lz4 frame that fails -- to decode if you find one.+--+-- Error codes from the C library lz4 are returned in the Left data+-- constructor. decompressU ::      Int -- ^ The exact size of the decompressed bytes   -> Bytes -- ^ Compressed bytes-  -> Maybe ByteArray+  -> Either Int ByteArray decompressU !decompressedSize (Bytes arr@(ByteArray arr# ) off len) = do-  when (len < 11) Nothing-  when (indexWord8 arr off /= 0x04) Nothing-  when (indexWord8 arr (off + 1) /= 0x22) Nothing-  when (indexWord8 arr (off + 2) /= 0x4D) Nothing-  when (indexWord8 arr (off + 3) /= 0x18) Nothing+  when (len < 11) (Left 10000)+  when (indexWord8 arr off /= 0x04) (Left 10001)+  when (indexWord8 arr (off + 1) /= 0x22) (Left 10002)+  when (indexWord8 arr (off + 2) /= 0x4D) (Left 10003)+  when (indexWord8 arr (off + 3) /= 0x18) (Left 10004)   let !flag = indexWord8 arr (off + 4)-  when (flag /= 0b0110_0000) Nothing+  -- when (flag /= 0b0110_0000) Nothing   -- Here is the code that would read the size hint from the bd. However,   -- there is no reason to use this since this function takes the actual   -- size as an argument. We ignore the checksum at position off+6 as well.@@ -62,32 +72,50 @@   --   0b0100_0000 -> pure 65536   --   _ -> Nothing   -- when (maximumDecompressedSize < decompressedSize) Nothing-  let !compressedSize = LE.indexUnalignedByteArray arr (off + 7) :: Word32-  let !compressedSizeI = fromIntegral (compressedSize .&. 0x7fff_ffff) :: Int-  when (compressedSizeI + (4 + 3 + 4 + 4) /= len) Nothing-  let !offPost = off + 11 + compressedSizeI-  when (indexWord8 arr offPost /= 0x00) Nothing-  when (indexWord8 arr (offPost + 1) /= 0x00) Nothing-  when (indexWord8 arr (offPost + 2) /= 0x00) Nothing-  when (indexWord8 arr (offPost + 3) /= 0x00) Nothing-  case compressedSize .&. 0x8000_0000 of-    0 -> runST $ do-      dst@(MutableByteArray dst# ) <- PM.newByteArray decompressedSize-      actualSz <- unsafeIOToST (c_hs_decompress_safe arr# (off + 11) dst# 0 compressedSizeI decompressedSize)-      -- Note: actualSz will be negative if decompression fails. That's fine.-      if actualSz == decompressedSize-        then do-          dst' <- PM.unsafeFreezeByteArray dst-          pure (Just dst')-        else pure Nothing-    _ -> do-      -- When the upper bit of the size is set, it means that the data in-      -- the block is uncompressed. This code path is not tested in the test-      -- suite, and I cannot find examples of this feature used in the wild.-      -- If anyone knows of an example, open a PR.-      when (decompressedSize /= compressedSizeI) Nothing-      when (decompressedSize + 15 /= len) Nothing-      Just $! Bytes.toByteArrayClone (Bytes arr (off + 11) decompressedSize)+  if | flag == 0b0110_0000+     , !compressedSize <- LE.indexUnalignedByteArray arr (off + 7) :: Word32+     , !compressedSizeI <- fromIntegral (compressedSize .&. 0x7fff_ffff) :: Int+     , compressedSizeI + (4 + 3 + 4 + 4) == len -> do+         -- When there is only one block and there aren't any checksums,+         -- we can just decompress the single block and allocating and+         -- freeing a context. This case is pretty common in practice.+         let !offPost = off + 11 + compressedSizeI+         when (indexWord8 arr offPost /= 0x00) (Left 10005)+         when (indexWord8 arr (offPost + 1) /= 0x00) (Left 10006)+         when (indexWord8 arr (offPost + 2) /= 0x00) (Left 10007)+         when (indexWord8 arr (offPost + 3) /= 0x00) (Left 10008)+         case compressedSize .&. 0x8000_0000 of+           0 -> runST $ do+             dst@(MutableByteArray dst# ) <- PM.newByteArray decompressedSize+             actualSz <- unsafeIOToST (c_hs_decompress_safe arr# (off + 11) dst# 0 compressedSizeI decompressedSize)+             -- Note: actualSz will be negative if decompression fails. That's fine.+             if actualSz == decompressedSize+               then do+                 dst' <- PM.unsafeFreezeByteArray dst+                 pure (Right dst')+               else pure (Left 10009)+           _ -> do+             -- When the upper bit of the size is set, it means that the data in+             -- the block is uncompressed. This code path is not tested in the test+             -- suite, and I cannot find examples of this feature used in the wild.+             -- If anyone knows of an example, open a PR.+             when (decompressedSize /= compressedSizeI) (Left 10010)+             when (decompressedSize + 15 /= len) (Left 10011)+             Right $! Bytes.toByteArrayClone (Bytes arr (off + 11) decompressedSize)+     | otherwise -> unsafeDupablePerformIO $ do+         dst@(MutableByteArray dst# ) <- PM.newByteArray decompressedSize+         dctxPtrMba :: MutablePrimArray RealWorld (Ptr DecompressionContext) <- PM.newPinnedPrimArray 1+         let !dctxPtrPtr = PM.mutablePrimArrayContents dctxPtrMba+         x <- c_LZ4F_createDecompressionContext dctxPtrPtr 100+         case x of+           0 -> do+             dctxPtr <- peek dctxPtrPtr+             r <- c_hs_decompress_frame dctxPtr arr# off len dst# decompressedSize+             _ <- c_LZ4F_freeDecompressionContext dctxPtr+             case r of+               0 -> Right <$> PM.unsafeFreezeByteArray dst+               _ -> pure (Left r)+           _ -> errorWithoutStackTrace "Lz4.Frame.decompressU: failed to create decompression context"  {- | Use HC compression to produce a frame with a single block. All optional fields (checksums, content sizes, and dictionary IDs)@@ -105,8 +133,8 @@   -- | Bytes to compress   Bytes ->   ByteArray-compressHighlyU !lvl (Bytes (ByteArray arr) off len) = runST do-  let maxSz = requiredBufferSize len + 15+compressHighlyU !lvl (Bytes (ByteArray arr) off0 len0) = runST do+  let maxSz = requiredBufferSize len0 + 15   dst@(MutableByteArray dst#) <- PM.newByteArray maxSz   -- -- First 4 bytes: magic identifier   PM.writeByteArray dst 0 (0x04 :: Word8)@@ -116,26 +144,35 @@   -- Next 3 bytes: frame descriptor   PM.writeByteArray dst 4 (0b0110_0000 :: Word8)   if-    | len <= 65_536 -> do+    | len0 <= 65_536 -> do         PM.writeByteArray dst 5 (0b0100_0000 :: Word8)         PM.writeByteArray dst 6 (0x82 :: Word8)-    | len <= 262_144 -> do+    | len0 <= 262_144 -> do         PM.writeByteArray dst 5 (0b0101_0000 :: Word8)         PM.writeByteArray dst 6 (0xFB :: Word8)-    | len <= 1_048_576 -> do+    | len0 <= 1_048_576 -> do         PM.writeByteArray dst 5 (0b0110_0000 :: Word8)         PM.writeByteArray dst 6 (0x51 :: Word8)     | otherwise -> do         PM.writeByteArray dst 5 (0b0111_0000 :: Word8)         PM.writeByteArray dst 6 (0x73 :: Word8)-  actualSz <- unsafeIOToST (c_hs_compress_HC arr off dst# 11 len maxSz lvl)-  LE.writeUnalignedByteArray dst 7 (fromIntegral actualSz :: Int32)-  PM.writeByteArray dst (actualSz + 11) (0x00 :: Word8)-  PM.writeByteArray dst (actualSz + 12) (0x00 :: Word8)-  PM.writeByteArray dst (actualSz + 13) (0x00 :: Word8)-  PM.writeByteArray dst (actualSz + 14) (0x00 :: Word8)-  PM.shrinkMutableByteArray dst (actualSz + 15)-  PM.unsafeFreezeByteArray dst+  let handleBlocks !ix !inputOff !inputRemaining = do+        let !inputClipped = min inputRemaining 4_194_304+        actualSz <- unsafeIOToST (c_hs_compress_HC arr inputOff dst# (ix + 4) inputClipped maxSz lvl)+        case actualSz of+          0 -> errorWithoutStackTrace "Lz4.Frame.compressHighlyU: compression failed"+          _ -> do+            LE.writeUnalignedByteArray dst ix (fromIntegral actualSz :: Int32)+            let inputRemaining' = inputRemaining - inputClipped+            let inputOff' = inputOff + inputClipped+            if inputRemaining' > 0+              then do+                handleBlocks (ix + 4 + actualSz) inputOff' inputRemaining'+              else do+                LE.writeUnalignedByteArray dst (actualSz + ix + 4) (0 :: Word32)+                PM.shrinkMutableByteArray dst (actualSz + ix + 8)+                PM.unsafeFreezeByteArray dst+  handleBlocks 7 off0 len0  indexWord8 :: ByteArray -> Int -> Word8 {-# inline indexWord8 #-}
src/Lz4/Internal.hs view
@@ -7,13 +7,20 @@ These functions do not perform any framing. -} module Lz4.Internal-  ( requiredBufferSize+  ( DecompressionContext+  , requiredBufferSize   , c_hs_compress_HC   , c_hs_decompress_safe+  , c_hs_decompress_frame+  , c_LZ4F_createDecompressionContext+  , c_LZ4F_freeDecompressionContext   ) where -import GHC.Exts (ByteArray#, MutableByteArray#)+import GHC.Exts (ByteArray#, MutableByteArray#, Ptr)+import Foreign.C.Types (CUInt(..), CSize(..)) +-- | Phantom type for pointers+data DecompressionContext  {- | Copied from the @LZ4_COMPRESSBOUND@ macro lz4.h to avoid using FFI for simple arithmetic. Make sure this stays in sync with the macro.@@ -42,3 +49,24 @@     -> Int       -- Input size     -> Int       -- Destination capacity     -> IO Int    -- Result length++foreign import ccall unsafe "hs_decompress_frame"+  c_hs_decompress_frame ::+       Ptr DecompressionContext+    -> ByteArray# -- Source+    -> Int        -- Source offset+    -> Int        -- Source length+    -> MutableByteArray# s -- Destination+    -> Int                 -- Destination offset+    -> IO Int              -- Result (0 means success)++foreign import ccall unsafe "LZ4F_createDecompressionContext"+  c_LZ4F_createDecompressionContext ::+       Ptr (Ptr DecompressionContext)+    -> CUInt -- version+    -> IO CSize++foreign import ccall unsafe "LZ4F_freeDecompressionContext"+  c_LZ4F_freeDecompressionContext ::+       Ptr DecompressionContext+    -> IO CSize
test/Main.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NumericUnderscores #-} {-# LANGUAGE ScopedTypeVariables #-}  import Data.Bytes (Bytes)@@ -33,18 +34,50 @@   , testGroup "frame"     [ testProperty "roundtrip-HC" $ forAll genByteArray $ \bs ->         let cs = Frame.compressHighlyU 3 (Bytes.fromByteArray bs) in-        Just bs+        Right bs         ===         Frame.decompressU (sizeofByteArray bs) (Bytes.fromByteArray cs)+    , testCase "roundtrip-HC-80k" $ testRoundtrip 80_000+    , testCase "roundtrip-HC-800k" $ testRoundtrip 800_000+    , testCase "roundtrip-HC-2M" $ testRoundtrip 2_000_000+    , testCase "roundtrip-HC-5M" $ testRoundtrip 5_000_000+    , testCase "roundtrip-HC-9M" $ testRoundtrip 9_000_000+    , testCase "packing-HC-80k" $ testPacking 80_000+    , testCase "packing-HC-800k" $ testPacking 800_000+    , testCase "packing-HC-2M" $ testPacking 2_000_000+    , testCase "packing-HC-5M" $ testPacking 5_000_000+    , testCase "packing-HC-9M" $ testPacking 9_000_000     , testCase "example-a" $ case Frame.decompressU 20 (Bytes.fromByteArray exampleA) of-        Nothing -> fail "decompression failed"-        Just _ -> pure ()+        Left{} -> fail "decompression failed"+        Right _ -> pure ()     , testCase "example-b" $ case Frame.decompressU 10 (Bytes.fromByteArray exampleB) of-        Nothing -> fail "decompression failed"-        Just x -> x @=? Exts.fromList [0xbb :: Word8, 0x01, 0xbb, 0x01, 0xbb, 0x01, 0xbb, 0x01, 0xbb, 0x01 ]+        Left{} -> fail "decompression failed"+        Right x -> x @=? Exts.fromList [0xbb :: Word8, 0x01, 0xbb, 0x01, 0xbb, 0x01, 0xbb, 0x01, 0xbb, 0x01 ]+    , testCase "example-c" $ case Frame.decompressU 20 (Bytes.fromByteArray exampleC) of+        Left e -> fail ("decompression failed, error code: " ++ show e)+        Right _ -> pure ()     ]   ] +testRoundtrip :: Int -> IO ()+testRoundtrip sz =+  let uncompressed = Bytes.replicate sz 0x01 in+  let compressed = Frame.compressHighlyU 3 uncompressed in+  case Frame.decompressU sz (Bytes.fromByteArray compressed) of+    Left{} -> fail "decompression failed"+    Right result -> if uncompressed == Bytes.fromByteArray result+      then pure ()+      else fail "compression and decompression did not round trip"++testPacking :: Int -> IO ()+testPacking sz =+  let uncompressed = Bytes.replicate sz 0x01 in+  let compressed = Frame.compressHighlyU 3 uncompressed in+  let lenCompressed = sizeofByteArray compressed in+  if lenCompressed * 100 > sz+    then fail "Repetition of same byte has compression factor less than 100"+    else pure ()+ genBytes :: Gen Bytes genBytes = do   n <- choose (0, 200)@@ -61,6 +94,19 @@ exampleA = Exts.fromList   [ 0x04, 0x22, 0x4d, (0x18 :: Word8)   , 0x60, 0x40, 0x82+  , 0x0d, 0x00, 0x00, 0x00 -- little-endian encoding of the number 13+  , 0x47, 0x15, 0x08, 0x01, 0x0a, 0x04 , 0x00, 0x50, 0x0a, 0x15, 0x08, 0x01, 0x0a+  , 0x00, 0x00, 0x00, 0x00+  ]++-- Same as exampleA, but the flag indicates that linked blocks are used.+-- There is only one block, so there aren't actually linked blocks, but+-- this lets us force the decompress function to take the slow path+-- where it sets up a decompression context.+exampleC :: ByteArray+exampleC = Exts.fromList+  [ 0x04, 0x22, 0x4d, (0x18 :: Word8)+  , 0x40, 0x40, 0xc0   , 0x0d, 0x00, 0x00, 0x00 -- little-endian encoding of the number 13   , 0x47, 0x15, 0x08, 0x01, 0x0a, 0x04 , 0x00, 0x50, 0x0a, 0x15, 0x08, 0x01, 0x0a   , 0x00, 0x00, 0x00, 0x00