hex_utilities/
lib.rs

1use std::io::Read;
2use std::{fmt::Write, num::ParseIntError};
3
4use binary_utils::{convert_to_binary_string, get_binary_string_for_byte_array};
5
6// Should work like this: http://www.unit-conversion.info/texttools/hexadecimal/
7pub struct Error;
8
9pub fn convert_decimal_to_32_byte_hex(num: u32) -> String {
10    format!("{:08x}", num)
11}
12pub fn convert_decimal_to_8_byte_hex(num: u8) -> String {
13    format!("{:02x}", num)
14}
15pub fn convert_hex_to_decimal(hex: &str) -> Result<i64, ParseIntError> {
16    let z = i64::from_str_radix(hex, 16);
17    z
18}
19
20pub fn get_text_for_hex(hex: &String) -> Result<String, Error> {
21    let maybe_hex_utf8 = convert_hex_utf8(&hex);
22    match maybe_hex_utf8 {
23        Ok(hex_utf8) => Ok(hex_utf8),
24        Err(_error) => {
25            let maybe_hex_ascii = convert_hex_to_ascii(&hex);
26            match maybe_hex_ascii {
27                Ok(hex_ascii) => Ok(hex_ascii),
28                Err(_error) => Err(Error),
29            }
30        }
31    }
32}
33
34pub fn convert_hex_utf8(hex: &String) -> Result<String, Error> {
35    let maybe_decoded_hex = decode_hex(&hex.to_string());
36    match maybe_decoded_hex {
37        Ok(decoded_hex) => {
38            let maybe_utf_str = std::str::from_utf8(&decoded_hex);
39            match maybe_utf_str {
40                Ok(utf_str) => Ok(utf_str.to_string()),
41                Err(_error) => Err(Error),
42            }
43        }
44        Err(_error) => Err(Error),
45    }
46}
47
48pub fn convert_hex_to_ascii(hex: &String) -> Result<String, Error> {
49    enum Error {
50        Int(ParseIntError),
51        Unicode(u32),
52    }
53    fn hex_to_char(s: &str) -> Result<char, Error> {
54        // u8::from_str_radix(s, 16).map(|n| n as char)
55        // u8::from_str_radix(s, 16).map(|n| n as char)
56        let unicode = u32::from_str_radix(s, 16).map_err(Error::Int)?;
57        char::from_u32(unicode).ok_or_else(|| Error::Unicode(unicode))
58    }
59
60    let maybe_decoded_hex = decode_hex(&hex.to_string());
61    match maybe_decoded_hex {
62        Ok(decoded_hex) => {
63            let mut new_string: String = String::new();
64            for maybe_byte in decoded_hex.bytes() {
65                match maybe_byte {
66                    Ok(byte) => {
67                        let hex = format!("{:02X}", byte);
68                        let maybe_char = hex_to_char(&hex);
69                        match maybe_char {
70                            Ok(char) => {
71                                new_string.push(char);
72                            }
73                            Err(_) => return Err(Error),
74                        }
75                    }
76                    Err(_) => return Err(Error),
77                }
78            }
79            Ok(new_string)
80        }
81        Err(_error) => Err(Error),
82    }
83}
84
85pub fn decode_hex(s: &str) -> Result<Vec<u8>, ParseIntError> {
86    let len = s.len();
87    let is_len_odd = len % 2 == 1;
88    let s_twos_complement = if is_len_odd {
89        format!("0{}", s)
90    } else {
91        s.to_string()
92    };
93    (0..s_twos_complement.len())
94        .step_by(2)
95        .map(|i| u8::from_str_radix(&s_twos_complement[i..i + 2], 16))
96        .collect()
97}
98
99pub fn encode_hex(bytes: &[u8]) -> String {
100    let mut s = String::with_capacity(bytes.len() * 2);
101    for &b in bytes {
102        // We want to print the leading zero in each byte array item, so we need 02x formatting
103        // here. So "0d" won't be printed as "d"
104        write!(&mut s, "{:02x}", b).unwrap();
105    }
106    s
107}
108
109pub fn convert_big_endian_hex_to_little_endian(hex: &String) -> String {
110    let decoded_hex = decode_hex(&hex).unwrap();
111    let reversed_decoded_hex: Vec<u8> = decoded_hex.into_iter().rev().collect();
112    let reversed_encoded_hex = encode_hex(&reversed_decoded_hex);
113    reversed_encoded_hex
114}
115
116pub fn convert_decimal_to_hexadecimal(
117    decimal_num: u64,
118    include_prefix: bool,
119    bytes: Option<u8>,
120) -> String {
121    let hex_string_without_prefix = match bytes {
122        // two characters per byte
123        Some(bytes) => match bytes {
124            1 => format!("{:02x}", decimal_num),
125            2 => format!("{:04x}", decimal_num),
126            3 => format!("{:06x}", decimal_num),
127            4 => format!("{:08x}", decimal_num),
128            5 => format!("{:010x}", decimal_num),
129            6 => format!("{:012x}", decimal_num),
130            7 => format!("{:014x}", decimal_num),
131            8 => format!("{:016x}", decimal_num),
132            _ => panic!("bytes for hex not supported: {}", bytes),
133        },
134        None => format!("{:x}", decimal_num),
135    };
136    if include_prefix {
137        format!("0x{hex_string_without_prefix}")
138    } else {
139        hex_string_without_prefix
140    }
141}
142pub fn binary_to_hex(b: &str) -> Option<&str> {
143    match b {
144        "0000" => Some("0"),
145        "0001" => Some("1"),
146        "0010" => Some("2"),
147        "0011" => Some("3"),
148        "0100" => Some("4"),
149        "0101" => Some("5"),
150        "0110" => Some("6"),
151        "0111" => Some("7"),
152        "1000" => Some("8"),
153        "1001" => Some("9"),
154        "1010" => Some("A"),
155        "1011" => Some("B"),
156        "1100" => Some("C"),
157        "1101" => Some("D"),
158        "1110" => Some("E"),
159        "1111" => Some("F"),
160        _ => None,
161    }
162}
163pub fn convert_string_to_hex(s: &String) -> String {
164    let wif_bytes = s.as_bytes();
165    let binary = get_binary_string_for_byte_array(&wif_bytes.to_vec());
166
167    let mut s = String::new();
168    let mut b = String::new();
169    for byte in wif_bytes {
170        let binary_string = convert_to_binary_string(*byte, 8);
171
172        let first_4_binary = &binary_string[0..=3];
173        let first_4_hex = binary_to_hex(first_4_binary).unwrap();
174        let last_4_binary = &binary_string[4..=7];
175        let last_4_hex = binary_to_hex(last_4_binary).unwrap();
176        let to_p = format!("{}{}", first_4_hex, last_4_hex);
177
178        s.push_str(&to_p);
179    }
180    s
181}
182
183pub fn get_hex_string_from_byte_array(byte_array: &[u8]) -> String {
184    // Use that array to then create a length 32 array but with hexidecimal values, since we want
185    // each item of the array to represent only 4 bits, which is how many bits a hex represents
186    let array_with_base_16_numbers: Vec<u8> = byte_array.iter().map(|num| num % 16).collect();
187    // turn hex byte array into hex string
188    let hex_string = array_with_base_16_numbers
189        .iter()
190        .map(|byte| format!("{:x}", byte))
191        .collect::<String>();
192    hex_string
193}
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198
199    // TODO: write tests
200    #[test]
201    fn it_works() {
202        // test: http://www.unit-conversion.info/texttools/hexadecimal/
203        let hex = "30784e6f6e63652077617320666f756e646564".to_string();
204        let expected_text = "0xNonce was founded".to_string();
205        let maybe_text = get_text_for_hex(&hex);
206        let text = match maybe_text {
207            Ok(text) => text.to_string(),
208            Err(_) => "wrong".to_string(),
209        };
210        assert_eq!(text, expected_text);
211    }
212    #[test]
213    fn decode_hex_test() {
214        let hex = "d473a59";
215        let decoded = decode_hex(hex);
216    }
217}