Aquí hi ha 5 versions de zxc, des de 7 de juliol del 2026 fins a l’actual, 0.15.0. Cadascuna enllaça amb els instal·ladors del mateix desenvolupador.
| Versió | Data | Mida | Fitxers |
|---|---|---|---|
| 0.15.0Darrera versió | 13 d’octubre del 2026 | — | 64 bits ZIP Notes de la versió# Release Notes
v0.15.0 is an integrity release built on a format break, and a speed release on top of it.
**Decompression gains up to 24 % at levels 3-5 and 9-14 % at level 7 over v0.14.x; compression gains up to 39 % at levels 3-7. Level 3 now decodes 2.03x faster than LZ4 on Apple M2 (1.75x in v0.14), at a smaller size.**
**Format v9** redoes every integrity field:checksums that leave no header bit unprotected, block checksums over the decoded bytes, an optional archive digest, a seek table that validates itself group by group. On top of it, ZXC archives become **multi-frame**: `cat a.zxc b.zxc` is a valid archive, and the seekable reader spans every frame.
> ⚠️ **Breaking change (format and ABI).** The container format is now **v9**, and dictionaries move to **`.zxd` version 2**. v0.15.0 cannot read v8 archives or version-1 dictionaries, and v0.14.x cannot read what v0.15.0 writes (`ZXC_ERROR_BAD_VERSION`). The **soname moves to `libzxc.so.5`**:seekable block counts are 64-bit (#438), so programs linked against `libzxc.so.4` must be rebuilt.
>
> **Migrating v8 -> v9** is the same one-time transcode as before:
>
> ```sh
> zxc-old -dc old.zxc | zxc-new -z -c > new.zxc
> ```
>
> A dictionary is migrated with its archives:retrain it with the new build, or convert it byte for byte to keep its `dict_id`. Full guide, including the CLI output changes and the new Windows archive layout: **[docs/MIGRATION.md](https://github.com/hellobertrand/zxc/blob/v0.15.0/docs/MIGRATION.md)**.
## ZXC format v9
The compressed data is unchanged:same blocks, same parser, same entropy coders. The break is in what protects them and in how a reader finds its way. (#452)
• **Multiplicative header checksums (#432).** The XOR/shift construction left part of the compressed size unprotected; the same 2 bytes now cover every header bit.
• **Block checksums cover the decoded bytes, seeded by position (#434).** A block moved or duplicated inside an archive no longer verifies. The whole-archive hash gives way to an optional 8-byte **archive digest** folded from the block checksums.
• **A seek table that validates itself (#436, #438).** Groups of one 64-bit anchor and 64 block sizes, checked one group at a time and loaded lazily, so opening a large archive reads only what a range needs. Block counts are 64-bit.
• **`HAS_SEEK_TABLE` header flag (#448).** The table is announced instead of probed for. In v0.14, about one footer in 65 536 parsed as a seek-table header and failed an intact archive with `ZXC_ERROR_IO`; that ambiguity is gone.
• **A variable-length footer (#489).** Source size and compressed frame size are stored on the bytes they need, behind the optional digest, with a last byte giving their lengths:3 to 17 bytes, plus 8 with the digest. `ZXC_FILE_FOOTER_SIZE` is replaced by `ZXC_FILE_FOOTER_MIN_SIZE` / `ZXC_FILE_FOOTER_MAX_SIZE`.
• **One valid form for the EOF and SEK headers.** Reserved bytes must be zero there and decoders check them, so a lying flag reads as corrupt data rather than a truncated table.
• **`.zxd` dictionaries version 2**, signed with the new header checksum.
## Multi-frame archives (#490)
A ZXC file is now one or more frames back to back. After each footer comes the end of the input, the next frame's magic, or an error.
• **Concatenation just works.** `cat a.zxc b.zxc > ab.zxc` decodes to both sources in order, through the buffer, context, `FILE*` and push-stream APIs, and the size queries add the frames up. Frames keep their own block size, checksum flag and dictionary.
• **Seekable across frames.** When every frame carries a seek table, `zxc_seekable_open` spans them all (up to 2^20 frames), with a dictionary per frame.
• **Frame info API (#489).** `zxc_get_frame_info()`, `zxc_get_last_frame_info()` and their `FILE*` versions report a frame's sizes and flags; the compressed frame size in each footer lets a reader walk the frames back from the end.
• **Wrappers.** Go, Rust and Python readers decode concatenations as one |
| 0.14.1 | 21 de setembre del 2026 | — | 64 bits ZIP Notes de la versió# Release Notes
v0.14.1 is a hardening release:every decode path got stricter, block decompression is **10-13 % faster**, reusable contexts reach all five wrappers, and seekable archives can verify per-block checksums.
**Drop-in for v0.14.0.** Same format v8, byte-identical output at every level (verified on Silesia), soname still `libzxc.so.4`. One symbol added, `zxc_seekable_set_checksum`; none removed or changed.
## Decoder hardening
• **A forged block size passed off a truncated decode as success (#428).** A payload size spanning the EOF marker made the frame walk run off the archive and return what it had, with checksums off (the default). A data block's payload can no longer exceed the header's block size, the walk must end on the EOF block, and a seek-table entry spans at most one block. The check sits in the block decoder shared by every reader. Both rules are now normative in `FORMAT.md`.
• **Stack address stored in heap memory (#429).** Multi-threaded seekable jobs held the caller's output pointer. This was harmless, since workers are joined before return, but a scanner can't prove that. Jobs now carry offsets from one base pointer on the caller's stack.
• **`zxc_stream_decompress` ignored the dictionary size limit (#430).** A dictionary above `ZXC_DICT_SIZE_MAX` was accepted, or rejected with a misleading `ZXC_ERROR_DICT_MISMATCH`. The check moved into the shared stream engine.
• **Contexts (#417, #422).** Static contexts reject oversized blocks up front. An empty input through a context now yields the canonical 36-byte archive, like the one-shot API.
## API
• **Reusable contexts in every wrapper (#424, #414, #415).** `Cctx` and `Dctx` now ship in Rust, Go, Python, Node.js and WASM. A dictionary given to the factory applies to every call that doesn't override it. The block API also takes a dictionary's shared literal Huffman table (#415), so small blocks no longer spend bytes describing their own.
• **Seekable checksum verification (#425).** `zxc_seekable_decompress_range` can verify per-block checksums through `zxc_seekable_set_checksum`. It is **off by default** and exposed in all five wrappers.
Also fixed:an overflowing offset plus length slipped past the bounds check, and an incomplete range returned a silent partial read instead of `ZXC_ERROR_CORRUPT_DATA`.
## CLI
• **`-l` and `-t` read checksum status from the `HAS_CHECKSUM` header flag (#435).** `-j` adds `checksum_method`; exit codes are unchanged. Thanks to @Vladexy88x for the fix.
## Performance
• **`zxc_decompress_block` writes straight to the destination (#418).** Given the `zxc_decompress_block_bound()` capacity, it skips the bounce-buffer copy and runs **10-13 % faster**, from 64 KB to 2 MB blocks (Apple M3, level 3, Silesia). An exact-size destination falls back to the bounce buffer instead of failing with `ZXC_ERROR_OVERFLOW`.
## Build & Packaging
• Trusted publishing for the release workflows (#421), replacing long-lived tokens.
• Rapidhash is resolved at configure time (#420). The vendored copy is used unless `-DZXC_USE_SYSTEM_RAPIDHASH=ON`, and a missing copy fails at configure rather than mid-build. Thanks to @jeanga for the issue.
• Wrapper packaging and release integrity tightened (#409). Publish jobs no longer install an unpinned global npm (#426, #427).
• One seeded checksum entry point (#423), tidier nudge tuning macros (#412), and SARIF uploads skipped on fork PRs.
## Documentation
`FORMAT.md` gains the two decoder rules and the dictionary ID derivation (#413):a 32-bit value that binds a dictionary to an archive without authenticating it. The Rust crate's `zxc-compress` / `zxc` naming is clarified (#410), with README refinements (#408).
## Changelog
• api:Enforces strict block size and EOF validation (#428)
• api:Implements reusable compression contexts (#424)
• api:Enhances seekable API with checksum control and robust range validation (#425)
• api:Fix empty frame compression in contexts (#422)
• api:Enforce strict block si |
| 0.14.0 | 8 de setembre del 2026 | — | 64 bits ZIP Notes de la versió# Release Notes
v0.14.0 is a decode-speed release built on a format break.
**This release boosts decompression speed by up to 19% over v0.13.x, up to doubling our performance lead over LZ4 on ARM64 (+85% to +105%) and up to tripling it on x86_64 (+50% to +175%).**
Three independent changes get there:blocks stop describing what the decoder can derive (**format v8**), short back-references are copied 32 bytes at a time instead of 16, and at levels 1-5 the encoder keeps its matches far enough back that the widest SIMD copy path stays on. The PivCo Huffman kernels also picked up AVX-512 VBMI, 256-bit AVX2 and NEON work.
Nothing in the public API moved:no symbol added, none removed, **ABI unchanged** (`libzxc.so.4`). The break is in the container format.
> ⚠️ **Breaking change (format).** The container format is now **v8**. v0.14.0 writes v8 archives that v0.13.x and earlier decoders reject, and it cannot read v7 or older:the header version byte is checked for exact equality (`ZXC_ERROR_BAD_VERSION`). The **ABI is unchanged** (soname stays `libzxc.so.4`), so no re-link is required — but upgrading the library alone makes newly written archives v8.
>
> **Migrating v7 -> v8** is a one-time transcode — decompress with your old build, recompress with the new one:
>
> ```sh
> zxc-old -dc old.zxc | zxc-new -z -c > new.zxc
> ```
>
> Keep a v7 build around until your data at rest is converted; if the old archive used a dictionary, pass it to the decompress side (`zxc-old -dc -D dict.zxd`). Full guide (bulk migration, dictionaries, verification):**[docs/MIGRATION.md](https://github.com/hellobertrand/zxc/blob/v0.14.0/docs/MIGRATION.md)**.
## ZXC format v8
Compression is untouched — same parser, same match finder, same entropy coders. What changed is how a block describes itself, and every change pulls the same way:**stop writing down what the decoder can work out.** (#374)
• **Block sub-header:16 -> 12 bytes.** Four reserved bytes nobody used.
• **Descriptors only when they carry information.** v7 wrote a fixed 32-byte table of section sizes; most of them follow from the header. v8 keeps the two that don't:the literal section's compressed size when it is RLE- or entropy-coded, and the token section's at level 7. GLO now carries 0, 4 or 8 descriptor bytes, GHI none. The extras section is the leftover payload.
• **`enc_litlen` -> `enc_tok`.** The field always described the token section, never literal lengths.
• **32 readable bytes must follow the literal section.** Literals are copied with a wild copy that overshoots, and those bytes keep the last copy inside the payload. Real blocks clear the bar without trying; the encoder pads into the extras when a tiny block doesn't. Always relied on, never written down — now normative, and decoders must reject blocks that break it.
• **`enc_lit`, `enc_tok` and `enc_off` are closed value sets.** Decoders reject unknown values instead of defaulting, which keeps the spare values free for a future version.
Per block this saves 25 to 34 bytes:invisible at the 512 KB default (levels 6 and 7 land 0.02 % smaller), worth about **2 %** at the 4 KB blocks where dictionaries live.
## Performance
Decompression on Silesia (202 MB), single-threaded, v0.13.3 -> v0.14.0 on the same reference hardware:
| Level | Apple M2 | Neoverse-V2 | EPYC Zen 5 | EPYC Zen 3 |
|:---|---:|---:|---:|---:|
| **-1** | +6.5 % | +2.8 % | +4.5 % | +3.4 % |
| **-2** | +7.7 % | +2.1 % | +6.2 % | +3.1 % |
| **-3** | **+19.0 %** | **+16.6 %** | **+10.9 %** | **+13.4 %** |
| **-4** | **+18.7 %** | **+16.6 %** | **+10.2 %** | **+13.2 %** |
| **-5** | **+18.0 %** | **+16.8 %** | +9.8 % | **+13.0 %** |
| **-6** | +10.3 % | +9.5 % | +3.9 % | +9.3 % |
| **-7** | +9.2 % | +6.2 % | +1.7 % | +6.2 % |
In absolute terms, level 3 decodes at **8.4 GB/s** on Apple M2 and **6.7 GB/s** on Zen 5; level 6 holds **6.7 GB/s** on M2 at a 36.28 % ratio, ahead of `lz4hc -9` on both axes on every machine measured. Full tables, cycles/byte and effective throu |
| 0.13.3 | 20 d’agost del 2026 | — | 64 bits ZIP |
| 0.12.0 | 7 de juliol del 2026 | — | 64 bits ZIP |