From e8e10e9e5d1479549072b8aed48c20102c57256d Mon Sep 17 00:00:00 2001 From: Aetias Date: Sun, 23 Nov 2025 11:48:40 +0100 Subject: [PATCH 01/16] Format --- lib/src/rom/overlay_table.rs | 3 +-- lib/src/rom/raw/overlay.rs | 3 +-- lib/src/rom/raw/overlay_table.rs | 3 +-- lib/src/rom/raw/rom.rs | 32 +++++++++++++------------------- lib/src/rom/rom.rs | 13 ++++--------- 5 files changed, 20 insertions(+), 34 deletions(-) diff --git a/lib/src/rom/overlay_table.rs b/lib/src/rom/overlay_table.rs index fb7ecae..2fa71a6 100644 --- a/lib/src/rom/overlay_table.rs +++ b/lib/src/rom/overlay_table.rs @@ -1,9 +1,8 @@ -use crate::crypto::hmac_sha1::HmacSha1; - use super::{ raw::{self, HmacSha1Signature}, Arm9, Overlay, OverlayError, }; +use crate::crypto::hmac_sha1::HmacSha1; /// An overlay table, used for both ARM9 and ARM7 overlays. This is the plain struct, see the raw one [here](super::raw::OverlayTable). #[derive(Clone, Default)] diff --git a/lib/src/rom/raw/overlay.rs b/lib/src/rom/raw/overlay.rs index 421be3f..54aa1c6 100644 --- a/lib/src/rom/raw/overlay.rs +++ b/lib/src/rom/raw/overlay.rs @@ -7,9 +7,8 @@ use bitfield_struct::bitfield; use bytemuck::{Pod, PodCastError, Zeroable}; use snafu::{Backtrace, Snafu}; -use crate::rom::Arm9OverlaySignaturesError; - use super::{RawArm9Error, RawHeaderError}; +use crate::rom::Arm9OverlaySignaturesError; /// An entry in an overlay table. This is the raw struct, see the plain one [here](super::super::Overlay). #[repr(C)] diff --git a/lib/src/rom/raw/overlay_table.rs b/lib/src/rom/raw/overlay_table.rs index 637224e..abd30f2 100644 --- a/lib/src/rom/raw/overlay_table.rs +++ b/lib/src/rom/raw/overlay_table.rs @@ -1,8 +1,7 @@ use std::{borrow::Cow, fmt::Display}; -use crate::crypto::hmac_sha1::HmacSha1; - use super::{HmacSha1Signature, Overlay}; +use crate::crypto::hmac_sha1::HmacSha1; /// An overlay table, used for both ARM9 and ARM7 overlays. This is the raw struct, see the plain one [here](crate::rom::OverlayTable). pub struct OverlayTable<'a> { diff --git a/lib/src/rom/raw/rom.rs b/lib/src/rom/raw/rom.rs index 90146da..5645df1 100644 --- a/lib/src/rom/raw/rom.rs +++ b/lib/src/rom/raw/rom.rs @@ -118,16 +118,13 @@ impl<'a> Rom<'a> { header.arm9_build_info_offset }; - Ok(Arm9::new( - Cow::Borrowed(data), - Arm9Offsets { - base_address: header.arm9.base_addr, - entry_function: header.arm9.entry, - build_info: build_info_offset, - autoload_callback: header.arm9_autoload_callback, - overlay_signatures: footer.overlay_signatures_offset, - }, - )?) + Ok(Arm9::new(Cow::Borrowed(data), Arm9Offsets { + base_address: header.arm9.base_addr, + entry_function: header.arm9.entry, + build_info: build_info_offset, + autoload_callback: header.arm9_autoload_callback, + overlay_signatures: footer.overlay_signatures_offset, + })?) } /// Returns a reference to the ARM9 footer of this [`Rom`]. @@ -220,15 +217,12 @@ impl<'a> Rom<'a> { let build_info_offset = if header.arm7_build_info_offset == 0 { 0 } else { header.arm7_build_info_offset - header.arm7.offset }; - Ok(Arm7::new( - Cow::Borrowed(data), - Arm7Offsets { - base_address: header.arm7.base_addr, - entry_function: header.arm7.entry, - build_info: build_info_offset, - autoload_callback: header.arm7_autoload_callback, - }, - )) + Ok(Arm7::new(Cow::Borrowed(data), Arm7Offsets { + base_address: header.arm7.base_addr, + entry_function: header.arm7.entry, + build_info: build_info_offset, + autoload_callback: header.arm7_autoload_callback, + })) } /// Returns the ARM7 overlay table of this [`Rom`]. diff --git a/lib/src/rom/rom.rs b/lib/src/rom/rom.rs index efe47aa..2835283 100644 --- a/lib/src/rom/rom.rs +++ b/lib/src/rom/rom.rs @@ -370,15 +370,10 @@ impl<'a> Rom<'a> { }; // --------------------- Build ARM9 program --------------------- - let mut arm9 = Arm9::with_autoloads( - arm9, - &autoloads, - arm9_build_config.offsets, - Arm9WithTcmsOptions { - originally_compressed: arm9_build_config.compressed, - originally_encrypted: arm9_build_config.encrypted, - }, - )?; + let mut arm9 = Arm9::with_autoloads(arm9, &autoloads, arm9_build_config.offsets, Arm9WithTcmsOptions { + originally_compressed: arm9_build_config.compressed, + originally_encrypted: arm9_build_config.encrypted, + })?; arm9_build_config.build_info.assign_to_raw(arm9.build_info_mut()?); arm9.update_overlay_signatures(&arm9_overlays)?; if arm9_build_config.compressed && options.compress { From 647cfaf0215a09d150c19adc3182679ced68f294 Mon Sep 17 00:00:00 2001 From: Aetias Date: Sun, 23 Nov 2025 11:49:38 +0100 Subject: [PATCH 02/16] Expose hidden lifetime specifiers --- lib/src/rom/arm9.rs | 2 +- lib/src/rom/banner.rs | 2 +- lib/src/rom/file.rs | 10 +++++----- lib/src/rom/overlay_table.rs | 2 +- lib/src/rom/raw/arm9_footer.rs | 2 +- lib/src/rom/raw/autoload_info.rs | 2 +- lib/src/rom/raw/banner.rs | 2 +- lib/src/rom/raw/build_info.rs | 2 +- lib/src/rom/raw/fnt.rs | 2 +- lib/src/rom/raw/header.rs | 6 +++--- lib/src/rom/raw/overlay.rs | 2 +- lib/src/rom/raw/rom.rs | 14 +++++++------- lib/src/rom/rom.rs | 12 ++++++------ 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lib/src/rom/arm9.rs b/lib/src/rom/arm9.rs index a1c4fa2..7919b7d 100644 --- a/lib/src/rom/arm9.rs +++ b/lib/src/rom/arm9.rs @@ -442,7 +442,7 @@ impl<'a> Arm9<'a> { /// /// This function will return an error if [`Self::build_info`] or [`Self::get_autoload_infos`] fails or this ARM9 program /// is compressed. - pub fn autoloads(&self) -> Result, Arm9AutoloadError> { + pub fn autoloads(&self) -> Result]>, Arm9AutoloadError> { let build_info = self.build_info()?; if build_info.is_compressed() { CompressedSnafu {}.fail()?; diff --git a/lib/src/rom/banner.rs b/lib/src/rom/banner.rs index e5c3b03..bbd4bea 100644 --- a/lib/src/rom/banner.rs +++ b/lib/src/rom/banner.rs @@ -98,7 +98,7 @@ impl Banner { /// /// This function will return an error if the banner version is not yet supported by this library, or there are too many /// keyframes. - pub fn build(&self) -> Result { + pub fn build(&self) -> Result, BannerError> { // TODO: Increase max version to Animated // The challenge is to convert the animated icon to indexed bitmaps. Each bitmap can use any of the 8 palettes at any // given time according to the keyframes. This means that to convert the PNG animation frames to indexed bitmaps, we diff --git a/lib/src/rom/file.rs b/lib/src/rom/file.rs index c57d3e6..ba9f4ae 100644 --- a/lib/src/rom/file.rs +++ b/lib/src/rom/file.rs @@ -158,7 +158,7 @@ impl<'a> FileSystem<'a> { } /// Returns a file. - pub fn file(&self, id: u16) -> &File { + pub fn file(&self, id: u16) -> &File<'a> { &self.files[id as usize - self.num_overlays] } @@ -237,7 +237,7 @@ impl<'a> FileSystem<'a> { } } - fn build_subtable(&self, parent: &Dir) -> Result { + fn build_subtable(&self, parent: &Dir) -> Result, FileBuildError> { let mut data = vec![]; for child in &parent.children { @@ -287,7 +287,7 @@ impl<'a> FileSystem<'a> { /// # Errors /// /// This function will return an error if a file/directory name contains non-ASCII characters. - pub fn build_fnt(&self) -> Result { + pub fn build_fnt(&self) -> Result, FileBuildError> { let mut subtables = vec![]; self.build_fnt_recursive(&mut subtables, ROOT_DIR_ID)?; Ok(Fnt { subtables: subtables.into_boxed_slice() }) @@ -385,7 +385,7 @@ impl<'a> FileSystem<'a> { self.dirs.last().unwrap() } - fn make_child_file(&mut self, name: String, parent_id: u16, contents: Vec) -> &File { + fn make_child_file(&mut self, name: String, parent_id: u16, contents: Vec) -> &File<'a> { let id = self.next_file_id; self.files.push(File { id, name, original_offset: 0, contents: contents.into() }); let parent = self.dir_mut(parent_id); @@ -471,7 +471,7 @@ impl<'a> FileSystem<'a> { } /// Creates a [`DisplayFileSystem`] which implements [`Display`]. - pub fn display(&self, indent: usize) -> DisplayFileSystem { + pub fn display(&self, indent: usize) -> DisplayFileSystem<'_> { DisplayFileSystem { files: self, parent_id: ROOT_DIR_ID, indent } } diff --git a/lib/src/rom/overlay_table.rs b/lib/src/rom/overlay_table.rs index 2fa71a6..a1eda6f 100644 --- a/lib/src/rom/overlay_table.rs +++ b/lib/src/rom/overlay_table.rs @@ -57,7 +57,7 @@ impl<'a> OverlayTable<'a> { } /// Builds a raw overlay table. - pub fn build(&self) -> raw::OverlayTable { + pub fn build(&self) -> raw::OverlayTable<'a> { let overlays: Vec = self.overlays.iter().map(|overlay| overlay.build()).collect(); let signature = self.signature; raw::OverlayTable::new(overlays, signature) diff --git a/lib/src/rom/raw/arm9_footer.rs b/lib/src/rom/raw/arm9_footer.rs index a7b8f87..9fa133d 100644 --- a/lib/src/rom/raw/arm9_footer.rs +++ b/lib/src/rom/raw/arm9_footer.rs @@ -121,7 +121,7 @@ impl Arm9Footer { } /// Creates a [`DisplayArm9Footer`] which implements [`Display`]. - pub fn display(&self, indent: usize) -> DisplayArm9Footer { + pub fn display(&self, indent: usize) -> DisplayArm9Footer<'_> { DisplayArm9Footer { footer: self, indent } } } diff --git a/lib/src/rom/raw/autoload_info.rs b/lib/src/rom/raw/autoload_info.rs index 5440905..1dad167 100644 --- a/lib/src/rom/raw/autoload_info.rs +++ b/lib/src/rom/raw/autoload_info.rs @@ -162,7 +162,7 @@ impl AutoloadInfo { } /// Creates a [`DisplayAutoloadInfo`] which implements [`Display`]. - pub fn display(&self, indent: usize) -> DisplayAutoloadInfo { + pub fn display(&self, indent: usize) -> DisplayAutoloadInfo<'_> { DisplayAutoloadInfo { info: self, indent } } } diff --git a/lib/src/rom/raw/banner.rs b/lib/src/rom/raw/banner.rs index 27fc766..128d628 100644 --- a/lib/src/rom/raw/banner.rs +++ b/lib/src/rom/raw/banner.rs @@ -200,7 +200,7 @@ impl<'a> Banner<'a> { } /// Creates a [`DisplayBanner`] which implements [`Display`]. - pub fn display(&self, indent: usize) -> DisplayBanner { + pub fn display(&self, indent: usize) -> DisplayBanner<'_> { DisplayBanner { banner: self, indent } } } diff --git a/lib/src/rom/raw/build_info.rs b/lib/src/rom/raw/build_info.rs index 06b59a1..85869ea 100644 --- a/lib/src/rom/raw/build_info.rs +++ b/lib/src/rom/raw/build_info.rs @@ -137,7 +137,7 @@ impl BuildInfo { } /// Creates a [`DisplayBuildInfo`] which implements [`Display`]. - pub fn display(&self, indent: usize) -> DisplayBuildInfo { + pub fn display(&self, indent: usize) -> DisplayBuildInfo<'_> { DisplayBuildInfo { build_info: self, indent } } } diff --git a/lib/src/rom/raw/fnt.rs b/lib/src/rom/raw/fnt.rs index 8f1e42b..69a85d2 100644 --- a/lib/src/rom/raw/fnt.rs +++ b/lib/src/rom/raw/fnt.rs @@ -146,7 +146,7 @@ impl<'a> Fnt<'a> { impl FntSubtable<'_> { /// Returns an iterator over all immediate children (files and directories) in this subtable. - pub fn iter(&self) -> IterFntSubtable { + pub fn iter(&self) -> IterFntSubtable<'_> { IterFntSubtable { data: &self.data, id: self.directory.first_file_id } } } diff --git a/lib/src/rom/raw/header.rs b/lib/src/rom/raw/header.rs index f214cd5..107fee3 100644 --- a/lib/src/rom/raw/header.rs +++ b/lib/src/rom/raw/header.rs @@ -288,7 +288,7 @@ impl Header { } /// Creates a [`DisplayHeader`] which implements [`Display`]. - pub fn display(&self, indent: usize) -> DisplayHeader { + pub fn display(&self, indent: usize) -> DisplayHeader<'_> { DisplayHeader { header: self, indent } } } @@ -479,7 +479,7 @@ pub struct ProgramOffset { impl ProgramOffset { /// Creates a [`DisplayProgramOffset`] which implements [`Display`]. - pub fn display(&self, indent: usize) -> DisplayProgramOffset { + pub fn display(&self, indent: usize) -> DisplayProgramOffset<'_> { DisplayProgramOffset { offset: self, indent } } } @@ -514,7 +514,7 @@ pub struct TableOffset { impl TableOffset { /// Creates a [`DisplayTableOffset`] which implements [`Display`]. - pub fn display(&self, indent: usize) -> DisplayTableOffset { + pub fn display(&self, indent: usize) -> DisplayTableOffset<'_> { DisplayTableOffset { offset: self, indent } } } diff --git a/lib/src/rom/raw/overlay.rs b/lib/src/rom/raw/overlay.rs index 54aa1c6..d251bc1 100644 --- a/lib/src/rom/raw/overlay.rs +++ b/lib/src/rom/raw/overlay.rs @@ -105,7 +105,7 @@ impl Overlay { } /// Creates a [`DisplayOverlay`] which implements [`Display`]. - pub fn display(&self, indent: usize) -> DisplayOverlay { + pub fn display(&self, indent: usize) -> DisplayOverlay<'_> { DisplayOverlay { overlay: self, indent } } } diff --git a/lib/src/rom/raw/rom.rs b/lib/src/rom/raw/rom.rs index 5645df1..bc95f28 100644 --- a/lib/src/rom/raw/rom.rs +++ b/lib/src/rom/raw/rom.rs @@ -102,7 +102,7 @@ impl<'a> Rom<'a> { /// # Errors /// /// See [`Self::header`]. - pub fn arm9(&self) -> Result { + pub fn arm9(&self) -> Result, RawArm9Error> { let header = self.header()?; let start = header.arm9.offset as usize; let end = start + header.arm9.size as usize; @@ -175,7 +175,7 @@ impl<'a> Rom<'a> { /// # Errors /// /// See [`Self::arm9`] and [`Self::arm9_overlay_table_with`]. - pub fn arm9_overlay_table(&self) -> Result { + pub fn arm9_overlay_table(&self) -> Result, RawOverlayError> { let arm9 = self.arm9()?; self.arm9_overlay_table_with(&arm9) } @@ -185,7 +185,7 @@ impl<'a> Rom<'a> { /// # Errors /// /// See [`Self::arm9_overlays`] and [`Arm9::overlay_table_signature`]. - pub fn arm9_overlay_table_with(&self, arm9: &Arm9) -> Result { + pub fn arm9_overlay_table_with(&self, arm9: &Arm9) -> Result, RawOverlayError> { let overlays = self.arm9_overlays()?; let signature = arm9.overlay_table_signature()?.cloned(); Ok(OverlayTable::new(overlays, signature)) @@ -208,7 +208,7 @@ impl<'a> Rom<'a> { /// # Errors /// /// See [`Self::header`]. - pub fn arm7(&self) -> Result { + pub fn arm7(&self) -> Result, RawHeaderError> { let header = self.header()?; let start = header.arm7.offset as usize; let end = start + header.arm7.size as usize; @@ -247,7 +247,7 @@ impl<'a> Rom<'a> { /// # Errors /// /// See [`Self::arm7_overlays`]. - pub fn arm7_overlay_table(&self) -> Result { + pub fn arm7_overlay_table(&self) -> Result, RawOverlayError> { let overlays = self.arm7_overlays()?; Ok(OverlayTable::new(overlays, None)) } @@ -269,7 +269,7 @@ impl<'a> Rom<'a> { /// # Errors /// /// See [`Self::header`] and [`Fnt::borrow_from_slice`]. - pub fn fnt(&self) -> Result { + pub fn fnt(&self) -> Result, RawFntError> { let header = self.header()?; let start = header.file_names.offset as usize; let end = start + header.file_names.size as usize; @@ -296,7 +296,7 @@ impl<'a> Rom<'a> { /// # Errors /// /// See [`Self::header`] and [`Banner::borrow_from_slice`]. - pub fn banner(&self) -> Result { + pub fn banner(&self) -> Result, RawBannerError> { let header = self.header()?; let start = header.banner_offset as usize; let data = &self.data[start..]; diff --git a/lib/src/rom/rom.rs b/lib/src/rom/rom.rs index 2835283..900cc1d 100644 --- a/lib/src/rom/rom.rs +++ b/lib/src/rom/rom.rs @@ -865,32 +865,32 @@ impl<'a> Rom<'a> { } /// Returns a reference to the ARM9 program of this [`Rom`]. - pub fn arm9(&self) -> &Arm9 { + pub fn arm9(&self) -> &Arm9<'a> { &self.arm9 } /// Returns a reference to the ARM9 overlay table of this [`Rom`]. - pub fn arm9_overlay_table(&self) -> &OverlayTable { + pub fn arm9_overlay_table(&self) -> &OverlayTable<'a> { &self.arm9_overlay_table } /// Returns a reference to the ARM9 overlays of this [`Rom`]. - pub fn arm9_overlays(&self) -> &[Overlay] { + pub fn arm9_overlays(&self) -> &[Overlay<'a>] { self.arm9_overlay_table.overlays() } /// Returns a reference to the ARM7 program of this [`Rom`]. - pub fn arm7(&self) -> &Arm7 { + pub fn arm7(&self) -> &Arm7<'a> { &self.arm7 } /// Returns a reference to the ARM7 overlay table of this [`Rom`]. - pub fn arm7_overlay_table(&self) -> &OverlayTable { + pub fn arm7_overlay_table(&self) -> &OverlayTable<'a> { &self.arm7_overlay_table } /// Returns a reference to the ARM7 overlays of this [`Rom`]. - pub fn arm7_overlays(&self) -> &[Overlay] { + pub fn arm7_overlays(&self) -> &[Overlay<'a>] { self.arm7_overlay_table.overlays() } From 5190aaa64861ff8d0265859f7cedc1ff9f9c28ec Mon Sep 17 00:00:00 2001 From: Aetias Date: Sun, 23 Nov 2025 11:57:01 +0100 Subject: [PATCH 03/16] Mutable getters to plain `Rom` fields --- lib/src/rom/overlay_table.rs | 5 +++++ lib/src/rom/rom.rs | 40 ++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/lib/src/rom/overlay_table.rs b/lib/src/rom/overlay_table.rs index a1eda6f..1233129 100644 --- a/lib/src/rom/overlay_table.rs +++ b/lib/src/rom/overlay_table.rs @@ -22,6 +22,11 @@ impl<'a> OverlayTable<'a> { &self.overlays } + /// Returns a mutable reference to the overlays of this [`OverlayTable`]. + pub fn overlays_mut(&mut self) -> &mut [Overlay<'a>] { + &mut self.overlays + } + /// Returns the length of this [`OverlayTable`]. pub fn len(&self) -> usize { self.overlays.len() diff --git a/lib/src/rom/rom.rs b/lib/src/rom/rom.rs index 900cc1d..fd7a276 100644 --- a/lib/src/rom/rom.rs +++ b/lib/src/rom/rom.rs @@ -864,41 +864,81 @@ impl<'a> Rom<'a> { &self.header_logo } + /// Returns a mutable reference to the header logo of this [`Rom`]. + pub fn header_logo_mut(&mut self) -> &mut Logo { + &mut self.header_logo + } + /// Returns a reference to the ARM9 program of this [`Rom`]. pub fn arm9(&self) -> &Arm9<'a> { &self.arm9 } + /// Returns a mutable reference to the ARM9 program of this [`Rom`]. + pub fn arm9_mut(&mut self) -> &mut Arm9<'a> { + &mut self.arm9 + } + /// Returns a reference to the ARM9 overlay table of this [`Rom`]. pub fn arm9_overlay_table(&self) -> &OverlayTable<'a> { &self.arm9_overlay_table } + /// Returns a mutable reference to the ARM9 overlay table of this [`Rom`]. + pub fn arm9_overlay_table_mut(&mut self) -> &mut OverlayTable<'a> { + &mut self.arm9_overlay_table + } + /// Returns a reference to the ARM9 overlays of this [`Rom`]. pub fn arm9_overlays(&self) -> &[Overlay<'a>] { self.arm9_overlay_table.overlays() } + /// Returns a mutable reference to the ARM9 overlays of this [`Rom`]. + pub fn arm9_overlays_mut(&mut self) -> &mut [Overlay<'a>] { + self.arm9_overlay_table.overlays_mut() + } + /// Returns a reference to the ARM7 program of this [`Rom`]. pub fn arm7(&self) -> &Arm7<'a> { &self.arm7 } + /// Returns a mutable reference to the ARM7 program of this [`Rom`]. + pub fn arm7_mut(&mut self) -> &mut Arm7<'a> { + &mut self.arm7 + } + /// Returns a reference to the ARM7 overlay table of this [`Rom`]. pub fn arm7_overlay_table(&self) -> &OverlayTable<'a> { &self.arm7_overlay_table } + /// Returns a mutable reference to the ARM7 overlay table of this [`Rom`]. + pub fn arm7_overlay_table_mut(&mut self) -> &mut OverlayTable<'a> { + &mut self.arm7_overlay_table + } + /// Returns a reference to the ARM7 overlays of this [`Rom`]. pub fn arm7_overlays(&self) -> &[Overlay<'a>] { self.arm7_overlay_table.overlays() } + /// Returns a mutable reference to the ARM7 overlays of this [`Rom`]. + pub fn arm7_overlays_mut(&mut self) -> &mut [Overlay<'a>] { + self.arm7_overlay_table.overlays_mut() + } + /// Returns a reference to the header of this [`Rom`]. pub fn header(&self) -> &Header { &self.header } + /// Returns a mutable reference to the header of this [`Rom`]. + pub fn header_mut(&mut self) -> &mut Header { + &mut self.header + } + /// Returns the [`RomConfig`] consisting of paths to extracted files. pub fn config(&self) -> &RomConfig { &self.config From 283422a548ab89201fbeea035ecc3a1bc5d7cacb Mon Sep 17 00:00:00 2001 From: Aetias Date: Fri, 26 Dec 2025 13:04:58 +0100 Subject: [PATCH 04/16] Fix warnings --- Cargo.lock | 8 ++++---- lib/src/compress/huffman.rs | 4 ++-- lib/src/crypto/blowfish.rs | 4 ++-- lib/src/rom/raw/autoload_info.rs | 2 +- lib/src/rom/raw/banner.rs | 2 +- lib/src/rom/raw/fat.rs | 2 +- lib/src/rom/raw/fnt.rs | 2 +- lib/src/rom/raw/hmac_sha1_signature.rs | 2 +- lib/src/rom/raw/overlay.rs | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb732d6..64ab3e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,18 +145,18 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.16.1" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.0" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", diff --git a/lib/src/compress/huffman.rs b/lib/src/compress/huffman.rs index 7ea95d8..e462806 100644 --- a/lib/src/compress/huffman.rs +++ b/lib/src/compress/huffman.rs @@ -80,7 +80,7 @@ impl NibbleHuffman { /// /// Panics if `data.len()` is not a multiple of 2. pub fn diff16_to_data(&self, data: &mut [u8]) { - assert!(data.len() % 2 == 0); + assert!(data.len().is_multiple_of(2)); let mut prev = 0; for i in (0..data.len()).step_by(2) { let curr = u16::from_le_bytes([data[i], data[i + 1]]); @@ -100,7 +100,7 @@ impl NibbleHuffman { /// /// Panics if `data.len()` is not a multiple of 2. pub fn data_to_diff16(&self, data: &mut [u8]) { - assert!(data.len() % 2 == 0); + assert!(data.len().is_multiple_of(2)); let mut prev = 0; for i in (0..data.len()).step_by(2) { let curr = u16::from_le_bytes([data[i], data[i + 1]]); diff --git a/lib/src/crypto/blowfish.rs b/lib/src/crypto/blowfish.rs index 1998d5f..83a9da1 100644 --- a/lib/src/crypto/blowfish.rs +++ b/lib/src/crypto/blowfish.rs @@ -58,7 +58,7 @@ impl Blowfish { /// /// This function will return an error if `data.len()` is not a multiple of 8. pub fn encrypt(&self, data: &mut [u8]) -> Result<(), BlowfishError> { - if data.len() % 8 != 0 { + if !data.len().is_multiple_of(8) { OddBlockCountSnafu {}.fail()?; } for chunk in data.chunks_exact_mut(8) { @@ -89,7 +89,7 @@ impl Blowfish { /// /// This function will return an error if `data.len()` is not a multiple of 8. pub fn decrypt(&self, data: &mut [u8]) -> Result<(), BlowfishError> { - if data.len() % 8 != 0 { + if !data.len().is_multiple_of(8) { OddBlockCountSnafu {}.fail()?; } for chunk in data.chunks_mut(8) { diff --git a/lib/src/rom/raw/autoload_info.rs b/lib/src/rom/raw/autoload_info.rs index 1dad167..f48faa0 100644 --- a/lib/src/rom/raw/autoload_info.rs +++ b/lib/src/rom/raw/autoload_info.rs @@ -93,7 +93,7 @@ pub enum RawAutoloadInfoError { impl AutoloadInfoEntry { fn check_size(data: &'_ [u8]) -> Result<(), RawAutoloadInfoError> { let size = size_of::(); - if data.len() % size != 0 { + if !data.len().is_multiple_of(size) { InvalidSizeSnafu {}.fail() } else { Ok(()) diff --git a/lib/src/rom/raw/banner.rs b/lib/src/rom/raw/banner.rs index 128d628..01b6862 100644 --- a/lib/src/rom/raw/banner.rs +++ b/lib/src/rom/raw/banner.rs @@ -83,7 +83,7 @@ impl<'a> Banner<'a> { /// or is not aligned enough. pub fn borrow_from_slice(data: &'a [u8]) -> Result { let addr = data as *const [u8] as *const () as usize; - if addr % 2 != 0 { + if !addr.is_multiple_of(2) { return MisalignedSnafu { expected: 2usize, actual: 1usize << addr.trailing_zeros() as usize }.fail(); } diff --git a/lib/src/rom/raw/fat.rs b/lib/src/rom/raw/fat.rs index 88b7144..e9289cf 100644 --- a/lib/src/rom/raw/fat.rs +++ b/lib/src/rom/raw/fat.rs @@ -48,7 +48,7 @@ pub enum RawFatError { impl FileAlloc { fn check_size(data: &'_ [u8]) -> Result<(), RawFatError> { let size = size_of::(); - if data.len() % size != 0 { + if !data.len().is_multiple_of(size) { InvalidSizeSnafu {}.fail() } else { Ok(()) diff --git a/lib/src/rom/raw/fnt.rs b/lib/src/rom/raw/fnt.rs index 69a85d2..194b736 100644 --- a/lib/src/rom/raw/fnt.rs +++ b/lib/src/rom/raw/fnt.rs @@ -93,7 +93,7 @@ impl<'a> Fnt<'a> { pub fn borrow_from_slice(data: &'a [u8]) -> Result { Self::check_size(data)?; let addr = data as *const [u8] as *const () as usize; - if addr % 4 != 0 { + if !addr.is_multiple_of(4) { return MisalignedSnafu { expected: 4usize, actual: 1usize << addr.trailing_zeros() as usize }.fail(); } diff --git a/lib/src/rom/raw/hmac_sha1_signature.rs b/lib/src/rom/raw/hmac_sha1_signature.rs index 31e3008..032f0d4 100644 --- a/lib/src/rom/raw/hmac_sha1_signature.rs +++ b/lib/src/rom/raw/hmac_sha1_signature.rs @@ -49,7 +49,7 @@ impl HmacSha1Signature { fn check_size(data: &[u8]) -> Result<(), HmacSha1SignatureError> { let size = size_of::(); - if data.len() % size != 0 { + if !data.len().is_multiple_of(size) { InvalidSizeSnafu {}.fail() } else { Ok(()) diff --git a/lib/src/rom/raw/overlay.rs b/lib/src/rom/raw/overlay.rs index d251bc1..9e9a738 100644 --- a/lib/src/rom/raw/overlay.rs +++ b/lib/src/rom/raw/overlay.rs @@ -74,7 +74,7 @@ pub enum RawOverlayError { impl Overlay { fn check_size(data: &[u8]) -> Result<(), RawOverlayError> { let size = size_of::(); - if data.len() % size != 0 { + if !data.len().is_multiple_of(size) { InvalidSizeSnafu {}.fail() } else { Ok(()) From c2f78bc7999212af10b56639e64c902a509685d1 Mon Sep 17 00:00:00 2001 From: Aetias Date: Fri, 26 Dec 2025 13:05:39 +0100 Subject: [PATCH 05/16] Update .gitignore --- .gitignore | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index f685841..d37c7f7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,4 @@ -/target +/target/ *.nds -/.vscode -/*.bin -/test -/build.sh -/build.ps1 +/.vscode/ +/temp/ From cefd5746fe5f83dfc10802861a0d917b68c0b63f Mon Sep 17 00:00:00 2001 From: Aetias Date: Fri, 26 Dec 2025 13:18:35 +0100 Subject: [PATCH 06/16] Don't require HMAC-SHA1 key if overlay table signature is specified --- lib/src/rom/rom.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/rom/rom.rs b/lib/src/rom/rom.rs index fd7a276..6668c7e 100644 --- a/lib/src/rom/rom.rs +++ b/lib/src/rom/rom.rs @@ -472,12 +472,12 @@ impl<'a> Rom<'a> { let mut overlay_table = OverlayTable::new(overlays); if overlay_table_config.table_signed { - let Some(ref hmac_sha1) = hmac_sha1 else { - return NoHmacSha1KeySnafu {}.fail(); - }; if let Some(signature) = overlay_table_config.table_signature { overlay_table.set_signature(signature); } else { + let Some(ref hmac_sha1) = hmac_sha1 else { + return NoHmacSha1KeySnafu {}.fail(); + }; overlay_table.sign(hmac_sha1); } } From 9fcea9c8bbc1a53700fc1e572b53fc851a71d1ac Mon Sep 17 00:00:00 2001 From: Aetias Date: Fri, 26 Dec 2025 18:31:13 +0100 Subject: [PATCH 07/16] Support multiboot signatures --- cli/src/dump.rs | 21 ++++ lib/src/crypto/mod.rs | 3 + lib/src/crypto/rsa.rs | 78 ++++++++++++++ lib/src/rom/config.rs | 3 + lib/src/rom/raw/mod.rs | 2 + lib/src/rom/raw/multiboot_signature.rs | 137 +++++++++++++++++++++++++ lib/src/rom/raw/rom.rs | 21 +++- lib/src/rom/rom.rs | 64 +++++++++++- lib/src/str.rs | 27 ----- 9 files changed, 323 insertions(+), 33 deletions(-) create mode 100644 lib/src/crypto/rsa.rs create mode 100644 lib/src/rom/raw/multiboot_signature.rs diff --git a/cli/src/dump.rs b/cli/src/dump.rs index f47957a..5357e4f 100644 --- a/cli/src/dump.rs +++ b/cli/src/dump.rs @@ -75,6 +75,7 @@ impl Dump { DumpCommand::Arm7Overlay(dump_arm7_overlay) => dump_arm7_overlay.run(&rom), DumpCommand::Arm9Footer(dump_arm9_footer) => dump_arm9_footer.run(&rom), DumpCommand::Arm9OverlaySignatures(dump_arm9_overlay_signatures) => dump_arm9_overlay_signatures.run(&rom), + DumpCommand::MultibootSignature(dump_multiboot_signature) => dump_multiboot_signature.run(&rom), } } } @@ -103,6 +104,8 @@ enum DumpCommand { Arm9Footer(DumpArm9Footer), #[command(name = "arm9-ov-sigs")] Arm9OverlaySignatures(DumpArm9OverlaySignatures), + #[command(name = "mb-sig")] + MultibootSignature(DumpMultibootSignature), } /// Shows the contents of the ROM header. @@ -495,3 +498,21 @@ impl DumpArm9OverlaySignatures { Ok(()) } } + +/// Prints the multiboot (download play) signature. +#[derive(Args)] +struct DumpMultibootSignature {} + +impl DumpMultibootSignature { + pub fn run(&self, raw_rom: &raw::Rom) -> Result<()> { + let rom = Rom::extract(raw_rom)?; + + if let Some(multiboot_signature) = rom.multiboot_signature() { + println!("{}", multiboot_signature.display(2)); + } else { + println!("No multiboot signature found"); + } + + Ok(()) + } +} diff --git a/lib/src/crypto/mod.rs b/lib/src/crypto/mod.rs index 7740549..c997a76 100644 --- a/lib/src/crypto/mod.rs +++ b/lib/src/crypto/mod.rs @@ -3,3 +3,6 @@ pub mod blowfish; /// Authentication using HMAC-SHA1. pub mod hmac_sha1; + +/// RSA signature type, no de/encryption yet. +pub mod rsa; diff --git a/lib/src/crypto/rsa.rs b/lib/src/crypto/rsa.rs new file mode 100644 index 0000000..ed073f6 --- /dev/null +++ b/lib/src/crypto/rsa.rs @@ -0,0 +1,78 @@ +use std::fmt::Display; + +use bytemuck::{Pod, Zeroable}; +use serde::{de::Visitor, Deserialize, Serialize}; + +/// Represents an RSA signature. +#[repr(C)] +#[derive(Zeroable, Pod, Clone, Copy)] +pub struct RsaSignature(pub [u8; 0x80]); + +impl Serialize for RsaSignature { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_bytes(&self.0) + } +} + +impl<'de> Deserialize<'de> for RsaSignature { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_bytes(RsaSignatureBytesVisitor) + } +} + +struct RsaSignatureBytesVisitor; + +impl<'de> Visitor<'de> for RsaSignatureBytesVisitor { + type Value = RsaSignature; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("an array of 128 (0x80) bytes") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: serde::de::Error, + { + if v.len() != 0x80 { + Err(serde::de::Error::custom("RSA signature must be 128 bytes")) + } else { + let mut buf = [0u8; 0x80]; + buf.copy_from_slice(v); + Ok(RsaSignature(buf)) + } + } +} + +impl RsaSignature { + /// Returns a [`DisplayRsaSignature`] which implements [`Display`]. + pub fn display(&self, indent: usize) -> DisplayRsaSignature<'_> { + DisplayRsaSignature { rsa_signature: self, indent } + } +} + +/// Can be used to display values inside [`RsaSignature`]. +pub struct DisplayRsaSignature<'a> { + rsa_signature: &'a RsaSignature, + indent: usize, +} + +impl Display for DisplayRsaSignature<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let i = " ".repeat(self.indent); + let bytes = &self.rsa_signature.0; + for row in 0..8 { + write!(f, "{i}")?; + for col in 0..16 { + write!(f, "{:02x} ", bytes[row * 16 + col])?; + } + writeln!(f)?; + } + Ok(()) + } +} diff --git a/lib/src/rom/config.rs b/lib/src/rom/config.rs index a21fd80..bf343fe 100644 --- a/lib/src/rom/config.rs +++ b/lib/src/rom/config.rs @@ -49,6 +49,9 @@ pub struct RomConfig { /// Path to HMAC SHA1 key file for ARM9 pub arm9_hmac_sha1_key: Option, + /// Path to multiboot signature YAML + pub multiboot_signature: Option, + /// Alignment of ROM sections pub alignment: RomConfigAlignment, } diff --git a/lib/src/rom/raw/mod.rs b/lib/src/rom/raw/mod.rs index 3dc1d9d..65fb2bd 100644 --- a/lib/src/rom/raw/mod.rs +++ b/lib/src/rom/raw/mod.rs @@ -6,6 +6,7 @@ mod fat; mod fnt; mod header; mod hmac_sha1_signature; +mod multiboot_signature; mod overlay; mod overlay_table; mod rom; @@ -18,6 +19,7 @@ pub use fat::*; pub use fnt::*; pub use header::*; pub use hmac_sha1_signature::*; +pub use multiboot_signature::*; pub use overlay::*; pub use overlay_table::*; pub use rom::*; diff --git a/lib/src/rom/raw/multiboot_signature.rs b/lib/src/rom/raw/multiboot_signature.rs new file mode 100644 index 0000000..c817f95 --- /dev/null +++ b/lib/src/rom/raw/multiboot_signature.rs @@ -0,0 +1,137 @@ +use std::{backtrace::Backtrace, fmt::Display}; + +use bytemuck::{Pod, PodCastError, Zeroable}; +use serde::{Deserialize, Serialize}; +use snafu::Snafu; + +use crate::{crypto::rsa::RsaSignature, rom::raw::RawHeaderError}; + +/// Contains the RSA signature used to verify the integrity of the ROM header and the ARM9 and ARM7 +/// programs, after it is transferred for Download Play. +#[repr(C)] +#[derive(Zeroable, Pod, Clone, Copy, Serialize, Deserialize)] +pub struct MultibootSignature { + magic: u32, + rsa_signature: RsaSignature, + key_seed: u32, +} + +/// Magic number at the start of a multiboot signature. +pub const MULTIBOOT_SIGNATURE_MAGIC: u32 = 0x00016361; + +/// Errors related to [`MultibootSignature`]. +#[derive(Debug, Snafu)] +pub enum RawMultibootSignatureError { + /// See [`RawHeaderError`]. + #[snafu(transparent)] + RawHeader { + /// Source error. + source: RawHeaderError, + }, + /// Occurs when the input is too small to contain a [`MultibootSignature`]. + #[snafu(display("expected {expected:#x} bytes for multiboot signature but had only {actual:#x}:\n{backtrace}"))] + DataTooSmall { + /// Expected size. + expected: usize, + /// Actual input size. + actual: usize, + /// Backtrace to the source of the error. + backtrace: Backtrace, + }, + /// Occurs when the input is less aligned than [`MultibootSignature`]. + #[snafu(display("expected {expected}-alignment but got {actual}-alignment:\n{backtrace}"))] + Misaligned { + /// Expected alignment. + expected: usize, + /// Actual alignment. + actual: usize, + /// Backtrace to the source of the error. + backtrace: Backtrace, + }, + /// Occurs when the magic number does not match [`MULTIBOOT_SIGNATURE_MAGIC`]. + #[snafu(display("expected magic number {expected:#010x} but got {actual:#010x}:\n{backtrace}"))] + InvalidMagic { + /// Expected magic number. + expected: u32, + /// Actual magic number. + actual: u32, + /// Backtrace to the source of the error. + backtrace: Backtrace, + }, +} + +impl MultibootSignature { + fn check_size(data: &'_ [u8]) -> Result<(), RawMultibootSignatureError> { + let size = size_of::(); + if data.len() < size { + DataTooSmallSnafu { expected: size, actual: data.len() }.fail() + } else { + Ok(()) + } + } + + fn handle_pod_cast(result: Result, addr: usize) -> Result { + match result { + Ok(build_info) => Ok(build_info), + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => { + MisalignedSnafu { expected: align_of::(), actual: 1usize << addr.trailing_zeros() }.fail() + } + Err(PodCastError::AlignmentMismatch) => panic!(), + Err(PodCastError::OutputSliceWouldHaveSlop) => panic!(), + Err(PodCastError::SizeMismatch) => unreachable!(), + } + } + + /// Reinterprets a `&[u8]` as a reference to [`MultibootSignature`]. + /// + /// # Errors + /// + /// This function will return an error if the input is too small or not aligned enough. + pub fn borrow_from_slice(data: &[u8]) -> Result<&Self, RawMultibootSignatureError> { + let size = size_of::(); + Self::check_size(data)?; + let addr = data as *const [u8] as *const () as usize; + let multiboot_signature: &Self = Self::handle_pod_cast(bytemuck::try_from_bytes(&data[..size]), addr)?; + if multiboot_signature.magic != MULTIBOOT_SIGNATURE_MAGIC { + return InvalidMagicSnafu { expected: MULTIBOOT_SIGNATURE_MAGIC, actual: multiboot_signature.magic }.fail(); + } + Ok(multiboot_signature) + } + + /// Creates a [`DisplayMultibootSignature`] which implements [`Display`]. + pub fn display(&self, indent: usize) -> DisplayMultibootSignature<'_> { + DisplayMultibootSignature { multiboot_signature: self, indent } + } + + /// Returns the magic number of this [`MultibootSignature`]. This is always equal to [`MULTIBOOT_SIGNATURE_MAGIC`]. + pub fn magic(&self) -> u32 { + self.magic + } + + /// Returns the [`RsaSignature`] of this [`MultibootSignature`]. + pub fn rsa_signature(&self) -> &RsaSignature { + &self.rsa_signature + } + + /// Returns the RSA key seed of this [`MultibootSignature`]. + pub fn key_seed(&self) -> u32 { + self.key_seed + } +} + +/// Can be used to display values inside [`MultibootSignature`]. +pub struct DisplayMultibootSignature<'a> { + multiboot_signature: &'a MultibootSignature, + indent: usize, +} + +impl Display for DisplayMultibootSignature<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let i = " ".repeat(self.indent); + let multiboot_signature = &self.multiboot_signature; + writeln!(f, "{i}Magic number ... : {:#010x}", multiboot_signature.magic)?; + writeln!(f, "{i}RSA key seed ... : {:#010x}", multiboot_signature.key_seed)?; + writeln!(f, "{i}RSA signature .. :\n{}", multiboot_signature.rsa_signature.display(self.indent + 2))?; + Ok(()) + } +} diff --git a/lib/src/rom/raw/rom.rs b/lib/src/rom/raw/rom.rs index bc95f28..5bc99f6 100644 --- a/lib/src/rom/raw/rom.rs +++ b/lib/src/rom/raw/rom.rs @@ -8,7 +8,10 @@ use super::{ }; use crate::{ io::{open_file, write_file, FileError}, - rom::{Arm7, Arm7Offsets, Arm9, Arm9Offsets, RomConfigAlignment}, + rom::{ + raw::{MultibootSignature, RawMultibootSignatureError}, + Arm7, Arm7Offsets, Arm9, Arm9Offsets, RomConfigAlignment, + }, }; /// A raw DS ROM, see the plain struct [here](super::super::Rom). @@ -303,6 +306,22 @@ impl<'a> Rom<'a> { Banner::borrow_from_slice(data) } + /// Returns the multiboot signature of this [`Rom`]. + /// + /// # Errors + /// + /// See [`Self::header`] and [`MultibootSignature::borrow_from_slice`]. + pub fn multiboot_signature(&self) -> Result, RawMultibootSignatureError> { + let header = self.header()?; + let start = header.rom_size_ds as usize; + let data = &self.data[start..]; + match MultibootSignature::borrow_from_slice(data) { + Ok(s) => Ok(Some(s)), + Err(RawMultibootSignatureError::InvalidMagic { .. }) => Ok(None), + Err(e) => Err(e), + } + } + /// Returns the padding value in the file image block of this [`Rom`]. /// /// # Errors diff --git a/lib/src/rom/rom.rs b/lib/src/rom/rom.rs index 6668c7e..dc0e92f 100644 --- a/lib/src/rom/rom.rs +++ b/lib/src/rom/rom.rs @@ -25,7 +25,10 @@ use crate::{ hmac_sha1::{HmacSha1, HmacSha1FromBytesError}, }, io::{create_dir_all, create_file, create_file_and_dirs, open_file, read_file, read_to_string, FileError}, - rom::{raw::FileAlloc, Arm9WithTcmsOptions, RomConfig}, + rom::{ + raw::{FileAlloc, MultibootSignature, RawMultibootSignatureError}, + Arm9WithTcmsOptions, RomConfig, + }, }; /// A plain ROM. @@ -38,6 +41,8 @@ pub struct Rom<'a> { arm7_overlay_table: OverlayTable<'a>, banner: Banner, files: FileSystem<'a>, + multiboot_signature: Option, + path_order: Vec, config: RomConfig, } @@ -129,6 +134,12 @@ pub enum RomExtractError { /// Source error. source: Arm9HmacSha1KeyError, }, + /// See [`RawMultibootSignatureError`]. + #[snafu(transparent)] + RawMultibootSignature { + /// Source error. + source: RawMultibootSignatureError, + }, } /// Errors related to [`Rom::build`]. @@ -423,6 +434,13 @@ impl<'a> Rom<'a> { (FileSystem::new(num_overlays), vec![]) }; + // --------------------- Load multiboot signature --------------------- + let multiboot_signature = if let Some(multiboot_signature) = config.multiboot_signature.as_ref() { + serde_yml::from_reader(open_file(path.join(multiboot_signature))?)? + } else { + None + }; + Ok(Self { header, header_logo, @@ -433,6 +451,7 @@ impl<'a> Rom<'a> { banner, files, path_order, + multiboot_signature, config, }) } @@ -590,6 +609,16 @@ impl<'a> Rom<'a> { path_order_file.write_all("\n".as_bytes())?; } + // --------------------- Save multiboot signature --------------------- + if let Some(multiboot_signature) = &self.multiboot_signature { + if let Some(signature_file) = &self.config.multiboot_signature { + let file_path = path.join(signature_file); + serde_yml::to_writer(create_file_and_dirs(&file_path)?, multiboot_signature)?; + } + } else if self.config.multiboot_signature.is_some() { + log::warn!("Multiboot signature not found, but config requested it to be saved"); + } + Ok(()) } @@ -678,6 +707,8 @@ impl<'a> Rom<'a> { let has_arm9_hmac_sha1 = decompressed_arm9.hmac_sha1_key()?.is_some(); + let multiboot_signature = rom.multiboot_signature()?.cloned(); + let alignment = rom.alignments()?; let config = RomConfig { @@ -697,6 +728,7 @@ impl<'a> Rom<'a> { banner: "banner/banner.yaml".into(), files_dir: "files/".into(), path_order: "path_order.txt".into(), + multiboot_signature: if multiboot_signature.is_none() { None } else { Some("multiboot_signature.yaml".into()) }, arm9_hmac_sha1_key: has_arm9_hmac_sha1.then_some("arm9/hmac_sha1_key.bin".into()), alignment, }; @@ -710,6 +742,7 @@ impl<'a> Rom<'a> { arm7_overlay_table: arm7_overlays, banner: Banner::load_raw(&banner), files: file_root, + multiboot_signature, path_order, config, }) @@ -824,8 +857,14 @@ impl<'a> Rom<'a> { cursor.write_all(contents).expect("failed to write file contents"); }); - // --------------------- Write padding --------------------- + // --------------------- Write multiboot signature --------------------- + // Multiboot signature is placed "after" the ROM ends context.rom_size = Some(cursor.position() as u32); + if let Some(multiboot_signature) = &self.multiboot_signature { + cursor.write_all(bytemuck::bytes_of(multiboot_signature))?; + } + + // --------------------- Write padding --------------------- let padded_rom_size = cursor.position().next_power_of_two().max(128 * 1024) as u32; self.align_file_image(&mut cursor, padded_rom_size)?; @@ -943,6 +982,11 @@ impl<'a> Rom<'a> { pub fn config(&self) -> &RomConfig { &self.config } + + /// Returns the [`MultibootSignature`] of this [`Rom`]. + pub fn multiboot_signature(&self) -> Option<&MultibootSignature> { + self.multiboot_signature.as_ref() + } } /// Build context, generated during [`Rom::build`] and later passed to [`Header::build`] to fill in the header. @@ -988,14 +1032,24 @@ pub struct RomLoadOptions<'a> { pub encrypt: bool, /// If true (default), load asset files. pub load_files: bool, - /// If true (default), load header and header logo. + /// If true (default), load the header and the header logo. pub load_header: bool, - /// If true (default), load banner. + /// If true (default), load the banner. pub load_banner: bool, + /// If true (default), load the multiboot signature. + pub load_multiboot_signature: bool, } impl Default for RomLoadOptions<'_> { fn default() -> Self { - Self { key: None, compress: true, encrypt: true, load_files: true, load_header: true, load_banner: true } + Self { + key: None, + compress: true, + encrypt: true, + load_files: true, + load_header: true, + load_banner: true, + load_multiboot_signature: true, + } } } diff --git a/lib/src/str.rs b/lib/src/str.rs index b8c948c..20f42be 100644 --- a/lib/src/str.rs +++ b/lib/src/str.rs @@ -141,30 +141,3 @@ impl Display for BlobSize { } } } - -/// For debugging purposes. -#[allow(unused)] -pub(crate) fn write_hex(f: &mut std::fmt::Formatter<'_>, data: &[u8]) -> std::fmt::Result { - for (offset, chunk) in data.chunks(16).enumerate() { - write!(f, "{:08x} ", offset * 16)?; - for byte in chunk { - write!(f, " {byte:02x}")?; - } - writeln!(f)?; - } - writeln!(f)?; - Ok(()) -} - -/// For debugging purposes. -#[allow(unused)] -pub(crate) fn print_hex(data: &[u8]) { - for (offset, chunk) in data.chunks(16).enumerate() { - print!("{:08x} ", offset * 16); - for byte in chunk { - print!(" {byte:02x}"); - } - println!(); - } - println!(); -} From 21a62886908e07d7d49043d5a286ad28e1c31c83 Mon Sep 17 00:00:00 2001 From: Aetias Date: Fri, 26 Dec 2025 18:38:47 +0100 Subject: [PATCH 08/16] Replace `serde_yml` with `serde-saphyr` --- Cargo.lock | 287 ++++++++++++++++++++++++++++----------------- lib/Cargo.toml | 2 +- lib/src/rom/rom.rs | 48 ++++---- 3 files changed, 210 insertions(+), 127 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 64ab3e1..24c1403 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,19 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -81,6 +94,12 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + [[package]] name = "autocfg" version = "1.3.0" @@ -102,6 +121,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitfield-struct" version = "0.8.0" @@ -119,12 +144,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - [[package]] name = "bitreader" version = "0.3.8" @@ -295,7 +314,7 @@ dependencies = [ "log", "rust-bitwriter", "serde", - "serde_yml", + "serde-saphyr", "sha1", "snafu", ] @@ -320,6 +339,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "encoding_rs_io" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83" +dependencies = [ + "encoding_rs", +] + [[package]] name = "env_filter" version = "0.1.2" @@ -343,28 +371,6 @@ dependencies = [ "log", ] -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - [[package]] name = "fdeflate" version = "0.3.4" @@ -384,6 +390,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "generic-array" version = "0.14.7" @@ -394,6 +406,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "gimli" version = "0.29.0" @@ -402,9 +426,21 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown", +] [[package]] name = "heck" @@ -430,16 +466,6 @@ dependencies = [ "png", ] -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -dependencies = [ - "equivalent", - "hashbrown", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -458,18 +484,6 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" -[[package]] -name = "libyml" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e281a65eeba3d4503a2839252f86374528f9ceafe6fed97c1d3b52e1fb625c1" - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - [[package]] name = "log" version = "0.4.22" @@ -492,6 +506,12 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "num-traits" version = "0.2.19" @@ -510,13 +530,19 @@ dependencies = [ "memchr", ] +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "png" version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" dependencies = [ - "bitflags 1.3.2", + "bitflags", "crc32fast", "fdeflate", "flate2", @@ -534,13 +560,19 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "regex" version = "1.10.6" @@ -586,38 +618,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] -name = "rustix" -version = "0.38.34" +name = "ryu" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62049b2877bf12821e8f9ad256ee38fdc31db7387ec2d3b3f403024de2034aea" + +[[package]] +name = "saphyr-parser" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "4fb771b59f6b1985d1406325ec28f97cfb14256abcec4fdfb37b36a1766d6af7" dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", + "arraydeque", + "hashlink", ] [[package]] -name = "ryu" -version = "1.0.18" +name = "serde" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] [[package]] -name = "serde" -version = "1.0.204" +name = "serde-saphyr" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc40144bd36ca0cf5c8ee3bc181d315f2ba92c0078a59f32317d89938140829" +dependencies = [ + "ahash", + "base64", + "encoding_rs_io", + "nohash-hasher", + "num-traits", + "ryu", + "saphyr-parser", + "serde", + "serde_json", + "smallvec", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -626,30 +683,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_yml" -version = "0.0.10" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ce6afeda22f0b55dde2c34897bce76a629587348480384231205c14b59a01f" +checksum = "6af14725505314343e673e9ecb7cd7e8a36aa9791eb936235a3567cc31447ae4" dependencies = [ - "indexmap", "itoa", - "libyml", - "log", "memchr", - "ryu", "serde", - "serde_json", - "tempfile", + "serde_core", + "zmij", ] [[package]] @@ -669,6 +711,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "smallvec" +version = "2.0.0-alpha.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef784004ca8777809dcdad6ac37629f0a97caee4c685fcea805278d81dd8b857" + [[package]] name = "snafu" version = "0.8.3" @@ -699,27 +747,15 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.66" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys", -] - [[package]] name = "typenum" version = "1.18.0" @@ -744,6 +780,15 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -816,3 +861,35 @@ name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "zerocopy" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0095ecd462946aa3927d9297b63ef82fb9a5316d7a37d134eeb36e58228615a" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 91f1fa5..0727aa1 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -18,7 +18,7 @@ image = { version = "0.25.1", default-features = false, features = ["png"] } log = "0.4.22" rust-bitwriter = "0.0.1" serde = { version = "1.0.204", features = ["derive"] } -serde_yml = "0.0.10" +serde-saphyr = "0.0.11" sha1 = "0.10.6" snafu = { version = "0.8.3", features = ["backtrace"] } diff --git a/lib/src/rom/rom.rs b/lib/src/rom/rom.rs index dc0e92f..0bd76bf 100644 --- a/lib/src/rom/rom.rs +++ b/lib/src/rom/rom.rs @@ -189,11 +189,17 @@ pub enum RomSaveError { /// Source error. source: FileError, }, - /// See [`serde_yml::Error`]. + /// See [`serde_saphyr::Error`]. #[snafu(transparent)] - SerdeJson { + SerdeSaphyrDeserialize { /// Source error. - source: serde_yml::Error, + source: serde_saphyr::Error, + }, + /// See [`serde_saphyr::ser_error::Error`]. + #[snafu(transparent)] + SerdeSaphyrSerialize { + /// Source error. + source: serde_saphyr::ser_error::Error, }, /// See [`LogoSaveError`]. #[snafu(transparent)] @@ -327,12 +333,12 @@ impl<'a> Rom<'a> { let config_path = config_path.as_ref(); log::info!("Loading ROM from {}", config_path.display()); - let config: RomConfig = serde_yml::from_reader(open_file(config_path)?)?; + let config: RomConfig = serde_saphyr::from_reader(open_file(config_path)?)?; let path = config_path.parent().unwrap(); // --------------------- Load header --------------------- let (header, header_logo) = if options.load_header { - let header: Header = serde_yml::from_reader(open_file(path.join(&config.header))?)?; + let header: Header = serde_saphyr::from_reader(open_file(path.join(&config.header))?)?; let header_logo = Logo::from_png(path.join(&config.header_logo))?; (header, header_logo) } else { @@ -340,25 +346,25 @@ impl<'a> Rom<'a> { }; // --------------------- Load ARM9 program --------------------- - let arm9_build_config: Arm9BuildConfig = serde_yml::from_reader(open_file(path.join(&config.arm9_config))?)?; + let arm9_build_config: Arm9BuildConfig = serde_saphyr::from_reader(open_file(path.join(&config.arm9_config))?)?; let arm9 = read_file(path.join(&config.arm9_bin))?; // --------------------- Load autoloads --------------------- let mut autoloads = vec![]; let itcm = read_file(path.join(&config.itcm.bin))?; - let itcm_info = serde_yml::from_reader(open_file(path.join(&config.itcm.config))?)?; + let itcm_info = serde_saphyr::from_reader(open_file(path.join(&config.itcm.config))?)?; let itcm = Autoload::new(itcm, itcm_info); autoloads.push(itcm); let dtcm = read_file(path.join(&config.dtcm.bin))?; - let dtcm_info = serde_yml::from_reader(open_file(path.join(&config.dtcm.config))?)?; + let dtcm_info = serde_saphyr::from_reader(open_file(path.join(&config.dtcm.config))?)?; let dtcm = Autoload::new(dtcm, dtcm_info); autoloads.push(dtcm); for unknown_autoload in &config.unknown_autoloads { let autoload = read_file(path.join(&unknown_autoload.files.bin))?; - let autoload_info = serde_yml::from_reader(open_file(path.join(&unknown_autoload.files.config))?)?; + let autoload_info = serde_saphyr::from_reader(open_file(path.join(&unknown_autoload.files.config))?)?; let autoload = Autoload::new(autoload, autoload_info); autoloads.push(autoload); } @@ -408,14 +414,14 @@ impl<'a> Rom<'a> { // --------------------- Load ARM7 program --------------------- let arm7 = read_file(path.join(&config.arm7_bin))?; - let arm7_config = serde_yml::from_reader(open_file(path.join(&config.arm7_config))?)?; + let arm7_config = serde_saphyr::from_reader(open_file(path.join(&config.arm7_config))?)?; let arm7 = Arm7::new(arm7, arm7_config); // --------------------- Load banner --------------------- let banner = if options.load_banner { let banner_path = path.join(&config.banner); let banner_dir = banner_path.parent().unwrap(); - let mut banner: Banner = serde_yml::from_reader(open_file(&banner_path)?)?; + let mut banner: Banner = serde_saphyr::from_reader(open_file(&banner_path)?)?; banner.images.load(banner_dir)?; banner } else { @@ -436,7 +442,7 @@ impl<'a> Rom<'a> { // --------------------- Load multiboot signature --------------------- let multiboot_signature = if let Some(multiboot_signature) = config.multiboot_signature.as_ref() { - serde_yml::from_reader(open_file(path.join(multiboot_signature))?)? + serde_saphyr::from_reader(open_file(path.join(multiboot_signature))?)? } else { None }; @@ -464,7 +470,7 @@ impl<'a> Rom<'a> { ) -> Result, RomSaveError> { let path = config_path.parent().unwrap(); let mut overlays = vec![]; - let overlay_table_config: OverlayTableConfig = serde_yml::from_reader(open_file(config_path)?)?; + let overlay_table_config: OverlayTableConfig = serde_saphyr::from_reader(open_file(config_path)?)?; let num_overlays = overlay_table_config.overlays.len(); for mut config in overlay_table_config.overlays.into_iter() { let data = read_file(path.join(config.file_name))?; @@ -516,15 +522,15 @@ impl<'a> Rom<'a> { log::info!("Saving ROM to directory {}", path.display()); // --------------------- Save config --------------------- - serde_yml::to_writer(create_file_and_dirs(path.join("config.yaml"))?, &self.config)?; + serde_saphyr::to_io_writer(&mut create_file_and_dirs(path.join("config.yaml"))?, &self.config)?; // --------------------- Save header --------------------- - serde_yml::to_writer(create_file_and_dirs(path.join(&self.config.header))?, &self.header)?; + serde_saphyr::to_io_writer(&mut create_file_and_dirs(path.join(&self.config.header))?, &self.header)?; self.header_logo.save_png(path.join(&self.config.header_logo))?; // --------------------- Save ARM9 program --------------------- let arm9_build_config = self.arm9_build_config()?; - serde_yml::to_writer(create_file_and_dirs(path.join(&self.config.arm9_config))?, &arm9_build_config)?; + serde_saphyr::to_io_writer(&mut create_file_and_dirs(path.join(&self.config.arm9_config))?, &arm9_build_config)?; let mut plain_arm9 = self.arm9.clone(); if plain_arm9.is_encrypted() { let Some(key) = key else { @@ -564,7 +570,7 @@ impl<'a> Rom<'a> { } }; create_file_and_dirs(bin_path)?.write_all(autoload.code())?; - serde_yml::to_writer(create_file_and_dirs(config_path)?, autoload.info())?; + serde_saphyr::to_io_writer(&mut create_file_and_dirs(config_path)?, autoload.info())?; } // --------------------- Save ARM9 overlays --------------------- @@ -574,7 +580,7 @@ impl<'a> Rom<'a> { // --------------------- Save ARM7 program --------------------- create_file_and_dirs(path.join(&self.config.arm7_bin))?.write_all(self.arm7.full_data())?; - serde_yml::to_writer(create_file_and_dirs(path.join(&self.config.arm7_config))?, self.arm7.offsets())?; + serde_saphyr::to_io_writer(&mut create_file_and_dirs(path.join(&self.config.arm7_config))?, self.arm7.offsets())?; // --------------------- Save ARM7 overlays --------------------- if let Some(arm7_overlays_config) = &self.config.arm7_overlays { @@ -585,7 +591,7 @@ impl<'a> Rom<'a> { { let banner_path = path.join(&self.config.banner); let banner_dir = banner_path.parent().unwrap(); - serde_yml::to_writer(create_file_and_dirs(&banner_path)?, &self.banner)?; + serde_saphyr::to_io_writer(&mut create_file_and_dirs(&banner_path)?, &self.banner)?; self.banner.images.save_bitmap_file(banner_dir)?; } @@ -613,7 +619,7 @@ impl<'a> Rom<'a> { if let Some(multiboot_signature) = &self.multiboot_signature { if let Some(signature_file) = &self.config.multiboot_signature { let file_path = path.join(signature_file); - serde_yml::to_writer(create_file_and_dirs(&file_path)?, multiboot_signature)?; + serde_saphyr::to_io_writer(&mut create_file_and_dirs(&file_path)?, multiboot_signature)?; } } else if self.config.multiboot_signature.is_some() { log::warn!("Multiboot signature not found, but config requested it to be saved"); @@ -661,7 +667,7 @@ impl<'a> Rom<'a> { table_signature: overlay_table.signature(), overlays: configs, }; - serde_yml::to_writer(create_file(config_path)?, &overlay_table_config)?; + serde_saphyr::to_io_writer(&mut create_file_and_dirs(config_path)?, &overlay_table_config)?; } Ok(()) } From 9535155acb0fe012fbb7763bad810a3cfb55f002 Mon Sep 17 00:00:00 2001 From: Aetias Date: Sat, 27 Dec 2025 11:09:40 +0100 Subject: [PATCH 09/16] Skip multiboot signature if `rom_size_ds` is not aligned --- lib/src/rom/raw/rom.rs | 3 ++- lib/src/rom/rom.rs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/rom/raw/rom.rs b/lib/src/rom/raw/rom.rs index 5bc99f6..3d0f463 100644 --- a/lib/src/rom/raw/rom.rs +++ b/lib/src/rom/raw/rom.rs @@ -317,7 +317,8 @@ impl<'a> Rom<'a> { let data = &self.data[start..]; match MultibootSignature::borrow_from_slice(data) { Ok(s) => Ok(Some(s)), - Err(RawMultibootSignatureError::InvalidMagic { .. }) => Ok(None), + Err(RawMultibootSignatureError::InvalidMagic { .. }) => Ok(None), // signature not found + Err(RawMultibootSignatureError::Misaligned { .. }) => Ok(None), // not aligned by 4 Err(e) => Err(e), } } diff --git a/lib/src/rom/rom.rs b/lib/src/rom/rom.rs index 0bd76bf..dd1d31e 100644 --- a/lib/src/rom/rom.rs +++ b/lib/src/rom/rom.rs @@ -679,6 +679,8 @@ impl<'a> Rom<'a> { /// This function will return an error if a component is missing from the raw ROM. pub fn extract(rom: &'a raw::Rom) -> Result { let header = rom.header()?; + log::info!("Extracting from {}", header.title); + let fnt = rom.fnt()?; let fat = rom.fat()?; let banner = rom.banner()?; From 8e2eea7e5630de42694efb2ff31f1977bc551308 Mon Sep 17 00:00:00 2001 From: Aetias Date: Sat, 27 Dec 2025 14:05:26 +0100 Subject: [PATCH 10/16] Update CI workflow --- .github/workflows/{release.yml => build.yml} | 49 ++++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) rename .github/workflows/{release.yml => build.yml} (69%) diff --git a/.github/workflows/release.yml b/.github/workflows/build.yml similarity index 69% rename from .github/workflows/release.yml rename to .github/workflows/build.yml index 92f46be..2a94923 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/build.yml @@ -1,10 +1,48 @@ -name: Release ds-rom +name: Build on: + pull_request: workflow_dispatch: +env: + RUSTFLAGS: -D warnings + jobs: - build: + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Rust + uses: dtolnay/rust-toolchain@stable + with: + components: clippy + + - name: Cache Rust workspace + uses: Swatinem/rust-cache@v2 + + - name: Clippy + run: cargo clippy + + fmt: + name: Format + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Rust + uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt + + - name: Format + run: cargo fmt --all --check + + build-cli: + name: Build ds-rom-cli strategy: matrix: include: @@ -17,7 +55,6 @@ jobs: name: linux-x86_64 target: x86_64-unknown-linux-gnu file: dsrom-linux-x86_64 - runs-on: ${{ matrix.os }} steps: - name: Checkout code @@ -54,9 +91,11 @@ jobs: name: dsrom-${{ matrix.name }} path: ${{ matrix.file }} if-no-files-found: error - + release: - needs: build + name: Release + needs: build-cli + if: startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest permissions: contents: write From 68e456e754230ec67c9bf53e2ae346e1db8b43fb Mon Sep 17 00:00:00 2001 From: Aetias Date: Sat, 27 Dec 2025 14:07:00 +0100 Subject: [PATCH 11/16] Bump version --- Cargo.lock | 4 ++-- cli/Cargo.toml | 2 +- lib/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24c1403..b3c9206 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,7 +301,7 @@ dependencies = [ [[package]] name = "ds-rom" -version = "0.6.1" +version = "0.7.0" dependencies = [ "anyhow", "bitfield-struct", @@ -321,7 +321,7 @@ dependencies = [ [[package]] name = "ds-rom-cli" -version = "0.6.1" +version = "0.7.0" dependencies = [ "anyhow", "clap", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 9c0e1fc..d12616b 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ds-rom-cli" -version = "0.6.1" +version = "0.7.0" edition = "2021" authors = ["Aetias "] license = "MIT" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 0727aa1..6ae7440 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ds-rom" -version = "0.6.1" +version = "0.7.0" edition = "2021" authors = ["Aetias "] license = "MIT" From ce9701fa86441fd85158e0287f195f593660d5f1 Mon Sep 17 00:00:00 2001 From: Aetias Date: Sat, 27 Dec 2025 18:09:16 +0100 Subject: [PATCH 12/16] `Arm9::libraries` method to get library version strings --- cli/src/dump.rs | 23 +++++++++++++++++++ lib/src/rom/arm9.rs | 40 +++++++++++++++++++++++++++++++- lib/src/rom/library_entry.rs | 44 ++++++++++++++++++++++++++++++++++++ lib/src/rom/mod.rs | 2 ++ 4 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 lib/src/rom/library_entry.rs diff --git a/cli/src/dump.rs b/cli/src/dump.rs index 5357e4f..077b422 100644 --- a/cli/src/dump.rs +++ b/cli/src/dump.rs @@ -76,6 +76,7 @@ impl Dump { DumpCommand::Arm9Footer(dump_arm9_footer) => dump_arm9_footer.run(&rom), DumpCommand::Arm9OverlaySignatures(dump_arm9_overlay_signatures) => dump_arm9_overlay_signatures.run(&rom), DumpCommand::MultibootSignature(dump_multiboot_signature) => dump_multiboot_signature.run(&rom), + DumpCommand::Libraries(dump_libraries) => dump_libraries.run(&rom), } } } @@ -106,6 +107,8 @@ enum DumpCommand { Arm9OverlaySignatures(DumpArm9OverlaySignatures), #[command(name = "mb-sig")] MultibootSignature(DumpMultibootSignature), + #[command(name = "libs")] + Libraries(DumpLibraries), } /// Shows the contents of the ROM header. @@ -516,3 +519,23 @@ impl DumpMultibootSignature { Ok(()) } } + +/// Prints libraries used by the game. +#[derive(Args)] +pub struct DumpLibraries {} + +impl DumpLibraries { + pub fn run(&self, raw_rom: &raw::Rom) -> Result<()> { + let arm9 = raw_rom.arm9()?; + let libraries = arm9.libraries()?; + + if libraries.is_empty() { + println!("No libraries found"); + } + for library in libraries { + println!("{}", library.display(2)); + } + + Ok(()) + } +} diff --git a/lib/src/rom/arm9.rs b/lib/src/rom/arm9.rs index 7919b7d..0e43a6d 100644 --- a/lib/src/rom/arm9.rs +++ b/lib/src/rom/arm9.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, io, mem::replace, ops::Range}; +use std::{borrow::Cow, io, mem::replace, ops::Range, str::Utf8Error}; use serde::{Deserialize, Serialize}; use snafu::{Backtrace, Snafu}; @@ -14,6 +14,7 @@ use crate::{ compress::lz77::{Lz77, Lz77DecompressError}, crc::CRC_16_MODBUS, crypto::blowfish::{Blowfish, BlowfishError, BlowfishKey, BlowfishLevel}, + rom::LibraryEntry, }; /// ARM9 program. @@ -352,6 +353,43 @@ impl<'a> Arm9<'a> { BuildInfo::borrow_from_slice_mut(&mut self.data.to_mut()[self.offsets.build_info as usize..]) } + /// Returns the library version strings in this [`Arm9`]. + /// + /// # Errors + /// + /// This function will return an error if a library string is not valid UTF-8. + pub fn libraries(&self) -> Result]>, Utf8Error> { + let libraries_start = self.offsets.build_info as usize + size_of::(); + let mut address = self.base_address() + libraries_start as u32; + let mut data = &self.data[libraries_start..]; + + let mut libraries = Vec::new(); + + 'outer: while data[0] == b'[' { + let Some((end_pos, _)) = data.iter().enumerate().find(|(_, c)| **c == b']') else { + break; + }; + let version_string = str::from_utf8(&data[..end_pos + 1])?; + + libraries.push(LibraryEntry::new(address, version_string)); + + address += end_pos as u32 + 1; + data = &data[end_pos + 1..]; + loop { + match data[0] { + b'\0' => { + address += 1; + data = &data[1..] + } + b'[' => break, + _ => break 'outer, + } + } + } + + Ok(libraries.into_boxed_slice()) + } + /// Returns whether this ARM9 program is compressed. See [`Self::originally_compressed`] for whether the program was /// compressed originally. /// diff --git a/lib/src/rom/library_entry.rs b/lib/src/rom/library_entry.rs new file mode 100644 index 0000000..5b75ac8 --- /dev/null +++ b/lib/src/rom/library_entry.rs @@ -0,0 +1,44 @@ +use std::fmt::Display; + +/// A library version string entry after the build info of an ARM9 program. +pub struct LibraryEntry<'a> { + address: u32, + version_string: &'a str, +} + +impl<'a> LibraryEntry<'a> { + /// Creates a new [`LibraryEntry`]. + pub fn new(address: u32, version_string: &'a str) -> Self { + Self { address, version_string } + } + + /// Returns the address of this [`LibraryEntry`]. + pub fn address(&self) -> u32 { + self.address + } + + /// Returns the version string of this [`LibraryEntry`]. + pub fn version_string(&self) -> &'a str { + self.version_string + } + + /// Returns a [`DisplayLibraryEntry`] which implements [`Display`]. + pub fn display(&'a self, indent: usize) -> DisplayLibraryEntry<'a> { + DisplayLibraryEntry { entry: self, indent } + } +} + +/// Can be used to display values inside [`LibraryEntry`]. +pub struct DisplayLibraryEntry<'a> { + entry: &'a LibraryEntry<'a>, + indent: usize, +} + +impl Display for DisplayLibraryEntry<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let i = " ".repeat(self.indent); + writeln!(f, "{i}Address .......... : {:#010x}", self.entry.address)?; + writeln!(f, "{i}Version string ... : {}", self.entry.version_string)?; + Ok(()) + } +} diff --git a/lib/src/rom/mod.rs b/lib/src/rom/mod.rs index 3e20baa..accd3b7 100644 --- a/lib/src/rom/mod.rs +++ b/lib/src/rom/mod.rs @@ -6,6 +6,7 @@ mod build_info; mod config; mod file; mod header; +mod library_entry; mod logo; mod overlay; mod overlay_table; @@ -21,6 +22,7 @@ pub use build_info::*; pub use config::*; pub use file::*; pub use header::*; +pub use library_entry::*; pub use logo::*; pub use overlay::*; pub use overlay_table::*; From c80b09ec7aa076ddaee029cde2dd1ea8907df87f Mon Sep 17 00:00:00 2001 From: Aetias Date: Fri, 20 Feb 2026 18:15:48 +0100 Subject: [PATCH 13/16] Bump dependencies --- Cargo.lock | 531 +++++++++++++++++++++++++++++-------------------- lib/Cargo.toml | 28 +-- 2 files changed, 329 insertions(+), 230 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3c9206..06da492 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 4 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" @@ -32,18 +32,29 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "annotate-snippets" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "c86cd1c51b95d71dde52bca69ed225008f6ff4c8cc825b08042aa1ef823e1980" dependencies = [ + "anstyle", "memchr", + "unicode-width", ] [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -56,43 +67,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", + "once_cell_polyfill", "windows-sys", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "arraydeque" @@ -102,23 +114,23 @@ checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-link", ] [[package]] @@ -129,9 +141,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitfield-struct" -version = "0.8.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de05f8756f1c68937349406d4632ae96ae35901019b5e59c508d9c38c64715fb" +checksum = "8769c4854c5ada2852ddf6fd09d15cf43d4c2aaeccb4de6432f5402f08a6003b" dependencies = [ "proc-macro2", "quote", @@ -140,15 +152,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitreader" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdd859c9d97f7c468252795b35aeccc412bdbb1e90ee6969c4fa6328272eaeff" +checksum = "886559b1e163d56c765bc3a985febb4eee8009f625244511d8ee3c432e08c066" dependencies = [ "cfg-if", ] @@ -162,11 +174,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" dependencies = [ "bytemuck_derive", ] @@ -183,28 +201,22 @@ dependencies = [ ] [[package]] -name = "byteorder" -version = "1.5.0" +name = "byteorder-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cc" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "779e6b7d17797c0b42023d417228c02889300190e700cb074c3438d9c541d332" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.22" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", "clap_derive", @@ -212,9 +224,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.22" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstream", "anstyle", @@ -224,9 +236,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck", "proc-macro2", @@ -236,15 +248,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "cpufeatures" @@ -257,9 +269,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -272,18 +284,18 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -332,9 +344,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -350,9 +362,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" dependencies = [ "log", "regex", @@ -360,42 +372,42 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "fdeflate" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" dependencies = [ "simd-adler32", ] [[package]] name = "flate2" -version = "1.0.30" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", ] -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "generic-array" version = "0.14.7" @@ -413,99 +425,138 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasip2", + "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.29.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "image" +version = "0.25.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" dependencies = [ - "foldhash", + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "png", ] [[package]] -name = "hashlink" -version = "0.10.0" +name = "indexmap" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ + "equivalent", "hashbrown", ] [[package]] -name = "heck" -version = "0.5.0" +name = "is_terminal_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] -name = "humantime" -version = "2.1.0" +name = "itoa" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] -name = "image" -version = "0.25.1" +name = "jiff" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" +checksum = "c867c356cc096b33f4981825ab281ecba3db0acefe60329f044c1789d94c6543" dependencies = [ - "bytemuck", - "byteorder", - "num-traits", - "png", + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", ] [[package]] -name = "is_terminal_polyfill" -version = "1.70.1" +name = "jiff-static" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "f7946b4325269738f270bb55b3c19ab5c5040525f83fd625259422a9d25d9be5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "itoa" -version = "1.0.11" +name = "js-sys" +version = "0.3.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d36139f1c97c42c0c86a411910b04e48d4939a0376e6e0f989420cbdee0120e5" +dependencies = [ + "once_cell", + "wasm-bindgen", +] [[package]] name = "libc" -version = "0.2.155" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "log" -version = "0.4.22" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", "simd-adler32", ] +[[package]] +name = "moxcms" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -523,9 +574,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.1" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -536,11 +587,17 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "png" -version = "0.17.13" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ "bitflags", "crc32fast", @@ -549,20 +606,44 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +dependencies = [ + "portable-atomic", +] + [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] +[[package]] +name = "pxfm" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" +dependencies = [ + "num-traits", +] + [[package]] name = "quote" -version = "1.0.42" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -575,9 +656,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "regex" -version = "1.10.6" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -587,9 +668,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -598,9 +679,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "rust-bitwriter" @@ -613,24 +694,25 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] -name = "ryu" -version = "1.0.21" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62049b2877bf12821e8f9ad256ee38fdc31db7387ec2d3b3f403024de2034aea" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] -name = "saphyr-parser" -version = "0.0.6" +name = "saphyr-parser-bw" +version = "0.0.608" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb771b59f6b1985d1406325ec28f97cfb14256abcec4fdfb37b36a1766d6af7" +checksum = "d55ae5ea09894b6d5382621db78f586df37ef18ab581bf32c754e75076b124b1" dependencies = [ "arraydeque", - "hashlink", + "smallvec", + "thiserror", ] [[package]] @@ -645,20 +727,23 @@ dependencies = [ [[package]] name = "serde-saphyr" -version = "0.0.11" +version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc40144bd36ca0cf5c8ee3bc181d315f2ba92c0078a59f32317d89938140829" +checksum = "29fb2d57f074f415e3ea6905994be8aca2bd7a17f8a0344cc43ed15bf240a547" dependencies = [ "ahash", + "annotate-snippets", "base64", "encoding_rs_io", + "getrandom", "nohash-hasher", "num-traits", - "ryu", - "saphyr-parser", + "regex", + "saphyr-parser-bw", "serde", "serde_json", "smallvec", + "zmij", ] [[package]] @@ -683,10 +768,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.147" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af14725505314343e673e9ecb7cd7e8a36aa9791eb936235a3567cc31447ae4" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ + "indexmap", "itoa", "memchr", "serde", @@ -707,21 +793,21 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] name = "smallvec" -version = "2.0.0-alpha.12" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef784004ca8777809dcdad6ac37629f0a97caee4c685fcea805278d81dd8b857" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "snafu" -version = "0.8.3" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418b8136fec49956eba89be7da2847ec1909df92a9ae4178b5ff0ff092c8d95e" +checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2" dependencies = [ "backtrace", "snafu-derive", @@ -729,9 +815,9 @@ dependencies = [ [[package]] name = "snafu-derive" -version = "0.8.3" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a4812a669da00d17d8266a0439eddcacbc88b17f732f927e52eeb9d196f7fb5" +checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" dependencies = [ "heck", "proc-macro2", @@ -747,26 +833,52 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "utf8parse" @@ -782,106 +894,93 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ "wit-bindgen", ] [[package]] -name = "windows-sys" -version = "0.52.0" +name = "wasm-bindgen" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "9ff9c7baef35ac3c0e17d8bfc9ad75eb62f85a2f02bccc906699dadb0aa9c622" dependencies = [ - "windows-targets", + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] -name = "windows-targets" -version = "0.52.5" +name = "wasm-bindgen-macro" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "39455e84ad887a0bbc93c116d72403f1bb0a39e37dd6f235a43e2128a0c7f1fd" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "quote", + "wasm-bindgen-macro-support", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" +name = "wasm-bindgen-macro-support" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "dff4761f60b0b51fd13fec8764167b7bbcc34498ce3e52805fe1db6f2d56b6d6" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] [[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" +name = "wasm-bindgen-shared" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "bc6a171c53d98021a93a474c4a4579d76ba97f9517d871bc12e27640f218b6dd" +dependencies = [ + "unicode-ident", +] [[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", @@ -890,6 +989,6 @@ dependencies = [ [[package]] name = "zmij" -version = "0.1.9" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0095ecd462946aa3927d9297b63ef82fb9a5316d7a37d134eeb36e58228615a" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 6ae7440..3bb7f0d 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -9,22 +9,22 @@ readme = "../README.md" description = "Library for extracting/building Nintendo DS ROMs." [dependencies] -bitfield-struct = "0.8.0" -bitreader = "0.3.8" -bytemuck = { version = "1.16.1", features = ["derive"] } -crc = "3.2.1" -encoding_rs = "0.8.34" -image = { version = "0.25.1", default-features = false, features = ["png"] } -log = "0.4.22" -rust-bitwriter = "0.0.1" -serde = { version = "1.0.204", features = ["derive"] } -serde-saphyr = "0.0.11" -sha1 = "0.10.6" -snafu = { version = "0.8.3", features = ["backtrace"] } +bitfield-struct = "0.12" +bitreader = "0.3" +bytemuck = { version = "1.25", features = ["derive"] } +crc = "3.4" +encoding_rs = "0.8" +image = { version = "0.25", default-features = false, features = ["png"] } +log = "0.4" +rust-bitwriter = "0.0" +serde = { version = "1.0", features = ["derive"] } +serde-saphyr = "0.0" +sha1 = "0.10" +snafu = { version = "0.8", features = ["backtrace"] } [dev-dependencies] -anyhow = "1.0.86" -env_logger = "0.11.5" +anyhow = "1.0" +env_logger = "0.11" [lints.clippy] needless_range_loop = "allow" From 8cb9b26495c05c3a6e908421b13cc36986b5dc27 Mon Sep 17 00:00:00 2001 From: Aetias Date: Fri, 20 Feb 2026 18:22:43 +0100 Subject: [PATCH 14/16] Enable LTO --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index e223453..861184b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,6 @@ [workspace] members = ["cli", "lib"] resolver = "2" + +[profile.release] +lto = true From fad7e5d337d6fb13b1eacc9a498ae85f72a018d3 Mon Sep 17 00:00:00 2001 From: Aetias Date: Fri, 20 Feb 2026 18:23:03 +0100 Subject: [PATCH 15/16] Use `image::ImageReader` over deprecated `image::io::Reader` --- lib/src/rom/banner.rs | 6 +++--- lib/src/rom/logo.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/src/rom/banner.rs b/lib/src/rom/banner.rs index bbd4bea..6fe0b85 100644 --- a/lib/src/rom/banner.rs +++ b/lib/src/rom/banner.rs @@ -3,7 +3,7 @@ use std::{ path::{Path, PathBuf}, }; -use image::{io::Reader, GenericImageView, ImageError, Rgba, RgbaImage}; +use image::{GenericImageView, ImageError, ImageReader, Rgba, RgbaImage}; use serde::{Deserialize, Serialize}; use snafu::{Backtrace, Snafu}; @@ -218,7 +218,7 @@ impl BannerImages { /// This function will return an error if [`Reader::open`] or [`Reader::decode`] fails, or if the images are the wrong /// size, or the bitmap has a color not present in the palette. pub fn load(&mut self, path: &Path) -> Result<(), BannerImageError> { - let bitmap_image = Reader::open(path.join(&self.bitmap_path))?.decode()?; + let bitmap_image = ImageReader::open(path.join(&self.bitmap_path))?.decode()?; if bitmap_image.width() != 32 || bitmap_image.height() != 32 { return WrongSizeSnafu { expected: ImageSize { width: 32, height: 32 }, @@ -227,7 +227,7 @@ impl BannerImages { .fail(); } - let palette_image = Reader::open(path.join(&self.palette_path))?.decode()?; + let palette_image = ImageReader::open(path.join(&self.palette_path))?.decode()?; if palette_image.width() != 16 || palette_image.height() != 1 { return WrongSizeSnafu { expected: ImageSize { width: 16, height: 1 }, diff --git a/lib/src/rom/logo.rs b/lib/src/rom/logo.rs index c7f5c0b..6854d9b 100644 --- a/lib/src/rom/logo.rs +++ b/lib/src/rom/logo.rs @@ -1,6 +1,6 @@ use std::{fmt::Display, io, path::Path}; -use image::{io::Reader, GenericImageView, GrayImage, ImageError, Luma}; +use image::{GenericImageView, GrayImage, ImageError, ImageReader, Luma}; use snafu::{Backtrace, Snafu}; use crate::compress::huffman::{NibbleHuffman, NibbleHuffmanCode}; @@ -175,7 +175,7 @@ impl Logo { /// /// This function will return an error if it failed to open or decode the image, or the image has the wrong size or colors. pub fn from_png>(path: P) -> Result { - let image = Reader::open(path)?.decode()?; + let image = ImageReader::open(path)?.decode()?; if image.width() != WIDTH as u32 || image.height() != HEIGHT as u32 { ImageSizeSnafu { expected: ImageSize { width: WIDTH as u32, height: HEIGHT as u32 }, From dc46cb18020cbc8366d08932487df31ed3b3e5b5 Mon Sep 17 00:00:00 2001 From: Aetias Date: Fri, 20 Feb 2026 18:34:03 +0100 Subject: [PATCH 16/16] Clippy --- lib/src/rom/arm9.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/rom/arm9.rs b/lib/src/rom/arm9.rs index 0e43a6d..1352f36 100644 --- a/lib/src/rom/arm9.rs +++ b/lib/src/rom/arm9.rs @@ -545,7 +545,7 @@ impl<'a> Arm9<'a> { if end > self.data.len() { return Ok(None); } - return Ok(Some(start..end)); + Ok(Some(start..end)) } /// Returns the ARM9 overlay table signature. @@ -593,7 +593,7 @@ impl<'a> Arm9<'a> { if end > self.data.len() { return Ok(None); } - return Ok(Some(start..end)); + Ok(Some(start..end)) } /// Returns the ARM9 overlay signature table.