use byteorder_slice::{BigEndian, ByteOrder, LittleEndian};
use super::PcapNgState;
use super::blocks::block_common::{Block, RawBlock};
use super::blocks::enhanced_packet::EnhancedPacketBlock;
use super::blocks::interface_description::InterfaceDescriptionBlock;
use super::blocks::section_header::SectionHeaderBlock;
use crate::errors::PcapError;
use crate::Endianness;
pub struct PcapNgParser {
pub(crate) state: PcapNgState,
}
impl PcapNgParser {
pub fn new(src: &[u8]) -> Result<(&[u8], Self), PcapError> {
let mut state = PcapNgState::default();
let (rem, block) = Block::from_slice::<BigEndian>(&state, src)?;
if !matches!(&block, Block::SectionHeader(_)) {
return Err(PcapError::InvalidField("PcapNg: SectionHeader invalid or missing"));
};
state.update_from_block(&block)?;
let parser = PcapNgParser { state };
Ok((rem, parser))
}
pub fn next_block<'a>(&mut self, src: &'a [u8]) -> Result<(&'a [u8], Block<'a>), PcapError> {
match self.state.section.endianness {
Endianness::Big => {
let (rem, raw_block) = self.next_raw_block_inner::<BigEndian>(src)?;
let block = raw_block.try_into_block::<BigEndian>(&self.state)?;
Ok((rem, block))
},
Endianness::Little => {
let (rem, raw_block) = self.next_raw_block_inner::<LittleEndian>(src)?;
let block = raw_block.try_into_block::<LittleEndian>(&self.state)?;
Ok((rem, block))
},
}
}
pub fn next_raw_block<'a>(&mut self, src: &'a [u8]) -> Result<(&'a [u8], RawBlock<'a>), PcapError> {
match self.state.section.endianness {
Endianness::Big => self.next_raw_block_inner::<BigEndian>(src),
Endianness::Little => self.next_raw_block_inner::<LittleEndian>(src),
}
}
fn next_raw_block_inner<'a, B: ByteOrder>(&mut self, src: &'a [u8]) -> Result<(&'a [u8], RawBlock<'a>), PcapError> {
let (rem, raw_block) = RawBlock::from_slice::<B>(src)?;
self.state.update_from_raw_block::<B>(&raw_block)?;
Ok((rem, raw_block))
}
pub fn section(&self) -> &SectionHeaderBlock<'static> {
&self.state.section
}
pub fn interfaces(&self) -> &[InterfaceDescriptionBlock<'static>] {
&self.state.interfaces[..]
}
pub fn packet_interface(&self, packet: &EnhancedPacketBlock) -> Option<&InterfaceDescriptionBlock<'_>> {
self.state.interfaces.get(packet.interface_id as usize)
}
}