Exe can now be sliced by a position range.

This commit is contained in:
Filipe Rodrigues 2021-01-12 03:32:05 +00:00
parent d9bc90882b
commit 5390df6d72
3 changed files with 32 additions and 21 deletions

View File

@ -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<Pos> {
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<Range<Pos>> for Exe {
type Output = [u8];
fn index(&self, index: Range<Pos>) -> &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]
}
}

View File

@ -58,7 +58,7 @@ impl<'a> Iterator for Iter<'a> {
fn next(&mut self) -> Option<Self::Item> {
// 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),
})
}
}

View File

@ -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")
}
}