use super::{decode_location, trunc_key_at0};
#[derive(Clone, Copy, Debug)]
pub struct Entry<R> {
pub name: R,
pub typ: u32,
pub location: u32,
pub meta: u32,
pub rest: R,
}
#[derive(Clone, Copy)]
pub struct Ref<'a> {
cklen: usize,
strtab: &'a [u8],
data: &'a [u8],
}
impl<'a> Ref<'a> {
pub fn parse(data: &'a [u8], location: u32) -> Option<Self> {
let sel = decode_location(location)?;
if data.len() < (sel + 16) {
return None;
}
let sel = &data[sel..];
let strtab_link = u32::from_be_bytes(sel[0..4].try_into().unwrap());
let entcount = u16::from_be_bytes(sel[4..6].try_into().unwrap());
let entsize = u16::from_be_bytes(sel[6..8].try_into().unwrap());
let strtab_loc = decode_location(strtab_link)?;
let dataspan = 16..(16 + 16 * usize::from(entsize) * usize::from(entcount));
if data.len() <= strtab_loc || entsize == 0 {
return None;
}
Some(Self {
cklen: 16 * usize::from(entsize),
strtab: &data[strtab_loc..],
data: sel.get(dataspan)?,
})
}
}
impl<'a> Iterator for Ref<'a> {
type Item = Entry<&'a [u8]>;
fn next(&mut self) -> Option<Self::Item> {
if self.data.len() < self.cklen {
debug_assert!(self.data.is_empty());
return None;
}
let (i, j) = self.data.split_at(self.cklen);
self.data = j;
let name = usize::try_from(u32::from_be_bytes(i[0..4].try_into().unwrap())).unwrap();
let name = trunc_key_at0(self.strtab.get(name..)?);
Some(Entry {
name,
typ: u32::from_be_bytes(i[4..8].try_into().unwrap()),
location: u32::from_be_bytes(i[8..12].try_into().unwrap()),
meta: u32::from_be_bytes(i[12..16].try_into().unwrap()),
rest: &i[16..],
})
}
}