Created
June 16, 2015 04:18
-
-
Save richo/4a67af2758ee4b68356b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use nom::{IResult}; | |
| use nom::{le_u64,le_u32,le_u16}; | |
| use std::str::from_utf8; | |
| // FIXME(richo) Flesh this out properly with it's own discrete parser. | |
| #[derive(Debug)] | |
| pub struct Options<'a> { | |
| pub options: Vec<Opt<'a>>, | |
| } | |
| #[derive(Debug)] | |
| pub struct Opt<'a> { | |
| code: u16, | |
| length: u16, | |
| value: &'a [u8], | |
| } | |
| // 0 1 2 3 | |
| // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | Option Code | Option Length | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // / Option Value / | |
| // / /* variable length, aligned to 32 bits */ / | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // / / | |
| // / . . . other options . . . / | |
| // / / | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | Option Code == opt_endofopt | Option Length == 0 | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| #[inline(always)] | |
| // Debug helper, since at various points being able to dump how much it's planning to read has been | |
| // really handy | |
| fn expand(i: u16) -> usize { | |
| i as usize | |
| } | |
| named!(option<&[u8],Opt>, | |
| chain!( | |
| code: le_u16 ~ | |
| length: le_u16 ~ | |
| value: take!(expand(length)) , | |
| ||{ | |
| Opt { | |
| code: code, | |
| length: length, | |
| value: value, | |
| } | |
| } | |
| ) | |
| ); | |
| // It's not abundantly clear to me that this is actually safe. | |
| // My belief is that because we're operating on a &[u8] that was carved out of the high level | |
| // buffer, and that *it* is a fat pointer with a length, the runtime will stop us from running off | |
| // the end, but it needs to be actually proven. | |
| named!(pub parse_options< &[u8],Options >, | |
| chain!( | |
| opts: many1!(option), | |
| ||{ | |
| // It's also not super clear to me that we actually want to include the final option | |
| // in the vector | |
| if let Some(last) = opts.last() { | |
| assert_eq!(last.code, 0x0); | |
| assert_eq!(last.length, 0x0); | |
| } | |
| Options { | |
| options: opts | |
| } | |
| } | |
| ) | |
| ); | |
| #[test] | |
| fn test_parse_options() { | |
| let input = b"\x12\x42\x08\x00asdfasdf\x00\x00\x00\x00"; | |
| match parse_options(input) { | |
| IResult::Done(left, opts) => { | |
| assert_eq!(opts.options.len(), 2); | |
| let o = &opts.options[0]; | |
| assert_eq!(o.code, 0x4212); | |
| assert_eq!(o.length, 0x08); | |
| assert_eq!(o.value, b"asdfasdf"); | |
| }, | |
| _ => { | |
| panic!("Hit a codepath we shouldn't have"); | |
| }, | |
| } | |
| } | |
| #[test] | |
| fn test_multiple_options() { | |
| let input = b"\x03\x00\x0b\x00\x57\x69\x6e\x64\ | |
| \x6f\x77\x73\x20\x58\x50\x00\x00\x04\x00\x0c\x00\x54\x65\x73\x74\ | |
| \x30\x30\x34\x2e\x65\x78\x65\x00\x00\x00\x00\x00\x40\x00\x00\x00"; | |
| match parse_options(input) { | |
| IResult::Done(left, opts) => { | |
| // assert_eq!(opts.options.len(), 3); | |
| let o = &opts.options[0]; | |
| assert_eq!(o.code, 0x03); | |
| assert_eq!(o.length, 0x0b); | |
| assert_eq!(&o.value[..], b"Windows XP\x00"); | |
| let o = &opts.options[1]; | |
| // assert_eq!(o.code, 0x4212); | |
| // assert_eq!(o.length, 0x08); | |
| // assert_eq!(from_utf8(o.value).unwrap(), "Windows XP"); | |
| }, | |
| _ => { | |
| panic!("Hit a codepath we shouldn't have"); | |
| }, | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment