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