ds_rom/rom/raw/
overlay.rs1use std::{
2 fmt::Display,
3 mem::{align_of, size_of},
4};
5
6use bitfield_struct::bitfield;
7use bytemuck::{Pod, PodCastError, Zeroable};
8use snafu::{Backtrace, Snafu};
9
10use super::{RawArm9Error, RawHeaderError};
11use crate::rom::Arm9OverlaySignaturesError;
12
13#[repr(C)]
15#[derive(Clone, Copy, Zeroable, Pod)]
16pub struct Overlay {
17 pub id: u32,
19 pub base_addr: u32,
21 pub code_size: u32,
23 pub bss_size: u32,
25 pub ctor_start: u32,
27 pub ctor_end: u32,
29 pub file_id: u32,
31 pub flags: OverlayFlags,
33}
34
35#[derive(Snafu, Debug)]
37pub enum RawOverlayError {
38 #[snafu(transparent)]
40 RawHeader {
41 source: RawHeaderError,
43 },
44 #[snafu(transparent)]
46 RawArm9 {
47 source: RawArm9Error,
49 },
50 #[snafu(transparent)]
52 Arm9OverlaySignatures {
53 source: Arm9OverlaySignaturesError,
55 },
56 #[snafu(display("the overlay table must be a multiple of {} bytes:\n{backtrace}", size_of::<Overlay>()))]
58 InvalidSize {
59 backtrace: Backtrace,
61 },
62 #[snafu(display("expected {expected}-alignment for overlay table but got {actual}-alignment:\n{backtrace}"))]
64 Misaligned {
65 expected: usize,
67 actual: usize,
69 backtrace: Backtrace,
71 },
72}
73
74impl Overlay {
75 fn check_size(data: &[u8]) -> Result<(), RawOverlayError> {
76 let size = size_of::<Self>();
77 if !data.len().is_multiple_of(size) {
78 InvalidSizeSnafu {}.fail()
79 } else {
80 Ok(())
81 }
82 }
83
84 fn handle_pod_cast<T>(result: Result<T, PodCastError>, addr: usize) -> Result<T, RawOverlayError> {
85 match result {
86 Ok(build_info) => Ok(build_info),
87 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
88 MisalignedSnafu { expected: align_of::<Self>(), actual: 1usize << addr.trailing_zeros() }.fail()
89 }
90 Err(PodCastError::AlignmentMismatch) => panic!(),
91 Err(PodCastError::OutputSliceWouldHaveSlop) => panic!(),
92 Err(PodCastError::SizeMismatch) => unreachable!(),
93 }
94 }
95
96 pub fn borrow_from_slice(data: &'_ [u8]) -> Result<&'_ [Self], RawOverlayError> {
102 Self::check_size(data)?;
103 let addr = data as *const [u8] as *const () as usize;
104 Self::handle_pod_cast(bytemuck::try_cast_slice(data), addr)
105 }
106
107 pub fn display(&self, indent: usize) -> DisplayOverlay<'_> {
109 DisplayOverlay { overlay: self, indent }
110 }
111}
112
113pub struct DisplayOverlay<'a> {
115 overlay: &'a Overlay,
116 indent: usize,
117}
118
119impl Display for DisplayOverlay<'_> {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 let i = " ".repeat(self.indent);
122 let overlay = &self.overlay;
123 writeln!(f, "{i}ID ............... : {}", overlay.id)?;
124 writeln!(f, "{i}File ID .......... : {}", overlay.file_id)?;
125 writeln!(f, "{i}Base address ..... : {:#x}", overlay.base_addr)?;
126 writeln!(f, "{i}Code size ........ : {:#x}", overlay.code_size)?;
127 writeln!(f, "{i}.bss size ........ : {:#x}", overlay.bss_size)?;
128 writeln!(f, "{i}.ctor start ...... : {:#x}", overlay.ctor_start)?;
129 writeln!(f, "{i}.ctor end ........ : {:#x}", overlay.ctor_end)?;
130 writeln!(f, "{i}Compressed size .. : {:#x}", overlay.flags.size())?;
131 writeln!(f, "{i}Is compressed .... : {}", overlay.flags.is_compressed())?;
132 writeln!(f, "{i}Is signed ........ : {}", overlay.flags.is_signed())?;
133 writeln!(f, "{i}Reserved flags ... : {:#x}", overlay.flags.reserved())?;
134 Ok(())
135 }
136}
137
138#[bitfield(u32)]
140pub struct OverlayFlags {
141 #[bits(24)]
143 pub size: usize,
144 pub is_compressed: bool,
145 pub is_signed: bool,
146 #[bits(6)]
147 pub reserved: u8,
148}
149
150unsafe impl Zeroable for OverlayFlags {}
151unsafe impl Pod for OverlayFlags {}