buup/transformers/
hex_to_ascii.rs1use crate::{Transform, TransformError, TransformerCategory};
2
3#[derive(Debug, Clone, PartialEq, Eq, Default)]
13pub struct HexToAscii;
14
15impl Transform for HexToAscii {
16 fn name(&self) -> &'static str {
17 "Hex to ASCII"
18 }
19
20 fn id(&self) -> &'static str {
21 "hex_to_ascii"
22 }
23
24 fn description(&self) -> &'static str {
25 "Decodes a hexadecimal string into its ASCII representation."
26 }
27
28 fn category(&self) -> TransformerCategory {
29 TransformerCategory::Decoder
30 }
31
32 fn default_test_input(&self) -> &'static str {
33 "48656c6c6f"
34 }
35
36 fn transform(&self, input: &str) -> Result<String, TransformError> {
37 if !input.len().is_multiple_of(2) {
39 return Err(TransformError::InvalidArgument(
40 "Input hex string must have an even number of characters".into(),
41 ));
42 }
43
44 let cleaned_input = input.trim().trim_start_matches("0x");
46
47 let mut bytes = Vec::with_capacity(cleaned_input.len() / 2);
48 let mut chars = cleaned_input.chars();
49
50 while let (Some(h), Some(l)) = (chars.next(), chars.next()) {
51 let hex_pair = format!("{}{}", h, l);
52 match u8::from_str_radix(&hex_pair, 16) {
53 Ok(byte) => bytes.push(byte),
54 Err(_) => {
55 return Err(TransformError::InvalidArgument(
56 format!("Invalid hex character sequence found: '{}'", hex_pair).into(),
57 ))
58 }
59 }
60 }
61
62 String::from_utf8(bytes).map_err(|_| TransformError::Utf8Error)
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn test_hex_to_ascii() {
72 let transformer = HexToAscii;
73 assert_eq!(
74 transformer
75 .transform(transformer.default_test_input())
76 .unwrap(),
77 "Hello"
78 );
79 assert_eq!(
80 transformer.transform("68656c6c6f20776f726c64").unwrap(),
81 "hello world"
82 );
83 assert_eq!(transformer.transform("").unwrap(), "");
84 assert_eq!(transformer.transform("313233").unwrap(), "123");
85 }
86
87 #[test]
88 fn test_invalid_hex() {
89 let transformer = HexToAscii;
90 assert!(matches!(
92 transformer.transform("48656c6c6G"),
93 Err(TransformError::InvalidArgument(_))
94 ));
95 assert!(matches!(
97 transformer.transform("48656c6c6"),
98 Err(TransformError::InvalidArgument(_))
99 ));
100 }
101
102 #[test]
103 fn test_non_utf8_output() {
104 let transformer = HexToAscii;
105 assert!(matches!(
107 transformer.transform("80"),
108 Err(TransformError::Utf8Error)
109 ));
110 assert!(matches!(
111 transformer.transform("c0"),
112 Err(TransformError::Utf8Error)
113 )); }
115
116 #[test]
117 fn test_properties() {
118 let transformer = HexToAscii;
119 assert_eq!(transformer.name(), "Hex to ASCII");
120 assert_eq!(transformer.id(), "hex_to_ascii");
121 assert_eq!(
122 transformer.description(),
123 "Decodes a hexadecimal string into its ASCII representation."
124 );
125 assert_eq!(transformer.category(), TransformerCategory::Decoder);
126 }
127}