//!Rust crate to decode and encode hexadecimal. //! //! # Examples //!``` //!let hex_string = "1a2b3c"; //!let data = rhex::decode_hex(&hex_string).unwrap(); //!``` #[derive(Debug)] ///Possible errors that occur during decoding pub enum HexDecodeError { InvalidByteCount, InvalidHexCharacter, } struct EncodeHexIterSlice<'data_lifetime> { //bytes to encode as hex data: &'data_lifetime [u8], //each byte generates 2 hex characters but we only return one at a time next_char : Option } impl<'data_lifetime> EncodeHexIterSlice<'data_lifetime> { fn new(data : &'data_lifetime [u8]) -> Self { EncodeHexIterSlice{ data, next_char : None } } } impl<'data_lifetime> Iterator for EncodeHexIterSlice<'data_lifetime> { type Item = char; fn next(&mut self) -> Option { //if the we still have a pending character return it if let Some(c) = self.next_char.take() { return Some(c); } if self.data.len() == 0 { return None; } let next_byte = &self.data[0]; self.data = &self.data[1..]; let high = byte_to_hex_char((next_byte & 0xF0) >> 4); let low = byte_to_hex_char(next_byte & 0x0F); self.next_char = Some(low); Some(high) } } struct DecodeHexIterSlice<'data_lifetime> { //ascii encoded hex characters //if any of the bytes is not valid ascii hex the iterator will return None data: &'data_lifetime [u8], } impl<'data_lifetime> DecodeHexIterSlice<'data_lifetime> { fn new(data: &'data_lifetime [u8]) -> Self { DecodeHexIterSlice { data } } } impl<'data_lifetime> Iterator for DecodeHexIterSlice<'data_lifetime> { type Item = u8; fn next(&mut self) -> Option { if self.data.len() < 2 { return None; } let v1_opt = hex_char_byte_to_value(self.data[0]); let v2_opt = hex_char_byte_to_value(self.data[1]); if v1_opt.is_err() || v2_opt.is_err() { self.data = &[]; return None; } self.data = &self.data[2..]; let v1 = v1_opt.unwrap(); let v2 = v2_opt.unwrap(); Some(v1 * 16 + v2) } } fn hex_char_byte_to_value(c: u8) -> Result { if !c.is_ascii_hexdigit() { return Err(HexDecodeError::InvalidHexCharacter); } Ok((c as char).to_digit(16).unwrap() as u8) } fn byte_to_hex_char(b: u8) -> char { assert!(b <= 15); match b { digit if digit < 10 => ('0' as u8 + digit) as char, letter => ('a' as u8 + letter - 10) as char, } } fn append_byte_hex_to_string(byte: u8, string: &mut String) { let high = (byte & 0xF0) >> 4; let low = byte & 0x0F; string.push(byte_to_hex_char(high)); string.push(byte_to_hex_char(low)); } ///Returns an iterator that decodes the hex characters into bytes ///if any error occures it returns None so no error code is reported /// ///``` ///let hex_string = "12ffbc"; ///for byte in rhex::decode_hex_iter(&hex_string) { /// //do something ///} ///``` pub fn decode_hex_iter<'a, T>(string: &'a T) -> impl Iterator + 'a where T: AsRef<[u8]> + ?Sized { DecodeHexIterSlice::new(string.as_ref()) } ///Returns an iterator of char's that are the hexadecimal representation of the data. ///The chars returned by the iterar are all lower case. /// ///``` ///let data = &[0x11, 0xbc, 0x22]; ///for c in rhex::encode_hex_iter(&data) { /// //do something with c ///} ///``` pub fn encode_hex_iter<'a, T>(data : &'a T) -> impl Iterator + 'a where T: AsRef<[u8]> + ?Sized { EncodeHexIterSlice::new(data.as_ref()) } ///Returns a Vec containing all the decoded hex data. /// ///``` ///let hex_string = "ffaa11"; ///let data = rhex::decode_hex(&hex_string).unwrap(); ///``` pub fn decode_hex>(string: T) -> Result, HexDecodeError> { let chars = string.as_ref(); if chars.len() % 2 != 0 { return Err(HexDecodeError::InvalidByteCount); } let mut data = Vec::new(); let mut index = 0; let mut first_digit: u8 = 0; for c in chars.iter() { if index % 2 != 0 { let second_digit = hex_char_byte_to_value(*c)?; let value = first_digit * 16 + second_digit; data.push(value); } else { first_digit = hex_char_byte_to_value(*c)?; } index += 1; } Ok(data) } ///Returns a new string contaning the hexadecimal representation of the data. /// ///``` ///let data = &[0x11, 0x12, 0x13]; ///let string = rhex::encode_hex(&data); ///assert_eq!(string, "111213"); ///``` pub fn encode_hex>(data: T) -> String { let mut string = String::new(); let data_ref = data.as_ref(); for b in data_ref.iter() { append_byte_hex_to_string(*b, &mut string); } string } #[cfg(test)] mod tests { use super::*; #[test] fn decode_zero_bytes_test() { let string = ""; let data = decode_hex(&string).unwrap(); assert_eq!(0, data.len()); } #[test] fn decode_one_byte_test() { let string = "ff"; let data = decode_hex(&string).unwrap(); assert_eq!(1, data.len()); assert_eq!(0xff, data[0]); } #[test] fn decode_multiple_bytes_test() { let string = "ffaabbccdd1122"; let data = decode_hex(&string).unwrap(); assert_eq!(7, data.len()); assert_eq!(&[0xff, 0xaa, 0xbb, 0xcc, 0xdd, 0x11, 0x22], data.as_slice()); } #[test] fn decode_invalid_character_test() { let string = "ffaabz"; match decode_hex(&string) { Err(HexDecodeError::InvalidHexCharacter) => {} _ => panic!("Invalid result returned"), } } #[test] fn decode_invalid_character_length() { let string = "ffaab"; match decode_hex(&string) { Err(HexDecodeError::InvalidByteCount) => {} _ => panic!("Invalid result returned"), } } #[test] fn encode_zero_bytes() { let data: &[u8; 0] = &[]; let string = encode_hex(&data); assert_eq!(string, ""); } #[test] fn encode_one_byte() { let data: &[u8; 1] = &[0xa1]; let string = encode_hex(&data); assert_eq!(string, "a1"); } #[test] fn encode_multiple_bytes() { let data: &[u8; 5] = &[0xaa, 0xbb, 0xcc, 0xdd, 0xee]; let string = encode_hex(&data); assert_eq!(string, "aabbccddee"); } #[test] fn owned_string_decode() { //this test just needs to compile let string = String::from("aabbccddee"); let _ = decode_hex(&string); let _ = decode_hex(string); } #[test] fn iter_decode_test() { let string = "aabbcc"; let data: Vec = decode_hex_iter(&string).collect(); assert_eq!(&[0xaa, 0xbb, 0xcc], data.as_slice()); } #[test] fn iter_encode_test() { let data = &[0xff, 0xaa, 0x12, 0x45]; let string : String = encode_hex_iter(&data).collect(); assert_eq!(string, "ffaa1245"); } }