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::Endianness;
use crate::pcapng::errors::{PcapNgFormatError, PcapNgParseError};
#[derive(Debug)]
pub struct PcapNgParser {
pub(crate) state: PcapNgState,
}
impl PcapNgParser {
pub fn new(src: &[u8]) -> Result<(&[u8], Self), PcapNgParseError> {
let mut state = PcapNgState::default();
let (rem, raw_block) = RawBlock::from_slice::<BigEndian>(src)?;
let block = Block::try_from_raw_block::<BigEndian>(&state, raw_block)?;
if !matches!(&block, Block::SectionHeader(_)) {
return Err(PcapNgFormatError::MissingSectionHeader.into());
};
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>), PcapNgParseError> {
fn next_block_inner<'a, B: ByteOrder>(
parser: &mut PcapNgParser,
src: &'a [u8],
) -> Result<(&'a [u8], Block<'a>), PcapNgParseError> {
let (rem, raw_block) = RawBlock::from_slice::<B>(src)?;
let state = &parser.state;
let block = raw_block.try_into_block(state)?;
parser.state.update_from_block(&block);
Ok((rem, block))
}
match self.state.section.endianness {
Endianness::Big => next_block_inner::<BigEndian>(self, src),
Endianness::Little => next_block_inner::<LittleEndian>(self, src),
}
}
pub fn next_raw_block<'a>(&mut self, src: &'a [u8]) -> Result<(&'a [u8], RawBlock<'a>), PcapNgParseError> {
fn next_raw_block_inner<'a, B: ByteOrder>(
parser: &mut PcapNgParser,
src: &'a [u8],
) -> Result<(&'a [u8], RawBlock<'a>), PcapNgParseError> {
let (rem, raw_block) = RawBlock::from_slice::<B>(src)?;
if let Some(block) = parser.state.decode_block_if_needed(&raw_block)? {
parser.state.update_from_block(&block);
}
Ok((rem, raw_block))
}
match self.state.section.endianness {
Endianness::Big => next_raw_block_inner::<BigEndian>(self, src),
Endianness::Little => next_raw_block_inner::<LittleEndian>(self, src),
}
}
pub fn state(&self) -> &PcapNgState {
&self.state
}
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)
}
}