use crate::{utils, PartitionError, PartitionType, SliceExt};
#[cfg(feature = "heapless")]
use heapless::String;
pub type PartitionBuffer = [u8; PartitionEntry::SIZE];
#[derive(Clone, Debug, Default)]
pub struct PartitionEntry {
pub type_: PartitionType,
pub offset: u32,
pub size: usize,
#[cfg(feature = "heapless")]
pub name: String<{ Self::MAX_NAME_LEN }>,
#[cfg(not(feature = "heapless"))]
name: [u8; Self::MAX_NAME_LEN],
pub encrypted: bool,
}
impl PartitionEntry {
pub const MAGIC: [u8; 2] = [0xAA, 0x50];
pub const SIZE: usize = 32;
pub const MAX_NAME_LEN: usize = 16;
pub fn new(
type_: impl Into<PartitionType>,
offset: u32,
size: usize,
name: impl AsRef<str>,
encrypted: bool,
) -> Result<Self, PartitionError> {
let name = name.as_ref();
#[cfg(feature = "heapless")]
let name = name.try_into().map_err(|_| PartitionError::InvalidString)?;
#[cfg(not(feature = "heapless"))]
let name = {
let mut name_data = [0u8; Self::MAX_NAME_LEN];
utils::name_into(&mut name_data, name)?;
name_data
};
Ok(Self {
type_: type_.into(),
offset,
size,
name,
encrypted,
})
}
pub fn set_offset(&mut self, offset: u32) -> Result<(), PartitionError> {
self.type_.check_offset(offset)?;
self.offset = offset;
Ok(())
}
pub fn name(&self) -> &str {
#[cfg(not(feature = "heapless"))]
{
let name = utils::name_trim(&self.name);
unsafe { core::str::from_utf8_unchecked(name) }
}
#[cfg(feature = "heapless")]
{
&self.name
}
}
pub fn set_name(&mut self, name: impl AsRef<str>) -> Result<(), PartitionError> {
let name = name.as_ref();
#[cfg(feature = "heapless")]
{
self.name = name.try_into().map_err(|_| PartitionError::InvalidString)?;
Ok(())
}
#[cfg(not(feature = "heapless"))]
{
utils::name_into(&mut self.name, name)
}
}
pub fn from_bytes(data: &PartitionBuffer) -> Result<Self, PartitionError> {
let (magic, data) = data.split_array_ref_();
if magic != &Self::MAGIC {
return Err(PartitionError::InvalidMagic);
}
let (type_data, data) = data.split_array_ref_();
let type_ = type_data.try_into()?;
let (offset_data, data) = data.split_array_ref_();
let offset = u32::from_le_bytes(*offset_data);
let (size_data, data) = data.split_array_ref_();
let size = u32::from_le_bytes(*size_data) as usize;
let (name_data, data) = data.split_array_ref_();
let _name_str = utils::name_from(name_data)?;
#[cfg(feature = "heapless")]
let name = _name_str.into();
#[cfg(not(feature = "heapless"))]
let name = *name_data;
let (flags_data, _) = data.split_array_ref_();
let flags = u32::from_le_bytes(*flags_data);
let encrypted = flags & 0x01 != 0;
Ok(Self {
type_,
offset,
size,
name,
encrypted,
})
}
pub fn to_bytes(&self, data: &mut PartitionBuffer) -> Result<(), PartitionError> {
self.type_.check_offset(self.offset)?;
let (magic_data, data) = data.split_array_mut_();
*magic_data = Self::MAGIC;
let (type_data, data) = data.split_array_mut_();
self.type_.to_bytes(type_data)?;
let (offset_data, data) = data.split_array_mut_();
*offset_data = self.offset.to_le_bytes();
let (size_data, data) = data.split_array_mut_();
*size_data = (self.size as u32).to_le_bytes();
let (name_data, data) = data.split_array_mut_();
#[cfg(feature = "heapless")]
utils::name_into(name_data, self.name.as_str())?;
#[cfg(not(feature = "heapless"))]
{
*name_data = self.name;
}
let (flags_data, _) = data.split_array_mut_();
*flags_data = (self.encrypted as u32).to_le_bytes();
Ok(())
}
}
impl AsRef<PartitionEntry> for PartitionEntry {
fn as_ref(&self) -> &Self {
self
}
}
impl TryFrom<&[u8]> for PartitionEntry {
type Error = PartitionError;
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
<&PartitionBuffer>::try_from(data)
.map_err(|_| PartitionError::NotEnoughData)
.and_then(Self::try_from)
}
}
impl TryFrom<&PartitionBuffer> for PartitionEntry {
type Error = PartitionError;
fn try_from(data: &PartitionBuffer) -> Result<Self, Self::Error> {
Self::from_bytes(data)
}
}
pub type Md5Data = [u8; 16];
#[derive(Clone, Debug, Default)]
pub struct PartitionMd5 {
pub data: Md5Data,
}
impl From<PartitionMd5> for Md5Data {
fn from(md5: PartitionMd5) -> Self {
md5.data
}
}
impl From<Md5Data> for PartitionMd5 {
fn from(data: Md5Data) -> Self {
Self { data }
}
}
#[cfg(feature = "md5")]
impl From<md5::Digest> for PartitionMd5 {
fn from(digest: md5::Digest) -> Self {
Self {
data: digest.into(),
}
}
}
impl PartitionMd5 {
pub const MAGIC: [u8; 2] = [0xeb, 0xeb];
pub const RESERVED_SIZE: usize = 14;
pub const RESERVED_DATA: u8 = 0xff;
pub fn from_bytes(data: &PartitionBuffer) -> Result<Self, PartitionError> {
let (magic, data) = data.split_array_ref_();
if magic != &Self::MAGIC {
return Err(PartitionError::InvalidMagic);
}
let (reserved_data, data) = data.split_array_ref_::<{ Self::RESERVED_SIZE }>();
for reserved in reserved_data {
if *reserved != Self::RESERVED_DATA {
return Err(PartitionError::InvalidMagic);
}
}
let (md5_data, _) = data.split_array_ref_();
Ok(Self { data: *md5_data })
}
pub fn to_bytes(&self, data: &mut PartitionBuffer) -> Result<(), PartitionError> {
let (magic_data, data) = data.split_array_mut_();
*magic_data = Self::MAGIC;
let (reserved_data, data) = data.split_array_mut_::<{ Self::RESERVED_SIZE }>();
reserved_data.fill(Self::RESERVED_DATA);
let (md5_data, _) = data.split_array_mut_();
*md5_data = self.data;
Ok(())
}
}
impl TryFrom<&[u8]> for PartitionMd5 {
type Error = PartitionError;
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
<&PartitionBuffer>::try_from(data)
.map_err(|_| PartitionError::NotEnoughData)
.and_then(Self::try_from)
}
}
impl TryFrom<&PartitionBuffer> for PartitionMd5 {
type Error = PartitionError;
fn try_from(data: &PartitionBuffer) -> Result<Self, Self::Error> {
Self::from_bytes(data)
}
}