Skip to content

Development

clem-gb edited this page Oct 8, 2026 · 2 revisions

Development

Layout

File Role
src/main.rs Command line, extraction order, writing files, running the relinker
src/fih.rs FIH header and CNT container
src/pfs.rs Outer PFS: superblock, inodes, block lists, directory records
src/naps.rs NAPS layout parser
src/inner.rs Inner image: block map, block cache, file tree
src/kraken.rs Kraken decoder
src/selfelf.rs SELF → ELF unwrapping
src/source.rs Positional reads from the package
src/bytes.rs Endian field readers
src/error.rs The Error type: Io, Format, Unsupported

See Package Format for what each layer contains.

Build and check

cargo build --release
cargo test
cargo clippy --all-targets -- -D warnings
cargo fmt --check

CI runs these on every push and pull request: tests and a smoke test on Linux, Windows and macOS, clippy for both the Linux and Windows targets, and cargo test on Rust 1.88 (the minimum supported version). rustfmt.toml sets a 140-column width.

Platform-specific code is kept to two places: positional reads in src/source.rs (read_exact_at on Unix, a seek_read loop on Windows), and Windows path rules in is_windows_safe_path (src/main.rs).

Releasing

  1. Bump version in Cargo.toml and commit.
  2. Tag and push: git tag v0.2.0 && git push origin v0.2.0.
  3. The Release workflow tests and builds Linux (x86_64, aarch64, static musl), Windows (x86_64) and macOS (aarch64), then publishes a GitHub release with the archives, SHA256SUMS.txt and generated notes.

Project rules

  1. No guessing. A value that does not match the format is an error (Error::Format). A valid feature that is not implemented is Error::Unsupported. Never write a partial or guessed file.
  2. Untrusted input. Every header field is attacker-controlled. Use checked_add/checked_mul for offsets, check a size against the package (Source::read_vec) before allocating, and refuse output paths that fail is_plain_relative_path.
  3. No keys, no decryption. Encrypted data is refused. Pull requests adding keys or decryption will not be accepted; see Legal.
  4. Standard library only. No dependencies.

Tests

Unit tests sit next to the code (#[cfg(test)]) and use small hand-built byte buffers. No test needs a real package. When you fix a parser bug, add a test with the smallest input that triggered it.

To check against a real package, compare the output of --list, --executables-only and --only before and after your change. Do not commit package data or file listings of commercial games.

Clone this wiki locally