1use crate::Error;
2use nom::*;
3
4const MAGIC_NUMBER: u32 = 0xA1B2C3D4u32;
5#[cfg(target_endian = "little")]
6pub const NATIVE_ENDIAN: Endianness = Endianness::Little;
7#[cfg(target_endian = "big")]
8pub const NATIVE_ENDIAN: Endianness = Endianness::Big;
9
10#[allow(unused)]
14#[derive(Clone, Copy, Debug)]
15pub struct GlobalHeader {
16 pub endianness: Endianness,
17 pub version_major: u16,
18 pub version_minor: u16,
19 pub zone: i32,
20 pub sig_figs: i32,
21 pub snap_length: u32,
22 pub network: u32,
23}
24
25impl Default for GlobalHeader {
26 fn default() -> Self {
27 Self {
28 endianness: NATIVE_ENDIAN,
29 version_major: 2,
30 version_minor: 4,
31 zone: 0,
32 sig_figs: 0,
33 snap_length: 1500,
34 network: 1,
35 }
36 }
37}
38
39impl GlobalHeader {
40 pub fn parse<'a>(input: &'a [u8]) -> Result<(&'a [u8], GlobalHeader), Error> {
41 do_parse!(
42 input,
43 endianness: map!(u32!(NATIVE_ENDIAN), |e| {
44 let res = if e == MAGIC_NUMBER {
45 NATIVE_ENDIAN
46 } else if NATIVE_ENDIAN == Endianness::Little {
47 Endianness::Big
48 } else {
49 Endianness::Little
50 };
51 #[cfg(feature = "log-errors")]
52 debug!("Using endianness {:?} read {:02x} compared to magic number {:02x}, setting endianness to {:?}", NATIVE_ENDIAN, e, MAGIC_NUMBER, res);
53 res
54 }) >> version_major: u16!(endianness)
55 >> version_minor: u16!(endianness)
56 >> zone: i32!(endianness)
57 >> sig_figs: i32!(endianness)
58 >> snap_length: u32!(endianness)
59 >> network: u32!(endianness)
60 >> (GlobalHeader {
61 endianness: endianness,
62 version_major: version_major,
63 version_minor: version_minor,
64 zone: zone,
65 sig_figs: sig_figs,
66 snap_length: snap_length,
67 network: network
68 })
69 ).map_err(Error::from)
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[cfg(target_endian = "little")]
78 const RAW_DATA: &'static [u8] = &[
79 0xD4u8, 0xC3u8, 0xB2u8, 0xA1u8, 0x04u8, 0x00u8, 0x02u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x13u8, 0x06u8, 0x00u8, 0x00u8, 0x02u8, 0x00u8, 0x00u8, 0x00u8, ];
87 #[cfg(target_endian = "little")]
88 const RAW_DATA_REVERSED: &'static [u8] = &[
89 0x1Au8, 0x2Bu8, 0x3Cu8, 0x4Du8, 0x00u8, 0x04u8, 0x00u8, 0x02u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x04u8, 0x00u8, 0x00u8, 0x06u8, 0x13u8, 0x00u8, 0x00u8, 0x00u8, 0x02u8, ];
97 #[cfg(target_endian = "big")]
98 const RAW_DATA: &'static [u8] = &[
99 0x1Au8, 0x2Bu8, 0x3Cu8, 0x4Du8, 0x00u8, 0x04u8, 0x00u8, 0x02u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x04u8, 0x00u8, 0x00u8, 0x06u8, 0x13u8, 0x00u8, 0x00u8, 0x00u8, 0x02u8, ];
107 #[cfg(target_endian = "big")]
108 const RAW_DATA_REVERSED: &'static [u8] = &[
109 0xD4u8, 0xC3u8, 0xB2u8, 0xA1u8, 0x04u8, 0x00u8, 0x02u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x13u8, 0x06u8, 0x00u8, 0x00u8, 0x02u8, 0x00u8, 0x00u8, 0x00u8, ];
117
118 #[test]
119 fn global_header_native_endian() {
120 let _ = env_logger::try_init();
121
122 let (rem, gh) = GlobalHeader::parse(RAW_DATA).expect("Failed to parse header");
123
124 assert!(rem.is_empty());
125 assert_eq!(gh.version_major, 4);
126 assert_eq!(gh.version_minor, 2);
127 assert_eq!(gh.endianness, NATIVE_ENDIAN);
128 assert_eq!(gh.snap_length, 1555);
129 }
130
131 #[test]
132 fn global_header_not_native_endian() {
133 let (rem, gh) = GlobalHeader::parse(RAW_DATA_REVERSED).expect("Failed to parse header");
134
135 let expected_endianness = match NATIVE_ENDIAN {
136 Endianness::Little => Endianness::Big,
137 Endianness::Big => Endianness::Little,
138 };
139
140 assert!(rem.is_empty());
141 assert_eq!(gh.version_major, 4);
142 assert_eq!(gh.version_minor, 2);
143 assert_eq!(gh.endianness, expected_endianness);
144 assert_eq!(gh.snap_length, 1555);
145 }
146}