1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use byteorder::{BigEndian, LittleEndian};

use super::RawCapPacket;
use crate::cap::{CapHeader, CapPacket};
use crate::errors::*;
use crate::Endianness;

/// Parses a Cap from a slice of bytes.
///
/// You can match on [`PcapError::IncompleteBuffer`](crate::errors::PcapError) to known if the parser need more data.
///
/// # Example
/// ```no_run
/// use pcaparse::cap::CapParser;
/// use pcaparse::PcapError;
///
/// let cap = vec![0_u8; 0];
/// let mut src = &cap[..];
///
/// // Creates a new parser and parse the cap header
/// let (rem, cap_parser) = CapParser::new(&cap[..]).unwrap();
/// src = rem;
///
/// loop {
///     match cap_parser.next_packet(src) {
///         Ok((rem, packet)) => {
///             // Do something
///
///             // Don't forget to update src
///             src = rem;
///
///             // No more data, if no more incoming either then this is the end of the file
///             if rem.is_empty() {
///                 break;
///             }
///         },
///         Err(PcapError::IncompleteBuffer) => {}, // Load more data into src
///         Err(_) => {},                           // Parsing error
///     }
/// }
/// ```
#[derive(Debug)]
pub struct CapParser {
    header: CapHeader,
}

impl CapParser {
    /// Creates a new [`CapParser`].
    ///
    /// Returns the remainder and the parser.
    pub fn new(slice: &[u8]) -> PcapResult<(&[u8], CapParser)> {
        let (slice, header) = CapHeader::from_slice(slice)?;

        let parser = CapParser { header };

        Ok((slice, parser))
    }

    /// Creates a new Asynchronously [`CapParser`].
    ///
    /// Returns the remainder and the parser.
    #[cfg(feature = "tokio")]
    pub async fn async_new(slice: &[u8]) -> PcapResult<(&[u8], CapParser)> {
        let (slice, header) = CapHeader::async_from_slice(slice).await?;

        let parser = CapParser { header };

        Ok((slice, parser))
    }

    /// Returns the remainder and the next [`CapPacket`].
    pub fn next_packet<'a>(&self, slice: &'a [u8]) -> PcapResult<(&'a [u8], CapPacket<'a>)> {
        match self.header.endianness {
            Endianness::Big => CapPacket::from_slice::<BigEndian>(slice, self.header.start_time),
            Endianness::Little => CapPacket::from_slice::<LittleEndian>(slice, self.header.start_time),
        }
    }

    /// Asynchronously returns the remainder and the next [`CapPacket`].
    #[cfg(feature = "tokio")]
    pub async fn async_next_packet<'a>(&self, slice: &'a [u8]) -> PcapResult<(&'a [u8], CapPacket<'a>)> {
        match self.header.endianness {
            Endianness::Big => CapPacket::async_from_slice::<BigEndian>(slice, self.header.start_time).await,
            Endianness::Little => CapPacket::async_from_slice::<LittleEndian>(slice, self.header.start_time).await,
        }
    }

    /// Returns the remainder and the next [`RawCapPacket`].
    pub fn next_raw_packet<'a>(&self, slice: &'a [u8]) -> PcapResult<(&'a [u8], RawCapPacket<'a>)> {
        match self.header.endianness {
            Endianness::Big => RawCapPacket::from_slice::<BigEndian>(slice),
            Endianness::Little => RawCapPacket::from_slice::<LittleEndian>(slice),
        }
    }

    /// Asynchronously returns the remainder and the next [`RawCapPacket`].
    #[cfg(feature = "tokio")]
    pub async fn async_next_raw_packet<'a>(&self, slice: &'a [u8]) -> PcapResult<(&'a [u8], RawCapPacket<'a>)> {
        match self.header.endianness {
            Endianness::Big => RawCapPacket::async_from_slice::<BigEndian>(slice).await,
            Endianness::Little => RawCapPacket::async_from_slice::<LittleEndian>(slice).await,
        }
    }

    /// Returns the header of the cap file.
    pub fn header(&self) -> CapHeader {
        self.header
    }
}