mod pfs;
mod raw;
pub use pfs::{PfsNodeDecoder, PfsSessionDecoder};
pub use raw::RawDecoder;
#[derive(Debug, Clone, PartialEq)]
pub enum FieldValue {
None,
U64(u64),
Bytes(Vec<u8>),
Text(String),
Uid([u8; 16]),
Enum {
raw: u64,
name: String,
},
Flags {
raw: u64,
set: Vec<String>,
},
}
#[derive(Debug, Clone, PartialEq)]
pub struct FieldNode {
pub name: String,
pub value: FieldValue,
pub range: Option<(u64, u64)>,
pub note: Option<String>,
pub children: Vec<FieldNode>,
}
impl FieldNode {
pub fn group(name: impl Into<String>) -> Self {
Self {
name: name.into(),
value: FieldValue::None,
range: None,
note: None,
children: Vec::new(),
}
}
pub fn leaf(name: impl Into<String>, value: FieldValue, range: (u64, u64)) -> Self {
Self {
name: name.into(),
value,
range: Some(range),
note: None,
children: Vec::new(),
}
}
pub fn with_note(mut self, note: impl Into<String>) -> Self {
self.note = Some(note.into());
self
}
pub fn child(mut self, c: FieldNode) -> Self {
self.children.push(c);
self
}
pub fn push(&mut self, c: FieldNode) {
self.children.push(c);
}
}
#[derive(Debug, Clone, Copy)]
pub struct PartitionMeta<'a> {
pub partition_type: u32,
pub uid: &'a [u8; 16],
pub label: &'a str,
}
#[derive(Debug, Clone)]
pub struct Decoded {
pub format_name: String,
pub fields: Vec<FieldNode>,
pub warnings: Vec<String>,
}
pub trait PartitionDecoder {
fn name(&self) -> &'static str;
fn matches(&self, meta: &PartitionMeta, data: &[u8]) -> bool;
fn decode(&self, meta: &PartitionMeta, data: &[u8]) -> Decoded;
}
pub struct DecoderRegistry {
decoders: Vec<Box<dyn PartitionDecoder>>,
}
impl DecoderRegistry {
pub fn with_builtins() -> Self {
Self {
decoders: vec![
Box::new(PfsNodeDecoder),
Box::new(PfsSessionDecoder),
Box::new(RawDecoder),
],
}
}
pub fn register(&mut self, d: Box<dyn PartitionDecoder>) {
let insert_at = self.decoders.len().saturating_sub(1);
self.decoders.insert(insert_at, d);
}
pub fn names(&self) -> Vec<&'static str> {
self.decoders.iter().map(|d| d.name()).collect()
}
pub fn decode(&self, meta: &PartitionMeta, data: &[u8]) -> Decoded {
for d in &self.decoders {
if d.matches(meta, data) {
return d.decode(meta, data);
}
}
RawDecoder.decode(meta, data)
}
pub fn decode_with(&self, name: &str, meta: &PartitionMeta, data: &[u8]) -> Option<Decoded> {
self.decoders
.iter()
.find(|d| d.name() == name)
.map(|d| d.decode(meta, data))
}
}
impl Default for DecoderRegistry {
fn default() -> Self {
Self::with_builtins()
}
}
pub(crate) fn le_u16(data: &[u8], off: usize) -> Option<u16> {
Some(u16::from_le_bytes(data.get(off..off + 2)?.try_into().ok()?))
}
pub(crate) fn le_u32(data: &[u8], off: usize) -> Option<u32> {
Some(u32::from_le_bytes(data.get(off..off + 4)?.try_into().ok()?))
}
pub(crate) fn le_u64(data: &[u8], off: usize) -> Option<u64> {
Some(u64::from_le_bytes(data.get(off..off + 8)?.try_into().ok()?))
}
pub(crate) fn uid_at(data: &[u8], off: usize) -> Option<[u8; 16]> {
data.get(off..off + 16)?.try_into().ok()
}