xref: /illumos-gate/usr/src/common/lz4/lz4.c (revision cab7c30c9587a8c7b5dd94af5f688dc5b8e8add7)
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