From b67f5178a61f6ebf44c59235e4a89d1f45c39336 Mon Sep 17 00:00:00 2001 From: Lorenzo Delgado Date: Thu, 13 Aug 2026 15:27:03 +0200 Subject: [PATCH] docs(nx-object): repoint the dead format references The README still described the layers by a feature that no longer exists, and a third of the wiki pages the crate cites have been renamed or removed since they were written, so a reader following one lands on a 404 rather than on the structure the code mirrors. - Rewrite the README against the current runtime tiers: `raw` and `read` need no allocator, `write` needs a heap, and only the `from_directory` builders need a filesystem. Drop the feature table, which restated what each feature's own doc comment already says. - Repoint every reference that moved: `KIP` to `KIP1`, the MOD0 header to `MOD`, and `PFS0` to the `NCA` page that absorbed it, along with the section anchors switchbrew renamed on the NRO, NSO, NACP and NPDM pages. - Cite the 3DS page for RomFS, whose layout the console inherits unchanged, since switchbrew documents the format nowhere. - Name the layers in the crate docs rather than linking them, so the table can describe the crate whole without a lean build leaving a link with nothing to resolve to. Signed-off-by: Lorenzo Delgado --- README.md | 61 ++++++++++++++++++++++++++++------------------- src/blz.rs | 2 +- src/lib.rs | 59 ++++++++++++++++++++++++--------------------- src/raw/kip.rs | 8 +++---- src/raw/mod0.rs | 4 ++-- src/raw/nacp.rs | 4 ++-- src/raw/npdm.rs | 8 +++---- src/raw/nro.rs | 12 +++++----- src/raw/nso.rs | 8 +++---- src/raw/pfs0.rs | 8 +++---- src/raw/romfs.rs | 12 +++++----- src/write/npdm.rs | 2 +- 12 files changed, 103 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index 89ce0c9..2ea1e2f 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,24 @@ Zero-copy parsing and generation of Nintendo Switch file formats. -The crate is `no_std` by default and opts into `std` through the `filesystem-support` feature, so the -same format definitions serve both host-side tooling and code running on the console. +Turns a byte buffer into a validated view of an NRO, NSO, NACP, NPDM, or RomFS image, and builds each +of those formats 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, always available. -- **`read`** -- Parsing wrappers over the raw structures. Validate magic numbers and sizes, and report - a typed error per format. Always available. -- **`write`** -- Builders that assemble a format and return the finished image as a byte buffer, so the - caller chooses where the artifact lands. Requires `filesystem-support`. + 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 @@ -29,15 +34,12 @@ The crate is organized in three layers, each usable on its own: | PFS0 | Partition filesystem archive | ✓ | | ✓ | | MOD0 | Module header embedded in executables | ✓ | ✓ | | -## Features - -| Feature | Description | -|----------------------|----------------------------------------------------------------------------| -| `filesystem-support` | Enables the `write` layer and `std`. Required by the other features. | -| `elf-parsing` | Derives NRO and NSO segments from a linked ELF binary (`elf` module). | -| `lz4-compression` | LZ4 compression and decompression of NSO segments. | +## What this crate does not do -No features are enabled by default; that configuration is `no_std`. +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 +also does not decompress, because a reader that borrows its buffer has nowhere to put the expanded +bytes. ## Usage @@ -46,30 +48,41 @@ No features are enabled by default; that configuration is `no_std`. 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`](Cargo.toml). + ## Development ```bash 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 no_std half, the way CI builds it -just check --no-default-features --target aarch64-unknown-none -just clippy --no-default-features --target aarch64-unknown-none +# 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 -- [switchbrew NRO](https://switchbrew.org/wiki/NRO) -- [switchbrew NSO](https://switchbrew.org/wiki/NSO) -- [switchbrew KIP](https://switchbrew.org/wiki/KIP) -- [switchbrew NACP](https://switchbrew.org/wiki/NACP) -- [switchbrew NPDM](https://switchbrew.org/wiki/NPDM) -- [switchbrew RomFS](https://switchbrew.org/wiki/RomFS) +Every format the crate covers is documented on the [switchbrew] wiki, except RomFS, whose layout the +console inherits unchanged from the 3DS. + +- [NRO](https://switchbrew.org/wiki/NRO) +- [NSO](https://switchbrew.org/wiki/NSO) +- [KIP1](https://switchbrew.org/wiki/KIP1) +- [NACP](https://switchbrew.org/wiki/NACP) +- [NPDM](https://switchbrew.org/wiki/NPDM) +- [PFS0](https://switchbrew.org/wiki/NCA#PFS0) +- [MOD](https://switchbrew.org/wiki/MOD) +- [RomFS](https://www.3dbrew.org/wiki/RomFS) ## License MIT. See [LICENSE](LICENSE). [`zerocopy`]: https://docs.rs/zerocopy +[switchbrew]: https://switchbrew.org/wiki/Main_Page diff --git a/src/blz.rs b/src/blz.rs index 0900a89..ad18051 100644 --- a/src/blz.rs +++ b/src/blz.rs @@ -78,7 +78,7 @@ //! //! # References //! -//! - +//! - use alloc::{vec, vec::Vec}; diff --git a/src/lib.rs b/src/lib.rs index 4f8c7fc..8d56bff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,26 +10,29 @@ //! Each layer is usable on its own, and each is a different answer to how much the caller wants //! done for them. //! -//! | Layer | What it gives you | Available | -//! |---------------|--------------------------------------------------------------|----------------------| -//! | [`mod@raw`] | The on-disk layouts as `#[repr(C)]` structures, unvalidated | always | -//! | [`mod@read`] | Views that validate once, then hand out parts without checks | always | -//! | [`mod@write`] | Builders returning a finished image as a byte buffer | `alloc` | -//! | [`mod@elf`] | Segments extracted from a linked ELF, ready for a builder | `elf-parsing` | +//! | Layer | What it gives you | Available | +//! |---------|--------------------------------------------------------------|---------------| +//! | `raw` | The on-disk layouts as `#[repr(C)]` structures, unvalidated | always | +//! | `read` | Views that validate once, then hand out parts without checks | always | +//! | `write` | Builders returning a finished image as a byte buffer | `alloc` | +//! | `elf` | Segments extracted from a linked ELF, ready for a builder | `elf-parsing` | //! -//! Reach for [`mod@raw`] to inspect a field directly, and for [`mod@read`] to be told when the image -//! is not what it claims. A [`mod@read`] type that exists is one whose bounds have been proven, -//! which is why its accessors return plain slices rather than `Result`. +//! Reach for `raw` to inspect a field directly, and for `read` to be told when the image is not what +//! it claims. A `read` type that exists is one whose bounds have been proven, which is why its +//! accessors return plain slices rather than `Result`. +//! +//! The layers are named here rather than linked, because a build that leaves `write` or `elf` out +//! would have nothing for the link to resolve to and the table describes the crate whole. //! //! # `no_std` //! //! The crate is `no_std` unless `std` is enabled, and it needs an allocator only where the work //! genuinely does. Three tiers, each a feature: //! -//! - **Bare `no_std`** gives [`mod@raw`] and [`mod@read`]. Parsing borrows the buffer it is handed, -//! so it allocates nothing at all. -//! - **`alloc`** adds [`mod@write`]. A builder has to put the assembled bytes somewhere, and a heap -//! is the whole of what it needs. +//! - **Bare `no_std`** gives `raw` and `read`. Parsing borrows the buffer it is handed, so it +//! allocates nothing at all. +//! - **`alloc`** adds `write`. A builder has to put the assembled bytes somewhere, and a heap is the +//! whole of what it needs. //! - **`std`** adds the `from_directory` builders and the path-carrying errors they report, which //! are the only things here that touch a filesystem. //! @@ -38,16 +41,16 @@ //! //! # Formats //! -//! | Format | What it is | [`mod@raw`] | [`mod@read`] | [`mod@write`] | -//! |--------|-----------------------------------------------|:-----------:|:------------:|:-------------:| -//! | NRO | The executable the homebrew menu launches | ✓ | ✓ | ✓ | -//! | NSO | The executable format system modules use | ✓ | ✓ | ✓ | -//! | KIP | An initial process the kernel starts directly | ✓ | | ✓ | -//! | NACP | How a title is presented and what it may do | ✓ | ✓ | ✓ | -//! | NPDM | The permissions a program is granted | ✓ | ✓ | ✓ | -//! | RomFS | The read-only filesystem a title ships | ✓ | ✓ | ✓ | -//! | PFS0 | The flat archive an NSP is built from | ✓ | | ✓ | -//! | MOD0 | The runtime header embedded in an executable | ✓ | ✓ | | +//! | Format | What it is | `raw` | `read` | `write` | +//! |--------|-----------------------------------------------|:-----:|:------:|:-------:| +//! | NRO | The executable the homebrew menu launches | ✓ | ✓ | ✓ | +//! | NSO | The executable format system modules use | ✓ | ✓ | ✓ | +//! | KIP | An initial process the kernel starts directly | ✓ | | ✓ | +//! | NACP | How a title is presented and what it may do | ✓ | ✓ | ✓ | +//! | NPDM | The permissions a program is granted | ✓ | ✓ | ✓ | +//! | RomFS | The read-only filesystem a title ships | ✓ | ✓ | ✓ | +//! | PFS0 | The flat archive an NSP is built from | ✓ | | ✓ | +//! | MOD0 | The runtime header embedded in an executable | ✓ | ✓ | | //! //! # What this crate does not do //! @@ -59,15 +62,17 @@ //! # References //! //! Every format is documented on the switchbrew wiki, and each module links the page for the -//! structure it mirrors. +//! structure it mirrors. RomFS is the exception: switchbrew has no page for it, and the layout is +//! the one the console inherits unchanged from the 3DS. //! //! - [NRO](https://switchbrew.org/wiki/NRO) //! - [NSO](https://switchbrew.org/wiki/NSO) -//! - [KIP](https://switchbrew.org/wiki/KIP) +//! - [KIP1](https://switchbrew.org/wiki/KIP1) //! - [NACP](https://switchbrew.org/wiki/NACP) //! - [NPDM](https://switchbrew.org/wiki/NPDM) -//! - [RomFS](https://switchbrew.org/wiki/RomFS) -//! - [PFS0](https://switchbrew.org/wiki/PFS0) +//! - [MOD](https://switchbrew.org/wiki/MOD) +//! - [PFS0](https://switchbrew.org/wiki/NCA#PFS0) +//! - [RomFS](https://www.3dbrew.org/wiki/RomFS) #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] diff --git a/src/raw/kip.rs b/src/raw/kip.rs index 1295840..2ecc91b 100644 --- a/src/raw/kip.rs +++ b/src/raw/kip.rs @@ -19,7 +19,7 @@ pub const KIP1_MAGIC: u32 = 0x3150494b; /// stored length to find the compressed bytes and the final length to know how much room to leave. /// When the segment's compression bit in [`Kip1Header::flags`] is clear, the two are equal. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, zerocopy::FromZeros, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] pub struct Kip1Segment { @@ -36,7 +36,7 @@ pub struct Kip1Segment { pub attributes: U32, } -// Verify struct size - https://switchbrew.org/wiki/KIP#Segment_Header +// Verify struct size - https://switchbrew.org/wiki/KIP1#Segment_Header const_assert_eq!(size_of::(), 0x10); const_assert_eq!(align_of::(), 0x1); @@ -46,7 +46,7 @@ const_assert_eq!(align_of::(), 0x1); /// Occupies the first `0x100` bytes of the file. A KIP is launched by the kernel before any /// filesystem exists, so the header carries what a loader would otherwise read from an NPDM. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, zerocopy::FromZeros, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] pub struct Kip1Header { @@ -79,6 +79,6 @@ pub struct Kip1Header { pub capabilities: [u8; 0x80], } -// Verify struct size - https://switchbrew.org/wiki/KIP#KIP_Header +// Verify struct size - https://switchbrew.org/wiki/KIP1#KIP1 const_assert_eq!(size_of::(), 0x100); const_assert_eq!(align_of::(), 0x1); diff --git a/src/raw/mod0.rs b/src/raw/mod0.rs index deebbd0..693ee35 100644 --- a/src/raw/mod0.rs +++ b/src/raw/mod0.rs @@ -23,7 +23,7 @@ pub const MOD0_MAGIC: u32 = 0x30444f4d; /// /// [`NroStart::mod_offset`]: crate::raw::nro::NroStart::mod_offset /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct Mod0Header { @@ -45,6 +45,6 @@ pub struct Mod0Header { pub module_object_offset: I32, } -// Verify struct size - https://switchbrew.org/wiki/NRO#MOD +// Verify struct size - https://switchbrew.org/wiki/MOD#ModuleHeader const_assert_eq!(size_of::(), 0x1C); const_assert_eq!(align_of::(), 0x1); diff --git a/src/raw/nacp.rs b/src/raw/nacp.rs index 99e83cf..3b13243 100644 --- a/src/raw/nacp.rs +++ b/src/raw/nacp.rs @@ -19,7 +19,7 @@ use zerocopy::{ /// indexing rather than by searching. An entry left zeroed means the title offers no name in that /// language and the console falls back to another. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct NacpLanguageEntry { @@ -29,7 +29,7 @@ pub struct NacpLanguageEntry { pub author: [u8; 0x100], } -// Verify struct size - https://switchbrew.org/wiki/NACP#Title +// Verify struct size - https://switchbrew.org/wiki/NACP#ApplicationTitle const_assert_eq!(size_of::(), 0x300); const_assert_eq!(align_of::(), 0x1); diff --git a/src/raw/npdm.rs b/src/raw/npdm.rs index e7c8de0..d68e670 100644 --- a/src/raw/npdm.rs +++ b/src/raw/npdm.rs @@ -76,7 +76,7 @@ const_assert_eq!(align_of::(), 0x1); /// signature is what makes that binding. ACI0 then requests some subset of it, and the loader /// rejects a program asking for more than its ACID allows. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct AcidHeader { @@ -112,7 +112,7 @@ pub struct AcidHeader { _reserved_238: U64, } -// Verify struct size - https://switchbrew.org/wiki/NPDM#ACID +// Verify struct size - https://switchbrew.org/wiki/NPDM#Acid const_assert_eq!(size_of::(), 0x240); const_assert_eq!(align_of::(), 0x1); @@ -122,7 +122,7 @@ const_assert_eq!(align_of::(), 0x1); /// is checked against it at load, so nothing here grants anything the descriptor did not already /// allow. Its blocks are laid out identically, which is what lets the loader compare them directly. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct Aci0Header { @@ -147,6 +147,6 @@ pub struct Aci0Header { _reserved_38: U64, } -// Verify struct size - https://switchbrew.org/wiki/NPDM#ACI0 +// Verify struct size - https://switchbrew.org/wiki/NPDM#Aci const_assert_eq!(size_of::(), 0x40); const_assert_eq!(align_of::(), 0x1); diff --git a/src/raw/nro.rs b/src/raw/nro.rs index 4e437b7..649c991 100644 --- a/src/raw/nro.rs +++ b/src/raw/nro.rs @@ -29,7 +29,7 @@ pub const ASSET_MAGIC: u32 = 0x54455341; /// The three segments of an NRO appear in [`NroHeader::segments`] in load order: `text`, `rodata`, `data`. /// Each is mapped with its own permissions, so a segment's bounds decide which pages are executable. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct NroSegment { @@ -39,7 +39,7 @@ pub struct NroSegment { pub size: U32, } -// Verify struct size - https://switchbrew.org/wiki/NRO#Segments +// Verify struct size - https://switchbrew.org/wiki/NRO#NroHeader const_assert_eq!(size_of::(), 0x8); const_assert_eq!(align_of::(), 0x1); @@ -49,7 +49,7 @@ const_assert_eq!(align_of::(), 0x1); /// A homebrew NRO puts its crt0 branch here; preserving those bytes is what keeps an NRO /// launchable after a rewrite. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct NroStart { @@ -63,7 +63,7 @@ pub struct NroStart { _padding: [u8; 8], } -// Verify struct size - https://switchbrew.org/wiki/NRO#Start +// Verify struct size - https://switchbrew.org/wiki/NRO#RocrtHeader const_assert_eq!(size_of::(), 0x10); const_assert_eq!(align_of::(), 0x1); @@ -71,7 +71,7 @@ const_assert_eq!(align_of::(), 0x1); /// /// Sits at offset `0x10`, immediately after [`NroStart`]. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct NroHeader { @@ -101,7 +101,7 @@ pub struct NroHeader { _reserved2: [u8; 0x20], } -// Verify struct size - https://switchbrew.org/wiki/NRO#Header +// Verify struct size - https://switchbrew.org/wiki/NRO#NroHeader const_assert_eq!(size_of::(), 0x70); const_assert_eq!(align_of::(), 0x1); diff --git a/src/raw/nso.rs b/src/raw/nso.rs index ca822ac..47b1d55 100644 --- a/src/raw/nso.rs +++ b/src/raw/nso.rs @@ -42,7 +42,7 @@ bitflags! { /// Where one segment sits in the file, where it lands in memory, and how large it is once expanded. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct NsoSegmentHeader { @@ -58,7 +58,7 @@ pub struct NsoSegmentHeader { pub size: U32, } -// Verify struct size - https://switchbrew.org/wiki/NSO#Segment_Header +// Verify struct size - https://switchbrew.org/wiki/NSO#NsoHeader const_assert_eq!(size_of::(), 0xC); const_assert_eq!(align_of::(), 0x1); @@ -67,7 +67,7 @@ const_assert_eq!(align_of::(), 0x1); /// Occupies the first `0x100` bytes of the file. Unlike an NRO, an NSO opens with its magic rather /// than with code, and its segments may be compressed and verified individually. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct NsoHeader { @@ -119,6 +119,6 @@ pub struct NsoHeader { pub data_hash: [u8; 0x20], } -// Verify struct size - https://switchbrew.org/wiki/NSO#Header +// Verify struct size - https://switchbrew.org/wiki/NSO#NsoHeader const_assert_eq!(size_of::(), 0x100); const_assert_eq!(align_of::(), 0x1); diff --git a/src/raw/pfs0.rs b/src/raw/pfs0.rs index 3041f2b..7e989ec 100644 --- a/src/raw/pfs0.rs +++ b/src/raw/pfs0.rs @@ -26,7 +26,7 @@ pub const PFS0_MAGIC: u32 = 0x30534650; /// and `string_table_size`. Both fields are therefore load-bearing, and a wrong one shifts every /// file in the archive. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct Pfs0Header { @@ -40,7 +40,7 @@ pub struct Pfs0Header { pub _reserved: U32, } -// Verify struct size - https://switchbrew.org/wiki/PFS0#Header +// Verify struct size - https://switchbrew.org/wiki/NCA#PFS0 const_assert_eq!(size_of::(), 0x10); const_assert_eq!(align_of::(), 0x1); @@ -49,7 +49,7 @@ const_assert_eq!(align_of::(), 0x1); /// Entries sit in a table immediately after [`Pfs0Header`], in the same order as the files in the /// data region. Neither offset is absolute, and the two are measured from different origins. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct Pfs0FileEntry { @@ -66,6 +66,6 @@ pub struct Pfs0FileEntry { pub _reserved: U32, } -// Verify struct size - https://switchbrew.org/wiki/PFS0#File_Entry +// Verify struct size - https://switchbrew.org/wiki/NCA#PartitionEntry const_assert_eq!(size_of::(), 0x18); const_assert_eq!(align_of::(), 0x1); diff --git a/src/raw/romfs.rs b/src/raw/romfs.rs index 39dbf7d..c92be13 100644 --- a/src/raw/romfs.rs +++ b/src/raw/romfs.rs @@ -28,7 +28,7 @@ pub const NO_ENTRY: u32 = 0xFFFF_FFFF; /// probe, and the metadata tables hold the entries themselves; a lookup reads the hash table to /// find a candidate entry, then walks the chain in the metadata table. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct RomFsHeader { @@ -57,7 +57,7 @@ pub struct RomFsHeader { pub file_data_offset: U64, } -// Verify struct size - https://switchbrew.org/wiki/RomFS#Header +// Verify struct size - https://www.3dbrew.org/wiki/RomFS#Level_3_Header_Format const_assert_eq!(size_of::(), 0x50); const_assert_eq!(align_of::(), 0x1); @@ -70,7 +70,7 @@ const_assert_eq!(align_of::(), 0x1); /// /// The `0x18` bytes asserted below are the fixed prefix only; the entry's name follows it inline. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct RomFsDirEntry { @@ -89,7 +89,7 @@ pub struct RomFsDirEntry { // The UTF-8 name follows inline, padded to a 4-byte boundary. } -// Verify struct size - https://switchbrew.org/wiki/RomFS#Directory_Entry +// Verify struct size - https://www.3dbrew.org/wiki/RomFS#Directory_Metadata_Structure const_assert_eq!(size_of::(), 0x18); const_assert_eq!(align_of::(), 0x1); @@ -101,7 +101,7 @@ const_assert_eq!(align_of::(), 0x1); /// /// The `0x20` bytes asserted below are the fixed prefix only; the entry's name follows it inline. /// -/// See . +/// See . #[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)] #[repr(C)] pub struct RomFsFileEntry { @@ -120,7 +120,7 @@ pub struct RomFsFileEntry { // The UTF-8 name follows inline, padded to a 4-byte boundary. } -// Verify struct size - https://switchbrew.org/wiki/RomFS#File_Entry +// Verify struct size - https://www.3dbrew.org/wiki/RomFS#File_Metadata_Structure const_assert_eq!(size_of::(), 0x20); const_assert_eq!(align_of::(), 0x1); diff --git a/src/write/npdm.rs b/src/write/npdm.rs index 0b89312..0cbc1aa 100644 --- a/src/write/npdm.rs +++ b/src/write/npdm.rs @@ -32,7 +32,7 @@ pub struct MapRegionDescriptor { /// format defined by the Nintendo Switch kernel. The encoding includes a trailing /// bit pattern that identifies the capability type. /// -/// See: +/// See: #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(