rusty_pcap/
byte_order.rs

1//! Byte Order handling for pcap and pcap-ng files
2
3use std::io::{Read, Write};
4
5use thiserror::Error;
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
7#[error("Undetermined byte order")]
8pub struct UndertminedByteOrder;
9/// Represents a trait for byte order operations
10pub trait ByteOrder: Clone + Copy {
11    /// Converts a byte array to a u16
12    fn u16_from_bytes(self, bytes: [u8; 2]) -> u16;
13    fn u16_to_bytes(self, value: u16) -> [u8; 2];
14    /// Converts a byte array to a u32
15    fn u32_from_bytes(self, bytes: [u8; 4]) -> u32;
16    fn u32_to_bytes(self, value: u32) -> [u8; 4];
17    fn u64_from_bytes(self, bytes: [u8; 8]) -> u64;
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct BigEndian;
22impl ByteOrder for BigEndian {
23    fn u16_from_bytes(self, bytes: [u8; 2]) -> u16 {
24        u16::from_be_bytes(bytes)
25    }
26    fn u16_to_bytes(self, value: u16) -> [u8; 2] {
27        value.to_be_bytes()
28    }
29    fn u32_from_bytes(self, bytes: [u8; 4]) -> u32 {
30        u32::from_be_bytes(bytes)
31    }
32    fn u32_to_bytes(self, value: u32) -> [u8; 4] {
33        value.to_be_bytes()
34    }
35    fn u64_from_bytes(self, bytes: [u8; 8]) -> u64 {
36        u64::from_be_bytes(bytes)
37    }
38}
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub struct LittleEndian;
41impl ByteOrder for LittleEndian {
42    fn u16_from_bytes(self, bytes: [u8; 2]) -> u16 {
43        u16::from_le_bytes(bytes)
44    }
45    fn u16_to_bytes(self, value: u16) -> [u8; 2] {
46        value.to_le_bytes()
47    }
48    fn u32_from_bytes(self, bytes: [u8; 4]) -> u32 {
49        u32::from_le_bytes(bytes)
50    }
51    fn u32_to_bytes(self, value: u32) -> [u8; 4] {
52        value.to_le_bytes()
53    }
54    fn u64_from_bytes(self, bytes: [u8; 8]) -> u64 {
55        u64::from_le_bytes(bytes)
56    }
57}
58
59/// Represents the endianness of the byte order
60///
61/// ## Note
62///
63/// Default is based on the system. SO using default should not be used in tests
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum Endianness {
66    /// Little-endian byte order
67    LittleEndian,
68    /// Big-endian byte order
69    BigEndian,
70}
71#[cfg(target_endian = "little")]
72#[allow(clippy::derivable_impls)]
73impl Default for Endianness {
74    fn default() -> Self {
75        Endianness::LittleEndian
76    }
77}
78
79#[cfg(target_endian = "big")]
80#[allow(clippy::derivable_impls)]
81impl Default for Endianness {
82    fn default() -> Self {
83        Endianness::BigEndian
84    }
85}
86impl ByteOrder for Endianness {
87    fn u16_from_bytes(self, bytes: [u8; 2]) -> u16 {
88        match self {
89            Endianness::BigEndian => BigEndian.u16_from_bytes(bytes),
90            Endianness::LittleEndian => LittleEndian.u16_from_bytes(bytes),
91        }
92    }
93    fn u16_to_bytes(self, value: u16) -> [u8; 2] {
94        match self {
95            Endianness::BigEndian => BigEndian.u16_to_bytes(value),
96            Endianness::LittleEndian => LittleEndian.u16_to_bytes(value),
97        }
98    }
99    fn u32_from_bytes(self, bytes: [u8; 4]) -> u32 {
100        match self {
101            Endianness::BigEndian => BigEndian.u32_from_bytes(bytes),
102            Endianness::LittleEndian => LittleEndian.u32_from_bytes(bytes),
103        }
104    }
105    fn u32_to_bytes(self, value: u32) -> [u8; 4] {
106        match self {
107            Endianness::BigEndian => BigEndian.u32_to_bytes(value),
108            Endianness::LittleEndian => LittleEndian.u32_to_bytes(value),
109        }
110    }
111    fn u64_from_bytes(self, bytes: [u8; 8]) -> u64 {
112        match self {
113            Endianness::BigEndian => BigEndian.u64_from_bytes(bytes),
114            Endianness::LittleEndian => LittleEndian.u64_from_bytes(bytes),
115        }
116    }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
120#[error("Unexpected Size for {name}: expected {expected}, got {got}")]
121pub struct UnexpectedSize {
122    pub name: &'static str,
123    pub expected: usize,
124    pub got: usize,
125}
126pub(crate) trait ExtendedByteOrder: ByteOrder {
127    /// Converts a byte slice to a u16
128    #[allow(dead_code)]
129    fn try_u16_from_bytes(self, bytes: &[u8]) -> Result<u16, UnexpectedSize>;
130
131    /// Converts a byte slice to a u32
132    fn try_u32_from_bytes(self, bytes: &[u8]) -> Result<u32, UnexpectedSize>;
133}
134impl<B: ByteOrder> ExtendedByteOrder for B {
135    fn try_u16_from_bytes(self, bytes: &[u8]) -> Result<u16, UnexpectedSize> {
136        if bytes.len() != 2 {
137            return Err(UnexpectedSize {
138                name: "u16",
139                expected: 2,
140                got: bytes.len(),
141            });
142        }
143        Ok(self.u16_from_bytes([bytes[0], bytes[1]]))
144    }
145
146    fn try_u32_from_bytes(self, bytes: &[u8]) -> Result<u32, UnexpectedSize> {
147        if bytes.len() != 4 {
148            return Err(UnexpectedSize {
149                name: "u32",
150                expected: 4,
151                got: bytes.len(),
152            });
153        }
154        Ok(self.u32_from_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
155    }
156}
157pub trait ReadExt {
158    /// Reads a u16 from the reader
159    fn read_u16<B: ByteOrder>(&mut self, byte_order: B) -> Result<u16, std::io::Error>;
160
161    /// Reads a u32 from the reader
162    fn read_u32<B: ByteOrder>(&mut self, byte_order: B) -> Result<u32, std::io::Error>;
163    /// Has nothing to do with byte order, just reads a fixed number of bytes
164    ///
165    /// But exists for simplicity
166    fn read_bytes<const SIZE: usize>(&mut self) -> Result<[u8; SIZE], std::io::Error>;
167}
168impl<R: Read> ReadExt for R {
169    fn read_u16<B: ByteOrder>(&mut self, byte_order: B) -> Result<u16, std::io::Error> {
170        let mut buffer = [0u8; 2];
171        self.read_exact(&mut buffer)?;
172        Ok(byte_order.u16_from_bytes(buffer))
173    }
174    fn read_u32<B: ByteOrder>(&mut self, byte_order: B) -> Result<u32, std::io::Error> {
175        let mut buffer = [0u8; 4];
176        self.read_exact(&mut buffer)?;
177        Ok(byte_order.u32_from_bytes(buffer))
178    }
179    fn read_bytes<const SIZE: usize>(&mut self) -> Result<[u8; SIZE], std::io::Error> {
180        let mut buffer = [0u8; SIZE];
181        self.read_exact(&mut buffer)?;
182        Ok(buffer)
183    }
184}
185
186pub trait WriteExt {
187    /// Reads a u16 from the reader
188    fn write_u16<B: ByteOrder>(&mut self, value: u16, byte_order: B) -> Result<(), std::io::Error>;
189
190    fn write_u32<B: ByteOrder>(&mut self, value: u32, byte_order: B) -> Result<(), std::io::Error>;
191}
192impl<R: Write> WriteExt for R {
193    fn write_u16<B: ByteOrder>(&mut self, value: u16, byte_order: B) -> Result<(), std::io::Error> {
194        let value = byte_order.u16_to_bytes(value);
195        self.write_all(&value)?;
196        Ok(())
197    }
198    fn write_u32<B: ByteOrder>(&mut self, value: u32, byte_order: B) -> Result<(), std::io::Error> {
199        let value = byte_order.u32_to_bytes(value);
200        self.write_all(&value)?;
201        Ok(())
202    }
203}
204#[cfg(test)]
205mod tests {
206    use super::*;
207    #[test]
208    fn test_big_endian() {
209        let bytes: [u8; 2] = [0x12, 0x34];
210        assert_eq!(BigEndian.u16_from_bytes(bytes), 0x1234);
211        let bytes: [u8; 4] = [0x12, 0x34, 0x56, 0x78];
212        assert_eq!(BigEndian.u32_from_bytes(bytes), 0x12345678);
213    }
214    #[test]
215    fn test_little_endian() {
216        let bytes: [u8; 2] = [0x34, 0x12];
217        assert_eq!(LittleEndian.u16_from_bytes(bytes), 0x1234);
218        let bytes: [u8; 4] = [0x78, 0x56, 0x34, 0x12];
219        assert_eq!(LittleEndian.u32_from_bytes(bytes), 0x12345678);
220    }
221}