aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--src/lib.rs171
2 files changed, 158 insertions, 14 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..73c5212
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
# rhex
diff --git a/src/lib.rs b/src/lib.rs
index c31c3a0..e5597e3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,45 +1,159 @@
1///Rust crate to decode and encode hexadecimal.
2///
3///#Examples
4///```
5///let hex_string = "1a2b3c";
6///let data = rhex::decode_hex(&hex_string).unwrap();
7///```
8
1#[derive(Debug)] 9#[derive(Debug)]
10///Possible errors that occur during decoding
2pub enum HexDecodeError { 11pub enum HexDecodeError {
3 InvalidByteCount, 12 InvalidByteCount,
4 InvalidHexCharacter, 13 InvalidHexCharacter,
5} 14}
6 15
7fn hex_char_byte_to_value(c : u8) -> Result<u8, HexDecodeError> { 16struct EncodeHexIterSlice<'data_lifetime> {
17 //bytes to encode as hex
18 data: &'data_lifetime [u8],
19 //each byte generates 2 hex characters but we only return one at a time
20 next_char : Option<char>
21}
22
23impl<'data_lifetime> EncodeHexIterSlice<'data_lifetime> {
24 fn new(data : &'data_lifetime [u8]) -> Self {
25 EncodeHexIterSlice{
26 data,
27 next_char : None
28 }
29 }
30}
31
32impl<'data_lifetime> Iterator for EncodeHexIterSlice<'data_lifetime> {
33 type Item = char;
34 fn next(&mut self) -> Option<Self::Item> {
35 //if the we still have a pending character return it
36 if let Some(c) = self.next_char.take() {
37 return Some(c);
38 }
39 if self.data.len() == 0 {
40 return None;
41 }
42
43 let next_byte = &self.data[0];
44 self.data = &self.data[1..];
45
46 let high = byte_to_hex_char((next_byte & 0xF0) >> 4);
47 let low = byte_to_hex_char(next_byte & 0x0F);
48 self.next_char = Some(low);
49 Some(high)
50 }
51}
52
53struct DecodeHexIterSlice<'data_lifetime> {
54 //ascii encoded hex characters
55 //if any of the bytes is not valid ascii hex the iterator will return None
56 data: &'data_lifetime [u8],
57}
58
59impl<'data_lifetime> DecodeHexIterSlice<'data_lifetime> {
60 fn new(data: &'data_lifetime [u8]) -> Self {
61 DecodeHexIterSlice { data }
62 }
63}
64
65impl<'data_lifetime> Iterator for DecodeHexIterSlice<'data_lifetime> {
66 type Item = u8;
67 fn next(&mut self) -> Option<Self::Item> {
68 if self.data.len() < 2 {
69 return None;
70 }
71 let v1_opt = hex_char_byte_to_value(self.data[0]);
72 let v2_opt = hex_char_byte_to_value(self.data[1]);
73 if v1_opt.is_err() || v2_opt.is_err() {
74 self.data = &[];
75 return None;
76 }
77 self.data = &self.data[2..];
78 let v1 = v1_opt.unwrap();
79 let v2 = v2_opt.unwrap();
80 Some(v1 * 16 + v2)
81 }
82}
83
84fn hex_char_byte_to_value(c: u8) -> Result<u8, HexDecodeError> {
8 if !c.is_ascii_hexdigit() { 85 if !c.is_ascii_hexdigit() {
9 return Err(HexDecodeError::InvalidHexCharacter); 86 return Err(HexDecodeError::InvalidHexCharacter);
10 } 87 }
11 Ok( (c as char).to_digit(16).unwrap() as u8) 88 Ok((c as char).to_digit(16).unwrap() as u8)
12} 89}
13 90
14fn byte_to_hex_char(b : u8) -> char { 91fn byte_to_hex_char(b: u8) -> char {
15 assert!(b <= 15); 92 assert!(b <= 15);
16 match b { 93 match b {
17 digit if digit < 10 => ('0' as u8 + digit) as char, 94 digit if digit < 10 => ('0' as u8 + digit) as char,
18 letter => ('a' as u8 + letter - 10) as char 95 letter => ('a' as u8 + letter - 10) as char,
19 } 96 }
20} 97}
21 98
22fn append_byte_hex_to_string(byte : u8, string : &mut String) { 99fn append_byte_hex_to_string(byte: u8, string: &mut String) {
23 let high = (byte & 0xF0) >> 4; 100 let high = (byte & 0xF0) >> 4;
24 let low = byte & 0x0F; 101 let low = byte & 0x0F;
25 string.push(byte_to_hex_char(high)); 102 string.push(byte_to_hex_char(high));
26 string.push(byte_to_hex_char(low)); 103 string.push(byte_to_hex_char(low));
27} 104}
28 105
29pub fn decode_hex<T : AsRef<[u8]>>(string : T) -> Result<Vec<u8>, HexDecodeError> { 106///Returns an iterator that decodes the hex characters into bytes
107///if any error occures it returns None so no error code is reported
108///
109///```
110///let hex_string = "12ffbc";
111///for byte in rhex::decode_hex_iter(&hex_string) {
112/// //do something
113///}
114///```
115pub fn decode_hex_iter<'a, T>(string: &'a T) -> impl Iterator<Item = u8> + 'a
116where
117 T: AsRef<[u8]> + ?Sized
118{
119 DecodeHexIterSlice::new(string.as_ref())
120}
121
122///Returns an iterator of char's that are the hexadecimal representation of the data.
123///The chars returned by the iterar are all lower case.
124///
125///```
126///let data = &[0x11, 0xbc, 0x22];
127///for c in rhex::encode_hex_iter(&data) {
128/// //do something with c
129///}
130///```
131pub fn encode_hex_iter<'a, T>(data : &'a T) -> impl Iterator<Item = char> + 'a
132where T: AsRef<[u8]> + ?Sized
133{
134 EncodeHexIterSlice::new(data.as_ref())
135}
136
137///Returns a Vec containing all the decoded hex data.
138///
139///```
140///let hex_string = "ffaa11";
141///let data = rhex::decode_hex(&hex_string).unwrap();
142///```
143pub fn decode_hex<T: AsRef<[u8]>>(string: T) -> Result<Vec<u8>, HexDecodeError> {
30 let chars = string.as_ref(); 144 let chars = string.as_ref();
31 if chars.len() % 2 != 0 { 145 if chars.len() % 2 != 0 {
32 return Err(HexDecodeError::InvalidByteCount); 146 return Err(HexDecodeError::InvalidByteCount);
33 } 147 }
34 let mut data = Vec::new(); 148 let mut data = Vec::new();
35 let mut index = 0; 149 let mut index = 0;
36 let mut first_digit : u8 = 0; 150 let mut first_digit: u8 = 0;
37 for c in chars.iter() { 151 for c in chars.iter() {
38 if index % 2 != 0 { 152 if index % 2 != 0 {
39 let second_digit = hex_char_byte_to_value(*c)?; 153 let second_digit = hex_char_byte_to_value(*c)?;
40 let value = first_digit * 16 + second_digit; 154 let value = first_digit * 16 + second_digit;
41 data.push(value); 155 data.push(value);
42 }else { 156 } else {
43 first_digit = hex_char_byte_to_value(*c)?; 157 first_digit = hex_char_byte_to_value(*c)?;
44 } 158 }
45 index += 1; 159 index += 1;
@@ -47,7 +161,14 @@ pub fn decode_hex<T : AsRef<[u8]>>(string : T) -> Result<Vec<u8>, HexDecodeError
47 Ok(data) 161 Ok(data)
48} 162}
49 163
50pub fn encode_hex<T : AsRef<[u8]>>(data : T) -> String { 164///Returns a new string contaning the hexadecimal representation of the data.
165///
166///```
167///let data = &[0x11, 0x12, 0x13];
168///let string = rhex::encode_hex(&data);
169///assert_eq!(string, "111213");
170///```
171pub fn encode_hex<T: AsRef<[u8]>>(data: T) -> String {
51 let mut string = String::new(); 172 let mut string = String::new();
52 let data_ref = data.as_ref(); 173 let data_ref = data.as_ref();
53 for b in data_ref.iter() { 174 for b in data_ref.iter() {
@@ -63,14 +184,14 @@ mod tests {
63 #[test] 184 #[test]
64 fn decode_zero_bytes_test() { 185 fn decode_zero_bytes_test() {
65 let string = ""; 186 let string = "";
66 let data = decode_hex(string).unwrap(); 187 let data = decode_hex(&string).unwrap();
67 assert_eq!(0, data.len()); 188 assert_eq!(0, data.len());
68 } 189 }
69 190
70 #[test] 191 #[test]
71 fn decode_one_byte_test() { 192 fn decode_one_byte_test() {
72 let string = "ff"; 193 let string = "ff";
73 let data = decode_hex(string).unwrap(); 194 let data = decode_hex(&string).unwrap();
74 assert_eq!(1, data.len()); 195 assert_eq!(1, data.len());
75 assert_eq!(0xff, data[0]); 196 assert_eq!(0xff, data[0]);
76 } 197 }
@@ -78,7 +199,7 @@ mod tests {
78 #[test] 199 #[test]
79 fn decode_multiple_bytes_test() { 200 fn decode_multiple_bytes_test() {
80 let string = "ffaabbccdd1122"; 201 let string = "ffaabbccdd1122";
81 let data = decode_hex(string).unwrap(); 202 let data = decode_hex(&string).unwrap();
82 assert_eq!(7, data.len()); 203 assert_eq!(7, data.len());
83 assert_eq!(&[0xff, 0xaa, 0xbb, 0xcc, 0xdd, 0x11, 0x22], data.as_slice()); 204 assert_eq!(&[0xff, 0xaa, 0xbb, 0xcc, 0xdd, 0x11, 0x22], data.as_slice());
84 } 205 }
@@ -86,7 +207,7 @@ mod tests {
86 #[test] 207 #[test]
87 fn decode_invalid_character_test() { 208 fn decode_invalid_character_test() {
88 let string = "ffaabz"; 209 let string = "ffaabz";
89 match decode_hex(string) { 210 match decode_hex(&string) {
90 Err(HexDecodeError::InvalidHexCharacter) => {} 211 Err(HexDecodeError::InvalidHexCharacter) => {}
91 _ => panic!("Invalid result returned"), 212 _ => panic!("Invalid result returned"),
92 } 213 }
@@ -95,7 +216,7 @@ mod tests {
95 #[test] 216 #[test]
96 fn decode_invalid_character_length() { 217 fn decode_invalid_character_length() {
97 let string = "ffaab"; 218 let string = "ffaab";
98 match decode_hex(string) { 219 match decode_hex(&string) {
99 Err(HexDecodeError::InvalidByteCount) => {} 220 Err(HexDecodeError::InvalidByteCount) => {}
100 _ => panic!("Invalid result returned"), 221 _ => panic!("Invalid result returned"),
101 } 222 }
@@ -121,4 +242,26 @@ mod tests {
121 let string = encode_hex(&data); 242 let string = encode_hex(&data);
122 assert_eq!(string, "aabbccddee"); 243 assert_eq!(string, "aabbccddee");
123 } 244 }
245
246 #[test]
247 fn owned_string_decode() {
248 //this test just needs to compile
249 let string = String::from("aabbccddee");
250 let _ = decode_hex(&string);
251 let _ = decode_hex(string);
252 }
253
254 #[test]
255 fn iter_decode_test() {
256 let string = "aabbcc";
257 let data: Vec<u8> = decode_hex_iter(&string).collect();
258 assert_eq!(&[0xaa, 0xbb, 0xcc], data.as_slice());
259 }
260
261 #[test]
262 fn iter_encode_test() {
263 let data = &[0xff, 0xaa, 0x12, 0x45];
264 let string : String = encode_hex_iter(&data).collect();
265 assert_eq!(string, "ffaa1245");
266 }
124} 267}