use std::fs::File;
use std::io::{Read, Seek};
use std::path::Path;
use color_eyre::eyre::{Context, Result, eyre};
use log::debug;
mod elf;
mod ihex;
mod raw;
use self::elf::ELFFirmwareFile;
use self::ihex::IntelHexFirmwareFile;
use self::raw::RawFirmwareFile;
trait FirmwareStorage
{
fn load_address(&self) -> Option<u32>;
fn firmware_data(&self) -> &[u8];
}
pub struct FirmwareFile
{
inner: Box<dyn FirmwareStorage>,
}
impl FirmwareFile
{
pub fn from_path(file_name: &Path) -> Result<Self>
{
let mut file =
File::open(file_name).wrap_err_with(|| eyre!("Failed to read file {} as firmware", file_name.display()))?;
debug!("Reading firmware from {}", file_name.display());
let mut signature = [0u8; 4];
let _ = file.read(&mut signature)?;
file.rewind()?;
let storage: Box<dyn FirmwareStorage> = if &signature == b"\x7fELF" {
Box::new(ELFFirmwareFile::try_from(file)?)
} else if &signature[0..1] == b":" {
Box::new(IntelHexFirmwareFile::try_from(file)?)
} else {
Box::new(RawFirmwareFile::try_from(file)?)
};
Ok(Self {
inner: storage,
})
}
pub fn load_address(&self) -> Option<u32>
{
self.inner.load_address()
}
pub fn data(&self) -> &[u8]
{
self.inner.firmware_data()
}
pub fn len(&self) -> u32
{
self.inner.firmware_data().len() as u32
}
}