1/* 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) 5 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 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 15 * distribution. 16 * 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. 28 * 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/ 32 * 33 * Changed for kernel use by: 34 * Chanho Min <chanho.min@lge.com> 35 */ 36 37#include <linux/module.h> 38#include <linux/kernel.h> 39#include <linux/lz4.h> 40#include <asm/unaligned.h> 41#include "lz4defs.h" 42 43/* 44 * LZ4_compressCtx : 45 * ----------------- 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 50 * compression fails 51 */ 52static inline int lz4_compressctx(void *ctx, 53 const char *source, 54 char *dest, 55 int isize, 56 int maxoutputsize) 57{ 58 HTYPE *hashtable = (HTYPE *)ctx; 59 const u8 *ip = (u8 *)source; 60#if LZ4_ARCH64 61 const BYTE * const base = ip; 62#else 63 const int base = 0; 64#endif 65 const u8 *anchor = ip; 66 const u8 *const iend = ip + isize; 67 const u8 *const mflimit = iend - MFLIMIT; 68 #define MATCHLIMIT (iend - LASTLITERALS) 69 70 u8 *op = (u8 *) dest; 71 u8 *const oend = op + maxoutputsize; 72 int length; 73 const int skipstrength = SKIPSTRENGTH; 74 u32 forwardh; 75 int lastrun; 76 77 /* Init */ 78 if (isize < MINLENGTH) 79 goto _last_literals; 80 81 memset((void *)hashtable, 0, LZ4_MEM_COMPRESS); 82 83 /* First Byte */ 84 hashtable[LZ4_HASH_VALUE(ip)] = ip - base; 85 ip++; 86 forwardh = LZ4_HASH_VALUE(ip); 87 88 /* Main Loop */ 89 for (;;) { 90 int findmatchattempts = (1U << skipstrength) + 3; 91 const u8 *forwardip = ip; 92 const u8 *ref; 93 u8 *token; 94 95 /* Find a match */ 96 do { 97 u32 h = forwardh; 98 int step = findmatchattempts++ >> skipstrength; 99 ip = forwardip; 100 forwardip = ip + step; 101 102 if (unlikely(forwardip > mflimit)) 103 goto _last_literals; 104 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))); 109 110 /* Catch up */ 111 while ((ip > anchor) && (ref > (u8 *)source) && 112 unlikely(ip[-1] == ref[-1])) { 113 ip--; 114 ref--; 115 } 116 117 /* Encode Literal length */ 118 length = (int)(ip - anchor); 119 token = op++; 120 /* check output limit */ 121 if (unlikely(op + length + (2 + 1 + LASTLITERALS) + 122 (length >> 8) > oend)) 123 return 0; 124 125 if (length >= (int)RUN_MASK) { 126 int len; 127 *token = (RUN_MASK << ML_BITS); 128 len = length - RUN_MASK; 129 for (; len > 254 ; len -= 255) 130 *op++ = 255; 131 *op++ = (u8)len; 132 } else 133 *token = (length << ML_BITS); 134 135 /* Copy Literals */ 136 LZ4_BLINDCOPY(anchor, op, length); 137_next_match: 138 /* Encode Offset */ 139 LZ4_WRITE_LITTLEENDIAN_16(op, (u16)(ip - ref)); 140 141 /* Start Counting */ 142 ip += MINMATCH; 143 /* MinMatch verified */ 144 ref += MINMATCH; 145 anchor = ip; 146 while (likely(ip < MATCHLIMIT - (STEPSIZE - 1))) { 147 #if LZ4_ARCH64 148 u64 diff = A64(ref) ^ A64(ip); 149 #else 150 u32 diff = A32(ref) ^ A32(ip); 151 #endif 152 if (!diff) { 153 ip += STEPSIZE; 154 ref += STEPSIZE; 155 continue; 156 } 157 ip += LZ4_NBCOMMONBYTES(diff); 158 goto _endcount; 159 } 160 #if LZ4_ARCH64 161 if ((ip < (MATCHLIMIT - 3)) && (A32(ref) == A32(ip))) { 162 ip += 4; 163 ref += 4; 164 } 165 #endif 166 if ((ip < (MATCHLIMIT - 1)) && (A16(ref) == A16(ip))) { 167 ip += 2; 168 ref += 2; 169 } 170 if ((ip < MATCHLIMIT) && (*ref == *ip)) 171 ip++; 172_endcount: 173 /* Encode MatchLength */ 174 length = (int)(ip - anchor); 175 /* Check output limit */ 176 if (unlikely(op + (1 + LASTLITERALS) + (length >> 8) > oend)) 177 return 0; 178 if (length >= (int)ML_MASK) { 179 *token += ML_MASK; 180 length -= ML_MASK; 181 for (; length > 509 ; length -= 510) { 182 *op++ = 255; 183 *op++ = 255; 184 } 185 if (length > 254) { 186 length -= 255; 187 *op++ = 255; 188 } 189 *op++ = (u8)length; 190 } else 191 *token += length; 192 193 /* Test end of chunk */ 194 if (ip > mflimit) { 195 anchor = ip; 196 break; 197 } 198 199 /* Fill table */ 200 hashtable[LZ4_HASH_VALUE(ip-2)] = ip - 2 - base; 201 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))) { 206 token = op++; 207 *token = 0; 208 goto _next_match; 209 } 210 211 /* Prepare next loop */ 212 anchor = ip++; 213 forwardh = LZ4_HASH_VALUE(ip); 214 } 215 216_last_literals: 217 /* Encode Last Literals */ 218 lastrun = (int)(iend - anchor); 219 if (((char *)op - dest) + lastrun + 1 220 + ((lastrun + 255 - RUN_MASK) / 255) > (u32)maxoutputsize) 221 return 0; 222 223 if (lastrun >= (int)RUN_MASK) { 224 *op++ = (RUN_MASK << ML_BITS); 225 lastrun -= RUN_MASK; 226 for (; lastrun > 254 ; lastrun -= 255) 227 *op++ = 255; 228 *op++ = (u8)lastrun; 229 } else 230 *op++ = (lastrun << ML_BITS); 231 memcpy(op, anchor, iend - anchor); 232 op += iend - anchor; 233 234 /* End */ 235 return (int)(((char *)op) - dest); 236} 237 238static inline int lz4_compress64kctx(void *ctx, 239 const char *source, 240 char *dest, 241 int isize, 242 int maxoutputsize) 243{ 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) 251 252 u8 *op = (u8 *) dest; 253 u8 *const oend = op + maxoutputsize; 254 int len, length; 255 const int skipstrength = SKIPSTRENGTH; 256 u32 forwardh; 257 int lastrun; 258 259 /* Init */ 260 if (isize < MINLENGTH) 261 goto _last_literals; 262 263 memset((void *)hashtable, 0, LZ4_MEM_COMPRESS); 264 265 /* First Byte */ 266 ip++; 267 forwardh = LZ4_HASH64K_VALUE(ip); 268 269 /* Main Loop */ 270 for (;;) { 271 int findmatchattempts = (1U << skipstrength) + 3; 272 const u8 *forwardip = ip; 273 const u8 *ref; 274 u8 *token; 275 276 /* Find a match */ 277 do { 278 u32 h = forwardh; 279 int step = findmatchattempts++ >> skipstrength; 280 ip = forwardip; 281 forwardip = ip + step; 282 283 if (forwardip > mflimit) 284 goto _last_literals; 285 286 forwardh = LZ4_HASH64K_VALUE(forwardip); 287 ref = base + hashtable[h]; 288 hashtable[h] = (u16)(ip - base); 289 } while (A32(ref) != A32(ip)); 290 291 /* Catch up */ 292 while ((ip > anchor) && (ref > (u8 *)source) 293 && (ip[-1] == ref[-1])) { 294 ip--; 295 ref--; 296 } 297 298 /* Encode Literal length */ 299 length = (int)(ip - anchor); 300 token = op++; 301 /* Check output limit */ 302 if (unlikely(op + length + (2 + 1 + LASTLITERALS) 303 + (length >> 8) > oend)) 304 return 0; 305 if (length >= (int)RUN_MASK) { 306 *token = (RUN_MASK << ML_BITS); 307 len = length - RUN_MASK; 308 for (; len > 254 ; len -= 255) 309 *op++ = 255; 310 *op++ = (u8)len; 311 } else 312 *token = (length << ML_BITS); 313 314 /* Copy Literals */ 315 LZ4_BLINDCOPY(anchor, op, length); 316 317_next_match: 318 /* Encode Offset */ 319 LZ4_WRITE_LITTLEENDIAN_16(op, (u16)(ip - ref)); 320 321 /* Start Counting */ 322 ip += MINMATCH; 323 /* MinMatch verified */ 324 ref += MINMATCH; 325 anchor = ip; 326 327 while (ip < MATCHLIMIT - (STEPSIZE - 1)) { 328 #if LZ4_ARCH64 329 u64 diff = A64(ref) ^ A64(ip); 330 #else 331 u32 diff = A32(ref) ^ A32(ip); 332 #endif 333 334 if (!diff) { 335 ip += STEPSIZE; 336 ref += STEPSIZE; 337 continue; 338 } 339 ip += LZ4_NBCOMMONBYTES(diff); 340 goto _endcount; 341 } 342 #if LZ4_ARCH64 343 if ((ip < (MATCHLIMIT - 3)) && (A32(ref) == A32(ip))) { 344 ip += 4; 345 ref += 4; 346 } 347 #endif 348 if ((ip < (MATCHLIMIT - 1)) && (A16(ref) == A16(ip))) { 349 ip += 2; 350 ref += 2; 351 } 352 if ((ip < MATCHLIMIT) && (*ref == *ip)) 353 ip++; 354_endcount: 355 356 /* Encode MatchLength */ 357 len = (int)(ip - anchor); 358 /* Check output limit */ 359 if (unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend)) 360 return 0; 361 if (len >= (int)ML_MASK) { 362 *token += ML_MASK; 363 len -= ML_MASK; 364 for (; len > 509 ; len -= 510) { 365 *op++ = 255; 366 *op++ = 255; 367 } 368 if (len > 254) { 369 len -= 255; 370 *op++ = 255; 371 } 372 *op++ = (u8)len; 373 } else 374 *token += len; 375 376 /* Test end of chunk */ 377 if (ip > mflimit) { 378 anchor = ip; 379 break; 380 } 381 382 /* Fill table */ 383 hashtable[LZ4_HASH64K_VALUE(ip-2)] = (u16)(ip - 2 - base); 384 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)) { 389 token = op++; 390 *token = 0; 391 goto _next_match; 392 } 393 394 /* Prepare next loop */ 395 anchor = ip++; 396 forwardh = LZ4_HASH64K_VALUE(ip); 397 } 398 399_last_literals: 400 /* Encode Last Literals */ 401 lastrun = (int)(iend - anchor); 402 if (op + lastrun + 1 + (lastrun - RUN_MASK + 255) / 255 > oend) 403 return 0; 404 if (lastrun >= (int)RUN_MASK) { 405 *op++ = (RUN_MASK << ML_BITS); 406 lastrun -= RUN_MASK; 407 for (; lastrun > 254 ; lastrun -= 255) 408 *op++ = 255; 409 *op++ = (u8)lastrun; 410 } else 411 *op++ = (lastrun << ML_BITS); 412 memcpy(op, anchor, iend - anchor); 413 op += iend - anchor; 414 /* End */ 415 return (int)(((char *)op) - dest); 416} 417 418int lz4_compress(const unsigned char *src, size_t src_len, 419 unsigned char *dst, size_t *dst_len, void *wrkmem) 420{ 421 int ret = -1; 422 int out_len = 0; 423 424 if (src_len < LZ4_64KLIMIT) 425 out_len = lz4_compress64kctx(wrkmem, src, dst, src_len, 426 lz4_compressbound(src_len)); 427 else 428 out_len = lz4_compressctx(wrkmem, src, dst, src_len, 429 lz4_compressbound(src_len)); 430 431 if (out_len < 0) 432 goto exit; 433 434 *dst_len = out_len; 435 436 return 0; 437exit: 438 return ret; 439} 440EXPORT_SYMBOL(lz4_compress); 441 442MODULE_LICENSE("Dual BSD/GPL"); 443MODULE_DESCRIPTION("LZ4 compressor"); 444