ds_rom/rom/raw/
arm9_footer.rs1use std::{
2 fmt::Display,
3 mem::{align_of, size_of},
4};
5
6use bytemuck::{Pod, PodCastError, Zeroable};
7use snafu::{Backtrace, Snafu};
8
9use super::{RawHeaderError, NITROCODE};
10
11#[repr(C)]
13#[derive(Clone, Copy, Zeroable, Pod)]
14pub struct Arm9Footer {
15 nitrocode: u32,
16 pub build_info_offset: u32,
18 pub overlay_signatures_offset: u32,
20}
21
22#[derive(Debug, Snafu)]
24pub enum Arm9FooterError {
25 #[snafu(transparent)]
27 RawHeader {
28 source: RawHeaderError,
30 },
31 #[snafu(display("ARM9 footer must be {expected} bytes but got {actual} bytes:\n{backtrace}"))]
33 WrongSize {
34 expected: usize,
36 actual: usize,
38 backtrace: Backtrace,
40 },
41 #[snafu(display("expected {expected}-alignment for ARM9 footer but got {actual}-alignment:\n{backtrace}"))]
43 Misaligned {
44 expected: usize,
46 actual: usize,
48 backtrace: Backtrace,
50 },
51 #[snafu(display("expected nitrocode {expected:#x} in ARM9 footer but got {actual:#x}:\n{backtrace}"))]
53 NoNitrocode {
54 expected: u32,
56 actual: u32,
58 backtrace: Backtrace,
60 },
61}
62
63impl Arm9Footer {
64 pub fn new(build_info_offset: u32, overlay_signatures_offset: u32) -> Self {
66 Self { nitrocode: NITROCODE, build_info_offset, overlay_signatures_offset }
67 }
68
69 fn check_size(data: &'_ [u8]) -> Result<(), Arm9FooterError> {
70 if data.len() != size_of::<Self>() {
71 WrongSizeSnafu { expected: size_of::<Self>(), actual: data.len() }.fail()
72 } else {
73 Ok(())
74 }
75 }
76
77 fn handle_pod_cast<T>(result: Result<T, PodCastError>, addr: usize) -> Result<T, Arm9FooterError> {
78 match result {
79 Ok(build_info) => Ok(build_info),
80 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
81 MisalignedSnafu { expected: align_of::<Self>(), actual: 1usize << addr.trailing_zeros() }.fail()
82 }
83 Err(PodCastError::AlignmentMismatch) => panic!(),
84 Err(PodCastError::OutputSliceWouldHaveSlop) => panic!(),
85 Err(PodCastError::SizeMismatch) => unreachable!(),
86 }
87 }
88
89 fn check_nitrocode(&self) -> Result<(), Arm9FooterError> {
90 if self.nitrocode != NITROCODE {
91 NoNitrocodeSnafu { expected: NITROCODE, actual: self.nitrocode }.fail()
92 } else {
93 Ok(())
94 }
95 }
96
97 pub fn borrow_from_slice(data: &'_ [u8]) -> Result<&'_ Self, Arm9FooterError> {
103 Self::check_size(data)?;
104 let addr = data as *const [u8] as *const () as usize;
105 let footer: &Self = Self::handle_pod_cast(bytemuck::try_from_bytes(data), addr)?;
106 footer.check_nitrocode()?;
107 Ok(footer)
108 }
109
110 pub fn borrow_from_slice_mut(data: &'_ mut [u8]) -> Result<&'_ mut Self, Arm9FooterError> {
116 Self::check_size(data)?;
117 let addr = data as *const [u8] as *const () as usize;
118 let footer: &mut Self = Self::handle_pod_cast(bytemuck::try_from_bytes_mut(data), addr)?;
119 footer.check_nitrocode()?;
120 Ok(footer)
121 }
122
123 pub fn display(&self, indent: usize) -> DisplayArm9Footer<'_> {
125 DisplayArm9Footer { footer: self, indent }
126 }
127}
128
129pub struct DisplayArm9Footer<'a> {
131 footer: &'a Arm9Footer,
132 indent: usize,
133}
134
135impl Display for DisplayArm9Footer<'_> {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 let i = " ".repeat(self.indent);
138 writeln!(f, "{i} Build info offset .......... : {:#x}", self.footer.build_info_offset)?;
139 writeln!(f, "{i} Overlay signatures offset .. : {:#x}", self.footer.overlay_signatures_offset)
140 }
141}