Skip to content

feat(format): CAB and XAR read-only seek providers [RM-305]#68

Merged
P4suta merged 2 commits into
mainfrom
feature/dev-111-rm-305-cab-and-xar-read-only-providers
Jul 23, 2026
Merged

feat(format): CAB and XAR read-only seek providers [RM-305]#68
P4suta merged 2 commits into
mainfrom
feature/dev-111-rm-305-cab-and-xar-read-only-providers

Conversation

@P4suta

@P4suta P4suta commented Jul 23, 2026

Copy link
Copy Markdown
Owner

RM-305 / DEV-111 — CAB and XAR read-only providers

arca's first read-only built-in seek-native formats: Microsoft Cabinet (CAB) and eXtensible ARchive (XAR). Both decode through the always-on miniz_oxide codec, so they need no feature gate and stay pure-Rust / C-free on the portable profile.

Registration

FormatId::Cab / FormatId::Xar with MSCF / xar! probe signatures (core format.rs); decode-only FormatCapabilities::new(true, false, true) + format_name (provider.rs); a SeekDispatch::Cab/::Xar arm + signature detection in SeekArchiveReader::open (seek_stream.rs); mod cab/mod xar (lib.rs). Write is rejected without a bespoke path — the decode-only capability yields a typed Capability error and SeekArchiveWriter falls through to Unsupported.

CAB (cab.rs)

Bounded MSCF parser: CFHEADER (optional reserve + prev/next strings), CFFOLDER/CFFILE tables, per-folder CFDATA blocks, all within Limits; a folder decoded one block at a time (no whole folder materialised). Store copies through; MSZIP verifies the CK magic and inflates each block's raw DEFLATE while carrying the folder's 32 KiB LZ77 window across blocks via a fresh DecompressorOxide over a preserved wrapping ring. QUANTUM/LZX/cross-cabinet-continuation/spanning → structured Unsupported.

XAR (xar.rs)

Big-endian header locates the zlib TOC (inflated bounded by metadata_bytes, length-verified) and the heap (heap_start = header.size + toc_length_compressed). A hand-rolled bounded XML pull-scanner (DFS <file>-frame stack, no DOM / no XML crate) resolves each entry's /-joined path, emitting directories before children. Regular files stream their heap blob per entry as stored or zlib (x-gzip = RFC-1950, decoded as zlib not gzip), decoded length verified. x-bzip2 / unknown encodings / version ≠ 1 → structured Unsupported.

Tests & review

  • interop_cab_meta.rs / interop_xar_meta.rs: first-party in-code raw builders (independent DEFLATE/zlib via flate2, re-inflated by miniz_oxide → codec independence) read back through the RM-301 harness; content round trips + unsupported-method and truncated/out-of-range-header structured-error negatives.
  • A three-lens adversarial review (panic/bounds, spec-correctness, malformed-input) with a verification pass ran over both modules. Its one confirmed finding — XAR <ea> extended-attribute children overwriting a file's <data>/<name> (silent mis-read of valid macOS xars) — is fixed here (scope the scanner to ignore <ea> leaf capture) with a regression test. Minor findings (MSZIP wrapping-ring over-far-distance behaviour) are documented in the module.
  • forbid(unsafe) / no-dyn / bounded hold; no new dependency. just ci passed locally.

Note: CAB/XAR are decoders using in-code raw-builder fixtures for hermetic CI; per-format PROVENANCE.md documents the external independent producers (makecab/gcab/cabextract; xar CLI / bsdtar --format=xar) as the escape hatch.

🤖 Generated with Claude Code

P4suta and others added 2 commits July 23, 2026 10:40
Add arca's first read-only built-in seek-native formats: Microsoft Cabinet (CAB)
and eXtensible ARchive (XAR). Both decode through the always-on miniz_oxide codec,
so they need no feature gate and stay pure-Rust / C-free on the portable profile.

Registration: FormatId::Cab / FormatId::Xar with MSCF / xar! probe signatures
(core format.rs); decode-only capability FormatCapabilities::new(true, false, true)
and format_name (provider.rs); a SeekDispatch::Cab / ::Xar arm + signature
detection in SeekArchiveReader::open (seek_stream.rs); mod cab / mod xar (lib.rs).
Write is rejected without a bespoke path: the decode-only capability yields a typed
Capability error and SeekArchiveWriter falls through to Unsupported.

CAB (cab.rs): bounded MSCF parser — CFHEADER (with optional reserve + prev/next
strings), CFFOLDER / CFFILE tables, per-folder CFDATA blocks, all within Limits. A
folder is decoded one block at a time (no whole folder materialised). Store copies
through; MSZIP verifies the CK magic and inflates each block's raw DEFLATE while
carrying the folder's 32 KiB LZ77 window across blocks via a fresh DecompressorOxide
over a preserved wrapping ring. QUANTUM/LZX/cross-cabinet-continuation/spanning
blocks list metadata then surface structured Unsupported.

XAR (xar.rs): big-endian header locates the zlib TOC (inflated bounded by
metadata_bytes, length-verified) and the heap (heap_start = header.size +
toc_length_compressed). A hand-rolled bounded XML pull-scanner (DFS <file>-frame
stack, no DOM/xml crate) resolves each entry's /-joined path, emitting directories
before children. Regular files stream their heap blob per entry as stored or zlib
(x-gzip = RFC-1950, decoded as zlib not gzip), decoded length verified. x-bzip2 and
unknown encodings are structured Unsupported; version != 1 is Unsupported.

Tests: interop_cab_meta.rs / interop_xar_meta.rs build valid archives with
first-party in-code raw builders (independent DEFLATE/zlib via flate2, re-inflated
by miniz_oxide), read them back through the RM-301 harness, and assert content
round trips plus unsupported-method and truncated-header structured-error negatives.
A three-lens adversarial review with a verification pass ran over both modules; its
one confirmed finding — XAR <ea> extended-attribute children overwriting a file's
<data>/<name> — is fixed here (scope the pull-scanner to ignore <ea> leaf capture)
with a regression test. forbid(unsafe)/no-dyn/bounded hold; no new dependency.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@P4suta
P4suta enabled auto-merge (squash) July 23, 2026 03:53
@P4suta
P4suta merged commit 701edc7 into main Jul 23, 2026
22 checks passed
@P4suta
P4suta deleted the feature/dev-111-rm-305-cab-and-xar-read-only-providers branch July 23, 2026 04:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant