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