gcrecomp_core/recompiler/
parser.rs1use anyhow::{Context, Result};
19use std::io::{Cursor, Read};
20
21#[derive(Debug, Clone)]
25pub struct DolFile {
26 pub text_sections: Vec<Section>,
28 pub data_sections: Vec<Section>,
30 pub bss_address: u32,
32 pub bss_size: u32,
34 pub entry_point: u32,
36 pub path: String,
38}
39
40#[derive(Debug, Clone)]
44pub struct Section {
45 pub offset: u32,
47 pub address: u32,
49 pub size: u32,
51 pub data: Vec<u8>,
53 pub executable: bool,
55}
56
57impl DolFile {
58 #[inline(never)] pub fn parse(data: &[u8], path: &str) -> Result<Self> {
84 const MIN_DOL_SIZE: usize = 0x100usize;
85 if data.len() < MIN_DOL_SIZE {
86 anyhow::bail!("DOL file too small: {} bytes (minimum {} bytes)", data.len(), MIN_DOL_SIZE);
87 }
88
89 let mut cursor: Cursor<&[u8]> = Cursor::new(data);
90
91 const NUM_TEXT_SECTIONS: usize = 7usize;
93 let mut text_offsets: [u32; NUM_TEXT_SECTIONS] = [0u32; NUM_TEXT_SECTIONS];
94 for offset in text_offsets.iter_mut() {
95 *offset = read_u32_be(&mut cursor)?;
96 }
97
98 const NUM_DATA_SECTIONS: usize = 11usize;
100 let mut data_offsets: [u32; NUM_DATA_SECTIONS] = [0u32; NUM_DATA_SECTIONS];
101 for offset in data_offsets.iter_mut() {
102 *offset = read_u32_be(&mut cursor)?;
103 }
104
105 let mut text_addresses: [u32; NUM_TEXT_SECTIONS] = [0u32; NUM_TEXT_SECTIONS];
107 for addr in text_addresses.iter_mut() {
108 *addr = read_u32_be(&mut cursor)?;
109 }
110
111 let mut data_addresses: [u32; NUM_DATA_SECTIONS] = [0u32; NUM_DATA_SECTIONS];
113 for addr in data_addresses.iter_mut() {
114 *addr = read_u32_be(&mut cursor)?;
115 }
116
117 let mut text_sizes: [u32; NUM_TEXT_SECTIONS] = [0u32; NUM_TEXT_SECTIONS];
119 for size in text_sizes.iter_mut() {
120 *size = read_u32_be(&mut cursor)?;
121 }
122
123 let mut data_sizes: [u32; NUM_DATA_SECTIONS] = [0u32; NUM_DATA_SECTIONS];
125 for size in data_sizes.iter_mut() {
126 *size = read_u32_be(&mut cursor)?;
127 }
128
129 const BSS_OFFSET: u64 = 0xD8u64;
131 cursor.set_position(BSS_OFFSET);
132 let bss_address: u32 = read_u32_be(&mut cursor)?;
133 let bss_size: u32 = read_u32_be(&mut cursor)?;
134
135 const ENTRY_POINT_OFFSET: u64 = 0xE0u64;
137 cursor.set_position(ENTRY_POINT_OFFSET);
138 let entry_point: u32 = read_u32_be(&mut cursor)?;
139
140 let mut text_sections: Vec<Section> = Vec::with_capacity(NUM_TEXT_SECTIONS);
142 for i in 0usize..NUM_TEXT_SECTIONS {
143 if text_offsets[i] != 0u32 && text_sizes[i] != 0u32 {
144 let offset: usize = text_offsets[i] as usize;
145 let size: usize = text_sizes[i] as usize;
146
147 if offset.wrapping_add(size) > data.len() {
148 anyhow::bail!("Text section {} extends beyond file: offset {}, size {}", i, offset, size);
149 }
150
151 let section_data: Vec<u8> = data[offset..offset.wrapping_add(size)].to_vec();
152 text_sections.push(Section {
153 offset: text_offsets[i],
154 address: text_addresses[i],
155 size: text_sizes[i],
156 data: section_data,
157 executable: true,
158 });
159 }
160 }
161
162 let mut data_sections: Vec<Section> = Vec::with_capacity(NUM_DATA_SECTIONS);
164 for i in 0usize..NUM_DATA_SECTIONS {
165 if data_offsets[i] != 0u32 && data_sizes[i] != 0u32 {
166 let offset: usize = data_offsets[i] as usize;
167 let size: usize = data_sizes[i] as usize;
168
169 if offset.wrapping_add(size) > data.len() {
170 anyhow::bail!("Data section {} extends beyond file: offset {}, size {}", i, offset, size);
171 }
172
173 let section_data: Vec<u8> = data[offset..offset.wrapping_add(size)].to_vec();
174 data_sections.push(Section {
175 offset: data_offsets[i],
176 address: data_addresses[i],
177 size: data_sizes[i],
178 data: section_data,
179 executable: false,
180 });
181 }
182 }
183
184 Ok(Self {
185 text_sections,
186 data_sections,
187 bss_address,
188 bss_size,
189 entry_point,
190 path: path.to_string(),
191 })
192 }
193
194 #[inline] pub fn get_all_sections(&self) -> Vec<Section> {
205 let mut all: Vec<Section> = Vec::with_capacity(self.text_sections.len() + self.data_sections.len());
206 all.extend_from_slice(&self.text_sections);
207 all.extend_from_slice(&self.data_sections);
208 all
209 }
210}
211
212#[inline] fn read_u32_be(cursor: &mut Cursor<&[u8]>) -> Result<u32> {
221 const U32_SIZE: usize = 4usize;
222 let mut buf: [u8; U32_SIZE] = [0u8; U32_SIZE];
223 cursor
224 .read_exact(&mut buf)
225 .context("Failed to read u32 from DOL file")?;
226 Ok(u32::from_be_bytes(buf))
227}