#[macro_use]
extern crate chomp;
#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
use winapi::guiddef::GUID;
use chomp::prelude::*;
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)]
#[allow(non_camel_case_types)]
pub struct u48 {
pub hi: u16,
pub lo: u32
}
impl u48 {
pub fn to_u64(self) -> u64 {
((self.hi as u64) << 32) +
((self.lo as u64) )
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)]
pub struct Chunks {
pub chunk1: u32,
pub chunk2: u16,
pub chunk3: u16,
pub chunk4: u16,
pub chunk5: u48
}
impl Chunks {
pub fn to_bytes(self) -> [u8; 16] {
[ ((self.chunk1 & 0xFF000000) >> 24) as u8,
((self.chunk1 & 0x00FF0000) >> 16) as u8,
((self.chunk1 & 0x0000FF00) >> 8) as u8,
((self.chunk1 & 0x000000FF) ) as u8,
((self.chunk2 & 0xFF00) >> 8) as u8,
((self.chunk2 & 0x00FF) ) as u8,
((self.chunk3 & 0xFF00) >> 8) as u8,
((self.chunk3 & 0x00FF) ) as u8,
((self.chunk4 & 0xFF00) >> 8) as u8,
((self.chunk4 & 0x00FF) ) as u8,
((self.chunk5.hi & 0xFF00) >> 8) as u8,
((self.chunk5.hi & 0x00FF) ) as u8,
((self.chunk5.lo & 0xFF000000) >> 24) as u8,
((self.chunk5.lo & 0x00FF0000) >> 16) as u8,
((self.chunk5.lo & 0x0000FF00) >> 8) as u8,
((self.chunk5.lo & 0x000000FF) ) as u8 ]
}
pub fn to_parts(self) -> (u32, u16, u16, [u8; 8]) {
let b = self.to_bytes();
(self.chunk1,
self.chunk2,
self.chunk3,
[b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]])
}
#[cfg(windows)]
pub fn to_guid(self) -> GUID {
GUID {
Data1: self.chunk1,
Data2: self.chunk2,
Data3: self.chunk3,
Data4: [
((self.chunk4 & 0xFF00) >> 8) as u8,
((self.chunk4 & 0x00FF) ) as u8,
((self.chunk5.hi & 0xFF00) >> 8) as u8,
((self.chunk5.hi & 0x00FF) ) as u8,
((self.chunk5.lo & 0xFF000000) >> 24) as u8,
((self.chunk5.lo & 0x00FF0000) >> 16) as u8,
((self.chunk5.lo & 0x0000FF00) >> 8) as u8,
((self.chunk5.lo & 0x000000FF) ) as u8
]
}
}
}
fn hex_digit<I: U8Input>(i: I) -> SimpleResult<I, u8> {
satisfy(i, |c| {
b'0' <= c && c <= b'9' ||
b'A' <= c && c <= b'F' ||
b'a' <= c && c <= b'f'
}).map(|c| {
if b'0' <= c && c <= b'9' {
c - b'0'
} else if b'A' <= c && c <= b'F' {
(c - b'A') + 10
} else if b'a' <= c && c <= b'f' {
(c - b'a') + 10
} else {
unreachable!()
}
})
}
fn short_chunk<I: U8Input>(i: I) -> SimpleResult<I, u16> {
parse!{i;
let digit1 = hex_digit();
let digit2 = hex_digit();
let digit3 = hex_digit();
let digit4 = hex_digit();
ret ((digit1 as u16) << 12) +
((digit2 as u16) << 8) +
((digit3 as u16) << 4) +
((digit4 as u16) )
}
}
fn medium_chunk<I: U8Input>(i: I) -> SimpleResult<I, u32> {
parse!{i;
let short1 = short_chunk();
let short2 = short_chunk();
ret ((short1 as u32) << 16) +
((short2 as u32) )
}
}
fn long_chunk<I: U8Input>(i: I) -> SimpleResult<I, u48> {
parse!{i;
let hi = short_chunk();
let lo = medium_chunk();
ret u48 { hi, lo }
}
}
pub fn chunks<I: U8Input>(i: I) -> SimpleResult<I, Chunks> {
parse!{i;
let chunk1 = medium_chunk();
string(b"-");
let chunk2 = short_chunk();
string(b"-");
let chunk3 = short_chunk();
string(b"-");
let chunk4 = short_chunk();
string(b"-");
let chunk5 = long_chunk();
ret Chunks { chunk1, chunk2, chunk3, chunk4, chunk5 }
}
}
#[cfg(test)]
mod tests {
use chomp::prelude::*;
use super::{hex_digit, short_chunk, medium_chunk, long_chunk, chunks, Chunks, u48};
#[test]
fn test_hex_digit() {
assert_eq!(parse_only(hex_digit, b"c"), Ok(12));
assert_eq!(parse_only(hex_digit, b"C"), Ok(12));
assert_eq!(parse_only(hex_digit, b"9"), Ok(9));
}
#[test]
fn test_short_chunk() {
assert_eq!(parse_only(short_chunk, b"cafe"), Ok(0xcafe));
assert_eq!(parse_only(short_chunk, b"CAFE"), Ok(0xcafe));
}
#[test]
fn test_medium_chunk() {
assert_eq!(parse_only(medium_chunk, b"cafef00d"), Ok(0xcafef00d));
assert_eq!(parse_only(medium_chunk, b"CAFEF00D"), Ok(0xcafef00d));
}
#[test]
fn test_long_chunk() {
assert_eq!(parse_only(long_chunk, b"1234cafef00d").map(|long| long.to_u64()), Ok(0x1234cafef00d));
assert_eq!(parse_only(long_chunk, b"1234CAFEF00D").map(|long| long.to_u64()), Ok(0x1234cafef00d));
}
#[test]
fn test_chunks() {
assert_eq!(parse_only(chunks, b"cafef00d-CAFE-f00d-BEEF-1234abcdDADA"), Ok(Chunks {
chunk1: 0xcafef00d,
chunk2: 0xCAFE,
chunk3: 0xf00d,
chunk4: 0xBEEF,
chunk5: u48 {
hi: 0x1234,
lo: 0xabcdDADA
}
}));
}
#[test]
fn test_bytes() {
let chunks = parse_only(chunks, b"cafef00d-CAFE-f00d-BEEF-1234abcdDADA").unwrap();
let bytes = chunks.to_bytes();
assert_eq!( [ 0xca, 0xfe, 0xf0, 0x0d, 0xCA, 0xFE, 0xf0, 0x0d, 0xBE, 0xEF, 0x12, 0x34, 0xab, 0xcd, 0xDA, 0xDA ],
bytes);
}
#[cfg(windows)]
#[test]
fn test_guid() {
let chunks = parse_only(chunks, b"cafef00d-CAFE-f00d-BEEF-1234abcdDADA").unwrap();
let guid = chunks.to_guid();
assert_eq!(GUID {
Data1: 0xcafef00d,
Data2: 0xCAFE,
Data3: 0cf00d,
Data4: [ 0xBE, 0xEF, 0x12, 0x34, 0xab, 0xcd, 0xDA, 0xDA ]
}, guid);
}
}