From 5ac2d28d076ab8f038012b0aabc47d11577afcc0 Mon Sep 17 00:00:00 2001 From: diogo Date: Sat, 23 May 2020 00:03:54 +0100 Subject: init --- .gitignore | 2 + Cargo.toml | 9 +++++ src/lib.rs | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..428a728 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rhex" +version = "0.1.0" +authors = ["diogo "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..c31c3a0 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,124 @@ +#[derive(Debug)] +pub enum HexDecodeError { + InvalidByteCount, + InvalidHexCharacter, +} + +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)); +} + +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) +} + +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"); + } +} -- cgit