1use crate::util::{opt_u32, read_str, read_u32le, read_u8};
2use crate::Patch;
3use std::convert::TryInto;
4use std::fmt::{self, Display, Formatter};
5use std::io::{self, Read};
6
7#[derive(Debug)]
9pub struct Section {
10 name: Vec<u8>,
11 source_file_id: Option<u32>,
12 line_no: Option<u32>,
13 size: u32,
14 sect_type: SectionType,
15 modifier: SectionMod,
16 org: Option<u32>,
17 bank: Option<u32>,
18 align: u8,
19 ofs: u32,
20}
21impl Section {
22 pub(crate) fn read_from(mut input: impl Read, has_src: bool) -> Result<Self, io::Error> {
23 let name = read_str(&mut input)?;
24 let source_file_id = if has_src {
25 Some(read_u32le(&mut input)?)
26 } else {
27 None
28 };
29 let line_no = if has_src {
30 Some(read_u32le(&mut input)?)
31 } else {
32 None
33 };
34 let size = read_u32le(&mut input)?;
35 let sect_type = read_u8(&mut input)?;
36 let modifier = SectionMod::from(sect_type)?;
37 let org = opt_u32(read_u32le(&mut input)?);
38 let bank = opt_u32(read_u32le(&mut input)?);
39 let align = read_u8(&mut input)?;
40 let ofs = read_u32le(&mut input)?;
41
42 let sect_type = SectionType::read_from(sect_type, input, size.try_into().unwrap())?;
43
44 Ok(Self {
45 name,
46 source_file_id,
47 line_no,
48 size,
49 sect_type,
50 modifier,
51 org,
52 bank,
53 align,
54 ofs,
55 })
56 }
57
58 pub fn name(&self) -> &[u8] {
61 &self.name
62 }
63
64 pub fn source(&self) -> Option<(u32, u32)> {
68 match (self.source_file_id, self.line_no) {
69 (Some(source_file_id), Some(line_no)) => Some((source_file_id, line_no)),
70 _ => None,
71 }
72 }
73
74 pub fn size(&self) -> u32 {
76 self.size
77 }
78
79 pub fn type_data(&self) -> &SectionType {
81 &self.sect_type
82 }
83
84 pub fn modifier(&self) -> SectionMod {
86 self.modifier
87 }
88
89 pub fn org(&self) -> Option<u32> {
91 self.org
92 }
93
94 pub fn bank(&self) -> Option<u32> {
96 self.bank
97 }
98
99 pub fn align(&self) -> u8 {
101 self.align
102 }
103
104 pub fn align_ofs(&self) -> u32 {
106 self.ofs
107 }
108}
109
110#[derive(Debug)]
112pub enum SectionType {
113 Wram0,
114 Vram,
115 Romx(SectionData),
116 Rom0(SectionData),
117 Hram,
118 Wramx,
119 Sram,
120 Oam,
121}
122impl SectionType {
123 fn read_from(byte: u8, input: impl Read, size: usize) -> Result<Self, io::Error> {
124 use SectionType::*;
125
126 Ok(match byte & 0x3F {
127 0 => Wram0,
128 1 => Vram,
129 2 => Romx(SectionData::read_from(input, size)?),
130 3 => Rom0(SectionData::read_from(input, size)?),
131 4 => Hram,
132 5 => Wramx,
133 6 => Sram,
134 7 => Oam,
135 _ => {
136 return Err(io::Error::new(
137 io::ErrorKind::InvalidData,
138 "Invalid section type",
139 ))
140 }
141 })
142 }
143
144 pub fn data(&self) -> Option<&SectionData> {
146 use SectionType::*;
147
148 match self {
149 Rom0(data) | Romx(data) => Some(data),
150 _ => None,
151 }
152 }
153
154 pub fn is_banked(&self) -> bool {
158 use SectionType::*;
159
160 matches!(self, Romx(..) | Vram | Sram | Wramx)
161 }
162
163 pub fn name(&self) -> &'static str {
165 use SectionType::*;
166
167 match self {
168 Wram0 => "WRAM0",
169 Vram => "VRAM",
170 Romx(..) => "ROMX",
171 Rom0(..) => "ROM0",
172 Hram => "HRAM",
173 Wramx => "WRAMX",
174 Sram => "SRAM",
175 Oam => "OAM",
176 }
177 }
178}
179impl Display for SectionType {
180 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
181 write!(fmt, "{}", self.name())
182 }
183}
184
185#[derive(Debug, PartialEq, Eq, Clone, Copy)]
187pub enum SectionMod {
188 Normal,
189 Union,
190 Fragment,
191}
192impl SectionMod {
193 fn from(byte: u8) -> Result<Self, io::Error> {
194 use SectionMod::*;
195
196 Ok(match byte & 0xC0 {
197 0x00 => Normal,
198 0x80 => Union,
199 0x40 => Fragment,
200 _ => {
201 return Err(io::Error::new(
202 io::ErrorKind::InvalidData,
203 "Invalid section modifier",
204 ))
205 }
206 })
207 }
208
209 pub fn name(&self) -> Option<&'static str> {
211 use SectionMod::*;
212
213 match self {
214 Normal => None,
215 Union => Some("UNION"),
216 Fragment => Some("FRAGMENT"),
217 }
218 }
219}
220
221#[derive(Debug)]
223pub struct SectionData {
224 data: Vec<u8>,
225 patches: Vec<Patch>,
226}
227impl SectionData {
228 fn read_from(mut input: impl Read, size: usize) -> Result<Self, io::Error> {
229 let mut data = vec![0; size];
230 input.read_exact(&mut data)?;
231
232 let nb_patches = read_u32le(&mut input)?.try_into().unwrap();
233 let mut patches = Vec::with_capacity(nb_patches);
234 for _ in 0..nb_patches {
235 patches.push(Patch::read_from(&mut input)?);
236 }
237
238 Ok(Self { data, patches })
239 }
240
241 pub fn data(&self) -> &[u8] {
243 &self.data
244 }
245
246 pub fn patches(&self) -> &[Patch] {
248 &self.patches
249 }
250}