|
@@ -0,0 +1,5687 @@
|
|
|
+# HG changeset patch
|
|
|
+# User Ryan VanderMeulen <ryanvm@gmail.com>
|
|
|
+# Date 1661962245 0
|
|
|
+# Wed Aug 31 16:10:45 2022 +0000
|
|
|
+# Node ID 7eef756241bc1408a297d251f396657fda0b5a55
|
|
|
+# Parent 5be68f0fff6d9abd730db7c0921c37c2992cba7b
|
|
|
+Bug 1784990 - Update lz4 to 1.9.4. r=glandium
|
|
|
+
|
|
|
+Differential Revision: https://phabricator.services.mozilla.com/D154770
|
|
|
+
|
|
|
+diff --git a/mfbt/lz4/LICENSE b/mfbt/lz4/LICENSE
|
|
|
+--- a/mfbt/lz4/LICENSE
|
|
|
++++ b/mfbt/lz4/LICENSE
|
|
|
+@@ -1,10 +1,10 @@
|
|
|
+ LZ4 Library
|
|
|
+-Copyright (c) 2011-2016, Yann Collet
|
|
|
++Copyright (c) 2011-2020, Yann Collet
|
|
|
+ All rights reserved.
|
|
|
+
|
|
|
+ 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.
|
|
|
+
|
|
|
+diff --git a/mfbt/lz4/README.md b/mfbt/lz4/README.md
|
|
|
+--- a/mfbt/lz4/README.md
|
|
|
++++ b/mfbt/lz4/README.md
|
|
|
+@@ -1,46 +1,65 @@
|
|
|
+ LZ4 - Library Files
|
|
|
+ ================================
|
|
|
+
|
|
|
+ The `/lib` directory contains many files, but depending on project's objectives,
|
|
|
+-not all of them are necessary.
|
|
|
++not all of them are required.
|
|
|
++Limited systems may want to reduce the nb of source files to include
|
|
|
++as a way to reduce binary size and dependencies.
|
|
|
+
|
|
|
+-#### Minimal LZ4 build
|
|
|
++Capabilities are added at the "level" granularity, detailed below.
|
|
|
++
|
|
|
++#### Level 1 : Minimal LZ4 build
|
|
|
+
|
|
|
+ The minimum required is **`lz4.c`** and **`lz4.h`**,
|
|
|
+ which provides the fast compression and decompression algorithms.
|
|
|
+ They generate and decode data using the [LZ4 block format].
|
|
|
+
|
|
|
+
|
|
|
+-#### High Compression variant
|
|
|
++#### Level 2 : High Compression variant
|
|
|
+
|
|
|
+ For more compression ratio at the cost of compression speed,
|
|
|
+ the High Compression variant called **lz4hc** is available.
|
|
|
+ Add files **`lz4hc.c`** and **`lz4hc.h`**.
|
|
|
+ This variant also compresses data using the [LZ4 block format],
|
|
|
+ and depends on regular `lib/lz4.*` source files.
|
|
|
+
|
|
|
+
|
|
|
+-#### Frame support, for interoperability
|
|
|
++#### Level 3 : Frame support, for interoperability
|
|
|
+
|
|
|
+ In order to produce compressed data compatible with `lz4` command line utility,
|
|
|
+ it's necessary to use the [official interoperable frame format].
|
|
|
+ This format is generated and decoded automatically by the **lz4frame** library.
|
|
|
+ Its public API is described in `lib/lz4frame.h`.
|
|
|
+ In order to work properly, lz4frame needs all other modules present in `/lib`,
|
|
|
+ including, lz4 and lz4hc, and also **xxhash**.
|
|
|
+-So it's necessary to include all `*.c` and `*.h` files present in `/lib`.
|
|
|
++So it's necessary to also include `xxhash.c` and `xxhash.h`.
|
|
|
++
|
|
|
++
|
|
|
++#### Level 4 : File compression operations
|
|
|
++
|
|
|
++As a helper around file operations,
|
|
|
++the library has been recently extended with `lz4file.c` and `lz4file.h`
|
|
|
++(still considered experimental at the time of this writing).
|
|
|
++These helpers allow opening, reading, writing, and closing files
|
|
|
++using transparent LZ4 compression / decompression.
|
|
|
++As a consequence, using `lz4file` adds a dependency on `<stdio.h>`.
|
|
|
++
|
|
|
++`lz4file` relies on `lz4frame` in order to produce compressed data
|
|
|
++conformant to the [LZ4 Frame format] specification.
|
|
|
++Consequently, to enable this capability,
|
|
|
++it's necessary to include all `*.c` and `*.h` files from `lib/` directory.
|
|
|
+
|
|
|
+
|
|
|
+ #### Advanced / Experimental API
|
|
|
+
|
|
|
+ Definitions which are not guaranteed to remain stable in future versions,
|
|
|
+ are protected behind macros, such as `LZ4_STATIC_LINKING_ONLY`.
|
|
|
+-As the name strongly implies, these definitions should only be invoked
|
|
|
++As the name suggests, these definitions should only be invoked
|
|
|
+ in the context of static linking ***only***.
|
|
|
+ Otherwise, dependent application may fail on API or ABI break in the future.
|
|
|
+ The associated symbols are also not exposed by the dynamic library by default.
|
|
|
+ Should they be nonetheless needed, it's possible to force their publication
|
|
|
+ by using build macros `LZ4_PUBLISH_STATIC_FUNCTIONS`
|
|
|
+ and `LZ4F_PUBLISH_STATIC_FUNCTIONS`.
|
|
|
+
|
|
|
+
|
|
|
+@@ -53,60 +72,72 @@ The following build macro can be selecte
|
|
|
+ It's also possible to enable or disable it manually, by passing `LZ4_FAST_DEC_LOOP=1` or `0` to the preprocessor.
|
|
|
+ For example, with `gcc` : `-DLZ4_FAST_DEC_LOOP=1`,
|
|
|
+ and with `make` : `CPPFLAGS+=-DLZ4_FAST_DEC_LOOP=1 make lz4`.
|
|
|
+
|
|
|
+ - `LZ4_DISTANCE_MAX` : control the maximum offset that the compressor will allow.
|
|
|
+ Set to 65535 by default, which is the maximum value supported by lz4 format.
|
|
|
+ Reducing maximum distance will reduce opportunities for LZ4 to find matches,
|
|
|
+ hence will produce a worse compression ratio.
|
|
|
+- However, a smaller max distance can allow compatibility with specific decoders using limited memory budget.
|
|
|
++ Setting a smaller max distance could allow compatibility with specific decoders with limited memory budget.
|
|
|
+ This build macro only influences the compressed output of the compressor.
|
|
|
+
|
|
|
+ - `LZ4_DISABLE_DEPRECATE_WARNINGS` : invoking a deprecated function will make the compiler generate a warning.
|
|
|
+ This is meant to invite users to update their source code.
|
|
|
+ Should this be a problem, it's generally possible to make the compiler ignore these warnings,
|
|
|
+ for example with `-Wno-deprecated-declarations` on `gcc`,
|
|
|
+ or `_CRT_SECURE_NO_WARNINGS` for Visual Studio.
|
|
|
+ This build macro offers another project-specific method
|
|
|
+ by defining `LZ4_DISABLE_DEPRECATE_WARNINGS` before including the LZ4 header files.
|
|
|
+
|
|
|
+-- `LZ4_USER_MEMORY_FUNCTIONS` : replace calls to <stdlib>'s `malloc`, `calloc` and `free`
|
|
|
+- by user-defined functions, which must be called `LZ4_malloc()`, `LZ4_calloc()` and `LZ4_free()`.
|
|
|
+- User functions must be available at link time.
|
|
|
+-
|
|
|
+ - `LZ4_FORCE_SW_BITCOUNT` : by default, the compression algorithm tries to determine lengths
|
|
|
+ by using bitcount instructions, generally implemented as fast single instructions in many cpus.
|
|
|
+ In case the target cpus doesn't support it, or compiler intrinsic doesn't work, or feature bad performance,
|
|
|
+ it's possible to use an optimized software path instead.
|
|
|
+- This is achieved by setting this build macros .
|
|
|
++ This is achieved by setting this build macros.
|
|
|
+ In most cases, it's not expected to be necessary,
|
|
|
+ but it can be legitimately considered for less common platforms.
|
|
|
+
|
|
|
+ - `LZ4_ALIGN_TEST` : alignment test ensures that the memory area
|
|
|
+ passed as argument to become a compression state is suitably aligned.
|
|
|
+ This test can be disabled if it proves flaky, by setting this value to 0.
|
|
|
+
|
|
|
++- `LZ4_USER_MEMORY_FUNCTIONS` : replace calls to `<stdlib,h>`'s `malloc()`, `calloc()` and `free()`
|
|
|
++ by user-defined functions, which must be named `LZ4_malloc()`, `LZ4_calloc()` and `LZ4_free()`.
|
|
|
++ User functions must be available at link time.
|
|
|
++
|
|
|
++- `LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION` :
|
|
|
++ Remove support of dynamic memory allocation.
|
|
|
++ For more details, see description of this macro in `lib/lz4.c`.
|
|
|
++
|
|
|
++- `LZ4_FREESTANDING` : by setting this build macro to 1,
|
|
|
++ LZ4/HC removes dependencies on the C standard library,
|
|
|
++ including allocation functions and `memmove()`, `memcpy()`, and `memset()`.
|
|
|
++ This build macro is designed to help use LZ4/HC in restricted environments
|
|
|
++ (embedded, bootloader, etc).
|
|
|
++ For more details, see description of this macro in `lib/lz4.h`.
|
|
|
++
|
|
|
++
|
|
|
+
|
|
|
+ #### Amalgamation
|
|
|
+
|
|
|
+ lz4 source code can be amalgamated into a single file.
|
|
|
+ One can combine all source code into `lz4_all.c` by using following command:
|
|
|
+ ```
|
|
|
+ cat lz4.c lz4hc.c lz4frame.c > lz4_all.c
|
|
|
+ ```
|
|
|
+ (`cat` file order is important) then compile `lz4_all.c`.
|
|
|
+ All `*.h` files present in `/lib` remain necessary to compile `lz4_all.c`.
|
|
|
+
|
|
|
+
|
|
|
+ #### Windows : using MinGW+MSYS to create DLL
|
|
|
+
|
|
|
+ DLL can be created using MinGW+MSYS with the `make liblz4` command.
|
|
|
+ This command creates `dll\liblz4.dll` and the import library `dll\liblz4.lib`.
|
|
|
+-To override the `dlltool` command when cross-compiling on Linux, just set the `DLLTOOL` variable. Example of cross compilation on Linux with mingw-w64 64 bits:
|
|
|
++To override the `dlltool` command when cross-compiling on Linux, just set the `DLLTOOL` variable. Example of cross compilation on Linux with mingw-w64 64 bits:
|
|
|
+ ```
|
|
|
+ make BUILD_STATIC=no CC=x86_64-w64-mingw32-gcc DLLTOOL=x86_64-w64-mingw32-dlltool OS=Windows_NT
|
|
|
+ ```
|
|
|
+ The import library is only required with Visual C++.
|
|
|
+ The header files `lz4.h`, `lz4hc.h`, `lz4frame.h` and the dynamic library
|
|
|
+ `dll\liblz4.dll` are required to compile a project using gcc/MinGW.
|
|
|
+ The dynamic library has to be added to linking options.
|
|
|
+ It means that if a project that uses LZ4 consists of a single `test-dll.c`
|
|
|
+@@ -122,16 +153,17 @@ The compiled executable will require LZ4
|
|
|
+ Other files present in the directory are not source code. They are :
|
|
|
+
|
|
|
+ - `LICENSE` : contains the BSD license text
|
|
|
+ - `Makefile` : `make` script to compile and install lz4 library (static and dynamic)
|
|
|
+ - `liblz4.pc.in` : for `pkg-config` (used in `make install`)
|
|
|
+ - `README.md` : this file
|
|
|
+
|
|
|
+ [official interoperable frame format]: ../doc/lz4_Frame_format.md
|
|
|
++[LZ4 Frame format]: ../doc/lz4_Frame_format.md
|
|
|
+ [LZ4 block format]: ../doc/lz4_Block_format.md
|
|
|
+
|
|
|
+
|
|
|
+ #### License
|
|
|
+
|
|
|
+ All source material within __lib__ directory are BSD 2-Clause licensed.
|
|
|
+ See [LICENSE](LICENSE) for details.
|
|
|
+ The license is also reminded at the top of each source file.
|
|
|
+diff --git a/mfbt/lz4/README.mozilla b/mfbt/lz4/README.mozilla
|
|
|
+new file mode 100644
|
|
|
+--- /dev/null
|
|
|
++++ b/mfbt/lz4/README.mozilla
|
|
|
+@@ -0,0 +1,18 @@
|
|
|
++This directory contains the LZ4 source from the upstream repo:
|
|
|
++https://github.com/lz4/lz4/
|
|
|
++
|
|
|
++Current version: 1.9.4 [5ff839680134437dbf4678f3d0c7b371d84f4964]
|
|
|
++
|
|
|
++Our in-tree copy of LZ4 does not depend on any generated files from the
|
|
|
++upstream build system, only the lz4*.{c,h} files found in the lib
|
|
|
++sub-directory. Therefore, it should be sufficient to simply overwrite
|
|
|
++the in-tree files with the updated ones from upstream.
|
|
|
++
|
|
|
++If the collection of source files changes, manual updates to moz.build may be
|
|
|
++needed as we don't use the upstream makefiles.
|
|
|
++
|
|
|
++Note that we do NOT use the copy of xxhash.{c,h} from the LZ4 repo. We
|
|
|
++instead use the newer release from that project's upstream repo:
|
|
|
++https://github.com/Cyan4973/xxHash
|
|
|
++
|
|
|
++Current version: 0.8.1 [35b0373c697b5f160d3db26b1cbb45a0d5ba788c]
|
|
|
+diff --git a/mfbt/lz4/lz4.c b/mfbt/lz4/lz4.c
|
|
|
+--- a/mfbt/lz4/lz4.c
|
|
|
++++ b/mfbt/lz4/lz4.c
|
|
|
+@@ -1,11 +1,11 @@
|
|
|
+ /*
|
|
|
+ LZ4 - Fast LZ compression algorithm
|
|
|
+- Copyright (C) 2011-present, 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
|
|
|
+ modification, are permitted provided that the following conditions are
|
|
|
+ met:
|
|
|
+
|
|
|
+ * Redistributions of source code must retain the above copyright
|
|
|
+@@ -119,16 +119,17 @@
|
|
|
+
|
|
|
+
|
|
|
+ /*-************************************
|
|
|
+ * 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__
|
|
|
+@@ -182,35 +183,60 @@
|
|
|
+ #ifndef LZ4_ALIGN_TEST /* can be externally provided */
|
|
|
+ # define LZ4_ALIGN_TEST 1
|
|
|
+ #endif
|
|
|
+
|
|
|
+
|
|
|
+ /*-************************************
|
|
|
+ * Memory routines
|
|
|
+ **************************************/
|
|
|
+-#ifdef LZ4_USER_MEMORY_FUNCTIONS
|
|
|
++
|
|
|
++/*! 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
|
|
|
+
|
|
|
+-#include <string.h> /* memset, memcpy */
|
|
|
+-#define MEM_INIT(p,v,s) memset((p),(v),(s))
|
|
|
++#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
|
|
|
+@@ -311,20 +337,30 @@ typedef enum {
|
|
|
+ /**
|
|
|
+ * 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(__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)
|
|
|
++#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];
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -338,24 +374,24 @@ static reg_t LZ4_read_ARCH(const void* m
|
|
|
+
|
|
|
+ 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;
|
|
|
++typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) LZ4_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 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) { ((unalign*)memPtr)->u16 = value; }
|
|
|
+-static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
|
|
|
++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;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -416,20 +452,22 @@ void LZ4_wildCopy8(void* dstPtr, const v
|
|
|
+
|
|
|
+ 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 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 */
|
|
|
++ /* 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
|
|
|
+
|
|
|
+@@ -481,17 +519,24 @@ LZ4_memcpy_using_offset(BYTE* dstPtr, co
|
|
|
+
|
|
|
+ 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;
|
|
|
+@@ -510,19 +555,30 @@ LZ4_memcpy_using_offset(BYTE* dstPtr, co
|
|
|
+ /*-************************************
|
|
|
+ * 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(LZ4_FORCE_SW_BITCOUNT)
|
|
|
++# 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;
|
|
|
+@@ -647,52 +703,54 @@ typedef enum { clearedTable = 0, byPtr,
|
|
|
+ * - 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
|
|
|
++ * - 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 LZ4_STREAMSIZE; }
|
|
|
++int LZ4_sizeofState(void) { return sizeof(LZ4_stream_t); }
|
|
|
+
|
|
|
+
|
|
|
+-/*-************************************
|
|
|
+-* Internal Definitions used in Tests
|
|
|
+-**************************************/
|
|
|
++/*-****************************************
|
|
|
++* 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)
|
|
|
+@@ -822,19 +880,20 @@ LZ4_prepareTable(LZ4_stream_t_internal*
|
|
|
+ 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.
|
|
|
++ /* 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;
|
|
|
+@@ -848,17 +907,17 @@ LZ4_prepareTable(LZ4_stream_t_internal*
|
|
|
+ * - 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 */
|
|
|
++ 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;
|
|
|
+@@ -880,17 +939,18 @@ LZ4_FORCE_INLINE int LZ4_compress_generi
|
|
|
+ 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 : (dictDirective == usingDictCtx) ?
|
|
|
++ 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;
|
|
|
+@@ -976,20 +1036,21 @@ LZ4_FORCE_INLINE int LZ4_compress_generi
|
|
|
+ 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) {
|
|
|
++ } 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;
|
|
|
+@@ -1043,17 +1104,17 @@ LZ4_FORCE_INLINE int LZ4_compress_generi
|
|
|
+ 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
|
|
|
++ * - 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 */
|
|
|
+@@ -1168,16 +1229,17 @@ LZ4_FORCE_INLINE int LZ4_compress_generi
|
|
|
+ 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;
|
|
|
+@@ -1350,17 +1412,17 @@ int LZ4_compress_fast_extState_fastReset
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ 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 */
|
|
|
++ 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)
|
|
|
+@@ -1415,25 +1477,27 @@ int LZ4_compress_destSize(const char* sr
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /*-******************************
|
|
|
+ * 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(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */
|
|
|
++ 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 */
|
|
|
+@@ -1457,23 +1521,25 @@ void LZ4_resetStream (LZ4_stream_t* LZ4_
|
|
|
+ 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;
|
|
|
+@@ -1509,18 +1575,19 @@ int LZ4_loadDict (LZ4_stream_t* LZ4_dict
|
|
|
+ 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 :
|
|
|
++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
|
|
|
+@@ -1563,46 +1630,50 @@ static void LZ4_renormDictT(LZ4_stream_t
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
++ 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)", inputSize);
|
|
|
++ DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i, dictSize=%u)", inputSize, streamPtr->dictSize);
|
|
|
+
|
|
|
+- LZ4_renormDictT(streamPtr, inputSize); /* avoid index overflow */
|
|
|
++ 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-1 < 4-1) /* intentional underflow */
|
|
|
+- && (dictEnd != (const BYTE*)source) ) {
|
|
|
++ 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 = (const BYTE*)source;
|
|
|
++ dictEnd = source;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Check overlapping input/dictionary space */
|
|
|
+- { const BYTE* sourceEnd = (const BYTE*) source + inputSize;
|
|
|
+- if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) {
|
|
|
++ { 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 = dictEnd - streamPtr->dictSize;
|
|
|
++ streamPtr->dictionary = (const BYTE*)dictEnd - streamPtr->dictSize;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* prefix mode : source data follows dictionary */
|
|
|
+- if (dictEnd == (const BYTE*)source) {
|
|
|
++ 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;
|
|
|
+@@ -1618,17 +1689,17 @@ int LZ4_compress_fast_continue (LZ4_stre
|
|
|
+ * 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 {
|
|
|
++ } 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;
|
|
|
+@@ -1656,77 +1727,205 @@ int LZ4_compress_forceExtDict (LZ4_strea
|
|
|
+
|
|
|
+ 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.
|
|
|
++ * 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;
|
|
|
+- const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize;
|
|
|
++
|
|
|
++ 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)
|
|
|
+- memmove(safeBuffer, previousDictEnd - dictSize, dictSize);
|
|
|
++ 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 { 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) )
|
|
|
+
|
|
|
++
|
|
|
++/* 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 - 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)
|
|
|
++ * @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)
|
|
|
+ {
|
|
|
+- U32 length = 0;
|
|
|
+- U32 s;
|
|
|
+- if (initial_check && unlikely((*ip) >= lencheck)) { /* overflow detection */
|
|
|
+- *error = initial_error;
|
|
|
+- return length;
|
|
|
++ 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 (loop_check && unlikely((*ip) >= lencheck)) { /* overflow detection */
|
|
|
+- *error = loop_error;
|
|
|
+- return length;
|
|
|
++ 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.
|
|
|
+@@ -1736,167 +1935,153 @@ read_variable_length(const BYTE**ip, con
|
|
|
+ */
|
|
|
+ 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; }
|
|
|
++ 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 safeDecode = (endOnInput==endOnInputSize);
|
|
|
+- const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
|
|
|
++ const int checkOffset = (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* 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 ((endOnInput) && (unlikely(outputSize==0))) {
|
|
|
++ if (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; }
|
|
|
++ if (unlikely(srcSize==0)) { return -1; }
|
|
|
+
|
|
|
+- /* Currently the fast loop shows a regression on qualcomm arm chips. */
|
|
|
++ /* 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 < iend-FASTLOOP_SAFE_DISTANCE */
|
|
|
++ /* 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);
|
|
|
+- if (endOnInput) { assert(ip < iend); }
|
|
|
++ 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, (int)endOnInput, (int)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 */
|
|
|
++ 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 (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 */
|
|
|
+- }
|
|
|
++ 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;
|
|
|
+- 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 */
|
|
|
+- LZ4_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 */
|
|
|
+- LZ4_memcpy(op, ip, 8);
|
|
|
+- if (length > 8) { LZ4_memcpy(op+8, ip+8, 8); }
|
|
|
+- }
|
|
|
++ 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);
|
|
|
++ assert(match <= op); /* overflow check */
|
|
|
+
|
|
|
+ /* get matchlength */
|
|
|
+ length = token & ML_MASK;
|
|
|
+
|
|
|
+ if (length == ML_MASK) {
|
|
|
+- variable_length_error error = ok;
|
|
|
++ 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 */
|
|
|
+- length += read_variable_length(&ip, iend - LASTLITERALS + 1, (int)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 */
|
|
|
++ /* 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 */
|
|
|
+- memmove(op, dictEnd - (lowPrefix-match), length);
|
|
|
++ 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 */
|
|
|
+@@ -1922,35 +2107,34 @@ LZ4_decompress_generic(
|
|
|
+
|
|
|
+ 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 */
|
|
|
+
|
|
|
+- 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)
|
|
|
++ if ( (length != RUN_MASK)
|
|
|
+ /* strictly "less than" on input, to re-enter the loop with at least one byte */
|
|
|
+- && likely((endOnInput ? ip < shortiend : 1) & (op <= shortoend)) ) {
|
|
|
++ && likely((ip < shortiend) & (op <= shortoend)) ) {
|
|
|
+ /* Copy the literals */
|
|
|
+- LZ4_memcpy(op, ip, endOnInput ? 16 : 8);
|
|
|
++ 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 */
|
|
|
+@@ -1970,42 +2154,39 @@ LZ4_decompress_generic(
|
|
|
+
|
|
|
+ /* 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, (int)endOnInput, (int)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 */
|
|
|
++ 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 ( ((endOnInput) && ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) )
|
|
|
+- || ((!endOnInput) && (cpy>oend-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.
|
|
|
+ */
|
|
|
+- assert(endOnInput);
|
|
|
+ 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) {
|
|
|
+@@ -2016,76 +2197,73 @@ LZ4_decompress_generic(
|
|
|
+ * 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 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))) {
|
|
|
++ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+- memmove(op, ip, length); /* supports overlapping memory regions; only matters for in-place decompression scenarios */
|
|
|
++ 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); /* may overwrite up to WILDCOPYLENGTH beyond cpy */
|
|
|
++ 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) {
|
|
|
+- variable_length_error error = ok;
|
|
|
+- length += read_variable_length(&ip, iend - LASTLITERALS + 1, (int)endOnInput, 0, &error);
|
|
|
+- if (error != ok) goto _output_error;
|
|
|
+- if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */
|
|
|
++ 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 */
|
|
|
+- memmove(op, dictEnd - (lowPrefix-match), length);
|
|
|
++ 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 */
|
|
|
+@@ -2146,152 +2324,176 @@ LZ4_decompress_generic(
|
|
|
+ } else {
|
|
|
+ LZ4_memcpy(op, match, 8);
|
|
|
+ if (length > 16) { LZ4_wildCopy8(op+8, match+8, cpy); }
|
|
|
+ }
|
|
|
+ op = cpy; /* wildcopy correction */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* end of decoding */
|
|
|
+- if (endOnInput) {
|
|
|
+- DEBUGLOG(5, "decoded %i bytes", (int) (((char*)op)-dst));
|
|
|
+- return (int) (((char*)op)-dst); /* Nb of output bytes decoded */
|
|
|
+- } else {
|
|
|
+- return (int) (((const char*)ip)-src); /* Nb of input bytes read */
|
|
|
+- }
|
|
|
++ 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,
|
|
|
+- endOnInputSize, decode_full_block, noDict,
|
|
|
++ 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,
|
|
|
+- endOnInputSize, partial_decode,
|
|
|
++ partial_decode,
|
|
|
+ noDict, (BYTE*)dst, NULL, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ LZ4_FORCE_O2
|
|
|
+ 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);
|
|
|
++ 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,
|
|
|
+- endOnInputSize, decode_full_block, withPrefix64k,
|
|
|
++ 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)
|
|
|
+ {
|
|
|
+- /* LZ4_decompress_fast doesn't validate match offsets,
|
|
|
+- * and thus serves well with any prefixed dictionary. */
|
|
|
+- return LZ4_decompress_fast(source, dest, 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,
|
|
|
+- endOnInputSize, decode_full_block, noDict,
|
|
|
++ 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,
|
|
|
+- endOnInputSize, decode_full_block, usingExtDict,
|
|
|
++ 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_generic(source, dest, 0, originalSize,
|
|
|
+- endOnOutputSize, decode_full_block, usingExtDict,
|
|
|
+- (BYTE*)dest, (const BYTE*)dictStart, 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,
|
|
|
+- 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,
|
|
|
++ 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_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;
|
|
|
++ 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;
|
|
|
+- lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;
|
|
|
++ 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
|
|
|
+@@ -2353,39 +2555,45 @@ int LZ4_decompress_safe_continue (LZ4_st
|
|
|
+ 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_FORCE_O2 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;
|
|
|
++ 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) {
|
|
|
+- 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);
|
|
|
++ 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;
|
|
|
+ }
|
|
|
+@@ -2411,20 +2619,37 @@ int LZ4_decompress_safe_usingDict(const
|
|
|
+ }
|
|
|
+ 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_fast(source, dest, originalSize);
|
|
|
++ 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
|
|
|
+ ***************************************************/
|
|
|
+@@ -2466,30 +2691,32 @@ int LZ4_uncompress (const char* source,
|
|
|
+ }
|
|
|
+ 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 LZ4_STREAMSIZE; }
|
|
|
++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)
|
|
|
+ {
|
|
|
+ /* avoid const char * -> char * conversion warning */
|
|
|
+ return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary;
|
|
|
+ }
|
|
|
+
|
|
|
+ #endif /* LZ4_COMMONDEFS_ONLY */
|
|
|
+diff --git a/mfbt/lz4/lz4.h b/mfbt/lz4/lz4.h
|
|
|
+--- a/mfbt/lz4/lz4.h
|
|
|
++++ b/mfbt/lz4/lz4.h
|
|
|
+@@ -1,12 +1,12 @@
|
|
|
+ /*
|
|
|
+ * 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)
|
|
|
+
|
|
|
+ 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
|
|
|
+@@ -92,46 +92,87 @@ extern "C" {
|
|
|
+ #if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)
|
|
|
+ # define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY
|
|
|
+ #elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)
|
|
|
+ # define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
|
|
|
+ #else
|
|
|
+ # 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 3 /* 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
|
|
|
+ **************************************/
|
|
|
+ /*! LZ4_compress_default() :
|
|
|
+ * Compresses 'srcSize' bytes from buffer 'src'
|
|
|
+ * into already allocated 'dst' buffer of size 'dstCapacity'.
|
|
|
+ * Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize).
|
|
|
+@@ -265,18 +306,35 @@ LZ4LIB_API int LZ4_compress_destSize (co
|
|
|
+ LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity);
|
|
|
+
|
|
|
+
|
|
|
+ /*-*********************************************
|
|
|
+ * Streaming Compression Functions
|
|
|
+ ***********************************************/
|
|
|
+ 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
|
|
|
+ * (e.g., LZ4_compress_fast_continue()).
|
|
|
+ *
|
|
|
+ * An LZ4_stream_t must be initialized once before usage.
|
|
|
+ * This is automatically done when created by LZ4_createStream().
|
|
|
+ * However, should the LZ4_stream_t be simply declared on stack (for example),
|
|
|
+@@ -350,18 +408,22 @@ LZ4LIB_API int LZ4_saveDict (LZ4_stream_
|
|
|
+ * Bufferless synchronous API
|
|
|
+ ************************************************/
|
|
|
+ typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* tracking context */
|
|
|
+
|
|
|
+ /*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() :
|
|
|
+ * 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.
|
|
|
+ * Use this function to start decompression of a new stream of blocks.
|
|
|
+ * A dictionary can optionally be set. Use NULL or size 0 for a reset order.
|
|
|
+ * Dictionary is presumed stable : it must remain accessible and unmodified during next decompression.
|
|
|
+ * @return : 1 if OK, 0 if error
|
|
|
+ */
|
|
|
+@@ -401,28 +463,40 @@ LZ4LIB_API int LZ4_decoderRingBufferSize
|
|
|
+ * - Decompression buffer is larger than encoding buffer, by a minimum of maxBlockSize more bytes.
|
|
|
+ * In which case, encoding and decoding buffers do not need to be synchronized,
|
|
|
+ * and encoding ring buffer can have any size, including small ones ( < 64 KB).
|
|
|
+ *
|
|
|
+ * Whenever these conditions are not possible,
|
|
|
+ * 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() :
|
|
|
+ * These decoding functions work the same as
|
|
|
+ * a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue()
|
|
|
+ * They are stand-alone, and don't need an LZ4_streamDecode_t structure.
|
|
|
+ * Dictionary is presumed stable : it must remain accessible and unmodified during decompression.
|
|
|
+ * 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 */
|
|
|
+
|
|
|
+
|
|
|
+ /*^*************************************
|
|
|
+ * !!!!!! STATIC LINKING ONLY !!!!!!
|
|
|
+ ***************************************/
|
|
|
+
|
|
|
+@@ -491,23 +565,25 @@ LZ4LIB_STATIC_API int LZ4_compress_fast_
|
|
|
+ * logically immediately precede the data compressed in the first subsequent
|
|
|
+ * compression call.
|
|
|
+ *
|
|
|
+ * The dictionary will only remain attached to the working stream through the
|
|
|
+ * first compression call, at the end of which it is cleared. The dictionary
|
|
|
+ * stream (and source buffer) must remain in-place / accessible / unchanged
|
|
|
+ * through the completion of the first compression call on the stream.
|
|
|
+ */
|
|
|
+-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.
|
|
|
+ *
|
|
|
+ * |<------------------------buffer--------------------------------->|
|
|
|
+ * |<-----------compressed data--------->|
|
|
|
+ * |<-----------decompressed size------------------>|
|
|
|
+ * |<----margin---->|
|
|
|
+@@ -587,48 +663,36 @@ LZ4LIB_STATIC_API void LZ4_attach_dictio
|
|
|
+ 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 {
|
|
|
+ LZ4_u32 hashTable[LZ4_HASH_SIZE_U32];
|
|
|
++ const LZ4_byte* dictionary;
|
|
|
++ const LZ4_stream_t_internal* dictCtx;
|
|
|
+ LZ4_u32 currentOffset;
|
|
|
+ LZ4_u32 tableType;
|
|
|
+- const LZ4_byte* dictionary;
|
|
|
+- const LZ4_stream_t_internal* dictCtx;
|
|
|
+ LZ4_u32 dictSize;
|
|
|
++ /* Implicit padding to ensure structure is aligned */
|
|
|
+ };
|
|
|
+
|
|
|
+-typedef struct {
|
|
|
+- const LZ4_byte* externalDict;
|
|
|
+- size_t extDictSize;
|
|
|
+- const LZ4_byte* prefixEnd;
|
|
|
+- size_t prefixSize;
|
|
|
+-} LZ4_streamDecode_t_internal;
|
|
|
+-
|
|
|
+-
|
|
|
+-/*! LZ4_stream_t :
|
|
|
+- * Do not use below internal definitions directly !
|
|
|
+- * Declare or allocate an LZ4_stream_t instead.
|
|
|
+- * 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 future versions.
|
|
|
+- */
|
|
|
+-#define LZ4_STREAMSIZE 16416 /* static size, for inter-version compatibility */
|
|
|
+-#define LZ4_STREAMSIZE_VOIDP (LZ4_STREAMSIZE / sizeof(void*))
|
|
|
++#define LZ4_STREAM_MINSIZE ((1UL << LZ4_MEMORY_USAGE) + 32) /* static size, for inter-version compatibility */
|
|
|
+ union LZ4_stream_u {
|
|
|
+- void* table[LZ4_STREAMSIZE_VOIDP];
|
|
|
++ char minStateSize[LZ4_STREAM_MINSIZE];
|
|
|
+ LZ4_stream_t_internal internal_donotuse;
|
|
|
+ }; /* 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(),
|
|
|
+ * but it's not when the structure is simply declared on stack (for example).
|
|
|
+@@ -636,31 +700,35 @@ union LZ4_stream_u {
|
|
|
+ * Use LZ4_initStream() to properly initialize a newly declared LZ4_stream_t.
|
|
|
+ * It can also initialize any arbitrary buffer of sufficient size,
|
|
|
+ * and will @return a pointer of proper type upon initialization.
|
|
|
+ *
|
|
|
+ * Note : initialization fails if size and alignment conditions are not respected.
|
|
|
+ * 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 */
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /*-************************************
|
|
|
+ * Obsolete Functions
|
|
|
+ **************************************/
|
|
|
+diff --git a/mfbt/lz4/lz4file.c b/mfbt/lz4/lz4file.c
|
|
|
+new file mode 100644
|
|
|
+--- /dev/null
|
|
|
++++ b/mfbt/lz4/lz4file.c
|
|
|
+@@ -0,0 +1,311 @@
|
|
|
++/*
|
|
|
++ * LZ4 file library
|
|
|
++ * Copyright (C) 2022, Xiaomi Inc.
|
|
|
++ *
|
|
|
++ * 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
|
|
|
++ */
|
|
|
++#include <stdlib.h>
|
|
|
++#include <string.h>
|
|
|
++#include "lz4.h"
|
|
|
++#include "lz4file.h"
|
|
|
++
|
|
|
++struct LZ4_readFile_s {
|
|
|
++ LZ4F_dctx* dctxPtr;
|
|
|
++ FILE* fp;
|
|
|
++ LZ4_byte* srcBuf;
|
|
|
++ size_t srcBufNext;
|
|
|
++ size_t srcBufSize;
|
|
|
++ size_t srcBufMaxSize;
|
|
|
++};
|
|
|
++
|
|
|
++struct LZ4_writeFile_s {
|
|
|
++ LZ4F_cctx* cctxPtr;
|
|
|
++ FILE* fp;
|
|
|
++ LZ4_byte* dstBuf;
|
|
|
++ size_t maxWriteSize;
|
|
|
++ size_t dstBufMaxSize;
|
|
|
++ LZ4F_errorCode_t errCode;
|
|
|
++};
|
|
|
++
|
|
|
++LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp)
|
|
|
++{
|
|
|
++ char buf[LZ4F_HEADER_SIZE_MAX];
|
|
|
++ size_t consumedSize;
|
|
|
++ LZ4F_errorCode_t ret;
|
|
|
++ LZ4F_frameInfo_t info;
|
|
|
++
|
|
|
++ if (fp == NULL || lz4fRead == NULL) {
|
|
|
++ return -LZ4F_ERROR_GENERIC;
|
|
|
++ }
|
|
|
++
|
|
|
++ *lz4fRead = (LZ4_readFile_t*)calloc(1, sizeof(LZ4_readFile_t));
|
|
|
++ if (*lz4fRead == NULL) {
|
|
|
++ return -LZ4F_ERROR_allocation_failed;
|
|
|
++ }
|
|
|
++
|
|
|
++ ret = LZ4F_createDecompressionContext(&(*lz4fRead)->dctxPtr, LZ4F_getVersion());
|
|
|
++ if (LZ4F_isError(ret)) {
|
|
|
++ free(*lz4fRead);
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++
|
|
|
++ (*lz4fRead)->fp = fp;
|
|
|
++ consumedSize = fread(buf, 1, sizeof(buf), (*lz4fRead)->fp);
|
|
|
++ if (consumedSize != sizeof(buf)) {
|
|
|
++ free(*lz4fRead);
|
|
|
++ return -LZ4F_ERROR_GENERIC;
|
|
|
++ }
|
|
|
++
|
|
|
++ ret = LZ4F_getFrameInfo((*lz4fRead)->dctxPtr, &info, buf, &consumedSize);
|
|
|
++ if (LZ4F_isError(ret)) {
|
|
|
++ LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);
|
|
|
++ free(*lz4fRead);
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++
|
|
|
++ switch (info.blockSizeID) {
|
|
|
++ case LZ4F_default :
|
|
|
++ case LZ4F_max64KB :
|
|
|
++ (*lz4fRead)->srcBufMaxSize = 64 * 1024;
|
|
|
++ break;
|
|
|
++ case LZ4F_max256KB:
|
|
|
++ (*lz4fRead)->srcBufMaxSize = 256 * 1024;
|
|
|
++ break;
|
|
|
++ case LZ4F_max1MB:
|
|
|
++ (*lz4fRead)->srcBufMaxSize = 1 * 1024 * 1024;
|
|
|
++ break;
|
|
|
++ case LZ4F_max4MB:
|
|
|
++ (*lz4fRead)->srcBufMaxSize = 4 * 1024 * 1024;
|
|
|
++ break;
|
|
|
++ default:
|
|
|
++ LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);
|
|
|
++ free(*lz4fRead);
|
|
|
++ return -LZ4F_ERROR_maxBlockSize_invalid;
|
|
|
++ }
|
|
|
++
|
|
|
++ (*lz4fRead)->srcBuf = (LZ4_byte*)malloc((*lz4fRead)->srcBufMaxSize);
|
|
|
++ if ((*lz4fRead)->srcBuf == NULL) {
|
|
|
++ LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);
|
|
|
++ free(lz4fRead);
|
|
|
++ return -LZ4F_ERROR_allocation_failed;
|
|
|
++ }
|
|
|
++
|
|
|
++ (*lz4fRead)->srcBufSize = sizeof(buf) - consumedSize;
|
|
|
++ memcpy((*lz4fRead)->srcBuf, buf + consumedSize, (*lz4fRead)->srcBufSize);
|
|
|
++
|
|
|
++ return ret;
|
|
|
++}
|
|
|
++
|
|
|
++size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size)
|
|
|
++{
|
|
|
++ LZ4_byte* p = (LZ4_byte*)buf;
|
|
|
++ size_t next = 0;
|
|
|
++
|
|
|
++ if (lz4fRead == NULL || buf == NULL)
|
|
|
++ return -LZ4F_ERROR_GENERIC;
|
|
|
++
|
|
|
++ while (next < size) {
|
|
|
++ size_t srcsize = lz4fRead->srcBufSize - lz4fRead->srcBufNext;
|
|
|
++ size_t dstsize = size - next;
|
|
|
++ size_t ret;
|
|
|
++
|
|
|
++ if (srcsize == 0) {
|
|
|
++ ret = fread(lz4fRead->srcBuf, 1, lz4fRead->srcBufMaxSize, lz4fRead->fp);
|
|
|
++ if (ret > 0) {
|
|
|
++ lz4fRead->srcBufSize = ret;
|
|
|
++ srcsize = lz4fRead->srcBufSize;
|
|
|
++ lz4fRead->srcBufNext = 0;
|
|
|
++ }
|
|
|
++ else if (ret == 0) {
|
|
|
++ break;
|
|
|
++ }
|
|
|
++ else {
|
|
|
++ return -LZ4F_ERROR_GENERIC;
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
++ ret = LZ4F_decompress(lz4fRead->dctxPtr,
|
|
|
++ p, &dstsize,
|
|
|
++ lz4fRead->srcBuf + lz4fRead->srcBufNext,
|
|
|
++ &srcsize,
|
|
|
++ NULL);
|
|
|
++ if (LZ4F_isError(ret)) {
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++
|
|
|
++ lz4fRead->srcBufNext += srcsize;
|
|
|
++ next += dstsize;
|
|
|
++ p += dstsize;
|
|
|
++ }
|
|
|
++
|
|
|
++ return next;
|
|
|
++}
|
|
|
++
|
|
|
++LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead)
|
|
|
++{
|
|
|
++ if (lz4fRead == NULL)
|
|
|
++ return -LZ4F_ERROR_GENERIC;
|
|
|
++ LZ4F_freeDecompressionContext(lz4fRead->dctxPtr);
|
|
|
++ free(lz4fRead->srcBuf);
|
|
|
++ free(lz4fRead);
|
|
|
++ return LZ4F_OK_NoError;
|
|
|
++}
|
|
|
++
|
|
|
++LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr)
|
|
|
++{
|
|
|
++ LZ4_byte buf[LZ4F_HEADER_SIZE_MAX];
|
|
|
++ size_t ret;
|
|
|
++
|
|
|
++ if (fp == NULL || lz4fWrite == NULL)
|
|
|
++ return -LZ4F_ERROR_GENERIC;
|
|
|
++
|
|
|
++ *lz4fWrite = (LZ4_writeFile_t*)malloc(sizeof(LZ4_writeFile_t));
|
|
|
++ if (*lz4fWrite == NULL) {
|
|
|
++ return -LZ4F_ERROR_allocation_failed;
|
|
|
++ }
|
|
|
++ if (prefsPtr != NULL) {
|
|
|
++ switch (prefsPtr->frameInfo.blockSizeID) {
|
|
|
++ case LZ4F_default :
|
|
|
++ case LZ4F_max64KB :
|
|
|
++ (*lz4fWrite)->maxWriteSize = 64 * 1024;
|
|
|
++ break;
|
|
|
++ case LZ4F_max256KB:
|
|
|
++ (*lz4fWrite)->maxWriteSize = 256 * 1024;
|
|
|
++ break;
|
|
|
++ case LZ4F_max1MB:
|
|
|
++ (*lz4fWrite)->maxWriteSize = 1 * 1024 * 1024;
|
|
|
++ break;
|
|
|
++ case LZ4F_max4MB:
|
|
|
++ (*lz4fWrite)->maxWriteSize = 4 * 1024 * 1024;
|
|
|
++ break;
|
|
|
++ default:
|
|
|
++ free(lz4fWrite);
|
|
|
++ return -LZ4F_ERROR_maxBlockSize_invalid;
|
|
|
++ }
|
|
|
++ } else {
|
|
|
++ (*lz4fWrite)->maxWriteSize = 64 * 1024;
|
|
|
++ }
|
|
|
++
|
|
|
++ (*lz4fWrite)->dstBufMaxSize = LZ4F_compressBound((*lz4fWrite)->maxWriteSize, prefsPtr);
|
|
|
++ (*lz4fWrite)->dstBuf = (LZ4_byte*)malloc((*lz4fWrite)->dstBufMaxSize);
|
|
|
++ if ((*lz4fWrite)->dstBuf == NULL) {
|
|
|
++ free(*lz4fWrite);
|
|
|
++ return -LZ4F_ERROR_allocation_failed;
|
|
|
++ }
|
|
|
++
|
|
|
++ ret = LZ4F_createCompressionContext(&(*lz4fWrite)->cctxPtr, LZ4F_getVersion());
|
|
|
++ if (LZ4F_isError(ret)) {
|
|
|
++ free((*lz4fWrite)->dstBuf);
|
|
|
++ free(*lz4fWrite);
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++
|
|
|
++ ret = LZ4F_compressBegin((*lz4fWrite)->cctxPtr, buf, LZ4F_HEADER_SIZE_MAX, prefsPtr);
|
|
|
++ if (LZ4F_isError(ret)) {
|
|
|
++ LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr);
|
|
|
++ free((*lz4fWrite)->dstBuf);
|
|
|
++ free(*lz4fWrite);
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++
|
|
|
++ if (ret != fwrite(buf, 1, ret, fp)) {
|
|
|
++ LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr);
|
|
|
++ free((*lz4fWrite)->dstBuf);
|
|
|
++ free(*lz4fWrite);
|
|
|
++ return -LZ4F_ERROR_GENERIC;
|
|
|
++ }
|
|
|
++
|
|
|
++ (*lz4fWrite)->fp = fp;
|
|
|
++ (*lz4fWrite)->errCode = LZ4F_OK_NoError;
|
|
|
++ return LZ4F_OK_NoError;
|
|
|
++}
|
|
|
++
|
|
|
++size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, void* buf, size_t size)
|
|
|
++{
|
|
|
++ LZ4_byte* p = (LZ4_byte*)buf;
|
|
|
++ size_t remain = size;
|
|
|
++ size_t chunk;
|
|
|
++ size_t ret;
|
|
|
++
|
|
|
++ if (lz4fWrite == NULL || buf == NULL)
|
|
|
++ return -LZ4F_ERROR_GENERIC;
|
|
|
++ while (remain) {
|
|
|
++ if (remain > lz4fWrite->maxWriteSize)
|
|
|
++ chunk = lz4fWrite->maxWriteSize;
|
|
|
++ else
|
|
|
++ chunk = remain;
|
|
|
++
|
|
|
++ ret = LZ4F_compressUpdate(lz4fWrite->cctxPtr,
|
|
|
++ lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
|
|
|
++ p, chunk,
|
|
|
++ NULL);
|
|
|
++ if (LZ4F_isError(ret)) {
|
|
|
++ lz4fWrite->errCode = ret;
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++
|
|
|
++ if(ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
|
|
|
++ lz4fWrite->errCode = -LZ4F_ERROR_GENERIC;
|
|
|
++ return -LZ4F_ERROR_GENERIC;
|
|
|
++ }
|
|
|
++
|
|
|
++ p += chunk;
|
|
|
++ remain -= chunk;
|
|
|
++ }
|
|
|
++
|
|
|
++ return size;
|
|
|
++}
|
|
|
++
|
|
|
++LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite)
|
|
|
++{
|
|
|
++ LZ4F_errorCode_t ret = LZ4F_OK_NoError;
|
|
|
++
|
|
|
++ if (lz4fWrite == NULL)
|
|
|
++ return -LZ4F_ERROR_GENERIC;
|
|
|
++
|
|
|
++ if (lz4fWrite->errCode == LZ4F_OK_NoError) {
|
|
|
++ ret = LZ4F_compressEnd(lz4fWrite->cctxPtr,
|
|
|
++ lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
|
|
|
++ NULL);
|
|
|
++ if (LZ4F_isError(ret)) {
|
|
|
++ goto out;
|
|
|
++ }
|
|
|
++
|
|
|
++ if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
|
|
|
++ ret = -LZ4F_ERROR_GENERIC;
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
++out:
|
|
|
++ LZ4F_freeCompressionContext(lz4fWrite->cctxPtr);
|
|
|
++ free(lz4fWrite->dstBuf);
|
|
|
++ free(lz4fWrite);
|
|
|
++ return ret;
|
|
|
++}
|
|
|
+diff --git a/mfbt/lz4/lz4file.h b/mfbt/lz4/lz4file.h
|
|
|
+new file mode 100644
|
|
|
+--- /dev/null
|
|
|
++++ b/mfbt/lz4/lz4file.h
|
|
|
+@@ -0,0 +1,93 @@
|
|
|
++/*
|
|
|
++ LZ4 file library
|
|
|
++ Header File
|
|
|
++ Copyright (C) 2022, Xiaomi Inc.
|
|
|
++ 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
|
|
|
++*/
|
|
|
++#if defined (__cplusplus)
|
|
|
++extern "C" {
|
|
|
++#endif
|
|
|
++
|
|
|
++#ifndef LZ4FILE_H
|
|
|
++#define LZ4FILE_H
|
|
|
++
|
|
|
++#include <stdio.h>
|
|
|
++#include "lz4frame_static.h"
|
|
|
++
|
|
|
++typedef struct LZ4_readFile_s LZ4_readFile_t;
|
|
|
++typedef struct LZ4_writeFile_s LZ4_writeFile_t;
|
|
|
++
|
|
|
++/*! LZ4F_readOpen() :
|
|
|
++ * Set read lz4file handle.
|
|
|
++ * `lz4f` will set a lz4file handle.
|
|
|
++ * `fp` must be the return value of the lz4 file opened by fopen.
|
|
|
++ */
|
|
|
++LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp);
|
|
|
++
|
|
|
++/*! LZ4F_read() :
|
|
|
++ * Read lz4file content to buffer.
|
|
|
++ * `lz4f` must use LZ4_readOpen to set first.
|
|
|
++ * `buf` read data buffer.
|
|
|
++ * `size` read data buffer size.
|
|
|
++ */
|
|
|
++LZ4FLIB_STATIC_API size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size);
|
|
|
++
|
|
|
++/*! LZ4F_readClose() :
|
|
|
++ * Close lz4file handle.
|
|
|
++ * `lz4f` must use LZ4_readOpen to set first.
|
|
|
++ */
|
|
|
++LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead);
|
|
|
++
|
|
|
++/*! LZ4F_writeOpen() :
|
|
|
++ * Set write lz4file handle.
|
|
|
++ * `lz4f` will set a lz4file handle.
|
|
|
++ * `fp` must be the return value of the lz4 file opened by fopen.
|
|
|
++ */
|
|
|
++LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr);
|
|
|
++
|
|
|
++/*! LZ4F_write() :
|
|
|
++ * Write buffer to lz4file.
|
|
|
++ * `lz4f` must use LZ4F_writeOpen to set first.
|
|
|
++ * `buf` write data buffer.
|
|
|
++ * `size` write data buffer size.
|
|
|
++ */
|
|
|
++LZ4FLIB_STATIC_API size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, void* buf, size_t size);
|
|
|
++
|
|
|
++/*! LZ4F_writeClose() :
|
|
|
++ * Close lz4file handle.
|
|
|
++ * `lz4f` must use LZ4F_writeOpen to set first.
|
|
|
++ */
|
|
|
++LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite);
|
|
|
++
|
|
|
++#endif /* LZ4FILE_H */
|
|
|
++
|
|
|
++#if defined (__cplusplus)
|
|
|
++}
|
|
|
++#endif
|
|
|
+diff --git a/mfbt/lz4/lz4frame.c b/mfbt/lz4/lz4frame.c
|
|
|
+--- a/mfbt/lz4/lz4frame.c
|
|
|
++++ b/mfbt/lz4/lz4frame.c
|
|
|
+@@ -40,17 +40,17 @@
|
|
|
+ * (see Memory Routines below).
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+ /*-************************************
|
|
|
+ * Compiler Options
|
|
|
+ **************************************/
|
|
|
+ #ifdef _MSC_VER /* Visual Studio */
|
|
|
+-# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
|
|
++# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
|
|
+ #endif
|
|
|
+
|
|
|
+
|
|
|
+ /*-************************************
|
|
|
+ * Tuning parameters
|
|
|
+ **************************************/
|
|
|
+ /*
|
|
|
+ * LZ4F_HEAPMODE :
|
|
|
+@@ -58,51 +58,89 @@
|
|
|
+ * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).
|
|
|
+ */
|
|
|
+ #ifndef LZ4F_HEAPMODE
|
|
|
+ # define LZ4F_HEAPMODE 0
|
|
|
+ #endif
|
|
|
+
|
|
|
+
|
|
|
+ /*-************************************
|
|
|
+-* Memory routines
|
|
|
+-**************************************/
|
|
|
+-/*
|
|
|
+- * User may redirect invocations of
|
|
|
+- * malloc(), calloc() and free()
|
|
|
+- * towards another library or solution of their choice
|
|
|
+- * by modifying below section.
|
|
|
+- */
|
|
|
+-#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
|
|
|
+-
|
|
|
+-#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
|
|
|
+-
|
|
|
+-
|
|
|
+-/*-************************************
|
|
|
+ * 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
|
|
|
+@@ -138,17 +176,17 @@ static int g_debuglog_enable = 1;
|
|
|
+ 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 endianess & alignment issues */
|
|
|
++/* 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;
|
|
|
+@@ -201,46 +239,49 @@ static void LZ4F_writeLE64 (void* dst, U
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #define _1BIT 0x01
|
|
|
+ #define _2BITS 0x03
|
|
|
+ #define _3BITS 0x07
|
|
|
+ #define _4BITS 0x0F
|
|
|
+ #define _8BITS 0xFF
|
|
|
+
|
|
|
+-#define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U
|
|
|
+-#define LZ4F_MAGICNUMBER 0x184D2204U
|
|
|
+ #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;
|
|
|
+- BYTE* tmpIn;
|
|
|
+- size_t tmpInSize;
|
|
|
++ 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) };
|
|
|
+@@ -259,37 +300,43 @@ const char* LZ4F_getErrorName(LZ4F_error
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 err0r(LZ4F_errorCodes code)
|
|
|
++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(unsigned blockSizeID)
|
|
|
++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 err0r(LZ4F_ERROR_maxBlockSize_invalid);
|
|
|
+- blockSizeID -= LZ4F_max64KB;
|
|
|
+- return blockSizes[blockSizeID];
|
|
|
+-}
|
|
|
++ 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)
|
|
|
+ {
|
|
|
+@@ -392,31 +439,30 @@ size_t LZ4F_compressFrame_usingCDict(LZ4
|
|
|
+ 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;
|
|
|
+
|
|
|
+- if (dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs)) /* condition to guarantee success */
|
|
|
+- return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
|
|
|
++ RETURN_ERROR_IF(dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs), dstMaxSize_tooSmall);
|
|
|
+
|
|
|
+ { size_t const headerSize = LZ4F_compressBegin_usingCDict(cctx, dstBuffer, dstCapacity, cdict, &prefs); /* write header */
|
|
|
+- if (LZ4F_isError(headerSize)) return headerSize;
|
|
|
++ 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);
|
|
|
+- if (LZ4F_isError(cSize)) return cSize;
|
|
|
++ 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 */
|
|
|
+- if (LZ4F_isError(tailSize)) return tailSize;
|
|
|
++ FORWARD_IF_ERROR(tailSize);
|
|
|
+ dstPtr += tailSize; }
|
|
|
+
|
|
|
+ assert(dstEnd >= dstStart);
|
|
|
+ return (size_t)(dstPtr - dstStart);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /*! LZ4F_compressFrame() :
|
|
|
+@@ -427,139 +473,162 @@ size_t LZ4F_compressFrame_usingCDict(LZ4
|
|
|
+ * 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;
|
|
|
++ LZ4F_cctx_t* cctxPtr;
|
|
|
+ result = LZ4F_createCompressionContext(&cctxPtr, LZ4F_VERSION);
|
|
|
+- if (LZ4F_isError(result)) return result;
|
|
|
++ FORWARD_IF_ERROR(result);
|
|
|
+ #else
|
|
|
+ LZ4F_cctx_t cctx;
|
|
|
+ LZ4_stream_t lz4ctx;
|
|
|
+- LZ4F_cctx_t *cctxPtr = &cctx;
|
|
|
++ LZ4F_cctx_t* const cctxPtr = &cctx;
|
|
|
+
|
|
|
+- DEBUGLOG(4, "LZ4F_compressFrame");
|
|
|
+ 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)
|
|
|
+- {
|
|
|
++ 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)
|
|
|
+- {
|
|
|
+- FREEMEM(cctxPtr->lz4CtxPtr);
|
|
|
++ 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_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)
|
|
|
++LZ4F_CDict*
|
|
|
++LZ4F_createCDict_advanced(LZ4F_CustomMem cmem, const void* dictBuffer, size_t dictSize)
|
|
|
+ {
|
|
|
+ const char* dictStart = (const char*)dictBuffer;
|
|
|
+- LZ4F_CDict* cdict = (LZ4F_CDict*) ALLOC(sizeof(*cdict));
|
|
|
+- DEBUGLOG(4, "LZ4F_createCDict");
|
|
|
++ 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 = ALLOC(dictSize);
|
|
|
+- cdict->fastCtx = LZ4_createStream();
|
|
|
+- cdict->HCCtx = LZ4_createStreamHC();
|
|
|
++ 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 */
|
|
|
+- FREEMEM(cdict->dictContent);
|
|
|
+- LZ4_freeStream(cdict->fastCtx);
|
|
|
+- LZ4_freeStreamHC(cdict->HCCtx);
|
|
|
+- FREEMEM(cdict);
|
|
|
++ 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)
|
|
|
++**/
|
|
|
++LZ4F_errorCode_t
|
|
|
++LZ4F_createCompressionContext(LZ4F_cctx** LZ4F_compressionContextPtr, unsigned version)
|
|
|
+ {
|
|
|
+- LZ4F_cctx_t* const cctxPtr = (LZ4F_cctx_t*)ALLOC_AND_ZERO(sizeof(LZ4F_cctx_t));
|
|
|
+- if (cctxPtr==NULL) return err0r(LZ4F_ERROR_allocation_failed);
|
|
|
++ 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);
|
|
|
+
|
|
|
+- cctxPtr->version = version;
|
|
|
+- cctxPtr->cStage = 0; /* Next stage : init stream */
|
|
|
+-
|
|
|
+- *LZ4F_compressionContextPtr = cctxPtr;
|
|
|
+-
|
|
|
++ *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 */
|
|
|
+- FREEMEM(cctxPtr->lz4CtxPtr); /* note: LZ4_streamHC_t and LZ4_stream_t are simple POD types */
|
|
|
+- FREEMEM(cctxPtr->tmpBuff);
|
|
|
+- FREEMEM(cctxPtr);
|
|
|
++ 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.
|
|
|
+ *
|
|
|
+@@ -583,78 +652,93 @@ static void LZ4F_initStream(void* 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.
|
|
|
+- * dstBuffer must be >= LZ4F_HEADER_SIZE_MAX bytes.
|
|
|
+- * @return : number of bytes written into dstBuffer for the header
|
|
|
++ * 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 prefNull;
|
|
|
++ LZ4F_preferences_t const prefNull = LZ4F_INIT_PREFERENCES;
|
|
|
+ BYTE* const dstStart = (BYTE*)dstBuffer;
|
|
|
+ BYTE* dstPtr = dstStart;
|
|
|
+- BYTE* headerStart;
|
|
|
+
|
|
|
+- if (dstCapacity < maxFHSize) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
|
|
|
+- MEM_INIT(&prefNull, 0, sizeof(prefNull));
|
|
|
++ RETURN_ERROR_IF(dstCapacity < maxFHSize, dstMaxSize_tooSmall);
|
|
|
+ if (preferencesPtr == NULL) preferencesPtr = &prefNull;
|
|
|
+ cctxPtr->prefs = *preferencesPtr;
|
|
|
+
|
|
|
+- /* Ctx Management */
|
|
|
++ /* cctx Management */
|
|
|
+ { U16 const ctxTypeID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2;
|
|
|
+- if (cctxPtr->lz4CtxAlloc < ctxTypeID) {
|
|
|
+- FREEMEM(cctxPtr->lz4CtxPtr);
|
|
|
++ 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) {
|
|
|
+- cctxPtr->lz4CtxPtr = LZ4_createStream();
|
|
|
++ /* 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 = LZ4_createStreamHC();
|
|
|
++ cctxPtr->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_streamHC_t), cctxPtr->cmem);
|
|
|
++ if (cctxPtr->lz4CtxPtr)
|
|
|
++ LZ4_initStreamHC(cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t));
|
|
|
+ }
|
|
|
+- if (cctxPtr->lz4CtxPtr == NULL)
|
|
|
+- return err0r(LZ4F_ERROR_allocation_failed);
|
|
|
++ RETURN_ERROR_IF(cctxPtr->lz4CtxPtr == NULL, allocation_failed);
|
|
|
+ cctxPtr->lz4CtxAlloc = ctxTypeID;
|
|
|
+ cctxPtr->lz4CtxState = ctxTypeID;
|
|
|
+ } else if (cctxPtr->lz4CtxState != ctxTypeID) {
|
|
|
+- /* otherwise, a sufficient buffer is allocated, but we need to
|
|
|
+- * reset it to the correct context type */
|
|
|
++ /* 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));
|
|
|
++ 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);
|
|
|
++ 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;
|
|
|
+- FREEMEM(cctxPtr->tmpBuff);
|
|
|
+- cctxPtr->tmpBuff = (BYTE*)ALLOC_AND_ZERO(requiredBuffSize);
|
|
|
+- if (cctxPtr->tmpBuff == NULL) return err0r(LZ4F_ERROR_allocation_failed);
|
|
|
++ 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;
|
|
|
+@@ -664,51 +748,52 @@ size_t LZ4F_compressBegin_usingCDict(LZ4
|
|
|
+ }
|
|
|
+ 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;
|
|
|
+- headerStart = dstPtr;
|
|
|
++ { 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;
|
|
|
++ /* 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++;
|
|
|
+ }
|
|
|
+- /* 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.
|
|
|
+- * dstBuffer must be >= LZ4F_HEADER_SIZE_MAX bytes.
|
|
|
+- * preferencesPtr can be NULL, in which case default parameters are selected.
|
|
|
++ * 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,
|
|
|
+@@ -739,21 +824,23 @@ typedef int (*compressFunc_t)(void* ctx,
|
|
|
+ */
|
|
|
+ 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 = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+BHSize),
|
|
|
+- (int)(srcSize), (int)(srcSize-1),
|
|
|
+- level, cdict);
|
|
|
+- if (cSize == 0) { /* compression failed */
|
|
|
+- DEBUGLOG(5, "LZ4F_makeBlock: compression failed, creating a raw block (size %u)", (U32)srcSize);
|
|
|
++ 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 */
|
|
|
+@@ -761,28 +848,30 @@ static size_t LZ4F_makeBlock(void* dst,
|
|
|
+ }
|
|
|
+ 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);
|
|
|
+@@ -791,67 +880,94 @@ static int LZ4F_compressBlockHC(void* ct
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int level)
|
|
|
++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;
|
|
|
+
|
|
|
+-/*! LZ4F_compressUpdate() :
|
|
|
++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.
|
|
|
+- * dstBuffer MUST be >= LZ4F_compressBound(srcSize, preferencesPtr).
|
|
|
+- * LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
|
|
|
++ * 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.
|
|
|
+ */
|
|
|
+-size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr,
|
|
|
+- void* dstBuffer, size_t dstCapacity,
|
|
|
++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_compressOptions_t cOptionsNull;
|
|
|
++ 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);
|
|
|
+-
|
|
|
++ compressFunc_t const compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, blockCompression);
|
|
|
++ size_t bytesWritten;
|
|
|
+ DEBUGLOG(4, "LZ4F_compressUpdate (srcSize=%zu)", srcSize);
|
|
|
+
|
|
|
+- if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC);
|
|
|
++ 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 err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
|
|
|
+- MEM_INIT(&cOptionsNull, 0, sizeof(cOptionsNull));
|
|
|
+- if (compressOptionsPtr == NULL) compressOptionsPtr = &cOptionsNull;
|
|
|
++ 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 */
|
|
|
+@@ -859,61 +975,64 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cc
|
|
|
+ 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)) {
|
|
|
+- /* compress remaining input < blockSize */
|
|
|
++ /* 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;
|
|
|
++ srcPtr = srcEnd;
|
|
|
+ }
|
|
|
+
|
|
|
+- /* preserve dictionary if necessary */
|
|
|
++ /* 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;
|
|
|
++ cctxPtr->tmpIn = cctxPtr->tmpBuff; /* src is stable : dictionary remains in src across invocations */
|
|
|
+ } else {
|
|
|
+ int const realDictSize = LZ4F_localSaveDict(cctxPtr);
|
|
|
+- if (realDictSize==0) return err0r(LZ4F_ERROR_GENERIC);
|
|
|
++ assert(0 <= realDictSize && realDictSize <= 64 KB);
|
|
|
+ cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* keep tmpIn within limits */
|
|
|
+- if ((cctxPtr->tmpIn + blockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize) /* necessarily LZ4F_blockLinked && lastBlockCompressed==fromTmpBuffer */
|
|
|
+- && !(cctxPtr->prefs.autoFlush))
|
|
|
++ 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;
|
|
|
+@@ -921,16 +1040,63 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cc
|
|
|
+
|
|
|
+ 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.
|
|
|
+@@ -939,23 +1105,22 @@ 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 */
|
|
|
+- if (cctxPtr->cStage != 1) return err0r(LZ4F_ERROR_GENERIC);
|
|
|
+- if (dstCapacity < (cctxPtr->tmpInSize + BHSize + BFSize))
|
|
|
+- return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
|
|
|
+- (void)compressOptionsPtr; /* not yet useful */
|
|
|
++ 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);
|
|
|
++ 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));
|
|
|
+@@ -987,40 +1152,40 @@ size_t LZ4F_compressEnd(LZ4F_cctx* cctxP
|
|
|
+ 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);
|
|
|
+- if (LZ4F_isError(flushSize)) return flushSize;
|
|
|
++ FORWARD_IF_ERROR(flushSize);
|
|
|
+ dstPtr += flushSize;
|
|
|
+
|
|
|
+ assert(flushSize <= dstCapacity);
|
|
|
+ dstCapacity -= flushSize;
|
|
|
+
|
|
|
+- if (dstCapacity < 4) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
|
|
|
++ 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));
|
|
|
+- if (dstCapacity < 8) return err0r(LZ4F_ERROR_dstMaxSize_tooSmall);
|
|
|
++ 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 err0r(LZ4F_ERROR_frameSize_wrong);
|
|
|
++ RETURN_ERROR(frameSize_wrong);
|
|
|
+ }
|
|
|
+
|
|
|
+ return (size_t)(dstPtr - dstStart);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /*-***************************************************
|
|
|
+ * Frame Decompression
|
|
|
+@@ -1034,16 +1199,17 @@ typedef enum {
|
|
|
+ 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;
|
|
|
+@@ -1051,59 +1217,71 @@ struct LZ4F_dctx_s {
|
|
|
+ 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)
|
|
|
++LZ4F_errorCode_t
|
|
|
++LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber)
|
|
|
+ {
|
|
|
+- LZ4F_dctx* const dctx = (LZ4F_dctx*)ALLOC_AND_ZERO(sizeof(LZ4F_dctx));
|
|
|
+- if (dctx == NULL) { /* failed allocation */
|
|
|
+- *LZ4F_decompressionContextPtr = NULL;
|
|
|
+- return err0r(LZ4F_ERROR_allocation_failed);
|
|
|
++ 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);
|
|
|
+ }
|
|
|
+-
|
|
|
+- dctx->version = versionNumber;
|
|
|
+- *LZ4F_decompressionContextPtr = dctx;
|
|
|
+ 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;
|
|
|
+- FREEMEM(dctx->tmpIn);
|
|
|
+- FREEMEM(dctx->tmpOutBuffer);
|
|
|
+- FREEMEM(dctx);
|
|
|
++ 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.
|
|
|
+@@ -1113,53 +1291,52 @@ void LZ4F_resetDecompressionContext(LZ4F
|
|
|
+ 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 */
|
|
|
+- if (srcSize < minFHSize) return err0r(LZ4F_ERROR_frameHeader_incomplete); /* minimal frame header size */
|
|
|
++ 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 err0r(LZ4F_ERROR_frameType_unknown);
|
|
|
++ 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 err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bit */
|
|
|
+- if (version != 1) return err0r(LZ4F_ERROR_headerVersion_wrong); /* Version Number, only supported value */
|
|
|
++ 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)
|
|
|
+@@ -1168,68 +1345,66 @@ static size_t LZ4F_decodeHeader(LZ4F_dct
|
|
|
+ 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 err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bit */
|
|
|
+- if (blockSizeID < 4) return err0r(LZ4F_ERROR_maxBlockSize_invalid); /* 4-7 only supported values for the time being */
|
|
|
+- if (((BD>>0)&_4BITS) != 0) return err0r(LZ4F_ERROR_reservedFlag_set); /* Reserved bits */
|
|
|
++ 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);
|
|
|
+- if (HC != srcPtr[frameHeaderSize-1])
|
|
|
+- return err0r(LZ4F_ERROR_headerChecksum_invalid);
|
|
|
++ 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(blockSizeID);
|
|
|
++ dctx->maxBlockSize = LZ4F_getBlockSize((LZ4F_blockSizeID_t)blockSizeID);
|
|
|
+ if (contentSizeFlag)
|
|
|
+- dctx->frameRemainingSize =
|
|
|
+- dctx->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6);
|
|
|
++ 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)
|
|
|
+ {
|
|
|
+- if (src == NULL) return err0r(LZ4F_ERROR_srcPtr_wrong);
|
|
|
++ RETURN_ERROR_IF(src == NULL, srcPtr_wrong);
|
|
|
+
|
|
|
+ /* minimal srcSize to determine header size */
|
|
|
+ if (srcSize < LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH)
|
|
|
+- return err0r(LZ4F_ERROR_frameHeader_incomplete);
|
|
|
++ 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 err0r(LZ4F_ERROR_frameType_unknown);
|
|
|
++ 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);
|
|
|
+ }
|
|
|
+@@ -1261,23 +1436,23 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_
|
|
|
+ *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 err0r(LZ4F_ERROR_frameDecoding_alreadyStarted);
|
|
|
++ 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 err0r(LZ4F_ERROR_frameHeader_incomplete);
|
|
|
++ 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 */
|
|
|
+@@ -1285,26 +1460,24 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_
|
|
|
+ *frameInfoPtr = dctx->frameInfo;
|
|
|
+ return decodeResult;
|
|
|
+ } } }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* LZ4F_updateDict() :
|
|
|
+ * only used for LZ4F_blockLinked mode
|
|
|
+- * Condition : dstPtr != NULL
|
|
|
++ * 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; /* priority to prefix mode */
|
|
|
+- }
|
|
|
++ 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);
|
|
|
+@@ -1357,17 +1530,16 @@ static void LZ4F_updateDict(LZ4F_dctx* d
|
|
|
+ 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).
|
|
|
+@@ -1401,29 +1573,30 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
|
|
|
+ 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 */
|
|
|
+- if (LZ4F_isError(hSize)) return hSize;
|
|
|
++ 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 */
|
|
|
+@@ -1435,37 +1608,33 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+- { size_t const hSize = LZ4F_decodeHeader(dctx, dctx->header, dctx->tmpInTarget); /* will update dStage appropriately */
|
|
|
+- if (LZ4F_isError(hSize)) return hSize;
|
|
|
+- }
|
|
|
++ 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*/
|
|
|
+- FREEMEM(dctx->tmpIn);
|
|
|
+- dctx->tmpIn = (BYTE*)ALLOC(dctx->maxBlockSize + BFSize /* block checksum */);
|
|
|
+- if (dctx->tmpIn == NULL)
|
|
|
+- return err0r(LZ4F_ERROR_allocation_failed);
|
|
|
+- FREEMEM(dctx->tmpOutBuffer);
|
|
|
+- dctx->tmpOutBuffer= (BYTE*)ALLOC(bufferNeeded);
|
|
|
+- if (dctx->tmpOutBuffer== NULL)
|
|
|
+- return err0r(LZ4F_ERROR_allocation_failed);
|
|
|
++ 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;
|
|
|
+
|
|
|
+@@ -1504,17 +1673,17 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
|
|
|
+ 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 err0r(LZ4F_ERROR_maxBlockSize_invalid);
|
|
|
++ 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);
|
|
|
+ }
|
|
|
+@@ -1535,21 +1704,23 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
|
|
|
+ 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->frameInfo.blockChecksumFlag) {
|
|
|
+- (void)XXH32_update(&dctx->blockChecksum, 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.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);
|
|
|
+ } }
|
|
|
+
|
|
|
+@@ -1585,24 +1756,25 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
|
|
|
+ dctx->tmpInSize += sizeToCopy;
|
|
|
+ srcPtr += sizeToCopy;
|
|
|
+ if (dctx->tmpInSize < 4) { /* all input consumed */
|
|
|
+ doAnotherStage = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ crcSrc = dctx->header;
|
|
|
+ }
|
|
|
+- { U32 const readCRC = LZ4F_readLE32(crcSrc);
|
|
|
++ 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 err0r(LZ4F_ERROR_blockChecksum_invalid);
|
|
|
++ RETURN_ERROR(blockChecksum_invalid);
|
|
|
+ }
|
|
|
+ #else
|
|
|
+ (void)readCRC;
|
|
|
+ (void)calcCRC;
|
|
|
+ #endif
|
|
|
+ } }
|
|
|
+ dctx->dStage = dstage_getBlockHeader; /* new block */
|
|
|
+ break;
|
|
|
+@@ -1632,91 +1804,99 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
|
|
|
+ + 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
|
|
|
+- if (readBlockCrc != calcBlockCrc)
|
|
|
+- return err0r(LZ4F_ERROR_blockChecksum_invalid);
|
|
|
++ RETURN_ERROR_IF(readBlockCrc != calcBlockCrc, blockChecksum_invalid);
|
|
|
+ #else
|
|
|
+ (void)readBlockCrc;
|
|
|
+ (void)calcBlockCrc;
|
|
|
+ #endif
|
|
|
+ } }
|
|
|
+
|
|
|
+- if ((size_t)(dstEnd-dstPtr) >= dctx->maxBlockSize) {
|
|
|
++ /* 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) {
|
|
|
+- /* the dictSize param is an int, avoid truncation / sign issues */
|
|
|
++ /* overflow control : dctx->dictSize is an int, avoid truncation / sign issues */
|
|
|
+ dict += dictSize - 64 KB;
|
|
|
+ dictSize = 64 KB;
|
|
|
+ }
|
|
|
+- /* enough capacity in `dst` to decompress directly there */
|
|
|
+ decodedSize = LZ4_decompress_safe_usingDict(
|
|
|
+ (const char*)selectedIn, (char*)dstPtr,
|
|
|
+ (int)dctx->tmpInTarget, (int)dctx->maxBlockSize,
|
|
|
+ dict, (int)dictSize);
|
|
|
+- if (decodedSize < 0) return err0r(LZ4F_ERROR_GENERIC); /* decompression failed */
|
|
|
+- if (dctx->frameInfo.contentChecksumFlag)
|
|
|
++ 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;
|
|
|
++ dctx->dStage = dstage_getBlockHeader; /* end of block, let's get another one */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* not enough place into dst : decode into tmpOut */
|
|
|
+- /* ensure enough place for 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 tmp */
|
|
|
++ } else { /* dict not within tmpOut */
|
|
|
+ size_t const reservedDictSpace = MIN(dctx->dictSize, 64 KB);
|
|
|
+ dctx->tmpOut = dctx->tmpOutBuffer + reservedDictSpace;
|
|
|
+ } }
|
|
|
+
|
|
|
+- /* Decode block */
|
|
|
++ /* 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);
|
|
|
+- if (decodedSize < 0) /* decompression failed */
|
|
|
+- return err0r(LZ4F_ERROR_decompressionFailed);
|
|
|
+- if (dctx->frameInfo.contentChecksumFlag)
|
|
|
++ 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 */
|
|
|
+@@ -1739,18 +1919,17 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ /* could not flush everything : stop there, just request a block header */
|
|
|
+ doAnotherStage = 0;
|
|
|
+ nextSrcSizeHint = BHSize;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case dstage_getSuffix:
|
|
|
+- if (dctx->frameRemainingSize)
|
|
|
+- return err0r(LZ4F_ERROR_frameSize_wrong); /* incorrect frame size decoded */
|
|
|
++ 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;
|
|
|
+@@ -1772,30 +1951,30 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
|
|
|
+ nextSrcSizeHint = 4 - dctx->tmpInSize;
|
|
|
+ doAnotherStage=0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ selectedIn = dctx->tmpIn;
|
|
|
+ } /* if (dctx->dStage == dstage_storeSuffix) */
|
|
|
+
|
|
|
+ /* case dstage_checkSuffix: */ /* no direct entry, avoid initialization risks */
|
|
|
+- { U32 const readCRC = LZ4F_readLE32(selectedIn);
|
|
|
++ if (!dctx->skipChecksum) {
|
|
|
++ U32 const readCRC = LZ4F_readLE32(selectedIn);
|
|
|
+ U32 const resultCRC = XXH32_digest(&(dctx->xxh));
|
|
|
+ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
|
|
+- if (readCRC != resultCRC)
|
|
|
+- return err0r(LZ4F_ERROR_contentChecksum_invalid);
|
|
|
++ RETURN_ERROR_IF(readCRC != resultCRC, contentChecksum_invalid);
|
|
|
+ #else
|
|
|
+ (void)readCRC;
|
|
|
+ (void)resultCRC;
|
|
|
+ #endif
|
|
|
+- nextSrcSizeHint = 0;
|
|
|
+- LZ4F_resetDecompressionContext(dctx);
|
|
|
+- doAnotherStage = 0;
|
|
|
+- break;
|
|
|
+ }
|
|
|
++ 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;
|
|
|
+@@ -1836,17 +2015,17 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
|
|
|
+ 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 tmp whenever necessary */
|
|
|
++ /* 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) {
|
|
|
+diff --git a/mfbt/lz4/lz4frame.h b/mfbt/lz4/lz4frame.h
|
|
|
+--- a/mfbt/lz4/lz4frame.h
|
|
|
++++ b/mfbt/lz4/lz4frame.h
|
|
|
+@@ -1,12 +1,12 @@
|
|
|
+ /*
|
|
|
+- LZ4 auto-framing library
|
|
|
++ LZ4F - LZ4-Frame library
|
|
|
+ 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
|
|
|
+ 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.
|
|
|
+@@ -34,37 +34,37 @@
|
|
|
+
|
|
|
+ /* 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 constant such as LZ4_VERSION_NUMBER.
|
|
|
++ * 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 (doc/lz4_Frame_format.md).
|
|
|
+- lz4frame.h provides frame compression functions that take care
|
|
|
+- of encoding standard metadata alongside LZ4-compressed blocks.
|
|
|
+-*/
|
|
|
++ * 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.
|
|
|
+@@ -205,17 +205,17 @@ typedef struct {
|
|
|
+ ***********************************/
|
|
|
+
|
|
|
+ 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 used with LZ4F_compressUpdate() _if no flush() operation_ is performed.
|
|
|
++ * 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.
|
|
|
+@@ -225,43 +225,50 @@ LZ4FLIB_API size_t LZ4F_compressFrame(vo
|
|
|
+ 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 previous API version */
|
|
|
++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 be used in all compression operations.
|
|
|
+- * This is achieved using LZ4F_createCompressionContext(), which takes as argument a version.
|
|
|
+- * The version provided MUST be LZ4F_VERSION. It is intended to track potential version mismatch, notably when using DLL.
|
|
|
+- * The function will provide a pointer to a fully allocated LZ4F_cctx object.
|
|
|
+- * If @return != zero, there was an error during context creation.
|
|
|
+- * Object can release its memory using LZ4F_freeCompressionContext();
|
|
|
+- */
|
|
|
++ * 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 paramaters */
|
|
|
++#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
|
|
|
+
|
|
|
+@@ -296,18 +303,19 @@ LZ4FLIB_API size_t LZ4F_compressBegin(LZ
|
|
|
+ */
|
|
|
+ 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).
|
|
|
+- * LZ4F_compressUpdate() doesn't guarantee error recovery.
|
|
|
+- * When an error occurs, compression context must be freed or resized.
|
|
|
++ * 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);
|
|
|
+@@ -342,56 +350,63 @@ LZ4FLIB_API size_t LZ4F_compressEnd(LZ4F
|
|
|
+
|
|
|
+ /*-*********************************
|
|
|
+ * 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. This optimization skips storage operations in tmp buffers. */
|
|
|
+- unsigned reserved[3]; /* must be set to zero for forward compatibility */
|
|
|
++ 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.
|
|
|
+- * The version provided MUST be LZ4F_VERSION.
|
|
|
+- * The function provides a pointer to an allocated and initialized LZ4F_dctx object.
|
|
|
+- * The result is an errorCode, which can be tested using LZ4F_isError().
|
|
|
++ * @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 call LZ4F_decompress() directly.
|
|
|
++ * 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`,
|
|
|
+@@ -422,19 +437,20 @@ LZ4FLIB_API size_t LZ4F_headerSize(const
|
|
|
+ * 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);
|
|
|
++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.
|
|
|
+ *
|
|
|
+@@ -457,20 +473,21 @@ LZ4FLIB_API size_t LZ4F_getFrameInfo(LZ4
|
|
|
+ * 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);
|
|
|
++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 */
|
|
|
+@@ -524,27 +541,53 @@ extern "C" {
|
|
|
+ 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);
|
|
|
+
|
|
|
+-LZ4FLIB_STATIC_API size_t LZ4F_getBlockSize(unsigned);
|
|
|
++
|
|
|
++/*! 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.
|
|
|
+ *
|
|
|
+@@ -578,46 +621,72 @@ LZ4FLIB_STATIC_API void LZ4F_free
|
|
|
+ * 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);
|
|
|
++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);
|
|
|
++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);
|
|
|
++** 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) */
|
|
|
+diff --git a/mfbt/lz4/lz4frame_static.h b/mfbt/lz4/lz4frame_static.h
|
|
|
+--- a/mfbt/lz4/lz4frame_static.h
|
|
|
++++ b/mfbt/lz4/lz4frame_static.h
|
|
|
+@@ -1,12 +1,12 @@
|
|
|
+ /*
|
|
|
+ LZ4 auto-framing library
|
|
|
+ Header File for static linking only
|
|
|
+- Copyright (C) 2011-2016, 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
|
|
|
+ modification, are permitted provided that the following conditions are
|
|
|
+ met:
|
|
|
+
|
|
|
+ * Redistributions of source code must retain the above copyright
|
|
|
+diff --git a/mfbt/lz4/lz4hc.c b/mfbt/lz4/lz4hc.c
|
|
|
+--- a/mfbt/lz4/lz4hc.c
|
|
|
++++ b/mfbt/lz4/lz4hc.c
|
|
|
+@@ -1,11 +1,11 @@
|
|
|
+ /*
|
|
|
+ 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)
|
|
|
+
|
|
|
+ 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
|
|
|
+@@ -37,17 +37,17 @@
|
|
|
+ /* *************************************
|
|
|
+ * Tuning Parameter
|
|
|
+ ***************************************/
|
|
|
+
|
|
|
+ /*! HEAPMODE :
|
|
|
+ * Select how default compression function will allocate workplace memory,
|
|
|
+ * in stack (0:fastest), or in heap (1:requires malloc()).
|
|
|
+ * Since workplace is rather large, heap mode is recommended.
|
|
|
+- */
|
|
|
++**/
|
|
|
+ #ifndef LZ4HC_HEAPMODE
|
|
|
+ # define LZ4HC_HEAPMODE 1
|
|
|
+ #endif
|
|
|
+
|
|
|
+
|
|
|
+ /*=== Dependency ===*/
|
|
|
+ #define LZ4_HC_STATIC_LINKING_ONLY
|
|
|
+ #include "lz4hc.h"
|
|
|
+@@ -94,42 +94,47 @@ static U32 LZ4HC_hashPtr(const void* ptr
|
|
|
+ static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)
|
|
|
+ {
|
|
|
+ MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable));
|
|
|
+ MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
|
|
|
+ }
|
|
|
+
|
|
|
+ static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)
|
|
|
+ {
|
|
|
+- 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* Update chains up to ip (excluded) */
|
|
|
+ LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
|
|
|
+ {
|
|
|
+ U16* const chainTable = hc4->chainTable;
|
|
|
+ U32* const hashTable = hc4->hashTable;
|
|
|
+- const BYTE* const 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;
|
|
|
+ hashTable[h] = idx;
|
|
|
+ idx++;
|
|
|
+ }
|
|
|
+
|
|
|
+ hc4->nextToUpdate = target;
|
|
|
+@@ -188,35 +193,34 @@ LZ4HC_countPattern(const BYTE* ip, const
|
|
|
+ ip++; patternByte >>= 8;
|
|
|
+ }
|
|
|
+ } else { /* big endian */
|
|
|
+ U32 bitOffset = (sizeof(pattern)*8) - 8;
|
|
|
+ while (ip < iEnd) {
|
|
|
+ BYTE const byte = (BYTE)(pattern >> bitOffset);
|
|
|
+ if (*ip != byte) break;
|
|
|
+ ip ++; bitOffset -= 8;
|
|
|
+- }
|
|
|
+- }
|
|
|
++ } }
|
|
|
+
|
|
|
+ return (unsigned)(ip - iStart);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* LZ4HC_reverseCountPattern() :
|
|
|
+ * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
|
|
|
+- * read using natural platform endianess */
|
|
|
++ * read using natural platform endianness */
|
|
|
+ static unsigned
|
|
|
+ LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)
|
|
|
+ {
|
|
|
+ const BYTE* const iStart = ip;
|
|
|
+
|
|
|
+ while (likely(ip >= iLow+4)) {
|
|
|
+ if (LZ4_read32(ip-4) != pattern) break;
|
|
|
+ ip -= 4;
|
|
|
+ }
|
|
|
+- { const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianess */
|
|
|
++ { const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */
|
|
|
+ while (likely(ip>iLow)) {
|
|
|
+ if (ip[-1] != *bytePtr) break;
|
|
|
+ ip--; bytePtr--;
|
|
|
+ } }
|
|
|
+ return (unsigned)(iStart - ip);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* LZ4HC_protectDictEnd() :
|
|
|
+@@ -229,38 +233,38 @@ static int LZ4HC_protectDictEnd(U32 cons
|
|
|
+ return ((U32)((dictLimit - 1) - matchIndex) >= 3);
|
|
|
+ }
|
|
|
+
|
|
|
+ typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;
|
|
|
+ typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;
|
|
|
+
|
|
|
+ LZ4_FORCE_INLINE int
|
|
|
+ LZ4HC_InsertAndGetWiderMatch (
|
|
|
+- LZ4HC_CCtx_internal* 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;
|
|
|
+ U32 const pattern = LZ4_read32(ip);
|
|
|
+ U32 matchIndex;
|
|
|
+ repeat_state_e repeat = rep_untested;
|
|
|
+ size_t srcPatternLength = 0;
|
|
|
+
|
|
|
+@@ -272,67 +276,66 @@ LZ4HC_InsertAndGetWiderMatch (
|
|
|
+ matchIndex, lowestMatchIndex);
|
|
|
+
|
|
|
+ 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) {
|
|
|
+ longest = matchLength;
|
|
|
+ *matchpos = matchPtr + back;
|
|
|
+ *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;
|
|
|
+ U32 distanceToNextMatch = 1;
|
|
|
+ int const end = longest - MINMATCH + 1;
|
|
|
+ int step = 1;
|
|
|
+ int accel = 1 << kTrigger;
|
|
|
+ int pos;
|
|
|
+ for (pos = 0; pos < end; pos += step) {
|
|
|
+ U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);
|
|
|
+ step = (accel++ >> kTrigger);
|
|
|
+ if (candidateDist > distanceToNextMatch) {
|
|
|
+ distanceToNextMatch = candidateDist;
|
|
|
+ matchChainPos = (U32)pos;
|
|
|
+ accel = 1 << kTrigger;
|
|
|
+- }
|
|
|
+- }
|
|
|
++ } }
|
|
|
+ if (distanceToNextMatch > 1) {
|
|
|
+ if (distanceToNextMatch > matchIndex) break; /* avoid overflow */
|
|
|
+ matchIndex -= distanceToNextMatch;
|
|
|
+ continue;
|
|
|
+ } } }
|
|
|
+
|
|
|
+ { U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);
|
|
|
+ if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {
|
|
|
+@@ -342,64 +345,65 @@ LZ4HC_InsertAndGetWiderMatch (
|
|
|
+ if ( ((pattern & 0xFFFF) == (pattern >> 16))
|
|
|
+ & ((pattern & 0xFF) == (pattern >> 24)) ) {
|
|
|
+ repeat = rep_confirmed;
|
|
|
+ srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);
|
|
|
+ } else {
|
|
|
+ repeat = rep_not;
|
|
|
+ } }
|
|
|
+ if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)
|
|
|
+- && LZ4HC_protectDictEnd(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);
|
|
|
+ assert(matchCandidateIdx - backLength >= lowestMatchIndex);
|
|
|
+ currentSegmentLength = backLength + forwardPatternLength;
|
|
|
+ /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */
|
|
|
+ if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */
|
|
|
+ && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */
|
|
|
+ U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */
|
|
|
+- if (LZ4HC_protectDictEnd(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);
|
|
|
+ if (distToNextPattern > matchIndex) break; /* avoid overflow */
|
|
|
+ matchIndex -= distToNextPattern;
|
|
|
+ } } } } }
|
|
|
+ continue;
|
|
|
+ } }
|
|
|
+@@ -408,52 +412,52 @@ LZ4HC_InsertAndGetWiderMatch (
|
|
|
+ /* follow current chain */
|
|
|
+ matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);
|
|
|
+
|
|
|
+ } /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */
|
|
|
+
|
|
|
+ if ( dict == usingDictCtxHc
|
|
|
+ && nbAttempts > 0
|
|
|
+ && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {
|
|
|
+- size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->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;
|
|
|
+ int back = 0;
|
|
|
+ const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);
|
|
|
+ if (vLimit > iHighLimit) vLimit = iHighLimit;
|
|
|
+ mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
|
|
|
+- back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->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;
|
|
|
+ } }
|
|
|
+
|
|
|
+ { U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);
|
|
|
+ dictMatchIndex -= nextOffset;
|
|
|
+ matchIndex -= nextOffset;
|
|
|
+ } } }
|
|
|
+
|
|
|
+ return longest;
|
|
|
+ }
|
|
|
+
|
|
|
+-LZ4_FORCE_INLINE
|
|
|
+-int LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */
|
|
|
+- const BYTE* const ip, const BYTE* const iLimit,
|
|
|
+- const BYTE** matchpos,
|
|
|
+- const int maxNbAttempts,
|
|
|
+- const int patternAnalysis,
|
|
|
+- const dictCtx_directive dict)
|
|
|
++LZ4_FORCE_INLINE int
|
|
|
++LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */
|
|
|
++ const BYTE* const ip, const BYTE* const iLimit,
|
|
|
++ const BYTE** matchpos,
|
|
|
++ const int maxNbAttempts,
|
|
|
++ const int patternAnalysis,
|
|
|
++ const dictCtx_directive dict)
|
|
|
+ {
|
|
|
+ const BYTE* uselessPtr = ip;
|
|
|
+ /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),
|
|
|
+ * but this won't be the case here, as we define iLowLimit==ip,
|
|
|
+ * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
|
|
|
+ return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -746,17 +750,17 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hash
|
|
|
+ if (lastRunSize >= RUN_MASK) {
|
|
|
+ size_t accumulator = lastRunSize - RUN_MASK;
|
|
|
+ *op++ = (RUN_MASK << ML_BITS);
|
|
|
+ for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
|
|
|
+ *op++ = (BYTE) accumulator;
|
|
|
+ } else {
|
|
|
+ *op++ = (BYTE)(lastRunSize << ML_BITS);
|
|
|
+ }
|
|
|
+- memcpy(op, anchor, lastRunSize);
|
|
|
++ LZ4_memcpy(op, anchor, lastRunSize);
|
|
|
+ op += lastRunSize;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* End */
|
|
|
+ *srcSizePtr = (int) (((const char*)ip) - source);
|
|
|
+ return (int) (((char*)op)-dest);
|
|
|
+
|
|
|
+ _dest_overflow:
|
|
|
+@@ -879,23 +883,23 @@ LZ4HC_compress_generic_dictCtx (
|
|
|
+ const char* const src,
|
|
|
+ char* const dst,
|
|
|
+ int* const srcSizePtr,
|
|
|
+ int const dstCapacity,
|
|
|
+ int cLevel,
|
|
|
+ limitedOutput_directive limit
|
|
|
+ )
|
|
|
+ {
|
|
|
+- const size_t position = (size_t)(ctx->end - ctx->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);
|
|
|
+ } else {
|
|
|
+ return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -948,23 +952,25 @@ int LZ4_compress_HC_extStateHC (void* st
|
|
|
+ {
|
|
|
+ LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));
|
|
|
+ if (ctx==NULL) return 0; /* init failure */
|
|
|
+ return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);
|
|
|
+ }
|
|
|
+
|
|
|
+ int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)
|
|
|
+ {
|
|
|
++ int cSize;
|
|
|
+ #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
|
|
+ LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));
|
|
|
++ if (statePtr==NULL) return 0;
|
|
|
+ #else
|
|
|
+ LZ4_streamHC_t state;
|
|
|
+ LZ4_streamHC_t* const statePtr = &state;
|
|
|
+ #endif
|
|
|
+- 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
|
|
|
+ return cSize;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */
|
|
|
+ int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)
|
|
|
+@@ -977,39 +983,39 @@ int LZ4_compress_HC_destSize(void* state
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**************************************
|
|
|
+ * Streaming Functions
|
|
|
+ **************************************/
|
|
|
+ /* allocation */
|
|
|
++#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
|
|
|
+ LZ4_streamHC_t* LZ4_createStreamHC(void)
|
|
|
+ {
|
|
|
+ LZ4_streamHC_t* const state =
|
|
|
+ (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t));
|
|
|
+ if (state == NULL) return NULL;
|
|
|
+ LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT);
|
|
|
+ return state;
|
|
|
+ }
|
|
|
+
|
|
|
+ int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
|
|
|
+ {
|
|
|
+ DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);
|
|
|
+ if (!LZ4_streamHCPtr) return 0; /* support free on NULL */
|
|
|
+ FREEMEM(LZ4_streamHCPtr);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
++#endif
|
|
|
+
|
|
|
+
|
|
|
+ LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
|
|
|
+ {
|
|
|
+ LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;
|
|
|
+- /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
|
|
|
+- LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= LZ4_STREAMHCSIZE);
|
|
|
+ DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);
|
|
|
+ /* check conditions */
|
|
|
+ if (buffer == NULL) return NULL;
|
|
|
+ if (size < sizeof(LZ4_streamHC_t)) return NULL;
|
|
|
+ if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;
|
|
|
+ /* init */
|
|
|
+ { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);
|
|
|
+ MEM_INIT(hcstate, 0, sizeof(*hcstate)); }
|
|
|
+@@ -1025,23 +1031,23 @@ void LZ4_resetStreamHC (LZ4_streamHC_t*
|
|
|
+ }
|
|
|
+
|
|
|
+ void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
|
|
+ {
|
|
|
+ DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);
|
|
|
+ if (LZ4_streamHCPtr->internal_donotuse.dirty) {
|
|
|
+ LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));
|
|
|
+ } else {
|
|
|
+- /* preserve end - base : can trigger clearTable's threshold */
|
|
|
++ /* 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.base;
|
|
|
++ LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.prefixStart;
|
|
|
+ } else {
|
|
|
+- assert(LZ4_streamHCPtr->internal_donotuse.base == NULL);
|
|
|
++ assert(LZ4_streamHCPtr->internal_donotuse.prefixStart == NULL);
|
|
|
+ }
|
|
|
+- LZ4_streamHCPtr->internal_donotuse.base = NULL;
|
|
|
++ LZ4_streamHCPtr->internal_donotuse.prefixStart = NULL;
|
|
|
+ LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;
|
|
|
+ }
|
|
|
+ LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);
|
|
|
+ }
|
|
|
+
|
|
|
+ void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
|
|
+ {
|
|
|
+ DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);
|
|
|
+@@ -1082,24 +1088,24 @@ void LZ4_attach_HC_dictionary(LZ4_stream
|
|
|
+ working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* compression */
|
|
|
+
|
|
|
+ static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
|
|
|
+ {
|
|
|
+ DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);
|
|
|
+- if (ctxPtr->end >= ctxPtr->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 */
|
|
|
+
|
|
|
+ /* cannot reference an extDict and a dictCtx at the same time */
|
|
|
+ ctxPtr->dictCtx = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ static int
|
|
|
+@@ -1108,38 +1114,41 @@ LZ4_compressHC_continue_generic (LZ4_str
|
|
|
+ int* srcSizePtr, int dstCapacity,
|
|
|
+ limitedOutput_directive limit)
|
|
|
+ {
|
|
|
+ LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
|
|
|
+ DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
|
|
|
+ LZ4_streamHCPtr, src, *srcSizePtr, limit);
|
|
|
+ assert(ctxPtr != NULL);
|
|
|
+ /* auto-init if forgotten */
|
|
|
+- if (ctxPtr->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);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Check if blocks follow each other */
|
|
|
+ if ((const BYTE*)src != ctxPtr->end)
|
|
|
+ LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);
|
|
|
+
|
|
|
+ /* Check overlapping input/dictionary space */
|
|
|
+ { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;
|
|
|
+- const BYTE* const dictBegin = ctxPtr->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);
|
|
|
+ }
|
|
|
+
|
|
|
+ int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)
|
|
|
+ {
|
|
|
+ if (dstCapacity < LZ4_compressBound(srcSize))
|
|
|
+ return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);
|
|
|
+@@ -1157,30 +1166,31 @@ int LZ4_compress_HC_continue_destSize (L
|
|
|
+ /* 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));
|
|
|
++ int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);
|
|
|
+ DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
|
|
|
+ assert(prefixSize >= 0);
|
|
|
+ if (dictSize > 64 KB) dictSize = 64 KB;
|
|
|
+ if (dictSize < 4) dictSize = 0;
|
|
|
+ if (dictSize > prefixSize) dictSize = prefixSize;
|
|
|
+ if (safeBuffer == NULL) assert(dictSize == 0);
|
|
|
+ if (dictSize > 0)
|
|
|
+- memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
|
|
|
+- { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
|
|
|
++ 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;
|
|
|
++ streamPtr->dictStart = streamPtr->prefixStart;
|
|
|
+ if (streamPtr->nextToUpdate < streamPtr->dictLimit)
|
|
|
+ streamPtr->nextToUpdate = streamPtr->dictLimit;
|
|
|
+ }
|
|
|
+ return dictSize;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /***************************************************
|
|
|
+@@ -1198,60 +1208,62 @@ int LZ4_compressHC_withStateHC (void* st
|
|
|
+ int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }
|
|
|
+ int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
|
|
|
+ int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }
|
|
|
+ int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }
|
|
|
+ int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }
|
|
|
+
|
|
|
+
|
|
|
+ /* Deprecated streaming functions */
|
|
|
+-int LZ4_sizeofStreamStateHC(void) { return 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 */
|
|
|
+ int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
|
|
|
+ {
|
|
|
+ LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));
|
|
|
+ if (hc4 == NULL) return 1; /* init failed */
|
|
|
+ LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
++#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
|
|
|
+ void* LZ4_createHC (const char* inputBuffer)
|
|
|
+ {
|
|
|
+ LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
|
|
|
+ if (hc4 == NULL) return NULL; /* not enough memory */
|
|
|
+ LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
|
|
|
+ return hc4;
|
|
|
+ }
|
|
|
+
|
|
|
+ int LZ4_freeHC (void* LZ4HC_Data)
|
|
|
+ {
|
|
|
+ if (!LZ4HC_Data) return 0; /* support free on NULL */
|
|
|
+ FREEMEM(LZ4HC_Data);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
++#endif
|
|
|
+
|
|
|
+ int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
|
|
|
+ {
|
|
|
+ return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);
|
|
|
+ }
|
|
|
+
|
|
|
+ int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)
|
|
|
+ {
|
|
|
+ return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);
|
|
|
+ }
|
|
|
+
|
|
|
+ char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
|
|
|
+ {
|
|
|
+- LZ4_streamHC_t *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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* ================================================
|
|
|
+ * LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])
|
|
|
+ * ===============================================*/
|
|
|
+ typedef struct {
|
|
|
+ int price;
|
|
|
+@@ -1324,17 +1336,17 @@ static int LZ4HC_compress_optimal ( LZ4H
|
|
|
+ size_t sufficient_len,
|
|
|
+ const limitedOutput_directive limit,
|
|
|
+ int const fullUpdate,
|
|
|
+ const dictCtx_directive dict,
|
|
|
+ const HCfavor_e favorDecSpeed)
|
|
|
+ {
|
|
|
+ int retval = 0;
|
|
|
+ #define TRAILING_LITERALS 3
|
|
|
+-#ifdef LZ4HC_HEAPMODE
|
|
|
++#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
|
|
+ LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));
|
|
|
+ #else
|
|
|
+ LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */
|
|
|
+ #endif
|
|
|
+
|
|
|
+ const BYTE* ip = (const BYTE*) source;
|
|
|
+ const BYTE* anchor = ip;
|
|
|
+ const BYTE* const iend = ip + *srcSizePtr;
|
|
|
+@@ -1342,17 +1354,17 @@ static int LZ4HC_compress_optimal ( LZ4H
|
|
|
+ const BYTE* const matchlimit = iend - LASTLITERALS;
|
|
|
+ BYTE* op = (BYTE*) dst;
|
|
|
+ BYTE* opSaved = (BYTE*) dst;
|
|
|
+ BYTE* oend = op + dstCapacity;
|
|
|
+ int ovml = MINMATCH; /* overflow - last sequence */
|
|
|
+ const BYTE* ovref = NULL;
|
|
|
+
|
|
|
+ /* init */
|
|
|
+-#ifdef LZ4HC_HEAPMODE
|
|
|
++#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 */
|
|
|
+@@ -1574,17 +1586,17 @@ encode: /* cur, last_match_pos, best_mle
|
|
|
+ if (lastRunSize >= RUN_MASK) {
|
|
|
+ size_t accumulator = lastRunSize - RUN_MASK;
|
|
|
+ *op++ = (RUN_MASK << ML_BITS);
|
|
|
+ for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;
|
|
|
+ *op++ = (BYTE) accumulator;
|
|
|
+ } else {
|
|
|
+ *op++ = (BYTE)(lastRunSize << ML_BITS);
|
|
|
+ }
|
|
|
+- memcpy(op, anchor, lastRunSize);
|
|
|
++ LZ4_memcpy(op, anchor, lastRunSize);
|
|
|
+ op += lastRunSize;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* End */
|
|
|
+ *srcSizePtr = (int) (((const char*)ip) - source);
|
|
|
+ retval = (int) ((char*)op-dst);
|
|
|
+ goto _return_label;
|
|
|
+
|
|
|
+@@ -1607,13 +1619,13 @@ if (limit == fillOutput) {
|
|
|
+ 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:
|
|
|
+-#ifdef LZ4HC_HEAPMODE
|
|
|
++#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
|
|
|
+ FREEMEM(opt);
|
|
|
+ #endif
|
|
|
+ return retval;
|
|
|
+ }
|
|
|
+diff --git a/mfbt/lz4/lz4hc.h b/mfbt/lz4/lz4hc.h
|
|
|
+--- a/mfbt/lz4/lz4hc.h
|
|
|
++++ b/mfbt/lz4/lz4hc.h
|
|
|
+@@ -1,12 +1,12 @@
|
|
|
+ /*
|
|
|
+ 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
|
|
|
+ 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.
|
|
|
+@@ -193,63 +193,61 @@ LZ4LIB_API int LZ4_saveDictHC (LZ4_strea
|
|
|
+ #define LZ4HC_MAXD (1<<LZ4HC_DICTIONARY_LOGSIZE)
|
|
|
+ #define LZ4HC_MAXD_MASK (LZ4HC_MAXD - 1)
|
|
|
+
|
|
|
+ #define LZ4HC_HASH_LOG 15
|
|
|
+ #define LZ4HC_HASHTABLESIZE (1 << LZ4HC_HASH_LOG)
|
|
|
+ #define LZ4HC_HASH_MASK (LZ4HC_HASHTABLESIZE - 1)
|
|
|
+
|
|
|
+
|
|
|
++/* 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
|
|
|
+ {
|
|
|
+ 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* base; /* All index relative to this position */
|
|
|
+- const LZ4_byte* dictBase; /* alternate base for extDict */
|
|
|
++ 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;
|
|
|
+ };
|
|
|
+
|
|
|
+-
|
|
|
+-/* Do not use these definitions directly !
|
|
|
+- * Declare or allocate an LZ4_streamHC_t instead.
|
|
|
+- */
|
|
|
+-#define LZ4_STREAMHCSIZE 262200 /* static size, for inter-version compatibility */
|
|
|
+-#define LZ4_STREAMHCSIZE_VOIDP (LZ4_STREAMHCSIZE / sizeof(void*))
|
|
|
++#define LZ4_STREAMHC_MINSIZE 262200 /* static size, for inter-version compatibility */
|
|
|
+ union LZ4_streamHC_u {
|
|
|
+- void* table[LZ4_STREAMHCSIZE_VOIDP];
|
|
|
++ 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.
|
|
|
+ *
|
|
|
+ * Note that invoking LZ4_initStreamHC() is not required when
|
|
|
+ * the state was created using LZ4_createStreamHC() (which is recommended).
|
|
|
+ * Using the normal builder, a newly created state is automatically initialized.
|
|
|
+ *
|
|
|
+ * Static allocation shall only be used in combination with static linking.
|
|
|
+ */
|
|
|
+
|
|
|
+ /* LZ4_initStreamHC() : v1.9.0+
|
|
|
+ * 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);
|
|
|
+
|
|
|
+
|
|
|
+ /*-************************************
|
|
|
+ * Deprecated Functions
|
|
|
+ **************************************/
|
|
|
+ /* see lz4.h LZ4_DISABLE_DEPRECATE_WARNINGS to turn off deprecation warnings */
|
|
|
+
|
|
|
+ /* deprecated compression functions */
|
|
|
+@@ -267,19 +265,21 @@ LZ4_DEPRECATED("use LZ4_compress_HC_cont
|
|
|
+ /* Obsolete streaming functions; 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
|
|
|
+ * possible: using them will still produce a correct output. However, use of
|
|
|
+ * 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_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_freeStreamHC() instead") LZ4LIB_API int LZ4_freeHC (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);
|
|
|
+ LZ4_DEPRECATED("use LZ4_initStreamHC() instead") LZ4LIB_API int LZ4_resetStreamStateHC(void* state, char* inputBuffer);
|
|
|
+
|
|
|
+
|
|
|
+ /* LZ4_resetStreamHC() is now replaced by LZ4_initStreamHC().
|
|
|
+ * The intention is to emphasize the difference with LZ4_resetStreamHC_fast(),
|
|
|
+@@ -300,17 +300,17 @@ LZ4LIB_API void LZ4_resetStreamHC (LZ4_s
|
|
|
+
|
|
|
+
|
|
|
+ /*-**************************************************
|
|
|
+ * !!!!! STATIC LINKING ONLY !!!!!
|
|
|
+ * Following definitions are considered experimental.
|
|
|
+ * 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
|
|
|
+ #define LZ4_HC_SLO_098092834
|
|
|
+
|
|
|
+ #define LZ4_STATIC_LINKING_ONLY /* LZ4LIB_STATIC_API */
|
|
|
+ #include "lz4.h"
|
|
|
+
|
|
|
+diff --git a/mfbt/moz.build b/mfbt/moz.build
|
|
|
+--- a/mfbt/moz.build
|
|
|
++++ b/mfbt/moz.build
|
|
|
+@@ -146,16 +146,17 @@ if CONFIG['MOZ_BUILD_APP'] != 'tools/cra
|
|
|
+ # tools/crashreporter.
|
|
|
+ TEST_DIRS += ['tests']
|
|
|
+
|
|
|
+ DEFINES['IMPL_MFBT'] = True
|
|
|
+
|
|
|
+ SOURCES += [
|
|
|
+ 'decimal/Decimal.cpp',
|
|
|
+ 'lz4/lz4.c',
|
|
|
++ "lz4/lz4file.c",
|
|
|
+ 'lz4/lz4frame.c',
|
|
|
+ 'lz4/lz4hc.c',
|
|
|
+ 'lz4/xxhash.c',
|
|
|
+ ]
|
|
|
+
|
|
|
+ if CONFIG['CC_TYPE'] != 'msvc':
|
|
|
+ SOURCES["lz4/xxhash.c"].flags += ["-Wno-unused-function"]
|
|
|
+
|