Skip to main content

Module mar

Module mar 

Source
Expand description

MAR archive reader + writer (classic Mac, Hampa Hug’s mar tool).

A .mar archive stores a single Mac item — a file or a folder tree — with both forks, type/creator, Finder flags, and 1904-epoch dates. It is the native format of the mar MPW/Mac tool. Layout (all fields big-endian):

[128-byte record header] [data block] [rsrc block] [comment block] ...

Each record header is 128 bytes: 0 u32 magic ‘MAR\x80’ (0x4d415280) 4 u32 id: ‘file’ (file) | ‘fold’ (folder start) | ‘––’ (folder end) 8 pstr name (length byte + up to 63 Mac-Roman bytes, 64 bytes total) 72 u32 data fork size 76 u32 rsrc fork size 80 u32 comment size 84 u32 file flags (bit0 = locked) 88 u32 create date (Mac 1904) 92 u32 mod date 96 16 FInfo/DInfo: type@96 creator@100 finderFlags@104 … 124 u32 header CRC (over bytes 0..124)

A file header is followed by its data, resource, and comment blocks (each present only when its size > 0). A block is [payload][u32 CRC][zero pad], padded so payload + 4 + pad is a multiple of 128. A fold header is followed by its children (more records) terminated by a ---- header.

The whole byte stream may be wrapped in LZW (Unix compress, magic 1f 9d) or an LZ4 frame (magic 04 22 4d 18); an unwrapped archive starts directly with the first record’s MAR\x80. We read/write the stored (unwrapped) form; a compressed archive is detected and reported (not silently mis-read).

Both CRCs use a non-reflected CRC-32 with the Castagnoli polynomial 0x1edc6f41 (init 0, no xorout) — mar’s own checksum, distinct from the StuffIt/Compact-Pro fork checksums.

Clean-room Rust from the format as described by the GPL-2.0 mar-0.2.0 sources (Hampa Hug); no code is copied. Forks are decoded eagerly into a buffer and exposed through the shared StuffItArchive model (stored forks, offsets into the returned buffer) so the existing extract / browse / CLI path handles MAR with no special case — exactly like the loose-BinHex synthesis in super::extract.

Functions§

build_archive
Build a stored MAR archive. A MAR holds a single root item: with one input node the node becomes the root; with several, they’re wrapped in a folder named root_name. Forks are stored uncompressed (this tool never writes the optional LZW/LZ4 wrapper). The result round-trips through parse and is read by the mar tool.
is_mar
Detect a stored (unwrapped) MAR archive by its first record header. Compressed wrappers are intentionally not reported here — parse surfaces them with a clear “not yet supported” message rather than a detection false-positive on the generic LZW/LZ4 magics.
parse
Parse a MAR archive. Returns the decoded byte buffer (fork offsets in the entries are absolute within it) plus the parsed directory — the same (Vec<u8>, StuffItArchive) shape every other Mac-archive parser returns, so super::extract handles it unchanged. Forks are modelled as stored (method 0) over the returned buffer; each fork’s MAR CRC-32 is verified here.