use byteorder::ByteOrder;
use byteorder::LittleEndian;
pub static MZ_HEADER_START: u16 = 0x5A4D;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum HeaderError {
NotMZ,
NoHeader,
}
impl HeaderError {
pub fn to_str(&self) -> &'static str {
match self {
HeaderError::NotMZ => "Not an MZ header.",
HeaderError::NoHeader => "No header could be read.",
}
}
}
#[derive(Debug)]
pub struct Header {
pub signature: u16,
pub extra_bytes: u16,
pub pages: u16,
pub reloc_items: u16,
pub header_size: u16,
pub min_alloc: u16,
pub max_alloc: u16,
pub init_ss: u16,
pub init_sp: u16,
pub checksum: u16,
pub init_ip: u16,
pub init_cs: u16,
pub reloc_table: u16,
pub overlay: u16,
}
impl Header {
pub fn from_words(words: [u16; 14]) -> Result<Header, HeaderError> {
if words[0] != MZ_HEADER_START {
return Err(HeaderError::NotMZ);
}
let out = Header {
signature: words[0],
extra_bytes: words[1],
pages: words[2],
reloc_items: words[3],
header_size: words[4],
min_alloc: words[5],
max_alloc: words[6],
init_ss: words[7],
init_sp: words[8],
checksum: words[9],
init_ip: words[10],
init_cs: words[11],
reloc_table: words[12],
overlay: words[13],
};
Ok(out)
}
pub fn new(bytes: &[u8]) -> Result<Header, HeaderError> {
let mut words: [u16; 14] = [0u16; 14];
let mut it = bytes.chunks_exact(2);
for i in 0..14 {
match it.next() {
Some(some) => {
words[i] = LittleEndian::read_u16(some);
}
None => {
return Err(HeaderError::NoHeader);
}
}
}
Header::from_words(words)
}
#[inline]
pub fn exe_data_start(&self) -> usize {
(self.header_size as usize) * 16
}
pub fn extra_data_start(&self) -> usize {
let mut extra_data_start = (self.pages as usize) * 512;
if self.extra_bytes != 0 {
extra_data_start -= 512 - (self.extra_bytes as usize);
}
extra_data_start
}
#[inline]
pub fn relocation_table_start(&self) -> usize {
self.reloc_table as usize
}
#[inline]
pub fn relocation_table_end(&self) -> usize {
(self.reloc_table + (self.reloc_items * 2 * 2)) as usize
}
pub fn exe_data<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
match bytes.split_at(self.extra_data_start()) {
(data, _) => match data.split_at(self.exe_data_start()) {
(_, data) => data,
},
}
}
pub fn extra_data<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
match bytes.split_at(self.extra_data_start()) {
(_, data) => data,
}
}
pub fn header_data<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
let header_offset = (self.header_size as usize) * 16;
match bytes.split_at(header_offset) {
(data, _) => data,
}
}
pub fn relocation_table_data<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
match bytes.split_at(self.relocation_table_end()) {
(data, _) => match data.split_at(self.relocation_table_start()) {
(_, data) => data,
},
}
}
}