use std::io::{Error, ErrorKind, Read};
use crate::PcapError;
#[derive(Debug)]
pub(crate) struct ReadBuffer<R: Read> {
reader: R,
buffer: Vec<u8>,
pos: usize,
len: usize,
}
impl<R: Read> ReadBuffer<R> {
pub fn new(reader: R) -> Self {
Self::with_capacity(reader, 8_000_000)
}
pub fn with_capacity(reader: R, capacity: usize) -> Self {
Self { reader, buffer: vec![0_u8; capacity], pos: 0, len: 0 }
}
pub fn parse_with<'a, 'b: 'a, 'c: 'a, F, O>(&'c mut self, mut parser: F) -> Result<O, PcapError>
where
F: FnMut(&'a [u8]) -> Result<(&'a [u8], O), PcapError>,
F: 'b,
O: 'a,
{
loop {
let buf = &self.buffer[self.pos..self.len];
let buf: &'a [u8] = unsafe { std::mem::transmute(buf) };
match parser(buf) {
Ok((rem, value)) => {
self.advance_with_slice(rem);
return Ok(value);
},
Err(PcapError::IncompleteBuffer) => {
if buf.len() == self.buffer.len() {
return Err(PcapError::IoError(Error::from(ErrorKind::UnexpectedEof)));
}
let nb_read = self.fill_buf().map_err(PcapError::IoError)?;
if nb_read == 0 {
return Err(PcapError::IoError(Error::from(ErrorKind::UnexpectedEof)));
}
},
Err(e) => return Err(e),
}
}
}
fn fill_buf(&mut self) -> Result<usize, std::io::Error> {
let rem_len = unsafe {
let buf_ptr_mut = self.buffer.as_mut_ptr();
let rem_ptr_mut = buf_ptr_mut.add(self.pos);
std::ptr::copy(rem_ptr_mut, buf_ptr_mut, self.len - self.pos);
self.len - self.pos
};
let nb_read = self.reader.read(&mut self.buffer[rem_len..])?;
self.len = rem_len + nb_read;
self.pos = 0;
Ok(nb_read)
}
fn advance(&mut self, nb_bytes: usize) {
assert!(self.pos + nb_bytes <= self.len);
self.pos += nb_bytes;
}
fn advance_with_slice(&mut self, rem: &[u8]) {
let diff_len = (rem.as_ptr() as usize)
.checked_sub(self.buffer().as_ptr() as usize)
.expect("Rem is not a sub slice of self.buffer");
self.advance(diff_len)
}
pub fn buffer(&self) -> &[u8] {
&self.buffer[self.pos..self.len]
}
pub fn has_data_left(&mut self) -> Result<bool, std::io::Error> {
if self.buffer().is_empty() {
let nb_read = self.fill_buf()?;
if nb_read == 0 {
return Ok(false);
}
}
Ok(true)
}
pub fn into_inner(self) -> R {
self.reader
}
pub fn get_ref(&self) -> &R {
&self.reader
}
}
#[cfg(test)]
mod test {
}