1 use crate::modules::base::Hex;
2 use crate::modules::{base, Command, Module};
3 use clap::{Arg, ArgMatches, SubCommand};
4 use regex::Regex;
5 use std::io;
6 use std::io::Write;
7
module<'a, 'b>() -> Module<'a, 'b>8 pub fn module<'a, 'b>() -> Module<'a, 'b> {
9 Module {
10 desc: "Hex / UTF-8 string / binary / byte array conversion".to_string(),
11 commands: commands(),
12 get_cases: cases::cases,
13 }
14 }
15
commands<'a, 'b>() -> Vec<Command<'a, 'b>>16 pub fn commands<'a, 'b>() -> Vec<Command<'a, 'b>> {
17 vec![
18 Command {
19 app: SubCommand::with_name("h2s")
20 .about("Convert hex to UTF-8 string")
21 .arg(Arg::with_name("INPUT").required(false).index(1)),
22 f: h2s,
23 },
24 Command {
25 app: SubCommand::with_name("s2h")
26 .about("Convert UTF-8 string to hex")
27 .arg(Arg::with_name("INPUT").required(false).index(1)),
28 f: s2h,
29 },
30 Command {
31 app: SubCommand::with_name("h2b")
32 .about("Convert hex to binary")
33 .arg(Arg::with_name("INPUT").required(false).index(1)),
34 f: h2b,
35 },
36 Command {
37 app: SubCommand::with_name("b2h")
38 .about("Convert binary to hex")
39 .arg(Arg::with_name("INPUT").required(false).index(1)),
40 f: b2h,
41 },
42 Command {
43 app: SubCommand::with_name("h2a")
44 .about("Convert hex to byte array")
45 .arg(Arg::with_name("INPUT").required(false).index(1)),
46 f: h2a,
47 },
48 Command {
49 app: SubCommand::with_name("a2h")
50 .about("Convert byte array to hex")
51 .arg(Arg::with_name("INPUT").required(false).index(1)),
52 f: a2h,
53 },
54 ]
55 }
56
h2s(matches: &ArgMatches) -> Result<Vec<String>, String>57 fn h2s(matches: &ArgMatches) -> Result<Vec<String>, String> {
58 let input = base::input_string(matches)?;
59 let input: Vec<u8> = input.parse::<Hex>().map_err(|_| "Convert failed")?.into();
60
61 let result = String::from_utf8(input).map_err(|_| "Not UTF-8")?;
62
63 Ok(vec![result])
64 }
65
s2h(matches: &ArgMatches) -> Result<Vec<String>, String>66 fn s2h(matches: &ArgMatches) -> Result<Vec<String>, String> {
67 let input = base::input_string(matches).map_err(|_| "Not UTF-8")?;
68
69 let input = input.as_bytes().to_vec();
70 let result: String = Hex::from(input).into();
71
72 Ok(vec![result])
73 }
74
h2b_inner(matches: &ArgMatches) -> Result<Vec<u8>, String>75 fn h2b_inner(matches: &ArgMatches) -> Result<Vec<u8>, String> {
76 let input = base::input_string(matches)?;
77 let result: Vec<u8> = input.parse::<Hex>().map_err(|_| "Convert failed")?.into();
78
79 Ok(result)
80 }
81
h2b(matches: &ArgMatches) -> Result<Vec<String>, String>82 fn h2b(matches: &ArgMatches) -> Result<Vec<String>, String> {
83 let result = h2b_inner(matches)?;
84
85 io::stdout()
86 .write_all(&result)
87 .map_err(|_| "Convert failed")?;
88
89 Ok(vec![])
90 }
91
b2h(matches: &ArgMatches) -> Result<Vec<String>, String>92 fn b2h(matches: &ArgMatches) -> Result<Vec<String>, String> {
93 let input = base::input_bytes(matches)?;
94
95 let result: String = Hex::from(input).into();
96
97 Ok(vec![result])
98 }
99
h2a(matches: &ArgMatches) -> Result<Vec<String>, String>100 fn h2a(matches: &ArgMatches) -> Result<Vec<String>, String> {
101 let input = base::input_string(matches)?;
102 let input: Vec<u8> = input.parse::<Hex>().map_err(|_| "Convert failed")?.into();
103
104 let result = input
105 .into_iter()
106 .map(|x| format!("{}", x))
107 .collect::<Vec<String>>()
108 .join(", ");
109 let result = format!("[{}]", result);
110
111 Ok(vec![result])
112 }
113
a2h(matches: &ArgMatches) -> Result<Vec<String>, String>114 fn a2h(matches: &ArgMatches) -> Result<Vec<String>, String> {
115 let input = base::input_string(matches).map_err(|_| "Not UTF-8")?;
116
117 let input = input.trim_start_matches('[').trim_end_matches(']');
118 let input = Regex::new(", *")
119 .expect("qed")
120 .split(input)
121 .collect::<Vec<_>>();
122 let input = input
123 .into_iter()
124 .map(|x| x.parse::<u8>())
125 .collect::<Result<Vec<_>, _>>()
126 .map_err(|_| "Invalid byte array")?;
127
128 let result: String = Hex::from(input).into();
129 Ok(vec![result])
130 }
131
132 mod cases {
133 use crate::modules::Case;
134 use linked_hash_map::LinkedHashMap;
135
cases() -> LinkedHashMap<&'static str, Vec<Case>>136 pub fn cases() -> LinkedHashMap<&'static str, Vec<Case>> {
137 vec![
138 (
139 "h2s",
140 vec![Case {
141 desc: "".to_string(),
142 input: vec!["0x61626364"].into_iter().map(Into::into).collect(),
143 output: vec!["abcd"].into_iter().map(Into::into).collect(),
144 is_example: true,
145 is_test: true,
146 since: "0.1.0".to_string(),
147 }],
148 ),
149 (
150 "s2h",
151 vec![Case {
152 desc: "".to_string(),
153 input: vec!["abcd"].into_iter().map(Into::into).collect(),
154 output: vec!["0x61626364"].into_iter().map(Into::into).collect(),
155 is_example: true,
156 is_test: true,
157 since: "0.1.0".to_string(),
158 }],
159 ),
160 (
161 "h2b",
162 vec![Case {
163 desc: "".to_string(),
164 input: vec!["0x61626364"].into_iter().map(Into::into).collect(),
165 output: vec!["abcd"].into_iter().map(Into::into).collect(),
166 is_example: true,
167 is_test: false,
168 since: "0.1.0".to_string(),
169 }],
170 ),
171 (
172 "b2h",
173 vec![Case {
174 desc: "".to_string(),
175 input: vec!["abcd"].into_iter().map(Into::into).collect(),
176 output: vec!["0x61626364"].into_iter().map(Into::into).collect(),
177 is_example: true,
178 is_test: true,
179 since: "0.1.0".to_string(),
180 }],
181 ),
182 (
183 "h2a",
184 vec![Case {
185 desc: "".to_string(),
186 input: vec!["0x61626364"].into_iter().map(Into::into).collect(),
187 output: vec!["[97, 98, 99, 100]"]
188 .into_iter()
189 .map(Into::into)
190 .collect(),
191 is_example: true,
192 is_test: true,
193 since: "0.7.0".to_string(),
194 }],
195 ),
196 (
197 "a2h",
198 vec![Case {
199 desc: "".to_string(),
200 input: vec!["'[97, 98, 99, 100]'"]
201 .into_iter()
202 .map(Into::into)
203 .collect(),
204 output: vec!["0x61626364"].into_iter().map(Into::into).collect(),
205 is_example: true,
206 is_test: true,
207 since: "0.7.0".to_string(),
208 }],
209 ),
210 ]
211 .into_iter()
212 .collect()
213 }
214 }
215
216 #[cfg(test)]
217 mod tests {
218 use super::*;
219 use crate::modules::base::test::test_module;
220
221 #[test]
test_cases()222 fn test_cases() {
223 test_module(module());
224 }
225
226 #[test]
test_h2b()227 fn test_h2b() {
228 let app = &commands()[1].app;
229
230 let matches = app.clone().get_matches_from(vec!["h2b", "0x61626364"]);
231 assert_eq!(h2b_inner(&matches), Ok(vec![0x61, 0x62, 0x63, 0x64]));
232 }
233 }
234