2 * LZ4 - Fast LZ compression algorithm
3 * Copyright (C) 2011-2012, Yann Collet.
4 * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * You can contact the author at :
30 * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
31 * - LZ4 source repository : http://code.google.com/p/lz4/
33 * Changed for kernel use by:
34 * Chanho Min <chanho.min@lge.com>
37 #include <linux/module.h>
38 #include <linux/kernel.h>
39 #include <linux/lz4.h>
40 #include <asm/unaligned.h>
46 * Compress 'isize' bytes from 'source' into an output buffer 'dest' of
47 * maximum size 'maxOutputSize'. * If it cannot achieve it, compression
48 * will stop, and result of the function will be zero.
49 * return : the number of bytes written in buffer 'dest', or 0 if the
52 static inline int lz4_compressctx(void *ctx
,
58 HTYPE
*hashtable
= (HTYPE
*)ctx
;
59 const u8
*ip
= (u8
*)source
;
61 const BYTE
* const base
= ip
;
65 const u8
*anchor
= ip
;
66 const u8
*const iend
= ip
+ isize
;
67 const u8
*const mflimit
= iend
- MFLIMIT
;
68 #define MATCHLIMIT (iend - LASTLITERALS)
71 u8
*const oend
= op
+ maxoutputsize
;
73 const int skipstrength
= SKIPSTRENGTH
;
78 if (isize
< MINLENGTH
)
81 memset((void *)hashtable
, 0, LZ4_MEM_COMPRESS
);
84 hashtable
[LZ4_HASH_VALUE(ip
)] = ip
- base
;
86 forwardh
= LZ4_HASH_VALUE(ip
);
90 int findmatchattempts
= (1U << skipstrength
) + 3;
91 const u8
*forwardip
= ip
;
98 int step
= findmatchattempts
++ >> skipstrength
;
100 forwardip
= ip
+ step
;
102 if (unlikely(forwardip
> mflimit
))
105 forwardh
= LZ4_HASH_VALUE(forwardip
);
106 ref
= base
+ hashtable
[h
];
107 hashtable
[h
] = ip
- base
;
108 } while ((ref
< ip
- MAX_DISTANCE
) || (A32(ref
) != A32(ip
)));
111 while ((ip
> anchor
) && (ref
> (u8
*)source
) &&
112 unlikely(ip
[-1] == ref
[-1])) {
117 /* Encode Literal length */
118 length
= (int)(ip
- anchor
);
120 /* check output limit */
121 if (unlikely(op
+ length
+ (2 + 1 + LASTLITERALS
) +
122 (length
>> 8) > oend
))
125 if (length
>= (int)RUN_MASK
) {
127 *token
= (RUN_MASK
<< ML_BITS
);
128 len
= length
- RUN_MASK
;
129 for (; len
> 254 ; len
-= 255)
133 *token
= (length
<< ML_BITS
);
136 LZ4_BLINDCOPY(anchor
, op
, length
);
139 LZ4_WRITE_LITTLEENDIAN_16(op
, (u16
)(ip
- ref
));
143 /* MinMatch verified */
146 while (likely(ip
< MATCHLIMIT
- (STEPSIZE
- 1))) {
148 u64 diff
= A64(ref
) ^ A64(ip
);
150 u32 diff
= A32(ref
) ^ A32(ip
);
157 ip
+= LZ4_NBCOMMONBYTES(diff
);
161 if ((ip
< (MATCHLIMIT
- 3)) && (A32(ref
) == A32(ip
))) {
166 if ((ip
< (MATCHLIMIT
- 1)) && (A16(ref
) == A16(ip
))) {
170 if ((ip
< MATCHLIMIT
) && (*ref
== *ip
))
173 /* Encode MatchLength */
174 length
= (int)(ip
- anchor
);
175 /* Check output limit */
176 if (unlikely(op
+ (1 + LASTLITERALS
) + (length
>> 8) > oend
))
178 if (length
>= (int)ML_MASK
) {
181 for (; length
> 509 ; length
-= 510) {
193 /* Test end of chunk */
200 hashtable
[LZ4_HASH_VALUE(ip
-2)] = ip
- 2 - base
;
202 /* Test next position */
203 ref
= base
+ hashtable
[LZ4_HASH_VALUE(ip
)];
204 hashtable
[LZ4_HASH_VALUE(ip
)] = ip
- base
;
205 if ((ref
> ip
- (MAX_DISTANCE
+ 1)) && (A32(ref
) == A32(ip
))) {
211 /* Prepare next loop */
213 forwardh
= LZ4_HASH_VALUE(ip
);
217 /* Encode Last Literals */
218 lastrun
= (int)(iend
- anchor
);
219 if (((char *)op
- dest
) + lastrun
+ 1
220 + ((lastrun
+ 255 - RUN_MASK
) / 255) > (u32
)maxoutputsize
)
223 if (lastrun
>= (int)RUN_MASK
) {
224 *op
++ = (RUN_MASK
<< ML_BITS
);
226 for (; lastrun
> 254 ; lastrun
-= 255)
230 *op
++ = (lastrun
<< ML_BITS
);
231 memcpy(op
, anchor
, iend
- anchor
);
235 return (int)(((char *)op
) - dest
);
238 static inline int lz4_compress64kctx(void *ctx
,
244 u16
*hashtable
= (u16
*)ctx
;
245 const u8
*ip
= (u8
*) source
;
246 const u8
*anchor
= ip
;
247 const u8
*const base
= ip
;
248 const u8
*const iend
= ip
+ isize
;
249 const u8
*const mflimit
= iend
- MFLIMIT
;
250 #define MATCHLIMIT (iend - LASTLITERALS)
252 u8
*op
= (u8
*) dest
;
253 u8
*const oend
= op
+ maxoutputsize
;
255 const int skipstrength
= SKIPSTRENGTH
;
260 if (isize
< MINLENGTH
)
263 memset((void *)hashtable
, 0, LZ4_MEM_COMPRESS
);
267 forwardh
= LZ4_HASH64K_VALUE(ip
);
271 int findmatchattempts
= (1U << skipstrength
) + 3;
272 const u8
*forwardip
= ip
;
279 int step
= findmatchattempts
++ >> skipstrength
;
281 forwardip
= ip
+ step
;
283 if (forwardip
> mflimit
)
286 forwardh
= LZ4_HASH64K_VALUE(forwardip
);
287 ref
= base
+ hashtable
[h
];
288 hashtable
[h
] = (u16
)(ip
- base
);
289 } while (A32(ref
) != A32(ip
));
292 while ((ip
> anchor
) && (ref
> (u8
*)source
)
293 && (ip
[-1] == ref
[-1])) {
298 /* Encode Literal length */
299 length
= (int)(ip
- anchor
);
301 /* Check output limit */
302 if (unlikely(op
+ length
+ (2 + 1 + LASTLITERALS
)
303 + (length
>> 8) > oend
))
305 if (length
>= (int)RUN_MASK
) {
306 *token
= (RUN_MASK
<< ML_BITS
);
307 len
= length
- RUN_MASK
;
308 for (; len
> 254 ; len
-= 255)
312 *token
= (length
<< ML_BITS
);
315 LZ4_BLINDCOPY(anchor
, op
, length
);
319 LZ4_WRITE_LITTLEENDIAN_16(op
, (u16
)(ip
- ref
));
323 /* MinMatch verified */
327 while (ip
< MATCHLIMIT
- (STEPSIZE
- 1)) {
329 u64 diff
= A64(ref
) ^ A64(ip
);
331 u32 diff
= A32(ref
) ^ A32(ip
);
339 ip
+= LZ4_NBCOMMONBYTES(diff
);
343 if ((ip
< (MATCHLIMIT
- 3)) && (A32(ref
) == A32(ip
))) {
348 if ((ip
< (MATCHLIMIT
- 1)) && (A16(ref
) == A16(ip
))) {
352 if ((ip
< MATCHLIMIT
) && (*ref
== *ip
))
356 /* Encode MatchLength */
357 len
= (int)(ip
- anchor
);
358 /* Check output limit */
359 if (unlikely(op
+ (1 + LASTLITERALS
) + (len
>> 8) > oend
))
361 if (len
>= (int)ML_MASK
) {
364 for (; len
> 509 ; len
-= 510) {
376 /* Test end of chunk */
383 hashtable
[LZ4_HASH64K_VALUE(ip
-2)] = (u16
)(ip
- 2 - base
);
385 /* Test next position */
386 ref
= base
+ hashtable
[LZ4_HASH64K_VALUE(ip
)];
387 hashtable
[LZ4_HASH64K_VALUE(ip
)] = (u16
)(ip
- base
);
388 if (A32(ref
) == A32(ip
)) {
394 /* Prepare next loop */
396 forwardh
= LZ4_HASH64K_VALUE(ip
);
400 /* Encode Last Literals */
401 lastrun
= (int)(iend
- anchor
);
402 if (op
+ lastrun
+ 1 + (lastrun
- RUN_MASK
+ 255) / 255 > oend
)
404 if (lastrun
>= (int)RUN_MASK
) {
405 *op
++ = (RUN_MASK
<< ML_BITS
);
407 for (; lastrun
> 254 ; lastrun
-= 255)
411 *op
++ = (lastrun
<< ML_BITS
);
412 memcpy(op
, anchor
, iend
- anchor
);
415 return (int)(((char *)op
) - dest
);
418 int lz4_compress(const unsigned char *src
, size_t src_len
,
419 unsigned char *dst
, size_t *dst_len
, void *wrkmem
)
424 if (src_len
< LZ4_64KLIMIT
)
425 out_len
= lz4_compress64kctx(wrkmem
, src
, dst
, src_len
,
426 lz4_compressbound(src_len
));
428 out_len
= lz4_compressctx(wrkmem
, src
, dst
, src_len
,
429 lz4_compressbound(src_len
));
440 EXPORT_SYMBOL(lz4_compress
);
442 MODULE_LICENSE("Dual BSD/GPL");
443 MODULE_DESCRIPTION("LZ4 compressor");