A codec that only talks to itself isn’t really compatible with anything. 0.3.4 makes OxiArc fluent with the reference implementations.
Today we released OxiArc 0.3.4 — an interoperability hardening release. A batch of spec-conformance defects, surfaced by downstream integration testing in FVRS, was root-caused and fixed across the LZMA, bzip2, LZH, 7z, ZIP, TAR, and XZ stacks.
No C, no Fortran, no zlib, no libarchive, no external shared libraries. Just clean, memory-safe, blazing-fast archiving and compression that compiles to a single static binary, targets WASM, and runs everywhere.
OxiArc is the Pure Rust replacement for the zip, tar, gzip, zstd, and 7-zip tools — and for the Rust crates zip, flate2, zstd, bzip2, lz4, tar, snap, brotli, and miniz_oxide.
Why 0.3.4 is a meaningful step
Self-consistent round-trip tests catch a lot — but they cannot catch two implementations quietly agreeing on the wrong thing. 0.3.4 closes that gap by validating every fixed codec bidirectionally against its reference implementation:
- LZMA/LZMA2 now interoperates with real liblzma streams. Four spec deviations made oxiarc’s own LZMA output mutually incompatible with liblzma: a custom distance-slot probability table layout instead of the spec’s
PosDecoders + dist - posSlotindexing; a wrongstate - 6mapping for states ≥ 10; a misread 2-bit LZMA2 control-byte reset field; and an embedded end-of-stream marker inside LZMA2 chunks that liblzma rejects as corrupt. All four are fixed, consistently, across the decoder, LZMA2 decoder, encoder, and optimal-parser pricing. - bzip2 gets a complete bidirectional fix. oxiarc could previously neither decode real bzip2 streams nor produce streams bzip2 could decode — wrong bit order (needed MSB-first, not DEFLATE-style LSB-first), the wrong CRC-32 variant, an incorrect MTF/Huffman pipeline layering, and an off-by-one in the Huffman alphabet size. All fixed; decoding now follows libbz2’s limit/base/perm scheme.
- 7z, ZIP, TAR, and XZ each got spec-conformance passes: real per-entry sizes in 7z solid-folder listings, injective Shift-JIS/EFS/CP437 ZIP name decoding (previously distinct Japanese filenames collapsed into identical mojibake), a TAR writer panic on multibyte UStar-prefix splitting, and correct XZ block-header CRC coverage and self-describing LZMA2 chunk framing.
- LZH gains
-lh1-support — a new decoder and spec-conformant greedy encoder — plus fixes for three independent bugs that corrupted lh4/5/6/7 streams beyond the window size.
Every one of these fixes was validated at development time against the real reference tool — liblzma, libbz2, bsdtar/libarchive, CPython’s stdlib — and the resulting golden vectors are committed as fully hermetic test data, so the test suite needs no external tools at run time.
Technical Deep Dive
- Distance-slot probability table (
oxiarc-lzma). The table used a custom overlapping layout instead of the spec’sPosDecoders + dist - posSlotindexing (perLzmaSpec.cpp), and was resized 114 → 115 (SPEC_POS_PROBS = 1 + FULL_DISTANCES - END_POS_MODEL_INDEX) to match. State::update_literal(oxiarc-lzma). States ≥ 10 mapped10 → 6instead of the spec’sstate - 6(10 → 4), corrupting decode of real liblzma streams past ~64 KB — a bug invisible to self-round-trip tests because oxiarc’s own encoder and decoder agreed with each other, just not with the spec.- MSB-first bit I/O (
oxiarc-bzip2). A new private bit-I/O module replaces the LSB-first (DEFLATE-style) reader/writer with the MSB-first stream the bzip2 format actually uses, alongside the non-reflected CRC-32 (0x04C11DB7, init0xFFFFFFFF) bzip2 expects instead of the reflected ZIP/GZIP variant. zip/name_codecandlzh/name_codec(oxiarc-archive). New modules implement the correct decode chain — strict UTF-8 when the EFS bit is set, Shift_JIS when it is not, and an injective CP437 fallback that never collapses distinct raw names into the sameU+FFFDstring — wired into both the central-directory and local-file-header paths.- Hermetic interop regression suites. 12 tests decode real liblzma LZMA1/
.lzma/LZMA2 streams; 13 tests cover real libbz2 output including a 1.2 MB two-block stream crossing the 900 KB boundary; a 7z/ZIP/TAR suite exercises bsdtar and python3-tarfile golden fixtures — all embedded as binary test data, none requiring the reference tool to be installed.
Getting Started
CLI:
cargo install oxiarc-cli
Library:
cargo add oxiarc-archive oxiarc-lzma oxiarc-bzip2
Nothing changes in how you call these codecs — the fixes are internal spec-conformance corrections, not API changes:
use oxiarc_archive::SevenZReader;
use oxiarc_lzma::{LzmaEncoder, LzmaDecoder};
use std::fs::File;
// Extract a real liblzma-produced .7z — CRCs now verified per entry
let file = File::open("archive.7z")?;
let mut sz = SevenZReader::new(file)?;
for entry in sz.entries() {
let data = sz.extract(&entry)?;
println!("{}: {} bytes", entry.name, data.len());
}
If you’ve been round-tripping through oxiarc-lzma or oxiarc-bzip2 only against itself, upgrading now means your .xz, .lzma, and .bz2 output will open cleanly in xz, bzip2, and every other tool that speaks the real format.
What’s New in 0.3.4
- oxiarc-lzma: Four LZMA/LZMA2 spec deviations fixed for real liblzma interop — distance-slot probability table layout,
State::update_literalmapping, LZMA2 control-byte reset field, and embedded end-of-stream markers inside LZMA2 chunks. NewLzmaEncoder::compress_chunkAPI for exact-size container framing. - oxiarc-bzip2: Complete bidirectional interop fix — MSB-first bit I/O, non-reflected CRC-32, corrected MTF/Huffman pipeline, and hardened corrupt-input handling (bounds checks, zero-run caps, block-size overflow checks).
- oxiarc-archive: 7z reader spec-conformance overhaul (real per-entry sizes, 0-byte/anti-item handling, correct variable-length number decoding, CRC verification on extract); new
zip/name_codecandlzh/name_codecmodules for injective Shift-JIS/EFS/CP437 name decoding; ZIP writer now sets the EFS flag for non-ASCII names; TAR writer char-boundary panic fixed plus new PAX long-name write support; XZ block-header CRC and index Unpadded Size corrected; reader parses self-describing LZMA2 chunk framing instead of scanning for the first zero byte. - oxiarc-lzhuf: New
-lh1-decoder and spec-conformant greedy encoder; three independent beyond-window bugs fixed in lh4/5/6/7 (incremental LZSS encoding, 16-bit block-size overflow, p-tree count field width). - oxiarc-archive: LZH reader now lists/skips unknown methods and
-lhd-/level-1/level-2 entries instead of aborting the whole archive; LZH writer encodes filenames as Shift_JIS per the LHA convention. - oxiarc-cli:
create/convertnow error up front on unwritable/unknown output extensions instead of silently writing ZIP data, and no longer force LZH entries to Store. - Hermetic golden-vector regression suites for all of the above — liblzma, libbz2, bsdtar, and CPython fixtures embedded as test data, no external tools needed at test time.
- 1,799 tests passing (all features), zero clippy/check/rustdoc warnings across the workspace.
Tips
- Re-encode any
.xz/.lzmafiles you produced with a pre-0.3.4 oxiarc if you need them to open in liblzma-based tools — the old encoder embedded an EOS marker inside LZMA2 chunks that liblzma rejects as corrupt. - If you’ve stored Japanese filenames in ZIP or LZH archives, upgrade before writing new ones. The new
name_codecmodules and EFS-flag writer fix are what make those names round-trip correctly throughbsdtar, Python’szipfile, and standard LHA tools. -lh1-archives now decode. If you’ve been hitting “unsupported method” on older LZH archives, 0.3.4 adds the decoder plus a spec-conformant encoder for producing them.SevenZReader::extractnow errors on CRC mismatch instead of silently returning unverified data — treat a CRC error as a signal to re-fetch the source archive, not a bug in oxiarc.- The interop suites are fully offline. You don’t need liblzma, libbz2, or bsdtar installed to run
cargo test— every golden vector is committed as binary test data generated once during development.
This is the foundation
Real-world interoperability is what lets OxiArc sit underneath the rest of the ecosystem without surprises: FVRS integration testing is what surfaced these defects in the first place, and the same LZMA/bzip2/7z/ZIP/TAR/XZ paths are exercised by OxiMedia, SciRS2/NumRS2, RusMES, OxiGDAL, and ToRSh wherever they read or write archives that also need to open correctly outside the COOLJAPAN ecosystem.
Repository: https://github.com/cool-japan/oxiarc
Star the repo if you want an archiver that doesn’t just agree with itself, but actually speaks the formats other tools speak too.
The era of “close enough to the spec” is over. Pure Rust archiving that’s byte-for-byte compatible is here.
— KitaSan at COOLJAPAN OÜ July 6, 2026