use crate::errors::PcapError;
use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt};
use crate::Endianness;
use crate::pcapng::blocks::common::opts_from_slice;
use crate::pcapng::{CustomBinaryOption, CustomUtf8Option, UnknownOption};
use std::borrow::Cow;
use derive_into_owned::IntoOwned;
#[derive(Clone, Debug, IntoOwned)]
pub struct SectionHeaderBlock<'a> {
pub magic: u32,
pub major_version: u16,
pub minor_version: u16,
pub section_length: i64,
pub options: Vec<SectionHeaderOption<'a>>
}
impl<'a> SectionHeaderBlock<'a> {
pub fn from_slice(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {
if slice.len() < 16 {
return Err(PcapError::InvalidField("SectionHeaderBlock: block length < 16"));
}
let magic = slice.read_u32::<BigEndian>()?;
let (rem, major_version, minor_version, section_length, options) = match magic {
0x1A2B3C4D => parse_inner::<BigEndian>(slice)?,
0x4D3C2B1A => parse_inner::<LittleEndian>(slice)?,
_ => unreachable!()
};
let block = SectionHeaderBlock {
magic,
major_version,
minor_version,
section_length,
options
};
return Ok((rem, block));
#[allow(clippy::type_complexity)]
fn parse_inner<B: ByteOrder>(mut slice: &[u8]) -> Result<(&[u8], u16, u16, i64, Vec<SectionHeaderOption>), PcapError> {
let maj_ver = slice.read_u16::<B>()?;
let min_ver = slice.read_u16::<B>()?;
let sec_len = slice.read_i64::<B>()?;
let (rem, opts) = SectionHeaderOption::from_slice::<B>(slice)?;
Ok((rem, maj_ver, min_ver, sec_len, opts))
}
}
pub fn endianness(&self) -> Endianness {
match self.magic {
0x1A2B3C4D => Endianness::Big,
0x4D3C2B1A => Endianness::Little,
_ => unreachable!()
}
}
}
#[derive(Clone, Debug, IntoOwned)]
pub enum SectionHeaderOption<'a> {
Comment(Cow<'a, str>),
Hardware(Cow<'a, str>),
OS(Cow<'a, str>),
UserApplication(Cow<'a, str>),
CustomBinary(CustomBinaryOption<'a>),
CustomUtf8(CustomUtf8Option<'a>),
Unknown(UnknownOption<'a>)
}
impl<'a> SectionHeaderOption<'a> {
fn from_slice<B:ByteOrder>(slice: &'a [u8]) -> Result<(&'a [u8], Vec<Self>), PcapError> {
opts_from_slice::<B, _, _>(slice, |slice, code, length| {
let opt = match code {
1 => SectionHeaderOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
2 => SectionHeaderOption::Hardware(Cow::Borrowed(std::str::from_utf8(slice)?)),
3 => SectionHeaderOption::OS(Cow::Borrowed(std::str::from_utf8(slice)?)),
4 => SectionHeaderOption::UserApplication(Cow::Borrowed(std::str::from_utf8(slice)?)),
2988 | 19372 => SectionHeaderOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice)?),
2989 | 19373 => SectionHeaderOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice)?),
_ => SectionHeaderOption::Unknown(UnknownOption::new(code, length, slice))
};
Ok(opt)
})
}
}