use super::str_to_array;
use crate::header::{ExecMode, Header};
use crate::sections::{SectionFlag, SectionHdr, SectionIndex};
use crate::{Error, HEADER_SIZE, Result, SECTION_HDR_SIZE, SECTION_INDEX_SIZE};
#[cfg(feature = "alloc")]
use alloc::{
string::{String, ToString},
vec::Vec,
};
#[derive(Debug, Clone)]
#[cfg(feature = "alloc")]
pub struct Builder<'a> {
min: [u16; 3],
max: [u16; 3],
entry: (u32, usize), author: String,
name: String,
mode: ExecMode,
sections: Vec<InnerSections<'a>>,
}
#[cfg(feature = "alloc")]
impl Default for Builder<'_> {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "alloc")]
impl<'a> Builder<'a> {
pub fn new() -> Self {
Self {
min: [0; 3],
max: [0; 3],
entry: (0, 0),
author: String::new(),
name: String::new(),
mode: ExecMode::UserApp,
sections: Vec::new(),
}
}
pub fn set_author(&mut self, author: &str) {
self.author = author.to_string();
}
pub fn set_name(&mut self, name: &str) {
self.name = name.to_string();
}
pub fn set_mode(&mut self, mode: ExecMode) {
self.mode = mode;
}
pub fn set_min(&mut self, min: [u16; 3]) {
self.min = min;
}
pub fn set_max(&mut self, max: [u16; 3]) {
self.max = max;
}
pub fn append(
&mut self,
data: &'a [u8],
name: &'a str,
is_loadable: bool,
is_execable: bool,
entry: Option<u32>,
) -> Result<()> {
if entry.is_some() && !(is_execable && is_loadable) {
return Err(Error::ExecutableCorrupted);
}
let flag = match (is_loadable, is_execable) {
(true, true) => SectionFlag::LOADABLE | SectionFlag::EXECABLE,
(true, false) => SectionFlag::LOADABLE,
(false, true) => SectionFlag::EXECABLE,
(false, false) => SectionFlag::empty(),
};
let section = InnerSections {
secinfo: SectionHdr {
flag,
_pad1: [0; 3],
base: 0, size: data.len() as u32,
_pad2: [0; 4],
},
secindex: SectionIndex {
base: 0, name_len: name.len() as u32,
},
name,
data,
};
self.sections.push(section);
if let Some(ent_offset) = entry {
let sec_index = self.sections.len() - 1;
self.entry = (ent_offset, sec_index);
}
Ok(())
}
pub fn build(self) -> Result<Vec<u8>> {
if self.sections.is_empty() {
return Err(Error::NoSections);
}
for (&min, &max) in self.min.iter().zip(self.max.iter()) {
if min > max {
return Err(Error::VersionIncorrect(self.min, self.max));
}
}
let mut data: Vec<u8> = Vec::new();
{
let mut header = Header::default();
header.min = self.min;
header.max = self.max;
header.entry_off = self.entry.0;
header.entry_sec = self.entry.1 as u16;
header.mode = self.mode;
header.author = str_to_array(self.author.as_str());
header.name = str_to_array(self.name.as_str());
header.sections = self.sections.len() as u16;
let header_bytes = header.to_array();
data.extend_from_slice(&header_bytes);
}
let mut cnt = 0;
for section in &self.sections {
let mut secindex = section.secindex;
secindex.base = (HEADER_SIZE + self.sections.len() * SECTION_INDEX_SIZE + cnt) as u32;
data.extend_from_slice(&secindex.to_array());
cnt += SECTION_HDR_SIZE + secindex.name_len as usize;
}
for section in &self.sections {
let mut secinfo = section.secinfo;
secinfo.base = (HEADER_SIZE + self.sections.len() * SECTION_INDEX_SIZE + cnt) as u32;
data.extend_from_slice(&secinfo.to_array());
data.extend_from_slice(section.name.as_bytes());
cnt += section.data.len();
}
for section in &self.sections {
data.extend_from_slice(section.data);
}
Ok(data)
}
}
#[derive(Debug, Clone, Copy)]
struct InnerSections<'a> {
pub secinfo: SectionHdr,
pub secindex: SectionIndex,
pub name: &'a str,
pub data: &'a [u8],
}