One module per supported format. Each exposes a single entry point:
pub fn apply(patch: &[u8], rom: &[u8]) -> Result<Vec<u8>>;Detection lives in mod.rs and probes magic bytes in an order that
disambiguates overlapping prefixes (APS10 must be checked before APS1).
| Module | Magic | Notes |
|---|---|---|
ips.rs |
PATCH |
24-bit BE offsets, 16-bit BE size, optional RLE (size=0), EOF terminator |
ups.rs |
UPS1 |
byuu VLV header (input/output size), XOR delta body, three CRC32s in footer |
bps.rs |
BPS1 |
byuu VLV header, action stream (SourceRead/TargetRead/SourceCopy/TargetCopy), three CRC32s in footer |
pmsr.rs |
PMSR |
Paper Mario Star Rod; record list + CRC32 ROM check |
aps.rs |
APS1/APS10 |
Two variants: GBA (12-byte header + 64 KiB XOR records) and N64 (variable header + offset+length records). See module header doc for details. |
ppf.rs |
PPF |
v1 / v2 / v3. v3 carries 64-bit offsets, BIN/GI image-type byte, optional block check + undo data |
rup.rs |
NINJA2 |
NINJA-2 sequential XOR delta with custom VLV; MD5 integrity |
bdf.rs |
BSDIFF40 |
bsdiff: 32-byte header with three signed 8-byte size fields, three concatenated bzip2 streams (control / diff / extra) |
-
VCDIFF/xdelta - deferred entirely from v1. RomPatcher.js does not ship vendorable test fixtures (their harness needs a copyrighted DS ROM plus a romhacking.net patch). Without
xdelta3-cross-checked fixtures we cannot verify our parser against anything but our own reading of RFC 3284, which is not enough confidence to ship. Users with.xdeltapatches fall back to the upstreamxdelta3tool. -
EBP - listed in the original plan in error. EBP exists in CoilSnake's Python
EBPatcherbut does not exist in marcrobledo/RomPatcher.js (the reference we follow). Not in scope. -
ZIP input - deferred. Pure quality-of-life so that
rompatch apply rom.zip patch.bpswould work directly. No format unlock, just saves the user oneunzipcall.
All formats share:
BinReaderfrombin_filefor cursor-based reads, includingread_vlvfor byuu's variable-length encoding (UPS/BPS/RUP).- The
hashmodule for CRC32 (UPS/BPS/PMSR), MD5 (RUP), Adler32 (reserved), and SHA-1 (CLI verify). - The
PatchErrorenum fromerrorfor all parse and integrity failures.
- Add a
format/<name>.rsmodule exposingpub fn apply(patch: &[u8], rom: &[u8]) -> Result<Vec<u8>>. - Declare it in
mod.rsand add aFormatKindvariant +name()mapping. - Extend
detect()to recognize the magic; place the probe so that no later probe can shadow it. - Wire the kind into
apply()dispatch. - Wire it into the CLI:
commands/apply.rs::parse_formatplus the--formatdoc string in the help text. - If the format has a useful header, extend
info::describeto print it. - Add a fuzz target under
fuzz/fuzz_targets/.