From b6b01071f56e4185ab08fe0ef0194a171f395bec Mon Sep 17 00:00:00 2001 From: "Phong X. Nguyen" Date: Tue, 2 Jun 2026 18:42:39 +0000 Subject: [PATCH] Update FastLZ to b1342da --- lib/fastlz/README.md | 64 ++++--- lib/fastlz/fastlz.cc | 442 +++++++++++++++---------------------------- lib/fastlz/fastlz.h | 14 +- 3 files changed, 208 insertions(+), 312 deletions(-) diff --git a/lib/fastlz/README.md b/lib/fastlz/README.md index 6ec851ac909..9d7bf696b5b 100644 --- a/lib/fastlz/README.md +++ b/lib/fastlz/README.md @@ -34,31 +34,49 @@ For [Vcpkg](https://github.com/microsoft/vcpkg) users, FastLZ is [already availa A simple file compressor called `6pack` is included as an example on how to use FastLZ. The corresponding decompressor is `6unpack`. -FastLZ supports any standard-conforming ANSI C/C90 compiler, including the popular ones such as GCC, Clang, Intel C++ Compiler, Visual Studio and even Tiny CC. FastLZ works well on a number of architectures (32-bit and 64-bit, big endian and little endian), from Intel/AMD, ARM, and MIPS. +FastLZ supports any standard-conforming ANSI C/C90 compiler, including the popular ones such as [GCC](https://gcc.gnu.org/), [Clang](https://clang.llvm.org/), [Visual Studio](https://visualstudio.microsoft.com/vs/features/cplusplus/), and even [Tiny CC](https://bellard.org/tcc/). FastLZ works well on a number of architectures (32-bit and 64-bit, big endian and little endian), from Intel/AMD, PowerPC, System z, ARM, MIPS, and RISC-V. The continuous integration system runs an extensive set of compression-decompression round trips on the following systems: For more details, check the corresponding [GitHub Actions build logs](https://github.com/ariya/FastLZ/actions). -| | | | | -|--------------|---------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| -| **amd64** | **Linux** | **Windows** | **macOS** | -| GCC | ![amd64_linux_gcc](https://github.com/ariya/FastLZ/workflows/amd64_linux_gcc/badge.svg) | ![amd64_windows_gcc](https://github.com/ariya/FastLZ/workflows/amd64_windows_gcc/badge.svg) | ![amd64_macos_gcc](https://github.com/ariya/FastLZ/workflows/amd64_macos_gcc/badge.svg) | -| Clang | ![amd64_linux_clang](https://github.com/ariya/FastLZ/workflows/amd64_linux_clang/badge.svg) | ![amd64_windows_clang](https://github.com/ariya/FastLZ/workflows/amd64_windows_clang/badge.svg) | ![amd64_macos_clang](https://github.com/ariya/FastLZ/workflows/amd64_macos_clang/badge.svg) | -| Intel CC | ![amd64_linux_icc](https://github.com/ariya/FastLZ/workflows/amd64_linux_icc/badge.svg) | | | -| TinyCC | ![amd64_linux_tcc](https://github.com/ariya/FastLZ/workflows/amd64_linux_tcc/badge.svg) | | | | -| VS 2017 | | ![amd64_windows_vs2017](https://github.com/ariya/FastLZ/workflows/amd64_windows_vs2017/badge.svg) | | -| VS 2019 | | ![amd64_windows_vs2019](https://github.com/ariya/FastLZ/workflows/amd64_windows_vs2019/badge.svg) | | -| **i686** | **Linux** | **Windows** | **macOS** | -| GCC | ![i686_linux_gcc](https://github.com/ariya/FastLZ/workflows/i686_linux_gcc/badge.svg) | | | -| Clang | ![i686_linux_clang](https://github.com/ariya/FastLZ/workflows/i686_linux_clang/badge.svg) | | | -| VS 2017 | | ![i686_windows_vs2017](https://github.com/ariya/FastLZ/workflows/i686_windows_vs2017/badge.svg) | | -| VS 2019 | | ![i686_windows_vs2019](https://github.com/ariya/FastLZ/workflows/i686_windows_vs2019/badge.svg) | | -| **arm64** | **Linux** | **Windows** | **macOS** | -| GCC | ![arm64_linux_gcc](https://github.com/ariya/FastLZ/workflows/arm64_linux_gcc/badge.svg) | | | -| **mips64** | **Linux** | **Windows** | **macOS** | -| GCC | ![mips64_linux_gcc](https://github.com/ariya/FastLZ/workflows/mips64_linux_gcc/badge.svg) | | | +| | | | | +|----------------------|--------------------------------------------------------------------------------------------------------:|--------------------------------------------------------------------------------------------------:|--------------------------------------------------------------------------------------------:| +| **amd64** | **Linux** | **Windows** | **macOS** | +| GCC | ![amd64_linux_gcc](https://github.com/ariya/FastLZ/workflows/amd64_linux_gcc/badge.svg) | ![amd64_windows_gcc](https://github.com/ariya/FastLZ/workflows/amd64_windows_gcc/badge.svg) | ![amd64_macos_gcc](https://github.com/ariya/FastLZ/workflows/amd64_macos_gcc/badge.svg) | +| Clang | ![amd64_linux_clang](https://github.com/ariya/FastLZ/workflows/amd64_linux_clang/badge.svg) | ![amd64_windows_clang](https://github.com/ariya/FastLZ/workflows/amd64_windows_clang/badge.svg) | ![amd64_macos_clang](https://github.com/ariya/FastLZ/workflows/amd64_macos_clang/badge.svg) | +| TinyCC | ![amd64_linux_tcc](https://github.com/ariya/FastLZ/workflows/amd64_linux_tcc/badge.svg) | ![amd64_windows_tcc](https://github.com/ariya/FastLZ/workflows/amd64_windows_tcc/badge.svg) | | +| VS 2019 | | ![amd64_windows_vs2019](https://github.com/ariya/FastLZ/workflows/amd64_windows_vs2019/badge.svg) | | +| **i686** | **Linux** | **Windows** | **macOS** | +| GCC | ![i686_linux_gcc](https://github.com/ariya/FastLZ/workflows/i686_linux_gcc/badge.svg) | | | +| Clang | ![i686_linux_clang](https://github.com/ariya/FastLZ/workflows/i686_linux_clang/badge.svg) | | | +| TinyCC | | ![i686_windows_tcc](https://github.com/ariya/FastLZ/workflows/i686_windows_tcc/badge.svg) | | +| VS 2019 | | ![i686_windows_vs2019](https://github.com/ariya/FastLZ/workflows/i686_windows_vs2019/badge.svg) | | +| **i586** | **Linux** | **DOS** | | +| GCC | | ![i586_dos_gcc_cross](https://github.com/ariya/FastLZ/workflows/i586_dos_gcc_cross/badge.svg) | | +| | **Linux** | | | +| **powerpc** | | | | +| GCC | ![powerpc_linux_gcc](https://github.com/ariya/FastLZ/workflows/powerpc_linux_gcc/badge.svg) | | | +| **ppc64(le)** | | | | +| GCC | ![ppc64_linux_gcc](https://github.com/ariya/FastLZ/workflows/ppc64_linux_gcc/badge.svg) | | | +| GCC | ![ppc64le_linux_gcc](https://github.com/ariya/FastLZ/workflows/ppc64le_linux_gcc/badge.svg) | | | +| **s390x** | | | | +| GCC | ![s390x_linux_gcc](https://github.com/ariya/FastLZ/workflows/s390x_linux_gcc/badge.svg) | | | +| **armhf** | | | | +| GCC | ![armhf_linux_gcc](https://github.com/ariya/FastLZ/workflows/armhf_linux_gcc/badge.svg) | | | +| **arm64** | | | | +| GCC | ![arm64_linux_gcc](https://github.com/ariya/FastLZ/workflows/arm64_linux_gcc/badge.svg) | | | +| **mips(el)** | | | | +| GCC | ![mipsel_linux_gcc](https://github.com/ariya/FastLZ/workflows/mipsel_linux_gcc/badge.svg) | | | +| GCC | ![mips_linux_gcc](https://github.com/ariya/FastLZ/workflows/mips_linux_gcc/badge.svg) | | | +| **mips64(el)** | | | | +| GCC | ![mips64el_linux_gcc](https://github.com/ariya/FastLZ/workflows/mips64el_linux_gcc/badge.svg) | | | +| GCC | ![mips64_linux_gcc](https://github.com/ariya/FastLZ/workflows/mips64_linux_gcc/badge.svg) | | | +| **riscv** | | | | +| GCC | ![riscv_linux_gcc](https://github.com/ariya/FastLZ/workflows/riscv_linux_gcc/badge.svg) | | | +| **riscv64** | | | | +| GCC | ![riscv64_linux_gcc](https://github.com/ariya/FastLZ/workflows/riscv64_linux_gcc/badge.svg) | | | @@ -66,7 +84,7 @@ For more details, check the corresponding [GitHub Actions build logs](https://gi Let us assume that FastLZ compresses an array of bytes, called the _uncompressed block_, into another array of bytes, called the _compressed block_. To understand what will be stored in the compressed block, it is illustrative to demonstrate how FastLZ will _decompress_ the block to retrieve the original uncompressed block. -The first 5-bit of the block, i.e. the 5 most-significant bits of the first byte, is the **block tag**. Currently the block tag determines the compression level used to produce the compressed block. +The first 3-bit of the block, i.e. the 3 most-significant bits of the first byte, is the **block tag**. Currently the block tag determines the compression level used to produce the compressed block. |Block tag|Compression level| |---------|-----------------| @@ -77,16 +95,16 @@ The content of the block will vary depending on the compression level. ### Block Format for Level 1 -FastLZ Level 1 impements LZ77 compression algorithm with 8 KB sliding window and up to 264 bytes of match length. +FastLZ Level 1 implements LZ77 compression algorithm with 8 KB sliding window and up to 264 bytes of match length. The compressed block consists of one or more **instructions**. Each instruction starts with a 1-byte opcode, 2-byte opcode, or 3-byte opcode. | Instruction type | Opcode[0] | Opcode[1] | Opcode[2] |-----------|------------------|--------------------|--| -| Literal run | `000`, L₅-L₀ | -|- | +| Literal run | `000`, L₄-L₀ | -|- | | Short match | M₂-M₀, R₁₂-R₈ | R₇-R₀ | - | -| Long match | `111`, R₁₂-R₈ | M₇-R₀ | R₇-R₀ | +| Long match | `111`, R₁₂-R₈ | M₇-M₀ | R₇-R₀ | Note that the _very first_ instruction in a compressed block is always a literal run. diff --git a/lib/fastlz/fastlz.cc b/lib/fastlz/fastlz.cc index 2e9bfb3d72d..f99bb10b0f3 100644 --- a/lib/fastlz/fastlz.cc +++ b/lib/fastlz/fastlz.cc @@ -25,14 +25,8 @@ #include -/* - * Always check for bound when decompressing. - * Generally it is best to leave it defined. - */ -#define FASTLZ_SAFE -#if defined(FASTLZ_USE_SAFE_DECOMPRESSOR) && (FASTLZ_USE_SAFE_DECOMPRESSOR == 0) -#undef FASTLZ_SAFE -#endif +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" /* * Give hints to the compiler for branch prediction optimization. @@ -48,33 +42,26 @@ /* * Specialize custom 64-bit implementation for speed improvements. */ -#if defined(__x86_64__) || defined(_M_X64) +#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) #define FLZ_ARCH64 #endif -#if defined(FASTLZ_SAFE) -#define FASTLZ_BOUND_CHECK(cond) \ - if (FASTLZ_UNLIKELY(!(cond))) \ - return 0; -#else -#define FASTLZ_BOUND_CHECK(cond) \ - do { \ - } while (0) +/* + * Workaround for DJGPP to find uint8_t, uint16_t, etc. + */ +#if defined(__MSDOS__) && defined(__GNUC__) +#include #endif #if defined(FASTLZ_USE_MEMMOVE) && (FASTLZ_USE_MEMMOVE == 0) -static void -fastlz_memmove(uint8_t *dest, const uint8_t *src, uint32_t count) -{ +static void fastlz_memmove(uint8_t* dest, const uint8_t* src, uint32_t count) { do { *dest++ = *src++; } while (--count); } -static void -fastlz_memcpy(uint8_t *dest, const uint8_t *src, uint32_t count) -{ +static void fastlz_memcpy(uint8_t* dest, const uint8_t* src, uint32_t count) { return fastlz_memmove(dest, src, count); } @@ -82,146 +69,64 @@ fastlz_memcpy(uint8_t *dest, const uint8_t *src, uint32_t count) #include -static void -fastlz_memmove(uint8_t *dest, const uint8_t *src, uint32_t count) -{ +static void fastlz_memmove(uint8_t* dest, const uint8_t* src, uint32_t count) { if ((count > 4) && (dest >= src + count)) { memmove(dest, src, count); } else { switch (count) { - default: - do { + default: + do { + *dest++ = *src++; + } while (--count); + break; + case 3: + *dest++ = *src++; + case 2: *dest++ = *src++; - } while (--count); - break; - case 3: - *dest++ = *src++; - [[fallthrough]]; - case 2: - *dest++ = *src++; - [[fallthrough]]; - case 1: - *dest++ = *src++; - [[fallthrough]]; - case 0: - break; + case 1: + *dest++ = *src++; + case 0: + break; } } } -static void -fastlz_memcpy(uint8_t *dest, const uint8_t *src, uint32_t count) -{ - memcpy(dest, src, count); -} +static void fastlz_memcpy(uint8_t* dest, const uint8_t* src, uint32_t count) { memcpy(dest, src, count); } #endif #if defined(FLZ_ARCH64) -static uint32_t -flz_readu32(const void *ptr) -{ - return *(const uint32_t *)ptr; -} - -static uint64_t -flz_readu64(const void *ptr) -{ - return *(const uint64_t *)ptr; -} +static uint32_t flz_readu32(const void* ptr) { return *(const uint32_t*)ptr; } -static uint32_t -flz_cmp(const uint8_t *p, const uint8_t *q, const uint8_t *r) -{ - const uint8_t *start = p; +static uint32_t flz_cmp(const uint8_t* p, const uint8_t* q, const uint8_t* r) { + const uint8_t* start = p; - if (flz_readu64(p) == flz_readu64(q)) { - p += 8; - q += 8; - } if (flz_readu32(p) == flz_readu32(q)) { p += 4; q += 4; } while (q < r) - if (*p++ != *q++) - break; + if (*p++ != *q++) break; return p - start; } -static void -flz_copy64(uint8_t *dest, const uint8_t *src, uint32_t count) -{ - const uint64_t *p = (const uint64_t *)src; - uint64_t *q = (uint64_t *)dest; - if (count < 16) { - if (count >= 8) { - *q++ = *p++; - } - *q++ = *p++; - } else { - *q++ = *p++; - *q++ = *p++; - *q++ = *p++; - *q++ = *p++; - } -} - -static void -flz_copy256(void *dest, const void *src) -{ - const uint64_t *p = (const uint64_t *)src; - uint64_t *q = (uint64_t *)dest; - *q++ = *p++; - *q++ = *p++; - *q++ = *p++; - *q++ = *p++; -} - #endif /* FLZ_ARCH64 */ #if !defined(FLZ_ARCH64) -static uint32_t -flz_readu32(const void *ptr) -{ - const uint8_t *p = (const uint8_t *)ptr; +static uint32_t flz_readu32(const void* ptr) { + const uint8_t* p = (const uint8_t*)ptr; return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; } -static uint32_t -flz_cmp(const uint8_t *p, const uint8_t *q, const uint8_t *r) -{ - const uint8_t *start = p; +static uint32_t flz_cmp(const uint8_t* p, const uint8_t* q, const uint8_t* r) { + const uint8_t* start = p; while (q < r) - if (*p++ != *q++) - break; + if (*p++ != *q++) break; return p - start; } -static void -flz_copy64(uint8_t *dest, const uint8_t *src, uint32_t count) -{ - const uint8_t *p = (const uint8_t *)src; - uint8_t *q = (uint8_t *)dest; - unsigned int c; - for (c = 0; c < count * 8; ++c) { - *q++ = *p++; - } -} - -static void -flz_copy256(void *dest, const void *src) -{ - const uint8_t *p = (const uint8_t *)src; - uint8_t *q = (uint8_t *)dest; - int c; - for (c = 0; c < 32; ++c) { - *q++ = *p++; - } -} - #endif /* !FLZ_ARCH64 */ #define MAX_COPY 32 @@ -230,60 +135,54 @@ flz_copy256(void *dest, const void *src) #define MAX_L2_DISTANCE 8191 #define MAX_FARDISTANCE (65535 + MAX_L2_DISTANCE - 1) -#define HASH_LOG 14 +#define HASH_LOG 13 #define HASH_SIZE (1 << HASH_LOG) #define HASH_MASK (HASH_SIZE - 1) -static uint16_t -flz_hash(uint32_t v) -{ +static uint16_t flz_hash(uint32_t v) { uint32_t h = (v * 2654435769LL) >> (32 - HASH_LOG); return h & HASH_MASK; } -static uint8_t * -flz_literals(uint32_t runs, const uint8_t *src, uint8_t *dest) -{ - while (runs >= MAX_COPY) { - *dest++ = MAX_COPY - 1; - flz_copy256(dest, src); - src += MAX_COPY; - dest += MAX_COPY; - runs -= MAX_COPY; - } - if (runs > 0) { - *dest++ = runs - 1; - flz_copy64(dest, src, runs); - dest += runs; - } - return dest; -} - -/* special case of memcpy: at most 32 bytes */ -static void -flz_smallcopy(uint8_t *dest, const uint8_t *src, uint32_t count) -{ +/* special case of memcpy: at most MAX_COPY bytes */ +static void flz_smallcopy(uint8_t* dest, const uint8_t* src, uint32_t count) { #if defined(FLZ_ARCH64) - if (count >= 8) { - const uint64_t *p = (const uint64_t *)src; - uint64_t *q = (uint64_t *)dest; - while (count > 8) { + if (count >= 4) { + const uint32_t* p = (const uint32_t*)src; + uint32_t* q = (uint32_t*)dest; + while (count > 4) { *q++ = *p++; - count -= 8; - dest += 8; - src += 8; + count -= 4; + dest += 4; + src += 4; } } #endif fastlz_memcpy(dest, src, count); } -static uint8_t * -flz_finalize(uint32_t runs, const uint8_t *src, uint8_t *dest) -{ +/* special case of memcpy: exactly MAX_COPY bytes */ +static void flz_maxcopy(void* dest, const void* src) { +#if defined(FLZ_ARCH64) + const uint32_t* p = (const uint32_t*)src; + uint32_t* q = (uint32_t*)dest; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; +#else + fastlz_memcpy(dest, src, MAX_COPY); +#endif +} + +static uint8_t* flz_literals(uint32_t runs, const uint8_t* src, uint8_t* dest) { while (runs >= MAX_COPY) { *dest++ = MAX_COPY - 1; - flz_smallcopy(dest, src, MAX_COPY); + flz_maxcopy(dest, src); src += MAX_COPY; dest += MAX_COPY; runs -= MAX_COPY; @@ -296,9 +195,7 @@ flz_finalize(uint32_t runs, const uint8_t *src, uint8_t *dest) return dest; } -static uint8_t * -flz1_match(uint32_t len, uint32_t distance, uint8_t *op) -{ +static uint8_t* flz1_match(uint32_t len, uint32_t distance, uint8_t* op) { --distance; if (FASTLZ_UNLIKELY(len > MAX_LEN - 2)) while (len > MAX_LEN - 2) { @@ -318,46 +215,44 @@ flz1_match(uint32_t len, uint32_t distance, uint8_t *op) return op; } -int -fastlz1_compress(const void *input, int length, void *output) -{ - const uint8_t *ip = (const uint8_t *)input; - const uint8_t *ip_start = ip; - const uint8_t *ip_bound = ip + length - 4; /* because readU32 */ - const uint8_t *ip_limit = ip + length - 12 - 1; - uint8_t *op = (uint8_t *)output; +#define FASTLZ_BOUND_CHECK(cond) \ + if (FASTLZ_UNLIKELY(!(cond))) return 0; + +static int fastlz1_compress(const void* input, int length, void* output) { + const uint8_t* ip = (const uint8_t*)input; + const uint8_t* ip_start = ip; + const uint8_t* ip_bound = ip + length - 4; /* because readU32 */ + const uint8_t* ip_limit = ip + length - 12 - 1; + uint8_t* op = (uint8_t*)output; uint32_t htab[HASH_SIZE]; uint32_t seq, hash; /* initializes hash table */ - for (hash = 0; hash < HASH_SIZE; ++hash) - htab[hash] = 0; + for (hash = 0; hash < HASH_SIZE; ++hash) htab[hash] = 0; /* we start with literal copy */ - const uint8_t *anchor = ip; + const uint8_t* anchor = ip; ip += 2; /* main loop */ while (FASTLZ_LIKELY(ip < ip_limit)) { - const uint8_t *ref; + const uint8_t* ref; uint32_t distance, cmp; /* find potential match */ do { - seq = flz_readu32(ip) & 0xffffff; - hash = flz_hash(seq); - ref = ip_start + htab[hash]; + seq = flz_readu32(ip) & 0xffffff; + hash = flz_hash(seq); + ref = ip_start + htab[hash]; htab[hash] = ip - ip_start; - distance = ip - ref; - cmp = FASTLZ_LIKELY(distance < MAX_L1_DISTANCE) ? flz_readu32(ref) & 0xffffff : 0x1000000; - if (FASTLZ_UNLIKELY(ip >= ip_limit)) - break; + distance = ip - ref; + cmp = FASTLZ_LIKELY(distance < MAX_L1_DISTANCE) ? flz_readu32(ref) & 0xffffff : 0x1000000; + if (FASTLZ_UNLIKELY(ip >= ip_limit)) break; ++ip; } while (seq != cmp); - if (FASTLZ_UNLIKELY(ip >= ip_limit)) - break; + if (FASTLZ_UNLIKELY(ip >= ip_limit)) break; --ip; if (FASTLZ_LIKELY(ip > anchor)) { @@ -365,41 +260,39 @@ fastlz1_compress(const void *input, int length, void *output) } uint32_t len = flz_cmp(ref + 3, ip + 3, ip_bound); - op = flz1_match(len, distance, op); + op = flz1_match(len, distance, op); /* update the hash at match boundary */ ip += len; - seq = flz_readu32(ip); - hash = flz_hash(seq & 0xffffff); + seq = flz_readu32(ip); + hash = flz_hash(seq & 0xffffff); htab[hash] = ip++ - ip_start; seq >>= 8; - hash = flz_hash(seq); + hash = flz_hash(seq); htab[hash] = ip++ - ip_start; anchor = ip; } - uint32_t copy = (uint8_t *)input + length - anchor; - op = flz_finalize(copy, anchor, op); + uint32_t copy = (uint8_t*)input + length - anchor; + op = flz_literals(copy, anchor, op); - return op - (uint8_t *)output; + return op - (uint8_t*)output; } -int -fastlz1_decompress(const void *input, int length, void *output, int maxout) -{ - const uint8_t *ip = (const uint8_t *)input; - const uint8_t *ip_limit = ip + length; - const uint8_t *ip_bound = ip_limit - 2; - uint8_t *op = (uint8_t *)output; - uint8_t *op_limit = op + maxout; - uint32_t ctrl = (*ip++) & 31; +static int fastlz1_decompress(const void* input, int length, void* output, int maxout) { + const uint8_t* ip = (const uint8_t*)input; + const uint8_t* ip_limit = ip + length; + const uint8_t* ip_bound = ip_limit - 2; + uint8_t* op = (uint8_t*)output; + uint8_t* op_limit = op + maxout; + uint32_t ctrl = (*ip++) & 31; while (1) { if (ctrl >= 32) { - uint32_t len = (ctrl >> 5) - 1; - uint32_t ofs = (ctrl & 31) << 8; - const uint8_t *ref = op - ofs - 1; + uint32_t len = (ctrl >> 5) - 1; + uint32_t ofs = (ctrl & 31) << 8; + const uint8_t* ref = op - ofs - 1; if (len == 7 - 1) { FASTLZ_BOUND_CHECK(ip <= ip_bound); len += *ip++; @@ -407,7 +300,7 @@ fastlz1_decompress(const void *input, int length, void *output, int maxout) ref -= *ip++; len += 3; FASTLZ_BOUND_CHECK(op + len <= op_limit); - FASTLZ_BOUND_CHECK(ref >= (uint8_t *)output); + FASTLZ_BOUND_CHECK(ref >= (uint8_t*)output); fastlz_memmove(op, ref, len); op += len; } else { @@ -419,17 +312,14 @@ fastlz1_decompress(const void *input, int length, void *output, int maxout) op += ctrl; } - if (FASTLZ_UNLIKELY(ip > ip_bound)) - break; + if (FASTLZ_UNLIKELY(ip > ip_bound)) break; ctrl = *ip++; } - return op - (uint8_t *)output; + return op - (uint8_t*)output; } -static uint8_t * -flz2_match(uint32_t len, uint32_t distance, uint8_t *op) -{ +static uint8_t* flz2_match(uint32_t len, uint32_t distance, uint8_t* op) { --distance; if (distance < MAX_L2_DISTANCE) { if (len < 7) { @@ -437,8 +327,7 @@ flz2_match(uint32_t len, uint32_t distance, uint8_t *op) *op++ = (distance & 255); } else { *op++ = (7 << 5) + (distance >> 8); - for (len -= 7; len >= 255; len -= 255) - *op++ = 255; + for (len -= 7; len >= 255; len -= 255) *op++ = 255; *op++ = len; *op++ = (distance & 255); } @@ -453,8 +342,7 @@ flz2_match(uint32_t len, uint32_t distance, uint8_t *op) } else { distance -= MAX_L2_DISTANCE; *op++ = (7 << 5) + 31; - for (len -= 7; len >= 255; len -= 255) - *op++ = 255; + for (len -= 7; len >= 255; len -= 255) *op++ = 255; *op++ = len; *op++ = 255; *op++ = distance >> 8; @@ -464,46 +352,41 @@ flz2_match(uint32_t len, uint32_t distance, uint8_t *op) return op; } -int -fastlz2_compress(const void *input, int length, void *output) -{ - const uint8_t *ip = (const uint8_t *)input; - const uint8_t *ip_start = ip; - const uint8_t *ip_bound = ip + length - 4; /* because readU32 */ - const uint8_t *ip_limit = ip + length - 12 - 1; - uint8_t *op = (uint8_t *)output; +static int fastlz2_compress(const void* input, int length, void* output) { + const uint8_t* ip = (const uint8_t*)input; + const uint8_t* ip_start = ip; + const uint8_t* ip_bound = ip + length - 4; /* because readU32 */ + const uint8_t* ip_limit = ip + length - 12 - 1; + uint8_t* op = (uint8_t*)output; uint32_t htab[HASH_SIZE]; uint32_t seq, hash; /* initializes hash table */ - for (hash = 0; hash < HASH_SIZE; ++hash) - htab[hash] = 0; + for (hash = 0; hash < HASH_SIZE; ++hash) htab[hash] = 0; /* we start with literal copy */ - const uint8_t *anchor = ip; + const uint8_t* anchor = ip; ip += 2; /* main loop */ while (FASTLZ_LIKELY(ip < ip_limit)) { - const uint8_t *ref; + const uint8_t* ref; uint32_t distance, cmp; /* find potential match */ do { - seq = flz_readu32(ip) & 0xffffff; - hash = flz_hash(seq); - ref = ip_start + htab[hash]; + seq = flz_readu32(ip) & 0xffffff; + hash = flz_hash(seq); + ref = ip_start + htab[hash]; htab[hash] = ip - ip_start; - distance = ip - ref; - cmp = FASTLZ_LIKELY(distance < MAX_FARDISTANCE) ? flz_readu32(ref) & 0xffffff : 0x1000000; - if (FASTLZ_UNLIKELY(ip >= ip_limit)) - break; + distance = ip - ref; + cmp = FASTLZ_LIKELY(distance < MAX_FARDISTANCE) ? flz_readu32(ref) & 0xffffff : 0x1000000; + if (FASTLZ_UNLIKELY(ip >= ip_limit)) break; ++ip; } while (seq != cmp); - if (FASTLZ_UNLIKELY(ip >= ip_limit)) - break; + if (FASTLZ_UNLIKELY(ip >= ip_limit)) break; --ip; @@ -520,48 +403,45 @@ fastlz2_compress(const void *input, int length, void *output) } uint32_t len = flz_cmp(ref + 3, ip + 3, ip_bound); - op = flz2_match(len, distance, op); + op = flz2_match(len, distance, op); /* update the hash at match boundary */ ip += len; - seq = flz_readu32(ip); - hash = flz_hash(seq & 0xffffff); + seq = flz_readu32(ip); + hash = flz_hash(seq & 0xffffff); htab[hash] = ip++ - ip_start; seq >>= 8; - hash = flz_hash(seq); + hash = flz_hash(seq); htab[hash] = ip++ - ip_start; anchor = ip; } - uint32_t copy = (uint8_t *)input + length - anchor; - op = flz_finalize(copy, anchor, op); + uint32_t copy = (uint8_t*)input + length - anchor; + op = flz_literals(copy, anchor, op); /* marker for fastlz2 */ - *(uint8_t *)output |= (1 << 5); + *(uint8_t*)output |= (1 << 5); - return op - (uint8_t *)output; + return op - (uint8_t*)output; } -int -fastlz2_decompress(const void *input, int length, void *output, int maxout) -{ - const uint8_t *ip = (const uint8_t *)input; - const uint8_t *ip_limit = ip + length; - const uint8_t *ip_bound = ip_limit - 2; - uint8_t *op = (uint8_t *)output; - uint8_t *op_limit = op + maxout; - uint32_t ctrl = (*ip++) & 31; +static int fastlz2_decompress(const void* input, int length, void* output, int maxout) { + const uint8_t* ip = (const uint8_t*)input; + const uint8_t* ip_limit = ip + length; + const uint8_t* ip_bound = ip_limit - 2; + uint8_t* op = (uint8_t*)output; + uint8_t* op_limit = op + maxout; + uint32_t ctrl = (*ip++) & 31; while (1) { if (ctrl >= 32) { - uint32_t len = (ctrl >> 5) - 1; - uint32_t ofs = (ctrl & 31) << 8; - const uint8_t *ref = op - ofs - 1; + uint32_t len = (ctrl >> 5) - 1; + uint32_t ofs = (ctrl & 31) << 8; + const uint8_t* ref = op - ofs - 1; uint8_t code; - if (len == 7 - 1) - do { + if (len == 7 - 1) do { FASTLZ_BOUND_CHECK(ip <= ip_bound); code = *ip++; len += code; @@ -580,7 +460,7 @@ fastlz2_decompress(const void *input, int length, void *output, int maxout) } FASTLZ_BOUND_CHECK(op + len <= op_limit); - FASTLZ_BOUND_CHECK(ref >= (uint8_t *)output); + FASTLZ_BOUND_CHECK(ref >= (uint8_t*)output); fastlz_memmove(op, ref, len); op += len; } else { @@ -592,47 +472,37 @@ fastlz2_decompress(const void *input, int length, void *output, int maxout) op += ctrl; } - if (FASTLZ_UNLIKELY(ip >= ip_limit)) - break; + if (FASTLZ_UNLIKELY(ip >= ip_limit)) break; ctrl = *ip++; } - return op - (uint8_t *)output; + return op - (uint8_t*)output; } -int -fastlz_compress(const void *input, int length, void *output) -{ +int fastlz_compress(const void* input, int length, void* output) { /* for short block, choose fastlz1 */ - if (length < 65536) - return fastlz1_compress(input, length, output); + if (length < 65536) return fastlz1_compress(input, length, output); /* else... */ return fastlz2_compress(input, length, output); } -int -fastlz_decompress(const void *input, int length, void *output, int maxout) -{ +int fastlz_decompress(const void* input, int length, void* output, int maxout) { /* magic identifier for compression level */ - int level = ((*(const uint8_t *)input) >> 5) + 1; + int level = ((*(const uint8_t*)input) >> 5) + 1; - if (level == 1) - return fastlz1_decompress(input, length, output, maxout); - if (level == 2) - return fastlz2_decompress(input, length, output, maxout); + if (level == 1) return fastlz1_decompress(input, length, output, maxout); + if (level == 2) return fastlz2_decompress(input, length, output, maxout); /* unknown level, trigger error */ return 0; } -int -fastlz_compress_level(int level, const void *input, int length, void *output) -{ - if (level == 1) - return fastlz1_compress(input, length, output); - if (level == 2) - return fastlz2_compress(input, length, output); +int fastlz_compress_level(int level, const void* input, int length, void* output) { + if (level == 1) return fastlz1_compress(input, length, output); + if (level == 2) return fastlz2_compress(input, length, output); return 0; } + +#pragma GCC diagnostic pop diff --git a/lib/fastlz/fastlz.h b/lib/fastlz/fastlz.h index fd41e961e04..9172d74de10 100644 --- a/lib/fastlz/fastlz.h +++ b/lib/fastlz/fastlz.h @@ -32,6 +32,10 @@ #define FASTLZ_VERSION_STRING "0.5.0" +#if defined(__cplusplus) +extern "C" { +#endif + /** Compress a block of data in the input buffer and returns the size of compressed block. The size of input buffer is specified by length. The @@ -54,7 +58,7 @@ decompressed using the function fastlz_decompress below. */ -int fastlz_compress_level(int level, const void *input, int length, void *output); +int fastlz_compress_level(int level, const void* input, int length, void* output); /** Decompress a block of compressed data and returns the size of the @@ -72,7 +76,7 @@ int fastlz_compress_level(int level, const void *input, int length, void *output producing the compressed block). */ -int fastlz_decompress(const void *input, int length, void *output, int maxout); +int fastlz_decompress(const void* input, int length, void* output, int maxout); /** DEPRECATED. @@ -84,6 +88,10 @@ int fastlz_decompress(const void *input, int length, void *output, int maxout); version. */ -int fastlz_compress(const void *input, int length, void *output); +int fastlz_compress(const void* input, int length, void* output); + +#if defined(__cplusplus) +} +#endif #endif /* FASTLZ_H */