#[cfg(test)]
use pretty_hex::PrettyHex;
use super::*;
pub struct SubsectionIter<'a> {
rest: &'a [u8],
}
impl<'a> SubsectionIter<'a> {
pub fn new(rest: &'a [u8]) -> Self {
Self { rest }
}
pub fn rest(&self) -> &'a [u8] {
self.rest
}
}
impl<'a> HasRestLen for SubsectionIter<'a> {
fn rest_len(&self) -> usize {
self.rest.len()
}
}
pub struct SubsectionIterMut<'a> {
rest: &'a mut [u8],
}
impl<'a> SubsectionIterMut<'a> {
pub fn new(rest: &'a mut [u8]) -> Self {
Self { rest }
}
pub fn rest(&self) -> &[u8] {
self.rest
}
}
impl<'a> HasRestLen for SubsectionIterMut<'a> {
fn rest_len(&self) -> usize {
self.rest.len()
}
}
pub struct Subsection<'a> {
pub kind: SubsectionKind,
pub data: &'a [u8],
}
pub struct SubsectionMut<'a> {
pub kind: SubsectionKind,
pub data: &'a mut [u8],
}
#[derive(IntoBytes, FromBytes, KnownLayout, Immutable, Unaligned)]
#[repr(C)]
pub struct SubsectionHeader {
pub kind: U32<LE>,
pub size: U32<LE>,
}
impl<'a> Iterator for SubsectionIter<'a> {
type Item = Subsection<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.rest.is_empty() {
return None;
}
let mut p = Parser::new(self.rest);
let header: &SubsectionHeader = if let Ok(h) = p.get::<SubsectionHeader>() {
h
} else {
warn!(
"Failed to decode subsection data (incomplete header)! rest_len = {}",
self.rest.len()
);
return None;
};
let size = header.size.get() as usize;
let data = if let Ok(d) = p.bytes(size) {
d
} else {
warn!(
"Failed to decode subsection data (incomplete payload)! rest_len = {}",
self.rest.len()
);
return None;
};
let alignment_len = (4 - (size & 3)) & 3;
let _ = p.skip(alignment_len);
self.rest = p.into_rest();
Some(Subsection {
kind: SubsectionKind(header.kind.get()),
data,
})
}
}
impl<'a> Iterator for SubsectionIterMut<'a> {
type Item = SubsectionMut<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.rest.is_empty() {
return None;
}
let mut p = ParserMut::new(core::mem::take(&mut self.rest));
let header: &SubsectionHeader = p.get::<SubsectionHeader>().ok()?;
let size = header.size.get() as usize;
let data = p.bytes_mut(size).ok()?;
let alignment_len = (4 - (size & 3)) & 3;
let _ = p.skip(alignment_len);
self.rest = p.into_rest();
Some(SubsectionMut {
kind: SubsectionKind(header.kind.get()),
data,
})
}
}
#[test]
fn empty_or_malformed_input() {
static CASES: &[(&str, &[u8])] = &[
("empty input", &[]),
("incomplete subsection_kind", &[0xf1, 0]),
("incomplete subsection_size", &[0xf1, 0, 0, 0, 0xff, 0xff]),
(
"incomplete subsection_data",
&[
0xf1, 0, 0, 0, 0, 0, 1, 0, ],
),
];
for &(case_name, case_data) in CASES.iter() {
println!("case: {}\n{:?}", case_name, case_data.hex_dump());
let ld = LineData::new(case_data);
assert_eq!(ld.subsections().count(), 0);
assert!(ld.find_checksums().is_none());
assert!(ld.find_checksums_bytes().is_none());
ld.iter_name_index(|_name| panic!("should never be called"))
.unwrap();
let mut case_data_mut = case_data.to_vec();
let mut ld = LineDataMut::new(&mut case_data_mut);
assert_eq!(ld.subsections_mut().count(), 0);
}
}
#[test]
fn test_subsection_alignment() {
const PAD: u8 = 0xaa;
#[rustfmt::skip]
static DATA: &[u8] = &[
0xf4, 0, 0, 0, 0x2, 0, 0, 0, 0xab, 0xcd, PAD, PAD, 0xf5, 0, 0, 0, 7, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, PAD, 0xf6, 0, 0, 0, 8, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1, 0xf7, 0, 0, 0, 5, 0, 0, 0, 10, 11, 12, 13, 14, PAD, PAD, PAD, ];
{
let mut iter = LineData::new(DATA).subsections();
let sub0 = iter.next().unwrap();
assert_eq!(sub0.kind, SubsectionKind::FILE_CHECKSUMS);
assert_eq!(sub0.data, &[0xab, 0xcd]);
let sub1 = iter.next().unwrap();
assert_eq!(sub1.kind, SubsectionKind::FRAMEDATA);
assert_eq!(sub1.data, &[1, 2, 3, 4, 5, 6, 7]);
let sub2 = iter.next().unwrap();
assert_eq!(sub2.kind, SubsectionKind::INLINEELINES);
assert_eq!(sub2.data, &[8, 7, 6, 5, 4, 3, 2, 1]);
let sub3 = iter.next().unwrap();
assert_eq!(sub3.kind, SubsectionKind::CROSSSCOPEIMPORTS);
assert_eq!(sub3.data, &[10, 11, 12, 13, 14]);
assert!(iter.rest().is_empty());
}
{
let mut data_mut = DATA.to_vec();
let mut iter = SubsectionIterMut::new(&mut data_mut);
let sub0 = iter.next().unwrap();
assert_eq!(sub0.kind, SubsectionKind::FILE_CHECKSUMS);
assert_eq!(sub0.data, &[0xab, 0xcd]);
let sub1 = iter.next().unwrap();
assert_eq!(sub1.kind, SubsectionKind::FRAMEDATA);
assert_eq!(sub1.data, &[1, 2, 3, 4, 5, 6, 7]);
let sub2 = iter.next().unwrap();
assert_eq!(sub2.kind, SubsectionKind::INLINEELINES);
assert_eq!(sub2.data, &[8, 7, 6, 5, 4, 3, 2, 1]);
let sub3 = iter.next().unwrap();
assert_eq!(sub3.kind, SubsectionKind::CROSSSCOPEIMPORTS);
assert_eq!(sub3.data, &[10, 11, 12, 13, 14]);
assert!(iter.rest().is_empty());
}
}