1e499793eSToomas Soome /* 2e499793eSToomas Soome * LZ4 - Fast LZ compression algorithm 3e499793eSToomas Soome * Header File 4e499793eSToomas Soome * Copyright (C) 2011-2013, Yann Collet. 5e499793eSToomas Soome * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 6e499793eSToomas Soome * 7e499793eSToomas Soome * Redistribution and use in source and binary forms, with or without 8e499793eSToomas Soome * modification, are permitted provided that the following conditions are 9e499793eSToomas Soome * met: 10e499793eSToomas Soome * 11e499793eSToomas Soome * * Redistributions of source code must retain the above copyright 12e499793eSToomas Soome * notice, this list of conditions and the following disclaimer. 13e499793eSToomas Soome * * Redistributions in binary form must reproduce the above 14e499793eSToomas Soome * copyright notice, this list of conditions and the following disclaimer 15e499793eSToomas Soome * in the documentation and/or other materials provided with the 16e499793eSToomas Soome * distribution. 17e499793eSToomas Soome * 18e499793eSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19e499793eSToomas Soome * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20e499793eSToomas Soome * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21e499793eSToomas Soome * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22e499793eSToomas Soome * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23e499793eSToomas Soome * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24e499793eSToomas Soome * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25e499793eSToomas Soome * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26e499793eSToomas Soome * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27e499793eSToomas Soome * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28e499793eSToomas Soome * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29e499793eSToomas Soome * 30e499793eSToomas Soome * You can contact the author at : 31e499793eSToomas Soome * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html 32e499793eSToomas Soome * - LZ4 source repository : http://code.google.com/p/lz4/ 33e499793eSToomas Soome */ 34e499793eSToomas Soome /* 35e499793eSToomas Soome * Copyright (c) 2016 by Delphix. All rights reserved. 36e499793eSToomas Soome */ 37e499793eSToomas Soome 3824e1a7acSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL) 39e499793eSToomas Soome #include <sys/zfs_context.h> 40e499793eSToomas Soome #elif defined(_STANDALONE) 41e499793eSToomas Soome #include <sys/cdefs.h> 42e499793eSToomas Soome #include <stand.h> 43e499793eSToomas Soome #include <sys/types.h> 44e499793eSToomas Soome #include <sys/endian.h> 45e499793eSToomas Soome #include <assert.h> 46e499793eSToomas Soome 47e499793eSToomas Soome #define ASSERT assert 48e499793eSToomas Soome #else 49e499793eSToomas Soome #include <string.h> 50e499793eSToomas Soome #include <stdlib.h> 51e499793eSToomas Soome #include <sys/types.h> 52e499793eSToomas Soome #include <netinet/in.h> 53e499793eSToomas Soome #include <assert.h> 54e499793eSToomas Soome 55e499793eSToomas Soome #define ASSERT assert 56e499793eSToomas Soome #endif 57e499793eSToomas Soome #include <lz4.h> 58e499793eSToomas Soome 59e499793eSToomas Soome static int real_LZ4_compress(const char *source, char *dest, int isize, 60e499793eSToomas Soome int osize); 61e499793eSToomas Soome static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, 62e499793eSToomas Soome int isize, int maxOutputSize); 63e499793eSToomas Soome static int LZ4_compressCtx(void *ctx, const char *source, char *dest, 64e499793eSToomas Soome int isize, int osize); 65e499793eSToomas Soome static int LZ4_compress64kCtx(void *ctx, const char *source, char *dest, 66e499793eSToomas Soome int isize, int osize); 67e499793eSToomas Soome 6824e1a7acSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL) 69e499793eSToomas Soome static kmem_cache_t *lz4_ctx_cache; 70e499793eSToomas Soome #endif 71e499793eSToomas Soome 72e499793eSToomas Soome size_t 73e499793eSToomas Soome lz4_compress(void *s_start, void *d_start, size_t s_len, size_t d_len, 74e499793eSToomas Soome int n __unused) 75e499793eSToomas Soome { 76e499793eSToomas Soome uint32_t bufsiz; 77e499793eSToomas Soome char *dest = d_start; 78e499793eSToomas Soome 79e499793eSToomas Soome ASSERT(d_len >= sizeof (bufsiz)); 80e499793eSToomas Soome 81e499793eSToomas Soome bufsiz = real_LZ4_compress(s_start, &dest[sizeof (bufsiz)], s_len, 82e499793eSToomas Soome d_len - sizeof (bufsiz)); 83e499793eSToomas Soome 84e499793eSToomas Soome /* Signal an error if the compression routine returned zero. */ 85e499793eSToomas Soome if (bufsiz == 0) 86e499793eSToomas Soome return (s_len); 87e499793eSToomas Soome 88e499793eSToomas Soome /* 89e499793eSToomas Soome * Encode the compresed buffer size at the start. We'll need this in 90e499793eSToomas Soome * decompression to counter the effects of padding which might be 91e499793eSToomas Soome * added to the compressed buffer and which, if unhandled, would 92e499793eSToomas Soome * confuse the hell out of our decompression function. 93e499793eSToomas Soome */ 9424e1a7acSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL) 95e499793eSToomas Soome *(uint32_t *)(void *)dest = BE_32(bufsiz); 96e499793eSToomas Soome #else 97e499793eSToomas Soome *(uint32_t *)(void *)dest = htonl(bufsiz); 98e499793eSToomas Soome #endif 99e499793eSToomas Soome 100e499793eSToomas Soome return (bufsiz + sizeof (bufsiz)); 101e499793eSToomas Soome } 102e499793eSToomas Soome 103e499793eSToomas Soome int 104e499793eSToomas Soome lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, 105e499793eSToomas Soome int n __unused) 106e499793eSToomas Soome { 107e499793eSToomas Soome const char *src = s_start; 10824e1a7acSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL) 109e499793eSToomas Soome uint32_t bufsiz = BE_IN32(s_start); 110e499793eSToomas Soome #else 111e499793eSToomas Soome uint32_t bufsiz = htonl(*(uint32_t *)s_start); 112e499793eSToomas Soome #endif 113e499793eSToomas Soome 114e499793eSToomas Soome /* invalid compressed buffer size encoded at start */ 115e499793eSToomas Soome if (bufsiz + sizeof (bufsiz) > s_len) 116e499793eSToomas Soome return (1); 117e499793eSToomas Soome 118e499793eSToomas Soome /* 119e499793eSToomas Soome * Returns 0 on success (decompression function returned non-negative) 120e499793eSToomas Soome * and non-zero on failure (decompression function returned negative). 121e499793eSToomas Soome */ 122e499793eSToomas Soome return (LZ4_uncompress_unknownOutputSize(&src[sizeof (bufsiz)], 123e499793eSToomas Soome d_start, bufsiz, d_len) < 0); 124e499793eSToomas Soome } 125e499793eSToomas Soome 126e499793eSToomas Soome /* 127e499793eSToomas Soome * LZ4 API Description: 128e499793eSToomas Soome * 129e499793eSToomas Soome * Simple Functions: 130e499793eSToomas Soome * real_LZ4_compress() : 131e499793eSToomas Soome * isize : is the input size. Max supported value is ~1.9GB 132e499793eSToomas Soome * return : the number of bytes written in buffer dest 133e499793eSToomas Soome * or 0 if the compression fails (if LZ4_COMPRESSMIN is set). 134e499793eSToomas Soome * note : destination buffer must be already allocated. 135e499793eSToomas Soome * destination buffer must be sized to handle worst cases 136e499793eSToomas Soome * situations (input data not compressible). 137e499793eSToomas Soome * 138e499793eSToomas Soome * Advanced Functions 139e499793eSToomas Soome * 140e499793eSToomas Soome * LZ4_uncompress_unknownOutputSize() : 141e499793eSToomas Soome * isize : is the input size, therefore the compressed size 142e499793eSToomas Soome * maxOutputSize : is the size of the destination buffer (which must be 143e499793eSToomas Soome * already allocated) 144e499793eSToomas Soome * return : the number of bytes decoded in the destination buffer 145e499793eSToomas Soome * (necessarily <= maxOutputSize). If the source stream is 146e499793eSToomas Soome * malformed, the function will stop decoding and return a 147e499793eSToomas Soome * negative result, indicating the byte position of the faulty 148e499793eSToomas Soome * instruction. This function never writes beyond dest + 149e499793eSToomas Soome * maxOutputSize, and is therefore protected against malicious 150e499793eSToomas Soome * data packets. 151e499793eSToomas Soome * note : Destination buffer must be already allocated. 152e499793eSToomas Soome * 153e499793eSToomas Soome * LZ4_compressCtx() : 154e499793eSToomas Soome * This function explicitly handles the CTX memory structure. 155e499793eSToomas Soome * 156e499793eSToomas Soome * ILLUMOS CHANGES: the CTX memory structure must be explicitly allocated 157e499793eSToomas Soome * by the caller (either on the stack or using kmem_zalloc). Passing NULL 158e499793eSToomas Soome * isn't valid. 159e499793eSToomas Soome * 160e499793eSToomas Soome * LZ4_compress64kCtx() : 161e499793eSToomas Soome * Same as LZ4_compressCtx(), but specific to small inputs (<64KB). 162e499793eSToomas Soome * isize *Must* be <64KB, otherwise the output will be corrupted. 163e499793eSToomas Soome * 164e499793eSToomas Soome * ILLUMOS CHANGES: the CTX memory structure must be explicitly allocated 165e499793eSToomas Soome * by the caller (either on the stack or using kmem_zalloc). Passing NULL 166e499793eSToomas Soome * isn't valid. 167e499793eSToomas Soome */ 168e499793eSToomas Soome 169e499793eSToomas Soome /* 170e499793eSToomas Soome * Tuning parameters 171e499793eSToomas Soome */ 172e499793eSToomas Soome 173e499793eSToomas Soome /* 174e499793eSToomas Soome * COMPRESSIONLEVEL: Increasing this value improves compression ratio 175e499793eSToomas Soome * Lowering this value reduces memory usage. Reduced memory usage 176e499793eSToomas Soome * typically improves speed, due to cache effect (ex: L1 32KB for Intel, 177e499793eSToomas Soome * L1 64KB for AMD). Memory usage formula : N->2^(N+2) Bytes 178e499793eSToomas Soome * (examples : 12 -> 16KB ; 17 -> 512KB) 179e499793eSToomas Soome */ 180e499793eSToomas Soome #define COMPRESSIONLEVEL 12 181e499793eSToomas Soome 182e499793eSToomas Soome /* 183e499793eSToomas Soome * NOTCOMPRESSIBLE_CONFIRMATION: Decreasing this value will make the 184e499793eSToomas Soome * algorithm skip faster data segments considered "incompressible". 185e499793eSToomas Soome * This may decrease compression ratio dramatically, but will be 186e499793eSToomas Soome * faster on incompressible data. Increasing this value will make 187e499793eSToomas Soome * the algorithm search more before declaring a segment "incompressible". 188e499793eSToomas Soome * This could improve compression a bit, but will be slower on 189e499793eSToomas Soome * incompressible data. The default value (6) is recommended. 190e499793eSToomas Soome */ 191e499793eSToomas Soome #define NOTCOMPRESSIBLE_CONFIRMATION 6 192e499793eSToomas Soome 193e499793eSToomas Soome /* 194e499793eSToomas Soome * BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE: This will provide a boost to 195e499793eSToomas Soome * performance for big endian cpu, but the resulting compressed stream 196e499793eSToomas Soome * will be incompatible with little-endian CPU. You can set this option 197e499793eSToomas Soome * to 1 in situations where data will stay within closed environment. 198e499793eSToomas Soome * This option is useless on Little_Endian CPU (such as x86). 199e499793eSToomas Soome */ 200e499793eSToomas Soome /* #define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 */ 201e499793eSToomas Soome 202e499793eSToomas Soome /* 203e499793eSToomas Soome * CPU Feature Detection 204e499793eSToomas Soome */ 205e499793eSToomas Soome 206e499793eSToomas Soome /* 32 or 64 bits ? */ 207e499793eSToomas Soome #if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || \ 208e499793eSToomas Soome defined(__amd64) || defined(__ppc64__) || defined(_WIN64) || \ 209e499793eSToomas Soome defined(__LP64__) || defined(_LP64)) 210e499793eSToomas Soome #define LZ4_ARCH64 1 211e499793eSToomas Soome #else 212e499793eSToomas Soome #define LZ4_ARCH64 0 213e499793eSToomas Soome #endif 214e499793eSToomas Soome 215e499793eSToomas Soome /* 216e499793eSToomas Soome * Limits the amount of stack space that the algorithm may consume to hold 217e499793eSToomas Soome * the compression lookup table. The value `9' here means we'll never use 218e499793eSToomas Soome * more than 2k of stack (see above for a description of COMPRESSIONLEVEL). 219e499793eSToomas Soome * If more memory is needed, it is allocated from the heap. 220e499793eSToomas Soome */ 221e499793eSToomas Soome /* FreeBSD: Use heap for all platforms for now */ 222e499793eSToomas Soome #define STACKLIMIT 0 223e499793eSToomas Soome 224e499793eSToomas Soome /* 225e499793eSToomas Soome * Little Endian or Big Endian? 226e499793eSToomas Soome * Note: overwrite the below #define if you know your architecture endianess. 227e499793eSToomas Soome */ 228e499793eSToomas Soome #if BYTE_ORDER == BIG_ENDIAN 229e499793eSToomas Soome #define LZ4_BIG_ENDIAN 1 230e499793eSToomas Soome #else 231e499793eSToomas Soome /* 232e499793eSToomas Soome * Little Endian assumed. PDP Endian and other very rare endian format 233e499793eSToomas Soome * are unsupported. 234e499793eSToomas Soome */ 235e499793eSToomas Soome #endif 236e499793eSToomas Soome 237e499793eSToomas Soome /* 238e499793eSToomas Soome * Unaligned memory access is automatically enabled for "common" CPU, 239e499793eSToomas Soome * such as x86. For others CPU, the compiler will be more cautious, and 240e499793eSToomas Soome * insert extra code to ensure aligned access is respected. If you know 241e499793eSToomas Soome * your target CPU supports unaligned memory access, you may want to 242e499793eSToomas Soome * force this option manually to improve performance 243e499793eSToomas Soome */ 244e499793eSToomas Soome #if defined(__ARM_FEATURE_UNALIGNED) 245e499793eSToomas Soome #define LZ4_FORCE_UNALIGNED_ACCESS 1 246e499793eSToomas Soome #endif 247e499793eSToomas Soome 248e499793eSToomas Soome /* 249e499793eSToomas Soome * Compiler Options 250e499793eSToomas Soome */ 251e499793eSToomas Soome #if __STDC_VERSION__ >= 199901L /* C99 */ 252e499793eSToomas Soome /* "restrict" is a known keyword */ 253e499793eSToomas Soome #else 254e499793eSToomas Soome /* Disable restrict */ 255e499793eSToomas Soome #define restrict 256e499793eSToomas Soome #endif 257e499793eSToomas Soome 258e499793eSToomas Soome #define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | \ 259e499793eSToomas Soome (((x) & 0xffu) << 8))) 260e499793eSToomas Soome 261e499793eSToomas Soome #define expect(expr, value) (__builtin_expect((expr), (value))) 262e499793eSToomas Soome 263e499793eSToomas Soome #if defined(likely) 264e499793eSToomas Soome #undef likely 265e499793eSToomas Soome #endif 266e499793eSToomas Soome #if defined(unlikely) 267e499793eSToomas Soome #undef unlikely 268e499793eSToomas Soome #endif 269e499793eSToomas Soome 270e499793eSToomas Soome #ifndef likely 271e499793eSToomas Soome #define likely(expr) expect((expr) != 0, 1) 272e499793eSToomas Soome #endif 273e499793eSToomas Soome 274e499793eSToomas Soome #ifndef unlikely 275e499793eSToomas Soome #define unlikely(expr) expect((expr) != 0, 0) 276e499793eSToomas Soome #endif 277e499793eSToomas Soome 278e499793eSToomas Soome /* Basic types */ 279e499793eSToomas Soome #define BYTE uint8_t 280e499793eSToomas Soome #define U16 uint16_t 281e499793eSToomas Soome #define U32 uint32_t 282e499793eSToomas Soome #define S32 int32_t 283e499793eSToomas Soome #define U64 uint64_t 284e499793eSToomas Soome 285e499793eSToomas Soome #ifndef LZ4_FORCE_UNALIGNED_ACCESS 286e499793eSToomas Soome #pragma pack(1) 287e499793eSToomas Soome #endif 288e499793eSToomas Soome 289e499793eSToomas Soome typedef struct _U16_S { 290e499793eSToomas Soome U16 v; 291e499793eSToomas Soome } U16_S; 292e499793eSToomas Soome typedef struct _U32_S { 293e499793eSToomas Soome U32 v; 294e499793eSToomas Soome } U32_S; 295e499793eSToomas Soome typedef struct _U64_S { 296e499793eSToomas Soome U64 v; 297e499793eSToomas Soome } U64_S; 298e499793eSToomas Soome 299e499793eSToomas Soome #ifndef LZ4_FORCE_UNALIGNED_ACCESS 300e499793eSToomas Soome #pragma pack() 301e499793eSToomas Soome #endif 302e499793eSToomas Soome 303e499793eSToomas Soome #define A64(x) (((U64_S *)(__DECONST(void *, x)))->v) 304e499793eSToomas Soome #define A32(x) (((U32_S *)(__DECONST(void *, x)))->v) 305e499793eSToomas Soome #define A16(x) (((U16_S *)(__DECONST(void *, x)))->v) 306e499793eSToomas Soome 307e499793eSToomas Soome /* 308e499793eSToomas Soome * Constants 309e499793eSToomas Soome */ 310e499793eSToomas Soome #define MINMATCH 4 311e499793eSToomas Soome 312e499793eSToomas Soome #define HASH_LOG COMPRESSIONLEVEL 313e499793eSToomas Soome #define HASHTABLESIZE (1 << HASH_LOG) 314e499793eSToomas Soome #define HASH_MASK (HASHTABLESIZE - 1) 315e499793eSToomas Soome 316e499793eSToomas Soome #define SKIPSTRENGTH (NOTCOMPRESSIBLE_CONFIRMATION > 2 ? \ 317e499793eSToomas Soome NOTCOMPRESSIBLE_CONFIRMATION : 2) 318e499793eSToomas Soome 319e499793eSToomas Soome /* 320e499793eSToomas Soome * Defines if memory is allocated into the stack (local variable), 321e499793eSToomas Soome * or into the heap (kmem_alloc()). 322e499793eSToomas Soome */ 323e499793eSToomas Soome #define HEAPMODE (HASH_LOG > STACKLIMIT) 324e499793eSToomas Soome #define COPYLENGTH 8 325e499793eSToomas Soome #define LASTLITERALS 5 326e499793eSToomas Soome #define MFLIMIT (COPYLENGTH + MINMATCH) 327e499793eSToomas Soome #define MINLENGTH (MFLIMIT + 1) 328e499793eSToomas Soome 329e499793eSToomas Soome #define MAXD_LOG 16 330e499793eSToomas Soome #define MAX_DISTANCE ((1 << MAXD_LOG) - 1) 331e499793eSToomas Soome 332e499793eSToomas Soome #define ML_BITS 4 333e499793eSToomas Soome #define ML_MASK ((1U<<ML_BITS)-1) 334e499793eSToomas Soome #define RUN_BITS (8-ML_BITS) 335e499793eSToomas Soome #define RUN_MASK ((1U<<RUN_BITS)-1) 336e499793eSToomas Soome 337e499793eSToomas Soome 338e499793eSToomas Soome /* 339e499793eSToomas Soome * Architecture-specific macros 340e499793eSToomas Soome */ 341e499793eSToomas Soome #if LZ4_ARCH64 342e499793eSToomas Soome #define STEPSIZE 8 343e499793eSToomas Soome #define UARCH U64 344e499793eSToomas Soome #define AARCH A64 345e499793eSToomas Soome #define LZ4_COPYSTEP(s, d) A64(d) = A64(s); d += 8; s += 8; 346e499793eSToomas Soome #define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d) 347e499793eSToomas Soome #define LZ4_SECURECOPY(s, d, e) if (d < e) LZ4_WILDCOPY(s, d, e) 348e499793eSToomas Soome #define HTYPE U32 349e499793eSToomas Soome #define INITBASE(base) const BYTE* const base = ip 350e499793eSToomas Soome #else /* !LZ4_ARCH64 */ 351e499793eSToomas Soome #define STEPSIZE 4 352e499793eSToomas Soome #define UARCH U32 353e499793eSToomas Soome #define AARCH A32 354e499793eSToomas Soome #define LZ4_COPYSTEP(s, d) A32(d) = A32(s); d += 4; s += 4; 355e499793eSToomas Soome #define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d); 356e499793eSToomas Soome #define LZ4_SECURECOPY LZ4_WILDCOPY 357e499793eSToomas Soome #define HTYPE const BYTE * 358e499793eSToomas Soome #define INITBASE(base) const int base = 0 359e499793eSToomas Soome #endif /* !LZ4_ARCH64 */ 360e499793eSToomas Soome 361e499793eSToomas Soome #if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE)) 362e499793eSToomas Soome #define LZ4_READ_LITTLEENDIAN_16(d, s, p) \ 363e499793eSToomas Soome { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; } 364e499793eSToomas Soome #define LZ4_WRITE_LITTLEENDIAN_16(p, i) \ 365e499793eSToomas Soome { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p += 2; } 366e499793eSToomas Soome #else 367e499793eSToomas Soome #define LZ4_READ_LITTLEENDIAN_16(d, s, p) { d = (s) - A16(p); } 368e499793eSToomas Soome #define LZ4_WRITE_LITTLEENDIAN_16(p, v) { A16(p) = v; p += 2; } 369e499793eSToomas Soome #endif 370e499793eSToomas Soome 371e499793eSToomas Soome 372e499793eSToomas Soome /* Local structures */ 373e499793eSToomas Soome struct refTables { 374e499793eSToomas Soome HTYPE hashTable[HASHTABLESIZE]; 375e499793eSToomas Soome }; 376e499793eSToomas Soome 377e499793eSToomas Soome 378e499793eSToomas Soome /* Macros */ 379e499793eSToomas Soome #define LZ4_HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH * 8) - \ 380e499793eSToomas Soome HASH_LOG)) 381e499793eSToomas Soome #define LZ4_HASH_VALUE(p) LZ4_HASH_FUNCTION(A32(p)) 382e499793eSToomas Soome #define LZ4_WILDCOPY(s, d, e) do { LZ4_COPYPACKET(s, d) } while (d < e); 383e499793eSToomas Soome #define LZ4_BLINDCOPY(s, d, l) { BYTE* e = (d) + l; LZ4_WILDCOPY(s, d, e); \ 384e499793eSToomas Soome d = e; } 385e499793eSToomas Soome 386e499793eSToomas Soome 387e499793eSToomas Soome /* Private functions */ 388e499793eSToomas Soome #if LZ4_ARCH64 389e499793eSToomas Soome 390e499793eSToomas Soome static inline int 391e499793eSToomas Soome LZ4_NbCommonBytes(register U64 val) 392e499793eSToomas Soome { 393e499793eSToomas Soome #if defined(LZ4_BIG_ENDIAN) 394e499793eSToomas Soome #if !defined(LZ4_FORCE_SW_BITCOUNT) 395e499793eSToomas Soome return (__builtin_clzll(val) >> 3); 396e499793eSToomas Soome #else 397e499793eSToomas Soome int r; 398e499793eSToomas Soome if (!(val >> 32)) { 399e499793eSToomas Soome r = 4; 400e499793eSToomas Soome } else { 401e499793eSToomas Soome r = 0; 402e499793eSToomas Soome val >>= 32; 403e499793eSToomas Soome } 404e499793eSToomas Soome if (!(val >> 16)) { 405e499793eSToomas Soome r += 2; 406e499793eSToomas Soome val >>= 8; 407e499793eSToomas Soome } else { 408e499793eSToomas Soome val >>= 24; 409e499793eSToomas Soome } 410e499793eSToomas Soome r += (!val); 411e499793eSToomas Soome return (r); 412e499793eSToomas Soome #endif 413e499793eSToomas Soome #else 414e499793eSToomas Soome #if !defined(LZ4_FORCE_SW_BITCOUNT) 415e499793eSToomas Soome return (__builtin_ctzll(val) >> 3); 416e499793eSToomas Soome #else 417e499793eSToomas Soome static const int DeBruijnBytePos[64] = 418e499793eSToomas Soome { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 419e499793eSToomas Soome 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 420e499793eSToomas Soome 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 421e499793eSToomas Soome 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 422e499793eSToomas Soome }; 423e499793eSToomas Soome return DeBruijnBytePos[((U64) ((val & -val) * 0x0218A392CDABBD3F)) >> 424e499793eSToomas Soome 58]; 425e499793eSToomas Soome #endif 426e499793eSToomas Soome #endif 427e499793eSToomas Soome } 428e499793eSToomas Soome 429e499793eSToomas Soome #else 430e499793eSToomas Soome 431e499793eSToomas Soome static inline int 432e499793eSToomas Soome LZ4_NbCommonBytes(register U32 val) 433e499793eSToomas Soome { 434e499793eSToomas Soome #if defined(LZ4_BIG_ENDIAN) 435e499793eSToomas Soome #if !defined(LZ4_FORCE_SW_BITCOUNT) 436e499793eSToomas Soome return (__builtin_clz(val) >> 3); 437e499793eSToomas Soome #else 438e499793eSToomas Soome int r; 439e499793eSToomas Soome if (!(val >> 16)) { 440e499793eSToomas Soome r = 2; 441e499793eSToomas Soome val >>= 8; 442e499793eSToomas Soome } else { 443e499793eSToomas Soome r = 0; 444e499793eSToomas Soome val >>= 24; 445e499793eSToomas Soome } 446e499793eSToomas Soome r += (!val); 447e499793eSToomas Soome return (r); 448e499793eSToomas Soome #endif 449e499793eSToomas Soome #else 450e499793eSToomas Soome #if !defined(LZ4_FORCE_SW_BITCOUNT) 451e499793eSToomas Soome return (__builtin_ctz(val) >> 3); 452e499793eSToomas Soome #else 453e499793eSToomas Soome static const int DeBruijnBytePos[32] = { 454e499793eSToomas Soome 0, 0, 3, 0, 3, 1, 3, 0, 455e499793eSToomas Soome 3, 2, 2, 1, 3, 2, 0, 1, 456e499793eSToomas Soome 3, 3, 1, 2, 2, 2, 2, 0, 457e499793eSToomas Soome 3, 1, 2, 0, 1, 0, 1, 1 458e499793eSToomas Soome }; 459e499793eSToomas Soome return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 460e499793eSToomas Soome 27]; 461e499793eSToomas Soome #endif 462e499793eSToomas Soome #endif 463e499793eSToomas Soome } 464e499793eSToomas Soome 465e499793eSToomas Soome #endif 466e499793eSToomas Soome 467e499793eSToomas Soome /* Compression functions */ 468e499793eSToomas Soome 469e499793eSToomas Soome /*ARGSUSED*/ 470e499793eSToomas Soome static int 471e499793eSToomas Soome LZ4_compressCtx(void *ctx, const char *source, char *dest, int isize, 472e499793eSToomas Soome int osize) 473e499793eSToomas Soome { 474e499793eSToomas Soome #if HEAPMODE 475e499793eSToomas Soome struct refTables *srt = (struct refTables *)ctx; 476e499793eSToomas Soome HTYPE *HashTable = (HTYPE *) (srt->hashTable); 477e499793eSToomas Soome #else 478e499793eSToomas Soome HTYPE HashTable[HASHTABLESIZE] = { 0 }; 479e499793eSToomas Soome #endif 480e499793eSToomas Soome 481e499793eSToomas Soome const BYTE *ip = (const BYTE *) source; 482e499793eSToomas Soome INITBASE(base); 483e499793eSToomas Soome const BYTE *anchor = ip; 484e499793eSToomas Soome const BYTE *const iend = ip + isize; 485e499793eSToomas Soome const BYTE *const oend = (BYTE *) dest + osize; 486e499793eSToomas Soome const BYTE *const mflimit = iend - MFLIMIT; 487e499793eSToomas Soome #define matchlimit (iend - LASTLITERALS) 488e499793eSToomas Soome 489e499793eSToomas Soome BYTE *op = (BYTE *) dest; 490e499793eSToomas Soome 491e499793eSToomas Soome int len, length; 492e499793eSToomas Soome const int skipStrength = SKIPSTRENGTH; 493e499793eSToomas Soome U32 forwardH; 494e499793eSToomas Soome 495e499793eSToomas Soome 496e499793eSToomas Soome /* Init */ 497e499793eSToomas Soome if (isize < MINLENGTH) 498e499793eSToomas Soome goto _last_literals; 499e499793eSToomas Soome 500e499793eSToomas Soome /* First Byte */ 501e499793eSToomas Soome HashTable[LZ4_HASH_VALUE(ip)] = ip - base; 502e499793eSToomas Soome ip++; 503e499793eSToomas Soome forwardH = LZ4_HASH_VALUE(ip); 504e499793eSToomas Soome 505e499793eSToomas Soome /* Main Loop */ 506e499793eSToomas Soome for (;;) { 507e499793eSToomas Soome int findMatchAttempts = (1U << skipStrength) + 3; 508e499793eSToomas Soome const BYTE *forwardIp = ip; 509e499793eSToomas Soome const BYTE *ref; 510e499793eSToomas Soome BYTE *token; 511e499793eSToomas Soome 512e499793eSToomas Soome /* Find a match */ 513e499793eSToomas Soome do { 514e499793eSToomas Soome U32 h = forwardH; 515e499793eSToomas Soome int step = findMatchAttempts++ >> skipStrength; 516e499793eSToomas Soome ip = forwardIp; 517e499793eSToomas Soome forwardIp = ip + step; 518e499793eSToomas Soome 519e499793eSToomas Soome if unlikely(forwardIp > mflimit) { 520e499793eSToomas Soome goto _last_literals; 521e499793eSToomas Soome } 522e499793eSToomas Soome 523e499793eSToomas Soome forwardH = LZ4_HASH_VALUE(forwardIp); 524e499793eSToomas Soome ref = base + HashTable[h]; 525e499793eSToomas Soome HashTable[h] = ip - base; 526e499793eSToomas Soome 527e499793eSToomas Soome } while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip))); 528e499793eSToomas Soome 529e499793eSToomas Soome /* Catch up */ 530e499793eSToomas Soome while ((ip > anchor) && (ref > (const BYTE *) source) && 531e499793eSToomas Soome unlikely(ip[-1] == ref[-1])) { 532e499793eSToomas Soome ip--; 533e499793eSToomas Soome ref--; 534e499793eSToomas Soome } 535e499793eSToomas Soome 536e499793eSToomas Soome /* Encode Literal length */ 537e499793eSToomas Soome length = ip - anchor; 538e499793eSToomas Soome token = op++; 539e499793eSToomas Soome 540e499793eSToomas Soome /* Check output limit */ 541e499793eSToomas Soome if unlikely(op + length + (2 + 1 + LASTLITERALS) + 542e499793eSToomas Soome (length >> 8) > oend) 543e499793eSToomas Soome return (0); 544e499793eSToomas Soome 545e499793eSToomas Soome if (length >= (int)RUN_MASK) { 546e499793eSToomas Soome *token = (RUN_MASK << ML_BITS); 547e499793eSToomas Soome len = length - RUN_MASK; 548e499793eSToomas Soome for (; len > 254; len -= 255) 549e499793eSToomas Soome *op++ = 255; 550e499793eSToomas Soome *op++ = (BYTE)len; 551e499793eSToomas Soome } else 552e499793eSToomas Soome *token = (length << ML_BITS); 553e499793eSToomas Soome 554e499793eSToomas Soome /* Copy Literals */ 555e499793eSToomas Soome LZ4_BLINDCOPY(anchor, op, length); 556e499793eSToomas Soome 557e499793eSToomas Soome _next_match: 558e499793eSToomas Soome /* Encode Offset */ 559e499793eSToomas Soome LZ4_WRITE_LITTLEENDIAN_16(op, ip - ref); 560e499793eSToomas Soome 561e499793eSToomas Soome /* Start Counting */ 562e499793eSToomas Soome ip += MINMATCH; 563e499793eSToomas Soome ref += MINMATCH; /* MinMatch verified */ 564e499793eSToomas Soome anchor = ip; 565e499793eSToomas Soome while likely(ip < matchlimit - (STEPSIZE - 1)) { 566e499793eSToomas Soome UARCH diff = AARCH(ref) ^ AARCH(ip); 567e499793eSToomas Soome if (!diff) { 568e499793eSToomas Soome ip += STEPSIZE; 569e499793eSToomas Soome ref += STEPSIZE; 570e499793eSToomas Soome continue; 571e499793eSToomas Soome } 572e499793eSToomas Soome ip += LZ4_NbCommonBytes(diff); 573e499793eSToomas Soome goto _endCount; 574e499793eSToomas Soome } 575e499793eSToomas Soome #if LZ4_ARCH64 576e499793eSToomas Soome if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) { 577e499793eSToomas Soome ip += 4; 578e499793eSToomas Soome ref += 4; 579e499793eSToomas Soome } 580e499793eSToomas Soome #endif 581e499793eSToomas Soome if ((ip < (matchlimit - 1)) && (A16(ref) == A16(ip))) { 582e499793eSToomas Soome ip += 2; 583e499793eSToomas Soome ref += 2; 584e499793eSToomas Soome } 585e499793eSToomas Soome if ((ip < matchlimit) && (*ref == *ip)) 586e499793eSToomas Soome ip++; 587e499793eSToomas Soome _endCount: 588e499793eSToomas Soome 589e499793eSToomas Soome /* Encode MatchLength */ 590e499793eSToomas Soome len = (ip - anchor); 591e499793eSToomas Soome /* Check output limit */ 592e499793eSToomas Soome if unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend) 593e499793eSToomas Soome return (0); 594e499793eSToomas Soome if (len >= (int)ML_MASK) { 595e499793eSToomas Soome *token += ML_MASK; 596e499793eSToomas Soome len -= ML_MASK; 597e499793eSToomas Soome for (; len > 509; len -= 510) { 598e499793eSToomas Soome *op++ = 255; 599e499793eSToomas Soome *op++ = 255; 600e499793eSToomas Soome } 601e499793eSToomas Soome if (len > 254) { 602e499793eSToomas Soome len -= 255; 603e499793eSToomas Soome *op++ = 255; 604e499793eSToomas Soome } 605e499793eSToomas Soome *op++ = (BYTE)len; 606e499793eSToomas Soome } else 607e499793eSToomas Soome *token += len; 608e499793eSToomas Soome 609e499793eSToomas Soome /* Test end of chunk */ 610e499793eSToomas Soome if (ip > mflimit) { 611e499793eSToomas Soome anchor = ip; 612e499793eSToomas Soome break; 613e499793eSToomas Soome } 614e499793eSToomas Soome /* Fill table */ 615e499793eSToomas Soome HashTable[LZ4_HASH_VALUE(ip - 2)] = ip - 2 - base; 616e499793eSToomas Soome 617e499793eSToomas Soome /* Test next position */ 618e499793eSToomas Soome ref = base + HashTable[LZ4_HASH_VALUE(ip)]; 619e499793eSToomas Soome HashTable[LZ4_HASH_VALUE(ip)] = ip - base; 620e499793eSToomas Soome if ((ref > ip - (MAX_DISTANCE + 1)) && (A32(ref) == A32(ip))) { 621e499793eSToomas Soome token = op++; 622e499793eSToomas Soome *token = 0; 623e499793eSToomas Soome goto _next_match; 624e499793eSToomas Soome } 625e499793eSToomas Soome /* Prepare next loop */ 626e499793eSToomas Soome anchor = ip++; 627e499793eSToomas Soome forwardH = LZ4_HASH_VALUE(ip); 628e499793eSToomas Soome } 629e499793eSToomas Soome 630e499793eSToomas Soome _last_literals: 631e499793eSToomas Soome /* Encode Last Literals */ 632e499793eSToomas Soome { 633e499793eSToomas Soome int lastRun = iend - anchor; 634e499793eSToomas Soome if (op + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > 635e499793eSToomas Soome oend) 636e499793eSToomas Soome return (0); 637e499793eSToomas Soome if (lastRun >= (int)RUN_MASK) { 638e499793eSToomas Soome *op++ = (RUN_MASK << ML_BITS); 639e499793eSToomas Soome lastRun -= RUN_MASK; 640e499793eSToomas Soome for (; lastRun > 254; lastRun -= 255) { 641e499793eSToomas Soome *op++ = 255; 642e499793eSToomas Soome } 643e499793eSToomas Soome *op++ = (BYTE)lastRun; 644e499793eSToomas Soome } else 645e499793eSToomas Soome *op++ = (lastRun << ML_BITS); 646e499793eSToomas Soome (void) memcpy(op, anchor, iend - anchor); 647e499793eSToomas Soome op += iend - anchor; 648e499793eSToomas Soome } 649e499793eSToomas Soome 650e499793eSToomas Soome /* End */ 651e499793eSToomas Soome return (int)(((char *)op) - dest); 652e499793eSToomas Soome } 653e499793eSToomas Soome 654e499793eSToomas Soome 655e499793eSToomas Soome 656e499793eSToomas Soome /* Note : this function is valid only if isize < LZ4_64KLIMIT */ 657e499793eSToomas Soome #define LZ4_64KLIMIT ((1 << 16) + (MFLIMIT - 1)) 658e499793eSToomas Soome #define HASHLOG64K (HASH_LOG + 1) 659e499793eSToomas Soome #define HASH64KTABLESIZE (1U << HASHLOG64K) 660e499793eSToomas Soome #define LZ4_HASH64K_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8) - \ 661e499793eSToomas Soome HASHLOG64K)) 662e499793eSToomas Soome #define LZ4_HASH64K_VALUE(p) LZ4_HASH64K_FUNCTION(A32(p)) 663e499793eSToomas Soome 664e499793eSToomas Soome /*ARGSUSED*/ 665e499793eSToomas Soome static int 666e499793eSToomas Soome LZ4_compress64kCtx(void *ctx, const char *source, char *dest, int isize, 667e499793eSToomas Soome int osize) 668e499793eSToomas Soome { 669e499793eSToomas Soome #if HEAPMODE 670e499793eSToomas Soome struct refTables *srt = (struct refTables *)ctx; 671e499793eSToomas Soome U16 *HashTable = (U16 *) (srt->hashTable); 672e499793eSToomas Soome #else 673e499793eSToomas Soome U16 HashTable[HASH64KTABLESIZE] = { 0 }; 674e499793eSToomas Soome #endif 675e499793eSToomas Soome 676e499793eSToomas Soome const BYTE *ip = (const BYTE *) source; 677e499793eSToomas Soome const BYTE *anchor = ip; 678e499793eSToomas Soome const BYTE *const base = ip; 679e499793eSToomas Soome const BYTE *const iend = ip + isize; 680e499793eSToomas Soome const BYTE *const oend = (BYTE *) dest + osize; 681e499793eSToomas Soome const BYTE *const mflimit = iend - MFLIMIT; 682e499793eSToomas Soome #define matchlimit (iend - LASTLITERALS) 683e499793eSToomas Soome 684e499793eSToomas Soome BYTE *op = (BYTE *) dest; 685e499793eSToomas Soome 686e499793eSToomas Soome int len, length; 687e499793eSToomas Soome const int skipStrength = SKIPSTRENGTH; 688e499793eSToomas Soome U32 forwardH; 689e499793eSToomas Soome 690e499793eSToomas Soome /* Init */ 691e499793eSToomas Soome if (isize < MINLENGTH) 692e499793eSToomas Soome goto _last_literals; 693e499793eSToomas Soome 694e499793eSToomas Soome /* First Byte */ 695e499793eSToomas Soome ip++; 696e499793eSToomas Soome forwardH = LZ4_HASH64K_VALUE(ip); 697e499793eSToomas Soome 698e499793eSToomas Soome /* Main Loop */ 699e499793eSToomas Soome for (;;) { 700e499793eSToomas Soome int findMatchAttempts = (1U << skipStrength) + 3; 701e499793eSToomas Soome const BYTE *forwardIp = ip; 702e499793eSToomas Soome const BYTE *ref; 703e499793eSToomas Soome BYTE *token; 704e499793eSToomas Soome 705e499793eSToomas Soome /* Find a match */ 706e499793eSToomas Soome do { 707e499793eSToomas Soome U32 h = forwardH; 708e499793eSToomas Soome int step = findMatchAttempts++ >> skipStrength; 709e499793eSToomas Soome ip = forwardIp; 710e499793eSToomas Soome forwardIp = ip + step; 711e499793eSToomas Soome 712e499793eSToomas Soome if (forwardIp > mflimit) { 713e499793eSToomas Soome goto _last_literals; 714e499793eSToomas Soome } 715e499793eSToomas Soome 716e499793eSToomas Soome forwardH = LZ4_HASH64K_VALUE(forwardIp); 717e499793eSToomas Soome ref = base + HashTable[h]; 718e499793eSToomas Soome HashTable[h] = ip - base; 719e499793eSToomas Soome 720e499793eSToomas Soome } while (A32(ref) != A32(ip)); 721e499793eSToomas Soome 722e499793eSToomas Soome /* Catch up */ 723e499793eSToomas Soome while ((ip > anchor) && (ref > (const BYTE *) source) && 724e499793eSToomas Soome (ip[-1] == ref[-1])) { 725e499793eSToomas Soome ip--; 726e499793eSToomas Soome ref--; 727e499793eSToomas Soome } 728e499793eSToomas Soome 729e499793eSToomas Soome /* Encode Literal length */ 730e499793eSToomas Soome length = ip - anchor; 731e499793eSToomas Soome token = op++; 732e499793eSToomas Soome 733e499793eSToomas Soome /* Check output limit */ 734e499793eSToomas Soome if unlikely(op + length + (2 + 1 + LASTLITERALS) + 735e499793eSToomas Soome (length >> 8) > oend) 736e499793eSToomas Soome return (0); 737e499793eSToomas Soome 738e499793eSToomas Soome if (length >= (int)RUN_MASK) { 739e499793eSToomas Soome *token = (RUN_MASK << ML_BITS); 740e499793eSToomas Soome len = length - RUN_MASK; 741e499793eSToomas Soome for (; len > 254; len -= 255) 742e499793eSToomas Soome *op++ = 255; 743e499793eSToomas Soome *op++ = (BYTE)len; 744e499793eSToomas Soome } else 745e499793eSToomas Soome *token = (length << ML_BITS); 746e499793eSToomas Soome 747e499793eSToomas Soome /* Copy Literals */ 748e499793eSToomas Soome LZ4_BLINDCOPY(anchor, op, length); 749e499793eSToomas Soome 750e499793eSToomas Soome _next_match: 751e499793eSToomas Soome /* Encode Offset */ 752e499793eSToomas Soome LZ4_WRITE_LITTLEENDIAN_16(op, ip - ref); 753e499793eSToomas Soome 754e499793eSToomas Soome /* Start Counting */ 755e499793eSToomas Soome ip += MINMATCH; 756e499793eSToomas Soome ref += MINMATCH; /* MinMatch verified */ 757e499793eSToomas Soome anchor = ip; 758e499793eSToomas Soome while (ip < matchlimit - (STEPSIZE - 1)) { 759e499793eSToomas Soome UARCH diff = AARCH(ref) ^ AARCH(ip); 760e499793eSToomas Soome if (!diff) { 761e499793eSToomas Soome ip += STEPSIZE; 762e499793eSToomas Soome ref += STEPSIZE; 763e499793eSToomas Soome continue; 764e499793eSToomas Soome } 765e499793eSToomas Soome ip += LZ4_NbCommonBytes(diff); 766e499793eSToomas Soome goto _endCount; 767e499793eSToomas Soome } 768e499793eSToomas Soome #if LZ4_ARCH64 769e499793eSToomas Soome if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) { 770e499793eSToomas Soome ip += 4; 771e499793eSToomas Soome ref += 4; 772e499793eSToomas Soome } 773e499793eSToomas Soome #endif 774e499793eSToomas Soome if ((ip < (matchlimit - 1)) && (A16(ref) == A16(ip))) { 775e499793eSToomas Soome ip += 2; 776e499793eSToomas Soome ref += 2; 777e499793eSToomas Soome } 778e499793eSToomas Soome if ((ip < matchlimit) && (*ref == *ip)) 779e499793eSToomas Soome ip++; 780e499793eSToomas Soome _endCount: 781e499793eSToomas Soome 782e499793eSToomas Soome /* Encode MatchLength */ 783e499793eSToomas Soome len = (ip - anchor); 784e499793eSToomas Soome /* Check output limit */ 785e499793eSToomas Soome if unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend) 786e499793eSToomas Soome return (0); 787e499793eSToomas Soome if (len >= (int)ML_MASK) { 788e499793eSToomas Soome *token += ML_MASK; 789e499793eSToomas Soome len -= ML_MASK; 790e499793eSToomas Soome for (; len > 509; len -= 510) { 791e499793eSToomas Soome *op++ = 255; 792e499793eSToomas Soome *op++ = 255; 793e499793eSToomas Soome } 794e499793eSToomas Soome if (len > 254) { 795e499793eSToomas Soome len -= 255; 796e499793eSToomas Soome *op++ = 255; 797e499793eSToomas Soome } 798e499793eSToomas Soome *op++ = (BYTE)len; 799e499793eSToomas Soome } else 800e499793eSToomas Soome *token += len; 801e499793eSToomas Soome 802e499793eSToomas Soome /* Test end of chunk */ 803e499793eSToomas Soome if (ip > mflimit) { 804e499793eSToomas Soome anchor = ip; 805e499793eSToomas Soome break; 806e499793eSToomas Soome } 807e499793eSToomas Soome /* Fill table */ 808e499793eSToomas Soome HashTable[LZ4_HASH64K_VALUE(ip - 2)] = ip - 2 - base; 809e499793eSToomas Soome 810e499793eSToomas Soome /* Test next position */ 811e499793eSToomas Soome ref = base + HashTable[LZ4_HASH64K_VALUE(ip)]; 812e499793eSToomas Soome HashTable[LZ4_HASH64K_VALUE(ip)] = ip - base; 813e499793eSToomas Soome if (A32(ref) == A32(ip)) { 814e499793eSToomas Soome token = op++; 815e499793eSToomas Soome *token = 0; 816e499793eSToomas Soome goto _next_match; 817e499793eSToomas Soome } 818e499793eSToomas Soome /* Prepare next loop */ 819e499793eSToomas Soome anchor = ip++; 820e499793eSToomas Soome forwardH = LZ4_HASH64K_VALUE(ip); 821e499793eSToomas Soome } 822e499793eSToomas Soome 823e499793eSToomas Soome _last_literals: 824e499793eSToomas Soome /* Encode Last Literals */ 825e499793eSToomas Soome { 826e499793eSToomas Soome int lastRun = iend - anchor; 827e499793eSToomas Soome if (op + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > 828e499793eSToomas Soome oend) 829e499793eSToomas Soome return (0); 830e499793eSToomas Soome if (lastRun >= (int)RUN_MASK) { 831e499793eSToomas Soome *op++ = (RUN_MASK << ML_BITS); 832e499793eSToomas Soome lastRun -= RUN_MASK; 833e499793eSToomas Soome for (; lastRun > 254; lastRun -= 255) 834e499793eSToomas Soome *op++ = 255; 835e499793eSToomas Soome *op++ = (BYTE)lastRun; 836e499793eSToomas Soome } else 837e499793eSToomas Soome *op++ = (lastRun << ML_BITS); 838e499793eSToomas Soome (void) memcpy(op, anchor, iend - anchor); 839e499793eSToomas Soome op += iend - anchor; 840e499793eSToomas Soome } 841e499793eSToomas Soome 842e499793eSToomas Soome /* End */ 843e499793eSToomas Soome return (int)(((char *)op) - dest); 844e499793eSToomas Soome } 845e499793eSToomas Soome 846e499793eSToomas Soome static int 847e499793eSToomas Soome real_LZ4_compress(const char *source, char *dest, int isize, int osize) 848e499793eSToomas Soome { 849e499793eSToomas Soome #if HEAPMODE 85024e1a7acSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL) 851e499793eSToomas Soome void *ctx = kmem_cache_alloc(lz4_ctx_cache, KM_NOSLEEP); 852e499793eSToomas Soome #else 853*22ed31c2SToomas Soome void *ctx = calloc(1, sizeof(struct refTables)); 854e499793eSToomas Soome #endif 855e499793eSToomas Soome int result; 856e499793eSToomas Soome 857e499793eSToomas Soome /* 858e499793eSToomas Soome * out of kernel memory, gently fall through - this will disable 859e499793eSToomas Soome * compression in zio_compress_data 860e499793eSToomas Soome */ 861e499793eSToomas Soome if (ctx == NULL) 862e499793eSToomas Soome return (0); 863e499793eSToomas Soome 864e499793eSToomas Soome bzero(ctx, sizeof(struct refTables)); 865e499793eSToomas Soome if (isize < LZ4_64KLIMIT) 866e499793eSToomas Soome result = LZ4_compress64kCtx(ctx, source, dest, isize, osize); 867e499793eSToomas Soome else 868e499793eSToomas Soome result = LZ4_compressCtx(ctx, source, dest, isize, osize); 869e499793eSToomas Soome 87024e1a7acSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL) 871e499793eSToomas Soome kmem_cache_free(lz4_ctx_cache, ctx); 872e499793eSToomas Soome #else 873e499793eSToomas Soome free(ctx); 874e499793eSToomas Soome #endif 875e499793eSToomas Soome return (result); 876e499793eSToomas Soome #else 877e499793eSToomas Soome if (isize < (int)LZ4_64KLIMIT) 878e499793eSToomas Soome return (LZ4_compress64kCtx(NULL, source, dest, isize, osize)); 879e499793eSToomas Soome return (LZ4_compressCtx(NULL, source, dest, isize, osize)); 880e499793eSToomas Soome #endif 881e499793eSToomas Soome } 882e499793eSToomas Soome 883e499793eSToomas Soome /* Decompression functions */ 884e499793eSToomas Soome 885e499793eSToomas Soome /* 886e499793eSToomas Soome * Note: The decoding function LZ4_uncompress_unknownOutputSize() is safe 887e499793eSToomas Soome * against "buffer overflow" attack type. It will never write nor 888e499793eSToomas Soome * read outside of the provided output buffers. 889e499793eSToomas Soome * LZ4_uncompress_unknownOutputSize() also insures that it will never 890e499793eSToomas Soome * read outside of the input buffer. A corrupted input will produce 891e499793eSToomas Soome * an error result, a negative int, indicating the position of the 892e499793eSToomas Soome * error within input stream. 893e499793eSToomas Soome */ 894e499793eSToomas Soome 895e499793eSToomas Soome static int 896e499793eSToomas Soome LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, 897e499793eSToomas Soome int maxOutputSize) 898e499793eSToomas Soome { 899e499793eSToomas Soome /* Local Variables */ 900e499793eSToomas Soome const BYTE *restrict ip = (const BYTE *) source; 901e499793eSToomas Soome const BYTE *const iend = ip + isize; 902e499793eSToomas Soome const BYTE *ref; 903e499793eSToomas Soome 904e499793eSToomas Soome BYTE *op = (BYTE *) dest; 905e499793eSToomas Soome BYTE *const oend = op + maxOutputSize; 906e499793eSToomas Soome BYTE *cpy; 907e499793eSToomas Soome 908e499793eSToomas Soome size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; 909e499793eSToomas Soome #if LZ4_ARCH64 910e499793eSToomas Soome size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; 911e499793eSToomas Soome #endif 912e499793eSToomas Soome 913e499793eSToomas Soome /* Main Loop */ 914e499793eSToomas Soome while (ip < iend) { 915e499793eSToomas Soome unsigned token; 916e499793eSToomas Soome size_t length; 917e499793eSToomas Soome 918e499793eSToomas Soome /* get runlength */ 919e499793eSToomas Soome token = *ip++; 920e499793eSToomas Soome if ((length = (token >> ML_BITS)) == RUN_MASK) { 921e499793eSToomas Soome int s = 255; 922e499793eSToomas Soome while ((ip < iend) && (s == 255)) { 923e499793eSToomas Soome s = *ip++; 924e499793eSToomas Soome length += s; 925e499793eSToomas Soome } 926e499793eSToomas Soome } 927e499793eSToomas Soome /* copy literals */ 928e499793eSToomas Soome cpy = op + length; 929e499793eSToomas Soome /* CORNER-CASE: cpy might overflow. */ 930e499793eSToomas Soome if (cpy < op) 931e499793eSToomas Soome goto _output_error; /* cpy was overflowed, bail! */ 932e499793eSToomas Soome if ((cpy > oend - COPYLENGTH) || 933e499793eSToomas Soome (ip + length > iend - COPYLENGTH)) { 934e499793eSToomas Soome if (cpy > oend) 935e499793eSToomas Soome /* Error: writes beyond output buffer */ 936e499793eSToomas Soome goto _output_error; 937e499793eSToomas Soome if (ip + length != iend) 938e499793eSToomas Soome /* 939e499793eSToomas Soome * Error: LZ4 format requires to consume all 940e499793eSToomas Soome * input at this stage 941e499793eSToomas Soome */ 942e499793eSToomas Soome goto _output_error; 943e499793eSToomas Soome (void) memcpy(op, ip, length); 944e499793eSToomas Soome op += length; 945e499793eSToomas Soome /* Necessarily EOF, due to parsing restrictions */ 946e499793eSToomas Soome break; 947e499793eSToomas Soome } 948e499793eSToomas Soome LZ4_WILDCOPY(ip, op, cpy); 949e499793eSToomas Soome ip -= (op - cpy); 950e499793eSToomas Soome op = cpy; 951e499793eSToomas Soome 952e499793eSToomas Soome /* get offset */ 953e499793eSToomas Soome LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); 954e499793eSToomas Soome ip += 2; 955e499793eSToomas Soome if (ref < (BYTE * const) dest) 956e499793eSToomas Soome /* 957e499793eSToomas Soome * Error: offset creates reference outside of 958e499793eSToomas Soome * destination buffer 959e499793eSToomas Soome */ 960e499793eSToomas Soome goto _output_error; 961e499793eSToomas Soome 962e499793eSToomas Soome /* get matchlength */ 963e499793eSToomas Soome if ((length = (token & ML_MASK)) == ML_MASK) { 964e499793eSToomas Soome while (ip < iend) { 965e499793eSToomas Soome int s = *ip++; 966e499793eSToomas Soome length += s; 967e499793eSToomas Soome if (s == 255) 968e499793eSToomas Soome continue; 969e499793eSToomas Soome break; 970e499793eSToomas Soome } 971e499793eSToomas Soome } 972e499793eSToomas Soome /* copy repeated sequence */ 973e499793eSToomas Soome if unlikely(op - ref < STEPSIZE) { 974e499793eSToomas Soome #if LZ4_ARCH64 975e499793eSToomas Soome size_t dec64 = dec64table[op-ref]; 976e499793eSToomas Soome #else 977e499793eSToomas Soome const int dec64 = 0; 978e499793eSToomas Soome #endif 979e499793eSToomas Soome op[0] = ref[0]; 980e499793eSToomas Soome op[1] = ref[1]; 981e499793eSToomas Soome op[2] = ref[2]; 982e499793eSToomas Soome op[3] = ref[3]; 983e499793eSToomas Soome op += 4; 984e499793eSToomas Soome ref += 4; 985e499793eSToomas Soome ref -= dec32table[op-ref]; 986e499793eSToomas Soome A32(op) = A32(ref); 987e499793eSToomas Soome op += STEPSIZE - 4; 988e499793eSToomas Soome ref -= dec64; 989e499793eSToomas Soome } else { 990e499793eSToomas Soome LZ4_COPYSTEP(ref, op); 991e499793eSToomas Soome } 992e499793eSToomas Soome cpy = op + length - (STEPSIZE - 4); 993e499793eSToomas Soome if (cpy > oend - COPYLENGTH) { 994e499793eSToomas Soome if (cpy > oend) 995e499793eSToomas Soome /* 996e499793eSToomas Soome * Error: request to write outside of 997e499793eSToomas Soome * destination buffer 998e499793eSToomas Soome */ 999e499793eSToomas Soome goto _output_error; 1000e499793eSToomas Soome LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); 1001e499793eSToomas Soome while (op < cpy) 1002e499793eSToomas Soome *op++ = *ref++; 1003e499793eSToomas Soome op = cpy; 1004e499793eSToomas Soome if (op == oend) 1005e499793eSToomas Soome /* 1006e499793eSToomas Soome * Check EOF (should never happen, since 1007e499793eSToomas Soome * last 5 bytes are supposed to be literals) 1008e499793eSToomas Soome */ 1009e499793eSToomas Soome goto _output_error; 1010e499793eSToomas Soome continue; 1011e499793eSToomas Soome } 1012e499793eSToomas Soome LZ4_SECURECOPY(ref, op, cpy); 1013e499793eSToomas Soome op = cpy; /* correction */ 1014e499793eSToomas Soome } 1015e499793eSToomas Soome 1016e499793eSToomas Soome /* end of decoding */ 1017e499793eSToomas Soome return (int)(((char *)op) - dest); 1018e499793eSToomas Soome 1019e499793eSToomas Soome /* write overflow error detected */ 1020e499793eSToomas Soome _output_error: 1021e499793eSToomas Soome return (int)(-(((const char *)ip) - source)); 1022e499793eSToomas Soome } 1023e499793eSToomas Soome 102424e1a7acSToomas Soome #if defined(_KERNEL) || defined(_FAKE_KERNEL) 1025e499793eSToomas Soome extern void 1026e499793eSToomas Soome lz4_init(void) 1027e499793eSToomas Soome { 1028e499793eSToomas Soome 1029e499793eSToomas Soome #if HEAPMODE 1030e499793eSToomas Soome lz4_ctx_cache = kmem_cache_create("lz4_ctx", sizeof(struct refTables), 1031e499793eSToomas Soome 0, NULL, NULL, NULL, NULL, NULL, 0); 1032e499793eSToomas Soome #endif 1033e499793eSToomas Soome } 1034e499793eSToomas Soome 1035e499793eSToomas Soome extern void 1036e499793eSToomas Soome lz4_fini(void) 1037e499793eSToomas Soome { 1038e499793eSToomas Soome 1039e499793eSToomas Soome #if HEAPMODE 1040e499793eSToomas Soome kmem_cache_destroy(lz4_ctx_cache); 1041e499793eSToomas Soome #endif 1042e499793eSToomas Soome } 104324e1a7acSToomas Soome #endif /* _KERNEL || _FAKE_KERNEL */ 1044