Skip to content

Repository files navigation

nx-object

Zero-copy parsing and generation of Nintendo Switch file formats.

Turns a byte buffer into a validated view of every format it covers, and builds each of them back out of its parts. Nothing is copied to read an image and nothing is written to disk to produce one, so the same definitions serve a host-side packer and code running on the console.

Layers

The crate is organized in three layers, each usable on its own:

  • raw -- #[repr(C)] binary structure definitions backed by zerocopy. Direct field access, no parsing overhead, no allocator.
  • read -- Parsing wrappers over the raw structures. Validate magic numbers and sizes once, then hand out parts without further checks, and report a typed error per format. No allocator.
  • write -- Builders that assemble a format and return the finished image as a byte buffer, so the caller chooses where the artifact lands. Needs a heap; the builders that walk a directory need a filesystem too.

A fourth module, elf, extracts the segments of a linked ELF binary and hands them to the NRO and NSO builders.

Formats

Format Description raw read write
NRO Nintendo Relocatable Object (homebrew) ✓ ✓ ✓
NSO Nintendo Software Object (system module) ✓ ✓ ✓
KIP Kernel Initial Process ✓ ✓ ✓
NACP Nintendo Application Control Property ✓ ✓ ✓
NPDM Nintendo Program Description Metadata ✓ ✓ ✓
RomFS Read-only filesystem image ✓ ✓ ✓
PFS0 Partition filesystem archive ✓ ✓ ✓
MOD0 Module header embedded in executables ✓ ✓
NCA Nintendo Content Archive ✓ ✓ ✓
CNMT Content meta naming every NCA of a title ✓ ✓ ✓

What this crate does not do

It does not sign, encrypt, or verify anything: an NPDM's ACID signature is stored and reproduced but never checked, and an NSO's segment hashes are computed on write yet left to the caller on read.

It does decompress, but never behind an accessor. A reader borrows its buffer and has nowhere to put expanded bytes, so expanding is a separate call that allocates and can fail -- Kip1Segment and Nso each offer one, and a segment slice always comes back exactly as the file stores it.

NCA is where the encryption line is most visible, because an NCA on disk is encrypted throughout. NcaBuilder produces the plaintext container and every hash covering it, then names what is still owed; the caller supplies the keyset and the ciphers. Reading runs the same way in reverse: Nca takes a buffer the caller has already decrypted, and an image still in ciphertext fails its magic check rather than parsing into nonsense. Hashing stays here because a hash is part of the layout -- it is what makes the recorded offsets checkable -- while encryption is a transformation applied to a layout that is already correct.

Usage

[dependencies]
nx-object = { git = "https://github.com/nx-std/nx-object" }

The default build carries every format and the standard library. A consumer that wants less -- one format, or a build with no allocator and no OS -- selects it through the crate's Cargo features, which are documented on each entry in Cargo.toml.

Development

just check --all-targets --all-features   # compile check
just clippy --all-targets --all-features  # lint
just test --all-features                  # cargo nextest run (falls back to cargo test)
just check-unused-deps                    # cargo machete
just fmt                                  # cargo +nightly fmt --all

# The bare-metal half, the way CI builds it
just check --no-default-features --features all-formats,alloc --target aarch64-unknown-none
just clippy --no-default-features --features all-formats,alloc --target aarch64-unknown-none

References

Every format the crate covers is documented on the switchbrew wiki, except RomFS, whose layout the console inherits unchanged from the 3DS.

License

MIT. See LICENSE.

About

Zero-copy parsing and generation of Nintendo Switch file formats

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Contributors

Languages