hextool/lib.rs
1//! This crate provides functions that allows you to easily convert strings from and to hex.
2//!
3//!
4//! ## Usage
5//!
6//! This crate is [on crates.io](https://crates.io/crates/hextool) and can be added to your project.
7//! ```toml
8//! [dependencies]
9//! hextool = { version = "version", default-features = false }
10//! ```
11//! ## Examples
12//!
13//! ### Example: converting string to hex
14//!
15//! To convert a string to hex, use the `Hex` and `Convert` trait:
16//!
17//! ```
18//! use hextool::{Hex, Convert};
19//!
20//! // Convert a string to hex
21//! let hex = Hex::convert("hello", false, false);
22//! println!("hello in hex: {}", hex); // #=> "hello in hex: 68656c6c6f"
23//!
24//! // You can also split the output in bytes
25//! let hex = Hex::convert("hello", false, true);
26//! println!("hello in hex: {}", hex); // #=> "hello in hex: 68 65 6c 6c 6f"
27//!
28//! // Convert a string with numeric flag. This will take the numerical value of the string.
29//! // If the string is not a number, it will return an error.
30//! let hex = Hex::convert("255", true, false);
31//! println!("255 in hex: {}", hex); // #=> "255 in hex: {ff}"
32//! ```
33//! ### Example: converting hex to string
34//!
35//! To convert a hex string to a string, use the `UnHex` and `Convert` trait:
36//!
37//! ```
38//! use hextool::{UnHex, Convert};
39//!
40//! // Convert a hex string to a string
41//! let unhex = UnHex::convert("68656c6c6f", false, false);
42//! println!("68656c6c6f in string: {}", unhex); // #=> "68656c6c6f in string: hello"
43//!
44//! // Convert a hex string to a string with numeric flag. This will take the numerical value of the string.
45//! let unhex = UnHex::convert("cafebabe", true, false);
46//! println!("cafebabe in string: {}", unhex); // #=> "cafebabe in string: 3405691582"
47//!
48//! // If numeric is set to false, only valid strings [0-9a-f] is accepted. If the string is not valid,
49//! // it will return the string with the invalid string highlighted to red.
50//! let unhex = UnHex::convert("aga", true, false);
51//! println!("{}", unhex); // #=> "The highlighted chars can't be converted:\nag\u{1b}[31ma\u{1b}[0m."
52//!```
53
54#![doc(html_root_url = "https://docs.rs/hextool/0.1.1")]
55#![deny(missing_docs)]
56
57use std::error::Error;
58use std::fmt::{Debug, Display, Formatter};
59use regex::Regex;
60
61/// Error type for hextool
62pub struct HexToolError {
63 /// Error message
64 pub(crate) message: String,
65}
66
67/// Implement Debug, Display and Error for HexToolError
68impl Debug for HexToolError {
69 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
70 write!(f, "{}", self.message)
71 }
72}
73
74/// Implement Debug, Display and Error for HexToolError
75impl Display for HexToolError {
76 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77 write!(f, "{}", self.message)
78 }
79}
80
81/// Implement Debug, Display and Error for HexToolError
82impl Error for HexToolError {}
83
84
85/// Convert trait
86pub trait Convert {
87 /// Convert input to hex or string depending on the implementation
88 ///
89 /// ## Arguments
90 /// * `input` - The input to convert
91 /// * `numeric` - If set to true, the input will be considered as a numeric value.
92 /// * `split` - If set to true, the output will be split in bytes
93 /// ## Returns
94 /// A string with the converted input
95 fn convert(input: &str, numeric: bool, split: bool) -> String;
96}
97
98/// Hex struct
99///
100/// This struct implements the Convert trait and can be used to convert a string to hex.
101///
102/// ## Example
103/// ```
104/// use hextool::{Hex, Convert};
105///
106/// // Convert a string to hex
107/// let hex = Hex::convert("hello", false, false);
108/// println!("hello in hex: {}", hex); // #=> "hello in hex: 68656c6c6f"
109/// ```
110pub struct Hex;
111
112impl Hex {
113 fn hex_string(input: &str) -> Result<String, HexToolError> {
114 return Ok(input.as_bytes().iter().map(|b| format!("{:02x}", b)).collect());
115 }
116
117 fn hex_numeric(input: &str) -> Result<String, HexToolError> {
118 let is_all_digit = input.chars().all(|c| c.is_digit(10));
119 if !is_all_digit {
120 return Err(HexToolError {
121 message: String::from("Input is not valid for 'hex' with numeric flag (-n).")
122 });
123 }
124 let to_str: i64 = input.parse().unwrap();
125 Ok(format!("{:02x}", to_str))
126 }
127}
128
129impl Convert for Hex {
130 fn convert(input: &str, numeric: bool, split_byte: bool) -> String {
131 let result;
132 if numeric {
133 result = Hex::hex_numeric(input);
134 } else {
135 result = Hex::hex_string(input);
136 }
137
138 match result {
139 Ok(str) => {
140 if split_byte {
141 let mut result = String::new();
142 for (i, c) in str.chars().enumerate() {
143 if i % 2 == 0 && i != 0 {
144 result.push_str(" ");
145 }
146 result.push(c);
147 }
148 format!("{}", result)
149 } else {
150 format!("{}", str)
151 }
152 }
153 Err(e) => e.to_string(),
154 }
155 }
156}
157
158/// UnHex struct
159///
160/// This struct implements the Convert trait and can be used to convert a hex string to a string.
161///
162/// ## Example
163/// ```
164/// use hextool::{UnHex, Convert};
165///
166/// // Convert a hex string to a string
167/// let unhex = UnHex::convert("68656c6c6f", false, false);
168/// println!("68656c6c6f in string: {}", unhex); // #=> "68656c6c6f in string: hello"
169/// ```
170pub struct UnHex;
171
172impl UnHex {
173 fn un_hex_numeric(input: &str) -> Result<String, HexToolError> {
174 let parsed = i64::from_str_radix(input, 16);
175 match parsed {
176 Ok(i) => Ok(format!("{}", i)),
177 Err(e) => Err(HexToolError {
178 message: format!("Input is not valid for 'unhex' with numeric flag (-n). {}", e)
179 })
180 }
181 }
182
183 fn un_hex_string(input: &str) -> Result<String, HexToolError> {
184 // Go through each hex byte and convert to a string
185 let mut result = String::new();
186 let mut i = 0;
187
188 while i < input.len() {
189 let byte = &input[i..i + 2];
190 let parsed = u8::from_str_radix(byte, 16);
191 match parsed {
192 Ok(i) => result.push(i as char),
193 Err(e) => return Err(HexToolError {
194 message: format!("Could not parse {}", e)
195 })
196 }
197 i += 2;
198 }
199 Ok(result)
200 }
201
202 fn validate_hex(input: &str) -> Result<String, HexToolError> {
203 let re = Regex::new("0[x|X]").unwrap();
204 let cleaned = re.replace_all(input, "");
205
206 let mut is_valid = true;
207 let mut proc_input = String::new();
208 for c in cleaned.chars() {
209 if !c.is_digit(16) {
210 if is_valid { is_valid = false };
211 proc_input.push_str(&format!("\x1b[31m{}\x1b[0m", c));
212 continue;
213 }
214 proc_input.push(c);
215 }
216 if !is_valid {
217 return Err(HexToolError {
218 message: format!("The highlighted chars can't be converted:\n{}", proc_input)
219 });
220 }
221
222 if proc_input.len() % 2 != 0 {
223 proc_input = format!("0{}", proc_input)
224 };
225 Ok(proc_input.to_string())
226 }
227}
228
229impl Convert for UnHex {
230 fn convert(input: &str, numeric: bool, split_byte: bool) -> String {
231 let valid_input;
232 match UnHex::validate_hex(input) {
233 Ok(str) => { valid_input = str; }
234 Err(e) => return e.to_string()
235 }
236
237 let result;
238 if numeric {
239 result = UnHex::un_hex_numeric(&valid_input);
240 } else {
241 result = UnHex::un_hex_string(&valid_input);
242 }
243
244 match result {
245 Ok(str) => {
246 if !split_byte { return format!("{}", str); }
247 return str.chars().map(|c| format!("{}", c))
248 .collect::<Vec<String>>().join(" ");
249 }
250 Err(e) => { e.to_string() }
251 }
252 }
253}