xref: /freebsd/sys/dev/cxgbe/cudbg/fastlz.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1*f856f099SNavdeep Parhar /*
2*f856f099SNavdeep Parhar    FastLZ - lightning-fast lossless compression library
3*f856f099SNavdeep Parhar 
4*f856f099SNavdeep Parhar    Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
5*f856f099SNavdeep Parhar    Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
6*f856f099SNavdeep Parhar    Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
7*f856f099SNavdeep Parhar 
8*f856f099SNavdeep Parhar    Permission is hereby granted, free of charge, to any person obtaining a copy
9*f856f099SNavdeep Parhar    of this software and associated documentation files (the "Software"), to deal
10*f856f099SNavdeep Parhar    in the Software without restriction, including without limitation the rights
11*f856f099SNavdeep Parhar    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12*f856f099SNavdeep Parhar    copies of the Software, and to permit persons to whom the Software is
13*f856f099SNavdeep Parhar    furnished to do so, subject to the following conditions:
14*f856f099SNavdeep Parhar 
15*f856f099SNavdeep Parhar    The above copyright notice and this permission notice shall be included in
16*f856f099SNavdeep Parhar    all copies or substantial portions of the Software.
17*f856f099SNavdeep Parhar 
18*f856f099SNavdeep Parhar    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19*f856f099SNavdeep Parhar    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20*f856f099SNavdeep Parhar    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21*f856f099SNavdeep Parhar    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22*f856f099SNavdeep Parhar    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23*f856f099SNavdeep Parhar    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24*f856f099SNavdeep Parhar    THE SOFTWARE.
25*f856f099SNavdeep Parhar    */
26*f856f099SNavdeep Parhar #include <sys/cdefs.h>
27*f856f099SNavdeep Parhar #include "osdep.h"
28*f856f099SNavdeep Parhar #include "fastlz.h"
29*f856f099SNavdeep Parhar 
30*f856f099SNavdeep Parhar #if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
31*f856f099SNavdeep Parhar 
32*f856f099SNavdeep Parhar /*
33*f856f099SNavdeep Parhar  * Always check for bound when decompressing.
34*f856f099SNavdeep Parhar  * Generally it is best to leave it defined.
35*f856f099SNavdeep Parhar  */
36*f856f099SNavdeep Parhar #define FASTLZ_SAFE
37*f856f099SNavdeep Parhar 
38*f856f099SNavdeep Parhar #if defined(WIN32) || defined(__NT__) || defined(_WIN32) || defined(__WIN32__)
39*f856f099SNavdeep Parhar #if defined(_MSC_VER) || defined(__GNUC__)
40*f856f099SNavdeep Parhar /* #include <windows.h> */
41*f856f099SNavdeep Parhar #pragma warning(disable : 4242)
42*f856f099SNavdeep Parhar #pragma warning(disable : 4244)
43*f856f099SNavdeep Parhar #endif
44*f856f099SNavdeep Parhar #endif
45*f856f099SNavdeep Parhar 
46*f856f099SNavdeep Parhar /*
47*f856f099SNavdeep Parhar  * Give hints to the compiler for branch prediction optimization.
48*f856f099SNavdeep Parhar  */
49*f856f099SNavdeep Parhar #if defined(__GNUC__) && (__GNUC__ > 2)
50*f856f099SNavdeep Parhar #define FASTLZ_EXPECT_CONDITIONAL(c)	(__builtin_expect((c), 1))
51*f856f099SNavdeep Parhar #define FASTLZ_UNEXPECT_CONDITIONAL(c)	(__builtin_expect((c), 0))
52*f856f099SNavdeep Parhar #else
53*f856f099SNavdeep Parhar #define FASTLZ_EXPECT_CONDITIONAL(c)	(c)
54*f856f099SNavdeep Parhar #define FASTLZ_UNEXPECT_CONDITIONAL(c)	(c)
55*f856f099SNavdeep Parhar #endif
56*f856f099SNavdeep Parhar 
57*f856f099SNavdeep Parhar /*
58*f856f099SNavdeep Parhar  * Use inlined functions for supported systems.
59*f856f099SNavdeep Parhar  */
60*f856f099SNavdeep Parhar #if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) ||\
61*f856f099SNavdeep Parhar 	defined(__WATCOMC__) || defined(__SUNPRO_C)
62*f856f099SNavdeep Parhar #define FASTLZ_INLINE inline
63*f856f099SNavdeep Parhar #elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
64*f856f099SNavdeep Parhar #define FASTLZ_INLINE __inline
65*f856f099SNavdeep Parhar #else
66*f856f099SNavdeep Parhar #define FASTLZ_INLINE
67*f856f099SNavdeep Parhar #endif
68*f856f099SNavdeep Parhar 
69*f856f099SNavdeep Parhar /*
70*f856f099SNavdeep Parhar  * Prevent accessing more than 8-bit at once, except on x86 architectures.
71*f856f099SNavdeep Parhar  */
72*f856f099SNavdeep Parhar #if !defined(FASTLZ_STRICT_ALIGN)
73*f856f099SNavdeep Parhar #define FASTLZ_STRICT_ALIGN
74*f856f099SNavdeep Parhar #if defined(__i386__) || defined(__386)  /* GNU C, Sun Studio */
75*f856f099SNavdeep Parhar #undef FASTLZ_STRICT_ALIGN
76*f856f099SNavdeep Parhar #elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */
77*f856f099SNavdeep Parhar #undef FASTLZ_STRICT_ALIGN
78*f856f099SNavdeep Parhar #elif defined(_M_IX86) /* Intel, MSVC */
79*f856f099SNavdeep Parhar #undef FASTLZ_STRICT_ALIGN
80*f856f099SNavdeep Parhar #elif defined(__386)
81*f856f099SNavdeep Parhar #undef FASTLZ_STRICT_ALIGN
82*f856f099SNavdeep Parhar #elif defined(_X86_) /* MinGW */
83*f856f099SNavdeep Parhar #undef FASTLZ_STRICT_ALIGN
84*f856f099SNavdeep Parhar #elif defined(__I86__) /* Digital Mars */
85*f856f099SNavdeep Parhar #undef FASTLZ_STRICT_ALIGN
86*f856f099SNavdeep Parhar #endif
87*f856f099SNavdeep Parhar #endif
88*f856f099SNavdeep Parhar 
89*f856f099SNavdeep Parhar /*
90*f856f099SNavdeep Parhar  * FIXME: use preprocessor magic to set this on different platforms!
91*f856f099SNavdeep Parhar  */
92*f856f099SNavdeep Parhar 
93*f856f099SNavdeep Parhar #define MAX_COPY       32
94*f856f099SNavdeep Parhar #define MAX_LEN       264  /* 256 + 8 */
95*f856f099SNavdeep Parhar #define MAX_DISTANCE 8192
96*f856f099SNavdeep Parhar 
97*f856f099SNavdeep Parhar #if !defined(FASTLZ_STRICT_ALIGN)
98*f856f099SNavdeep Parhar #define FASTLZ_READU16(p) (*((const unsigned short *)(p)))
99*f856f099SNavdeep Parhar #else
100*f856f099SNavdeep Parhar #define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8)
101*f856f099SNavdeep Parhar #endif
102*f856f099SNavdeep Parhar 
103*f856f099SNavdeep Parhar #define HASH_LOG  13
104*f856f099SNavdeep Parhar #define HASH_SIZE (1 << HASH_LOG)
105*f856f099SNavdeep Parhar #define HASH_MASK  (HASH_SIZE - 1)
106*f856f099SNavdeep Parhar #define HASH_FUNCTION(v, p) {\
107*f856f099SNavdeep Parhar 				v = FASTLZ_READU16(p);\
108*f856f099SNavdeep Parhar 				v ^= FASTLZ_READU16(p + 1)^\
109*f856f099SNavdeep Parhar 				     (v>>(16 - HASH_LOG));\
110*f856f099SNavdeep Parhar 				v &= HASH_MASK;\
111*f856f099SNavdeep Parhar 			    }
112*f856f099SNavdeep Parhar 
113*f856f099SNavdeep Parhar #undef FASTLZ_LEVEL
114*f856f099SNavdeep Parhar #define FASTLZ_LEVEL 1
115*f856f099SNavdeep Parhar 
116*f856f099SNavdeep Parhar #undef FASTLZ_COMPRESSOR
117*f856f099SNavdeep Parhar #undef FASTLZ_DECOMPRESSOR
118*f856f099SNavdeep Parhar #define FASTLZ_COMPRESSOR fastlz1_compress
119*f856f099SNavdeep Parhar #define FASTLZ_DECOMPRESSOR fastlz1_decompress
120*f856f099SNavdeep Parhar static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length,
121*f856f099SNavdeep Parhar 					   void *output);
122*f856f099SNavdeep Parhar static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length,
123*f856f099SNavdeep Parhar 					     void *output, int maxout);
124*f856f099SNavdeep Parhar #include "fastlz.c"
125*f856f099SNavdeep Parhar 
126*f856f099SNavdeep Parhar #undef FASTLZ_LEVEL
127*f856f099SNavdeep Parhar #define FASTLZ_LEVEL 2
128*f856f099SNavdeep Parhar 
129*f856f099SNavdeep Parhar #undef MAX_DISTANCE
130*f856f099SNavdeep Parhar #define MAX_DISTANCE 8191
131*f856f099SNavdeep Parhar #define MAX_FARDISTANCE (65535 + MAX_DISTANCE - 1)
132*f856f099SNavdeep Parhar 
133*f856f099SNavdeep Parhar #undef FASTLZ_COMPRESSOR
134*f856f099SNavdeep Parhar #undef FASTLZ_DECOMPRESSOR
135*f856f099SNavdeep Parhar #define FASTLZ_COMPRESSOR fastlz2_compress
136*f856f099SNavdeep Parhar #define FASTLZ_DECOMPRESSOR fastlz2_decompress
137*f856f099SNavdeep Parhar static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length,
138*f856f099SNavdeep Parhar 					   void *output);
139*f856f099SNavdeep Parhar static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length,
140*f856f099SNavdeep Parhar 					     void *output, int maxout);
141*f856f099SNavdeep Parhar #include "fastlz.c"
142*f856f099SNavdeep Parhar 
fastlz_compress(const void * input,int length,void * output)143*f856f099SNavdeep Parhar int fastlz_compress(const void *input, int length, void *output)
144*f856f099SNavdeep Parhar {
145*f856f099SNavdeep Parhar 	/* for short block, choose fastlz1 */
146*f856f099SNavdeep Parhar 	if (length < 65536)
147*f856f099SNavdeep Parhar 		return fastlz1_compress(input, length, output);
148*f856f099SNavdeep Parhar 
149*f856f099SNavdeep Parhar 	/* else... */
150*f856f099SNavdeep Parhar 	return fastlz2_compress(input, length, output);
151*f856f099SNavdeep Parhar }
152*f856f099SNavdeep Parhar 
fastlz_decompress(const void * input,int length,void * output,int maxout)153*f856f099SNavdeep Parhar int fastlz_decompress(const void *input, int length, void *output, int maxout)
154*f856f099SNavdeep Parhar {
155*f856f099SNavdeep Parhar 	/* magic identifier for compression level */
156*f856f099SNavdeep Parhar 	int level = ((*(const unsigned char *)input) >> 5) + 1;
157*f856f099SNavdeep Parhar 
158*f856f099SNavdeep Parhar 	if (level == 1)
159*f856f099SNavdeep Parhar 		return fastlz1_decompress(input, length, output, maxout);
160*f856f099SNavdeep Parhar 	if (level == 2)
161*f856f099SNavdeep Parhar 		return fastlz2_decompress(input, length, output, maxout);
162*f856f099SNavdeep Parhar 
163*f856f099SNavdeep Parhar 	/* unknown level, trigger error */
164*f856f099SNavdeep Parhar 	return 0;
165*f856f099SNavdeep Parhar }
166*f856f099SNavdeep Parhar 
fastlz_compress_level(int level,const void * input,int length,void * output)167*f856f099SNavdeep Parhar int fastlz_compress_level(int level, const void *input, int length,
168*f856f099SNavdeep Parhar 			  void *output)
169*f856f099SNavdeep Parhar {
170*f856f099SNavdeep Parhar 	if (level == 1)
171*f856f099SNavdeep Parhar 		return fastlz1_compress(input, length, output);
172*f856f099SNavdeep Parhar 	if (level == 2)
173*f856f099SNavdeep Parhar 		return fastlz2_compress(input, length, output);
174*f856f099SNavdeep Parhar 
175*f856f099SNavdeep Parhar 	return 0;
176*f856f099SNavdeep Parhar }
177*f856f099SNavdeep Parhar 
178*f856f099SNavdeep Parhar #else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
179*f856f099SNavdeep Parhar 
180*f856f099SNavdeep Parhar 
FASTLZ_COMPRESSOR(const void * input,int length,void * output)181*f856f099SNavdeep Parhar static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length,
182*f856f099SNavdeep Parhar 					   void *output)
183*f856f099SNavdeep Parhar {
184*f856f099SNavdeep Parhar 	const unsigned char *ip = (const unsigned char *) input;
185*f856f099SNavdeep Parhar 	const unsigned char *ip_bound = ip + length - 2;
186*f856f099SNavdeep Parhar 	const unsigned char *ip_limit = ip + length - 12;
187*f856f099SNavdeep Parhar 	unsigned char *op = (unsigned char *) output;
188*f856f099SNavdeep Parhar 	static const unsigned char *g_htab[HASH_SIZE];
189*f856f099SNavdeep Parhar 
190*f856f099SNavdeep Parhar 	const unsigned char **htab = g_htab;
191*f856f099SNavdeep Parhar 	const unsigned char **hslot;
192*f856f099SNavdeep Parhar 	unsigned int hval;
193*f856f099SNavdeep Parhar 
194*f856f099SNavdeep Parhar 	unsigned int copy;
195*f856f099SNavdeep Parhar 
196*f856f099SNavdeep Parhar 	/* sanity check */
197*f856f099SNavdeep Parhar 	if (FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) {
198*f856f099SNavdeep Parhar 		if (length) {
199*f856f099SNavdeep Parhar 			/* create literal copy only */
200*f856f099SNavdeep Parhar 			*op++ = length - 1;
201*f856f099SNavdeep Parhar 			ip_bound++;
202*f856f099SNavdeep Parhar 			while (ip <= ip_bound)
203*f856f099SNavdeep Parhar 				*op++ = *ip++;
204*f856f099SNavdeep Parhar 			return length + 1;
205*f856f099SNavdeep Parhar 		} else
206*f856f099SNavdeep Parhar 			return 0;
207*f856f099SNavdeep Parhar 	}
208*f856f099SNavdeep Parhar 
209*f856f099SNavdeep Parhar 	/* initializes hash table */
210*f856f099SNavdeep Parhar 	for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
211*f856f099SNavdeep Parhar 		*hslot = ip;
212*f856f099SNavdeep Parhar 
213*f856f099SNavdeep Parhar 	/* we start with literal copy */
214*f856f099SNavdeep Parhar 	copy = 2;
215*f856f099SNavdeep Parhar 	*op++ = MAX_COPY - 1;
216*f856f099SNavdeep Parhar 	*op++ = *ip++;
217*f856f099SNavdeep Parhar 	*op++ = *ip++;
218*f856f099SNavdeep Parhar 
219*f856f099SNavdeep Parhar 	/* main loop */
220*f856f099SNavdeep Parhar 	while (FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) {
221*f856f099SNavdeep Parhar 		const unsigned char *ref;
222*f856f099SNavdeep Parhar 		unsigned int distance;
223*f856f099SNavdeep Parhar 
224*f856f099SNavdeep Parhar 		/* minimum match length */
225*f856f099SNavdeep Parhar 		unsigned int len = 3;
226*f856f099SNavdeep Parhar 
227*f856f099SNavdeep Parhar 		/* comparison starting-point */
228*f856f099SNavdeep Parhar 		const unsigned char *anchor = ip;
229*f856f099SNavdeep Parhar 
230*f856f099SNavdeep Parhar 		/* check for a run */
231*f856f099SNavdeep Parhar #if FASTLZ_LEVEL == 2
232*f856f099SNavdeep Parhar 		if (ip[0] == ip[-1] &&
233*f856f099SNavdeep Parhar 		    FASTLZ_READU16(ip - 1) == FASTLZ_READU16(ip + 1)) {
234*f856f099SNavdeep Parhar 			distance = 1;
235*f856f099SNavdeep Parhar 			ip += 3;
236*f856f099SNavdeep Parhar 			ref = anchor - 1 + 3;
237*f856f099SNavdeep Parhar 			goto match;
238*f856f099SNavdeep Parhar 		}
239*f856f099SNavdeep Parhar #endif
240*f856f099SNavdeep Parhar 
241*f856f099SNavdeep Parhar 		/* find potential match */
242*f856f099SNavdeep Parhar 		HASH_FUNCTION(hval, ip);
243*f856f099SNavdeep Parhar 		hslot = htab + hval;
244*f856f099SNavdeep Parhar 		ref = htab[hval];
245*f856f099SNavdeep Parhar 
246*f856f099SNavdeep Parhar 		/* calculate distance to the match */
247*f856f099SNavdeep Parhar 		distance = anchor - ref;
248*f856f099SNavdeep Parhar 
249*f856f099SNavdeep Parhar 		/* update hash table */
250*f856f099SNavdeep Parhar 		*hslot = anchor;
251*f856f099SNavdeep Parhar 
252*f856f099SNavdeep Parhar 		if (!ref)
253*f856f099SNavdeep Parhar 			goto literal;
254*f856f099SNavdeep Parhar 		/* is this a match? check the first 3 bytes */
255*f856f099SNavdeep Parhar 		if (distance == 0 ||
256*f856f099SNavdeep Parhar #if FASTLZ_LEVEL == 1
257*f856f099SNavdeep Parhar 				(distance >= MAX_DISTANCE) ||
258*f856f099SNavdeep Parhar #else
259*f856f099SNavdeep Parhar 				(distance >= MAX_FARDISTANCE) ||
260*f856f099SNavdeep Parhar #endif
261*f856f099SNavdeep Parhar 				*ref++ != *ip++ || *ref++ != *ip++ ||
262*f856f099SNavdeep Parhar 				*ref++ != *ip++)
263*f856f099SNavdeep Parhar 			goto literal;
264*f856f099SNavdeep Parhar 
265*f856f099SNavdeep Parhar #if FASTLZ_LEVEL == 2
266*f856f099SNavdeep Parhar 		/* far, needs at least 5-byte match */
267*f856f099SNavdeep Parhar 		if (distance >= MAX_DISTANCE) {
268*f856f099SNavdeep Parhar 			if (*ip++ != *ref++ || *ip++ != *ref++)
269*f856f099SNavdeep Parhar 				goto literal;
270*f856f099SNavdeep Parhar 			len += 2;
271*f856f099SNavdeep Parhar 		}
272*f856f099SNavdeep Parhar 
273*f856f099SNavdeep Parhar match:
274*f856f099SNavdeep Parhar #endif
275*f856f099SNavdeep Parhar 
276*f856f099SNavdeep Parhar 		/* last matched byte */
277*f856f099SNavdeep Parhar 		ip = anchor + len;
278*f856f099SNavdeep Parhar 
279*f856f099SNavdeep Parhar 		/* distance is biased */
280*f856f099SNavdeep Parhar 		distance--;
281*f856f099SNavdeep Parhar 
282*f856f099SNavdeep Parhar 		if (!distance) {
283*f856f099SNavdeep Parhar 			/* zero distance means a run */
284*f856f099SNavdeep Parhar 			unsigned char x = ip[-1];
285*f856f099SNavdeep Parhar 			while (ip < ip_bound)
286*f856f099SNavdeep Parhar 				if (*ref++ != x)
287*f856f099SNavdeep Parhar 					break;
288*f856f099SNavdeep Parhar 				else
289*f856f099SNavdeep Parhar 					ip++;
290*f856f099SNavdeep Parhar 		} else
291*f856f099SNavdeep Parhar 			for (;;) {
292*f856f099SNavdeep Parhar 				/* safe because the outer check
293*f856f099SNavdeep Parhar 				 * against ip limit */
294*f856f099SNavdeep Parhar 				if (*ref++ != *ip++)
295*f856f099SNavdeep Parhar 					break;
296*f856f099SNavdeep Parhar 				if (*ref++ != *ip++)
297*f856f099SNavdeep Parhar 					break;
298*f856f099SNavdeep Parhar 				if (*ref++ != *ip++)
299*f856f099SNavdeep Parhar 					break;
300*f856f099SNavdeep Parhar 				if (*ref++ != *ip++)
301*f856f099SNavdeep Parhar 					break;
302*f856f099SNavdeep Parhar 				if (*ref++ != *ip++)
303*f856f099SNavdeep Parhar 					break;
304*f856f099SNavdeep Parhar 				if (*ref++ != *ip++)
305*f856f099SNavdeep Parhar 					break;
306*f856f099SNavdeep Parhar 				if (*ref++ != *ip++)
307*f856f099SNavdeep Parhar 					break;
308*f856f099SNavdeep Parhar 				if (*ref++ != *ip++)
309*f856f099SNavdeep Parhar 					break;
310*f856f099SNavdeep Parhar 				while (ip < ip_bound)
311*f856f099SNavdeep Parhar 					if (*ref++ != *ip++)
312*f856f099SNavdeep Parhar 						break;
313*f856f099SNavdeep Parhar 				break;
314*f856f099SNavdeep Parhar 			}
315*f856f099SNavdeep Parhar 
316*f856f099SNavdeep Parhar 		/* if we have copied something, adjust the copy count */
317*f856f099SNavdeep Parhar 		if (copy)
318*f856f099SNavdeep Parhar 			/* copy is biased, '0' means 1 byte copy */
319*f856f099SNavdeep Parhar 			*(op - copy - 1) = copy - 1;
320*f856f099SNavdeep Parhar 		else
321*f856f099SNavdeep Parhar 			/* back, to overwrite the copy count */
322*f856f099SNavdeep Parhar 			op--;
323*f856f099SNavdeep Parhar 
324*f856f099SNavdeep Parhar 		/* reset literal counter */
325*f856f099SNavdeep Parhar 		copy = 0;
326*f856f099SNavdeep Parhar 
327*f856f099SNavdeep Parhar 		/* length is biased, '1' means a match of 3 bytes */
328*f856f099SNavdeep Parhar 		ip -= 3;
329*f856f099SNavdeep Parhar 		len = ip - anchor;
330*f856f099SNavdeep Parhar 
331*f856f099SNavdeep Parhar 		/* encode the match */
332*f856f099SNavdeep Parhar #if FASTLZ_LEVEL == 2
333*f856f099SNavdeep Parhar 		if (distance < MAX_DISTANCE) {
334*f856f099SNavdeep Parhar 			if (len < 7) {
335*f856f099SNavdeep Parhar 				*op++ = (len << 5) + (distance >> 8);
336*f856f099SNavdeep Parhar 				*op++ = (distance & 255);
337*f856f099SNavdeep Parhar 			} else {
338*f856f099SNavdeep Parhar 				*op++ = (7 << 5) + (distance >> 8);
339*f856f099SNavdeep Parhar 				for (len -= 7; len >= 255; len -= 255)
340*f856f099SNavdeep Parhar 					*op++ = 255;
341*f856f099SNavdeep Parhar 				*op++ = len;
342*f856f099SNavdeep Parhar 				*op++ = (distance & 255);
343*f856f099SNavdeep Parhar 			}
344*f856f099SNavdeep Parhar 		} else {
345*f856f099SNavdeep Parhar 			/* far away, but not yet in the another galaxy... */
346*f856f099SNavdeep Parhar 			if (len < 7) {
347*f856f099SNavdeep Parhar 				distance -= MAX_DISTANCE;
348*f856f099SNavdeep Parhar 				*op++ = (len << 5) + 31;
349*f856f099SNavdeep Parhar 				*op++ = 255;
350*f856f099SNavdeep Parhar 				*op++ = distance >> 8;
351*f856f099SNavdeep Parhar 				*op++ = distance & 255;
352*f856f099SNavdeep Parhar 			} else {
353*f856f099SNavdeep Parhar 				distance -= MAX_DISTANCE;
354*f856f099SNavdeep Parhar 				*op++ = (7 << 5) + 31;
355*f856f099SNavdeep Parhar 				for (len -= 7; len >= 255; len -= 255)
356*f856f099SNavdeep Parhar 					*op++ = 255;
357*f856f099SNavdeep Parhar 				*op++ = len;
358*f856f099SNavdeep Parhar 				*op++ = 255;
359*f856f099SNavdeep Parhar 				*op++ = distance >> 8;
360*f856f099SNavdeep Parhar 				*op++ = distance & 255;
361*f856f099SNavdeep Parhar 			}
362*f856f099SNavdeep Parhar 		}
363*f856f099SNavdeep Parhar #else
364*f856f099SNavdeep Parhar 
365*f856f099SNavdeep Parhar 		if (FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN - 2))
366*f856f099SNavdeep Parhar 			while (len > MAX_LEN - 2) {
367*f856f099SNavdeep Parhar 				*op++ = (7 << 5) + (distance >> 8);
368*f856f099SNavdeep Parhar 				*op++ = MAX_LEN - 2 - 7 - 2;
369*f856f099SNavdeep Parhar 				*op++ = (distance & 255);
370*f856f099SNavdeep Parhar 				len -= MAX_LEN - 2;
371*f856f099SNavdeep Parhar 			}
372*f856f099SNavdeep Parhar 
373*f856f099SNavdeep Parhar 		if (len < 7) {
374*f856f099SNavdeep Parhar 			*op++ = (len << 5) + (distance >> 8);
375*f856f099SNavdeep Parhar 			*op++ = (distance & 255);
376*f856f099SNavdeep Parhar 		} else {
377*f856f099SNavdeep Parhar 			*op++ = (7 << 5) + (distance >> 8);
378*f856f099SNavdeep Parhar 			*op++ = len - 7;
379*f856f099SNavdeep Parhar 			*op++ = (distance & 255);
380*f856f099SNavdeep Parhar 		}
381*f856f099SNavdeep Parhar #endif
382*f856f099SNavdeep Parhar 
383*f856f099SNavdeep Parhar 		/* update the hash at match boundary */
384*f856f099SNavdeep Parhar 		HASH_FUNCTION(hval, ip);
385*f856f099SNavdeep Parhar 		htab[hval] = ip++;
386*f856f099SNavdeep Parhar 		HASH_FUNCTION(hval, ip);
387*f856f099SNavdeep Parhar 		htab[hval] = ip++;
388*f856f099SNavdeep Parhar 
389*f856f099SNavdeep Parhar 		/* assuming literal copy */
390*f856f099SNavdeep Parhar 		*op++ = MAX_COPY - 1;
391*f856f099SNavdeep Parhar 
392*f856f099SNavdeep Parhar 		continue;
393*f856f099SNavdeep Parhar 
394*f856f099SNavdeep Parhar literal:
395*f856f099SNavdeep Parhar 		*op++ = *anchor++;
396*f856f099SNavdeep Parhar 		ip = anchor;
397*f856f099SNavdeep Parhar 		copy++;
398*f856f099SNavdeep Parhar 		if (FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) {
399*f856f099SNavdeep Parhar 			copy = 0;
400*f856f099SNavdeep Parhar 			*op++ = MAX_COPY - 1;
401*f856f099SNavdeep Parhar 		}
402*f856f099SNavdeep Parhar 	}
403*f856f099SNavdeep Parhar 
404*f856f099SNavdeep Parhar 	/* left-over as literal copy */
405*f856f099SNavdeep Parhar 	ip_bound++;
406*f856f099SNavdeep Parhar 	while (ip <= ip_bound) {
407*f856f099SNavdeep Parhar 		*op++ = *ip++;
408*f856f099SNavdeep Parhar 		copy++;
409*f856f099SNavdeep Parhar 		if (copy == MAX_COPY) {
410*f856f099SNavdeep Parhar 			copy = 0;
411*f856f099SNavdeep Parhar 			*op++ = MAX_COPY - 1;
412*f856f099SNavdeep Parhar 		}
413*f856f099SNavdeep Parhar 	}
414*f856f099SNavdeep Parhar 
415*f856f099SNavdeep Parhar 	/* if we have copied something, adjust the copy length */
416*f856f099SNavdeep Parhar 	if (copy)
417*f856f099SNavdeep Parhar 		*(op - copy - 1) = copy - 1;
418*f856f099SNavdeep Parhar 	else
419*f856f099SNavdeep Parhar 		op--;
420*f856f099SNavdeep Parhar 
421*f856f099SNavdeep Parhar #if FASTLZ_LEVEL == 2
422*f856f099SNavdeep Parhar 	/* marker for fastlz2 */
423*f856f099SNavdeep Parhar 	*(unsigned char *)output |= (1 << 5);
424*f856f099SNavdeep Parhar #endif
425*f856f099SNavdeep Parhar 
426*f856f099SNavdeep Parhar 	return op - (unsigned char *)output;
427*f856f099SNavdeep Parhar }
428*f856f099SNavdeep Parhar 
FASTLZ_DECOMPRESSOR(const void * input,int length,void * output,int maxout)429*f856f099SNavdeep Parhar static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length,
430*f856f099SNavdeep Parhar 					     void *output, int maxout)
431*f856f099SNavdeep Parhar {
432*f856f099SNavdeep Parhar 	const unsigned char *ip = (const unsigned char *) input;
433*f856f099SNavdeep Parhar 	const unsigned char *ip_limit  = ip + length;
434*f856f099SNavdeep Parhar 	unsigned char *op = (unsigned char *) output;
435*f856f099SNavdeep Parhar 	unsigned char *op_limit = op + maxout;
436*f856f099SNavdeep Parhar 	unsigned int ctrl = (*ip++) & 31;
437*f856f099SNavdeep Parhar 	int loop = 1;
438*f856f099SNavdeep Parhar 
439*f856f099SNavdeep Parhar 	do {
440*f856f099SNavdeep Parhar 		const unsigned char *ref = op;
441*f856f099SNavdeep Parhar 		unsigned int len = ctrl >> 5;
442*f856f099SNavdeep Parhar 		unsigned int ofs = (ctrl & 31) << 8;
443*f856f099SNavdeep Parhar 
444*f856f099SNavdeep Parhar 		if (ctrl >= 32) {
445*f856f099SNavdeep Parhar #if FASTLZ_LEVEL == 2
446*f856f099SNavdeep Parhar 			unsigned char code;
447*f856f099SNavdeep Parhar #endif
448*f856f099SNavdeep Parhar 			len--;
449*f856f099SNavdeep Parhar 			ref -= ofs;
450*f856f099SNavdeep Parhar 			if (len == 7 - 1)
451*f856f099SNavdeep Parhar #if FASTLZ_LEVEL == 1
452*f856f099SNavdeep Parhar 				len += *ip++;
453*f856f099SNavdeep Parhar 			ref -= *ip++;
454*f856f099SNavdeep Parhar #else
455*f856f099SNavdeep Parhar 			do {
456*f856f099SNavdeep Parhar 				code = *ip++;
457*f856f099SNavdeep Parhar 				len += code;
458*f856f099SNavdeep Parhar 			} while (code == 255);
459*f856f099SNavdeep Parhar 			code = *ip++;
460*f856f099SNavdeep Parhar 			ref -= code;
461*f856f099SNavdeep Parhar 
462*f856f099SNavdeep Parhar 			/* match from 16-bit distance */
463*f856f099SNavdeep Parhar 			if (FASTLZ_UNEXPECT_CONDITIONAL(code == 255))
464*f856f099SNavdeep Parhar 				if (FASTLZ_EXPECT_CONDITIONAL(ofs ==
465*f856f099SNavdeep Parhar 							      (31 << 8))) {
466*f856f099SNavdeep Parhar 					ofs = (*ip++) << 8;
467*f856f099SNavdeep Parhar 					ofs += *ip++;
468*f856f099SNavdeep Parhar 					ref = op - ofs - MAX_DISTANCE;
469*f856f099SNavdeep Parhar 				}
470*f856f099SNavdeep Parhar #endif
471*f856f099SNavdeep Parhar 
472*f856f099SNavdeep Parhar #ifdef FASTLZ_SAFE
473*f856f099SNavdeep Parhar 			if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 >
474*f856f099SNavdeep Parhar 							op_limit))
475*f856f099SNavdeep Parhar 				return 0;
476*f856f099SNavdeep Parhar 
477*f856f099SNavdeep Parhar 			if (FASTLZ_UNEXPECT_CONDITIONAL(ref - 1 <
478*f856f099SNavdeep Parhar 							(unsigned char *)output)
479*f856f099SNavdeep Parhar 						       )
480*f856f099SNavdeep Parhar 				return 0;
481*f856f099SNavdeep Parhar #endif
482*f856f099SNavdeep Parhar 
483*f856f099SNavdeep Parhar 			if (FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
484*f856f099SNavdeep Parhar 				ctrl = *ip++;
485*f856f099SNavdeep Parhar 			else
486*f856f099SNavdeep Parhar 				loop = 0;
487*f856f099SNavdeep Parhar 
488*f856f099SNavdeep Parhar 			if (ref == op) {
489*f856f099SNavdeep Parhar 				/* optimize copy for a run */
490*f856f099SNavdeep Parhar 				unsigned char b = ref[-1];
491*f856f099SNavdeep Parhar 				*op++ = b;
492*f856f099SNavdeep Parhar 				*op++ = b;
493*f856f099SNavdeep Parhar 				*op++ = b;
494*f856f099SNavdeep Parhar 				for (; len; --len)
495*f856f099SNavdeep Parhar 					*op++ = b;
496*f856f099SNavdeep Parhar 			} else {
497*f856f099SNavdeep Parhar #if !defined(FASTLZ_STRICT_ALIGN)
498*f856f099SNavdeep Parhar 				const unsigned short *p;
499*f856f099SNavdeep Parhar 				unsigned short *q;
500*f856f099SNavdeep Parhar #endif
501*f856f099SNavdeep Parhar 				/* copy from reference */
502*f856f099SNavdeep Parhar 				ref--;
503*f856f099SNavdeep Parhar 				*op++ = *ref++;
504*f856f099SNavdeep Parhar 				*op++ = *ref++;
505*f856f099SNavdeep Parhar 				*op++ = *ref++;
506*f856f099SNavdeep Parhar 
507*f856f099SNavdeep Parhar #if !defined(FASTLZ_STRICT_ALIGN)
508*f856f099SNavdeep Parhar 				/* copy a byte, so that now it's word aligned */
509*f856f099SNavdeep Parhar 				if (len & 1) {
510*f856f099SNavdeep Parhar 					*op++ = *ref++;
511*f856f099SNavdeep Parhar 					len--;
512*f856f099SNavdeep Parhar 				}
513*f856f099SNavdeep Parhar 
514*f856f099SNavdeep Parhar 				/* copy 16-bit at once */
515*f856f099SNavdeep Parhar 				q = (unsigned short *) op;
516*f856f099SNavdeep Parhar 				op += len;
517*f856f099SNavdeep Parhar 				p = (const unsigned short *) ref;
518*f856f099SNavdeep Parhar 				for (len >>= 1; len > 4; len -= 4) {
519*f856f099SNavdeep Parhar 					*q++ = *p++;
520*f856f099SNavdeep Parhar 					*q++ = *p++;
521*f856f099SNavdeep Parhar 					*q++ = *p++;
522*f856f099SNavdeep Parhar 					*q++ = *p++;
523*f856f099SNavdeep Parhar 				}
524*f856f099SNavdeep Parhar 				for (; len; --len)
525*f856f099SNavdeep Parhar 					*q++ = *p++;
526*f856f099SNavdeep Parhar #else
527*f856f099SNavdeep Parhar 				for (; len; --len)
528*f856f099SNavdeep Parhar 					*op++ = *ref++;
529*f856f099SNavdeep Parhar #endif
530*f856f099SNavdeep Parhar 			}
531*f856f099SNavdeep Parhar 		} else {
532*f856f099SNavdeep Parhar 			ctrl++;
533*f856f099SNavdeep Parhar #ifdef FASTLZ_SAFE
534*f856f099SNavdeep Parhar 			if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
535*f856f099SNavdeep Parhar 				return 0;
536*f856f099SNavdeep Parhar 			if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
537*f856f099SNavdeep Parhar 				return 0;
538*f856f099SNavdeep Parhar #endif
539*f856f099SNavdeep Parhar 
540*f856f099SNavdeep Parhar 			*op++ = *ip++;
541*f856f099SNavdeep Parhar 			for (--ctrl; ctrl; ctrl--)
542*f856f099SNavdeep Parhar 				*op++ = *ip++;
543*f856f099SNavdeep Parhar 
544*f856f099SNavdeep Parhar 			loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
545*f856f099SNavdeep Parhar 			if (loop)
546*f856f099SNavdeep Parhar 				ctrl = *ip++;
547*f856f099SNavdeep Parhar 		}
548*f856f099SNavdeep Parhar 	} while (FASTLZ_EXPECT_CONDITIONAL(loop));
549*f856f099SNavdeep Parhar 
550*f856f099SNavdeep Parhar 	return op - (unsigned char *)output;
551*f856f099SNavdeep Parhar }
552*f856f099SNavdeep Parhar 
553*f856f099SNavdeep Parhar #endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
554