use crate::blocks::PcapBlock;
use crate::endianness::*;
use crate::error::PcapError;
use crate::linktype::Linktype;
use crate::traits::*;
use crate::utils::*;
use nom::bytes::streaming::{tag, take};
use nom::combinator::{complete, map, map_parser};
use nom::error::*;
use nom::multi::{many0, many1, many_till};
use nom::number::streaming::{be_i64, be_u16, be_u32, le_i64, le_u16, le_u32};
use nom::{Err, IResult};
use rusticata_macros::{align32, newtype_enum};
use std::borrow::Cow;
use std::convert::TryFrom;
trait PcapNGBlockParser<'a, En: PcapEndianness, O: 'a> {
    const HDR_SZ: usize;
    const MAGIC: u32;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], O, E>;
}
pub const SHB_MAGIC: u32 = 0x0A0D_0D0A;
pub const IDB_MAGIC: u32 = 0x0000_0001;
pub const SPB_MAGIC: u32 = 0x0000_0003;
pub const NRB_MAGIC: u32 = 0x0000_0004;
pub const ISB_MAGIC: u32 = 0x0000_0005;
pub const EPB_MAGIC: u32 = 0x0000_0006;
pub const SJE_MAGIC: u32 = 0x0000_0009;
pub const DSB_MAGIC: u32 = 0x0000_000A;
pub const CB_MAGIC: u32 = 0x0000_0BAD;
pub const DCB_MAGIC: u32 = 0x4000_0BAD;
pub const BOM_MAGIC: u32 = 0x1A2B_3C4D;
pub const PIB_MAGIC: u32 = 0x8000_0001;
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct OptionCode(pub u16);
newtype_enum! {
impl debug OptionCode {
    EndOfOpt = 0,
    Comment = 1,
    ShbHardware = 2,
    ShbOs = 3,
    ShbUserAppl = 4,
    IfTsresol = 9,
    IfTsoffset = 14,
    Custom2988 = 2988,
    Custom2989 = 2989,
    Custom19372 = 19372,
    Custom19373 = 19373,
}
}
#[derive(Debug)]
pub enum Block<'a> {
    SectionHeader(SectionHeaderBlock<'a>),
    InterfaceDescription(InterfaceDescriptionBlock<'a>),
    EnhancedPacket(EnhancedPacketBlock<'a>),
    SimplePacket(SimplePacketBlock<'a>),
    NameResolution(NameResolutionBlock<'a>),
    InterfaceStatistics(InterfaceStatisticsBlock<'a>),
    SystemdJournalExport(SystemdJournalExportBlock<'a>),
    DecryptionSecrets(DecryptionSecretsBlock<'a>),
    ProcessInformation(ProcessInformationBlock<'a>),
    Custom(CustomBlock<'a>),
    Unknown(UnknownBlock<'a>),
}
impl<'a> Block<'a> {
    pub fn is_data_block(&self) -> bool {
        matches!(self, &Block::EnhancedPacket(_) | &Block::SimplePacket(_))
    }
    pub fn magic(&self) -> u32 {
        match self {
            Block::SectionHeader(_) => SHB_MAGIC,
            Block::InterfaceDescription(_) => IDB_MAGIC,
            Block::EnhancedPacket(_) => EPB_MAGIC,
            Block::SimplePacket(_) => SPB_MAGIC,
            Block::NameResolution(_) => NRB_MAGIC,
            Block::InterfaceStatistics(_) => ISB_MAGIC,
            Block::SystemdJournalExport(_) => SJE_MAGIC,
            Block::DecryptionSecrets(_) => DSB_MAGIC,
            Block::ProcessInformation(_) => PIB_MAGIC,
            Block::Custom(cb) => cb.block_type,
            Block::Unknown(ub) => ub.block_type,
        }
    }
}
pub struct Section<'a> {
    pub blocks: Vec<Block<'a>>,
    pub big_endian: bool,
}
impl<'a> Section<'a> {
    pub fn header(&self) -> Option<&SectionHeaderBlock> {
        if let Some(Block::SectionHeader(ref b)) = self.blocks.first() {
            Some(b)
        } else {
            None
        }
    }
    pub fn iter(&'a self) -> SectionBlockIterator<'a> {
        SectionBlockIterator {
            section: self,
            index_block: 0,
        }
    }
    pub fn iter_interfaces(&'a self) -> InterfaceBlockIterator<'a> {
        InterfaceBlockIterator {
            section: self,
            index_block: 0,
        }
    }
}
pub struct SectionBlockIterator<'a> {
    section: &'a Section<'a>,
    index_block: usize,
}
impl<'a> Iterator for SectionBlockIterator<'a> {
    type Item = PcapBlock<'a>;
    fn next(&mut self) -> Option<PcapBlock<'a>> {
        let block = self.section.blocks.get(self.index_block);
        self.index_block += 1;
        block.map(PcapBlock::from)
    }
}
pub struct InterfaceBlockIterator<'a> {
    section: &'a Section<'a>,
    index_block: usize,
}
impl<'a> Iterator for InterfaceBlockIterator<'a> {
    type Item = &'a InterfaceDescriptionBlock<'a>;
    fn next(&mut self) -> Option<&'a InterfaceDescriptionBlock<'a>> {
        if self.index_block >= self.section.blocks.len() {
            return None;
        }
        for block in &self.section.blocks[self.index_block..] {
            self.index_block += 1;
            if let Block::InterfaceDescription(ref idb) = block {
                return Some(idb);
            }
        }
        None
    }
}
pub fn build_ts_resolution(ts_resol: u8) -> Option<u64> {
    let ts_mode = ts_resol & 0x80;
    let unit = if ts_mode == 0 {
        if ts_resol > 19 {
            return None;
        }
        10u64.pow(ts_resol as u32)
    } else {
        if ts_resol > 63 {
            return None;
        }
        1 << ((ts_resol & 0x7f) as u64)
    };
    Some(unit)
}
pub fn build_ts(ts_high: u32, ts_low: u32, ts_offset: u64, resolution: u64) -> (u32, u32) {
    let if_tsoffset = ts_offset;
    let ts: u64 = ((ts_high as u64) << 32) | (ts_low as u64);
    let ts_sec = (if_tsoffset + (ts / resolution)) as u32;
    let ts_fractional = (ts % resolution) as u32;
    (ts_sec, ts_fractional)
}
pub fn build_ts_f64(ts_high: u32, ts_low: u32, ts_offset: u64, resolution: u64) -> f64 {
    let ts: u64 = ((ts_high as u64) << 32) | (ts_low as u64);
    let ts_sec = (ts_offset + (ts / resolution)) as u32;
    let ts_fractional = (ts % resolution) as u32;
    ts_sec as f64 + ((ts_fractional as f64) / (resolution as f64))
}
#[derive(Debug)]
pub struct SectionHeaderBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub bom: u32,
    pub major_version: u16,
    pub minor_version: u16,
    pub section_len: i64,
    pub options: Vec<PcapNGOption<'a>>,
    pub block_len2: u32,
}
impl<'a> SectionHeaderBlock<'a> {
    pub fn big_endian(&self) -> bool {
        self.bom != BOM_MAGIC
    }
}
impl<'a> PcapNGBlockParser<'a, PcapBE, SectionHeaderBlock<'a>> for SectionHeaderBlock<'a> {
    const HDR_SZ: usize = 28;
    const MAGIC: u32 = SHB_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], SectionHeaderBlock<'a>, E> {
        let (i, bom) = le_u32(i)?;
        let (i, major_version) = be_u16(i)?;
        let (i, minor_version) = be_u16(i)?;
        let (i, section_len) = be_i64(i)?;
        let (i, options) = opt_parse_options::<PcapBE, E>(i, block_len1 as usize, 28)?;
        let block = SectionHeaderBlock {
            block_type,
            block_len1,
            bom,
            major_version,
            minor_version,
            section_len,
            options,
            block_len2,
        };
        Ok((i, block))
    }
}
impl<'a> PcapNGBlockParser<'a, PcapLE, SectionHeaderBlock<'a>> for SectionHeaderBlock<'a> {
    const HDR_SZ: usize = 28;
    const MAGIC: u32 = SHB_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], SectionHeaderBlock<'a>, E> {
        let (i, bom) = le_u32(i)?;
        let (i, major_version) = le_u16(i)?;
        let (i, minor_version) = le_u16(i)?;
        let (i, section_len) = le_i64(i)?;
        let (i, options) = opt_parse_options::<PcapLE, E>(i, block_len1 as usize, 28)?;
        let block = SectionHeaderBlock {
            block_type,
            block_len1,
            bom,
            major_version,
            minor_version,
            section_len,
            options,
            block_len2,
        };
        Ok((i, block))
    }
}
#[derive(Debug)]
pub struct InterfaceDescriptionBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub linktype: Linktype,
    pub reserved: u16,
    pub snaplen: u32,
    pub options: Vec<PcapNGOption<'a>>,
    pub block_len2: u32,
    pub if_tsresol: u8,
    pub if_tsoffset: i64,
}
impl<'a> InterfaceDescriptionBlock<'a> {
    #[inline]
    pub fn ts_resolution(&self) -> Option<u64> {
        build_ts_resolution(self.if_tsresol)
    }
    #[inline]
    pub fn ts_offset(&self) -> i64 {
        self.if_tsoffset
    }
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, InterfaceDescriptionBlock<'a>>
    for InterfaceDescriptionBlock<'a>
{
    const HDR_SZ: usize = 20;
    const MAGIC: u32 = IDB_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], InterfaceDescriptionBlock<'a>, E> {
        let (i, linktype) = En::parse_u16(i)?;
        let (i, reserved) = En::parse_u16(i)?;
        let (i, snaplen) = En::parse_u32(i)?;
        let (i, options) = opt_parse_options::<En, E>(i, block_len1 as usize, 20)?;
        if block_len2 != block_len1 {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        let (if_tsresol, if_tsoffset) = if_extract_tsoffset_and_tsresol(&options);
        let block = InterfaceDescriptionBlock {
            block_type,
            block_len1,
            linktype: Linktype(linktype as i32),
            reserved,
            snaplen,
            options,
            block_len2,
            if_tsresol,
            if_tsoffset,
        };
        Ok((i, block))
    }
}
#[derive(Debug)]
pub struct EnhancedPacketBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub if_id: u32,
    pub ts_high: u32,
    pub ts_low: u32,
    pub caplen: u32,
    pub origlen: u32,
    pub data: &'a [u8],
    pub options: Vec<PcapNGOption<'a>>,
    pub block_len2: u32,
}
impl<'a> EnhancedPacketBlock<'a> {
    #[inline]
    pub fn decode_ts(&self, ts_offset: u64, resolution: u64) -> (u32, u32) {
        build_ts(self.ts_high, self.ts_low, ts_offset, resolution)
    }
    #[inline]
    pub fn decode_ts_f64(&self, ts_offset: u64, resolution: u64) -> f64 {
        build_ts_f64(self.ts_high, self.ts_low, ts_offset, resolution)
    }
}
impl<'a> PcapNGPacketBlock for EnhancedPacketBlock<'a> {
    fn big_endian(&self) -> bool {
        self.block_type != EPB_MAGIC
    }
    fn truncated(&self) -> bool {
        self.origlen != self.caplen
    }
    fn orig_len(&self) -> u32 {
        self.origlen
    }
    fn raw_packet_data(&self) -> &[u8] {
        self.data
    }
    fn packet_data(&self) -> &[u8] {
        let caplen = self.caplen as usize;
        if caplen < self.data.len() {
            &self.data[..caplen]
        } else {
            self.data
        }
    }
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, EnhancedPacketBlock<'a>>
    for EnhancedPacketBlock<'a>
{
    const HDR_SZ: usize = 32;
    const MAGIC: u32 = EPB_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], EnhancedPacketBlock<'a>, E> {
        let (b_hdr, packet_data) = i.split_at(20);
        let if_id = En::u32_from_bytes(*array_ref4(b_hdr, 0));
        let ts_high = En::u32_from_bytes(*array_ref4(b_hdr, 4));
        let ts_low = En::u32_from_bytes(*array_ref4(b_hdr, 8));
        let caplen = En::u32_from_bytes(*array_ref4(b_hdr, 12));
        let origlen = En::u32_from_bytes(*array_ref4(b_hdr, 16));
        if caplen >= ::std::u32::MAX - 4 {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        let padded_length = align32!(caplen);
        let (i, data) = take(padded_length)(packet_data)?;
        let current_offset = (32 + padded_length) as usize;
        let (i, options) = opt_parse_options::<En, E>(i, block_len1 as usize, current_offset)?;
        if block_len2 != block_len1 {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        let block = EnhancedPacketBlock {
            block_type,
            block_len1,
            if_id,
            ts_high,
            ts_low,
            caplen,
            origlen,
            data,
            options,
            block_len2,
        };
        Ok((i, block))
    }
}
#[derive(Debug)]
pub struct SimplePacketBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub origlen: u32,
    pub data: &'a [u8],
    pub block_len2: u32,
}
impl<'a> PcapNGPacketBlock for SimplePacketBlock<'a> {
    fn big_endian(&self) -> bool {
        self.block_type != SPB_MAGIC
    }
    fn truncated(&self) -> bool {
        self.origlen as usize <= self.data.len()
    }
    fn orig_len(&self) -> u32 {
        self.origlen
    }
    fn raw_packet_data(&self) -> &[u8] {
        self.data
    }
    fn packet_data(&self) -> &[u8] {
        let caplen = self.origlen as usize;
        if caplen < self.data.len() {
            &self.data[..caplen]
        } else {
            self.data
        }
    }
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, SimplePacketBlock<'a>>
    for SimplePacketBlock<'a>
{
    const HDR_SZ: usize = 16;
    const MAGIC: u32 = SPB_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], SimplePacketBlock<'a>, E> {
        let (i, origlen) = En::parse_u32(i)?;
        let (i, data) = take((block_len1 as usize) - 16)(i)?;
        let block = SimplePacketBlock {
            block_type,
            block_len1,
            origlen,
            data,
            block_len2,
        };
        Ok((i, block))
    }
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct NameRecordType(pub u16);
newtype_enum! {
    impl debug NameRecordType {
        End = 0,
        Ipv4 = 1,
        Ipv6 = 2
    }
}
#[derive(Debug)]
pub struct NameRecord<'a> {
    pub record_type: NameRecordType,
    pub record_value: &'a [u8],
}
impl<'a> NameRecord<'a> {
    pub const END: NameRecord<'static> = NameRecord {
        record_type: NameRecordType::End,
        record_value: &[],
    };
}
#[derive(Debug)]
pub struct NameResolutionBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub nr: Vec<NameRecord<'a>>,
    pub options: Vec<PcapNGOption<'a>>,
    pub block_len2: u32,
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, NameResolutionBlock<'a>>
    for NameResolutionBlock<'a>
{
    const HDR_SZ: usize = 12;
    const MAGIC: u32 = NRB_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], NameResolutionBlock<'a>, E> {
        let start_i = i;
        let (i, nr) = parse_name_record_list::<En, E>(i)?;
        let current_offset = 12 + (i.as_ptr() as usize) - (start_i.as_ptr() as usize);
        let (i, options) = opt_parse_options::<En, E>(i, block_len1 as usize, current_offset)?;
        if block_len2 != block_len1 {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        let block = NameResolutionBlock {
            block_type,
            block_len1,
            nr,
            options,
            block_len2,
        };
        Ok((i, block))
    }
}
#[derive(Debug)]
pub struct InterfaceStatisticsBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub if_id: u32,
    pub ts_high: u32,
    pub ts_low: u32,
    pub options: Vec<PcapNGOption<'a>>,
    pub block_len2: u32,
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, InterfaceStatisticsBlock<'a>>
    for InterfaceStatisticsBlock<'a>
{
    const HDR_SZ: usize = 24;
    const MAGIC: u32 = ISB_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], InterfaceStatisticsBlock<'a>, E> {
        let (i, if_id) = En::parse_u32(i)?;
        let (i, ts_high) = En::parse_u32(i)?;
        let (i, ts_low) = En::parse_u32(i)?;
        let (i, options) = opt_parse_options::<En, E>(i, block_len1 as usize, 24)?;
        if block_len2 != block_len1 {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        let block = InterfaceStatisticsBlock {
            block_type,
            block_len1,
            if_id,
            ts_high,
            ts_low,
            options,
            block_len2,
        };
        Ok((i, block))
    }
}
#[derive(Debug)]
pub struct SystemdJournalExportBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub data: &'a [u8],
    pub block_len2: u32,
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, SystemdJournalExportBlock<'a>>
    for SystemdJournalExportBlock<'a>
{
    const HDR_SZ: usize = 12;
    const MAGIC: u32 = SJE_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], SystemdJournalExportBlock<'a>, E> {
        let block = SystemdJournalExportBlock {
            block_type,
            block_len1,
            data: i,
            block_len2,
        };
        Ok((i, block))
    }
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct SecretsType(pub u32);
newtype_enum! {
    impl debug SecretsType {
        TlsKeyLog = 0x544c_534b, WireguardKeyLog = 0x5747_4b4c,
    }
}
#[derive(Debug)]
pub struct DecryptionSecretsBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub secrets_type: SecretsType,
    pub secrets_len: u32,
    pub data: &'a [u8],
    pub options: Vec<PcapNGOption<'a>>,
    pub block_len2: u32,
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, DecryptionSecretsBlock<'a>>
    for DecryptionSecretsBlock<'a>
{
    const HDR_SZ: usize = 20;
    const MAGIC: u32 = DSB_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], DecryptionSecretsBlock<'a>, E> {
        let (i, secrets_type) = En::parse_u32(i)?;
        let (i, secrets_len) = En::parse_u32(i)?;
        if secrets_len >= ::std::u32::MAX - 4 {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        let padded_length = align32!(secrets_len);
        let (i, data) = take(padded_length)(i)?;
        let current_offset = (20 + padded_length) as usize;
        let (i, options) = opt_parse_options::<En, E>(i, block_len1 as usize, current_offset)?;
        if block_len2 != block_len1 {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        let block = DecryptionSecretsBlock {
            block_type,
            block_len1,
            secrets_type: SecretsType(secrets_type),
            secrets_len,
            data,
            options,
            block_len2,
        };
        Ok((i, block))
    }
}
#[derive(Debug)]
pub struct CustomBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub pen: u32,
    pub data: &'a [u8],
    pub block_len2: u32,
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, CustomBlock<'a>> for CustomBlock<'a> {
    const HDR_SZ: usize = 16;
    const MAGIC: u32 = CB_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], CustomBlock<'a>, E> {
        let (i, pen) = En::parse_u32(i)?;
        let data = i;
        if block_len2 != block_len1 {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        let block = CustomBlock {
            block_type,
            block_len1,
            pen,
            data,
            block_len2,
        };
        Ok((i, block))
    }
}
struct DCBParser;
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, CustomBlock<'a>> for DCBParser {
    const HDR_SZ: usize = 16;
    const MAGIC: u32 = DCB_MAGIC;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], CustomBlock<'a>, E> {
        <CustomBlock as PcapNGBlockParser<En, CustomBlock<'a>>>::inner_parse::<E>(
            block_type, block_len1, i, block_len2,
        )
    }
}
impl<'a> CustomBlock<'a> {
    pub fn do_not_copy(&self) -> bool {
        self.block_type == DCB_MAGIC || self.block_type == DCB_MAGIC.swap_bytes()
    }
}
#[derive(Debug)]
pub struct ProcessInformationBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub process_id: u32,
    pub options: Vec<PcapNGOption<'a>>,
    pub block_len2: u32,
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, ProcessInformationBlock<'a>>
    for ProcessInformationBlock<'a>
{
    const MAGIC: u32 = PIB_MAGIC;
    const HDR_SZ: usize = 4;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], ProcessInformationBlock<'a>, E> {
        let (i, process_id) = En::parse_u32(i)?;
        let (i, options) = opt_parse_options::<En, E>(i, (block_len1 - 4) as usize, 12)?;
        if block_len2 != block_len1 {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        let block = ProcessInformationBlock {
            block_type,
            block_len1,
            process_id,
            options,
            block_len2,
        };
        Ok((i, block))
    }
}
#[derive(Debug)]
pub struct UnknownBlock<'a> {
    pub block_type: u32,
    pub block_len1: u32,
    pub data: &'a [u8],
    pub block_len2: u32,
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, UnknownBlock<'a>> for UnknownBlock<'a> {
    const HDR_SZ: usize = 12;
    const MAGIC: u32 = 0;
    fn inner_parse<E: ParseError<&'a [u8]>>(
        block_type: u32,
        block_len1: u32,
        i: &'a [u8],
        block_len2: u32,
    ) -> IResult<&'a [u8], UnknownBlock<'a>, E> {
        let block = UnknownBlock {
            block_type,
            block_len1,
            data: i,
            block_len2,
        };
        Ok((i, block))
    }
}
#[derive(Debug)]
pub struct PcapNGOption<'a> {
    pub code: OptionCode,
    pub len: u16,
    pub value: Cow<'a, [u8]>,
}
impl<'a> PcapNGOption<'a> {
    #[inline]
    pub fn value(&self) -> &[u8] {
        self.value.as_ref()
    }
    pub fn as_bytes(&self) -> Option<&[u8]> {
        let len = usize::from(self.len);
        if len <= self.value.len() {
            Some(&self.value[..len])
        } else {
            None
        }
    }
    pub fn as_i32_le(&self) -> Option<i32> {
        if self.len == 8 && self.value.len() == 8 {
            <[u8; 4]>::try_from(self.value())
                .ok()
                .map(i32::from_le_bytes)
        } else {
            None
        }
    }
    pub fn as_u32_le(&self) -> Option<u32> {
        if self.len == 8 && self.value.len() == 8 {
            <[u8; 4]>::try_from(self.value())
                .ok()
                .map(u32::from_le_bytes)
        } else {
            None
        }
    }
    pub fn as_i64_le(&self) -> Option<i64> {
        if self.len == 8 && self.value.len() == 8 {
            <[u8; 8]>::try_from(self.value())
                .ok()
                .map(i64::from_le_bytes)
        } else {
            None
        }
    }
    pub fn as_u64_le(&self) -> Option<u64> {
        if self.len == 8 && self.value.len() == 8 {
            <[u8; 8]>::try_from(self.value())
                .ok()
                .map(u64::from_le_bytes)
        } else {
            None
        }
    }
}
#[derive(Debug)]
pub struct PcapNGHeader {
    pub magic_number: u32,
    pub version_major: u16,
    pub version_minor: u16,
    pub thiszone: i32,
    pub sigfigs: u32,
    pub snaplen: u32,
    pub network: u32,
}
fn ng_block_parser<'a, P, En, O, E>() -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E>
where
    P: PcapNGBlockParser<'a, En, O>,
    En: PcapEndianness,
    O: 'a,
    E: ParseError<&'a [u8]>,
{
    move |i: &[u8]| {
        if i.len() < P::HDR_SZ {
            return Err(nom::Err::Incomplete(nom::Needed::new(P::HDR_SZ - i.len())));
        }
        let (i, block_type) = le_u32(i)?;
        let (i, block_len1) = En::parse_u32(i)?;
        if block_len1 < P::HDR_SZ as u32 {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        if P::MAGIC != 0 && En::native_u32(block_type) != P::MAGIC {
            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
        }
        let (i, block_content) = take(block_len1 - 12)(i)?;
        let (i, block_len2) = En::parse_u32(i)?;
        let (_, b) = P::inner_parse(block_type, block_len1, block_content, block_len2)?;
        Ok((i, b))
    }
}
#[inline]
pub fn parse_option_le<'i, E: ParseError<&'i [u8]>>(
    i: &'i [u8],
) -> IResult<&'i [u8], PcapNGOption, E> {
    parse_option::<PcapLE, E>(i)
}
#[inline]
pub fn parse_option_be<'i, E: ParseError<&'i [u8]>>(
    i: &'i [u8],
) -> IResult<&'i [u8], PcapNGOption, E> {
    parse_option::<PcapBE, E>(i)
}
pub(crate) fn parse_option<'i, En: PcapEndianness, E: ParseError<&'i [u8]>>(
    i: &'i [u8],
) -> IResult<&'i [u8], PcapNGOption, E> {
    let (i, code) = En::parse_u16(i)?;
    let (i, len) = En::parse_u16(i)?;
    let (i, value) = take(align32!(len as u32))(i)?;
    let option = PcapNGOption {
        code: OptionCode(code),
        len,
        value: Cow::Borrowed(value),
    };
    Ok((i, option))
}
pub(crate) fn opt_parse_options<'i, En: PcapEndianness, E: ParseError<&'i [u8]>>(
    i: &'i [u8],
    len: usize,
    opt_offset: usize,
) -> IResult<&'i [u8], Vec<PcapNGOption>, E> {
    if len > opt_offset {
        map_parser(
            take(len - opt_offset),
            many0(complete(parse_option::<En, E>)),
        )(i)
    } else {
        Ok((i, Vec::new()))
    }
}
pub fn parse_sectionheaderblock_le(
    i: &[u8],
) -> IResult<&[u8], SectionHeaderBlock, PcapError<&[u8]>> {
    ng_block_parser::<SectionHeaderBlock, PcapLE, _, _>()(i)
}
pub fn parse_sectionheaderblock_be(
    i: &[u8],
) -> IResult<&[u8], SectionHeaderBlock, PcapError<&[u8]>> {
    ng_block_parser::<SectionHeaderBlock, PcapBE, _, _>()(i)
}
pub fn parse_sectionheaderblock(i: &[u8]) -> IResult<&[u8], SectionHeaderBlock, PcapError<&[u8]>> {
    if i.len() < 12 {
        return Err(nom::Err::Incomplete(nom::Needed::new(12 - i.len())));
    }
    let bom = u32::from_le_bytes(*array_ref4(i, 8));
    if bom == BOM_MAGIC {
        parse_sectionheaderblock_le(i)
    } else if bom == u32::from_be(BOM_MAGIC) {
        parse_sectionheaderblock_be(i)
    } else {
        Err(Err::Error(PcapError::HeaderNotRecognized))
    }
}
fn if_extract_tsoffset_and_tsresol(options: &[PcapNGOption]) -> (u8, i64) {
    let mut if_tsresol: u8 = 6;
    let mut if_tsoffset: i64 = 0;
    for opt in options {
        match opt.code {
            OptionCode::IfTsresol => {
                if !opt.value.is_empty() {
                    if_tsresol = opt.value[0];
                }
            }
            OptionCode::IfTsoffset => {
                if opt.value.len() >= 8 {
                    let int_bytes =
                        <[u8; 8]>::try_from(&opt.value[..8]).expect("Convert bytes to i64");
                    if_tsoffset = i64::from_le_bytes(int_bytes);
                }
            }
            _ => (),
        }
    }
    (if_tsresol, if_tsoffset)
}
pub fn parse_interfacedescriptionblock_le(
    i: &[u8],
) -> IResult<&[u8], InterfaceDescriptionBlock, PcapError<&[u8]>> {
    ng_block_parser::<InterfaceDescriptionBlock, PcapLE, _, _>()(i)
}
pub fn parse_interfacedescriptionblock_be(
    i: &[u8],
) -> IResult<&[u8], InterfaceDescriptionBlock, PcapError<&[u8]>> {
    ng_block_parser::<InterfaceDescriptionBlock, PcapBE, _, _>()(i)
}
pub fn parse_simplepacketblock_le(i: &[u8]) -> IResult<&[u8], SimplePacketBlock, PcapError<&[u8]>> {
    ng_block_parser::<SimplePacketBlock, PcapLE, _, _>()(i)
}
pub fn parse_simplepacketblock_be(i: &[u8]) -> IResult<&[u8], SimplePacketBlock, PcapError<&[u8]>> {
    ng_block_parser::<SimplePacketBlock, PcapBE, _, _>()(i)
}
pub fn parse_enhancedpacketblock_le(
    i: &[u8],
) -> IResult<&[u8], EnhancedPacketBlock, PcapError<&[u8]>> {
    ng_block_parser::<EnhancedPacketBlock, PcapLE, _, _>()(i)
}
pub fn parse_enhancedpacketblock_be(
    i: &[u8],
) -> IResult<&[u8], EnhancedPacketBlock, PcapError<&[u8]>> {
    ng_block_parser::<EnhancedPacketBlock, PcapBE, _, _>()(i)
}
fn parse_name_record<'a, En: PcapEndianness, E: ParseError<&'a [u8]>>(
    i: &'a [u8],
) -> IResult<&'a [u8], NameRecord, E> {
    let (i, record_type) = En::parse_u16(i)?;
    let (i, record_len) = En::parse_u16(i)?;
    let aligned_len = align32!(record_len as u32);
    let (i, record_value) = take(aligned_len)(i)?;
    let name_record = NameRecord {
        record_type: NameRecordType(record_type),
        record_value,
    };
    Ok((i, name_record))
}
fn parse_name_record_list<'a, En: PcapEndianness, E: ParseError<&'a [u8]>>(
    i: &'a [u8],
) -> IResult<&'a [u8], Vec<NameRecord>, E> {
    map(
        many_till(parse_name_record::<En, E>, tag(b"\x00\x00\x00\x00")),
        |(mut v, _)| {
            v.push(NameRecord::END);
            v
        },
    )(i)
}
#[inline]
pub fn parse_nameresolutionblock_le(
    i: &[u8],
) -> IResult<&[u8], NameResolutionBlock, PcapError<&[u8]>> {
    ng_block_parser::<NameResolutionBlock, PcapLE, _, _>()(i)
}
#[inline]
pub fn parse_nameresolutionblock_be(
    i: &[u8],
) -> IResult<&[u8], NameResolutionBlock, PcapError<&[u8]>> {
    ng_block_parser::<NameResolutionBlock, PcapBE, _, _>()(i)
}
pub fn parse_interfacestatisticsblock_le(
    i: &[u8],
) -> IResult<&[u8], InterfaceStatisticsBlock, PcapError<&[u8]>> {
    ng_block_parser::<InterfaceStatisticsBlock, PcapLE, _, _>()(i)
}
pub fn parse_interfacestatisticsblock_be(
    i: &[u8],
) -> IResult<&[u8], InterfaceStatisticsBlock, PcapError<&[u8]>> {
    ng_block_parser::<InterfaceStatisticsBlock, PcapBE, _, _>()(i)
}
#[inline]
pub fn parse_systemdjournalexportblock_le(
    i: &[u8],
) -> IResult<&[u8], SystemdJournalExportBlock, PcapError<&[u8]>> {
    ng_block_parser::<SystemdJournalExportBlock, PcapLE, _, _>()(i)
}
#[inline]
pub fn parse_systemdjournalexportblock_be(
    i: &[u8],
) -> IResult<&[u8], SystemdJournalExportBlock, PcapError<&[u8]>> {
    ng_block_parser::<SystemdJournalExportBlock, PcapBE, _, _>()(i)
}
#[inline]
pub fn parse_decryptionsecretsblock_le(
    i: &[u8],
) -> IResult<&[u8], DecryptionSecretsBlock, PcapError<&[u8]>> {
    ng_block_parser::<DecryptionSecretsBlock, PcapLE, _, _>()(i)
}
#[inline]
pub fn parse_decryptionsecretsblock_be(
    i: &[u8],
) -> IResult<&[u8], DecryptionSecretsBlock, PcapError<&[u8]>> {
    ng_block_parser::<DecryptionSecretsBlock, PcapBE, _, _>()(i)
}
#[inline]
pub fn parse_customblock_le(i: &[u8]) -> IResult<&[u8], CustomBlock, PcapError<&[u8]>> {
    ng_block_parser::<CustomBlock, PcapLE, _, _>()(i)
}
#[inline]
pub fn parse_customblock_be(i: &[u8]) -> IResult<&[u8], CustomBlock, PcapError<&[u8]>> {
    ng_block_parser::<CustomBlock, PcapBE, _, _>()(i)
}
#[inline]
pub fn parse_dcb_le(i: &[u8]) -> IResult<&[u8], CustomBlock, PcapError<&[u8]>> {
    ng_block_parser::<DCBParser, PcapLE, _, _>()(i)
}
#[inline]
pub fn parse_dcb_be(i: &[u8]) -> IResult<&[u8], CustomBlock, PcapError<&[u8]>> {
    ng_block_parser::<DCBParser, PcapBE, _, _>()(i)
}
#[inline]
pub fn parse_processinformationblock_le(
    i: &[u8],
) -> IResult<&[u8], ProcessInformationBlock, PcapError<&[u8]>> {
    ng_block_parser::<ProcessInformationBlock, PcapLE, _, _>()(i)
}
#[inline]
pub fn parse_processinformationblock_be(
    i: &[u8],
) -> IResult<&[u8], ProcessInformationBlock, PcapError<&[u8]>> {
    ng_block_parser::<ProcessInformationBlock, PcapBE, _, _>()(i)
}
pub fn parse_unknownblock_le(i: &[u8]) -> IResult<&[u8], UnknownBlock, PcapError<&[u8]>> {
    ng_block_parser::<UnknownBlock, PcapLE, _, _>()(i)
}
pub fn parse_unknownblock_be(i: &[u8]) -> IResult<&[u8], UnknownBlock, PcapError<&[u8]>> {
    ng_block_parser::<UnknownBlock, PcapBE, _, _>()(i)
}
pub fn parse_block_le(i: &[u8]) -> IResult<&[u8], Block, PcapError<&[u8]>> {
    match le_u32(i) {
        Ok((_, id)) => match id {
            SHB_MAGIC => map(parse_sectionheaderblock, Block::SectionHeader)(i),
            IDB_MAGIC => map(
                parse_interfacedescriptionblock_le,
                Block::InterfaceDescription,
            )(i),
            SPB_MAGIC => map(parse_simplepacketblock_le, Block::SimplePacket)(i),
            EPB_MAGIC => map(parse_enhancedpacketblock_le, Block::EnhancedPacket)(i),
            NRB_MAGIC => map(parse_nameresolutionblock_le, Block::NameResolution)(i),
            ISB_MAGIC => map(
                parse_interfacestatisticsblock_le,
                Block::InterfaceStatistics,
            )(i),
            SJE_MAGIC => map(
                parse_systemdjournalexportblock_le,
                Block::SystemdJournalExport,
            )(i),
            DSB_MAGIC => map(parse_decryptionsecretsblock_le, Block::DecryptionSecrets)(i),
            CB_MAGIC => map(parse_customblock_le, Block::Custom)(i),
            DCB_MAGIC => map(parse_dcb_le, Block::Custom)(i),
            PIB_MAGIC => map(parse_processinformationblock_le, Block::ProcessInformation)(i),
            _ => map(parse_unknownblock_le, Block::Unknown)(i),
        },
        Err(e) => Err(e),
    }
}
pub fn parse_block_be(i: &[u8]) -> IResult<&[u8], Block, PcapError<&[u8]>> {
    match be_u32(i) {
        Ok((_, id)) => match id {
            SHB_MAGIC => map(parse_sectionheaderblock, Block::SectionHeader)(i),
            IDB_MAGIC => map(
                parse_interfacedescriptionblock_be,
                Block::InterfaceDescription,
            )(i),
            SPB_MAGIC => map(parse_simplepacketblock_be, Block::SimplePacket)(i),
            EPB_MAGIC => map(parse_enhancedpacketblock_be, Block::EnhancedPacket)(i),
            NRB_MAGIC => map(parse_nameresolutionblock_be, Block::NameResolution)(i),
            ISB_MAGIC => map(
                parse_interfacestatisticsblock_be,
                Block::InterfaceStatistics,
            )(i),
            SJE_MAGIC => map(
                parse_systemdjournalexportblock_be,
                Block::SystemdJournalExport,
            )(i),
            DSB_MAGIC => map(parse_decryptionsecretsblock_be, Block::DecryptionSecrets)(i),
            CB_MAGIC => map(parse_customblock_be, Block::Custom)(i),
            DCB_MAGIC => map(parse_dcb_be, Block::Custom)(i),
            PIB_MAGIC => map(parse_processinformationblock_be, Block::ProcessInformation)(i),
            _ => map(parse_unknownblock_be, Block::Unknown)(i),
        },
        Err(e) => Err(e),
    }
}
pub fn parse_section_content_block_le(i: &[u8]) -> IResult<&[u8], Block, PcapError<&[u8]>> {
    let (rem, block) = parse_block_le(i)?;
    match block {
        Block::SectionHeader(_) => Err(Err::Error(make_error(i, ErrorKind::Tag))),
        _ => Ok((rem, block)),
    }
}
pub fn parse_section_content_block_be(i: &[u8]) -> IResult<&[u8], Block, PcapError<&[u8]>> {
    let (rem, block) = parse_block_be(i)?;
    match block {
        Block::SectionHeader(_) => Err(Err::Error(make_error(i, ErrorKind::Tag))),
        _ => Ok((rem, block)),
    }
}
pub fn parse_section(i: &[u8]) -> IResult<&[u8], Section, PcapError<&[u8]>> {
    let (rem, shb) = parse_sectionheaderblock(i)?;
    let big_endian = shb.big_endian();
    let (rem, mut b) = if big_endian {
        many0(complete(parse_section_content_block_be))(rem)?
    } else {
        many0(complete(parse_section_content_block_le))(rem)?
    };
    let mut blocks = Vec::with_capacity(b.len() + 1);
    blocks.push(Block::SectionHeader(shb));
    blocks.append(&mut b);
    let section = Section { blocks, big_endian };
    Ok((rem, section))
}
#[inline]
pub fn parse_sections(i: &[u8]) -> IResult<&[u8], Vec<Section>, PcapError<&[u8]>> {
    many1(complete(parse_section))(i)
}