use crate::{Error, HEADER_SIZE, Result, SECTION_HDR_SIZE, SECTION_INDEX_SIZE, slice_to_str};
use bitflags::bitflags;
use bytemuck::{Pod, Zeroable, bytes_of};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionError {
LengthError,
BaseError(u32),
EntryOffsetOutOfRange(u32, u32),
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
pub struct SectionHdr {
pub flag: SectionFlag,
pub _pad1: [u8; 3],
pub base: u32,
pub size: u32,
pub _pad2: [u8; 4],
}
bitflags! {
#[repr(transparent)]
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
pub struct SectionFlag: u8 {
const LOADABLE = 1;
const EXECABLE = 1 << 1;
}
}
impl SectionHdr {
#[inline]
pub fn to_array(&self) -> [u8; SECTION_HDR_SIZE] {
let mut arr = [0u8; SECTION_HDR_SIZE];
arr.copy_from_slice(bytes_of(self));
arr
}
#[inline]
pub fn validate(&self) -> Result<()> {
if self.size == 0 {
return Err(Error::SectionError(SectionError::LengthError));
}
Ok(())
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
pub struct SectionIndex {
pub base: u32,
pub name_len: u32,
}
impl SectionIndex {
#[inline]
pub fn to_array(&self) -> [u8; SECTION_INDEX_SIZE] {
let mut arr = [0u8; SECTION_INDEX_SIZE];
arr.copy_from_slice(bytes_of(self));
arr
}
}
#[derive(Debug, Clone, Copy)]
pub struct SectionTable<'a> {
buf: &'a [u8],
total: u16,
current: u16,
}
impl<'a> SectionTable<'a> {
pub(crate) fn new(buf: &'a [u8], total: u16) -> Self {
Self {
buf,
total,
current: 0,
}
}
pub fn get(&self, index: usize) -> Option<SectionIndex> {
if index >= self.total as usize {
return None;
}
let offset = HEADER_SIZE + index * SECTION_INDEX_SIZE;
let slice = &self.buf[offset..offset + SECTION_INDEX_SIZE];
let mut section_index = SectionIndex::zeroed();
bytemuck::bytes_of_mut(&mut section_index).copy_from_slice(slice);
Some(section_index)
}
pub fn get_hdr_secindex(&self, section_index: SectionIndex) -> SectionHdr {
let offset = section_index.base as usize;
let slice = &self.buf[offset..offset + SECTION_HDR_SIZE];
let mut hdr = SectionHdr::zeroed();
bytemuck::bytes_of_mut(&mut hdr).copy_from_slice(slice);
hdr
}
pub fn get_hdr_idx(&self, index: usize) -> Option<SectionHdr> {
let section_index = self.get(index)?;
Some(self.get_hdr_secindex(section_index))
}
pub fn get_name_secindex(&self, section_index: SectionIndex) -> &str {
let offset = section_index.base as usize + SECTION_HDR_SIZE;
let content = &self.buf[offset..offset + section_index.name_len as usize];
slice_to_str(content).expect("Failed to get section's name")
}
pub fn get_name_idx(&self, index: usize) -> Option<&str> {
let section_index = self.get(index)?;
Some(self.get_name_secindex(section_index))
}
}
impl<'a> Iterator for SectionTable<'a> {
type Item = SectionIndex;
fn next(&mut self) -> Option<Self::Item> {
let result = self.get(self.current as usize)?;
self.current += 1;
Some(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_header_length() {
assert_eq!(crate::SECTION_HDR_SIZE, 16);
assert_eq!(core::mem::size_of::<SectionHdr>(), 16)
}
}