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