xref: /titanic_50/usr/src/uts/common/fs/zfs/lz4.c (revision 58d0718061c87e3d647c891ec5281b93c08dba4e)
1a6f561b4SSašo Kiselkov /*
2a6f561b4SSašo Kiselkov  * LZ4 - Fast LZ compression algorithm
3a6f561b4SSašo Kiselkov  * Header File
4a6f561b4SSašo Kiselkov  * Copyright (C) 2011-2013, Yann Collet.
5a6f561b4SSašo Kiselkov  * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6a6f561b4SSašo Kiselkov  *
7a6f561b4SSašo Kiselkov  * Redistribution and use in source and binary forms, with or without
8a6f561b4SSašo Kiselkov  * modification, are permitted provided that the following conditions are
9a6f561b4SSašo Kiselkov  * met:
10a6f561b4SSašo Kiselkov  *
11a6f561b4SSašo Kiselkov  *     * Redistributions of source code must retain the above copyright
12a6f561b4SSašo Kiselkov  * notice, this list of conditions and the following disclaimer.
13a6f561b4SSašo Kiselkov  *     * Redistributions in binary form must reproduce the above
14a6f561b4SSašo Kiselkov  * copyright notice, this list of conditions and the following disclaimer
15a6f561b4SSašo Kiselkov  * in the documentation and/or other materials provided with the
16a6f561b4SSašo Kiselkov  * distribution.
17a6f561b4SSašo Kiselkov  *
18a6f561b4SSašo Kiselkov  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19a6f561b4SSašo Kiselkov  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20a6f561b4SSašo Kiselkov  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21a6f561b4SSašo Kiselkov  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22a6f561b4SSašo Kiselkov  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23a6f561b4SSašo Kiselkov  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24a6f561b4SSašo Kiselkov  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25a6f561b4SSašo Kiselkov  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26a6f561b4SSašo Kiselkov  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27a6f561b4SSašo Kiselkov  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28a6f561b4SSašo Kiselkov  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29a6f561b4SSašo Kiselkov  *
30a6f561b4SSašo Kiselkov  * You can contact the author at :
31a6f561b4SSašo Kiselkov  * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
32a6f561b4SSašo Kiselkov  * - LZ4 source repository : http://code.google.com/p/lz4/
33a6f561b4SSašo Kiselkov  */
34a6f561b4SSašo Kiselkov 
35a6f561b4SSašo Kiselkov #include <sys/zfs_context.h>
36a6f561b4SSašo Kiselkov 
37a6f561b4SSašo Kiselkov static int real_LZ4_compress(const char *source, char *dest, int isize,
38a6f561b4SSašo Kiselkov     int osize);
39a6f561b4SSašo Kiselkov static int real_LZ4_uncompress(const char *source, char *dest, int osize);
40a6f561b4SSašo Kiselkov static int LZ4_compressBound(int isize);
41a6f561b4SSašo Kiselkov static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest,
42a6f561b4SSašo Kiselkov     int isize, int maxOutputSize);
43a6f561b4SSašo Kiselkov static int LZ4_compressCtx(void *ctx, const char *source, char *dest,
44a6f561b4SSašo Kiselkov     int isize, int osize);
45a6f561b4SSašo Kiselkov static int LZ4_compress64kCtx(void *ctx, const char *source, char *dest,
46a6f561b4SSašo Kiselkov     int isize, int osize);
47a6f561b4SSašo Kiselkov 
48a6f561b4SSašo Kiselkov /*ARGSUSED*/
49a6f561b4SSašo Kiselkov size_t
lz4_compress(void * s_start,void * d_start,size_t s_len,size_t d_len,int n)50a6f561b4SSašo Kiselkov lz4_compress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
51a6f561b4SSašo Kiselkov {
52a6f561b4SSašo Kiselkov 	uint32_t bufsiz;
53a6f561b4SSašo Kiselkov 	char *dest = d_start;
54a6f561b4SSašo Kiselkov 
55a6f561b4SSašo Kiselkov 	ASSERT(d_len >= sizeof (bufsiz));
56a6f561b4SSašo Kiselkov 
57a6f561b4SSašo Kiselkov 	bufsiz = real_LZ4_compress(s_start, &dest[sizeof (bufsiz)], s_len,
58a6f561b4SSašo Kiselkov 	    d_len - sizeof (bufsiz));
59a6f561b4SSašo Kiselkov 
60a6f561b4SSašo Kiselkov 	/* Signal an error if the compression routine returned zero. */
61a6f561b4SSašo Kiselkov 	if (bufsiz == 0)
62a6f561b4SSašo Kiselkov 		return (s_len);
63a6f561b4SSašo Kiselkov 
64a6f561b4SSašo Kiselkov 	/*
65a6f561b4SSašo Kiselkov 	 * Encode the compresed buffer size at the start. We'll need this in
66a6f561b4SSašo Kiselkov 	 * decompression to counter the effects of padding which might be
67a6f561b4SSašo Kiselkov 	 * added to the compressed buffer and which, if unhandled, would
68a6f561b4SSašo Kiselkov 	 * confuse the hell out of our decompression function.
69a6f561b4SSašo Kiselkov 	 */
70a6f561b4SSašo Kiselkov 	*(uint32_t *)dest = BE_32(bufsiz);
71a6f561b4SSašo Kiselkov 
72a6f561b4SSašo Kiselkov 	return (bufsiz + sizeof (bufsiz));
73a6f561b4SSašo Kiselkov }
74a6f561b4SSašo Kiselkov 
75a6f561b4SSašo Kiselkov /*ARGSUSED*/
76a6f561b4SSašo Kiselkov int
lz4_decompress(void * s_start,void * d_start,size_t s_len,size_t d_len,int n)77a6f561b4SSašo Kiselkov lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
78a6f561b4SSašo Kiselkov {
79a6f561b4SSašo Kiselkov 	const char *src = s_start;
80a6f561b4SSašo Kiselkov 	uint32_t bufsiz = BE_IN32(src);
81a6f561b4SSašo Kiselkov 
82a6f561b4SSašo Kiselkov 	/* invalid compressed buffer size encoded at start */
83a6f561b4SSašo Kiselkov 	if (bufsiz + sizeof (bufsiz) > s_len)
84a6f561b4SSašo Kiselkov 		return (1);
85a6f561b4SSašo Kiselkov 
86a6f561b4SSašo Kiselkov 	/*
87a6f561b4SSašo Kiselkov 	 * Returns 0 on success (decompression function returned non-negative)
88a6f561b4SSašo Kiselkov 	 * and non-zero on failure (decompression function returned negative.
89a6f561b4SSašo Kiselkov 	 */
90a6f561b4SSašo Kiselkov 	return (LZ4_uncompress_unknownOutputSize(&src[sizeof (bufsiz)],
91a6f561b4SSašo Kiselkov 	    d_start, bufsiz, d_len) < 0);
92a6f561b4SSašo Kiselkov }
93a6f561b4SSašo Kiselkov 
94a6f561b4SSašo Kiselkov /*
95a6f561b4SSašo Kiselkov  * LZ4 API Description:
96a6f561b4SSašo Kiselkov  *
97a6f561b4SSašo Kiselkov  * Simple Functions:
98a6f561b4SSašo Kiselkov  * real_LZ4_compress() :
99a6f561b4SSašo Kiselkov  * 	isize  : is the input size. Max supported value is ~1.9GB
100a6f561b4SSašo Kiselkov  * 	return : the number of bytes written in buffer dest
101a6f561b4SSašo Kiselkov  *		 or 0 if the compression fails (if LZ4_COMPRESSMIN is set).
102a6f561b4SSašo Kiselkov  * 	note : destination buffer must be already allocated.
103a6f561b4SSašo Kiselkov  * 		destination buffer must be sized to handle worst cases
104a6f561b4SSašo Kiselkov  * 		situations (input data not compressible) worst case size
105a6f561b4SSašo Kiselkov  * 		evaluation is provided by function LZ4_compressBound().
106a6f561b4SSašo Kiselkov  *
107a6f561b4SSašo Kiselkov  * real_LZ4_uncompress() :
108a6f561b4SSašo Kiselkov  * 	osize  : is the output size, therefore the original size
109a6f561b4SSašo Kiselkov  * 	return : the number of bytes read in the source buffer.
110a6f561b4SSašo Kiselkov  * 		If the source stream is malformed, the function will stop
111a6f561b4SSašo Kiselkov  * 		decoding and return a negative result, indicating the byte
112a6f561b4SSašo Kiselkov  * 		position of the faulty instruction. This function never
113a6f561b4SSašo Kiselkov  * 		writes beyond dest + osize, and is therefore protected
114a6f561b4SSašo Kiselkov  * 		against malicious data packets.
115a6f561b4SSašo Kiselkov  * 	note : destination buffer must be already allocated
116a6f561b4SSašo Kiselkov  *
117a6f561b4SSašo Kiselkov  * Advanced Functions
118a6f561b4SSašo Kiselkov  *
119a6f561b4SSašo Kiselkov  * LZ4_compressBound() :
120a6f561b4SSašo Kiselkov  * 	Provides the maximum size that LZ4 may output in a "worst case"
121a6f561b4SSašo Kiselkov  * 	scenario (input data not compressible) primarily useful for memory
122a6f561b4SSašo Kiselkov  * 	allocation of output buffer.
123a6f561b4SSašo Kiselkov  *
124a6f561b4SSašo Kiselkov  * 	isize  : is the input size. Max supported value is ~1.9GB
125a6f561b4SSašo Kiselkov  * 	return : maximum output size in a "worst case" scenario
126a6f561b4SSašo Kiselkov  * 	note : this function is limited by "int" range (2^31-1)
127a6f561b4SSašo Kiselkov  *
128a6f561b4SSašo Kiselkov  * LZ4_uncompress_unknownOutputSize() :
129a6f561b4SSašo Kiselkov  * 	isize  : is the input size, therefore the compressed size
130a6f561b4SSašo Kiselkov  * 	maxOutputSize : is the size of the destination buffer (which must be
131a6f561b4SSašo Kiselkov  * 		already allocated)
132a6f561b4SSašo Kiselkov  * 	return : the number of bytes decoded in the destination buffer
133a6f561b4SSašo Kiselkov  * 		(necessarily <= maxOutputSize). If the source stream is
134a6f561b4SSašo Kiselkov  * 		malformed, the function will stop decoding and return a
135a6f561b4SSašo Kiselkov  * 		negative result, indicating the byte position of the faulty
136a6f561b4SSašo Kiselkov  * 		instruction. This function never writes beyond dest +
137a6f561b4SSašo Kiselkov  * 		maxOutputSize, and is therefore protected against malicious
138a6f561b4SSašo Kiselkov  * 		data packets.
139a6f561b4SSašo Kiselkov  * 	note   : Destination buffer must be already allocated.
140a6f561b4SSašo Kiselkov  *		This version is slightly slower than real_LZ4_uncompress()
141a6f561b4SSašo Kiselkov  *
142a6f561b4SSašo Kiselkov  * LZ4_compressCtx() :
143a6f561b4SSašo Kiselkov  * 	This function explicitly handles the CTX memory structure.
144a6f561b4SSašo Kiselkov  *
145a6f561b4SSašo Kiselkov  * 	ILLUMOS CHANGES: the CTX memory structure must be explicitly allocated
146a6f561b4SSašo Kiselkov  * 	by the caller (either on the stack or using kmem_zalloc). Passing NULL
147a6f561b4SSašo Kiselkov  * 	isn't valid.
148a6f561b4SSašo Kiselkov  *
149a6f561b4SSašo Kiselkov  * LZ4_compress64kCtx() :
150a6f561b4SSašo Kiselkov  * 	Same as LZ4_compressCtx(), but specific to small inputs (<64KB).
151a6f561b4SSašo Kiselkov  * 	isize *Must* be <64KB, otherwise the output will be corrupted.
152a6f561b4SSašo Kiselkov  *
153a6f561b4SSašo Kiselkov  * 	ILLUMOS CHANGES: the CTX memory structure must be explicitly allocated
154a6f561b4SSašo Kiselkov  * 	by the caller (either on the stack or using kmem_zalloc). Passing NULL
155a6f561b4SSašo Kiselkov  * 	isn't valid.
156a6f561b4SSašo Kiselkov  */
157a6f561b4SSašo Kiselkov 
158a6f561b4SSašo Kiselkov /*
159a6f561b4SSašo Kiselkov  * Tuning parameters
160a6f561b4SSašo Kiselkov  */
161a6f561b4SSašo Kiselkov 
162a6f561b4SSašo Kiselkov /*
163a6f561b4SSašo Kiselkov  * COMPRESSIONLEVEL: Increasing this value improves compression ratio
164a6f561b4SSašo Kiselkov  *	 Lowering this value reduces memory usage. Reduced memory usage
165a6f561b4SSašo Kiselkov  *	typically improves speed, due to cache effect (ex: L1 32KB for Intel,
166a6f561b4SSašo Kiselkov  *	L1 64KB for AMD). Memory usage formula : N->2^(N+2) Bytes
167a6f561b4SSašo Kiselkov  *	(examples : 12 -> 16KB ; 17 -> 512KB)
168a6f561b4SSašo Kiselkov  */
169a6f561b4SSašo Kiselkov #define	COMPRESSIONLEVEL 12
170a6f561b4SSašo Kiselkov 
171a6f561b4SSašo Kiselkov /*
172a6f561b4SSašo Kiselkov  * NOTCOMPRESSIBLE_CONFIRMATION: Decreasing this value will make the
173a6f561b4SSašo Kiselkov  *	algorithm skip faster data segments considered "incompressible".
174a6f561b4SSašo Kiselkov  *	This may decrease compression ratio dramatically, but will be
175a6f561b4SSašo Kiselkov  *	faster on incompressible data. Increasing this value will make
176a6f561b4SSašo Kiselkov  *	the algorithm search more before declaring a segment "incompressible".
177a6f561b4SSašo Kiselkov  *	This could improve compression a bit, but will be slower on
178a6f561b4SSašo Kiselkov  *	incompressible data. The default value (6) is recommended.
179a6f561b4SSašo Kiselkov  */
180a6f561b4SSašo Kiselkov #define	NOTCOMPRESSIBLE_CONFIRMATION 6
181a6f561b4SSašo Kiselkov 
182a6f561b4SSašo Kiselkov /*
183a6f561b4SSašo Kiselkov  * BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE: This will provide a boost to
184a6f561b4SSašo Kiselkov  * performance for big endian cpu, but the resulting compressed stream
185a6f561b4SSašo Kiselkov  * will be incompatible with little-endian CPU. You can set this option
186a6f561b4SSašo Kiselkov  * to 1 in situations where data will stay within closed environment.
187a6f561b4SSašo Kiselkov  * This option is useless on Little_Endian CPU (such as x86).
188a6f561b4SSašo Kiselkov  */
189a6f561b4SSašo Kiselkov /* #define	BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 */
190a6f561b4SSašo Kiselkov 
191a6f561b4SSašo Kiselkov /*
192a6f561b4SSašo Kiselkov  * CPU Feature Detection
193a6f561b4SSašo Kiselkov  */
194a6f561b4SSašo Kiselkov 
195a6f561b4SSašo Kiselkov /* 32 or 64 bits ? */
196a6f561b4SSašo Kiselkov #if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || \
197a6f561b4SSašo Kiselkov     defined(__amd64) || defined(__ppc64__) || defined(_WIN64) || \
198a6f561b4SSašo Kiselkov     defined(__LP64__) || defined(_LP64))
199a6f561b4SSašo Kiselkov #define	LZ4_ARCH64 1
200a6f561b4SSašo Kiselkov #else
201a6f561b4SSašo Kiselkov #define	LZ4_ARCH64 0
202a6f561b4SSašo Kiselkov #endif
203a6f561b4SSašo Kiselkov 
204a6f561b4SSašo Kiselkov /*
205d8fa96c3SSašo Kiselkov  * Limits the amount of stack space that the algorithm may consume to hold
206d8fa96c3SSašo Kiselkov  * the compression lookup table. The value `9' here means we'll never use
207d8fa96c3SSašo Kiselkov  * more than 2k of stack (see above for a description of COMPRESSIONLEVEL).
208d8fa96c3SSašo Kiselkov  * If more memory is needed, it is allocated from the heap.
209d8fa96c3SSašo Kiselkov  */
210d8fa96c3SSašo Kiselkov #define	STACKLIMIT 9
211d8fa96c3SSašo Kiselkov 
212d8fa96c3SSašo Kiselkov /*
213a6f561b4SSašo Kiselkov  * Little Endian or Big Endian?
214a6f561b4SSašo Kiselkov  * Note: overwrite the below #define if you know your architecture endianess.
215a6f561b4SSašo Kiselkov  */
216a6f561b4SSašo Kiselkov #if (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || \
217a6f561b4SSašo Kiselkov 	defined(_BIG_ENDIAN) || defined(_ARCH_PPC) || defined(__PPC__) || \
218a6f561b4SSašo Kiselkov 	defined(__PPC) || defined(PPC) || defined(__powerpc__) || \
219a6f561b4SSašo Kiselkov 	defined(__powerpc) || defined(powerpc) || \
220a6f561b4SSašo Kiselkov 	((defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))))
221a6f561b4SSašo Kiselkov #define	LZ4_BIG_ENDIAN 1
222a6f561b4SSašo Kiselkov #else
223a6f561b4SSašo Kiselkov /*
224a6f561b4SSašo Kiselkov  * Little Endian assumed. PDP Endian and other very rare endian format
225a6f561b4SSašo Kiselkov  * are unsupported.
226a6f561b4SSašo Kiselkov  */
227a6f561b4SSašo Kiselkov #endif
228a6f561b4SSašo Kiselkov 
229a6f561b4SSašo Kiselkov /*
230a6f561b4SSašo Kiselkov  * Unaligned memory access is automatically enabled for "common" CPU,
231a6f561b4SSašo Kiselkov  * such as x86. For others CPU, the compiler will be more cautious, and
232a6f561b4SSašo Kiselkov  * insert extra code to ensure aligned access is respected. If you know
233a6f561b4SSašo Kiselkov  * your target CPU supports unaligned memory access, you may want to
234a6f561b4SSašo Kiselkov  * force this option manually to improve performance
235a6f561b4SSašo Kiselkov  */
236a6f561b4SSašo Kiselkov #if defined(__ARM_FEATURE_UNALIGNED)
237a6f561b4SSašo Kiselkov #define	LZ4_FORCE_UNALIGNED_ACCESS 1
238a6f561b4SSašo Kiselkov #endif
239a6f561b4SSašo Kiselkov 
2409c720e3bSIgor Kozhukhov #ifdef __sparc
2419c720e3bSIgor Kozhukhov #define	LZ4_FORCE_SW_BITCOUNT
2429c720e3bSIgor Kozhukhov #endif
243a6f561b4SSašo Kiselkov 
244a6f561b4SSašo Kiselkov /*
245a6f561b4SSašo Kiselkov  * Compiler Options
246a6f561b4SSašo Kiselkov  */
247a6f561b4SSašo Kiselkov #if __STDC_VERSION__ >= 199901L	/* C99 */
248a6f561b4SSašo Kiselkov /* "restrict" is a known keyword */
249a6f561b4SSašo Kiselkov #else
250a6f561b4SSašo Kiselkov /* Disable restrict */
251a6f561b4SSašo Kiselkov #define	restrict
252a6f561b4SSašo Kiselkov #endif
253a6f561b4SSašo Kiselkov 
254a6f561b4SSašo Kiselkov #define	GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
255a6f561b4SSašo Kiselkov 
256a6f561b4SSašo Kiselkov #ifdef _MSC_VER
257a6f561b4SSašo Kiselkov /* Visual Studio */
258a6f561b4SSašo Kiselkov /* Visual is not C99, but supports some kind of inline */
259a6f561b4SSašo Kiselkov #define	inline __forceinline
260a6f561b4SSašo Kiselkov #if LZ4_ARCH64
261a6f561b4SSašo Kiselkov /* For Visual 2005 */
262a6f561b4SSašo Kiselkov #pragma intrinsic(_BitScanForward64)
263a6f561b4SSašo Kiselkov #pragma intrinsic(_BitScanReverse64)
264a6f561b4SSašo Kiselkov #else /* !LZ4_ARCH64 */
265a6f561b4SSašo Kiselkov /* For Visual 2005 */
266a6f561b4SSašo Kiselkov #pragma intrinsic(_BitScanForward)
267a6f561b4SSašo Kiselkov #pragma intrinsic(_BitScanReverse)
268a6f561b4SSašo Kiselkov #endif /* !LZ4_ARCH64 */
269a6f561b4SSašo Kiselkov #endif /* _MSC_VER */
270a6f561b4SSašo Kiselkov 
271a6f561b4SSašo Kiselkov #ifdef _MSC_VER
272a6f561b4SSašo Kiselkov #define	lz4_bswap16(x) _byteswap_ushort(x)
273a6f561b4SSašo Kiselkov #else /* !_MSC_VER */
274a6f561b4SSašo Kiselkov #define	lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | \
275a6f561b4SSašo Kiselkov 	(((x) & 0xffu) << 8)))
276a6f561b4SSašo Kiselkov #endif /* !_MSC_VER */
277a6f561b4SSašo Kiselkov 
278a6f561b4SSašo Kiselkov #if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
279a6f561b4SSašo Kiselkov #define	expect(expr, value)    (__builtin_expect((expr), (value)))
280a6f561b4SSašo Kiselkov #else
281a6f561b4SSašo Kiselkov #define	expect(expr, value)    (expr)
282a6f561b4SSašo Kiselkov #endif
283a6f561b4SSašo Kiselkov 
284a6f561b4SSašo Kiselkov #define	likely(expr)	expect((expr) != 0, 1)
285a6f561b4SSašo Kiselkov #define	unlikely(expr)	expect((expr) != 0, 0)
286a6f561b4SSašo Kiselkov 
287a6f561b4SSašo Kiselkov /* Basic types */
288a6f561b4SSašo Kiselkov #if defined(_MSC_VER)
289a6f561b4SSašo Kiselkov /* Visual Studio does not support 'stdint' natively */
290a6f561b4SSašo Kiselkov #define	BYTE	unsigned __int8
291a6f561b4SSašo Kiselkov #define	U16	unsigned __int16
292a6f561b4SSašo Kiselkov #define	U32	unsigned __int32
293a6f561b4SSašo Kiselkov #define	S32	__int32
294a6f561b4SSašo Kiselkov #define	U64	unsigned __int64
295a6f561b4SSašo Kiselkov #else /* !defined(_MSC_VER) */
296a6f561b4SSašo Kiselkov #define	BYTE	uint8_t
297a6f561b4SSašo Kiselkov #define	U16	uint16_t
298a6f561b4SSašo Kiselkov #define	U32	uint32_t
299a6f561b4SSašo Kiselkov #define	S32	int32_t
300a6f561b4SSašo Kiselkov #define	U64	uint64_t
301a6f561b4SSašo Kiselkov #endif /* !defined(_MSC_VER) */
302a6f561b4SSašo Kiselkov 
303a6f561b4SSašo Kiselkov #ifndef LZ4_FORCE_UNALIGNED_ACCESS
304a6f561b4SSašo Kiselkov #pragma pack(1)
305a6f561b4SSašo Kiselkov #endif
306a6f561b4SSašo Kiselkov 
307a6f561b4SSašo Kiselkov typedef struct _U16_S {
308a6f561b4SSašo Kiselkov 	U16 v;
309a6f561b4SSašo Kiselkov } U16_S;
310a6f561b4SSašo Kiselkov typedef struct _U32_S {
311a6f561b4SSašo Kiselkov 	U32 v;
312a6f561b4SSašo Kiselkov } U32_S;
313a6f561b4SSašo Kiselkov typedef struct _U64_S {
314a6f561b4SSašo Kiselkov 	U64 v;
315a6f561b4SSašo Kiselkov } U64_S;
316a6f561b4SSašo Kiselkov 
317a6f561b4SSašo Kiselkov #ifndef LZ4_FORCE_UNALIGNED_ACCESS
318a6f561b4SSašo Kiselkov #pragma pack()
319a6f561b4SSašo Kiselkov #endif
320a6f561b4SSašo Kiselkov 
321a6f561b4SSašo Kiselkov #define	A64(x) (((U64_S *)(x))->v)
322a6f561b4SSašo Kiselkov #define	A32(x) (((U32_S *)(x))->v)
323a6f561b4SSašo Kiselkov #define	A16(x) (((U16_S *)(x))->v)
324a6f561b4SSašo Kiselkov 
325a6f561b4SSašo Kiselkov /*
326a6f561b4SSašo Kiselkov  * Constants
327a6f561b4SSašo Kiselkov  */
328a6f561b4SSašo Kiselkov #define	MINMATCH 4
329a6f561b4SSašo Kiselkov 
330a6f561b4SSašo Kiselkov #define	HASH_LOG COMPRESSIONLEVEL
331a6f561b4SSašo Kiselkov #define	HASHTABLESIZE (1 << HASH_LOG)
332a6f561b4SSašo Kiselkov #define	HASH_MASK (HASHTABLESIZE - 1)
333a6f561b4SSašo Kiselkov 
334a6f561b4SSašo Kiselkov #define	SKIPSTRENGTH (NOTCOMPRESSIBLE_CONFIRMATION > 2 ? \
335a6f561b4SSašo Kiselkov 	NOTCOMPRESSIBLE_CONFIRMATION : 2)
336a6f561b4SSašo Kiselkov 
337a6f561b4SSašo Kiselkov /*
338a6f561b4SSašo Kiselkov  * Defines if memory is allocated into the stack (local variable),
339a6f561b4SSašo Kiselkov  * or into the heap (kmem_alloc()).
340a6f561b4SSašo Kiselkov  */
341a6f561b4SSašo Kiselkov #define	HEAPMODE (HASH_LOG > STACKLIMIT)
342a6f561b4SSašo Kiselkov #define	COPYLENGTH 8
343a6f561b4SSašo Kiselkov #define	LASTLITERALS 5
344a6f561b4SSašo Kiselkov #define	MFLIMIT (COPYLENGTH + MINMATCH)
345a6f561b4SSašo Kiselkov #define	MINLENGTH (MFLIMIT + 1)
346a6f561b4SSašo Kiselkov 
347a6f561b4SSašo Kiselkov #define	MAXD_LOG 16
348a6f561b4SSašo Kiselkov #define	MAX_DISTANCE ((1 << MAXD_LOG) - 1)
349a6f561b4SSašo Kiselkov 
350a6f561b4SSašo Kiselkov #define	ML_BITS 4
351a6f561b4SSašo Kiselkov #define	ML_MASK ((1U<<ML_BITS)-1)
352a6f561b4SSašo Kiselkov #define	RUN_BITS (8-ML_BITS)
353a6f561b4SSašo Kiselkov #define	RUN_MASK ((1U<<RUN_BITS)-1)
354a6f561b4SSašo Kiselkov 
355a6f561b4SSašo Kiselkov 
356a6f561b4SSašo Kiselkov /*
357a6f561b4SSašo Kiselkov  * Architecture-specific macros
358a6f561b4SSašo Kiselkov  */
359a6f561b4SSašo Kiselkov #if LZ4_ARCH64
360a6f561b4SSašo Kiselkov #define	STEPSIZE 8
361a6f561b4SSašo Kiselkov #define	UARCH U64
362a6f561b4SSašo Kiselkov #define	AARCH A64
363a6f561b4SSašo Kiselkov #define	LZ4_COPYSTEP(s, d)	A64(d) = A64(s); d += 8; s += 8;
364a6f561b4SSašo Kiselkov #define	LZ4_COPYPACKET(s, d)	LZ4_COPYSTEP(s, d)
365a6f561b4SSašo Kiselkov #define	LZ4_SECURECOPY(s, d, e)	if (d < e) LZ4_WILDCOPY(s, d, e)
366a6f561b4SSašo Kiselkov #define	HTYPE U32
367a6f561b4SSašo Kiselkov #define	INITBASE(base)		const BYTE* const base = ip
368a6f561b4SSašo Kiselkov #else /* !LZ4_ARCH64 */
369a6f561b4SSašo Kiselkov #define	STEPSIZE 4
370a6f561b4SSašo Kiselkov #define	UARCH U32
371a6f561b4SSašo Kiselkov #define	AARCH A32
372a6f561b4SSašo Kiselkov #define	LZ4_COPYSTEP(s, d)	A32(d) = A32(s); d += 4; s += 4;
373a6f561b4SSašo Kiselkov #define	LZ4_COPYPACKET(s, d)	LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d);
374a6f561b4SSašo Kiselkov #define	LZ4_SECURECOPY		LZ4_WILDCOPY
375a6f561b4SSašo Kiselkov #define	HTYPE const BYTE *
376a6f561b4SSašo Kiselkov #define	INITBASE(base)		const int base = 0
377a6f561b4SSašo Kiselkov #endif /* !LZ4_ARCH64 */
378a6f561b4SSašo Kiselkov 
379a6f561b4SSašo Kiselkov #if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE))
380a6f561b4SSašo Kiselkov #define	LZ4_READ_LITTLEENDIAN_16(d, s, p) \
381a6f561b4SSašo Kiselkov 	{ U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; }
382a6f561b4SSašo Kiselkov #define	LZ4_WRITE_LITTLEENDIAN_16(p, i) \
383a6f561b4SSašo Kiselkov 	{ U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p += 2; }
384a6f561b4SSašo Kiselkov #else
385a6f561b4SSašo Kiselkov #define	LZ4_READ_LITTLEENDIAN_16(d, s, p) { d = (s) - A16(p); }
386a6f561b4SSašo Kiselkov #define	LZ4_WRITE_LITTLEENDIAN_16(p, v)  { A16(p) = v; p += 2; }
387a6f561b4SSašo Kiselkov #endif
388a6f561b4SSašo Kiselkov 
389a6f561b4SSašo Kiselkov 
390a6f561b4SSašo Kiselkov /* Local structures */
391a6f561b4SSašo Kiselkov struct refTables {
392a6f561b4SSašo Kiselkov 	HTYPE hashTable[HASHTABLESIZE];
393a6f561b4SSašo Kiselkov };
394a6f561b4SSašo Kiselkov 
395a6f561b4SSašo Kiselkov 
396a6f561b4SSašo Kiselkov /* Macros */
397a6f561b4SSašo Kiselkov #define	LZ4_HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH * 8) - \
398a6f561b4SSašo Kiselkov 	HASH_LOG))
399a6f561b4SSašo Kiselkov #define	LZ4_HASH_VALUE(p) LZ4_HASH_FUNCTION(A32(p))
400a6f561b4SSašo Kiselkov #define	LZ4_WILDCOPY(s, d, e) do { LZ4_COPYPACKET(s, d) } while (d < e);
401a6f561b4SSašo Kiselkov #define	LZ4_BLINDCOPY(s, d, l) { BYTE* e = (d) + l; LZ4_WILDCOPY(s, d, e); \
402a6f561b4SSašo Kiselkov 	d = e; }
403a6f561b4SSašo Kiselkov 
404a6f561b4SSašo Kiselkov 
405a6f561b4SSašo Kiselkov /* Private functions */
406a6f561b4SSašo Kiselkov #if LZ4_ARCH64
407a6f561b4SSašo Kiselkov 
408a6f561b4SSašo Kiselkov static inline int
LZ4_NbCommonBytes(register U64 val)409a6f561b4SSašo Kiselkov LZ4_NbCommonBytes(register U64 val)
410a6f561b4SSašo Kiselkov {
411a6f561b4SSašo Kiselkov #if defined(LZ4_BIG_ENDIAN)
412a6f561b4SSašo Kiselkov #if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
413a6f561b4SSašo Kiselkov 	unsigned long r = 0;
414a6f561b4SSašo Kiselkov 	_BitScanReverse64(&r, val);
415a6f561b4SSašo Kiselkov 	return (int)(r >> 3);
416a6f561b4SSašo Kiselkov #elif defined(__GNUC__) && (GCC_VERSION >= 304) && \
417a6f561b4SSašo Kiselkov 	!defined(LZ4_FORCE_SW_BITCOUNT)
418a6f561b4SSašo Kiselkov 	return (__builtin_clzll(val) >> 3);
419a6f561b4SSašo Kiselkov #else
420a6f561b4SSašo Kiselkov 	int r;
421a6f561b4SSašo Kiselkov 	if (!(val >> 32)) {
422a6f561b4SSašo Kiselkov 		r = 4;
423a6f561b4SSašo Kiselkov 	} else {
424a6f561b4SSašo Kiselkov 		r = 0;
425a6f561b4SSašo Kiselkov 		val >>= 32;
426a6f561b4SSašo Kiselkov 	}
427a6f561b4SSašo Kiselkov 	if (!(val >> 16)) {
428a6f561b4SSašo Kiselkov 		r += 2;
429a6f561b4SSašo Kiselkov 		val >>= 8;
430a6f561b4SSašo Kiselkov 	} else {
431a6f561b4SSašo Kiselkov 		val >>= 24;
432a6f561b4SSašo Kiselkov 	}
433a6f561b4SSašo Kiselkov 	r += (!val);
434a6f561b4SSašo Kiselkov 	return (r);
435a6f561b4SSašo Kiselkov #endif
436a6f561b4SSašo Kiselkov #else
437a6f561b4SSašo Kiselkov #if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
438a6f561b4SSašo Kiselkov 	unsigned long r = 0;
439a6f561b4SSašo Kiselkov 	_BitScanForward64(&r, val);
440a6f561b4SSašo Kiselkov 	return (int)(r >> 3);
441a6f561b4SSašo Kiselkov #elif defined(__GNUC__) && (GCC_VERSION >= 304) && \
442a6f561b4SSašo Kiselkov 	!defined(LZ4_FORCE_SW_BITCOUNT)
443a6f561b4SSašo Kiselkov 	return (__builtin_ctzll(val) >> 3);
444a6f561b4SSašo Kiselkov #else
445a6f561b4SSašo Kiselkov 	static const int DeBruijnBytePos[64] =
446a6f561b4SSašo Kiselkov 	    { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5,
447a6f561b4SSašo Kiselkov 		3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5,
448a6f561b4SSašo Kiselkov 		5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4,
449a6f561b4SSašo Kiselkov 		4, 5, 7, 2, 6, 5, 7, 6, 7, 7
450a6f561b4SSašo Kiselkov 	};
451a6f561b4SSašo Kiselkov 	return DeBruijnBytePos[((U64) ((val & -val) * 0x0218A392CDABBD3F)) >>
452a6f561b4SSašo Kiselkov 	    58];
453a6f561b4SSašo Kiselkov #endif
454a6f561b4SSašo Kiselkov #endif
455a6f561b4SSašo Kiselkov }
456a6f561b4SSašo Kiselkov 
457a6f561b4SSašo Kiselkov #else
458a6f561b4SSašo Kiselkov 
459a6f561b4SSašo Kiselkov static inline int
LZ4_NbCommonBytes(register U32 val)460a6f561b4SSašo Kiselkov LZ4_NbCommonBytes(register U32 val)
461a6f561b4SSašo Kiselkov {
462a6f561b4SSašo Kiselkov #if defined(LZ4_BIG_ENDIAN)
463a6f561b4SSašo Kiselkov #if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
464a6f561b4SSašo Kiselkov 	unsigned long r = 0;
465a6f561b4SSašo Kiselkov 	_BitScanReverse(&r, val);
466a6f561b4SSašo Kiselkov 	return (int)(r >> 3);
467a6f561b4SSašo Kiselkov #elif defined(__GNUC__) && (GCC_VERSION >= 304) && \
468a6f561b4SSašo Kiselkov 	!defined(LZ4_FORCE_SW_BITCOUNT)
469a6f561b4SSašo Kiselkov 	return (__builtin_clz(val) >> 3);
470a6f561b4SSašo Kiselkov #else
471a6f561b4SSašo Kiselkov 	int r;
472a6f561b4SSašo Kiselkov 	if (!(val >> 16)) {
473a6f561b4SSašo Kiselkov 		r = 2;
474a6f561b4SSašo Kiselkov 		val >>= 8;
475a6f561b4SSašo Kiselkov 	} else {
476a6f561b4SSašo Kiselkov 		r = 0;
477a6f561b4SSašo Kiselkov 		val >>= 24;
478a6f561b4SSašo Kiselkov 	}
479a6f561b4SSašo Kiselkov 	r += (!val);
480a6f561b4SSašo Kiselkov 	return (r);
481a6f561b4SSašo Kiselkov #endif
482a6f561b4SSašo Kiselkov #else
483a6f561b4SSašo Kiselkov #if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
484a6f561b4SSašo Kiselkov 	unsigned long r = 0;
485a6f561b4SSašo Kiselkov 	_BitScanForward(&r, val);
486a6f561b4SSašo Kiselkov 	return (int)(r >> 3);
487a6f561b4SSašo Kiselkov #elif defined(__GNUC__) && (GCC_VERSION >= 304) && \
488a6f561b4SSašo Kiselkov 	!defined(LZ4_FORCE_SW_BITCOUNT)
489a6f561b4SSašo Kiselkov 	return (__builtin_ctz(val) >> 3);
490a6f561b4SSašo Kiselkov #else
491a6f561b4SSašo Kiselkov 	static const int DeBruijnBytePos[32] = {
492a6f561b4SSašo Kiselkov 		0, 0, 3, 0, 3, 1, 3, 0,
493a6f561b4SSašo Kiselkov 		3, 2, 2, 1, 3, 2, 0, 1,
494a6f561b4SSašo Kiselkov 		3, 3, 1, 2, 2, 2, 2, 0,
495a6f561b4SSašo Kiselkov 		3, 1, 2, 0, 1, 0, 1, 1
496a6f561b4SSašo Kiselkov 	};
497a6f561b4SSašo Kiselkov 	return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >>
498a6f561b4SSašo Kiselkov 	    27];
499a6f561b4SSašo Kiselkov #endif
500a6f561b4SSašo Kiselkov #endif
501a6f561b4SSašo Kiselkov }
502a6f561b4SSašo Kiselkov 
503a6f561b4SSašo Kiselkov #endif
504a6f561b4SSašo Kiselkov 
505a6f561b4SSašo Kiselkov /* Public functions */
506a6f561b4SSašo Kiselkov 
507a6f561b4SSašo Kiselkov static int
LZ4_compressBound(int isize)508a6f561b4SSašo Kiselkov LZ4_compressBound(int isize)
509a6f561b4SSašo Kiselkov {
510a6f561b4SSašo Kiselkov 	return (isize + (isize / 255) + 16);
511a6f561b4SSašo Kiselkov }
512a6f561b4SSašo Kiselkov 
513a6f561b4SSašo Kiselkov /* Compression functions */
514a6f561b4SSašo Kiselkov 
515a6f561b4SSašo Kiselkov /*ARGSUSED*/
516a6f561b4SSašo Kiselkov static int
LZ4_compressCtx(void * ctx,const char * source,char * dest,int isize,int osize)517a6f561b4SSašo Kiselkov LZ4_compressCtx(void *ctx, const char *source, char *dest, int isize,
518a6f561b4SSašo Kiselkov     int osize)
519a6f561b4SSašo Kiselkov {
520a6f561b4SSašo Kiselkov #if HEAPMODE
521a6f561b4SSašo Kiselkov 	struct refTables *srt = (struct refTables *)ctx;
522a6f561b4SSašo Kiselkov 	HTYPE *HashTable = (HTYPE *) (srt->hashTable);
523a6f561b4SSašo Kiselkov #else
524a6f561b4SSašo Kiselkov 	HTYPE HashTable[HASHTABLESIZE] = { 0 };
525a6f561b4SSašo Kiselkov #endif
526a6f561b4SSašo Kiselkov 
527a6f561b4SSašo Kiselkov 	const BYTE *ip = (BYTE *) source;
528a6f561b4SSašo Kiselkov 	INITBASE(base);
529a6f561b4SSašo Kiselkov 	const BYTE *anchor = ip;
530a6f561b4SSašo Kiselkov 	const BYTE *const iend = ip + isize;
531a6f561b4SSašo Kiselkov 	const BYTE *const oend = (BYTE *) dest + osize;
532a6f561b4SSašo Kiselkov 	const BYTE *const mflimit = iend - MFLIMIT;
533a6f561b4SSašo Kiselkov #define	matchlimit (iend - LASTLITERALS)
534a6f561b4SSašo Kiselkov 
535a6f561b4SSašo Kiselkov 	BYTE *op = (BYTE *) dest;
536a6f561b4SSašo Kiselkov 
537a6f561b4SSašo Kiselkov 	int len, length;
538a6f561b4SSašo Kiselkov 	const int skipStrength = SKIPSTRENGTH;
539a6f561b4SSašo Kiselkov 	U32 forwardH;
540a6f561b4SSašo Kiselkov 
541a6f561b4SSašo Kiselkov 
542a6f561b4SSašo Kiselkov 	/* Init */
543a6f561b4SSašo Kiselkov 	if (isize < MINLENGTH)
544a6f561b4SSašo Kiselkov 		goto _last_literals;
545a6f561b4SSašo Kiselkov 
546a6f561b4SSašo Kiselkov 	/* First Byte */
547a6f561b4SSašo Kiselkov 	HashTable[LZ4_HASH_VALUE(ip)] = ip - base;
548a6f561b4SSašo Kiselkov 	ip++;
549a6f561b4SSašo Kiselkov 	forwardH = LZ4_HASH_VALUE(ip);
550a6f561b4SSašo Kiselkov 
551a6f561b4SSašo Kiselkov 	/* Main Loop */
552a6f561b4SSašo Kiselkov 	for (;;) {
553a6f561b4SSašo Kiselkov 		int findMatchAttempts = (1U << skipStrength) + 3;
554a6f561b4SSašo Kiselkov 		const BYTE *forwardIp = ip;
555a6f561b4SSašo Kiselkov 		const BYTE *ref;
556a6f561b4SSašo Kiselkov 		BYTE *token;
557a6f561b4SSašo Kiselkov 
558a6f561b4SSašo Kiselkov 		/* Find a match */
559a6f561b4SSašo Kiselkov 		do {
560a6f561b4SSašo Kiselkov 			U32 h = forwardH;
561a6f561b4SSašo Kiselkov 			int step = findMatchAttempts++ >> skipStrength;
562a6f561b4SSašo Kiselkov 			ip = forwardIp;
563a6f561b4SSašo Kiselkov 			forwardIp = ip + step;
564a6f561b4SSašo Kiselkov 
565a6f561b4SSašo Kiselkov 			if unlikely(forwardIp > mflimit) {
566a6f561b4SSašo Kiselkov 				goto _last_literals;
567a6f561b4SSašo Kiselkov 			}
568a6f561b4SSašo Kiselkov 
569a6f561b4SSašo Kiselkov 			forwardH = LZ4_HASH_VALUE(forwardIp);
570a6f561b4SSašo Kiselkov 			ref = base + HashTable[h];
571a6f561b4SSašo Kiselkov 			HashTable[h] = ip - base;
572a6f561b4SSašo Kiselkov 
573a6f561b4SSašo Kiselkov 		} while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip)));
574a6f561b4SSašo Kiselkov 
575a6f561b4SSašo Kiselkov 		/* Catch up */
576a6f561b4SSašo Kiselkov 		while ((ip > anchor) && (ref > (BYTE *) source) &&
577a6f561b4SSašo Kiselkov 		    unlikely(ip[-1] == ref[-1])) {
578a6f561b4SSašo Kiselkov 			ip--;
579a6f561b4SSašo Kiselkov 			ref--;
580a6f561b4SSašo Kiselkov 		}
581a6f561b4SSašo Kiselkov 
582a6f561b4SSašo Kiselkov 		/* Encode Literal length */
583a6f561b4SSašo Kiselkov 		length = ip - anchor;
584a6f561b4SSašo Kiselkov 		token = op++;
585a6f561b4SSašo Kiselkov 
586a6f561b4SSašo Kiselkov 		/* Check output limit */
587a6f561b4SSašo Kiselkov 		if unlikely(op + length + (2 + 1 + LASTLITERALS) +
588a6f561b4SSašo Kiselkov 		    (length >> 8) > oend)
589a6f561b4SSašo Kiselkov 			return (0);
590a6f561b4SSašo Kiselkov 
591a6f561b4SSašo Kiselkov 		if (length >= (int)RUN_MASK) {
592a6f561b4SSašo Kiselkov 			*token = (RUN_MASK << ML_BITS);
593a6f561b4SSašo Kiselkov 			len = length - RUN_MASK;
594a6f561b4SSašo Kiselkov 			for (; len > 254; len -= 255)
595a6f561b4SSašo Kiselkov 				*op++ = 255;
596a6f561b4SSašo Kiselkov 			*op++ = (BYTE)len;
597a6f561b4SSašo Kiselkov 		} else
598a6f561b4SSašo Kiselkov 			*token = (length << ML_BITS);
599a6f561b4SSašo Kiselkov 
600a6f561b4SSašo Kiselkov 		/* Copy Literals */
601a6f561b4SSašo Kiselkov 		LZ4_BLINDCOPY(anchor, op, length);
602a6f561b4SSašo Kiselkov 
603a6f561b4SSašo Kiselkov 		_next_match:
604a6f561b4SSašo Kiselkov 		/* Encode Offset */
605a6f561b4SSašo Kiselkov 		LZ4_WRITE_LITTLEENDIAN_16(op, ip - ref);
606a6f561b4SSašo Kiselkov 
607a6f561b4SSašo Kiselkov 		/* Start Counting */
608a6f561b4SSašo Kiselkov 		ip += MINMATCH;
609a6f561b4SSašo Kiselkov 		ref += MINMATCH;	/* MinMatch verified */
610a6f561b4SSašo Kiselkov 		anchor = ip;
611a6f561b4SSašo Kiselkov 		while likely(ip < matchlimit - (STEPSIZE - 1)) {
612a6f561b4SSašo Kiselkov 			UARCH diff = AARCH(ref) ^ AARCH(ip);
613a6f561b4SSašo Kiselkov 			if (!diff) {
614a6f561b4SSašo Kiselkov 				ip += STEPSIZE;
615a6f561b4SSašo Kiselkov 				ref += STEPSIZE;
616a6f561b4SSašo Kiselkov 				continue;
617a6f561b4SSašo Kiselkov 			}
618a6f561b4SSašo Kiselkov 			ip += LZ4_NbCommonBytes(diff);
619a6f561b4SSašo Kiselkov 			goto _endCount;
620a6f561b4SSašo Kiselkov 		}
621a6f561b4SSašo Kiselkov #if LZ4_ARCH64
622a6f561b4SSašo Kiselkov 		if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) {
623a6f561b4SSašo Kiselkov 			ip += 4;
624a6f561b4SSašo Kiselkov 			ref += 4;
625a6f561b4SSašo Kiselkov 		}
626a6f561b4SSašo Kiselkov #endif
627a6f561b4SSašo Kiselkov 		if ((ip < (matchlimit - 1)) && (A16(ref) == A16(ip))) {
628a6f561b4SSašo Kiselkov 			ip += 2;
629a6f561b4SSašo Kiselkov 			ref += 2;
630a6f561b4SSašo Kiselkov 		}
631a6f561b4SSašo Kiselkov 		if ((ip < matchlimit) && (*ref == *ip))
632a6f561b4SSašo Kiselkov 			ip++;
633a6f561b4SSašo Kiselkov 		_endCount:
634a6f561b4SSašo Kiselkov 
635a6f561b4SSašo Kiselkov 		/* Encode MatchLength */
636a6f561b4SSašo Kiselkov 		len = (ip - anchor);
637a6f561b4SSašo Kiselkov 		/* Check output limit */
638a6f561b4SSašo Kiselkov 		if unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend)
639a6f561b4SSašo Kiselkov 			return (0);
640a6f561b4SSašo Kiselkov 		if (len >= (int)ML_MASK) {
641a6f561b4SSašo Kiselkov 			*token += ML_MASK;
642a6f561b4SSašo Kiselkov 			len -= ML_MASK;
643a6f561b4SSašo Kiselkov 			for (; len > 509; len -= 510) {
644a6f561b4SSašo Kiselkov 				*op++ = 255;
645a6f561b4SSašo Kiselkov 				*op++ = 255;
646a6f561b4SSašo Kiselkov 			}
647a6f561b4SSašo Kiselkov 			if (len > 254) {
648a6f561b4SSašo Kiselkov 				len -= 255;
649a6f561b4SSašo Kiselkov 				*op++ = 255;
650a6f561b4SSašo Kiselkov 			}
651a6f561b4SSašo Kiselkov 			*op++ = (BYTE)len;
652a6f561b4SSašo Kiselkov 		} else
653a6f561b4SSašo Kiselkov 			*token += len;
654a6f561b4SSašo Kiselkov 
655a6f561b4SSašo Kiselkov 		/* Test end of chunk */
656a6f561b4SSašo Kiselkov 		if (ip > mflimit) {
657a6f561b4SSašo Kiselkov 			anchor = ip;
658a6f561b4SSašo Kiselkov 			break;
659a6f561b4SSašo Kiselkov 		}
660a6f561b4SSašo Kiselkov 		/* Fill table */
661a6f561b4SSašo Kiselkov 		HashTable[LZ4_HASH_VALUE(ip - 2)] = ip - 2 - base;
662a6f561b4SSašo Kiselkov 
663a6f561b4SSašo Kiselkov 		/* Test next position */
664a6f561b4SSašo Kiselkov 		ref = base + HashTable[LZ4_HASH_VALUE(ip)];
665a6f561b4SSašo Kiselkov 		HashTable[LZ4_HASH_VALUE(ip)] = ip - base;
666a6f561b4SSašo Kiselkov 		if ((ref > ip - (MAX_DISTANCE + 1)) && (A32(ref) == A32(ip))) {
667a6f561b4SSašo Kiselkov 			token = op++;
668a6f561b4SSašo Kiselkov 			*token = 0;
669a6f561b4SSašo Kiselkov 			goto _next_match;
670a6f561b4SSašo Kiselkov 		}
671a6f561b4SSašo Kiselkov 		/* Prepare next loop */
672a6f561b4SSašo Kiselkov 		anchor = ip++;
673a6f561b4SSašo Kiselkov 		forwardH = LZ4_HASH_VALUE(ip);
674a6f561b4SSašo Kiselkov 	}
675a6f561b4SSašo Kiselkov 
676a6f561b4SSašo Kiselkov 	_last_literals:
677a6f561b4SSašo Kiselkov 	/* Encode Last Literals */
678a6f561b4SSašo Kiselkov 	{
679a6f561b4SSašo Kiselkov 		int lastRun = iend - anchor;
680a6f561b4SSašo Kiselkov 		if (op + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) >
681a6f561b4SSašo Kiselkov 		    oend)
682a6f561b4SSašo Kiselkov 			return (0);
683a6f561b4SSašo Kiselkov 		if (lastRun >= (int)RUN_MASK) {
684a6f561b4SSašo Kiselkov 			*op++ = (RUN_MASK << ML_BITS);
685a6f561b4SSašo Kiselkov 			lastRun -= RUN_MASK;
686a6f561b4SSašo Kiselkov 			for (; lastRun > 254; lastRun -= 255) {
687a6f561b4SSašo Kiselkov 				*op++ = 255;
688a6f561b4SSašo Kiselkov 			}
689a6f561b4SSašo Kiselkov 			*op++ = (BYTE)lastRun;
690a6f561b4SSašo Kiselkov 		} else
691a6f561b4SSašo Kiselkov 			*op++ = (lastRun << ML_BITS);
692a6f561b4SSašo Kiselkov 		(void) memcpy(op, anchor, iend - anchor);
693a6f561b4SSašo Kiselkov 		op += iend - anchor;
694a6f561b4SSašo Kiselkov 	}
695a6f561b4SSašo Kiselkov 
696a6f561b4SSašo Kiselkov 	/* End */
697a6f561b4SSašo Kiselkov 	return (int)(((char *)op) - dest);
698a6f561b4SSašo Kiselkov }
699a6f561b4SSašo Kiselkov 
700a6f561b4SSašo Kiselkov 
701a6f561b4SSašo Kiselkov 
702a6f561b4SSašo Kiselkov /* Note : this function is valid only if isize < LZ4_64KLIMIT */
703a6f561b4SSašo Kiselkov #define	LZ4_64KLIMIT ((1 << 16) + (MFLIMIT - 1))
704a6f561b4SSašo Kiselkov #define	HASHLOG64K (HASH_LOG + 1)
705a6f561b4SSašo Kiselkov #define	HASH64KTABLESIZE (1U << HASHLOG64K)
706a6f561b4SSašo Kiselkov #define	LZ4_HASH64K_FUNCTION(i)	(((i) * 2654435761U) >> ((MINMATCH*8) - \
707a6f561b4SSašo Kiselkov 	HASHLOG64K))
708a6f561b4SSašo Kiselkov #define	LZ4_HASH64K_VALUE(p)	LZ4_HASH64K_FUNCTION(A32(p))
709a6f561b4SSašo Kiselkov 
710a6f561b4SSašo Kiselkov /*ARGSUSED*/
711a6f561b4SSašo Kiselkov static int
LZ4_compress64kCtx(void * ctx,const char * source,char * dest,int isize,int osize)712a6f561b4SSašo Kiselkov LZ4_compress64kCtx(void *ctx, const char *source, char *dest, int isize,
713a6f561b4SSašo Kiselkov     int osize)
714a6f561b4SSašo Kiselkov {
715a6f561b4SSašo Kiselkov #if HEAPMODE
716a6f561b4SSašo Kiselkov 	struct refTables *srt = (struct refTables *)ctx;
717a6f561b4SSašo Kiselkov 	U16 *HashTable = (U16 *) (srt->hashTable);
718a6f561b4SSašo Kiselkov #else
719a6f561b4SSašo Kiselkov 	U16 HashTable[HASH64KTABLESIZE] = { 0 };
720a6f561b4SSašo Kiselkov #endif
721a6f561b4SSašo Kiselkov 
722a6f561b4SSašo Kiselkov 	const BYTE *ip = (BYTE *) source;
723a6f561b4SSašo Kiselkov 	const BYTE *anchor = ip;
724a6f561b4SSašo Kiselkov 	const BYTE *const base = ip;
725a6f561b4SSašo Kiselkov 	const BYTE *const iend = ip + isize;
726a6f561b4SSašo Kiselkov 	const BYTE *const oend = (BYTE *) dest + osize;
727a6f561b4SSašo Kiselkov 	const BYTE *const mflimit = iend - MFLIMIT;
728a6f561b4SSašo Kiselkov #define	matchlimit (iend - LASTLITERALS)
729a6f561b4SSašo Kiselkov 
730a6f561b4SSašo Kiselkov 	BYTE *op = (BYTE *) dest;
731a6f561b4SSašo Kiselkov 
732a6f561b4SSašo Kiselkov 	int len, length;
733a6f561b4SSašo Kiselkov 	const int skipStrength = SKIPSTRENGTH;
734a6f561b4SSašo Kiselkov 	U32 forwardH;
735a6f561b4SSašo Kiselkov 
736a6f561b4SSašo Kiselkov 	/* Init */
737a6f561b4SSašo Kiselkov 	if (isize < MINLENGTH)
738a6f561b4SSašo Kiselkov 		goto _last_literals;
739a6f561b4SSašo Kiselkov 
740a6f561b4SSašo Kiselkov 	/* First Byte */
741a6f561b4SSašo Kiselkov 	ip++;
742a6f561b4SSašo Kiselkov 	forwardH = LZ4_HASH64K_VALUE(ip);
743a6f561b4SSašo Kiselkov 
744a6f561b4SSašo Kiselkov 	/* Main Loop */
745a6f561b4SSašo Kiselkov 	for (;;) {
746a6f561b4SSašo Kiselkov 		int findMatchAttempts = (1U << skipStrength) + 3;
747a6f561b4SSašo Kiselkov 		const BYTE *forwardIp = ip;
748a6f561b4SSašo Kiselkov 		const BYTE *ref;
749a6f561b4SSašo Kiselkov 		BYTE *token;
750a6f561b4SSašo Kiselkov 
751a6f561b4SSašo Kiselkov 		/* Find a match */
752a6f561b4SSašo Kiselkov 		do {
753a6f561b4SSašo Kiselkov 			U32 h = forwardH;
754a6f561b4SSašo Kiselkov 			int step = findMatchAttempts++ >> skipStrength;
755a6f561b4SSašo Kiselkov 			ip = forwardIp;
756a6f561b4SSašo Kiselkov 			forwardIp = ip + step;
757a6f561b4SSašo Kiselkov 
758a6f561b4SSašo Kiselkov 			if (forwardIp > mflimit) {
759a6f561b4SSašo Kiselkov 				goto _last_literals;
760a6f561b4SSašo Kiselkov 			}
761a6f561b4SSašo Kiselkov 
762a6f561b4SSašo Kiselkov 			forwardH = LZ4_HASH64K_VALUE(forwardIp);
763a6f561b4SSašo Kiselkov 			ref = base + HashTable[h];
764a6f561b4SSašo Kiselkov 			HashTable[h] = ip - base;
765a6f561b4SSašo Kiselkov 
766a6f561b4SSašo Kiselkov 		} while (A32(ref) != A32(ip));
767a6f561b4SSašo Kiselkov 
768a6f561b4SSašo Kiselkov 		/* Catch up */
769a6f561b4SSašo Kiselkov 		while ((ip > anchor) && (ref > (BYTE *) source) &&
770a6f561b4SSašo Kiselkov 		    (ip[-1] == ref[-1])) {
771a6f561b4SSašo Kiselkov 			ip--;
772a6f561b4SSašo Kiselkov 			ref--;
773a6f561b4SSašo Kiselkov 		}
774a6f561b4SSašo Kiselkov 
775a6f561b4SSašo Kiselkov 		/* Encode Literal length */
776a6f561b4SSašo Kiselkov 		length = ip - anchor;
777a6f561b4SSašo Kiselkov 		token = op++;
778a6f561b4SSašo Kiselkov 
779a6f561b4SSašo Kiselkov 		/* Check output limit */
780a6f561b4SSašo Kiselkov 		if unlikely(op + length + (2 + 1 + LASTLITERALS) +
781a6f561b4SSašo Kiselkov 		    (length >> 8) > oend)
782a6f561b4SSašo Kiselkov 			return (0);
783a6f561b4SSašo Kiselkov 
784a6f561b4SSašo Kiselkov 		if (length >= (int)RUN_MASK) {
785a6f561b4SSašo Kiselkov 			*token = (RUN_MASK << ML_BITS);
786a6f561b4SSašo Kiselkov 			len = length - RUN_MASK;
787a6f561b4SSašo Kiselkov 			for (; len > 254; len -= 255)
788a6f561b4SSašo Kiselkov 				*op++ = 255;
789a6f561b4SSašo Kiselkov 			*op++ = (BYTE)len;
790a6f561b4SSašo Kiselkov 		} else
791a6f561b4SSašo Kiselkov 			*token = (length << ML_BITS);
792a6f561b4SSašo Kiselkov 
793a6f561b4SSašo Kiselkov 		/* Copy Literals */
794a6f561b4SSašo Kiselkov 		LZ4_BLINDCOPY(anchor, op, length);
795a6f561b4SSašo Kiselkov 
796a6f561b4SSašo Kiselkov 		_next_match:
797a6f561b4SSašo Kiselkov 		/* Encode Offset */
798a6f561b4SSašo Kiselkov 		LZ4_WRITE_LITTLEENDIAN_16(op, ip - ref);
799a6f561b4SSašo Kiselkov 
800a6f561b4SSašo Kiselkov 		/* Start Counting */
801a6f561b4SSašo Kiselkov 		ip += MINMATCH;
802a6f561b4SSašo Kiselkov 		ref += MINMATCH;	/* MinMatch verified */
803a6f561b4SSašo Kiselkov 		anchor = ip;
804a6f561b4SSašo Kiselkov 		while (ip < matchlimit - (STEPSIZE - 1)) {
805a6f561b4SSašo Kiselkov 			UARCH diff = AARCH(ref) ^ AARCH(ip);
806a6f561b4SSašo Kiselkov 			if (!diff) {
807a6f561b4SSašo Kiselkov 				ip += STEPSIZE;
808a6f561b4SSašo Kiselkov 				ref += STEPSIZE;
809a6f561b4SSašo Kiselkov 				continue;
810a6f561b4SSašo Kiselkov 			}
811a6f561b4SSašo Kiselkov 			ip += LZ4_NbCommonBytes(diff);
812a6f561b4SSašo Kiselkov 			goto _endCount;
813a6f561b4SSašo Kiselkov 		}
814a6f561b4SSašo Kiselkov #if LZ4_ARCH64
815a6f561b4SSašo Kiselkov 		if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) {
816a6f561b4SSašo Kiselkov 			ip += 4;
817a6f561b4SSašo Kiselkov 			ref += 4;
818a6f561b4SSašo Kiselkov 		}
819a6f561b4SSašo Kiselkov #endif
820a6f561b4SSašo Kiselkov 		if ((ip < (matchlimit - 1)) && (A16(ref) == A16(ip))) {
821a6f561b4SSašo Kiselkov 			ip += 2;
822a6f561b4SSašo Kiselkov 			ref += 2;
823a6f561b4SSašo Kiselkov 		}
824a6f561b4SSašo Kiselkov 		if ((ip < matchlimit) && (*ref == *ip))
825a6f561b4SSašo Kiselkov 			ip++;
826a6f561b4SSašo Kiselkov 		_endCount:
827a6f561b4SSašo Kiselkov 
828a6f561b4SSašo Kiselkov 		/* Encode MatchLength */
829a6f561b4SSašo Kiselkov 		len = (ip - anchor);
830a6f561b4SSašo Kiselkov 		/* Check output limit */
831a6f561b4SSašo Kiselkov 		if unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend)
832a6f561b4SSašo Kiselkov 			return (0);
833a6f561b4SSašo Kiselkov 		if (len >= (int)ML_MASK) {
834a6f561b4SSašo Kiselkov 			*token += ML_MASK;
835a6f561b4SSašo Kiselkov 			len -= ML_MASK;
836a6f561b4SSašo Kiselkov 			for (; len > 509; len -= 510) {
837a6f561b4SSašo Kiselkov 				*op++ = 255;
838a6f561b4SSašo Kiselkov 				*op++ = 255;
839a6f561b4SSašo Kiselkov 			}
840a6f561b4SSašo Kiselkov 			if (len > 254) {
841a6f561b4SSašo Kiselkov 				len -= 255;
842a6f561b4SSašo Kiselkov 				*op++ = 255;
843a6f561b4SSašo Kiselkov 			}
844a6f561b4SSašo Kiselkov 			*op++ = (BYTE)len;
845a6f561b4SSašo Kiselkov 		} else
846a6f561b4SSašo Kiselkov 			*token += len;
847a6f561b4SSašo Kiselkov 
848a6f561b4SSašo Kiselkov 		/* Test end of chunk */
849a6f561b4SSašo Kiselkov 		if (ip > mflimit) {
850a6f561b4SSašo Kiselkov 			anchor = ip;
851a6f561b4SSašo Kiselkov 			break;
852a6f561b4SSašo Kiselkov 		}
853a6f561b4SSašo Kiselkov 		/* Fill table */
854a6f561b4SSašo Kiselkov 		HashTable[LZ4_HASH64K_VALUE(ip - 2)] = ip - 2 - base;
855a6f561b4SSašo Kiselkov 
856a6f561b4SSašo Kiselkov 		/* Test next position */
857a6f561b4SSašo Kiselkov 		ref = base + HashTable[LZ4_HASH64K_VALUE(ip)];
858a6f561b4SSašo Kiselkov 		HashTable[LZ4_HASH64K_VALUE(ip)] = ip - base;
859a6f561b4SSašo Kiselkov 		if (A32(ref) == A32(ip)) {
860a6f561b4SSašo Kiselkov 			token = op++;
861a6f561b4SSašo Kiselkov 			*token = 0;
862a6f561b4SSašo Kiselkov 			goto _next_match;
863a6f561b4SSašo Kiselkov 		}
864a6f561b4SSašo Kiselkov 		/* Prepare next loop */
865a6f561b4SSašo Kiselkov 		anchor = ip++;
866a6f561b4SSašo Kiselkov 		forwardH = LZ4_HASH64K_VALUE(ip);
867a6f561b4SSašo Kiselkov 	}
868a6f561b4SSašo Kiselkov 
869a6f561b4SSašo Kiselkov 	_last_literals:
870a6f561b4SSašo Kiselkov 	/* Encode Last Literals */
871a6f561b4SSašo Kiselkov 	{
872a6f561b4SSašo Kiselkov 		int lastRun = iend - anchor;
873a6f561b4SSašo Kiselkov 		if (op + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) >
874a6f561b4SSašo Kiselkov 		    oend)
875a6f561b4SSašo Kiselkov 			return (0);
876a6f561b4SSašo Kiselkov 		if (lastRun >= (int)RUN_MASK) {
877a6f561b4SSašo Kiselkov 			*op++ = (RUN_MASK << ML_BITS);
878a6f561b4SSašo Kiselkov 			lastRun -= RUN_MASK;
879a6f561b4SSašo Kiselkov 			for (; lastRun > 254; lastRun -= 255)
880a6f561b4SSašo Kiselkov 				*op++ = 255;
881a6f561b4SSašo Kiselkov 			*op++ = (BYTE)lastRun;
882a6f561b4SSašo Kiselkov 		} else
883a6f561b4SSašo Kiselkov 			*op++ = (lastRun << ML_BITS);
884a6f561b4SSašo Kiselkov 		(void) memcpy(op, anchor, iend - anchor);
885a6f561b4SSašo Kiselkov 		op += iend - anchor;
886a6f561b4SSašo Kiselkov 	}
887a6f561b4SSašo Kiselkov 
888a6f561b4SSašo Kiselkov 	/* End */
889a6f561b4SSašo Kiselkov 	return (int)(((char *)op) - dest);
890a6f561b4SSašo Kiselkov }
891a6f561b4SSašo Kiselkov 
892a6f561b4SSašo Kiselkov static int
real_LZ4_compress(const char * source,char * dest,int isize,int osize)893a6f561b4SSašo Kiselkov real_LZ4_compress(const char *source, char *dest, int isize, int osize)
894a6f561b4SSašo Kiselkov {
895a6f561b4SSašo Kiselkov #if HEAPMODE
896a6f561b4SSašo Kiselkov 	void *ctx = kmem_zalloc(sizeof (struct refTables), KM_NOSLEEP);
897a6f561b4SSašo Kiselkov 	int result;
898a6f561b4SSašo Kiselkov 
899a6f561b4SSašo Kiselkov 	/*
900a6f561b4SSašo Kiselkov 	 * out of kernel memory, gently fall through - this will disable
901a6f561b4SSašo Kiselkov 	 * compression in zio_compress_data
902a6f561b4SSašo Kiselkov 	 */
903a6f561b4SSašo Kiselkov 	if (ctx == NULL)
904a6f561b4SSašo Kiselkov 		return (0);
905a6f561b4SSašo Kiselkov 
906a6f561b4SSašo Kiselkov 	if (isize < LZ4_64KLIMIT)
907a6f561b4SSašo Kiselkov 		result = LZ4_compress64kCtx(ctx, source, dest, isize, osize);
908a6f561b4SSašo Kiselkov 	else
909a6f561b4SSašo Kiselkov 		result = LZ4_compressCtx(ctx, source, dest, isize, osize);
910a6f561b4SSašo Kiselkov 
911a6f561b4SSašo Kiselkov 	kmem_free(ctx, sizeof (struct refTables));
912a6f561b4SSašo Kiselkov 	return (result);
913a6f561b4SSašo Kiselkov #else
914a6f561b4SSašo Kiselkov 	if (isize < (int)LZ4_64KLIMIT)
915a6f561b4SSašo Kiselkov 		return (LZ4_compress64kCtx(NULL, source, dest, isize, osize));
916a6f561b4SSašo Kiselkov 	return (LZ4_compressCtx(NULL, source, dest, isize, osize));
917a6f561b4SSašo Kiselkov #endif
918a6f561b4SSašo Kiselkov }
919a6f561b4SSašo Kiselkov 
920a6f561b4SSašo Kiselkov /* Decompression functions */
921a6f561b4SSašo Kiselkov 
922a6f561b4SSašo Kiselkov /*
923a6f561b4SSašo Kiselkov  * Note: The decoding functions real_LZ4_uncompress() and
924a6f561b4SSašo Kiselkov  *	LZ4_uncompress_unknownOutputSize() are safe against "buffer overflow"
925a6f561b4SSašo Kiselkov  *	attack type. They will never write nor read outside of the provided
926a6f561b4SSašo Kiselkov  *	output buffers. LZ4_uncompress_unknownOutputSize() also insures that
927a6f561b4SSašo Kiselkov  *	it will never read outside of the input buffer. A corrupted input
928a6f561b4SSašo Kiselkov  *	will produce an error result, a negative int, indicating the position
929a6f561b4SSašo Kiselkov  *	of the error within input stream.
930a6f561b4SSašo Kiselkov  */
931a6f561b4SSašo Kiselkov 
932a6f561b4SSašo Kiselkov static int
real_LZ4_uncompress(const char * source,char * dest,int osize)933a6f561b4SSašo Kiselkov real_LZ4_uncompress(const char *source, char *dest, int osize)
934a6f561b4SSašo Kiselkov {
935a6f561b4SSašo Kiselkov 	/* Local Variables */
936a6f561b4SSašo Kiselkov 	const BYTE *restrict ip = (const BYTE *) source;
937a6f561b4SSašo Kiselkov 	const BYTE *ref;
938a6f561b4SSašo Kiselkov 
939a6f561b4SSašo Kiselkov 	BYTE *op = (BYTE *) dest;
940a6f561b4SSašo Kiselkov 	BYTE *const oend = op + osize;
941a6f561b4SSašo Kiselkov 	BYTE *cpy;
942a6f561b4SSašo Kiselkov 
943a6f561b4SSašo Kiselkov 	unsigned token;
944a6f561b4SSašo Kiselkov 
945a6f561b4SSašo Kiselkov 	size_t length;
946a6f561b4SSašo Kiselkov 	size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0};
947a6f561b4SSašo Kiselkov #if LZ4_ARCH64
948a6f561b4SSašo Kiselkov 	size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
949a6f561b4SSašo Kiselkov #endif
950a6f561b4SSašo Kiselkov 
951a6f561b4SSašo Kiselkov 	/* Main Loop */
952a6f561b4SSašo Kiselkov 	for (;;) {
953a6f561b4SSašo Kiselkov 		/* get runlength */
954a6f561b4SSašo Kiselkov 		token = *ip++;
955a6f561b4SSašo Kiselkov 		if ((length = (token >> ML_BITS)) == RUN_MASK) {
956a6f561b4SSašo Kiselkov 			size_t len;
957a6f561b4SSašo Kiselkov 			for (; (len = *ip++) == 255; length += 255) {
958a6f561b4SSašo Kiselkov 			}
959a6f561b4SSašo Kiselkov 			length += len;
960a6f561b4SSašo Kiselkov 		}
961a6f561b4SSašo Kiselkov 		/* copy literals */
962a6f561b4SSašo Kiselkov 		cpy = op + length;
963*58d07180SDan McDonald 		/* CORNER-CASE: cpy might overflow. */
964*58d07180SDan McDonald 		if (cpy < op)
965*58d07180SDan McDonald 			goto _output_error;	/* cpy was overflowed, bail! */
966a6f561b4SSašo Kiselkov 		if unlikely(cpy > oend - COPYLENGTH) {
967a6f561b4SSašo Kiselkov 			if (cpy != oend)
968a6f561b4SSašo Kiselkov 				/* Error: we must necessarily stand at EOF */
969a6f561b4SSašo Kiselkov 				goto _output_error;
970a6f561b4SSašo Kiselkov 			(void) memcpy(op, ip, length);
971a6f561b4SSašo Kiselkov 			ip += length;
972a6f561b4SSašo Kiselkov 			break;	/* EOF */
973a6f561b4SSašo Kiselkov 			}
974a6f561b4SSašo Kiselkov 		LZ4_WILDCOPY(ip, op, cpy);
975a6f561b4SSašo Kiselkov 		ip -= (op - cpy);
976a6f561b4SSašo Kiselkov 		op = cpy;
977a6f561b4SSašo Kiselkov 
978a6f561b4SSašo Kiselkov 		/* get offset */
979a6f561b4SSašo Kiselkov 		LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip);
980a6f561b4SSašo Kiselkov 		ip += 2;
981a6f561b4SSašo Kiselkov 		if unlikely(ref < (BYTE * const) dest)
982a6f561b4SSašo Kiselkov 			/*
983a6f561b4SSašo Kiselkov 			 * Error: offset create reference outside destination
984a6f561b4SSašo Kiselkov 			 * buffer
985a6f561b4SSašo Kiselkov 			 */
986a6f561b4SSašo Kiselkov 			goto _output_error;
987a6f561b4SSašo Kiselkov 
988a6f561b4SSašo Kiselkov 		/* get matchlength */
989a6f561b4SSašo Kiselkov 		if ((length = (token & ML_MASK)) == ML_MASK) {
990a6f561b4SSašo Kiselkov 			for (; *ip == 255; length += 255) {
991a6f561b4SSašo Kiselkov 				ip++;
992a6f561b4SSašo Kiselkov 			}
993a6f561b4SSašo Kiselkov 			length += *ip++;
994a6f561b4SSašo Kiselkov 		}
995a6f561b4SSašo Kiselkov 		/* copy repeated sequence */
996a6f561b4SSašo Kiselkov 		if unlikely(op - ref < STEPSIZE) {
997a6f561b4SSašo Kiselkov #if LZ4_ARCH64
998a6f561b4SSašo Kiselkov 			size_t dec64 = dec64table[op-ref];
999a6f561b4SSašo Kiselkov #else
1000a6f561b4SSašo Kiselkov 			const int dec64 = 0;
1001a6f561b4SSašo Kiselkov #endif
1002a6f561b4SSašo Kiselkov 			op[0] = ref[0];
1003a6f561b4SSašo Kiselkov 			op[1] = ref[1];
1004a6f561b4SSašo Kiselkov 			op[2] = ref[2];
1005a6f561b4SSašo Kiselkov 			op[3] = ref[3];
1006a6f561b4SSašo Kiselkov 			op += 4;
1007a6f561b4SSašo Kiselkov 			ref += 4;
1008a6f561b4SSašo Kiselkov 			ref -= dec32table[op-ref];
1009a6f561b4SSašo Kiselkov 			A32(op) = A32(ref);
1010a6f561b4SSašo Kiselkov 			op += STEPSIZE - 4;
1011a6f561b4SSašo Kiselkov 			ref -= dec64;
1012a6f561b4SSašo Kiselkov 		} else {
1013a6f561b4SSašo Kiselkov 			LZ4_COPYSTEP(ref, op);
1014a6f561b4SSašo Kiselkov 		}
1015a6f561b4SSašo Kiselkov 		cpy = op + length - (STEPSIZE - 4);
1016a6f561b4SSašo Kiselkov 		if (cpy > oend - COPYLENGTH) {
1017a6f561b4SSašo Kiselkov 			if (cpy > oend)
1018a6f561b4SSašo Kiselkov 				/*
1019a6f561b4SSašo Kiselkov 				 * Error: request to write beyond destination
1020a6f561b4SSašo Kiselkov 				 * buffer
1021a6f561b4SSašo Kiselkov 				 */
1022a6f561b4SSašo Kiselkov 				goto _output_error;
1023a6f561b4SSašo Kiselkov 			LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
1024a6f561b4SSašo Kiselkov 			while (op < cpy)
1025a6f561b4SSašo Kiselkov 				*op++ = *ref++;
1026a6f561b4SSašo Kiselkov 			op = cpy;
1027a6f561b4SSašo Kiselkov 			if (op == oend)
1028a6f561b4SSašo Kiselkov 				/*
1029a6f561b4SSašo Kiselkov 				 * Check EOF (should never happen, since last
1030a6f561b4SSašo Kiselkov 				 * 5 bytes are supposed to be literals)
1031a6f561b4SSašo Kiselkov 				 */
1032a6f561b4SSašo Kiselkov 				goto _output_error;
1033a6f561b4SSašo Kiselkov 			continue;
1034a6f561b4SSašo Kiselkov 		}
1035a6f561b4SSašo Kiselkov 		LZ4_SECURECOPY(ref, op, cpy);
1036a6f561b4SSašo Kiselkov 		op = cpy;	/* correction */
1037a6f561b4SSašo Kiselkov 	}
1038a6f561b4SSašo Kiselkov 
1039a6f561b4SSašo Kiselkov 	/* end of decoding */
1040a6f561b4SSašo Kiselkov 	return (int)(((char *)ip) - source);
1041a6f561b4SSašo Kiselkov 
1042a6f561b4SSašo Kiselkov 	/* write overflow error detected */
1043a6f561b4SSašo Kiselkov 	_output_error:
1044a6f561b4SSašo Kiselkov 	return (int)(-(((char *)ip) - source));
1045a6f561b4SSašo Kiselkov }
1046a6f561b4SSašo Kiselkov 
1047a6f561b4SSašo Kiselkov static int
LZ4_uncompress_unknownOutputSize(const char * source,char * dest,int isize,int maxOutputSize)1048a6f561b4SSašo Kiselkov LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize,
1049a6f561b4SSašo Kiselkov     int maxOutputSize)
1050a6f561b4SSašo Kiselkov {
1051a6f561b4SSašo Kiselkov 	/* Local Variables */
1052a6f561b4SSašo Kiselkov 	const BYTE *restrict ip = (const BYTE *) source;
1053a6f561b4SSašo Kiselkov 	const BYTE *const iend = ip + isize;
1054a6f561b4SSašo Kiselkov 	const BYTE *ref;
1055a6f561b4SSašo Kiselkov 
1056a6f561b4SSašo Kiselkov 	BYTE *op = (BYTE *) dest;
1057a6f561b4SSašo Kiselkov 	BYTE *const oend = op + maxOutputSize;
1058a6f561b4SSašo Kiselkov 	BYTE *cpy;
1059a6f561b4SSašo Kiselkov 
1060a6f561b4SSašo Kiselkov 	size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0};
1061a6f561b4SSašo Kiselkov #if LZ4_ARCH64
1062a6f561b4SSašo Kiselkov 	size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
1063a6f561b4SSašo Kiselkov #endif
1064a6f561b4SSašo Kiselkov 
1065a6f561b4SSašo Kiselkov 	/* Main Loop */
1066a6f561b4SSašo Kiselkov 	while (ip < iend) {
1067a6f561b4SSašo Kiselkov 		unsigned token;
1068a6f561b4SSašo Kiselkov 		size_t length;
1069a6f561b4SSašo Kiselkov 
1070a6f561b4SSašo Kiselkov 		/* get runlength */
1071a6f561b4SSašo Kiselkov 		token = *ip++;
1072a6f561b4SSašo Kiselkov 		if ((length = (token >> ML_BITS)) == RUN_MASK) {
1073a6f561b4SSašo Kiselkov 			int s = 255;
1074a6f561b4SSašo Kiselkov 			while ((ip < iend) && (s == 255)) {
1075a6f561b4SSašo Kiselkov 				s = *ip++;
1076a6f561b4SSašo Kiselkov 				length += s;
1077a6f561b4SSašo Kiselkov 			}
1078a6f561b4SSašo Kiselkov 		}
1079a6f561b4SSašo Kiselkov 		/* copy literals */
1080a6f561b4SSašo Kiselkov 		cpy = op + length;
1081*58d07180SDan McDonald 		/* CORNER-CASE: cpy might overflow. */
1082*58d07180SDan McDonald 		if (cpy < op)
1083*58d07180SDan McDonald 			goto _output_error;	/* cpy was overflowed, bail! */
1084a6f561b4SSašo Kiselkov 		if ((cpy > oend - COPYLENGTH) ||
1085a6f561b4SSašo Kiselkov 		    (ip + length > iend - COPYLENGTH)) {
1086a6f561b4SSašo Kiselkov 			if (cpy > oend)
1087a6f561b4SSašo Kiselkov 				/* Error: writes beyond output buffer */
1088a6f561b4SSašo Kiselkov 				goto _output_error;
1089a6f561b4SSašo Kiselkov 			if (ip + length != iend)
1090a6f561b4SSašo Kiselkov 				/*
1091a6f561b4SSašo Kiselkov 				 * Error: LZ4 format requires to consume all
1092a6f561b4SSašo Kiselkov 				 * input at this stage
1093a6f561b4SSašo Kiselkov 				 */
1094a6f561b4SSašo Kiselkov 				goto _output_error;
1095a6f561b4SSašo Kiselkov 			(void) memcpy(op, ip, length);
1096a6f561b4SSašo Kiselkov 			op += length;
1097a6f561b4SSašo Kiselkov 			/* Necessarily EOF, due to parsing restrictions */
1098a6f561b4SSašo Kiselkov 			break;
1099a6f561b4SSašo Kiselkov 		}
1100a6f561b4SSašo Kiselkov 		LZ4_WILDCOPY(ip, op, cpy);
1101a6f561b4SSašo Kiselkov 		ip -= (op - cpy);
1102a6f561b4SSašo Kiselkov 		op = cpy;
1103a6f561b4SSašo Kiselkov 
1104a6f561b4SSašo Kiselkov 		/* get offset */
1105a6f561b4SSašo Kiselkov 		LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip);
1106a6f561b4SSašo Kiselkov 		ip += 2;
1107a6f561b4SSašo Kiselkov 		if (ref < (BYTE * const) dest)
1108a6f561b4SSašo Kiselkov 			/*
1109a6f561b4SSašo Kiselkov 			 * Error: offset creates reference outside of
1110a6f561b4SSašo Kiselkov 			 * destination buffer
1111a6f561b4SSašo Kiselkov 			 */
1112a6f561b4SSašo Kiselkov 			goto _output_error;
1113a6f561b4SSašo Kiselkov 
1114a6f561b4SSašo Kiselkov 		/* get matchlength */
1115a6f561b4SSašo Kiselkov 		if ((length = (token & ML_MASK)) == ML_MASK) {
1116a6f561b4SSašo Kiselkov 			while (ip < iend) {
1117a6f561b4SSašo Kiselkov 				int s = *ip++;
1118a6f561b4SSašo Kiselkov 				length += s;
1119a6f561b4SSašo Kiselkov 				if (s == 255)
1120a6f561b4SSašo Kiselkov 					continue;
1121a6f561b4SSašo Kiselkov 				break;
1122a6f561b4SSašo Kiselkov 			}
1123a6f561b4SSašo Kiselkov 		}
1124a6f561b4SSašo Kiselkov 		/* copy repeated sequence */
1125a6f561b4SSašo Kiselkov 		if unlikely(op - ref < STEPSIZE) {
1126a6f561b4SSašo Kiselkov #if LZ4_ARCH64
1127a6f561b4SSašo Kiselkov 			size_t dec64 = dec64table[op-ref];
1128a6f561b4SSašo Kiselkov #else
1129a6f561b4SSašo Kiselkov 			const int dec64 = 0;
1130a6f561b4SSašo Kiselkov #endif
1131a6f561b4SSašo Kiselkov 			op[0] = ref[0];
1132a6f561b4SSašo Kiselkov 			op[1] = ref[1];
1133a6f561b4SSašo Kiselkov 			op[2] = ref[2];
1134a6f561b4SSašo Kiselkov 			op[3] = ref[3];
1135a6f561b4SSašo Kiselkov 			op += 4;
1136a6f561b4SSašo Kiselkov 			ref += 4;
1137a6f561b4SSašo Kiselkov 			ref -= dec32table[op-ref];
1138a6f561b4SSašo Kiselkov 			A32(op) = A32(ref);
1139a6f561b4SSašo Kiselkov 			op += STEPSIZE - 4;
1140a6f561b4SSašo Kiselkov 			ref -= dec64;
1141a6f561b4SSašo Kiselkov 		} else {
1142a6f561b4SSašo Kiselkov 			LZ4_COPYSTEP(ref, op);
1143a6f561b4SSašo Kiselkov 		}
1144a6f561b4SSašo Kiselkov 		cpy = op + length - (STEPSIZE - 4);
1145a6f561b4SSašo Kiselkov 		if (cpy > oend - COPYLENGTH) {
1146a6f561b4SSašo Kiselkov 			if (cpy > oend)
1147a6f561b4SSašo Kiselkov 				/*
1148a6f561b4SSašo Kiselkov 				 * Error: request to write outside of
1149a6f561b4SSašo Kiselkov 				 * destination buffer
1150a6f561b4SSašo Kiselkov 				 */
1151a6f561b4SSašo Kiselkov 				goto _output_error;
1152a6f561b4SSašo Kiselkov 			LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
1153a6f561b4SSašo Kiselkov 			while (op < cpy)
1154a6f561b4SSašo Kiselkov 				*op++ = *ref++;
1155a6f561b4SSašo Kiselkov 			op = cpy;
1156a6f561b4SSašo Kiselkov 			if (op == oend)
1157a6f561b4SSašo Kiselkov 				/*
1158a6f561b4SSašo Kiselkov 				 * Check EOF (should never happen, since
1159a6f561b4SSašo Kiselkov 				 * last 5 bytes are supposed to be literals)
1160a6f561b4SSašo Kiselkov 				 */
1161a6f561b4SSašo Kiselkov 				goto _output_error;
1162a6f561b4SSašo Kiselkov 			continue;
1163a6f561b4SSašo Kiselkov 		}
1164a6f561b4SSašo Kiselkov 		LZ4_SECURECOPY(ref, op, cpy);
1165a6f561b4SSašo Kiselkov 		op = cpy;	/* correction */
1166a6f561b4SSašo Kiselkov 	}
1167a6f561b4SSašo Kiselkov 
1168a6f561b4SSašo Kiselkov 	/* end of decoding */
1169a6f561b4SSašo Kiselkov 	return (int)(((char *)op) - dest);
1170a6f561b4SSašo Kiselkov 
1171a6f561b4SSašo Kiselkov 	/* write overflow error detected */
1172a6f561b4SSašo Kiselkov 	_output_error:
1173a6f561b4SSašo Kiselkov 	return (int)(-(((char *)ip) - source));
1174a6f561b4SSašo Kiselkov }
1175