use crate::blocks::PcapBlockOwned;
use crate::error::PcapError;
use crate::pcap::{
parse_pcap_frame, parse_pcap_frame_be, parse_pcap_frame_modified, parse_pcap_header,
LegacyPcapBlock, PcapHeader,
};
use crate::traits::PcapReaderIterator;
use circular::Buffer;
use nom::{IResult, Needed, Offset};
use std::io::Read;
pub struct LegacyPcapReader<R>
where
R: Read,
{
header: PcapHeader,
reader: R,
buffer: Buffer,
consumed: usize,
reader_exhausted: bool,
parse: LegacyParseFn,
}
type LegacyParseFn = fn(&[u8]) -> IResult<&[u8], LegacyPcapBlock, PcapError<&[u8]>>;
impl<R> LegacyPcapReader<R>
where
R: Read,
{
pub fn new(
capacity: usize,
reader: R,
) -> Result<LegacyPcapReader<R>, PcapError<&'static [u8]>> {
let buffer = Buffer::with_capacity(capacity);
Self::from_buffer(buffer, reader)
}
pub fn from_buffer(
mut buffer: Buffer,
mut reader: R,
) -> Result<LegacyPcapReader<R>, PcapError<&'static [u8]>> {
let sz = reader.read(buffer.space()).or(Err(PcapError::ReadError))?;
buffer.fill(sz);
let (_rem, header) = match parse_pcap_header(buffer.data()) {
Ok((r, h)) => Ok((r, h)),
Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e.to_owned_vec()),
Err(nom::Err::Incomplete(Needed::Size(n))) => Err(PcapError::Incomplete(n.into())),
Err(nom::Err::Incomplete(Needed::Unknown)) => Err(PcapError::Incomplete(0)),
}?;
let parse = if !header.is_modified_format() {
if header.is_bigendian() {
parse_pcap_frame_be
} else {
parse_pcap_frame
}
} else {
parse_pcap_frame_modified
};
Ok(LegacyPcapReader {
header,
reader,
buffer,
consumed: 0,
reader_exhausted: false,
parse,
})
}
}
impl<R> PcapReaderIterator for LegacyPcapReader<R>
where
R: Read,
{
fn next(&mut self) -> Result<(usize, PcapBlockOwned<'_>), PcapError<&'_ [u8]>> {
if self.consumed == 0 {
return Ok((
self.header.size(),
PcapBlockOwned::from(self.header.clone()),
));
}
if self.buffer.available_data() == 0
&& (self.buffer.position() == 0 && self.reader_exhausted)
{
return Err(PcapError::Eof);
}
let data = self.buffer.data();
match (self.parse)(data) {
Ok((rem, b)) => {
let offset = data.offset(rem);
Ok((offset, PcapBlockOwned::from(b)))
}
Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e),
Err(nom::Err::Incomplete(n)) => {
if self.reader_exhausted {
Err(PcapError::UnexpectedEof)
} else {
match n {
Needed::Size(n) => {
if self.buffer.available_data() + usize::from(n)
>= self.buffer.capacity()
{
Err(PcapError::BufferTooSmall)
} else {
Err(PcapError::Incomplete(n.into()))
}
}
Needed::Unknown => Err(PcapError::Incomplete(0)),
}
}
}
}
}
fn consume(&mut self, offset: usize) {
self.consumed += offset;
self.buffer.consume(offset);
}
fn consume_noshift(&mut self, offset: usize) {
self.consumed += offset;
self.buffer.consume_noshift(offset);
}
fn consumed(&self) -> usize {
self.consumed
}
fn refill(&mut self) -> Result<(), PcapError<&[u8]>> {
self.buffer.shift();
let space = self.buffer.space();
if space.is_empty() {
return Ok(());
}
let sz = self.reader.read(space).or(Err(PcapError::ReadError))?;
self.reader_exhausted = sz == 0;
self.buffer.fill(sz);
Ok(())
}
fn position(&self) -> usize {
self.buffer.position()
}
fn grow(&mut self, new_size: usize) -> bool {
self.buffer.grow(new_size)
}
fn data(&self) -> &[u8] {
self.buffer.data()
}
fn reader_exhausted(&self) -> bool {
self.reader_exhausted
}
}