Skip to content

Releases: hellobertrand/zxc

ZXC v0.10.0

16 Apr 07:21
05d7fbd

Choose a tag to compare

Release Notes

This release introduces seekable archives for random-access decompression, WebAssembly support for browser and server-side JavaScript, a block-level API for filesystem integrations, a runtime library information API, and an official Go wrapper. It improves stream engine robustness with thread-safety fixes and includes several breaking CLI changes (default extension, checksum behavior, pkg-config module name). It also delivers significant encoder optimizations (split hash table, semi-branchless varint decoding, unified literal copy fast path, BMI/LZCNT extensions, parameterized lazy matching, SIMD register optimization) and internal code quality improvements. SOVERSION is incremented to 3.

Breaking Changes

  • Default file extension changed to .zxc: Compressed files now use the .zxc extension instead of the previous .xc suffix. File detection, recursive processing, and documentation have been updated accordingly. (#143)
  • pkg-config module renamed to libzxc: Follows the naming convention used by libzstd, liblz4, liblzma, libbrotli. Consumers should update their build files to use pkg_check_modules(LIBZXC IMPORTED_TARGET libzxc). (#144)
  • Checksums enabled by default: The CLI now enables checksums for all operation modes except --bench, where they remain disabled to avoid measuring checksum overhead. (#142)
  • SOVERSION incremented to 3: The shared library SOVERSION is bumped from 2 to 3 due to ABI-breaking changes (new seekable API, block-level API, runtime info API). Consumers linking against the shared library (libzxc.so.3 / libzxc.3.dylib) must rebuild. Static library users are unaffected.

New Features

Seekable Archives

Introduces seekable ZXC archives for random-access decompression. When seekable = 1 is set in zxc_compress_opts_t, the compressor appends a seek table block (ZXC_BLOCK_SEK) containing per-block compressed sizes, enabling O(1) block lookup and byte-range decompression without scanning the full stream.

New APIs: zxc_seekable_open, zxc_seekable_open_file, zxc_seekable_read, zxc_seekable_close, zxc_seekable_get_num_blocks, zxc_seekable_get_decompressed_size. (#188)

WebAssembly (WASM) Support

Adds an Emscripten-based WebAssembly build target, enabling browser and server-side JavaScript compression. Includes a JavaScript API wrapper for buffer-based operations, Node.js roundtrip tests, and a GitHub Actions workflow for automated WASM builds on push and release events. (#189)

Block-Level API

Introduces zxc_compress_block, zxc_decompress_block, and zxc_compress_block_bound for single-block compression and decompression without file headers, footers, or EOF blocks. This API is designed for filesystem integrations (DwarFS, EROFS, SquashFS) where the caller manages its own block indexing. (#148)

Runtime Library Information API

Introduces zxc_min_level, zxc_max_level, zxc_default_level, and zxc_version_string to query the supported compression level range and library version string at runtime. This allows callers, such as filesystem integrations, to discover metadata and capabilities without relying on compile-time constants alone. (#163)

Go Wrapper

Introduces the official Go package for zxc, located in wrappers/go. Built on CGo, it exposes two idiomatic APIs:

  • Buffer API: for in-memory compression and decompression.
  • Streaming API: for large files, backed by the multi-threaded stream engine with separate reader, worker, and writer threads.

Typed sentinel errors map every C error code to a named Go error value. Cross-platform CI (ubuntu-latest, ubuntu-24.04-arm, macos-latest, windows-latest) runs both tests and benchmarks on every release via the Test Go Package workflow. (#149)

Scalar-Only Build Option

Introduces the ZXC_DISABLE_SIMD CMake option to bypass all hand-written SIMD intrinsics and inline assembly, forcing the library into a scalar-only execution path. Compiler auto-vectorization remains unaffected. This is useful for baseline performance benchmarking, portability testing, and security auditing of the scalar code paths. (#174)

Performance

  • Split hash table architecture: Separates the LZ77 hash table into a position array (uint32_t, 128 KB) and an 8-bit tag array (uint8_t, 32 KB) with 15-bit addressing (32 768 buckets, up from 16 384). The compact tag array fits in L1 cache and rejects mismatches before loading positions, while the doubled bucket count shortens chain walks. (#179)
  • Semi-branchless varint decoding: Replaces conditional branching in the variable-byte integer decoder with look-up tables and bitwise operations, reducing branch mispredictions in the decompression hot path. Also standardizes bit-width constants to use CHAR_BIT from <limits.h>. (#186)
  • Unified 32-byte literal copy: Replaces conditional 16-byte and 32-byte literal copies with a single 32-byte copy when buffer padding allows, reducing branching in the compression hot path. (#181)
  • Varint encoding simplification: Removes unreachable 4-byte and 5-byte varint encoding paths (bounded by the 2 MB block size limit), replaces hardcoded integer limits with bit-shift constants, and simplifies lazy evaluation naming for clarity. (#183)
  • Decoupled LZ77 lazy evaluation: Improves the parallelism of lazy evaluation checks within zxc_lz77_find_best_match by evaluating ip+1 and ip+2 positions independently before a single decision, enhancing match finding efficiency. (#177)
  • Refined numeric data detection: The zxc_probe_is_numeric function now employs multi-region sampling, analyzing both the start and middle of a block to more accurately determine if data is suitable for numeric compression. (#177)
  • Optimized decompression loop: The safe loop for sequence decoding in zxc_decode_block_ghi is now 4x unrolled to process multiple sequences concurrently, significantly boosting decompression speed. (#177)
  • SIMD register optimization: Eliminates GPR round-trips in SIMD batch loops across all platforms. On ARM64, uses vdupq_laneq_u32 for direct NEON lane broadcast. On AVX2, uses _mm256_permute2x128_si256 + _mm256_shuffle_epi32. On AVX-512, uses _mm512_shuffle_i32x4 + _mm512_shuffle_epi32. This keeps the running sum in vector registers throughout the decode batch loop, reducing instruction latency. (#164)
  • ARM64 encoder vectorization: Leverages vminvq_u8 and vmaxvq_u8 vector reduction intrinsics for 16-byte block uniformity checks during RLE and literal scanning, avoiding premature extraction to general-purpose registers. Also removes an unnecessary prefetch in the LZ77 match-finding loop. (#164)
  • Encoder micro-optimization: Extracts offset_bits and offset_mask from the context structure into local constants in zxc_encode_block_glo and zxc_encode_block_ghi, reducing repeated member access in performance-critical paths. (#141)
  • BMI/LZCNT extensions: Optimizes zxc_log2_u32 with platform-specific intrinsics (_BitScanReverse, __builtin_clz) and enables BMI1/BMI2/LZCNT instruction set flags for AVX2 and AVX512 build variants. Fixes potential undefined behavior in 64-bit shift calculations for offset mask and epoch values. (#159)
  • Parameterized lazy matching threshold: Replaces the hardcoded match length limit (128) for lazy evaluation with a configurable parameter in zxc_lz77_params_t, allowing each compression level to independently tune the trade-off between search depth and encoding speed. (#158)
  • I/O buffer alignment: Replaces hardcoded buffer constants in the CLI with the ZXC_IO_BUFFER_SIZE macro (1 MB), ensuring consistent I/O buffer sizing during file processing. (#162)
  • Decompression macro refactor: Introduces DECODE_COPY_LITERALS and DECODE_COPY_MATCH sub-macros to deduplicate the literal and match copying logic across SAFE and FAST decoding paths in both glo and ghi block decoders. (#150)

Bug Fixes & Robustness

  • Improved bit reader robustness: Corrects edge-case handling in the bit reader's zxc_br_ensure function, ensuring proper behavior when working with 64-bit masks and shifts.
  • Stream engine synchronization: Destroys mutexes and condition variables after worker threads have joined to prevent resource leaks. (#146)
  • Thread creation failure handling: Properly destroys synchronization primitives and joins started threads when thread creation or context initialization fails, preventing resource leaks and deadlocks. (#146)
  • Worker thread data races: Job status and result size updates in worker threads are now performed while holding the ...
Read more

ZXC v0.9.1

16 Mar 08:46

Choose a tag to compare

Release Notes

This is a maintenance release with CLI usability improvements and documentation updates. No ABI changes, SOVERSION remains 2.

Bug Fixes (CLI)

  • Fix: --bench duration parsing: --bench [N] was not correctly consuming the duration argument. The value was left as a positional argument, causing the next filename to be misinterpreted as a duration. All three forms now work correctly: -b2, --bench=2, --bench 2.

  • -B / --block-size in help text: The --block-size option was functional since v0.9.0 but missing from zxc --help output. Now documented: -B, --block-size Block size: 4K..2M, power of 2 {256K}.

Documentation

  • tar integration: Added usage examples for using zxc as an external compressor with tar:
    • GNU tar: tar -I 'zxc -5' -cf archive.tar.zxc data/
    • bsdtar (macOS): tar --use-compress-program='zxc -5' -cf archive.tar.zxc data/
    • Universal pipes: tar cf - data/ | zxc > archive.tar.zxc

Changes

Full Changelog: v0.9.0...v0.9.1

ZXC v0.9.0

15 Mar 07:52

Choose a tag to compare

Release Notes

This release introduces the Reusable Context API, configurable block sizes, a comprehensive API & ABI reference, and several security fixes; including a heap-buffer-overflow found by fuzzing the compression path.

SOVERSION bumped to 2: this release contains ABI-breaking changes.

Breaking Changes

  • SOVERSION 2: The shared library ABI version has been incremented. Binaries compiled against SOVERSION 1 must be recompiled.
  • Options structs: zxc_compress() and zxc_decompress() now take zxc_compress_opts_t* / zxc_decompress_opts_t* instead of positional parameters. Pass NULL for default behavior.
  • Block size encoding: The file header now stores block size as a log2 exponent [12..21] instead of the previous dual-scale encoding. Legacy value 64 is still accepted for backward compatibility.

New Features

Reusable Context API

Opaque, heap-allocated compression and decompression contexts that eliminate per-call allocation overhead, ideal for filesystem plug-ins (squashfs, dwarfs) and batch processing:

  • zxc_create_cctx() / zxc_free_cctx() / zxc_compress_cctx()
  • zxc_create_dctx() / zxc_free_dctx() / zxc_decompress_dctx()

Internal buffers are only reallocated when block_size or level changes between calls.

Configurable Block Sizes

  • Block size is now configurable via the block_size field in zxc_compress_opts_t.
  • Valid range: 4 KB - 2 MB (power of two).
  • Default remains 256 KB.
  • CLI: new --block-size or -B option with unit suffixes (4K, 1M, or 4KB, 1MB etc.).

Direct Decompression Fast Path

  • When the destination buffer is sufficiently padded, decompression skips the intermediate work buffer copy, reducing memory traffic and latency.

Security & Stability

  • Fix: heap-buffer-overflow in bitpacking (zxc_bitpack_stream_32): The packing loop could write up to 4 bytes past the output buffer when the last packed value straddled a byte boundary.
  • Fix: stream validation during decompression (zxc_decompress.c): Added validation to ensure the sequence stream size is sufficient for the declared number of sequences, preventing out-of-bounds reads.
  • Block size validation: Both zxc_cctx_init() and zxc_read_file_header() now validate that block sizes are within [ZXC_BLOCK_SIZE_MIN, ZXC_BLOCK_SIZE_MAX] and are powers of two.
  • C++ compatibility: All public headers now include extern "C" guards for seamless C++ consumption.
  • Fuzzing corpus storage: Configured persistent corpus storage for ClusterFuzzLite CI.

Documentation

  • docs/API.md: New comprehensive API & ABI reference documenting all 21 exported symbols, type definitions, visibility strategy, ABI versioning, thread safety guarantees, and error handling patterns.
  • Updated man page and README with installation instructions and packaging status (vcpkg, Conan, Homebrew).
  • Updated docs/FORMAT.md for exponent-based block size encoding.

Wrappers

All language wrappers updated to use the new options struct API:

  • Python: Updated CFFI bindings for options structs.
  • Rust: Updated FFI layer and safe wrapper for options structs and reusable context API.
  • Node.js: Updated N-API bindings for options structs.

Changes

Full Changelog: v0.8.3...v0.9.0

ZXC v0.8.3

06 Mar 08:06

Choose a tag to compare

Release Notes

Patch release fixing compilation errors with Clang 12-16 and suppressing warnings on MinGW (GCC). Also introduces a new CI workflow testing 22 compiler configurations.

Changes

Fixes

  • Fix _Atomic static initializer for Clang 12-16 (zxc_dispatch.c). Replaced with explicit casts to the target function pointer type.
  • Fix -Wunused-parameter warnings on MinGW for attr and retval parameters in the Win32 pthread.

CI

  • Add compiler compatibility CI workflow. Added a comprehensive CI workflow testing 22 compiler x architecture combinations (#134)

Full Changelog: v0.8.2...v0.8.3

ZXC v0.8.2

05 Mar 13:24

Choose a tag to compare

Release Notes

This release addresses multiple security findings reported by Snyk and an intensive fuzzing campaign (300M+ iterations). Enhances the overall robustness of the resource management.

Changes

Security & Hardening

  • Integer Overflow Prevention: Implemented thread count clamping and explicit size_t arithmetic for workspace allocation.
  • Resource Management: Fixed potential file handle leaks in CLI error paths and benchmark modes.
  • Input Sanitization: Hardened CLI argument parsing and enhanced output terminal guards.

Core Library

  • Thread Configuration: Centralized ZXC_MAX_THREADS (1024) and synchronized limits across the codebase.
  • Memory Safety: Patched potential out-of-bounds access points and refined scratch buffer management.

CI

  • Fuzzing: Optimized buffer API and memory reuse for automated fuzzing integration.

Full Changelog: v0.8.1...v0.8.2

ZXC v0.8.1

02 Mar 11:21

Choose a tag to compare

Release Notes

This is a pure packaging patch release for Linux/Debian maintainers.

Changes

  • Fix: Bumped SOVERSION to 1 in CMakeLists.txt to correctly reflect the ABI changes introduced in v0.8.0. Ensures the generated shared library is named libzxc.so.1, allowing co-installability with older versions (libzxc.so.0) without silently breaking existing dynamically linked software.

There are no functional or API changes in this release compared to v0.8.0.


Full Changelog: v0.8.0...v0.8.1

ZXC v0.8.0

01 Mar 18:27

Choose a tag to compare

Release Notes

This release brings significant improvements to the ZXC ecosystem, focusing on security, performance, cross-language support, and comprehensive documentation.

Breaking Changes (Format Version 5)

  • Format V5: Implemented an LZ offset bias (+1) at the format level to eliminate potential zero-offset attack vectors.
  • Checksums: Header checksums now use Marsaglia xorshift algorithm.

Performance Improvements

The new LZ77 hashing strategy and hash table configuration optimizations (#106) yield significant performance gains across different architectures, especially for higher compression levels.

Highlights:

  • Compression Speed: Massive improvements for levels 3 to 5, showing 33% to 43% faster compression speeds on both x86_64 and ARM64 architectures.
  • Decompression Speed: Notable improvements for faster levels (1 and 2), with up to 10-18% speedup on x86_64 and ~8-10% on ARM64.
  • Compression Ratio: Ratios are maintained or slightly improved, meaning these speed gains come at no cost to compression size.

Changes

Performance & Refactoring

  • Hashing Optimization: Optimized the LZ77 hashing strategy and standardized hash table configuration for improved compression efficiency (#106).
  • Enhanced Error Handling: Refactored error handling with robust error codes. The Python wrapper now exposes these C error constants to provide enhanced and native error reporting (#103, #111).
  • Dual-Scale Chunk Size Implementation: The ZXC_BLOCK_SIZE is no longer limited to 1 MB. The ZXC file format now formally supports block sizes up to 8 MB. Introduced a Most Significant Bit (MSB) dual-scale flag in Chunk Size Code.
    Fine Scale (MSB=0): Uses a 4 KB multiplier, enabling block sizes from 4 KB to 508 KB.
    Large Scale (MSB=1): Uses a 64 KB multiplier, unlocking block sizes from 64 KB up to 8 MB.
  • CLI: Adds multiple file processing mode. Introduces the -m or --multiple CLI option, enabling the processing of several input files in a single command. Each file is handled independently, with output filenames automatically derived from the input (e.g., file.txt compresses to file.txt.xc, file.txt.xc decompresses to file.txt).
  • CLI: Adds recursive directory processing mode. Introduces the -r or --recursive CLI option, enabling the processing of all regular files within specified directories and their subdirectories.

Security & Stability

  • Zero-Offset Attack Prevention: Implemented an LZ offset bias (+1) at the format level to eliminate potential zero-offset attack vectors (#104).
  • Memory Safety: Fixed potential buffer overflows, decoder underflows, and path handling edge cases (#105).
  • Code Quality: Enforced strict const correctness for local variables to ensure better compile-time safety (#110).
  • CLI: Fixes benchmark deadline calculation. Explicitly casts when calculating compression and decompression benchmark deadlines.
  • CLI: Refactors path handling for robustness (#119). Addresses compatibility issues arising from reliance on PATH_MAX fixed-size buffers.
  • Migrates internal path manipulation in validation and directory processing to use dynamic memory allocation with realpath(NULL), strdup, and malloc. This ensures adaptability to varying path lengths and improves compatibility on systems where PATH_MAX may be undefined or insufficient, such as GNU/Hurd.
  • Adds CI support for Alpha architecture (#122)

Wrappers

  • Node.js Support: Introduced a brand-new Node.js wrapper for zxc compression, expanding our language ecosystem (#107).
  • Python: Closes file handles in stream tests (#115). Prevents potential resource leaks by guaranteeing cleanup via a finally block, regardless of test success or failure.

Documentation & Ecosystem

  • Format Specification: Published a comprehensive ZXC file format specification featuring byte-level structures and a worked hexdump example.
  • MAN: Provides comprehensive documentation for the zxc command-line interface man.
  • Added vcpkg installation instructions, refined the introduction, and added a TL;DR and new package badges to the README.

Full Changelog: v0.7.3...v0.8.0

ZXC v0.7.3

18 Feb 09:50

Choose a tag to compare

Release Notes

This release fix the vcpkg integration by moves the rapidhash.h header file to a dedicated vendor directory to improve project structure and dependency management.

This change ensures better organization of external libraries and avoids potential naming conflicts. It also updates related build configurations, code analysis workflows, and coverage settings to reflect the new file location.

Changes

  • Moves rapidhash.h to vendors directory #101
  • Finds rapidhash via system or vendored fallback #102

Full Changelog: v0.7.2...v0.7.3

ZXC v0.7.2

16 Feb 05:29

Choose a tag to compare

Release Notes

This release fix a minor warning when zxc is build with ZXC_NATIVE_ARCH option to ON onto x86 architectures.

Bug Fixes & Safety

  • Fix warning for AVX2/AVX512 macro redefinition in native mode build #94

Full Changelog: v0.7.1...v0.7.2

ZXC v0.7.1

14 Feb 11:51
d692a48

Choose a tag to compare

Release Notes

This release focuses on hardening the decompression engine with safety checks and fix build for vcpkg port

Bug Fixes & Safety

  • Fixes potential out-of-bounds read in decompression in #92
  • CMake: specifies release config for /O2 flag

Full Changelog: v0.7.0...v0.7.1