diff --git a/dcb-exe/src/exe.rs b/dcb-exe/src/exe.rs index 2b37483..66e9a6b 100644 --- a/dcb-exe/src/exe.rs +++ b/dcb-exe/src/exe.rs @@ -25,6 +25,7 @@ use dcb_io::GameFile; use std::{ convert::TryFrom, io::{Read, Seek, Write}, + ops::{self, Range}, }; /// The game executable @@ -33,7 +34,7 @@ pub struct Exe { /// The executable header header: Header, - /// All bytes within the executable + /// All instruction bytes within the executable. bytes: Box<[u8]>, /// The data table. @@ -73,6 +74,14 @@ impl Exe { &self.func_table } + /// Returns this executable's instruction range + #[must_use] + pub fn inst_range(&self) -> Range { + let start = self.header.start_pos; + let end = self.header.start_pos + self.header.size; + start..end + } + /// Creates an iterator over this executable #[must_use] pub const fn iter(&self) -> iter::Iter { @@ -123,3 +132,14 @@ impl Exe { }) } } + +impl ops::Index> for Exe { + type Output = [u8]; + + fn index(&self, index: Range) -> &Self::Output { + let start = index.start.offset_from(self.header.start_pos); + let end = index.end.offset_from(self.header.start_pos); + + &self.bytes[start..end] + } +} diff --git a/dcb-exe/src/exe/iter.rs b/dcb-exe/src/exe/iter.rs index dafec8b..45355c3 100644 --- a/dcb-exe/src/exe/iter.rs +++ b/dcb-exe/src/exe/iter.rs @@ -58,7 +58,7 @@ impl<'a> Iterator for Iter<'a> { fn next(&mut self) -> Option { // If we're at the end, return `None` let cur_pos = self.cur_pos; - if cur_pos >= self.exe.header.start_pos + self.exe.header.size { + if cur_pos >= self.exe.inst_range().end { return None; } @@ -76,10 +76,7 @@ impl<'a> Iterator for Iter<'a> { return Some(ExeItem::Data { data, - insts: ParseIter::new( - &self.exe.bytes[cur_pos.as_mem_idx(self.exe.header.start_pos)..end_pos.as_mem_idx(self.exe.header.start_pos)], - cur_pos, - ), + insts: ParseIter::new(&self.exe[cur_pos..end_pos], cur_pos), }); } @@ -88,16 +85,13 @@ impl<'a> Iterator for Iter<'a> { self.cur_pos = func.end_pos; return Some(ExeItem::Func { func, - insts: ParseIter::new( - &self.exe.bytes[cur_pos.as_mem_idx(self.exe.header.start_pos)..func.end_pos.as_mem_idx(self.exe.header.start_pos)], - cur_pos, - ), + insts: ParseIter::new(&self.exe[cur_pos..func.end_pos], cur_pos), }); } // Else return an iterator until the next data / function, or until end, if none or past the end. - let next_data = self.exe.data_table.range(cur_pos..).next(); - let next_func = self.exe.func_table.range(cur_pos..).next(); + let next_data = self.exe.data_table().range(cur_pos..).next(); + let next_func = self.exe.func_table().range(cur_pos..).next(); let end_pos = match (next_data, next_func) { (Some(next_data), Some(next_func)) => match next_data.pos < next_func.start_pos { @@ -106,19 +100,16 @@ impl<'a> Iterator for Iter<'a> { }, (Some(next_data), None) => next_data.pos, (None, Some(next_func)) => next_func.start_pos, - (None, None) => self.exe.header.start_pos + self.exe.header.size, + (None, None) => self.exe.inst_range().end, }; // Make sure to limit the end position - let end_pos = end_pos.min(self.exe.header.start_pos + self.exe.header.size); + let end_pos = end_pos.min(self.exe.inst_range().end); self.cur_pos = end_pos; Some(ExeItem::Unknown { - insts: ParseIter::new( - &self.exe.bytes[cur_pos.as_mem_idx(self.exe.header.start_pos)..end_pos.as_mem_idx(self.exe.header.start_pos)], - cur_pos, - ), + insts: ParseIter::new(&self.exe[cur_pos..end_pos], cur_pos), }) } } diff --git a/dcb-exe/src/exe/pos.rs b/dcb-exe/src/exe/pos.rs index e98c153..b9b0b1d 100644 --- a/dcb-exe/src/exe/pos.rs +++ b/dcb-exe/src/exe/pos.rs @@ -13,10 +13,10 @@ use std::{convert::TryFrom, fmt, ops}; pub struct Pos(pub u32); impl Pos { - /// Returns the memory position of this position + /// Calculated the offset between two positions #[must_use] - pub fn as_mem_idx(self, start_pos: Self) -> usize { - usize::try_from(self - start_pos).expect("Failed to compute index") + pub fn offset_from(self, start_pos: Self) -> usize { + usize::try_from(self - start_pos).expect("Negative offset") } }