mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
baf78e7 Merge pull request #111 from Cyan4973/dev 6f50184 Updated NEWS acae59a Fixed : default sparse mode disabled on stdout, to support ` >>` redirection scenario reported by Takayuki Matsuoka (#110) 91c1b9a Performance fix : big compression speed boost for clang (+30%) 0fb0392 Merge branch 'dev' of github.com:Cyan4973/lz4 into dev bb22103 Merge pull request #107 from t-mat/issue/103pr2 7d72c0c Added LZF e769a0e Combine unique .lz4 file info ffff9ee Support iterative edit and testing a8fdeb4 Add log output of succeeded decompression to test script 5151c30 Add log of same files and sha1 hash of unique files to versionstest 26065c3 Fixed : LZ4IO exits too early when frame crc not present, reported by Yongwoon Cho (#106) 87e560e minor tests improvements a9ff13a minor test refactor 58b5aad Fixed sparse issue with non seekable streams (#105) 60d657a removed "flush" argument to please Travis's python version cdb136d cosmetic changes, 2nd try c779c80 minor cosmetic changes for Takayuki's testVersions 26021db Merge branch 'dev' of github.com:Cyan4973/lz4 into dev e3b5bf3 Merge pull request #104 from t-mat/issue/103pr2 fe11e0b Issue #103 : Add compatibility test between releases f02c467 Added a few more interoperability tests (32bits vs 64 bits) 05c3f66 Updated a few comments 9607848 Fixed minor typo 45e1995 minor introduction update 7d182b8 Merge pull request #102 from Cyan4973/dev fdd0029 minor parsing update 672bfde Updated comments b4ef93a Fixed typo efbebd2 Added : LZ4_compress_destSize() 1c3e633 Added compilation flag -Wcast-qual 05b0aa6 Updated readme e05088d Updated lz4hc API b4348a4 Fixed minor Visual warning 1171303 Updated streaming examples 1b17bf2 New lz4 API, using LZ4_compress_fast() b495c91 Merge pull request #99 from eberge/dev 791512c Fixed bug 9318 2a974d7 refactored lz4hc 1e751a7 Install the lz4frame.h header in the cmake build ad2dd6d moved lz4frame context types to incomplete typedef c9cbb8f Increased aligment requirement for lz4frame context pointer ef55dfb Modified lz4frame context typedef, to enforce stricter alignment condition 87a1c70 Fixed minor static analyzer warning d6dc0a4 streaming API : Improved ring buffer management bda38fd Merge pull request #98 from eberge/dev a9a24e8 cmake support for AIX, HPUX, Solaris and Windows 9c6fb8b Added LZ4_compress_fast_extState() b05d3d7 Frame content size disabled by default when using LZ4F_compressFrame(), to be in better coherence with the advanced API LZ4F_compress_update() b805d58 Removed obsolete functions from lz4 cli f11afaf Removed LZ4_compress() (obsolete) from lz4 72e6794 Updated LZ4F_freeDecompressionContext(), to provide stage hint as result a01e10d Changed LZ4F compressionLevel from unsigned to signed, in anticipation for LZ4_compress_fast() integration. cbcdd88 Fixed frame concatenation e18aa90 Fixed frametest c035b7a Restored make-lz4 197982e Fixed unfinished frame (issue #75) 409f816 Updated LZ4F_getFrameInfo() behavior, related to uncomplete frame header decoding attempts 47c3040 added --no-sparse test 9fd4f1f Sparse file support is now enabled by default 7644bee test error message in multiple files mode bce2eeb Reclassified some notification messages as errors 9e92bee stronger arm tests 2ed9dcc fix minor "divide by zero" risk 633c1ca fixed minor leak 0ed2e71 Static analyzer generates error codes on bug suspicion 2cf8a19 minor header refactoring 634e4ee Merge pull request #96 from t-mat/improve-pr-95 e328d41 minor optimization for small files 13c6e16 Removed status notification in multiple-files mode d153aaa Add LZ4F_OBSOLETE_ENUM() to describe obsolete enums a430b85 Multiple files decompression refactoring 4e574e7 Updated lz4frame error names d37926b Merge pull request #95 from t-mat/issue/90 240b554 Merge pull request #94 from t-mat/dev 3d46d4b Fix LZ4_DEPRECATED() in lz4hc.h 5f732e1 Merge pull request #91 from t-mat/dev 175890f Issue#90 : Change old enum names to new one 585bab8 Issue#90 : Change old enum to macro to maximize compatibility 081bcca Issue#90 : Add LZ4F_ prefix e1283c7 Fix LZ4_DEPRECATED() for older/non-gcc/clang/MSVC compilers d7298d2 Replace GCC_VERSION with LZ4_GCC_VERSION 9851583 Merge pull request #93 from drcrallen/descriptiveFrameErrors b664a72 Revert "Revert "Add more descriptive frame errors"" 3f4f623 Valgrind tests generate errors 83e350d Merge branch 'dev' of github.com:Cyan4973/lz4 into dev 066e9d3 Merge pull request #92 from Cyan4973/revert-89-descriptiveFrameErrors 5a66527 Revert "Add more descriptive frame errors" 0dc8308 Merge pull request #89 from drcrallen/descriptiveFrameErrors 05a46fc Changes LZ4F_compressBound() definition using NULL prefsPtr to cover worst case instead of default. 348f509 lz4io refactoring eabc6d8 New valgrind test with multiple files 113b150 Fix leak issue with compression of multiple files c64200d Improved performance when compressing a lot of small files cc24124 minor compatibility fixes ccba7a0 Merge pull request #86 from KyleJHarper/origin/r129/multiple_inputs_patch d535214 Add more descriptive frame errors bc28fc1 Merge pull request #87 from t-mat/fix-example2 fd77bad Replace obsolete functions b036eaa Add snprintf macro for MSVC 7f2f1fc Added support for continuation of file compression and decompression if input files are missing. Should more closely match gzip/bzip2/xz and so forth. Also removed a debug print accidentally left in. 0169502 Added new LZ4IO_decompressMultipleFilenames to allow decompression of multiple files with the -m switch added in r128 (ref: google code issue 151). Limitation: will only process files matching LZ4_EXTENSION macro, which for now seems reasonable. da11725 new memory leak test for fullbench using multi-files 2c79887 Shortened tests durations 42e5bc4 Updated badges 2852b9e Fixed issue #84 8f49666 Fixed : minor coverity warning 8a61000 Fixed a few coverity warnings 138673d fixed minor g++ warning cc8d617 Merge pull request #82 from t-mat/add-lz4-prefix 81fdd9d Fixed a few Valgrind warnings ad86910 Add LZ4 prefix to deprecation macros 66b8a4a Fixed : minor Visual warnings 62ed153 Fixed : a few minor coverity warnings 9443f3d Extended obsolete warning messages to lz4hc 973e385 Implemented obsolete warning message be9d248 Update lz4hc API : LZ4_compressHC_safe() a07db74 Clarified lz4frame.h inline doc 8b8e5ef fixed minor sanitize warning c22a0e1 Updated : fuzzer tests can be programmed for a timelength a2864fd Fixed a few minor sanitize warnings 33134fb Added : sanitize test f344fbd Fixed a few warnings from -fsanitize=undefined 2f8a4c3 New LZ4_compress_safe() API 1853622 fixed over-cautious visual warning b41137f minor Makefile test refactoring 327cb04 minor memory leak fix and test 43e0535 fix g++ typecast 61d7416 updated doc 17f8614 added : memtest on fullbench d38b0b6 Merge pull request #73 from funcodeio/dev 979a991 memcpy speed as reference 157a739 Merge pull request #74 from Cyan4973/fastMode dd69902 Removed unused lines. 43eaf8f Merge pull request #72 from fzort/master f72761f new tests for large files with content size support (#70) 90c0104 Added : progress indicator, in fast and decompression modes 1d3ab5d Cygwin has fileno, so there's no need to use _fileno. 78d2dfd fullbench : tests of _limitedOutput variants intentionnally provides less memory space than safe (LZ4_compressBound()) ef7cd83 Fixed issue 160, reported by Eric Berge 28e237e simplified LZ4_compress_limitedOutput() 89eee0d Removed make dist 0615eb4 Stricter tests : treat warnings as errors 76a03c1 simplified LZ4_compress_withState() 6625068 simplified LZ4_compress() 886b199 Modified files rights 7b5e945 Removed Visual 2013 solution, as AppVeyor automated mode only works with a single solution 117ab8c Added : Visual 2013 solution 08b24af Updated Visual 2012 solution : + 3 projects (fullbench, frametest, datagen) a761546 Fix : minor warning under Visual bf146ec Removed .suo & .user files from Visual solutions 7db6678 Restored proper credit 3bba55c Fixed : Windows compilation Added : Appveyor badge 160661c Merge pull request #69 from Cyan4973/dev 8437a0e Fixed : Visual compilation 7c26b03 Updated make dist f174964 Added : Frame documentation in MarkDown format 880381c Removed HTML Frame Format documentation 5b9fb69 minor tweak 4783cb8 Updated readme 4c227a4 Added LZ4_compress_fast() 003af71 Merge pull request #67 from Cyan4973/dev 2a82619 fixed fullbench memory allocation error 6c69dc1 faster compression in 64 bits mode 44793b8 Updated documentation b93f629 changed file name eeb8bea Updated comments on LZ4F_getFrameInfo() 002ec60 restored lz4hc compression ratio 987e78c Merge pull request #66 from Cyan4973/dev 8cb06d5 lz4frame validates contentSize during decompression d5da787 Changed struct member to contentSize 2d4fed5 Merge pull request #65 from Cyan4973/dev ce71b07 converted to markdown friendly syntax 1ba37f3 Reference format doc 5780864 Fixed : Makefile b009767 windows friendly make clean 27f7d06 minor beautifier (make clean) b4755c7 Added : arm cross-compilation test a357f43 Fixed cast-align warnings on 32-bits 4a9335b Added : doc authorship e652285 Merge pull request #63 from t-mat/comment-on-example-directory 2af52a9 Add "Examples" subtree 679afea Add README.md as table of contents 19665c9 Add document for "Line by Line Text Compression" example 438fee9 Add document for "Double Buffer" example a38166b Add document : "Streaming API Basics" 80e71c6 Updated man page : "--[no-]X" 5950f72 Updated tests 6b923d5 Updated long commands, with reverse "--no-" variants d0f8d40 updated dist list 00c3208 Merge pull request #61 from Cyan4973/dev 7f436a1 lz4 cli supports frame content size a28b147 removed useless man pages 7cf4e5c Updates tests & Man pages f02adc7 new long commands 86715b2 Some more tests related to frame content size 7ee7256 frame content size support 7d87d43 Updated lz4io sparse file support (alignment properties) b54d256 minor lz4frame optimisation (no more malloc() on using LZ4F_compressFrame() in fast mode) da9402c minor lz4frame refactoring 859fe3b Updated LZ4 frame format documentation 8edb7f1 Added : Readme into lib directory, to explain what does each file e7fb4d1 lz4 utility supports "pass-through" mode 2a02455 minor refactoring 3a68324 skippable frames support 93849d1 minor CMakeLists update 471eabe Merge pull request #60 from Cyberunner23/master ef029a1 Removed checking of CMAKE_SYSTEM_PROCESSOR when adding -fPIC, breaks when that var is '64bit'. c9a2b14 removed -s command from lz4c specific list of legacy commands 207aafd Added : unlz4 symbolic link to "lz4 -d" 2b55752 changed "make install" default install directory to /usr/local bbcfe21 Added : clang test 8a87769 Fix : static analyzer test on Travis 45b0642 scan-build tests a18fb43 Merge pull request #58 from Cyan4973/sparseFile 248b761 windows sparse file support d11ac40 Improved sparse files support 45a357f Improved sparse file support e38c268 Fixed minor g++ warnings 12ab415 Preliminary support for sparse files e3f33d2 Fixed minor warnings 74a6b14 Merge pull request #57 from alexDarcy/master f2cc4be Updated Cmake configuration for non-gnu compiler ceec6fa g++ compatibility 6b0c39b Updated datagen (can create sparse files) e277511 Merge pull request #54 from t-mat/gc-issue/155 e1d9b59 Fixed : static library (x64 binary) 32a85fc NetBSD compatibility (#48) 488029e Updated : compress multiple files 046bd3a Merge pull request #52 from KyleJHarper/r128/multiple_inputs dcdd628 Fix sentinel bit pattern de5c930 Fix sentinel size miscalculation eed7952 Add GNU coreutil's is_nul() method to isSparse() b372f45 Add Neil's method to isSparse() 01a24af Improve isSparse() 4a5d92b Adjust coding style 97679fa Google Code Issue 155: lz4 cli should support sparse file https://code.google.com/p/lz4/issues/detail?id=155 fa27d23 Added support for multiple input files to act more like other compressors. For example: gzip file1 file2 file3. You can now do: lz4 [args] -m file1 file2 file3. Fixes 151. 67f3b41 Merge pull request #49 from t-mat/msvc-fseeki64 e68d1c9 restored lz4 hc compression ratio 41b6ed3 Replace fseek with _fseeki64 to avoid MSVC's 2GiB barrier 8f4e201 Fix : lz4frame.h within uninstaller 9fd92de Added : Visual project directory git-subtree-dir: src/lz4 git-subtree-split: baf78e7e4dcbdf824a76f990ffeb573d113bbbdb
1517 lines
54 KiB
C
1517 lines
54 KiB
C
/*
|
|
LZ4 - Fast LZ compression algorithm
|
|
Copyright (C) 2011-2015, Yann Collet.
|
|
|
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are
|
|
met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above
|
|
copyright notice, this list of conditions and the following disclaimer
|
|
in the documentation and/or other materials provided with the
|
|
distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
You can contact the author at :
|
|
- LZ4 source repository : https://github.com/Cyan4973/lz4
|
|
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
|
*/
|
|
|
|
|
|
/**************************************
|
|
* Tuning parameters
|
|
**************************************/
|
|
/*
|
|
* HEAPMODE :
|
|
* Select how default compression functions will allocate memory for their hash table,
|
|
* in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).
|
|
*/
|
|
#define HEAPMODE 0
|
|
|
|
/*
|
|
* ACCELERATION_DEFAULT :
|
|
* Select "acceleration" for LZ4_compress_fast() when parameter value <= 0
|
|
*/
|
|
#define ACCELERATION_DEFAULT 1
|
|
|
|
|
|
/**************************************
|
|
* CPU Feature Detection
|
|
**************************************/
|
|
/*
|
|
* LZ4_FORCE_SW_BITCOUNT
|
|
* Define this parameter if your target system or compiler does not support hardware bit count
|
|
*/
|
|
#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */
|
|
# define LZ4_FORCE_SW_BITCOUNT
|
|
#endif
|
|
|
|
|
|
/**************************************
|
|
* Includes
|
|
**************************************/
|
|
#include "lz4.h"
|
|
|
|
|
|
/**************************************
|
|
* Compiler Options
|
|
**************************************/
|
|
#ifdef _MSC_VER /* Visual Studio */
|
|
# define FORCE_INLINE static __forceinline
|
|
# include <intrin.h>
|
|
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
|
# pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */
|
|
#else
|
|
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
|
|
# if defined(__GNUC__) || defined(__clang__)
|
|
# define FORCE_INLINE static inline __attribute__((always_inline))
|
|
# else
|
|
# define FORCE_INLINE static inline
|
|
# endif
|
|
# else
|
|
# define FORCE_INLINE static
|
|
# endif /* __STDC_VERSION__ */
|
|
#endif /* _MSC_VER */
|
|
|
|
/* LZ4_GCC_VERSION is defined into lz4.h */
|
|
#if (LZ4_GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
|
|
# define expect(expr,value) (__builtin_expect ((expr),(value)) )
|
|
#else
|
|
# define expect(expr,value) (expr)
|
|
#endif
|
|
|
|
#define likely(expr) expect((expr) != 0, 1)
|
|
#define unlikely(expr) expect((expr) != 0, 0)
|
|
|
|
|
|
/**************************************
|
|
* Memory routines
|
|
**************************************/
|
|
#include <stdlib.h> /* malloc, calloc, free */
|
|
#define ALLOCATOR(n,s) calloc(n,s)
|
|
#define FREEMEM free
|
|
#include <string.h> /* memset, memcpy */
|
|
#define MEM_INIT memset
|
|
|
|
|
|
/**************************************
|
|
* Basic Types
|
|
**************************************/
|
|
#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
|
|
# include <stdint.h>
|
|
typedef uint8_t BYTE;
|
|
typedef uint16_t U16;
|
|
typedef uint32_t U32;
|
|
typedef int32_t S32;
|
|
typedef uint64_t U64;
|
|
#else
|
|
typedef unsigned char BYTE;
|
|
typedef unsigned short U16;
|
|
typedef unsigned int U32;
|
|
typedef signed int S32;
|
|
typedef unsigned long long U64;
|
|
#endif
|
|
|
|
|
|
/**************************************
|
|
* Reading and writing into memory
|
|
**************************************/
|
|
#define STEPSIZE sizeof(size_t)
|
|
|
|
static unsigned LZ4_64bits(void) { return sizeof(void*)==8; }
|
|
|
|
static unsigned LZ4_isLittleEndian(void)
|
|
{
|
|
const union { U32 i; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
|
|
return one.c[0];
|
|
}
|
|
|
|
|
|
static U16 LZ4_read16(const void* memPtr)
|
|
{
|
|
U16 val16;
|
|
memcpy(&val16, memPtr, 2);
|
|
return val16;
|
|
}
|
|
|
|
static U16 LZ4_readLE16(const void* memPtr)
|
|
{
|
|
if (LZ4_isLittleEndian())
|
|
{
|
|
return LZ4_read16(memPtr);
|
|
}
|
|
else
|
|
{
|
|
const BYTE* p = (const BYTE*)memPtr;
|
|
return (U16)((U16)p[0] + (p[1]<<8));
|
|
}
|
|
}
|
|
|
|
static void LZ4_writeLE16(void* memPtr, U16 value)
|
|
{
|
|
if (LZ4_isLittleEndian())
|
|
{
|
|
memcpy(memPtr, &value, 2);
|
|
}
|
|
else
|
|
{
|
|
BYTE* p = (BYTE*)memPtr;
|
|
p[0] = (BYTE) value;
|
|
p[1] = (BYTE)(value>>8);
|
|
}
|
|
}
|
|
|
|
static U32 LZ4_read32(const void* memPtr)
|
|
{
|
|
U32 val32;
|
|
memcpy(&val32, memPtr, 4);
|
|
return val32;
|
|
}
|
|
|
|
static U64 LZ4_read64(const void* memPtr)
|
|
{
|
|
U64 val64;
|
|
memcpy(&val64, memPtr, 8);
|
|
return val64;
|
|
}
|
|
|
|
static size_t LZ4_read_ARCH(const void* p)
|
|
{
|
|
if (LZ4_64bits())
|
|
return (size_t)LZ4_read64(p);
|
|
else
|
|
return (size_t)LZ4_read32(p);
|
|
}
|
|
|
|
|
|
static void LZ4_copy4(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 4); }
|
|
|
|
static void LZ4_copy8(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 8); }
|
|
|
|
/* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */
|
|
static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
|
|
{
|
|
BYTE* d = (BYTE*)dstPtr;
|
|
const BYTE* s = (const BYTE*)srcPtr;
|
|
BYTE* e = (BYTE*)dstEnd;
|
|
do { LZ4_copy8(d,s); d+=8; s+=8; } while (d<e);
|
|
}
|
|
|
|
|
|
/**************************************
|
|
* Common Constants
|
|
**************************************/
|
|
#define MINMATCH 4
|
|
|
|
#define COPYLENGTH 8
|
|
#define LASTLITERALS 5
|
|
#define MFLIMIT (COPYLENGTH+MINMATCH)
|
|
static const int LZ4_minLength = (MFLIMIT+1);
|
|
|
|
#define KB *(1 <<10)
|
|
#define MB *(1 <<20)
|
|
#define GB *(1U<<30)
|
|
|
|
#define MAXD_LOG 16
|
|
#define MAX_DISTANCE ((1 << MAXD_LOG) - 1)
|
|
|
|
#define ML_BITS 4
|
|
#define ML_MASK ((1U<<ML_BITS)-1)
|
|
#define RUN_BITS (8-ML_BITS)
|
|
#define RUN_MASK ((1U<<RUN_BITS)-1)
|
|
|
|
|
|
/**************************************
|
|
* Common Utils
|
|
**************************************/
|
|
#define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
|
|
|
|
|
/**************************************
|
|
* Common functions
|
|
**************************************/
|
|
static unsigned LZ4_NbCommonBytes (register size_t val)
|
|
{
|
|
if (LZ4_isLittleEndian())
|
|
{
|
|
if (LZ4_64bits())
|
|
{
|
|
# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
|
|
unsigned long r = 0;
|
|
_BitScanForward64( &r, (U64)val );
|
|
return (int)(r>>3);
|
|
# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
|
|
return (__builtin_ctzll((U64)val) >> 3);
|
|
# else
|
|
static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
|
|
return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
|
|
# endif
|
|
}
|
|
else /* 32 bits */
|
|
{
|
|
# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
|
|
unsigned long r;
|
|
_BitScanForward( &r, (U32)val );
|
|
return (int)(r>>3);
|
|
# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
|
|
return (__builtin_ctz((U32)val) >> 3);
|
|
# else
|
|
static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
|
|
return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
|
|
# endif
|
|
}
|
|
}
|
|
else /* Big Endian CPU */
|
|
{
|
|
if (LZ4_64bits())
|
|
{
|
|
# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
|
|
unsigned long r = 0;
|
|
_BitScanReverse64( &r, val );
|
|
return (unsigned)(r>>3);
|
|
# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
|
|
return (__builtin_clzll((U64)val) >> 3);
|
|
# else
|
|
unsigned r;
|
|
if (!(val>>32)) { r=4; } else { r=0; val>>=32; }
|
|
if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
|
|
r += (!val);
|
|
return r;
|
|
# endif
|
|
}
|
|
else /* 32 bits */
|
|
{
|
|
# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
|
|
unsigned long r = 0;
|
|
_BitScanReverse( &r, (unsigned long)val );
|
|
return (unsigned)(r>>3);
|
|
# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
|
|
return (__builtin_clz((U32)val) >> 3);
|
|
# else
|
|
unsigned r;
|
|
if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
|
|
r += (!val);
|
|
return r;
|
|
# endif
|
|
}
|
|
}
|
|
}
|
|
|
|
static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
|
|
{
|
|
const BYTE* const pStart = pIn;
|
|
|
|
while (likely(pIn<pInLimit-(STEPSIZE-1)))
|
|
{
|
|
size_t diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);
|
|
if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }
|
|
pIn += LZ4_NbCommonBytes(diff);
|
|
return (unsigned)(pIn - pStart);
|
|
}
|
|
|
|
if (LZ4_64bits()) if ((pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }
|
|
if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }
|
|
if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
|
|
return (unsigned)(pIn - pStart);
|
|
}
|
|
|
|
|
|
#ifndef LZ4_COMMONDEFS_ONLY
|
|
/**************************************
|
|
* Local Constants
|
|
**************************************/
|
|
#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2)
|
|
#define HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
|
|
#define HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
|
|
|
|
static const int LZ4_64Klimit = ((64 KB) + (MFLIMIT-1));
|
|
static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression run slower on incompressible data */
|
|
|
|
|
|
/**************************************
|
|
* Local Structures and types
|
|
**************************************/
|
|
typedef struct {
|
|
U32 hashTable[HASH_SIZE_U32];
|
|
U32 currentOffset;
|
|
U32 initCheck;
|
|
const BYTE* dictionary;
|
|
BYTE* bufferStart; /* obsolete, used for slideInputBuffer */
|
|
U32 dictSize;
|
|
} LZ4_stream_t_internal;
|
|
|
|
typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive;
|
|
typedef enum { byPtr, byU32, byU16 } tableType_t;
|
|
|
|
typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
|
|
typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;
|
|
|
|
typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
|
|
typedef enum { full = 0, partial = 1 } earlyEnd_directive;
|
|
|
|
|
|
/**************************************
|
|
* Local Utils
|
|
**************************************/
|
|
int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }
|
|
int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); }
|
|
int LZ4_sizeofState() { return LZ4_STREAMSIZE; }
|
|
|
|
|
|
|
|
/********************************
|
|
* Compression functions
|
|
********************************/
|
|
|
|
static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType)
|
|
{
|
|
if (tableType == byU16)
|
|
return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
|
|
else
|
|
return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
|
|
}
|
|
|
|
static const U64 prime5bytes = 889523592379ULL;
|
|
static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType)
|
|
{
|
|
const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;
|
|
const U32 hashMask = (1<<hashLog) - 1;
|
|
return ((sequence * prime5bytes) >> (40 - hashLog)) & hashMask;
|
|
}
|
|
|
|
static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType)
|
|
{
|
|
if (LZ4_64bits())
|
|
return LZ4_hashSequence64(sequence, tableType);
|
|
return LZ4_hashSequence((U32)sequence, tableType);
|
|
}
|
|
|
|
static U32 LZ4_hashPosition(const void* p, tableType_t tableType) { return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); }
|
|
|
|
static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase)
|
|
{
|
|
switch (tableType)
|
|
{
|
|
case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }
|
|
case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }
|
|
case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }
|
|
}
|
|
}
|
|
|
|
static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
|
|
{
|
|
U32 h = LZ4_hashPosition(p, tableType);
|
|
LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
|
|
}
|
|
|
|
static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
|
|
{
|
|
if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }
|
|
if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }
|
|
{ U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
|
|
}
|
|
|
|
static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
|
|
{
|
|
U32 h = LZ4_hashPosition(p, tableType);
|
|
return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
|
|
}
|
|
|
|
FORCE_INLINE int LZ4_compress_generic(
|
|
void* const ctx,
|
|
const char* const source,
|
|
char* const dest,
|
|
const int inputSize,
|
|
const int maxOutputSize,
|
|
const limitedOutput_directive outputLimited,
|
|
const tableType_t tableType,
|
|
const dict_directive dict,
|
|
const dictIssue_directive dictIssue,
|
|
const U32 acceleration)
|
|
{
|
|
LZ4_stream_t_internal* const dictPtr = (LZ4_stream_t_internal*)ctx;
|
|
|
|
const BYTE* ip = (const BYTE*) source;
|
|
const BYTE* base;
|
|
const BYTE* lowLimit;
|
|
const BYTE* const lowRefLimit = ip - dictPtr->dictSize;
|
|
const BYTE* const dictionary = dictPtr->dictionary;
|
|
const BYTE* const dictEnd = dictionary + dictPtr->dictSize;
|
|
const size_t dictDelta = dictEnd - (const BYTE*)source;
|
|
const BYTE* anchor = (const BYTE*) source;
|
|
const BYTE* const iend = ip + inputSize;
|
|
const BYTE* const mflimit = iend - MFLIMIT;
|
|
const BYTE* const matchlimit = iend - LASTLITERALS;
|
|
|
|
BYTE* op = (BYTE*) dest;
|
|
BYTE* const olimit = op + maxOutputSize;
|
|
|
|
U32 forwardH;
|
|
size_t refDelta=0;
|
|
|
|
/* Init conditions */
|
|
if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */
|
|
switch(dict)
|
|
{
|
|
case noDict:
|
|
default:
|
|
base = (const BYTE*)source;
|
|
lowLimit = (const BYTE*)source;
|
|
break;
|
|
case withPrefix64k:
|
|
base = (const BYTE*)source - dictPtr->currentOffset;
|
|
lowLimit = (const BYTE*)source - dictPtr->dictSize;
|
|
break;
|
|
case usingExtDict:
|
|
base = (const BYTE*)source - dictPtr->currentOffset;
|
|
lowLimit = (const BYTE*)source;
|
|
break;
|
|
}
|
|
if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
|
|
if (inputSize<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
|
|
|
|
/* First Byte */
|
|
LZ4_putPosition(ip, ctx, tableType, base);
|
|
ip++; forwardH = LZ4_hashPosition(ip, tableType);
|
|
|
|
/* Main Loop */
|
|
for ( ; ; )
|
|
{
|
|
const BYTE* match;
|
|
BYTE* token;
|
|
{
|
|
const BYTE* forwardIp = ip;
|
|
unsigned step = 1;
|
|
unsigned searchMatchNb = acceleration << LZ4_skipTrigger;
|
|
|
|
/* Find a match */
|
|
do {
|
|
U32 h = forwardH;
|
|
ip = forwardIp;
|
|
forwardIp += step;
|
|
step = (searchMatchNb++ >> LZ4_skipTrigger);
|
|
|
|
if (unlikely(forwardIp > mflimit)) goto _last_literals;
|
|
|
|
match = LZ4_getPositionOnHash(h, ctx, tableType, base);
|
|
if (dict==usingExtDict)
|
|
{
|
|
if (match<(const BYTE*)source)
|
|
{
|
|
refDelta = dictDelta;
|
|
lowLimit = dictionary;
|
|
}
|
|
else
|
|
{
|
|
refDelta = 0;
|
|
lowLimit = (const BYTE*)source;
|
|
}
|
|
}
|
|
forwardH = LZ4_hashPosition(forwardIp, tableType);
|
|
LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
|
|
|
|
} while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0)
|
|
|| ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
|
|
|| (LZ4_read32(match+refDelta) != LZ4_read32(ip)) );
|
|
}
|
|
|
|
/* Catch up */
|
|
while ((ip>anchor) && (match+refDelta > lowLimit) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; }
|
|
|
|
{
|
|
/* Encode Literal length */
|
|
unsigned litLength = (unsigned)(ip - anchor);
|
|
token = op++;
|
|
if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
|
|
return 0; /* Check output limit */
|
|
if (litLength>=RUN_MASK)
|
|
{
|
|
int len = (int)litLength-RUN_MASK;
|
|
*token=(RUN_MASK<<ML_BITS);
|
|
for(; len >= 255 ; len-=255) *op++ = 255;
|
|
*op++ = (BYTE)len;
|
|
}
|
|
else *token = (BYTE)(litLength<<ML_BITS);
|
|
|
|
/* Copy Literals */
|
|
LZ4_wildCopy(op, anchor, op+litLength);
|
|
op+=litLength;
|
|
}
|
|
|
|
_next_match:
|
|
/* Encode Offset */
|
|
LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
|
|
|
|
/* Encode MatchLength */
|
|
{
|
|
unsigned matchLength;
|
|
|
|
if ((dict==usingExtDict) && (lowLimit==dictionary))
|
|
{
|
|
const BYTE* limit;
|
|
match += refDelta;
|
|
limit = ip + (dictEnd-match);
|
|
if (limit > matchlimit) limit = matchlimit;
|
|
matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);
|
|
ip += MINMATCH + matchLength;
|
|
if (ip==limit)
|
|
{
|
|
unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit);
|
|
matchLength += more;
|
|
ip += more;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
|
|
ip += MINMATCH + matchLength;
|
|
}
|
|
|
|
if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit)))
|
|
return 0; /* Check output limit */
|
|
if (matchLength>=ML_MASK)
|
|
{
|
|
*token += ML_MASK;
|
|
matchLength -= ML_MASK;
|
|
for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; }
|
|
if (matchLength >= 255) { matchLength-=255; *op++ = 255; }
|
|
*op++ = (BYTE)matchLength;
|
|
}
|
|
else *token += (BYTE)(matchLength);
|
|
}
|
|
|
|
anchor = ip;
|
|
|
|
/* Test end of chunk */
|
|
if (ip > mflimit) break;
|
|
|
|
/* Fill table */
|
|
LZ4_putPosition(ip-2, ctx, tableType, base);
|
|
|
|
/* Test next position */
|
|
match = LZ4_getPosition(ip, ctx, tableType, base);
|
|
if (dict==usingExtDict)
|
|
{
|
|
if (match<(const BYTE*)source)
|
|
{
|
|
refDelta = dictDelta;
|
|
lowLimit = dictionary;
|
|
}
|
|
else
|
|
{
|
|
refDelta = 0;
|
|
lowLimit = (const BYTE*)source;
|
|
}
|
|
}
|
|
LZ4_putPosition(ip, ctx, tableType, base);
|
|
if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1)
|
|
&& (match+MAX_DISTANCE>=ip)
|
|
&& (LZ4_read32(match+refDelta)==LZ4_read32(ip)) )
|
|
{ token=op++; *token=0; goto _next_match; }
|
|
|
|
/* Prepare next loop */
|
|
forwardH = LZ4_hashPosition(++ip, tableType);
|
|
}
|
|
|
|
_last_literals:
|
|
/* Encode Last Literals */
|
|
{
|
|
const size_t lastRun = (size_t)(iend - anchor);
|
|
if ((outputLimited) && ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize))
|
|
return 0; /* Check output limit */
|
|
if (lastRun >= RUN_MASK)
|
|
{
|
|
size_t accumulator = lastRun - RUN_MASK;
|
|
*op++ = RUN_MASK << ML_BITS;
|
|
for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
|
|
*op++ = (BYTE) accumulator;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (BYTE)(lastRun<<ML_BITS);
|
|
}
|
|
memcpy(op, anchor, lastRun);
|
|
op += lastRun;
|
|
}
|
|
|
|
/* End */
|
|
return (int) (((char*)op)-dest);
|
|
}
|
|
|
|
|
|
int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
|
|
{
|
|
LZ4_resetStream((LZ4_stream_t*)state);
|
|
if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
|
|
|
|
if (maxOutputSize >= LZ4_compressBound(inputSize))
|
|
{
|
|
if (inputSize < LZ4_64Klimit)
|
|
return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
|
|
else
|
|
return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
|
|
}
|
|
else
|
|
{
|
|
if (inputSize < LZ4_64Klimit)
|
|
return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
|
|
else
|
|
return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
|
|
}
|
|
}
|
|
|
|
|
|
int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
|
|
{
|
|
#if (HEAPMODE)
|
|
void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
|
|
#else
|
|
LZ4_stream_t ctx;
|
|
void* ctxPtr = &ctx;
|
|
#endif
|
|
|
|
int result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);
|
|
|
|
#if (HEAPMODE)
|
|
FREEMEM(ctxPtr);
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
|
|
int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize)
|
|
{
|
|
return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1);
|
|
}
|
|
|
|
|
|
/* hidden debug function */
|
|
/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */
|
|
int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
|
|
{
|
|
LZ4_stream_t ctx;
|
|
|
|
LZ4_resetStream(&ctx);
|
|
|
|
if (inputSize < LZ4_64Klimit)
|
|
return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
|
|
else
|
|
return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
|
|
}
|
|
|
|
|
|
/********************************
|
|
* destSize variant
|
|
********************************/
|
|
|
|
static int LZ4_compress_destSize_generic(
|
|
void* const ctx,
|
|
const char* const src,
|
|
char* const dst,
|
|
int* const srcSizePtr,
|
|
const int targetDstSize,
|
|
const tableType_t tableType)
|
|
{
|
|
const BYTE* ip = (const BYTE*) src;
|
|
const BYTE* base = (const BYTE*) src;
|
|
const BYTE* lowLimit = (const BYTE*) src;
|
|
const BYTE* anchor = ip;
|
|
const BYTE* const iend = ip + *srcSizePtr;
|
|
const BYTE* const mflimit = iend - MFLIMIT;
|
|
const BYTE* const matchlimit = iend - LASTLITERALS;
|
|
|
|
BYTE* op = (BYTE*) dst;
|
|
BYTE* const oend = op + targetDstSize;
|
|
BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */;
|
|
BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */);
|
|
BYTE* const oMaxSeq = oMaxLit - 1 /* token */;
|
|
|
|
U32 forwardH;
|
|
|
|
|
|
/* Init conditions */
|
|
if (targetDstSize < 1) return 0; /* Impossible to store anything */
|
|
if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */
|
|
if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
|
|
if (*srcSizePtr<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
|
|
|
|
/* First Byte */
|
|
*srcSizePtr = 0;
|
|
LZ4_putPosition(ip, ctx, tableType, base);
|
|
ip++; forwardH = LZ4_hashPosition(ip, tableType);
|
|
|
|
/* Main Loop */
|
|
for ( ; ; )
|
|
{
|
|
const BYTE* match;
|
|
BYTE* token;
|
|
{
|
|
const BYTE* forwardIp = ip;
|
|
unsigned step = 1;
|
|
unsigned searchMatchNb = 1 << LZ4_skipTrigger;
|
|
|
|
/* Find a match */
|
|
do {
|
|
U32 h = forwardH;
|
|
ip = forwardIp;
|
|
forwardIp += step;
|
|
step = (searchMatchNb++ >> LZ4_skipTrigger);
|
|
|
|
if (unlikely(forwardIp > mflimit))
|
|
goto _last_literals;
|
|
|
|
match = LZ4_getPositionOnHash(h, ctx, tableType, base);
|
|
forwardH = LZ4_hashPosition(forwardIp, tableType);
|
|
LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
|
|
|
|
} while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
|
|
|| (LZ4_read32(match) != LZ4_read32(ip)) );
|
|
}
|
|
|
|
/* Catch up */
|
|
while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }
|
|
|
|
{
|
|
/* Encode Literal length */
|
|
unsigned litLength = (unsigned)(ip - anchor);
|
|
token = op++;
|
|
if (op + ((litLength+240)/255) + litLength > oMaxLit)
|
|
{
|
|
/* Not enough space for a last match */
|
|
op--;
|
|
goto _last_literals;
|
|
}
|
|
if (litLength>=RUN_MASK)
|
|
{
|
|
unsigned len = litLength - RUN_MASK;
|
|
*token=(RUN_MASK<<ML_BITS);
|
|
for(; len >= 255 ; len-=255) *op++ = 255;
|
|
*op++ = (BYTE)len;
|
|
}
|
|
else *token = (BYTE)(litLength<<ML_BITS);
|
|
|
|
/* Copy Literals */
|
|
LZ4_wildCopy(op, anchor, op+litLength);
|
|
op += litLength;
|
|
}
|
|
|
|
_next_match:
|
|
/* Encode Offset */
|
|
LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
|
|
|
|
/* Encode MatchLength */
|
|
{
|
|
size_t matchLength;
|
|
|
|
matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
|
|
|
|
if (op + ((matchLength+240)/255) > oMaxMatch)
|
|
{
|
|
/* Match description too long : reduce it */
|
|
matchLength = (15-1) + (oMaxMatch-op) * 255;
|
|
}
|
|
//printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH);
|
|
ip += MINMATCH + matchLength;
|
|
|
|
if (matchLength>=ML_MASK)
|
|
{
|
|
*token += ML_MASK;
|
|
matchLength -= ML_MASK;
|
|
while (matchLength >= 255) { matchLength-=255; *op++ = 255; }
|
|
*op++ = (BYTE)matchLength;
|
|
}
|
|
else *token += (BYTE)(matchLength);
|
|
}
|
|
|
|
anchor = ip;
|
|
|
|
/* Test end of block */
|
|
if (ip > mflimit) break;
|
|
if (op > oMaxSeq) break;
|
|
|
|
/* Fill table */
|
|
LZ4_putPosition(ip-2, ctx, tableType, base);
|
|
|
|
/* Test next position */
|
|
match = LZ4_getPosition(ip, ctx, tableType, base);
|
|
LZ4_putPosition(ip, ctx, tableType, base);
|
|
if ( (match+MAX_DISTANCE>=ip)
|
|
&& (LZ4_read32(match)==LZ4_read32(ip)) )
|
|
{ token=op++; *token=0; goto _next_match; }
|
|
|
|
/* Prepare next loop */
|
|
forwardH = LZ4_hashPosition(++ip, tableType);
|
|
}
|
|
|
|
_last_literals:
|
|
/* Encode Last Literals */
|
|
{
|
|
size_t lastRunSize = (size_t)(iend - anchor);
|
|
if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend)
|
|
{
|
|
/* adapt lastRunSize to fill 'dst' */
|
|
lastRunSize = (oend-op) - 1;
|
|
lastRunSize -= (lastRunSize+240)/255;
|
|
}
|
|
ip = anchor + lastRunSize;
|
|
|
|
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);
|
|
op += lastRunSize;
|
|
}
|
|
|
|
/* End */
|
|
*srcSizePtr = (int) (((const char*)ip)-src);
|
|
return (int) (((char*)op)-dst);
|
|
}
|
|
|
|
|
|
static int LZ4_compress_destSize_extState (void* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize)
|
|
{
|
|
LZ4_resetStream((LZ4_stream_t*)state);
|
|
|
|
if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) /* compression success is guaranteed */
|
|
{
|
|
return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);
|
|
}
|
|
else
|
|
{
|
|
if (*srcSizePtr < LZ4_64Klimit)
|
|
return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, byU16);
|
|
else
|
|
return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, LZ4_64bits() ? byU32 : byPtr);
|
|
}
|
|
}
|
|
|
|
|
|
int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)
|
|
{
|
|
#if (HEAPMODE)
|
|
void* ctx = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
|
|
#else
|
|
LZ4_stream_t ctxBody;
|
|
void* ctx = &ctxBody;
|
|
#endif
|
|
|
|
int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);
|
|
|
|
#if (HEAPMODE)
|
|
FREEMEM(ctx);
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
/********************************
|
|
* Streaming functions
|
|
********************************/
|
|
|
|
LZ4_stream_t* LZ4_createStream(void)
|
|
{
|
|
LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64);
|
|
LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */
|
|
LZ4_resetStream(lz4s);
|
|
return lz4s;
|
|
}
|
|
|
|
void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
|
|
{
|
|
MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t));
|
|
}
|
|
|
|
int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
|
|
{
|
|
FREEMEM(LZ4_stream);
|
|
return (0);
|
|
}
|
|
|
|
|
|
#define HASH_UNIT sizeof(size_t)
|
|
int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)
|
|
{
|
|
LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict;
|
|
const BYTE* p = (const BYTE*)dictionary;
|
|
const BYTE* const dictEnd = p + dictSize;
|
|
const BYTE* base;
|
|
|
|
if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */
|
|
LZ4_resetStream(LZ4_dict);
|
|
|
|
if (dictSize < (int)HASH_UNIT)
|
|
{
|
|
dict->dictionary = NULL;
|
|
dict->dictSize = 0;
|
|
return 0;
|
|
}
|
|
|
|
if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;
|
|
dict->currentOffset += 64 KB;
|
|
base = p - dict->currentOffset;
|
|
dict->dictionary = p;
|
|
dict->dictSize = (U32)(dictEnd - p);
|
|
dict->currentOffset += dict->dictSize;
|
|
|
|
while (p <= dictEnd-HASH_UNIT)
|
|
{
|
|
LZ4_putPosition(p, dict->hashTable, byU32, base);
|
|
p+=3;
|
|
}
|
|
|
|
return dict->dictSize;
|
|
}
|
|
|
|
|
|
static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src)
|
|
{
|
|
if ((LZ4_dict->currentOffset > 0x80000000) ||
|
|
((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */
|
|
{
|
|
/* rescale hash table */
|
|
U32 delta = LZ4_dict->currentOffset - 64 KB;
|
|
const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;
|
|
int i;
|
|
for (i=0; i<HASH_SIZE_U32; i++)
|
|
{
|
|
if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;
|
|
else LZ4_dict->hashTable[i] -= delta;
|
|
}
|
|
LZ4_dict->currentOffset = 64 KB;
|
|
if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;
|
|
LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;
|
|
}
|
|
}
|
|
|
|
|
|
int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
|
|
{
|
|
LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream;
|
|
const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
|
|
|
|
const BYTE* smallest = (const BYTE*) source;
|
|
if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */
|
|
if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd;
|
|
LZ4_renormDictT(streamPtr, smallest);
|
|
if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
|
|
|
|
/* Check overlapping input/dictionary space */
|
|
{
|
|
const BYTE* sourceEnd = (const BYTE*) source + inputSize;
|
|
if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd))
|
|
{
|
|
streamPtr->dictSize = (U32)(dictEnd - sourceEnd);
|
|
if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;
|
|
if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;
|
|
streamPtr->dictionary = dictEnd - streamPtr->dictSize;
|
|
}
|
|
}
|
|
|
|
/* prefix mode : source data follows dictionary */
|
|
if (dictEnd == (const BYTE*)source)
|
|
{
|
|
int result;
|
|
if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
|
|
result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration);
|
|
else
|
|
result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration);
|
|
streamPtr->dictSize += (U32)inputSize;
|
|
streamPtr->currentOffset += (U32)inputSize;
|
|
return result;
|
|
}
|
|
|
|
/* external dictionary mode */
|
|
{
|
|
int result;
|
|
if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
|
|
result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration);
|
|
else
|
|
result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration);
|
|
streamPtr->dictionary = (const BYTE*)source;
|
|
streamPtr->dictSize = (U32)inputSize;
|
|
streamPtr->currentOffset += (U32)inputSize;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
/* Hidden debug function, to force external dictionary mode */
|
|
int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize)
|
|
{
|
|
LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict;
|
|
int result;
|
|
const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
|
|
|
|
const BYTE* smallest = dictEnd;
|
|
if (smallest > (const BYTE*) source) smallest = (const BYTE*) source;
|
|
LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest);
|
|
|
|
result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);
|
|
|
|
streamPtr->dictionary = (const BYTE*)source;
|
|
streamPtr->dictSize = (U32)inputSize;
|
|
streamPtr->currentOffset += (U32)inputSize;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)
|
|
{
|
|
LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict;
|
|
const BYTE* previousDictEnd = dict->dictionary + dict->dictSize;
|
|
|
|
if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */
|
|
if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize;
|
|
|
|
memmove(safeBuffer, previousDictEnd - dictSize, dictSize);
|
|
|
|
dict->dictionary = (const BYTE*)safeBuffer;
|
|
dict->dictSize = (U32)dictSize;
|
|
|
|
return dictSize;
|
|
}
|
|
|
|
|
|
|
|
/*******************************
|
|
* Decompression functions
|
|
*******************************/
|
|
/*
|
|
* This generic decompression function cover all use cases.
|
|
* It shall be instantiated several times, using different sets of directives
|
|
* Note that it is essential this generic function is really inlined,
|
|
* in order to remove useless branches during compilation optimization.
|
|
*/
|
|
FORCE_INLINE int LZ4_decompress_generic(
|
|
const char* const source,
|
|
char* const dest,
|
|
int inputSize,
|
|
int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */
|
|
|
|
int endOnInput, /* endOnOutputSize, endOnInputSize */
|
|
int partialDecoding, /* full, partial */
|
|
int targetOutputSize, /* only used if partialDecoding==partial */
|
|
int dict, /* noDict, withPrefix64k, usingExtDict */
|
|
const BYTE* const lowPrefix, /* == dest if dict == noDict */
|
|
const BYTE* const dictStart, /* only if dict==usingExtDict */
|
|
const size_t dictSize /* note : = 0 if noDict */
|
|
)
|
|
{
|
|
/* Local Variables */
|
|
const BYTE* ip = (const BYTE*) source;
|
|
const BYTE* const iend = ip + inputSize;
|
|
|
|
BYTE* op = (BYTE*) dest;
|
|
BYTE* const oend = op + outputSize;
|
|
BYTE* cpy;
|
|
BYTE* oexit = op + targetOutputSize;
|
|
const BYTE* const lowLimit = lowPrefix - dictSize;
|
|
|
|
const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize;
|
|
const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4};
|
|
const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
|
|
|
|
const int safeDecode = (endOnInput==endOnInputSize);
|
|
const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
|
|
|
|
|
|
/* Special cases */
|
|
if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */
|
|
if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
|
|
if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);
|
|
|
|
|
|
/* Main Loop */
|
|
while (1)
|
|
{
|
|
unsigned token;
|
|
size_t length;
|
|
const BYTE* match;
|
|
|
|
/* get literal length */
|
|
token = *ip++;
|
|
if ((length=(token>>ML_BITS)) == RUN_MASK)
|
|
{
|
|
unsigned s;
|
|
do
|
|
{
|
|
s = *ip++;
|
|
length += s;
|
|
}
|
|
while (likely((endOnInput)?ip<iend-RUN_MASK:1) && (s==255));
|
|
if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)(op))) goto _output_error; /* overflow detection */
|
|
if ((safeDecode) && unlikely((size_t)(ip+length)<(size_t)(ip))) goto _output_error; /* overflow detection */
|
|
}
|
|
|
|
/* copy literals */
|
|
cpy = op+length;
|
|
if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
|
|
|| ((!endOnInput) && (cpy>oend-COPYLENGTH)))
|
|
{
|
|
if (partialDecoding)
|
|
{
|
|
if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
|
|
if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
|
|
}
|
|
else
|
|
{
|
|
if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
|
|
if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
|
|
}
|
|
memcpy(op, ip, length);
|
|
ip += length;
|
|
op += length;
|
|
break; /* Necessarily EOF, due to parsing restrictions */
|
|
}
|
|
LZ4_wildCopy(op, ip, cpy);
|
|
ip += length; op = cpy;
|
|
|
|
/* get offset */
|
|
match = cpy - LZ4_readLE16(ip); ip+=2;
|
|
if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */
|
|
|
|
/* get matchlength */
|
|
length = token & ML_MASK;
|
|
if (length == ML_MASK)
|
|
{
|
|
unsigned s;
|
|
do
|
|
{
|
|
if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
|
|
s = *ip++;
|
|
length += s;
|
|
} while (s==255);
|
|
if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */
|
|
}
|
|
length += MINMATCH;
|
|
|
|
/* check external dictionary */
|
|
if ((dict==usingExtDict) && (match < lowPrefix))
|
|
{
|
|
if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */
|
|
|
|
if (length <= (size_t)(lowPrefix-match))
|
|
{
|
|
/* match can be copied as a single segment from external dictionary */
|
|
match = dictEnd - (lowPrefix-match);
|
|
memmove(op, match, length); op += length;
|
|
}
|
|
else
|
|
{
|
|
/* match encompass external dictionary and current segment */
|
|
size_t copySize = (size_t)(lowPrefix-match);
|
|
memcpy(op, dictEnd - copySize, copySize);
|
|
op += copySize;
|
|
copySize = length - copySize;
|
|
if (copySize > (size_t)(op-lowPrefix)) /* overlap within current segment */
|
|
{
|
|
BYTE* const endOfMatch = op + copySize;
|
|
const BYTE* copyFrom = lowPrefix;
|
|
while (op < endOfMatch) *op++ = *copyFrom++;
|
|
}
|
|
else
|
|
{
|
|
memcpy(op, lowPrefix, copySize);
|
|
op += copySize;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* copy repeated sequence */
|
|
cpy = op + length;
|
|
if (unlikely((op-match)<8))
|
|
{
|
|
const size_t dec64 = dec64table[op-match];
|
|
op[0] = match[0];
|
|
op[1] = match[1];
|
|
op[2] = match[2];
|
|
op[3] = match[3];
|
|
match += dec32table[op-match];
|
|
LZ4_copy4(op+4, match);
|
|
op += 8; match -= dec64;
|
|
} else { LZ4_copy8(op, match); op+=8; match+=8; }
|
|
|
|
if (unlikely(cpy>oend-12))
|
|
{
|
|
if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals */
|
|
if (op < oend-8)
|
|
{
|
|
LZ4_wildCopy(op, match, oend-8);
|
|
match += (oend-8) - op;
|
|
op = oend-8;
|
|
}
|
|
while (op<cpy) *op++ = *match++;
|
|
}
|
|
else
|
|
LZ4_wildCopy(op, match, cpy);
|
|
op=cpy; /* correction */
|
|
}
|
|
|
|
/* end of decoding */
|
|
if (endOnInput)
|
|
return (int) (((char*)op)-dest); /* Nb of output bytes decoded */
|
|
else
|
|
return (int) (((const char*)ip)-source); /* Nb of input bytes read */
|
|
|
|
/* Overflow error detected */
|
|
_output_error:
|
|
return (int) (-(((const char*)ip)-source))-1;
|
|
}
|
|
|
|
|
|
int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)
|
|
{
|
|
return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0);
|
|
}
|
|
|
|
int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize)
|
|
{
|
|
return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0);
|
|
}
|
|
|
|
int LZ4_decompress_fast(const char* source, char* dest, int originalSize)
|
|
{
|
|
return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB);
|
|
}
|
|
|
|
|
|
/* streaming decompression functions */
|
|
|
|
typedef struct
|
|
{
|
|
const BYTE* externalDict;
|
|
size_t extDictSize;
|
|
const BYTE* prefixEnd;
|
|
size_t prefixSize;
|
|
} LZ4_streamDecode_t_internal;
|
|
|
|
/*
|
|
* If you prefer dynamic allocation methods,
|
|
* LZ4_createStreamDecode()
|
|
* provides a pointer (void*) towards an initialized LZ4_streamDecode_t structure.
|
|
*/
|
|
LZ4_streamDecode_t* LZ4_createStreamDecode(void)
|
|
{
|
|
LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t));
|
|
return lz4s;
|
|
}
|
|
|
|
int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)
|
|
{
|
|
FREEMEM(LZ4_stream);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* LZ4_setStreamDecode
|
|
* Use this function to instruct where to find the dictionary
|
|
* This function is not necessary if previous data is still available where it was decoded.
|
|
* Loading a size of 0 is allowed (same effect as no dictionary).
|
|
* Return : 1 if OK, 0 if error
|
|
*/
|
|
int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)
|
|
{
|
|
LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
|
|
lz4sd->prefixSize = (size_t) dictSize;
|
|
lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;
|
|
lz4sd->externalDict = NULL;
|
|
lz4sd->extDictSize = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
*_continue() :
|
|
These decoding functions allow decompression of multiple blocks in "streaming" mode.
|
|
Previously decoded blocks must still be available at the memory position where they were decoded.
|
|
If it's not possible, save the relevant part of decoded data into a safe buffer,
|
|
and indicate where it stands using LZ4_setStreamDecode()
|
|
*/
|
|
int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)
|
|
{
|
|
LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
|
|
int result;
|
|
|
|
if (lz4sd->prefixEnd == (BYTE*)dest)
|
|
{
|
|
result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
|
|
endOnInputSize, full, 0,
|
|
usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
|
|
if (result <= 0) return result;
|
|
lz4sd->prefixSize += result;
|
|
lz4sd->prefixEnd += result;
|
|
}
|
|
else
|
|
{
|
|
lz4sd->extDictSize = lz4sd->prefixSize;
|
|
lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
|
|
result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
|
|
endOnInputSize, full, 0,
|
|
usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
|
|
if (result <= 0) return result;
|
|
lz4sd->prefixSize = result;
|
|
lz4sd->prefixEnd = (BYTE*)dest + result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize)
|
|
{
|
|
LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
|
|
int result;
|
|
|
|
if (lz4sd->prefixEnd == (BYTE*)dest)
|
|
{
|
|
result = LZ4_decompress_generic(source, dest, 0, originalSize,
|
|
endOnOutputSize, full, 0,
|
|
usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
|
|
if (result <= 0) return result;
|
|
lz4sd->prefixSize += originalSize;
|
|
lz4sd->prefixEnd += originalSize;
|
|
}
|
|
else
|
|
{
|
|
lz4sd->extDictSize = lz4sd->prefixSize;
|
|
lz4sd->externalDict = (BYTE*)dest - lz4sd->extDictSize;
|
|
result = LZ4_decompress_generic(source, dest, 0, originalSize,
|
|
endOnOutputSize, full, 0,
|
|
usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
|
|
if (result <= 0) return result;
|
|
lz4sd->prefixSize = originalSize;
|
|
lz4sd->prefixEnd = (BYTE*)dest + originalSize;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
Advanced decoding functions :
|
|
*_usingDict() :
|
|
These decoding functions work the same as "_continue" ones,
|
|
the dictionary must be explicitly provided within parameters
|
|
*/
|
|
|
|
FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize)
|
|
{
|
|
if (dictSize==0)
|
|
return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0);
|
|
if (dictStart+dictSize == dest)
|
|
{
|
|
if (dictSize >= (int)(64 KB - 1))
|
|
return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0);
|
|
return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0);
|
|
}
|
|
return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
|
|
}
|
|
|
|
int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
|
|
{
|
|
return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize);
|
|
}
|
|
|
|
int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)
|
|
{
|
|
return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize);
|
|
}
|
|
|
|
/* debug function */
|
|
int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
|
|
{
|
|
return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
|
|
}
|
|
|
|
|
|
/***************************************************
|
|
* Obsolete Functions
|
|
***************************************************/
|
|
/* obsolete compression functions */
|
|
int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); }
|
|
int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); }
|
|
int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); }
|
|
int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); }
|
|
int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); }
|
|
int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); }
|
|
|
|
/*
|
|
These function names are deprecated and should no longer be used.
|
|
They are only provided here for compatibility with older user programs.
|
|
- LZ4_uncompress is totally equivalent to LZ4_decompress_fast
|
|
- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe
|
|
*/
|
|
int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }
|
|
int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }
|
|
|
|
|
|
/* Obsolete Streaming functions */
|
|
|
|
int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; }
|
|
|
|
static void LZ4_init(LZ4_stream_t_internal* lz4ds, BYTE* base)
|
|
{
|
|
MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE);
|
|
lz4ds->bufferStart = base;
|
|
}
|
|
|
|
int LZ4_resetStreamState(void* state, char* inputBuffer)
|
|
{
|
|
if ((((size_t)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */
|
|
LZ4_init((LZ4_stream_t_internal*)state, (BYTE*)inputBuffer);
|
|
return 0;
|
|
}
|
|
|
|
void* LZ4_create (char* inputBuffer)
|
|
{
|
|
void* lz4ds = ALLOCATOR(8, LZ4_STREAMSIZE_U64);
|
|
LZ4_init ((LZ4_stream_t_internal*)lz4ds, (BYTE*)inputBuffer);
|
|
return lz4ds;
|
|
}
|
|
|
|
char* LZ4_slideInputBuffer (void* LZ4_Data)
|
|
{
|
|
LZ4_stream_t_internal* ctx = (LZ4_stream_t_internal*)LZ4_Data;
|
|
int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB);
|
|
return (char*)(ctx->bufferStart + dictSize);
|
|
}
|
|
|
|
/* Obsolete streaming decompression functions */
|
|
|
|
int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)
|
|
{
|
|
return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
|
|
}
|
|
|
|
int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)
|
|
{
|
|
return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
|
|
}
|
|
|
|
#endif /* LZ4_COMMONDEFS_ONLY */
|
|
|