2 * LZ4 HC - High Compression Mode of LZ4
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>
45 HTYPE hashtable
[HASHTABLESIZE
];
47 const u8
*nexttoupdate
;
48 } __attribute__((__packed__
));
50 static inline int lz4hc_init(struct lz4hc_data
*hc4
, const u8
*base
)
52 memset((void *)hc4
->hashtable
, 0, sizeof(hc4
->hashtable
));
53 memset(hc4
->chaintable
, 0xFF, sizeof(hc4
->chaintable
));
56 hc4
->nexttoupdate
= base
+ 1;
58 hc4
->nexttoupdate
= base
;
64 /* Update chains up to ip (excluded) */
65 static inline void lz4hc_insert(struct lz4hc_data
*hc4
, const u8
*ip
)
67 u16
*chaintable
= hc4
->chaintable
;
68 HTYPE
*hashtable
= hc4
->hashtable
;
70 const BYTE
* const base
= hc4
->base
;
75 while (hc4
->nexttoupdate
< ip
) {
76 const u8
*p
= hc4
->nexttoupdate
;
77 size_t delta
= p
- (hashtable
[HASH_VALUE(p
)] + base
);
78 if (delta
> MAX_DISTANCE
)
80 chaintable
[(size_t)(p
) & MAXD_MASK
] = (u16
)delta
;
81 hashtable
[HASH_VALUE(p
)] = (p
) - base
;
86 static inline size_t lz4hc_commonlength(const u8
*p1
, const u8
*p2
,
87 const u8
*const matchlimit
)
91 while (p1t
< matchlimit
- (STEPSIZE
- 1)) {
93 u64 diff
= A64(p2
) ^ A64(p1t
);
95 u32 diff
= A32(p2
) ^ A32(p1t
);
102 p1t
+= LZ4_NBCOMMONBYTES(diff
);
106 if ((p1t
< (matchlimit
-3)) && (A32(p2
) == A32(p1t
))) {
112 if ((p1t
< (matchlimit
- 1)) && (A16(p2
) == A16(p1t
))) {
116 if ((p1t
< matchlimit
) && (*p2
== *p1t
))
121 static inline int lz4hc_insertandfindbestmatch(struct lz4hc_data
*hc4
,
122 const u8
*ip
, const u8
*const matchlimit
, const u8
**matchpos
)
124 u16
*const chaintable
= hc4
->chaintable
;
125 HTYPE
*const hashtable
= hc4
->hashtable
;
128 const BYTE
* const base
= hc4
->base
;
132 int nbattempts
= MAX_NB_ATTEMPTS
;
133 size_t repl
= 0, ml
= 0;
136 /* HC4 match finder */
137 lz4hc_insert(hc4
, ip
);
138 ref
= hashtable
[HASH_VALUE(ip
)] + base
;
140 /* potential repetition */
143 if (A32(ref
) == A32(ip
)) {
144 delta
= (u16
)(ip
-ref
);
145 repl
= ml
= lz4hc_commonlength(ip
+ MINMATCH
,
146 ref
+ MINMATCH
, matchlimit
) + MINMATCH
;
149 ref
-= (size_t)chaintable
[(size_t)(ref
) & MAXD_MASK
];
152 while ((ref
>= ip
- MAX_DISTANCE
) && nbattempts
) {
154 if (*(ref
+ ml
) == *(ip
+ ml
)) {
155 if (A32(ref
) == A32(ip
)) {
157 lz4hc_commonlength(ip
+ MINMATCH
,
158 ref
+ MINMATCH
, matchlimit
) + MINMATCH
;
165 ref
-= (size_t)chaintable
[(size_t)(ref
) & MAXD_MASK
];
170 const BYTE
*ptr
= ip
;
172 end
= ip
+ repl
- (MINMATCH
-1);
174 while (ptr
< end
- delta
) {
175 chaintable
[(size_t)(ptr
) & MAXD_MASK
] = delta
;
179 chaintable
[(size_t)(ptr
) & MAXD_MASK
] = delta
;
181 hashtable
[HASH_VALUE(ptr
)] = (ptr
) - base
;
184 hc4
->nexttoupdate
= end
;
190 static inline int lz4hc_insertandgetwidermatch(struct lz4hc_data
*hc4
,
191 const u8
*ip
, const u8
*startlimit
, const u8
*matchlimit
, int longest
,
192 const u8
**matchpos
, const u8
**startpos
)
194 u16
*const chaintable
= hc4
->chaintable
;
195 HTYPE
*const hashtable
= hc4
->hashtable
;
197 const BYTE
* const base
= hc4
->base
;
202 int nbattempts
= MAX_NB_ATTEMPTS
;
203 int delta
= (int)(ip
- startlimit
);
206 lz4hc_insert(hc4
, ip
);
207 ref
= hashtable
[HASH_VALUE(ip
)] + base
;
209 while ((ref
>= ip
- MAX_DISTANCE
) && (ref
>= hc4
->base
)
212 if (*(startlimit
+ longest
) == *(ref
- delta
+ longest
)) {
213 if (A32(ref
) == A32(ip
)) {
214 const u8
*reft
= ref
+ MINMATCH
;
215 const u8
*ipt
= ip
+ MINMATCH
;
216 const u8
*startt
= ip
;
218 while (ipt
< matchlimit
-(STEPSIZE
- 1)) {
220 u64 diff
= A64(reft
) ^ A64(ipt
);
222 u32 diff
= A32(reft
) ^ A32(ipt
);
230 ipt
+= LZ4_NBCOMMONBYTES(diff
);
234 if ((ipt
< (matchlimit
- 3))
235 && (A32(reft
) == A32(ipt
))) {
241 if ((ipt
< (matchlimit
- 1))
242 && (A16(reft
) == A16(ipt
))) {
245 if ((ipt
< matchlimit
) && (*reft
== *ipt
))
250 while ((startt
> startlimit
)
251 && (reft
> hc4
->base
)
252 && (startt
[-1] == reft
[-1])) {
257 if ((ipt
- startt
) > longest
) {
258 longest
= (int)(ipt
- startt
);
264 ref
-= (size_t)chaintable
[(size_t)(ref
) & MAXD_MASK
];
269 static inline int lz4_encodesequence(const u8
**ip
, u8
**op
, const u8
**anchor
,
270 int ml
, const u8
*ref
)
275 /* Encode Literal length */
276 length
= (int)(*ip
- *anchor
);
278 if (length
>= (int)RUN_MASK
) {
279 *token
= (RUN_MASK
<< ML_BITS
);
280 len
= length
- RUN_MASK
;
281 for (; len
> 254 ; len
-= 255)
285 *token
= (length
<< ML_BITS
);
288 LZ4_BLINDCOPY(*anchor
, *op
, length
);
291 LZ4_WRITE_LITTLEENDIAN_16(*op
, (u16
)(*ip
- ref
));
293 /* Encode MatchLength */
294 len
= (int)(ml
- MINMATCH
);
295 if (len
>= (int)ML_MASK
) {
298 for (; len
> 509 ; len
-= 510) {
310 /* Prepare next loop */
317 static int lz4_compresshcctx(struct lz4hc_data
*ctx
,
322 const u8
*ip
= (const u8
*)source
;
323 const u8
*anchor
= ip
;
324 const u8
*const iend
= ip
+ isize
;
325 const u8
*const mflimit
= iend
- MFLIMIT
;
326 const u8
*const matchlimit
= (iend
- LASTLITERALS
);
330 int ml
, ml2
, ml3
, ml0
;
331 const u8
*ref
= NULL
;
332 const u8
*start2
= NULL
;
333 const u8
*ref2
= NULL
;
334 const u8
*start3
= NULL
;
335 const u8
*ref3
= NULL
;
343 while (ip
< mflimit
) {
344 ml
= lz4hc_insertandfindbestmatch(ctx
, ip
, matchlimit
, (&ref
));
350 /* saved, in case we would skip too much */
356 ml2
= lz4hc_insertandgetwidermatch(ctx
, ip
+ ml
- 2,
357 ip
+ 1, matchlimit
, ml
, &ref2
, &start2
);
360 /* No better match */
362 lz4_encodesequence(&ip
, &op
, &anchor
, ml
, ref
);
368 if (start2
< ip
+ ml0
) {
376 * First Match too small : removed
378 if ((start2
- ip
) < 3) {
387 * Currently we have :
389 * ip1+3 <= ip2 (usually < ip1+ml1)
391 if ((start2
- ip
) < OPTIMAL_ML
) {
394 if (new_ml
> OPTIMAL_ML
)
396 if (ip
+ new_ml
> start2
+ ml2
- MINMATCH
)
397 new_ml
= (int)(start2
- ip
) + ml2
- MINMATCH
;
398 correction
= new_ml
- (int)(start2
- ip
);
399 if (correction
> 0) {
400 start2
+= correction
;
406 * Now, we have start2 = ip+new_ml,
407 * with new_ml=min(ml, OPTIMAL_ML=18)
409 if (start2
+ ml2
< mflimit
)
410 ml3
= lz4hc_insertandgetwidermatch(ctx
,
411 start2
+ ml2
- 3, start2
, matchlimit
,
412 ml2
, &ref3
, &start3
);
416 /* No better match : 2 sequences to encode */
418 /* ip & ref are known; Now for ml */
420 ml
= (int)(start2
- ip
);
422 /* Now, encode 2 sequences */
423 lz4_encodesequence(&ip
, &op
, &anchor
, ml
, ref
);
425 lz4_encodesequence(&ip
, &op
, &anchor
, ml2
, ref2
);
429 /* Not enough space for match 2 : remove it */
430 if (start3
< ip
+ ml
+ 3) {
432 * can write Seq1 immediately ==> Seq2 is removed,
433 * so Seq3 becomes Seq1
435 if (start3
>= (ip
+ ml
)) {
436 if (start2
< ip
+ ml
) {
438 (int)(ip
+ ml
- start2
);
439 start2
+= correction
;
442 if (ml2
< MINMATCH
) {
449 lz4_encodesequence(&ip
, &op
, &anchor
, ml
, ref
);
467 * OK, now we have 3 ascending matches; let's write at least
468 * the first one ip & ref are known; Now for ml
470 if (start2
< ip
+ ml
) {
471 if ((start2
- ip
) < (int)ML_MASK
) {
475 if (ip
+ ml
> start2
+ ml2
- MINMATCH
)
476 ml
= (int)(start2
- ip
) + ml2
478 correction
= ml
- (int)(start2
- ip
);
479 if (correction
> 0) {
480 start2
+= correction
;
485 ml
= (int)(start2
- ip
);
487 lz4_encodesequence(&ip
, &op
, &anchor
, ml
, ref
);
500 /* Encode Last Literals */
501 lastrun
= (int)(iend
- anchor
);
502 if (lastrun
>= (int)RUN_MASK
) {
503 *op
++ = (RUN_MASK
<< ML_BITS
);
505 for (; lastrun
> 254 ; lastrun
-= 255)
507 *op
++ = (u8
) lastrun
;
509 *op
++ = (lastrun
<< ML_BITS
);
510 memcpy(op
, anchor
, iend
- anchor
);
513 return (int) (((char *)op
) - dest
);
516 int lz4hc_compress(const unsigned char *src
, size_t src_len
,
517 unsigned char *dst
, size_t *dst_len
, void *wrkmem
)
522 struct lz4hc_data
*hc4
= (struct lz4hc_data
*)wrkmem
;
523 lz4hc_init(hc4
, (const u8
*)src
);
524 out_len
= lz4_compresshcctx((struct lz4hc_data
*)hc4
, (const u8
*)src
,
525 (char *)dst
, (int)src_len
);
536 EXPORT_SYMBOL(lz4hc_compress
);
538 MODULE_LICENSE("Dual BSD/GPL");
539 MODULE_DESCRIPTION("LZ4HC compressor");