use std::io::Write;
use byteorder_slice::{BigEndian, LittleEndian};
use super::blocks::block_common::{Block, PcapNgBlock};
use super::blocks::interface_description::InterfaceDescriptionBlock;
use super::blocks::section_header::SectionHeaderBlock;
use super::{PcapNgState, RawBlock};
use crate::Endianness;
use crate::pcapng::errors::PcapNgWriteError;
pub struct PcapNgWriter<W: Write> {
state: PcapNgState,
writer: W,
}
impl<W: Write> PcapNgWriter<W> {
pub fn new(writer: W) -> Result<Self, PcapNgWriteError> {
Self::with_endianness(writer, Endianness::default())
}
pub fn with_endianness(writer: W, endianness: Endianness) -> Result<Self, PcapNgWriteError> {
let section = SectionHeaderBlock {
endianness,
..Default::default()
};
Self::with_section_header(writer, section)
}
pub fn with_section_header(mut writer: W, section: SectionHeaderBlock<'_>) -> Result<Self, PcapNgWriteError> {
let mut state = PcapNgState::default();
let endianness = section.endianness;
let block = section.into_owned().into_block();
let _ = match endianness {
Endianness::Big => block.write_to::<BigEndian, _>(&state, &mut writer),
Endianness::Little => block.write_to::<LittleEndian, _>(&state, &mut writer),
}?;
state.update_from_block(&block);
Ok(Self { state, writer })
}
pub fn write_block(&mut self, block: &Block) -> Result<usize, PcapNgWriteError> {
let endianess = self.state.block_endianness(Some(block));
let nb_written = match endianess {
Endianness::Big => block.write_to::<BigEndian, _>(&self.state, &mut self.writer)?,
Endianness::Little => block.write_to::<LittleEndian, _>(&self.state, &mut self.writer)?,
};
self.state.update_from_block(block);
Ok(nb_written)
}
pub fn write_pcapng_block<'a, B: PcapNgBlock<'a>>(&mut self, block: B) -> Result<usize, PcapNgWriteError> {
self.write_block(&block.into_block())
}
pub fn write_raw_block(&mut self, raw_block: &RawBlock) -> Result<usize, PcapNgWriteError> {
let opt_block = self.state.decode_block_if_needed(raw_block)?;
let endianess = self.state.block_endianness(opt_block.as_ref());
let nb_written = match endianess {
Endianness::Big => raw_block.write_to::<BigEndian, _>(&mut self.writer)?,
Endianness::Little => raw_block.write_to::<LittleEndian, _>(&mut self.writer)?,
};
if let Some(block) = opt_block {
self.state.update_from_block(&block);
}
Ok(nb_written)
}
pub fn into_inner(self) -> W {
self.writer
}
pub fn get_ref(&self) -> &W {
&self.writer
}
pub fn get_mut(&mut self) -> &mut W {
&mut self.writer
}
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
}
}