1 //! Helper macros
2 
3 use nom::combinator::rest;
4 use nom::HexDisplay;
5 use nom::IResult;
6 
7 /// Helper macro for newtypes: declare associated constants and implement Display trait
8 #[macro_export]
9 macro_rules! newtype_enum (
10     (@collect_impl, $name:ident, $($key:ident = $val:expr),* $(,)*) => {
11         $( pub const $key : $name = $name($val); )*
12     };
13 
14     (@collect_disp, $name:ident, $f:ident, $m:expr, $($key:ident = $val:expr),* $(,)*) => {
15         match $m {
16             $( $val => write!($f, stringify!{$key}), )*
17             n => write!($f, "{}({} / 0x{:x})", stringify!{$name}, n, n)
18         }
19     };
20 
21     // entry
22     (impl $name:ident {$($body:tt)*}) => (
23         #[allow(non_upper_case_globals)]
24         impl $name {
25             newtype_enum!{@collect_impl, $name, $($body)*}
26         }
27     );
28 
29     // entry with display
30     (impl display $name:ident {$($body:tt)*}) => (
31         newtype_enum!(impl $name { $($body)* });
32 
33         impl ::std::fmt::Display for $name {
34             fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
35                 newtype_enum!(@collect_disp, $name, f, self.0, $($body)*)
36             }
37         }
38     );
39 
40     // entry with display and debug
41     (impl debug $name:ident {$($body:tt)*}) => (
42         newtype_enum!(impl display $name { $($body)* });
43 
44         impl ::std::fmt::Debug for $name {
45             fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
46                 write!(f, "{}", self)
47             }
48         }
49     );
50 );
51 
52 /// Helper macro for nom parsers: raise error if the condition is false
53 ///
54 /// This macro is used when using custom errors
55 #[macro_export]
56 macro_rules! custom_check (
57   ($i:expr, $cond:expr, $err:expr) => (
58     {
59       if $cond {
60         Err(::nom::Err::Error($err))
61       } else {
62         Ok(($i, ()))
63       }
64     }
65   );
66 );
67 
68 /// Helper macro for nom parsers: raise error if the condition is false
69 ///
70 /// This macro is used when using `ErrorKind`
71 #[macro_export]
72 macro_rules! error_if (
73   ($i:expr, $cond:expr, $err:expr) => (
74     {
75       use nom::error_position;
76       if $cond {
77         Err(::nom::Err::Error(error_position!($i, $err)))
78       } else {
79         Ok(($i, ()))
80       }
81     }
82   );
83 );
84 
85 /// Helper macro for nom parsers: raise error if input is not empty
86 ///
87 /// Deprecated - use `nom::eof`
88 #[macro_export]
89 #[deprecated(since = "2.0.0")]
90 macro_rules! empty (
91   ($i:expr,) => (
92     {
93       use nom::eof;
94       eof!($i,)
95     }
96   );
97 );
98 
99 /// Helper macro for nom parsers: run first parser if condition is true, else second parser
100 #[macro_export]
101 macro_rules! cond_else (
102   ($i:expr, $cond:expr, $expr_then:ident!($($args_then:tt)*), $expr_else:ident!($($args_else:tt)*)) => (
103     {
104       if $cond { $expr_then!($i, $($args_then)*) }
105       else { $expr_else!($i, $($args_else)*) }
106     }
107   );
108   ($i:expr, $cond:expr, $expr_then:expr, $expr_else:ident!($($args_else:tt)*)) => (
109       cond_else!($i, $cond, call!($expr_then), $expr_else!($($args_else)*))
110   );
111   ($i:expr, $cond:expr, $expr_then:ident!($($args_then:tt)*), $expr_else:expr) => (
112       cond_else!($i, $cond, $expr_then!($($args_then)*), call!($expr_else))
113   );
114   ($i:expr, $cond:expr, $expr_then:expr, $expr_else:expr) => (
115       cond_else!($i, $cond, call!($expr_then), call!($expr_else))
116   );
117 );
118 
119 /// Dump the remaining bytes to stderr, formatted as hex
120 pub fn dbg_dmp_rest(i: &[u8]) -> IResult<&[u8], ()> {
121     map!(i, peek!(call!(rest)), |r| eprintln!("\n{}\n", r.to_hex(16)))
122 }
123 
124 /// Read an entire slice as a big-endian value.
125 ///
126 /// Returns the value as `u64`. This function checks for integer overflows, and returns a
127 /// `Result::Err` value if the value is too big.
128 pub fn bytes_to_u64(s: &[u8]) -> Result<u64, &'static str> {
129     let mut u: u64 = 0;
130 
131     if s.is_empty() {
132         return Err("empty");
133     };
134     if s.len() > 8 {
135         return Err("overflow");
136     }
137     for &c in s {
138         let u1 = u << 8;
139         u = u1 | (c as u64);
140     }
141 
142     Ok(u)
143 }
144 
145 /// Read a slice as a big-endian value.
146 #[macro_export]
147 macro_rules! parse_hex_to_u64 (
148     ( $i:expr, $size:expr ) => (
149         map_res!($i, take!(($size as usize)), $crate::bytes_to_u64)
150     );
151 );
152 
153 named_attr!(#[doc = "Read 3 bytes as an unsigned integer"]
154 #[deprecated(since="0.5.0", note="please use `be_u24` instead")],
155             pub parse_uint24<&[u8], u64>, parse_hex_to_u64!(3));
156 
157 //named!(parse_hex4<&[u8], u64>, parse_hex_to_u64!(4));
158 
159 /// Parse a slice and return a fixed-sized array of bytes
160 ///
161 /// This creates a copy of input data
162 /// Uses unsafe code
163 #[macro_export]
164 macro_rules! slice_fixed(
165     ( $i:expr, $count:expr ) => (
166         {
167             let cnt = $count;
168             let ires: IResult<_,_> = if $i.len() < cnt {
169                 Err(::nom::Err::Incomplete(Needed::Size(cnt)))
170             } else {
171                 let mut res: [u8; $count] = unsafe {
172                     ::std::mem::MaybeUninit::uninit().assume_init()
173                 };
174                 unsafe{::std::ptr::copy($i.as_ptr(), res.as_mut_ptr(), cnt)};
175                 Ok((&$i[cnt..],res))
176             };
177             ires
178         }
179     );
180 );
181 
182 /// Combination and flat_map! and take! as first combinator
183 #[macro_export]
184 macro_rules! flat_take (
185     ($i:expr, $len:expr, $f:ident) => ({
186         if $i.len() < $len { Err(::nom::Err::Incomplete(::nom::Needed::Size($len))) }
187         else {
188             let taken = &$i[0..$len];
189             let rem = &$i[$len..];
190             match $f(taken) {
191                 Ok((_,res)) => Ok((rem,res)),
192                 Err(e)      => Err(e)
193             }
194         }
195     });
196     ($i:expr, $len:expr, $submac:ident!( $($args:tt)*)) => ({
197         if $i.len() < $len { Err(::nom::Err::Incomplete(::nom::Needed::Size($len))) }
198         else {
199             let taken = &$i[0..$len];
200             let rem = &$i[$len..];
201             match $submac!(taken, $($args)*) {
202                 Ok((_,res)) => Ok((rem,res)),
203                 Err(e)      => Err(e)
204             }
205         }
206     });
207 );
208 
209 /// Apply combinator, trying to "upgrade" error to next error type (using the `Into` or `From`
210 /// traits).
211 #[macro_export]
212 macro_rules! upgrade_error (
213     ($i:expr, $submac:ident!( $($args:tt)*) ) => ({
214         upgrade_error!( $submac!( $i, $($args)* ) )
215     });
216     ($i:expr, $f:expr) => ({
217         upgrade_error!( call!($i, $f) )
218     });
219     ($e:expr) => ({
220         match $e {
221             Ok(o) => Ok(o),
222             Err(::nom::Err::Error(e)) => Err(::nom::Err::Error(e.into())),
223             Err(::nom::Err::Failure(e)) => Err(::nom::Err::Failure(e.into())),
224             Err(::nom::Err::Incomplete(i)) => Err(::nom::Err::Incomplete(i)),
225         }
226     });
227 );
228 
229 /// Apply combinator, trying to "upgrade" error to next error type (using the `Into` or `From`
230 /// traits).
231 #[macro_export]
232 macro_rules! upgrade_error_to (
233     ($i:expr, $ty:ty, $submac:ident!( $($args:tt)*) ) => ({
234         upgrade_error_to!( $ty, $submac!( $i, $($args)* ) )
235     });
236     ($i:expr, $ty:ty, $f:expr) => ({
237         upgrade_error_to!( $ty, call!($i, $f) )
238     });
239     ($ty:ty, $e:expr) => ({
240         match $e {
241             Ok(o) => Ok(o),
242             Err(::nom::Err::Error(e)) => Err(::nom::Err::Error(e.into::<$ty>())),
243             Err(::nom::Err::Failure(e)) => Err(::nom::Err::Failure(e.into::<$ty>())),
244             Err(::nom::Err::Incomplete(i)) => Err(::nom::Err::Incomplete(i)),
245         }
246     });
247 );
248 
249 /// Nom combinator that returns the given expression unchanged
250 #[macro_export]
251 macro_rules! q {
252     ($i:expr, $x:expr) => {{
253         Ok(($i, $x))
254     }};
255 }
256 
257 /// Align input value to the next multiple of n bytes
258 /// Valid only if n is a power of 2
259 #[macro_export]
260 macro_rules! align_n2 {
261     ($x:expr, $n:expr) => {
262         ($x + ($n - 1)) & !($n - 1)
263     };
264 }
265 
266 /// Align input value to the next multiple of 4 bytes
267 #[macro_export]
268 macro_rules! align32 {
269     ($x:expr) => {
270         $crate::align_n2!($x, 4)
271     };
272 }
273 
274 #[cfg(test)]
275 mod tests {
276     use nom::error::ErrorKind;
277     use nom::number::streaming::{be_u16, be_u32, be_u8};
278     use nom::{Err, IResult, Needed};
279 
280     #[test]
281     #[allow(unsafe_code)]
282     fn test_slice_fixed() {
283         let empty = &b""[..];
284         let b = &[0x01, 0x02, 0x03, 0x04, 0x05];
285 
286         let res = slice_fixed!(b, 4);
287         assert_eq!(res, Ok((&b[4..], [1, 2, 3, 4])));
288 
289         // can we still use the result ?
290         match res {
291             Ok((rem, _)) => {
292                 let res2: IResult<&[u8], u8> = be_u8(rem);
293                 assert_eq!(res2, Ok((empty, 5)));
294             }
295             _ => (),
296         }
297     }
298 
299     #[test]
300     #[allow(unsafe_code)]
301     fn test_slice_fixed_incomplete() {
302         let b = &[0x01, 0x02, 0x03, 0x04, 0x05];
303         let res = slice_fixed!(b, 8);
304         assert_eq!(res, Err(Err::Incomplete(Needed::Size(8))));
305     }
306 
307     #[test]
308     fn test_error_if() {
309         let empty = &b""[..];
310         let res: IResult<&[u8], ()> = error_if!(empty, true, ErrorKind::Tag);
311         assert_eq!(res, Err(Err::Error(error_position!(empty, ErrorKind::Tag))));
312     }
313 
314     #[test]
315     fn test_cond_else() {
316         let input = &[0x01][..];
317         let empty = &b""[..];
318         let a = 1;
319         fn parse_u8(i: &[u8]) -> IResult<&[u8], u8> {
320             be_u8(i)
321         }
322         assert_eq!(
323             cond_else!(input, a == 1, call!(parse_u8), value!(0x02)),
324             Ok((empty, 0x01))
325         );
326         assert_eq!(
327             cond_else!(input, a == 1, parse_u8, value!(0x02)),
328             Ok((empty, 0x01))
329         );
330         assert_eq!(
331             cond_else!(input, a == 2, parse_u8, value!(0x02)),
332             Ok((input, 0x02))
333         );
334         assert_eq!(
335             cond_else!(input, a == 1, value!(0x02), parse_u8),
336             Ok((input, 0x02))
337         );
338         let res: IResult<&[u8], u8> = cond_else!(input, a == 1, parse_u8, parse_u8);
339         assert_eq!(res, Ok((empty, 0x01)));
340     }
341 
342     #[test]
343     fn test_newtype_enum() {
344         #[derive(Debug, PartialEq, Eq)]
345         struct MyType(pub u8);
346 
347         newtype_enum! {
348             impl display MyType {
349                 Val1 = 0,
350                 Val2 = 1
351             }
352         }
353 
354         assert_eq!(MyType(0), MyType::Val1);
355         assert_eq!(MyType(1), MyType::Val2);
356 
357         assert_eq!(format!("{}", MyType(0)), "Val1");
358         assert_eq!(format!("{}", MyType(4)), "MyType(4 / 0x4)");
359     }
360     #[test]
361     fn test_flat_take() {
362         let input = &[0x00, 0x01, 0xff];
363         // read first 2 bytes and use correct combinator: OK
364         let res: IResult<&[u8], u16> = flat_take!(input, 2, be_u16);
365         assert_eq!(res, Ok((&input[2..], 0x0001)));
366         // read 3 bytes and use 2: OK (some input is just lost)
367         let res: IResult<&[u8], u16> = flat_take!(input, 3, be_u16);
368         assert_eq!(res, Ok((&b""[..], 0x0001)));
369         // read 2 bytes and a combinator requiring more bytes
370         let res: IResult<&[u8], u32> = flat_take!(input, 2, be_u32);
371         assert_eq!(res, Err(Err::Incomplete(Needed::Size(4))));
372         // test with macro as sub-combinator
373         let res: IResult<&[u8], u16> = flat_take!(input, 2, be_u16);
374         assert_eq!(res, Ok((&input[2..], 0x0001)));
375     }
376 
377     #[test]
378     fn test_q() {
379         let empty = &b""[..];
380         let res: IResult<&[u8], &str, ErrorKind> = q!(empty, "test");
381         assert_eq!(res, Ok((empty, "test")));
382     }
383 
384     #[test]
385     fn test_align32() {
386         assert_eq!(align32!(3), 4);
387         assert_eq!(align32!(4), 4);
388         assert_eq!(align32!(5), 8);
389         assert_eq!(align32!(5u32), 8);
390         assert_eq!(align32!(5i32), 8);
391         assert_eq!(align32!(5usize), 8);
392     }
393 }
394