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