mail_parser/decoders/
hex.rs1use super::quoted_printable::HEX_MAP;
8
9#[derive(PartialEq, Debug)]
10enum HexState {
11 None,
12 Percent,
13 Hex1,
14}
15
16pub fn decode_hex(src: &[u8]) -> (bool, Vec<u8>) {
17 let mut state = HexState::None;
18 let mut hex1 = 0;
19 let mut result = Vec::with_capacity(src.len());
20 let mut success = true;
21
22 for ch in src {
23 match ch {
24 b'%' => {
25 if let HexState::None = state {
26 state = HexState::Percent
27 } else {
28 success = false;
29 break;
30 }
31 }
32 _ => match state {
33 HexState::None => {
34 result.push(*ch);
35 }
36 HexState::Percent => {
37 hex1 = HEX_MAP[*ch as usize];
38 if hex1 != -1 {
39 state = HexState::Hex1;
40 } else {
41 success = false;
42 break;
43 }
44 }
45 HexState::Hex1 => {
46 let hex2 = HEX_MAP[*ch as usize];
47
48 state = HexState::None;
49 if hex2 != -1 {
50 result.push(((hex1 as u8) << 4) | hex2 as u8);
51 } else {
52 success = false;
53 break;
54 }
55 }
56 },
57 }
58 }
59
60 (success, result)
61}
62
63#[cfg(test)]
64mod tests {
65 use crate::decoders::hex::decode_hex;
66
67 #[test]
68 fn decode_hex_line() {
69 let inputs = [
70 ("this%20is%20some%20text", "this is some text"),
71 ("this is some text", "this is some text"),
72 ];
73
74 for input in inputs {
75 let (success, result) = decode_hex(input.0.as_bytes());
76
77 assert!(success, "Failed for '{:?}'", input.0);
78
79 let result_str = std::str::from_utf8(&result).unwrap();
80
81 assert_eq!(
89 input.1,
90 result_str,
91 "Failed for '{}'",
92 input.0.escape_debug()
93 );
94 }
95 }
96}