110ae99eeSToomas Soome /*
210ae99eeSToomas Soome * LZ4 - Fast LZ compression algorithm
310ae99eeSToomas Soome * Header File
410ae99eeSToomas Soome * Copyright (C) 2011-2013, Yann Collet.
510ae99eeSToomas Soome * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
610ae99eeSToomas Soome *
710ae99eeSToomas Soome * Redistribution and use in source and binary forms, with or without
810ae99eeSToomas Soome * modification, are permitted provided that the following conditions are
910ae99eeSToomas Soome * met:
1010ae99eeSToomas Soome *
1110ae99eeSToomas Soome * * Redistributions of source code must retain the above copyright
1210ae99eeSToomas Soome * notice, this list of conditions and the following disclaimer.
1310ae99eeSToomas Soome * * Redistributions in binary form must reproduce the above
1410ae99eeSToomas Soome * copyright notice, this list of conditions and the following disclaimer
1510ae99eeSToomas Soome * in the documentation and/or other materials provided with the
1610ae99eeSToomas Soome * distribution.
1710ae99eeSToomas Soome *
1810ae99eeSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1910ae99eeSToomas Soome * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2010ae99eeSToomas Soome * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2110ae99eeSToomas Soome * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2210ae99eeSToomas Soome * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2310ae99eeSToomas Soome * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2410ae99eeSToomas Soome * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2510ae99eeSToomas Soome * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2610ae99eeSToomas Soome * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2710ae99eeSToomas Soome * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2810ae99eeSToomas Soome * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2910ae99eeSToomas Soome *
3010ae99eeSToomas Soome * You can contact the author at :
3110ae99eeSToomas Soome * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
3210ae99eeSToomas Soome * - LZ4 source repository : http://code.google.com/p/lz4/
3310ae99eeSToomas Soome */
3410ae99eeSToomas Soome /*
3510ae99eeSToomas Soome * Copyright (c) 2016 by Delphix. All rights reserved.
36*cab7c30cSAndy Fiddaman * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
3710ae99eeSToomas Soome */
3810ae99eeSToomas Soome
3910ae99eeSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL)
4010ae99eeSToomas Soome #include <sys/zfs_context.h>
4110ae99eeSToomas Soome #elif defined(_STANDALONE)
4210ae99eeSToomas Soome #include <sys/cdefs.h>
4310ae99eeSToomas Soome #include <stand.h>
4410ae99eeSToomas Soome #include <sys/types.h>
4510ae99eeSToomas Soome #include <sys/endian.h>
4610ae99eeSToomas Soome #include <assert.h>
4710ae99eeSToomas Soome
4810ae99eeSToomas Soome #define ASSERT assert
4910ae99eeSToomas Soome #else
5010ae99eeSToomas Soome #include <string.h>
5110ae99eeSToomas Soome #include <stdlib.h>
5210ae99eeSToomas Soome #include <sys/types.h>
5310ae99eeSToomas Soome #include <sys/sysmacros.h>
5410ae99eeSToomas Soome #include <netinet/in.h>
5510ae99eeSToomas Soome #include <assert.h>
5610ae99eeSToomas Soome
5710ae99eeSToomas Soome #define ASSERT assert
5810ae99eeSToomas Soome #endif
5910ae99eeSToomas Soome #include <lz4.h>
6010ae99eeSToomas Soome
6110ae99eeSToomas Soome static int real_LZ4_compress(const char *source, char *dest, int isize,
6210ae99eeSToomas Soome int osize);
6310ae99eeSToomas Soome static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest,
6410ae99eeSToomas Soome int isize, int maxOutputSize);
6510ae99eeSToomas Soome static int LZ4_compressCtx(void *ctx, const char *source, char *dest,
6610ae99eeSToomas Soome int isize, int osize);
6710ae99eeSToomas Soome static int LZ4_compress64kCtx(void *ctx, const char *source, char *dest,
6810ae99eeSToomas Soome int isize, int osize);
6910ae99eeSToomas Soome
7010ae99eeSToomas Soome size_t
lz4_compress(void * s_start,void * d_start,size_t s_len,size_t d_len,int n __unused)7110ae99eeSToomas Soome lz4_compress(void *s_start, void *d_start, size_t s_len, size_t d_len,
7210ae99eeSToomas Soome int n __unused)
7310ae99eeSToomas Soome {
7410ae99eeSToomas Soome uint32_t bufsiz;
7510ae99eeSToomas Soome char *dest = d_start;
7610ae99eeSToomas Soome
7710ae99eeSToomas Soome ASSERT(d_len >= sizeof (bufsiz));
7810ae99eeSToomas Soome
7910ae99eeSToomas Soome bufsiz = real_LZ4_compress(s_start, &dest[sizeof (bufsiz)], s_len,
8010ae99eeSToomas Soome d_len - sizeof (bufsiz));
8110ae99eeSToomas Soome
8210ae99eeSToomas Soome /* Signal an error if the compression routine returned zero. */
8310ae99eeSToomas Soome if (bufsiz == 0)
8410ae99eeSToomas Soome return (s_len);
8510ae99eeSToomas Soome
8610ae99eeSToomas Soome /*
8710ae99eeSToomas Soome * Encode the compresed buffer size at the start. We'll need this in
8810ae99eeSToomas Soome * decompression to counter the effects of padding which might be
8910ae99eeSToomas Soome * added to the compressed buffer and which, if unhandled, would
9010ae99eeSToomas Soome * confuse the hell out of our decompression function.
9110ae99eeSToomas Soome */
9210ae99eeSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL)
9310ae99eeSToomas Soome *(uint32_t *)(void *)dest = BE_32(bufsiz);
9410ae99eeSToomas Soome #else
9510ae99eeSToomas Soome *(uint32_t *)(void *)dest = htonl(bufsiz);
9610ae99eeSToomas Soome #endif
9710ae99eeSToomas Soome
9810ae99eeSToomas Soome return (bufsiz + sizeof (bufsiz));
9910ae99eeSToomas Soome }
10010ae99eeSToomas Soome
10110ae99eeSToomas Soome int
lz4_decompress(void * s_start,void * d_start,size_t s_len,size_t d_len,int n __unused)10210ae99eeSToomas Soome lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len,
10310ae99eeSToomas Soome int n __unused)
10410ae99eeSToomas Soome {
10510ae99eeSToomas Soome const char *src = s_start;
10610ae99eeSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL)
10710ae99eeSToomas Soome uint32_t bufsiz = BE_IN32(s_start);
10810ae99eeSToomas Soome #else
10910ae99eeSToomas Soome uint32_t bufsiz = htonl(*(uint32_t *)s_start);
11010ae99eeSToomas Soome #endif
11110ae99eeSToomas Soome
11210ae99eeSToomas Soome /* invalid compressed buffer size encoded at start */
11310ae99eeSToomas Soome if (bufsiz + sizeof (bufsiz) > s_len)
11410ae99eeSToomas Soome return (1);
11510ae99eeSToomas Soome
11610ae99eeSToomas Soome /*
11710ae99eeSToomas Soome * Returns 0 on success (decompression function returned non-negative)
11810ae99eeSToomas Soome * and non-zero on failure (decompression function returned negative).
11910ae99eeSToomas Soome */
12010ae99eeSToomas Soome return (LZ4_uncompress_unknownOutputSize(&src[sizeof (bufsiz)],
12110ae99eeSToomas Soome d_start, bufsiz, d_len) < 0);
12210ae99eeSToomas Soome }
12310ae99eeSToomas Soome
12410ae99eeSToomas Soome /*
12510ae99eeSToomas Soome * LZ4 API Description:
12610ae99eeSToomas Soome *
12710ae99eeSToomas Soome * Simple Functions:
12810ae99eeSToomas Soome * real_LZ4_compress() :
12910ae99eeSToomas Soome * isize : is the input size. Max supported value is ~1.9GB
13010ae99eeSToomas Soome * return : the number of bytes written in buffer dest
13110ae99eeSToomas Soome * or 0 if the compression fails (if LZ4_COMPRESSMIN is set).
13210ae99eeSToomas Soome * note : destination buffer must be already allocated.
13310ae99eeSToomas Soome * destination buffer must be sized to handle worst cases
13410ae99eeSToomas Soome * situations (input data not compressible).
13510ae99eeSToomas Soome *
13610ae99eeSToomas Soome * Advanced Functions
13710ae99eeSToomas Soome *
13810ae99eeSToomas Soome * LZ4_compressBound() :
13910ae99eeSToomas Soome * Provides the maximum size that LZ4 may output in a "worst case"
14010ae99eeSToomas Soome * scenario (input data not compressible) primarily useful for memory
14110ae99eeSToomas Soome * allocation of output buffer.
14210ae99eeSToomas Soome *
14310ae99eeSToomas Soome * isize : is the input size. Max supported value is ~1.9GB
14410ae99eeSToomas Soome * return : maximum output size in a "worst case" scenario
14510ae99eeSToomas Soome * note : this function is limited by "int" range (2^31-1)
14610ae99eeSToomas Soome *
14710ae99eeSToomas Soome * LZ4_uncompress_unknownOutputSize() :
14810ae99eeSToomas Soome * isize : is the input size, therefore the compressed size
14910ae99eeSToomas Soome * maxOutputSize : is the size of the destination buffer (which must be
15010ae99eeSToomas Soome * already allocated)
15110ae99eeSToomas Soome * return : the number of bytes decoded in the destination buffer
15210ae99eeSToomas Soome * (necessarily <= maxOutputSize). If the source stream is
15310ae99eeSToomas Soome * malformed, the function will stop decoding and return a
15410ae99eeSToomas Soome * negative result, indicating the byte position of the faulty
15510ae99eeSToomas Soome * instruction. This function never writes beyond dest +
15610ae99eeSToomas Soome * maxOutputSize, and is therefore protected against malicious
15710ae99eeSToomas Soome * data packets.
15810ae99eeSToomas Soome * note : Destination buffer must be already allocated.
15910ae99eeSToomas Soome *
16010ae99eeSToomas Soome * LZ4_compressCtx() :
16110ae99eeSToomas Soome * This function explicitly handles the CTX memory structure.
16210ae99eeSToomas Soome *
16310ae99eeSToomas Soome * ILLUMOS CHANGES: the CTX memory structure must be explicitly allocated
16410ae99eeSToomas Soome * by the caller (either on the stack or using kmem_zalloc). Passing NULL
16510ae99eeSToomas Soome * isn't valid.
16610ae99eeSToomas Soome *
16710ae99eeSToomas Soome * LZ4_compress64kCtx() :
16810ae99eeSToomas Soome * Same as LZ4_compressCtx(), but specific to small inputs (<64KB).
16910ae99eeSToomas Soome * isize *Must* be <64KB, otherwise the output will be corrupted.
17010ae99eeSToomas Soome *
17110ae99eeSToomas Soome * ILLUMOS CHANGES: the CTX memory structure must be explicitly allocated
17210ae99eeSToomas Soome * by the caller (either on the stack or using kmem_zalloc). Passing NULL
17310ae99eeSToomas Soome * isn't valid.
17410ae99eeSToomas Soome */
17510ae99eeSToomas Soome
17610ae99eeSToomas Soome /*
17710ae99eeSToomas Soome * Tuning parameters
17810ae99eeSToomas Soome */
17910ae99eeSToomas Soome
18010ae99eeSToomas Soome /*
18110ae99eeSToomas Soome * COMPRESSIONLEVEL: Increasing this value improves compression ratio
18210ae99eeSToomas Soome * Lowering this value reduces memory usage. Reduced memory usage
18310ae99eeSToomas Soome * typically improves speed, due to cache effect (ex: L1 32KB for Intel,
18410ae99eeSToomas Soome * L1 64KB for AMD). Memory usage formula : N->2^(N+2) Bytes
18510ae99eeSToomas Soome * (examples : 12 -> 16KB ; 17 -> 512KB)
18610ae99eeSToomas Soome */
18710ae99eeSToomas Soome #define COMPRESSIONLEVEL 12
18810ae99eeSToomas Soome
18910ae99eeSToomas Soome /*
19010ae99eeSToomas Soome * NOTCOMPRESSIBLE_CONFIRMATION: Decreasing this value will make the
19110ae99eeSToomas Soome * algorithm skip faster data segments considered "incompressible".
19210ae99eeSToomas Soome * This may decrease compression ratio dramatically, but will be
19310ae99eeSToomas Soome * faster on incompressible data. Increasing this value will make
19410ae99eeSToomas Soome * the algorithm search more before declaring a segment "incompressible".
19510ae99eeSToomas Soome * This could improve compression a bit, but will be slower on
19610ae99eeSToomas Soome * incompressible data. The default value (6) is recommended.
19710ae99eeSToomas Soome */
19810ae99eeSToomas Soome #define NOTCOMPRESSIBLE_CONFIRMATION 6
19910ae99eeSToomas Soome
20010ae99eeSToomas Soome /*
20110ae99eeSToomas Soome * BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE: This will provide a boost to
20210ae99eeSToomas Soome * performance for big endian cpu, but the resulting compressed stream
20310ae99eeSToomas Soome * will be incompatible with little-endian CPU. You can set this option
20410ae99eeSToomas Soome * to 1 in situations where data will stay within closed environment.
20510ae99eeSToomas Soome * This option is useless on Little_Endian CPU (such as x86).
20610ae99eeSToomas Soome */
20710ae99eeSToomas Soome /* #define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 */
20810ae99eeSToomas Soome
20910ae99eeSToomas Soome /*
21010ae99eeSToomas Soome * CPU Feature Detection
21110ae99eeSToomas Soome */
21210ae99eeSToomas Soome
21310ae99eeSToomas Soome /* 32 or 64 bits ? */
21410ae99eeSToomas Soome #if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || \
21510ae99eeSToomas Soome defined(__amd64) || defined(__ppc64__) || defined(_WIN64) || \
21610ae99eeSToomas Soome defined(__LP64__) || defined(_LP64))
21710ae99eeSToomas Soome #define LZ4_ARCH64 1
21810ae99eeSToomas Soome #else
21910ae99eeSToomas Soome #define LZ4_ARCH64 0
22010ae99eeSToomas Soome #endif
22110ae99eeSToomas Soome
22210ae99eeSToomas Soome /*
22310ae99eeSToomas Soome * Limits the amount of stack space that the algorithm may consume to hold
22410ae99eeSToomas Soome * the compression lookup table. The value `9' here means we'll never use
22510ae99eeSToomas Soome * more than 2k of stack (see above for a description of COMPRESSIONLEVEL).
22610ae99eeSToomas Soome * If more memory is needed, it is allocated from the heap.
22710ae99eeSToomas Soome */
22810ae99eeSToomas Soome #define STACKLIMIT 9
22910ae99eeSToomas Soome
23010ae99eeSToomas Soome /*
23110ae99eeSToomas Soome * Little Endian or Big Endian?
23210ae99eeSToomas Soome * Note: overwrite the below #define if you know your architecture endianess.
23310ae99eeSToomas Soome */
23410ae99eeSToomas Soome #if defined(BYTE_ORDER)
23510ae99eeSToomas Soome #if BYTE_ORDER == BIG_ENDIAN /* This is sys/endian.h API */
23610ae99eeSToomas Soome #define LZ4_BIG_ENDIAN 1
23710ae99eeSToomas Soome #else
23810ae99eeSToomas Soome /*
23910ae99eeSToomas Soome * Little Endian assumed. PDP Endian and other very rare endian format
24010ae99eeSToomas Soome * are unsupported.
24110ae99eeSToomas Soome */
24210ae99eeSToomas Soome #endif
24310ae99eeSToomas Soome #else /* !defined(BYTE_ORDER) */
24410ae99eeSToomas Soome #if (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || \
24510ae99eeSToomas Soome defined(_BIG_ENDIAN) || defined(_ARCH_PPC) || defined(__PPC__) || \
24610ae99eeSToomas Soome defined(__PPC) || defined(PPC) || defined(__powerpc__) || \
24710ae99eeSToomas Soome defined(__powerpc) || defined(powerpc) || \
24810ae99eeSToomas Soome ((defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))))
24910ae99eeSToomas Soome #define LZ4_BIG_ENDIAN 1
25010ae99eeSToomas Soome #else
25110ae99eeSToomas Soome /*
25210ae99eeSToomas Soome * Little Endian assumed. PDP Endian and other very rare endian format
25310ae99eeSToomas Soome * are unsupported.
25410ae99eeSToomas Soome */
25510ae99eeSToomas Soome #endif
25610ae99eeSToomas Soome #endif /* defined(BYTE_ORDER) */
25710ae99eeSToomas Soome
25810ae99eeSToomas Soome /*
25910ae99eeSToomas Soome * Unaligned memory access is automatically enabled for "common" CPU,
26010ae99eeSToomas Soome * such as x86. For others CPU, the compiler will be more cautious, and
26110ae99eeSToomas Soome * insert extra code to ensure aligned access is respected. If you know
26210ae99eeSToomas Soome * your target CPU supports unaligned memory access, you may want to
26310ae99eeSToomas Soome * force this option manually to improve performance
26410ae99eeSToomas Soome */
26510ae99eeSToomas Soome #if defined(__ARM_FEATURE_UNALIGNED)
26610ae99eeSToomas Soome #define LZ4_FORCE_UNALIGNED_ACCESS 1
26710ae99eeSToomas Soome #endif
26810ae99eeSToomas Soome
26910ae99eeSToomas Soome #ifdef __sparc
27010ae99eeSToomas Soome #define LZ4_FORCE_SW_BITCOUNT
27110ae99eeSToomas Soome #endif
27210ae99eeSToomas Soome
27310ae99eeSToomas Soome /*
27410ae99eeSToomas Soome * Compiler Options
27510ae99eeSToomas Soome */
27610ae99eeSToomas Soome #if __STDC_VERSION__ >= 199901L /* C99 */
27710ae99eeSToomas Soome /* "restrict" is a known keyword */
27810ae99eeSToomas Soome #else
27910ae99eeSToomas Soome /* Disable restrict */
28010ae99eeSToomas Soome #define restrict
28110ae99eeSToomas Soome #endif
28210ae99eeSToomas Soome
28310ae99eeSToomas Soome #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
28410ae99eeSToomas Soome
28510ae99eeSToomas Soome #ifdef _MSC_VER
28610ae99eeSToomas Soome /* Visual Studio */
28710ae99eeSToomas Soome /* Visual is not C99, but supports some kind of inline */
28810ae99eeSToomas Soome #define inline __forceinline
28910ae99eeSToomas Soome #if LZ4_ARCH64
29010ae99eeSToomas Soome /* For Visual 2005 */
29110ae99eeSToomas Soome #pragma intrinsic(_BitScanForward64)
29210ae99eeSToomas Soome #pragma intrinsic(_BitScanReverse64)
29310ae99eeSToomas Soome #else /* !LZ4_ARCH64 */
29410ae99eeSToomas Soome /* For Visual 2005 */
29510ae99eeSToomas Soome #pragma intrinsic(_BitScanForward)
29610ae99eeSToomas Soome #pragma intrinsic(_BitScanReverse)
29710ae99eeSToomas Soome #endif /* !LZ4_ARCH64 */
29810ae99eeSToomas Soome #endif /* _MSC_VER */
29910ae99eeSToomas Soome
30010ae99eeSToomas Soome #ifdef _MSC_VER
30110ae99eeSToomas Soome #define lz4_bswap16(x) _byteswap_ushort(x)
30210ae99eeSToomas Soome #else /* !_MSC_VER */
30310ae99eeSToomas Soome #define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | \
30410ae99eeSToomas Soome (((x) & 0xffu) << 8)))
30510ae99eeSToomas Soome #endif /* !_MSC_VER */
30610ae99eeSToomas Soome
30710ae99eeSToomas Soome #if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
30810ae99eeSToomas Soome #define expect(expr, value) (__builtin_expect((expr), (value)))
30910ae99eeSToomas Soome #else
31010ae99eeSToomas Soome #define expect(expr, value) (expr)
31110ae99eeSToomas Soome #endif
31210ae99eeSToomas Soome
31310ae99eeSToomas Soome #ifndef likely
31410ae99eeSToomas Soome #define likely(expr) expect((expr) != 0, 1)
31510ae99eeSToomas Soome #endif
31610ae99eeSToomas Soome
31710ae99eeSToomas Soome #ifndef unlikely
31810ae99eeSToomas Soome #define unlikely(expr) expect((expr) != 0, 0)
31910ae99eeSToomas Soome #endif
32010ae99eeSToomas Soome
32110ae99eeSToomas Soome /* Basic types */
32210ae99eeSToomas Soome #if defined(_MSC_VER)
32310ae99eeSToomas Soome /* Visual Studio does not support 'stdint' natively */
32410ae99eeSToomas Soome #define BYTE unsigned __int8
32510ae99eeSToomas Soome #define U16 unsigned __int16
32610ae99eeSToomas Soome #define U32 unsigned __int32
32710ae99eeSToomas Soome #define S32 __int32
32810ae99eeSToomas Soome #define U64 unsigned __int64
32910ae99eeSToomas Soome #else /* !defined(_MSC_VER) */
33010ae99eeSToomas Soome #define BYTE uint8_t
33110ae99eeSToomas Soome #define U16 uint16_t
33210ae99eeSToomas Soome #define U32 uint32_t
33310ae99eeSToomas Soome #define S32 int32_t
33410ae99eeSToomas Soome #define U64 uint64_t
33510ae99eeSToomas Soome #endif /* !defined(_MSC_VER) */
33610ae99eeSToomas Soome
33710ae99eeSToomas Soome #ifndef LZ4_FORCE_UNALIGNED_ACCESS
33810ae99eeSToomas Soome #pragma pack(1)
33910ae99eeSToomas Soome #endif
34010ae99eeSToomas Soome
34110ae99eeSToomas Soome typedef struct _U16_S {
34210ae99eeSToomas Soome U16 v;
34310ae99eeSToomas Soome } U16_S;
34410ae99eeSToomas Soome typedef struct _U32_S {
34510ae99eeSToomas Soome U32 v;
34610ae99eeSToomas Soome } U32_S;
34710ae99eeSToomas Soome typedef struct _U64_S {
34810ae99eeSToomas Soome U64 v;
34910ae99eeSToomas Soome } U64_S;
35010ae99eeSToomas Soome
35110ae99eeSToomas Soome #ifndef LZ4_FORCE_UNALIGNED_ACCESS
35210ae99eeSToomas Soome #pragma pack()
35310ae99eeSToomas Soome #endif
35410ae99eeSToomas Soome
35510ae99eeSToomas Soome #define A64(x) (((U64_S *)(__DECONST(void *, x)))->v)
35610ae99eeSToomas Soome #define A32(x) (((U32_S *)(__DECONST(void *, x)))->v)
35710ae99eeSToomas Soome #define A16(x) (((U16_S *)(__DECONST(void *, x)))->v)
35810ae99eeSToomas Soome
35910ae99eeSToomas Soome /*
36010ae99eeSToomas Soome * Constants
36110ae99eeSToomas Soome */
36210ae99eeSToomas Soome #define MINMATCH 4
36310ae99eeSToomas Soome
36410ae99eeSToomas Soome #define HASH_LOG COMPRESSIONLEVEL
36510ae99eeSToomas Soome #define HASHTABLESIZE (1 << HASH_LOG)
36610ae99eeSToomas Soome #define HASH_MASK (HASHTABLESIZE - 1)
36710ae99eeSToomas Soome
36810ae99eeSToomas Soome #define SKIPSTRENGTH (NOTCOMPRESSIBLE_CONFIRMATION > 2 ? \
36910ae99eeSToomas Soome NOTCOMPRESSIBLE_CONFIRMATION : 2)
37010ae99eeSToomas Soome
37110ae99eeSToomas Soome /*
37210ae99eeSToomas Soome * Defines if memory is allocated into the stack (local variable),
37310ae99eeSToomas Soome * or into the heap (kmem_alloc()).
37410ae99eeSToomas Soome */
37510ae99eeSToomas Soome #define HEAPMODE (HASH_LOG > STACKLIMIT)
37610ae99eeSToomas Soome #define COPYLENGTH 8
37710ae99eeSToomas Soome #define LASTLITERALS 5
37810ae99eeSToomas Soome #define MFLIMIT (COPYLENGTH + MINMATCH)
37910ae99eeSToomas Soome #define MINLENGTH (MFLIMIT + 1)
38010ae99eeSToomas Soome
38110ae99eeSToomas Soome #define MAXD_LOG 16
38210ae99eeSToomas Soome #define MAX_DISTANCE ((1 << MAXD_LOG) - 1)
38310ae99eeSToomas Soome
38410ae99eeSToomas Soome #define ML_BITS 4
38510ae99eeSToomas Soome #define ML_MASK ((1U<<ML_BITS)-1)
38610ae99eeSToomas Soome #define RUN_BITS (8-ML_BITS)
38710ae99eeSToomas Soome #define RUN_MASK ((1U<<RUN_BITS)-1)
38810ae99eeSToomas Soome
38910ae99eeSToomas Soome
39010ae99eeSToomas Soome /*
39110ae99eeSToomas Soome * Architecture-specific macros
39210ae99eeSToomas Soome */
39310ae99eeSToomas Soome #if LZ4_ARCH64
39410ae99eeSToomas Soome #define STEPSIZE 8
39510ae99eeSToomas Soome #define UARCH U64
39610ae99eeSToomas Soome #define AARCH A64
39710ae99eeSToomas Soome #define LZ4_COPYSTEP(s, d) A64(d) = A64(s); d += 8; s += 8;
39810ae99eeSToomas Soome #define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d)
39910ae99eeSToomas Soome #define LZ4_SECURECOPY(s, d, e) if (d < e) LZ4_WILDCOPY(s, d, e)
40010ae99eeSToomas Soome #define HTYPE U32
40110ae99eeSToomas Soome #define INITBASE(base) const BYTE* const base = ip
40210ae99eeSToomas Soome #else /* !LZ4_ARCH64 */
40310ae99eeSToomas Soome #define STEPSIZE 4
40410ae99eeSToomas Soome #define UARCH U32
40510ae99eeSToomas Soome #define AARCH A32
40610ae99eeSToomas Soome #define LZ4_COPYSTEP(s, d) A32(d) = A32(s); d += 4; s += 4;
40710ae99eeSToomas Soome #define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d);
40810ae99eeSToomas Soome #define LZ4_SECURECOPY LZ4_WILDCOPY
40910ae99eeSToomas Soome #define HTYPE const BYTE *
41010ae99eeSToomas Soome #define INITBASE(base) const int base = 0
41110ae99eeSToomas Soome #endif /* !LZ4_ARCH64 */
41210ae99eeSToomas Soome
41310ae99eeSToomas Soome #if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE))
41410ae99eeSToomas Soome #define LZ4_READ_LITTLEENDIAN_16(d, s, p) \
41510ae99eeSToomas Soome { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; }
41610ae99eeSToomas Soome #define LZ4_WRITE_LITTLEENDIAN_16(p, i) \
41710ae99eeSToomas Soome { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p += 2; }
41810ae99eeSToomas Soome #else
41910ae99eeSToomas Soome #define LZ4_READ_LITTLEENDIAN_16(d, s, p) { d = (s) - A16(p); }
42010ae99eeSToomas Soome #define LZ4_WRITE_LITTLEENDIAN_16(p, v) { A16(p) = v; p += 2; }
42110ae99eeSToomas Soome #endif
42210ae99eeSToomas Soome
42310ae99eeSToomas Soome
42410ae99eeSToomas Soome /* Local structures */
42510ae99eeSToomas Soome struct refTables {
42610ae99eeSToomas Soome HTYPE hashTable[HASHTABLESIZE];
42710ae99eeSToomas Soome };
42810ae99eeSToomas Soome
42910ae99eeSToomas Soome
43010ae99eeSToomas Soome /* Macros */
43110ae99eeSToomas Soome #define LZ4_HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH * 8) - \
43210ae99eeSToomas Soome HASH_LOG))
43310ae99eeSToomas Soome #define LZ4_HASH_VALUE(p) LZ4_HASH_FUNCTION(A32(p))
43410ae99eeSToomas Soome #define LZ4_WILDCOPY(s, d, e) do { LZ4_COPYPACKET(s, d) } while (d < e);
43510ae99eeSToomas Soome #define LZ4_BLINDCOPY(s, d, l) { BYTE* e = (d) + l; LZ4_WILDCOPY(s, d, e); \
43610ae99eeSToomas Soome d = e; }
43710ae99eeSToomas Soome
43810ae99eeSToomas Soome
43910ae99eeSToomas Soome /* Private functions */
44010ae99eeSToomas Soome #if LZ4_ARCH64
44110ae99eeSToomas Soome
44210ae99eeSToomas Soome static inline int
LZ4_NbCommonBytes(register U64 val)44310ae99eeSToomas Soome LZ4_NbCommonBytes(register U64 val)
44410ae99eeSToomas Soome {
44510ae99eeSToomas Soome #if defined(LZ4_BIG_ENDIAN)
44610ae99eeSToomas Soome #if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
44710ae99eeSToomas Soome unsigned long r = 0;
44810ae99eeSToomas Soome _BitScanReverse64(&r, val);
44910ae99eeSToomas Soome return (int)(r >> 3);
45010ae99eeSToomas Soome #elif defined(__GNUC__) && (GCC_VERSION >= 304) && \
45110ae99eeSToomas Soome !defined(LZ4_FORCE_SW_BITCOUNT)
45210ae99eeSToomas Soome return (__builtin_clzll(val) >> 3);
45310ae99eeSToomas Soome #else
45410ae99eeSToomas Soome int r;
45510ae99eeSToomas Soome if (!(val >> 32)) {
45610ae99eeSToomas Soome r = 4;
45710ae99eeSToomas Soome } else {
45810ae99eeSToomas Soome r = 0;
45910ae99eeSToomas Soome val >>= 32;
46010ae99eeSToomas Soome }
46110ae99eeSToomas Soome if (!(val >> 16)) {
46210ae99eeSToomas Soome r += 2;
46310ae99eeSToomas Soome val >>= 8;
46410ae99eeSToomas Soome } else {
46510ae99eeSToomas Soome val >>= 24;
46610ae99eeSToomas Soome }
46710ae99eeSToomas Soome r += (!val);
46810ae99eeSToomas Soome return (r);
46910ae99eeSToomas Soome #endif
47010ae99eeSToomas Soome #else
47110ae99eeSToomas Soome #if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
47210ae99eeSToomas Soome unsigned long r = 0;
47310ae99eeSToomas Soome _BitScanForward64(&r, val);
47410ae99eeSToomas Soome return (int)(r >> 3);
47510ae99eeSToomas Soome #elif defined(__GNUC__) && (GCC_VERSION >= 304) && \
47610ae99eeSToomas Soome !defined(LZ4_FORCE_SW_BITCOUNT)
47710ae99eeSToomas Soome return (__builtin_ctzll(val) >> 3);
47810ae99eeSToomas Soome #else
47910ae99eeSToomas Soome static const int DeBruijnBytePos[64] =
48010ae99eeSToomas Soome { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5,
48110ae99eeSToomas Soome 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5,
48210ae99eeSToomas Soome 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4,
48310ae99eeSToomas Soome 4, 5, 7, 2, 6, 5, 7, 6, 7, 7
48410ae99eeSToomas Soome };
48510ae99eeSToomas Soome return DeBruijnBytePos[((U64) ((val & -val) * 0x0218A392CDABBD3F)) >>
48610ae99eeSToomas Soome 58];
48710ae99eeSToomas Soome #endif
48810ae99eeSToomas Soome #endif
48910ae99eeSToomas Soome }
49010ae99eeSToomas Soome
49110ae99eeSToomas Soome #else
49210ae99eeSToomas Soome
49310ae99eeSToomas Soome static inline int
LZ4_NbCommonBytes(register U32 val)49410ae99eeSToomas Soome LZ4_NbCommonBytes(register U32 val)
49510ae99eeSToomas Soome {
49610ae99eeSToomas Soome #if defined(LZ4_BIG_ENDIAN)
49710ae99eeSToomas Soome #if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
49810ae99eeSToomas Soome unsigned long r = 0;
49910ae99eeSToomas Soome _BitScanReverse(&r, val);
50010ae99eeSToomas Soome return (int)(r >> 3);
50110ae99eeSToomas Soome #elif defined(__GNUC__) && (GCC_VERSION >= 304) && \
50210ae99eeSToomas Soome !defined(LZ4_FORCE_SW_BITCOUNT)
50310ae99eeSToomas Soome return (__builtin_clz(val) >> 3);
50410ae99eeSToomas Soome #else
50510ae99eeSToomas Soome int r;
50610ae99eeSToomas Soome if (!(val >> 16)) {
50710ae99eeSToomas Soome r = 2;
50810ae99eeSToomas Soome val >>= 8;
50910ae99eeSToomas Soome } else {
51010ae99eeSToomas Soome r = 0;
51110ae99eeSToomas Soome val >>= 24;
51210ae99eeSToomas Soome }
51310ae99eeSToomas Soome r += (!val);
51410ae99eeSToomas Soome return (r);
51510ae99eeSToomas Soome #endif
51610ae99eeSToomas Soome #else
51710ae99eeSToomas Soome #if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
51810ae99eeSToomas Soome unsigned long r = 0;
51910ae99eeSToomas Soome _BitScanForward(&r, val);
52010ae99eeSToomas Soome return (int)(r >> 3);
52110ae99eeSToomas Soome #elif defined(__GNUC__) && (GCC_VERSION >= 304) && \
52210ae99eeSToomas Soome !defined(LZ4_FORCE_SW_BITCOUNT)
52310ae99eeSToomas Soome return (__builtin_ctz(val) >> 3);
52410ae99eeSToomas Soome #else
52510ae99eeSToomas Soome static const int DeBruijnBytePos[32] = {
52610ae99eeSToomas Soome 0, 0, 3, 0, 3, 1, 3, 0,
52710ae99eeSToomas Soome 3, 2, 2, 1, 3, 2, 0, 1,
52810ae99eeSToomas Soome 3, 3, 1, 2, 2, 2, 2, 0,
52910ae99eeSToomas Soome 3, 1, 2, 0, 1, 0, 1, 1
53010ae99eeSToomas Soome };
53110ae99eeSToomas Soome return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >>
53210ae99eeSToomas Soome 27];
53310ae99eeSToomas Soome #endif
53410ae99eeSToomas Soome #endif
53510ae99eeSToomas Soome }
53610ae99eeSToomas Soome
53710ae99eeSToomas Soome #endif
53810ae99eeSToomas Soome
53910ae99eeSToomas Soome /* Compression functions */
54010ae99eeSToomas Soome
54110ae99eeSToomas Soome /*ARGSUSED*/
54210ae99eeSToomas Soome static int
LZ4_compressCtx(void * ctx,const char * source,char * dest,int isize,int osize)54310ae99eeSToomas Soome LZ4_compressCtx(void *ctx, const char *source, char *dest, int isize,
54410ae99eeSToomas Soome int osize)
54510ae99eeSToomas Soome {
54610ae99eeSToomas Soome #if HEAPMODE
54710ae99eeSToomas Soome struct refTables *srt = (struct refTables *)ctx;
54810ae99eeSToomas Soome HTYPE *HashTable = (HTYPE *) (srt->hashTable);
54910ae99eeSToomas Soome #else
55010ae99eeSToomas Soome HTYPE HashTable[HASHTABLESIZE] = { 0 };
55110ae99eeSToomas Soome #endif
55210ae99eeSToomas Soome
55310ae99eeSToomas Soome const BYTE *ip = (const BYTE *) source;
55410ae99eeSToomas Soome INITBASE(base);
55510ae99eeSToomas Soome const BYTE *anchor = ip;
55610ae99eeSToomas Soome const BYTE *const iend = ip + isize;
55710ae99eeSToomas Soome const BYTE *const oend = (BYTE *) dest + osize;
55810ae99eeSToomas Soome const BYTE *const mflimit = iend - MFLIMIT;
55910ae99eeSToomas Soome #define matchlimit (iend - LASTLITERALS)
56010ae99eeSToomas Soome
56110ae99eeSToomas Soome BYTE *op = (BYTE *) dest;
56210ae99eeSToomas Soome
56310ae99eeSToomas Soome int len, length;
56410ae99eeSToomas Soome const int skipStrength = SKIPSTRENGTH;
56510ae99eeSToomas Soome U32 forwardH;
56610ae99eeSToomas Soome
56710ae99eeSToomas Soome
56810ae99eeSToomas Soome /* Init */
56910ae99eeSToomas Soome if (isize < MINLENGTH)
57010ae99eeSToomas Soome goto _last_literals;
57110ae99eeSToomas Soome
57210ae99eeSToomas Soome /* First Byte */
57310ae99eeSToomas Soome HashTable[LZ4_HASH_VALUE(ip)] = ip - base;
57410ae99eeSToomas Soome ip++;
57510ae99eeSToomas Soome forwardH = LZ4_HASH_VALUE(ip);
57610ae99eeSToomas Soome
57710ae99eeSToomas Soome /* Main Loop */
57810ae99eeSToomas Soome for (;;) {
57910ae99eeSToomas Soome int findMatchAttempts = (1U << skipStrength) + 3;
58010ae99eeSToomas Soome const BYTE *forwardIp = ip;
58110ae99eeSToomas Soome const BYTE *ref;
58210ae99eeSToomas Soome BYTE *token;
58310ae99eeSToomas Soome
58410ae99eeSToomas Soome /* Find a match */
58510ae99eeSToomas Soome do {
58610ae99eeSToomas Soome U32 h = forwardH;
58710ae99eeSToomas Soome int step = findMatchAttempts++ >> skipStrength;
58810ae99eeSToomas Soome ip = forwardIp;
58910ae99eeSToomas Soome forwardIp = ip + step;
59010ae99eeSToomas Soome
59110ae99eeSToomas Soome if unlikely(forwardIp > mflimit) {
59210ae99eeSToomas Soome goto _last_literals;
59310ae99eeSToomas Soome }
59410ae99eeSToomas Soome
59510ae99eeSToomas Soome forwardH = LZ4_HASH_VALUE(forwardIp);
59610ae99eeSToomas Soome ref = base + HashTable[h];
59710ae99eeSToomas Soome HashTable[h] = ip - base;
59810ae99eeSToomas Soome
59910ae99eeSToomas Soome } while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip)));
60010ae99eeSToomas Soome
60110ae99eeSToomas Soome /* Catch up */
60210ae99eeSToomas Soome while ((ip > anchor) && (ref > (const BYTE *) source) &&
60310ae99eeSToomas Soome unlikely(ip[-1] == ref[-1])) {
60410ae99eeSToomas Soome ip--;
60510ae99eeSToomas Soome ref--;
60610ae99eeSToomas Soome }
60710ae99eeSToomas Soome
60810ae99eeSToomas Soome /* Encode Literal length */
60910ae99eeSToomas Soome length = ip - anchor;
61010ae99eeSToomas Soome token = op++;
61110ae99eeSToomas Soome
61210ae99eeSToomas Soome /* Check output limit */
61310ae99eeSToomas Soome if unlikely(op + length + (2 + 1 + LASTLITERALS) +
61410ae99eeSToomas Soome (length >> 8) > oend)
61510ae99eeSToomas Soome return (0);
61610ae99eeSToomas Soome
61710ae99eeSToomas Soome if (length >= (int)RUN_MASK) {
61810ae99eeSToomas Soome *token = (RUN_MASK << ML_BITS);
61910ae99eeSToomas Soome len = length - RUN_MASK;
62010ae99eeSToomas Soome for (; len > 254; len -= 255)
62110ae99eeSToomas Soome *op++ = 255;
62210ae99eeSToomas Soome *op++ = (BYTE)len;
62310ae99eeSToomas Soome } else
62410ae99eeSToomas Soome *token = (length << ML_BITS);
62510ae99eeSToomas Soome
62610ae99eeSToomas Soome /* Copy Literals */
62710ae99eeSToomas Soome LZ4_BLINDCOPY(anchor, op, length);
62810ae99eeSToomas Soome
62910ae99eeSToomas Soome _next_match:
63010ae99eeSToomas Soome /* Encode Offset */
63110ae99eeSToomas Soome LZ4_WRITE_LITTLEENDIAN_16(op, ip - ref);
63210ae99eeSToomas Soome
63310ae99eeSToomas Soome /* Start Counting */
63410ae99eeSToomas Soome ip += MINMATCH;
63510ae99eeSToomas Soome ref += MINMATCH; /* MinMatch verified */
63610ae99eeSToomas Soome anchor = ip;
63710ae99eeSToomas Soome while likely(ip < matchlimit - (STEPSIZE - 1)) {
63810ae99eeSToomas Soome UARCH diff = AARCH(ref) ^ AARCH(ip);
63910ae99eeSToomas Soome if (!diff) {
64010ae99eeSToomas Soome ip += STEPSIZE;
64110ae99eeSToomas Soome ref += STEPSIZE;
64210ae99eeSToomas Soome continue;
64310ae99eeSToomas Soome }
64410ae99eeSToomas Soome ip += LZ4_NbCommonBytes(diff);
64510ae99eeSToomas Soome goto _endCount;
64610ae99eeSToomas Soome }
64710ae99eeSToomas Soome #if LZ4_ARCH64
64810ae99eeSToomas Soome if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) {
64910ae99eeSToomas Soome ip += 4;
65010ae99eeSToomas Soome ref += 4;
65110ae99eeSToomas Soome }
65210ae99eeSToomas Soome #endif
65310ae99eeSToomas Soome if ((ip < (matchlimit - 1)) && (A16(ref) == A16(ip))) {
65410ae99eeSToomas Soome ip += 2;
65510ae99eeSToomas Soome ref += 2;
65610ae99eeSToomas Soome }
65710ae99eeSToomas Soome if ((ip < matchlimit) && (*ref == *ip))
65810ae99eeSToomas Soome ip++;
65910ae99eeSToomas Soome _endCount:
66010ae99eeSToomas Soome
66110ae99eeSToomas Soome /* Encode MatchLength */
66210ae99eeSToomas Soome len = (ip - anchor);
66310ae99eeSToomas Soome /* Check output limit */
66410ae99eeSToomas Soome if unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend)
66510ae99eeSToomas Soome return (0);
66610ae99eeSToomas Soome if (len >= (int)ML_MASK) {
66710ae99eeSToomas Soome *token += ML_MASK;
66810ae99eeSToomas Soome len -= ML_MASK;
66910ae99eeSToomas Soome for (; len > 509; len -= 510) {
67010ae99eeSToomas Soome *op++ = 255;
67110ae99eeSToomas Soome *op++ = 255;
67210ae99eeSToomas Soome }
67310ae99eeSToomas Soome if (len > 254) {
67410ae99eeSToomas Soome len -= 255;
67510ae99eeSToomas Soome *op++ = 255;
67610ae99eeSToomas Soome }
67710ae99eeSToomas Soome *op++ = (BYTE)len;
67810ae99eeSToomas Soome } else
67910ae99eeSToomas Soome *token += len;
68010ae99eeSToomas Soome
68110ae99eeSToomas Soome /* Test end of chunk */
68210ae99eeSToomas Soome if (ip > mflimit) {
68310ae99eeSToomas Soome anchor = ip;
68410ae99eeSToomas Soome break;
68510ae99eeSToomas Soome }
68610ae99eeSToomas Soome /* Fill table */
68710ae99eeSToomas Soome HashTable[LZ4_HASH_VALUE(ip - 2)] = ip - 2 - base;
68810ae99eeSToomas Soome
68910ae99eeSToomas Soome /* Test next position */
69010ae99eeSToomas Soome ref = base + HashTable[LZ4_HASH_VALUE(ip)];
69110ae99eeSToomas Soome HashTable[LZ4_HASH_VALUE(ip)] = ip - base;
69210ae99eeSToomas Soome if ((ref > ip - (MAX_DISTANCE + 1)) && (A32(ref) == A32(ip))) {
69310ae99eeSToomas Soome token = op++;
69410ae99eeSToomas Soome *token = 0;
69510ae99eeSToomas Soome goto _next_match;
69610ae99eeSToomas Soome }
69710ae99eeSToomas Soome /* Prepare next loop */
69810ae99eeSToomas Soome anchor = ip++;
69910ae99eeSToomas Soome forwardH = LZ4_HASH_VALUE(ip);
70010ae99eeSToomas Soome }
70110ae99eeSToomas Soome
70210ae99eeSToomas Soome _last_literals:
70310ae99eeSToomas Soome /* Encode Last Literals */
70410ae99eeSToomas Soome {
70510ae99eeSToomas Soome int lastRun = iend - anchor;
70610ae99eeSToomas Soome if (op + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) >
70710ae99eeSToomas Soome oend)
70810ae99eeSToomas Soome return (0);
70910ae99eeSToomas Soome if (lastRun >= (int)RUN_MASK) {
71010ae99eeSToomas Soome *op++ = (RUN_MASK << ML_BITS);
71110ae99eeSToomas Soome lastRun -= RUN_MASK;
71210ae99eeSToomas Soome for (; lastRun > 254; lastRun -= 255) {
71310ae99eeSToomas Soome *op++ = 255;
71410ae99eeSToomas Soome }
71510ae99eeSToomas Soome *op++ = (BYTE)lastRun;
71610ae99eeSToomas Soome } else
71710ae99eeSToomas Soome *op++ = (lastRun << ML_BITS);
71810ae99eeSToomas Soome (void) memcpy(op, anchor, iend - anchor);
71910ae99eeSToomas Soome op += iend - anchor;
72010ae99eeSToomas Soome }
72110ae99eeSToomas Soome
72210ae99eeSToomas Soome /* End */
72310ae99eeSToomas Soome return (int)(((char *)op) - dest);
72410ae99eeSToomas Soome }
72510ae99eeSToomas Soome
72610ae99eeSToomas Soome
72710ae99eeSToomas Soome
72810ae99eeSToomas Soome /* Note : this function is valid only if isize < LZ4_64KLIMIT */
72910ae99eeSToomas Soome #define LZ4_64KLIMIT ((1 << 16) + (MFLIMIT - 1))
73010ae99eeSToomas Soome #define HASHLOG64K (HASH_LOG + 1)
73110ae99eeSToomas Soome #define HASH64KTABLESIZE (1U << HASHLOG64K)
73210ae99eeSToomas Soome #define LZ4_HASH64K_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8) - \
73310ae99eeSToomas Soome HASHLOG64K))
73410ae99eeSToomas Soome #define LZ4_HASH64K_VALUE(p) LZ4_HASH64K_FUNCTION(A32(p))
73510ae99eeSToomas Soome
73610ae99eeSToomas Soome /*ARGSUSED*/
73710ae99eeSToomas Soome static int
LZ4_compress64kCtx(void * ctx,const char * source,char * dest,int isize,int osize)73810ae99eeSToomas Soome LZ4_compress64kCtx(void *ctx, const char *source, char *dest, int isize,
73910ae99eeSToomas Soome int osize)
74010ae99eeSToomas Soome {
74110ae99eeSToomas Soome #if HEAPMODE
74210ae99eeSToomas Soome struct refTables *srt = (struct refTables *)ctx;
74310ae99eeSToomas Soome U16 *HashTable = (U16 *) (srt->hashTable);
74410ae99eeSToomas Soome #else
74510ae99eeSToomas Soome U16 HashTable[HASH64KTABLESIZE] = { 0 };
74610ae99eeSToomas Soome #endif
74710ae99eeSToomas Soome
74810ae99eeSToomas Soome const BYTE *ip = (const BYTE *) source;
74910ae99eeSToomas Soome const BYTE *anchor = ip;
75010ae99eeSToomas Soome const BYTE *const base = ip;
75110ae99eeSToomas Soome const BYTE *const iend = ip + isize;
75210ae99eeSToomas Soome const BYTE *const oend = (BYTE *) dest + osize;
75310ae99eeSToomas Soome const BYTE *const mflimit = iend - MFLIMIT;
75410ae99eeSToomas Soome #define matchlimit (iend - LASTLITERALS)
75510ae99eeSToomas Soome
75610ae99eeSToomas Soome BYTE *op = (BYTE *) dest;
75710ae99eeSToomas Soome
75810ae99eeSToomas Soome int len, length;
75910ae99eeSToomas Soome const int skipStrength = SKIPSTRENGTH;
76010ae99eeSToomas Soome U32 forwardH;
76110ae99eeSToomas Soome
76210ae99eeSToomas Soome /* Init */
76310ae99eeSToomas Soome if (isize < MINLENGTH)
76410ae99eeSToomas Soome goto _last_literals;
76510ae99eeSToomas Soome
76610ae99eeSToomas Soome /* First Byte */
76710ae99eeSToomas Soome ip++;
76810ae99eeSToomas Soome forwardH = LZ4_HASH64K_VALUE(ip);
76910ae99eeSToomas Soome
77010ae99eeSToomas Soome /* Main Loop */
77110ae99eeSToomas Soome for (;;) {
77210ae99eeSToomas Soome int findMatchAttempts = (1U << skipStrength) + 3;
77310ae99eeSToomas Soome const BYTE *forwardIp = ip;
77410ae99eeSToomas Soome const BYTE *ref;
77510ae99eeSToomas Soome BYTE *token;
77610ae99eeSToomas Soome
77710ae99eeSToomas Soome /* Find a match */
77810ae99eeSToomas Soome do {
77910ae99eeSToomas Soome U32 h = forwardH;
78010ae99eeSToomas Soome int step = findMatchAttempts++ >> skipStrength;
78110ae99eeSToomas Soome ip = forwardIp;
78210ae99eeSToomas Soome forwardIp = ip + step;
78310ae99eeSToomas Soome
78410ae99eeSToomas Soome if (forwardIp > mflimit) {
78510ae99eeSToomas Soome goto _last_literals;
78610ae99eeSToomas Soome }
78710ae99eeSToomas Soome
78810ae99eeSToomas Soome forwardH = LZ4_HASH64K_VALUE(forwardIp);
78910ae99eeSToomas Soome ref = base + HashTable[h];
79010ae99eeSToomas Soome HashTable[h] = ip - base;
79110ae99eeSToomas Soome
79210ae99eeSToomas Soome } while (A32(ref) != A32(ip));
79310ae99eeSToomas Soome
79410ae99eeSToomas Soome /* Catch up */
79510ae99eeSToomas Soome while ((ip > anchor) && (ref > (const BYTE *) source) &&
79610ae99eeSToomas Soome (ip[-1] == ref[-1])) {
79710ae99eeSToomas Soome ip--;
79810ae99eeSToomas Soome ref--;
79910ae99eeSToomas Soome }
80010ae99eeSToomas Soome
80110ae99eeSToomas Soome /* Encode Literal length */
80210ae99eeSToomas Soome length = ip - anchor;
80310ae99eeSToomas Soome token = op++;
80410ae99eeSToomas Soome
80510ae99eeSToomas Soome /* Check output limit */
80610ae99eeSToomas Soome if unlikely(op + length + (2 + 1 + LASTLITERALS) +
80710ae99eeSToomas Soome (length >> 8) > oend)
80810ae99eeSToomas Soome return (0);
80910ae99eeSToomas Soome
81010ae99eeSToomas Soome if (length >= (int)RUN_MASK) {
81110ae99eeSToomas Soome *token = (RUN_MASK << ML_BITS);
81210ae99eeSToomas Soome len = length - RUN_MASK;
81310ae99eeSToomas Soome for (; len > 254; len -= 255)
81410ae99eeSToomas Soome *op++ = 255;
81510ae99eeSToomas Soome *op++ = (BYTE)len;
81610ae99eeSToomas Soome } else
81710ae99eeSToomas Soome *token = (length << ML_BITS);
81810ae99eeSToomas Soome
81910ae99eeSToomas Soome /* Copy Literals */
82010ae99eeSToomas Soome LZ4_BLINDCOPY(anchor, op, length);
82110ae99eeSToomas Soome
82210ae99eeSToomas Soome _next_match:
82310ae99eeSToomas Soome /* Encode Offset */
82410ae99eeSToomas Soome LZ4_WRITE_LITTLEENDIAN_16(op, ip - ref);
82510ae99eeSToomas Soome
82610ae99eeSToomas Soome /* Start Counting */
82710ae99eeSToomas Soome ip += MINMATCH;
82810ae99eeSToomas Soome ref += MINMATCH; /* MinMatch verified */
82910ae99eeSToomas Soome anchor = ip;
83010ae99eeSToomas Soome while (ip < matchlimit - (STEPSIZE - 1)) {
83110ae99eeSToomas Soome UARCH diff = AARCH(ref) ^ AARCH(ip);
83210ae99eeSToomas Soome if (!diff) {
83310ae99eeSToomas Soome ip += STEPSIZE;
83410ae99eeSToomas Soome ref += STEPSIZE;
83510ae99eeSToomas Soome continue;
83610ae99eeSToomas Soome }
83710ae99eeSToomas Soome ip += LZ4_NbCommonBytes(diff);
83810ae99eeSToomas Soome goto _endCount;
83910ae99eeSToomas Soome }
84010ae99eeSToomas Soome #if LZ4_ARCH64
84110ae99eeSToomas Soome if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) {
84210ae99eeSToomas Soome ip += 4;
84310ae99eeSToomas Soome ref += 4;
84410ae99eeSToomas Soome }
84510ae99eeSToomas Soome #endif
84610ae99eeSToomas Soome if ((ip < (matchlimit - 1)) && (A16(ref) == A16(ip))) {
84710ae99eeSToomas Soome ip += 2;
84810ae99eeSToomas Soome ref += 2;
84910ae99eeSToomas Soome }
85010ae99eeSToomas Soome if ((ip < matchlimit) && (*ref == *ip))
85110ae99eeSToomas Soome ip++;
85210ae99eeSToomas Soome _endCount:
85310ae99eeSToomas Soome
85410ae99eeSToomas Soome /* Encode MatchLength */
85510ae99eeSToomas Soome len = (ip - anchor);
85610ae99eeSToomas Soome /* Check output limit */
85710ae99eeSToomas Soome if unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend)
85810ae99eeSToomas Soome return (0);
85910ae99eeSToomas Soome if (len >= (int)ML_MASK) {
86010ae99eeSToomas Soome *token += ML_MASK;
86110ae99eeSToomas Soome len -= ML_MASK;
86210ae99eeSToomas Soome for (; len > 509; len -= 510) {
86310ae99eeSToomas Soome *op++ = 255;
86410ae99eeSToomas Soome *op++ = 255;
86510ae99eeSToomas Soome }
86610ae99eeSToomas Soome if (len > 254) {
86710ae99eeSToomas Soome len -= 255;
86810ae99eeSToomas Soome *op++ = 255;
86910ae99eeSToomas Soome }
87010ae99eeSToomas Soome *op++ = (BYTE)len;
87110ae99eeSToomas Soome } else
87210ae99eeSToomas Soome *token += len;
87310ae99eeSToomas Soome
87410ae99eeSToomas Soome /* Test end of chunk */
87510ae99eeSToomas Soome if (ip > mflimit) {
87610ae99eeSToomas Soome anchor = ip;
87710ae99eeSToomas Soome break;
87810ae99eeSToomas Soome }
87910ae99eeSToomas Soome /* Fill table */
88010ae99eeSToomas Soome HashTable[LZ4_HASH64K_VALUE(ip - 2)] = ip - 2 - base;
88110ae99eeSToomas Soome
88210ae99eeSToomas Soome /* Test next position */
88310ae99eeSToomas Soome ref = base + HashTable[LZ4_HASH64K_VALUE(ip)];
88410ae99eeSToomas Soome HashTable[LZ4_HASH64K_VALUE(ip)] = ip - base;
88510ae99eeSToomas Soome if (A32(ref) == A32(ip)) {
88610ae99eeSToomas Soome token = op++;
88710ae99eeSToomas Soome *token = 0;
88810ae99eeSToomas Soome goto _next_match;
88910ae99eeSToomas Soome }
89010ae99eeSToomas Soome /* Prepare next loop */
89110ae99eeSToomas Soome anchor = ip++;
89210ae99eeSToomas Soome forwardH = LZ4_HASH64K_VALUE(ip);
89310ae99eeSToomas Soome }
89410ae99eeSToomas Soome
89510ae99eeSToomas Soome _last_literals:
89610ae99eeSToomas Soome /* Encode Last Literals */
89710ae99eeSToomas Soome {
89810ae99eeSToomas Soome int lastRun = iend - anchor;
89910ae99eeSToomas Soome if (op + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) >
90010ae99eeSToomas Soome oend)
90110ae99eeSToomas Soome return (0);
90210ae99eeSToomas Soome if (lastRun >= (int)RUN_MASK) {
90310ae99eeSToomas Soome *op++ = (RUN_MASK << ML_BITS);
90410ae99eeSToomas Soome lastRun -= RUN_MASK;
90510ae99eeSToomas Soome for (; lastRun > 254; lastRun -= 255)
90610ae99eeSToomas Soome *op++ = 255;
90710ae99eeSToomas Soome *op++ = (BYTE)lastRun;
90810ae99eeSToomas Soome } else
90910ae99eeSToomas Soome *op++ = (lastRun << ML_BITS);
91010ae99eeSToomas Soome (void) memcpy(op, anchor, iend - anchor);
91110ae99eeSToomas Soome op += iend - anchor;
91210ae99eeSToomas Soome }
91310ae99eeSToomas Soome
91410ae99eeSToomas Soome /* End */
91510ae99eeSToomas Soome return (int)(((char *)op) - dest);
91610ae99eeSToomas Soome }
91710ae99eeSToomas Soome
91810ae99eeSToomas Soome static int
real_LZ4_compress(const char * source,char * dest,int isize,int osize)91910ae99eeSToomas Soome real_LZ4_compress(const char *source, char *dest, int isize, int osize)
92010ae99eeSToomas Soome {
92110ae99eeSToomas Soome #if HEAPMODE
92210ae99eeSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL)
92310ae99eeSToomas Soome void *ctx = kmem_zalloc(sizeof (struct refTables), KM_NOSLEEP);
92410ae99eeSToomas Soome #else
925*cab7c30cSAndy Fiddaman void *ctx = calloc(1, sizeof (struct refTables));
92610ae99eeSToomas Soome #endif
92710ae99eeSToomas Soome int result;
92810ae99eeSToomas Soome
92910ae99eeSToomas Soome /*
93010ae99eeSToomas Soome * out of kernel memory, gently fall through - this will disable
93110ae99eeSToomas Soome * compression in zio_compress_data
93210ae99eeSToomas Soome */
93310ae99eeSToomas Soome if (ctx == NULL)
93410ae99eeSToomas Soome return (0);
93510ae99eeSToomas Soome
93610ae99eeSToomas Soome if (isize < LZ4_64KLIMIT)
93710ae99eeSToomas Soome result = LZ4_compress64kCtx(ctx, source, dest, isize, osize);
93810ae99eeSToomas Soome else
93910ae99eeSToomas Soome result = LZ4_compressCtx(ctx, source, dest, isize, osize);
94010ae99eeSToomas Soome
94110ae99eeSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL)
94210ae99eeSToomas Soome kmem_free(ctx, sizeof (struct refTables));
94310ae99eeSToomas Soome #else
94410ae99eeSToomas Soome free(ctx);
94510ae99eeSToomas Soome #endif
94610ae99eeSToomas Soome return (result);
94710ae99eeSToomas Soome #else
94810ae99eeSToomas Soome if (isize < (int)LZ4_64KLIMIT)
94910ae99eeSToomas Soome return (LZ4_compress64kCtx(NULL, source, dest, isize, osize));
95010ae99eeSToomas Soome return (LZ4_compressCtx(NULL, source, dest, isize, osize));
95110ae99eeSToomas Soome #endif
95210ae99eeSToomas Soome }
95310ae99eeSToomas Soome
95410ae99eeSToomas Soome /* Decompression functions */
95510ae99eeSToomas Soome
95610ae99eeSToomas Soome /*
95710ae99eeSToomas Soome * Note: The decoding function LZ4_uncompress_unknownOutputSize() is safe
95810ae99eeSToomas Soome * against "buffer overflow" attack type. It will never write nor
95910ae99eeSToomas Soome * read outside of the provided output buffers.
96010ae99eeSToomas Soome * LZ4_uncompress_unknownOutputSize() also insures that
96110ae99eeSToomas Soome * it will never read outside of the input buffer. A corrupted input
96210ae99eeSToomas Soome * will produce an error result, a negative int, indicating the position
96310ae99eeSToomas Soome * of the error within input stream.
96410ae99eeSToomas Soome */
96510ae99eeSToomas Soome
96610ae99eeSToomas Soome static int
LZ4_uncompress_unknownOutputSize(const char * source,char * dest,int isize,int maxOutputSize)96710ae99eeSToomas Soome LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize,
96810ae99eeSToomas Soome int maxOutputSize)
96910ae99eeSToomas Soome {
97010ae99eeSToomas Soome /* Local Variables */
97110ae99eeSToomas Soome const BYTE *restrict ip = (const BYTE *) source;
97210ae99eeSToomas Soome const BYTE *const iend = ip + isize;
97310ae99eeSToomas Soome const BYTE *ref;
97410ae99eeSToomas Soome
97510ae99eeSToomas Soome BYTE *op = (BYTE *) dest;
97610ae99eeSToomas Soome BYTE *const oend = op + maxOutputSize;
97710ae99eeSToomas Soome BYTE *cpy;
97810ae99eeSToomas Soome
97910ae99eeSToomas Soome size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0};
98010ae99eeSToomas Soome #if LZ4_ARCH64
98110ae99eeSToomas Soome size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
98210ae99eeSToomas Soome #endif
98310ae99eeSToomas Soome
98410ae99eeSToomas Soome /* Main Loop */
98510ae99eeSToomas Soome while (ip < iend) {
98610ae99eeSToomas Soome unsigned token;
98710ae99eeSToomas Soome size_t length;
98810ae99eeSToomas Soome
98910ae99eeSToomas Soome /* get runlength */
99010ae99eeSToomas Soome token = *ip++;
99110ae99eeSToomas Soome if ((length = (token >> ML_BITS)) == RUN_MASK) {
99210ae99eeSToomas Soome int s = 255;
99310ae99eeSToomas Soome while ((ip < iend) && (s == 255)) {
99410ae99eeSToomas Soome s = *ip++;
99510ae99eeSToomas Soome length += s;
99610ae99eeSToomas Soome }
99710ae99eeSToomas Soome }
99810ae99eeSToomas Soome /* copy literals */
99910ae99eeSToomas Soome cpy = op + length;
100010ae99eeSToomas Soome /* CORNER-CASE: cpy might overflow. */
100110ae99eeSToomas Soome if (cpy < op)
100210ae99eeSToomas Soome goto _output_error; /* cpy was overflowed, bail! */
100310ae99eeSToomas Soome if ((cpy > oend - COPYLENGTH) ||
100410ae99eeSToomas Soome (ip + length > iend - COPYLENGTH)) {
100510ae99eeSToomas Soome if (cpy > oend)
100610ae99eeSToomas Soome /* Error: writes beyond output buffer */
100710ae99eeSToomas Soome goto _output_error;
100810ae99eeSToomas Soome if (ip + length != iend)
100910ae99eeSToomas Soome /*
101010ae99eeSToomas Soome * Error: LZ4 format requires to consume all
101110ae99eeSToomas Soome * input at this stage
101210ae99eeSToomas Soome */
101310ae99eeSToomas Soome goto _output_error;
101410ae99eeSToomas Soome (void) memcpy(op, ip, length);
101510ae99eeSToomas Soome op += length;
101610ae99eeSToomas Soome /* Necessarily EOF, due to parsing restrictions */
101710ae99eeSToomas Soome break;
101810ae99eeSToomas Soome }
101910ae99eeSToomas Soome LZ4_WILDCOPY(ip, op, cpy);
102010ae99eeSToomas Soome ip -= (op - cpy);
102110ae99eeSToomas Soome op = cpy;
102210ae99eeSToomas Soome
102310ae99eeSToomas Soome /* get offset */
102410ae99eeSToomas Soome LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip);
102510ae99eeSToomas Soome ip += 2;
102610ae99eeSToomas Soome if (ref < (BYTE * const) dest)
102710ae99eeSToomas Soome /*
102810ae99eeSToomas Soome * Error: offset creates reference outside of
102910ae99eeSToomas Soome * destination buffer
103010ae99eeSToomas Soome */
103110ae99eeSToomas Soome goto _output_error;
103210ae99eeSToomas Soome
103310ae99eeSToomas Soome /* get matchlength */
103410ae99eeSToomas Soome if ((length = (token & ML_MASK)) == ML_MASK) {
103510ae99eeSToomas Soome while (ip < iend) {
103610ae99eeSToomas Soome int s = *ip++;
103710ae99eeSToomas Soome length += s;
103810ae99eeSToomas Soome if (s == 255)
103910ae99eeSToomas Soome continue;
104010ae99eeSToomas Soome break;
104110ae99eeSToomas Soome }
104210ae99eeSToomas Soome }
104310ae99eeSToomas Soome /* copy repeated sequence */
104410ae99eeSToomas Soome if unlikely(op - ref < STEPSIZE) {
104510ae99eeSToomas Soome #if LZ4_ARCH64
104610ae99eeSToomas Soome size_t dec64 = dec64table[op-ref];
104710ae99eeSToomas Soome #else
104810ae99eeSToomas Soome const int dec64 = 0;
104910ae99eeSToomas Soome #endif
105010ae99eeSToomas Soome op[0] = ref[0];
105110ae99eeSToomas Soome op[1] = ref[1];
105210ae99eeSToomas Soome op[2] = ref[2];
105310ae99eeSToomas Soome op[3] = ref[3];
105410ae99eeSToomas Soome op += 4;
105510ae99eeSToomas Soome ref += 4;
105610ae99eeSToomas Soome ref -= dec32table[op-ref];
105710ae99eeSToomas Soome A32(op) = A32(ref);
105810ae99eeSToomas Soome op += STEPSIZE - 4;
105910ae99eeSToomas Soome ref -= dec64;
106010ae99eeSToomas Soome } else {
106110ae99eeSToomas Soome LZ4_COPYSTEP(ref, op);
106210ae99eeSToomas Soome }
106310ae99eeSToomas Soome cpy = op + length - (STEPSIZE - 4);
106410ae99eeSToomas Soome if (cpy > oend - COPYLENGTH) {
106510ae99eeSToomas Soome if (cpy > oend)
106610ae99eeSToomas Soome /*
106710ae99eeSToomas Soome * Error: request to write outside of
106810ae99eeSToomas Soome * destination buffer
106910ae99eeSToomas Soome */
107010ae99eeSToomas Soome goto _output_error;
107110ae99eeSToomas Soome LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
107210ae99eeSToomas Soome while (op < cpy)
107310ae99eeSToomas Soome *op++ = *ref++;
107410ae99eeSToomas Soome op = cpy;
107510ae99eeSToomas Soome if (op == oend)
107610ae99eeSToomas Soome /*
107710ae99eeSToomas Soome * Check EOF (should never happen, since
107810ae99eeSToomas Soome * last 5 bytes are supposed to be literals)
107910ae99eeSToomas Soome */
108010ae99eeSToomas Soome goto _output_error;
108110ae99eeSToomas Soome continue;
108210ae99eeSToomas Soome }
108310ae99eeSToomas Soome LZ4_SECURECOPY(ref, op, cpy);
108410ae99eeSToomas Soome op = cpy; /* correction */
108510ae99eeSToomas Soome }
108610ae99eeSToomas Soome
108710ae99eeSToomas Soome /* end of decoding */
108810ae99eeSToomas Soome return (int)(((char *)op) - dest);
108910ae99eeSToomas Soome
109010ae99eeSToomas Soome /* write overflow error detected */
109110ae99eeSToomas Soome _output_error:
109210ae99eeSToomas Soome return (int)(-(((const char *)ip) - source));
109310ae99eeSToomas Soome }
1094