1*4a5d661aSToomas Soome /* 2*4a5d661aSToomas Soome * LZ4 - Fast LZ compression algorithm 3*4a5d661aSToomas Soome * Header File 4*4a5d661aSToomas Soome * Copyright (C) 2011-2013, Yann Collet. 5*4a5d661aSToomas Soome * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 6*4a5d661aSToomas Soome * 7*4a5d661aSToomas Soome * Redistribution and use in source and binary forms, with or without 8*4a5d661aSToomas Soome * modification, are permitted provided that the following conditions are 9*4a5d661aSToomas Soome * met: 10*4a5d661aSToomas Soome * 11*4a5d661aSToomas Soome * * Redistributions of source code must retain the above copyright 12*4a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer. 13*4a5d661aSToomas Soome * * Redistributions in binary form must reproduce the above 14*4a5d661aSToomas Soome * copyright notice, this list of conditions and the following disclaimer 15*4a5d661aSToomas Soome * in the documentation and/or other materials provided with the 16*4a5d661aSToomas Soome * distribution. 17*4a5d661aSToomas Soome * 18*4a5d661aSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19*4a5d661aSToomas Soome * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20*4a5d661aSToomas Soome * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21*4a5d661aSToomas Soome * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22*4a5d661aSToomas Soome * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23*4a5d661aSToomas Soome * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24*4a5d661aSToomas Soome * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25*4a5d661aSToomas Soome * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26*4a5d661aSToomas Soome * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27*4a5d661aSToomas Soome * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28*4a5d661aSToomas Soome * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29*4a5d661aSToomas Soome * 30*4a5d661aSToomas Soome * You can contact the author at : 31*4a5d661aSToomas Soome * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html 32*4a5d661aSToomas Soome * - LZ4 source repository : http://code.google.com/p/lz4/ 33*4a5d661aSToomas Soome * 34*4a5d661aSToomas Soome * $FreeBSD$ 35*4a5d661aSToomas Soome */ 36*4a5d661aSToomas Soome int lz4_decompress(void *, void *, size_t, size_t, int); 37*4a5d661aSToomas Soome 38*4a5d661aSToomas Soome static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, 39*4a5d661aSToomas Soome int isize, int maxOutputSize); 40*4a5d661aSToomas Soome 41*4a5d661aSToomas Soome /* ARGSUSED */ 42*4a5d661aSToomas Soome int 43*4a5d661aSToomas Soome lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, int dummy __unused) 44*4a5d661aSToomas Soome { 45*4a5d661aSToomas Soome const uint8_t *src = s_start; 46*4a5d661aSToomas Soome uint32_t bufsiz = htonl(*(uint32_t *)src); 47*4a5d661aSToomas Soome 48*4a5d661aSToomas Soome /* invalid compressed buffer size encoded at start */ 49*4a5d661aSToomas Soome if (bufsiz + 4 > s_len) 50*4a5d661aSToomas Soome return (1); 51*4a5d661aSToomas Soome 52*4a5d661aSToomas Soome /* 53*4a5d661aSToomas Soome * Returns 0 on success (decompression function returned non-negative) 54*4a5d661aSToomas Soome * and non-zero on failure (decompression function returned negative). 55*4a5d661aSToomas Soome */ 56*4a5d661aSToomas Soome return (LZ4_uncompress_unknownOutputSize((const char *)s_start + 4, d_start, bufsiz, 57*4a5d661aSToomas Soome d_len) < 0); 58*4a5d661aSToomas Soome } 59*4a5d661aSToomas Soome 60*4a5d661aSToomas Soome /* 61*4a5d661aSToomas Soome * CPU Feature Detection 62*4a5d661aSToomas Soome */ 63*4a5d661aSToomas Soome 64*4a5d661aSToomas Soome /* 32 or 64 bits ? */ 65*4a5d661aSToomas Soome #if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || \ 66*4a5d661aSToomas Soome defined(__amd64) || defined(__ppc64__) || defined(_WIN64) || \ 67*4a5d661aSToomas Soome defined(__LP64__) || defined(_LP64)) 68*4a5d661aSToomas Soome #define LZ4_ARCH64 1 69*4a5d661aSToomas Soome #else 70*4a5d661aSToomas Soome #define LZ4_ARCH64 0 71*4a5d661aSToomas Soome #endif 72*4a5d661aSToomas Soome 73*4a5d661aSToomas Soome /* 74*4a5d661aSToomas Soome * Little Endian or Big Endian? 75*4a5d661aSToomas Soome * Note: overwrite the below #define if you know your architecture endianess. 76*4a5d661aSToomas Soome */ 77*4a5d661aSToomas Soome #if BYTE_ORDER == BIG_ENDIAN 78*4a5d661aSToomas Soome #define LZ4_BIG_ENDIAN 1 79*4a5d661aSToomas Soome #else 80*4a5d661aSToomas Soome /* 81*4a5d661aSToomas Soome * Little Endian assumed. PDP Endian and other very rare endian format 82*4a5d661aSToomas Soome * are unsupported. 83*4a5d661aSToomas Soome */ 84*4a5d661aSToomas Soome #endif 85*4a5d661aSToomas Soome 86*4a5d661aSToomas Soome /* 87*4a5d661aSToomas Soome * Unaligned memory access is automatically enabled for "common" CPU, 88*4a5d661aSToomas Soome * such as x86. For others CPU, the compiler will be more cautious, and 89*4a5d661aSToomas Soome * insert extra code to ensure aligned access is respected. If you know 90*4a5d661aSToomas Soome * your target CPU supports unaligned memory access, you may want to 91*4a5d661aSToomas Soome * force this option manually to improve performance 92*4a5d661aSToomas Soome */ 93*4a5d661aSToomas Soome #if defined(__ARM_FEATURE_UNALIGNED) 94*4a5d661aSToomas Soome #define LZ4_FORCE_UNALIGNED_ACCESS 1 95*4a5d661aSToomas Soome #endif 96*4a5d661aSToomas Soome 97*4a5d661aSToomas Soome /* 98*4a5d661aSToomas Soome * Compiler Options 99*4a5d661aSToomas Soome */ 100*4a5d661aSToomas Soome #if __STDC_VERSION__ >= 199901L /* C99 */ 101*4a5d661aSToomas Soome /* "restrict" is a known keyword */ 102*4a5d661aSToomas Soome #else 103*4a5d661aSToomas Soome /* Disable restrict */ 104*4a5d661aSToomas Soome #define restrict 105*4a5d661aSToomas Soome #endif 106*4a5d661aSToomas Soome 107*4a5d661aSToomas Soome #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) 108*4a5d661aSToomas Soome 109*4a5d661aSToomas Soome #define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) \ 110*4a5d661aSToomas Soome | (((x) & 0xffu) << 8))) 111*4a5d661aSToomas Soome 112*4a5d661aSToomas Soome #if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) 113*4a5d661aSToomas Soome #define expect(expr, value) (__builtin_expect((expr), (value))) 114*4a5d661aSToomas Soome #else 115*4a5d661aSToomas Soome #define expect(expr, value) (expr) 116*4a5d661aSToomas Soome #endif 117*4a5d661aSToomas Soome 118*4a5d661aSToomas Soome #define likely(expr) expect((expr) != 0, 1) 119*4a5d661aSToomas Soome #define unlikely(expr) expect((expr) != 0, 0) 120*4a5d661aSToomas Soome 121*4a5d661aSToomas Soome /* Basic types */ 122*4a5d661aSToomas Soome #define BYTE uint8_t 123*4a5d661aSToomas Soome #define U16 uint16_t 124*4a5d661aSToomas Soome #define U32 uint32_t 125*4a5d661aSToomas Soome #define S32 int32_t 126*4a5d661aSToomas Soome #define U64 uint64_t 127*4a5d661aSToomas Soome 128*4a5d661aSToomas Soome #ifndef LZ4_FORCE_UNALIGNED_ACCESS 129*4a5d661aSToomas Soome #pragma pack(1) 130*4a5d661aSToomas Soome #endif 131*4a5d661aSToomas Soome 132*4a5d661aSToomas Soome typedef struct _U16_S { 133*4a5d661aSToomas Soome U16 v; 134*4a5d661aSToomas Soome } U16_S; 135*4a5d661aSToomas Soome typedef struct _U32_S { 136*4a5d661aSToomas Soome U32 v; 137*4a5d661aSToomas Soome } U32_S; 138*4a5d661aSToomas Soome typedef struct _U64_S { 139*4a5d661aSToomas Soome U64 v; 140*4a5d661aSToomas Soome } U64_S; 141*4a5d661aSToomas Soome 142*4a5d661aSToomas Soome #ifndef LZ4_FORCE_UNALIGNED_ACCESS 143*4a5d661aSToomas Soome #pragma pack() 144*4a5d661aSToomas Soome #endif 145*4a5d661aSToomas Soome 146*4a5d661aSToomas Soome #define A64(x) (((U64_S *)(x))->v) 147*4a5d661aSToomas Soome #define A32(x) (((U32_S *)(x))->v) 148*4a5d661aSToomas Soome #define A16(x) (((U16_S *)(x))->v) 149*4a5d661aSToomas Soome 150*4a5d661aSToomas Soome /* 151*4a5d661aSToomas Soome * Constants 152*4a5d661aSToomas Soome */ 153*4a5d661aSToomas Soome #define MINMATCH 4 154*4a5d661aSToomas Soome 155*4a5d661aSToomas Soome #define COPYLENGTH 8 156*4a5d661aSToomas Soome #define LASTLITERALS 5 157*4a5d661aSToomas Soome 158*4a5d661aSToomas Soome #define ML_BITS 4 159*4a5d661aSToomas Soome #define ML_MASK ((1U<<ML_BITS)-1) 160*4a5d661aSToomas Soome #define RUN_BITS (8-ML_BITS) 161*4a5d661aSToomas Soome #define RUN_MASK ((1U<<RUN_BITS)-1) 162*4a5d661aSToomas Soome 163*4a5d661aSToomas Soome /* 164*4a5d661aSToomas Soome * Architecture-specific macros 165*4a5d661aSToomas Soome */ 166*4a5d661aSToomas Soome #if LZ4_ARCH64 167*4a5d661aSToomas Soome #define STEPSIZE 8 168*4a5d661aSToomas Soome #define UARCH U64 169*4a5d661aSToomas Soome #define AARCH A64 170*4a5d661aSToomas Soome #define LZ4_COPYSTEP(s, d) A64(d) = A64(s); d += 8; s += 8; 171*4a5d661aSToomas Soome #define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d) 172*4a5d661aSToomas Soome #define LZ4_SECURECOPY(s, d, e) if (d < e) LZ4_WILDCOPY(s, d, e) 173*4a5d661aSToomas Soome #define HTYPE U32 174*4a5d661aSToomas Soome #define INITBASE(base) const BYTE* const base = ip 175*4a5d661aSToomas Soome #else 176*4a5d661aSToomas Soome #define STEPSIZE 4 177*4a5d661aSToomas Soome #define UARCH U32 178*4a5d661aSToomas Soome #define AARCH A32 179*4a5d661aSToomas Soome #define LZ4_COPYSTEP(s, d) A32(d) = A32(s); d += 4; s += 4; 180*4a5d661aSToomas Soome #define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d); 181*4a5d661aSToomas Soome #define LZ4_SECURECOPY LZ4_WILDCOPY 182*4a5d661aSToomas Soome #define HTYPE const BYTE* 183*4a5d661aSToomas Soome #define INITBASE(base) const int base = 0 184*4a5d661aSToomas Soome #endif 185*4a5d661aSToomas Soome 186*4a5d661aSToomas Soome #if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE)) 187*4a5d661aSToomas Soome #define LZ4_READ_LITTLEENDIAN_16(d, s, p) \ 188*4a5d661aSToomas Soome { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; } 189*4a5d661aSToomas Soome #define LZ4_WRITE_LITTLEENDIAN_16(p, i) \ 190*4a5d661aSToomas Soome { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p += 2; } 191*4a5d661aSToomas Soome #else 192*4a5d661aSToomas Soome #define LZ4_READ_LITTLEENDIAN_16(d, s, p) { d = (s) - A16(p); } 193*4a5d661aSToomas Soome #define LZ4_WRITE_LITTLEENDIAN_16(p, v) { A16(p) = v; p += 2; } 194*4a5d661aSToomas Soome #endif 195*4a5d661aSToomas Soome 196*4a5d661aSToomas Soome /* Macros */ 197*4a5d661aSToomas Soome #define LZ4_WILDCOPY(s, d, e) do { LZ4_COPYPACKET(s, d) } while (d < e); 198*4a5d661aSToomas Soome 199*4a5d661aSToomas Soome /* Decompression functions */ 200*4a5d661aSToomas Soome 201*4a5d661aSToomas Soome static int 202*4a5d661aSToomas Soome LZ4_uncompress_unknownOutputSize(const char *source, 203*4a5d661aSToomas Soome char *dest, int isize, int maxOutputSize) 204*4a5d661aSToomas Soome { 205*4a5d661aSToomas Soome /* Local Variables */ 206*4a5d661aSToomas Soome const BYTE *restrict ip = (const BYTE *) source; 207*4a5d661aSToomas Soome const BYTE *const iend = ip + isize; 208*4a5d661aSToomas Soome const BYTE *restrict ref; 209*4a5d661aSToomas Soome 210*4a5d661aSToomas Soome BYTE *restrict op = (BYTE *) dest; 211*4a5d661aSToomas Soome BYTE *const oend = op + maxOutputSize; 212*4a5d661aSToomas Soome BYTE *cpy; 213*4a5d661aSToomas Soome 214*4a5d661aSToomas Soome size_t dec[] = { 0, 3, 2, 3, 0, 0, 0, 0 }; 215*4a5d661aSToomas Soome 216*4a5d661aSToomas Soome /* Main Loop */ 217*4a5d661aSToomas Soome while (ip < iend) { 218*4a5d661aSToomas Soome BYTE token; 219*4a5d661aSToomas Soome int length; 220*4a5d661aSToomas Soome 221*4a5d661aSToomas Soome /* get runlength */ 222*4a5d661aSToomas Soome token = *ip++; 223*4a5d661aSToomas Soome if ((length = (token >> ML_BITS)) == RUN_MASK) { 224*4a5d661aSToomas Soome int s = 255; 225*4a5d661aSToomas Soome while ((ip < iend) && (s == 255)) { 226*4a5d661aSToomas Soome s = *ip++; 227*4a5d661aSToomas Soome length += s; 228*4a5d661aSToomas Soome } 229*4a5d661aSToomas Soome } 230*4a5d661aSToomas Soome /* copy literals */ 231*4a5d661aSToomas Soome cpy = op + length; 232*4a5d661aSToomas Soome if ((cpy > oend - COPYLENGTH) || 233*4a5d661aSToomas Soome (ip + length > iend - COPYLENGTH)) { 234*4a5d661aSToomas Soome if (cpy > oend) 235*4a5d661aSToomas Soome /* 236*4a5d661aSToomas Soome * Error: request to write beyond destination 237*4a5d661aSToomas Soome * buffer. 238*4a5d661aSToomas Soome */ 239*4a5d661aSToomas Soome goto _output_error; 240*4a5d661aSToomas Soome if (ip + length > iend) 241*4a5d661aSToomas Soome /* 242*4a5d661aSToomas Soome * Error : request to read beyond source 243*4a5d661aSToomas Soome * buffer. 244*4a5d661aSToomas Soome */ 245*4a5d661aSToomas Soome goto _output_error; 246*4a5d661aSToomas Soome memcpy(op, ip, length); 247*4a5d661aSToomas Soome op += length; 248*4a5d661aSToomas Soome ip += length; 249*4a5d661aSToomas Soome if (ip < iend) 250*4a5d661aSToomas Soome /* Error : LZ4 format violation */ 251*4a5d661aSToomas Soome goto _output_error; 252*4a5d661aSToomas Soome /* Necessarily EOF, due to parsing restrictions. */ 253*4a5d661aSToomas Soome break; 254*4a5d661aSToomas Soome } 255*4a5d661aSToomas Soome LZ4_WILDCOPY(ip, op, cpy); 256*4a5d661aSToomas Soome ip -= (op - cpy); 257*4a5d661aSToomas Soome op = cpy; 258*4a5d661aSToomas Soome 259*4a5d661aSToomas Soome /* get offset */ 260*4a5d661aSToomas Soome LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); 261*4a5d661aSToomas Soome ip += 2; 262*4a5d661aSToomas Soome if (ref < (BYTE * const) dest) 263*4a5d661aSToomas Soome /* 264*4a5d661aSToomas Soome * Error: offset creates reference outside of 265*4a5d661aSToomas Soome * destination buffer. 266*4a5d661aSToomas Soome */ 267*4a5d661aSToomas Soome goto _output_error; 268*4a5d661aSToomas Soome 269*4a5d661aSToomas Soome /* get matchlength */ 270*4a5d661aSToomas Soome if ((length = (token & ML_MASK)) == ML_MASK) { 271*4a5d661aSToomas Soome while (ip < iend) { 272*4a5d661aSToomas Soome int s = *ip++; 273*4a5d661aSToomas Soome length += s; 274*4a5d661aSToomas Soome if (s == 255) 275*4a5d661aSToomas Soome continue; 276*4a5d661aSToomas Soome break; 277*4a5d661aSToomas Soome } 278*4a5d661aSToomas Soome } 279*4a5d661aSToomas Soome /* copy repeated sequence */ 280*4a5d661aSToomas Soome if unlikely(op - ref < STEPSIZE) { 281*4a5d661aSToomas Soome #if LZ4_ARCH64 282*4a5d661aSToomas Soome size_t dec2table[] = { 0, 0, 0, -1, 0, 1, 2, 3 }; 283*4a5d661aSToomas Soome size_t dec2 = dec2table[op - ref]; 284*4a5d661aSToomas Soome #else 285*4a5d661aSToomas Soome const int dec2 = 0; 286*4a5d661aSToomas Soome #endif 287*4a5d661aSToomas Soome *op++ = *ref++; 288*4a5d661aSToomas Soome *op++ = *ref++; 289*4a5d661aSToomas Soome *op++ = *ref++; 290*4a5d661aSToomas Soome *op++ = *ref++; 291*4a5d661aSToomas Soome ref -= dec[op - ref]; 292*4a5d661aSToomas Soome A32(op) = A32(ref); 293*4a5d661aSToomas Soome op += STEPSIZE - 4; 294*4a5d661aSToomas Soome ref -= dec2; 295*4a5d661aSToomas Soome } else { 296*4a5d661aSToomas Soome LZ4_COPYSTEP(ref, op); 297*4a5d661aSToomas Soome } 298*4a5d661aSToomas Soome cpy = op + length - (STEPSIZE - 4); 299*4a5d661aSToomas Soome if (cpy > oend - COPYLENGTH) { 300*4a5d661aSToomas Soome if (cpy > oend) 301*4a5d661aSToomas Soome /* 302*4a5d661aSToomas Soome * Error: request to write outside of 303*4a5d661aSToomas Soome * destination buffer. 304*4a5d661aSToomas Soome */ 305*4a5d661aSToomas Soome goto _output_error; 306*4a5d661aSToomas Soome LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); 307*4a5d661aSToomas Soome while (op < cpy) 308*4a5d661aSToomas Soome *op++ = *ref++; 309*4a5d661aSToomas Soome op = cpy; 310*4a5d661aSToomas Soome if (op == oend) 311*4a5d661aSToomas Soome /* 312*4a5d661aSToomas Soome * Check EOF (should never happen, since last 313*4a5d661aSToomas Soome * 5 bytes are supposed to be literals). 314*4a5d661aSToomas Soome */ 315*4a5d661aSToomas Soome break; 316*4a5d661aSToomas Soome continue; 317*4a5d661aSToomas Soome } 318*4a5d661aSToomas Soome LZ4_SECURECOPY(ref, op, cpy); 319*4a5d661aSToomas Soome op = cpy; /* correction */ 320*4a5d661aSToomas Soome } 321*4a5d661aSToomas Soome 322*4a5d661aSToomas Soome /* end of decoding */ 323*4a5d661aSToomas Soome return (int)(((char *)op) - dest); 324*4a5d661aSToomas Soome 325*4a5d661aSToomas Soome /* write overflow error detected */ 326*4a5d661aSToomas Soome _output_error: 327*4a5d661aSToomas Soome return (int)(-(((char *)ip) - source)); 328*4a5d661aSToomas Soome } 329