gc_gcm/
dol.rs

1use crate::GcmError;
2use core::mem::size_of;
3use binread::{BinRead, BinReaderExt, io::{self, SeekFrom}, helpers::read_bytes};
4
5#[cfg(feature = "no_std")]
6use crate::std::vec::Vec;
7
8const SECTION_COUNT: usize = 18;
9
10/// The header of a dol executable, describing the 19 sections (including the bss) as well as the
11/// entrypoint of the executable.
12#[derive(BinRead, Debug)]
13pub struct DolHeader {
14    pub section_offsets: [u32; SECTION_COUNT],
15    pub section_addresses: [u32; SECTION_COUNT],
16    pub section_lengths: [u32; SECTION_COUNT],
17
18    pub bss_address: u32,
19    pub bss_length: u32,
20
21    pub entrypoint: u32,
22}
23
24impl DolHeader {
25    const SIZE: usize = (SECTION_COUNT * size_of::<u32>() * 3) + (size_of::<u32>() * 3);
26
27    pub fn calculate_file_size(&self) -> usize {
28        self.section_offsets
29            .iter()
30            .zip(self.section_lengths.iter())
31            .map(|(start, len)| (start + len) as usize)
32            .max()
33            .unwrap()
34    }
35}
36
37/// A dol ("Dolphin") executable file, used as the main executable of the gamecube
38///
39/// ```
40/// use gc_gcm::DolFile;
41///
42/// let dol = DolFile::open("boot.dol").unwrap();
43///
44/// println!(".text size: {:#x?}", dol.header.section_lengths[0]);
45/// ```
46#[derive(BinRead)]
47pub struct DolFile {
48    pub header: DolHeader,
49
50    #[br(seek_before = SeekFrom::Current(-(DolHeader::SIZE as i64)))]
51    #[br(count = header.calculate_file_size())]
52    #[br(parse_with = read_bytes)]
53    pub raw_data: Vec<u8>,
54}
55
56impl DolFile {
57    /// Parse a dol from a reader that implements `io::Read` and `io::Seek`
58    pub fn from_reader<R>(reader: &mut R) -> Result<Self, GcmError>
59        where R: io::Read + io::Seek,
60    {
61        Ok(reader.read_be()?)
62    }
63}
64
65#[cfg(not(feature = "no_std"))]
66use std::path::Path;
67
68#[cfg(not(feature = "no_std"))]
69impl DolFile {
70    /// Open a file from a given bath as a DolFile.
71    pub fn open<P>(path: P) -> Result<Self, GcmError>
72        where P: AsRef<Path>,
73    {
74        let mut reader = std::io::BufReader::new(std::fs::File::open(path)?);
75        Ok(reader.read_be()?)
76    }
77}
78
79use core::fmt;
80
81impl fmt::Debug for DolFile {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        f.debug_struct("DolFile")
84            .field("header", &self.header)
85            .finish()
86    }
87}