pub fn debug_format_array(array: &[String]) -> String {
let number_of_values: usize = array.len();
if number_of_values == 0 {
return String::from("[]");
}
let string_value: &String = &array[0];
let mut use_short_hand: bool = true;
for array_value in array.iter() {
if string_value != array_value {
use_short_hand = false;
break;
}
}
if use_short_hand {
return format!("[{}; {}]", string_value, number_of_values);
}
if number_of_values > 16 {
let mut string_parts: Vec<String> = Vec::new();
let last_value_index: usize = number_of_values - 16;
for value_index in (0..last_value_index).step_by(16) {
string_parts.push(array[value_index..value_index + 16].join(", "));
}
string_parts.push(array[last_value_index..].join(", "));
return format!("[\n {}\n ]", string_parts.join(",\n "));
}
format!("[{}]", array.join(", "))
}
pub fn format_as_hexdump(data: &[u8], group: bool) -> String {
let mut ascii_values: [char; 16] = ['.'; 16];
let mut character_index: usize = 0;
let mut data_offset: usize = 0;
let data_size: usize = data.len();
let groups_data_size: usize = (data_size / 16) * 16;
let mut group_data_offset: usize = 0;
let mut string_parts: Vec<String> = Vec::new();
while data_offset < groups_data_size {
if character_index == 0 {
if group
&& group_data_offset != data_offset
&& data[group_data_offset..group_data_offset + 16]
== data[data_offset..data_offset + 16]
&& data_offset + 16 < groups_data_size
{
if group_data_offset + 16 == data_offset {
string_parts.push(String::from("...\n"))
}
data_offset += 16;
continue;
}
group_data_offset = data_offset;
string_parts.push(format!("{:08x} ", data_offset));
}
let byte_value: u8 = data[data_offset];
ascii_values[character_index] = match byte_value {
0x20..0x7f => byte_value as char,
_ => '.',
};
string_parts.push(format!("{:02x} ", byte_value));
if character_index == 7 {
string_parts.push(String::from(" "));
}
if character_index == 15 {
character_index += 1;
string_parts.push(String::from(" "));
for ascii_value in ascii_values.iter().take(character_index) {
string_parts.push(format!("{}", ascii_value));
}
string_parts.push(String::from("\n"));
character_index = 0;
} else {
character_index += 1;
}
data_offset += 1;
}
while data_offset < data_size {
character_index = data_offset % 16;
if character_index == 0 {
string_parts.push(format!("{:08x} ", data_offset));
}
let byte_value: u8 = data[data_offset];
ascii_values[character_index] = match byte_value {
0x20..0x7f => byte_value as char,
_ => '.',
};
string_parts.push(format!("{:02x} ", data[data_offset]));
if character_index == 7 {
string_parts.push(String::from(" "));
}
data_offset += 1;
}
if data_size > 0 && character_index > 0 {
character_index += 1;
for index in character_index..16 {
if index == 7 {
string_parts.push(String::from(" "));
}
string_parts.push(String::from(" "));
}
string_parts.push(String::from(" "));
for ascii_value in ascii_values.iter().take(character_index) {
string_parts.push(format!("{}", ascii_value));
}
string_parts.push(String::from("\n"));
}
string_parts.push(String::from("\n"));
string_parts.join("")
}
pub fn format_as_string(data: &[u8]) -> String {
data.iter()
.map(|byte_value| format!("{:02x}", byte_value))
.collect::<Vec<String>>()
.join("")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_debug_format_array() {
let test_data: Vec<String> = ["0"; 16]
.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>();
let string: String = debug_format_array(&test_data);
assert_eq!(string, "[0; 16]");
let test_data: Vec<String> = [
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15",
]
.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>();
let string: String = debug_format_array(&test_data);
assert_eq!(
string,
"[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]"
);
}
#[test]
fn test_debug_format_array_with_0bytes() {
let test_data: Vec<String> = Vec::new();
let string: String = debug_format_array(&test_data);
assert_eq!(string, "[]");
}
#[test]
fn test_debug_format_array_with_3bytes() {
let test_data: Vec<String> = ["1"; 3].iter().map(|value| value.to_string()).collect();
let string: String = debug_format_array(&test_data);
assert_eq!(string, "[1; 3]");
}
#[test]
fn test_debug_format_array_with_32bytes() {
let test_data: Vec<String> = (0..32).map(|value| value.to_string()).collect();
let first_row: String = (0..16)
.map(|value| value.to_string())
.collect::<Vec<String>>()
.join(", ");
let last_row: String = (16..32)
.map(|value| value.to_string())
.collect::<Vec<String>>()
.join(", ");
let string: String = debug_format_array(&test_data);
assert_eq!(
string,
format!("[\n {},\n {}\n ]", first_row, last_row)
);
}
#[test]
fn test_format_as_hexdump_0bytes() {
let test_data: [u8; 0] = [];
let expected_string = ["", ""].join("\n");
let string: String = format_as_hexdump(&test_data, false);
assert_eq!(string, expected_string);
}
#[test]
fn test_format_as_hexdump_3bytes() {
let test_data: [u8; 3] = [0x61, 0x62, 0x63];
let expected_string = [
"00000000 61 62 63 abc",
"",
"",
]
.join("\n");
let string: String = format_as_hexdump(&test_data, false);
assert_eq!(string, expected_string);
}
#[test]
fn test_format_as_hexdump_9bytes() {
let test_data: [u8; 9] = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let expected_string = [
"00000000 00 01 02 03 04 05 06 07 08 .........",
"",
"",
]
.join("\n");
let string: String = format_as_hexdump(&test_data, false);
assert_eq!(string, expected_string);
}
#[test]
fn test_format_as_hexdump_16bytes() {
let test_data: [u8; 16] = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f,
];
let expected_string = [
"00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................",
"",
"",
]
.join("\n");
let string: String = format_as_hexdump(&test_data, false);
assert_eq!(string, expected_string);
}
#[test]
fn test_format_as_hexdump_with_group() {
let test_data: [u8; 428] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let expected_string = [
"00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................",
"...",
"00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................",
"000001a0 00 00 00 00 00 00 00 00 00 00 00 00 ............",
"",
"",
]
.join("\n");
let string: String = format_as_hexdump(&test_data, true);
assert_eq!(string, expected_string);
}
#[test]
fn test_format_as_hexdump_with_group_16byte_aligned() {
let test_data: [u8; 512] = [
0x63, 0x6f, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x28, 0x8c, 0x38, 0x27,
0x71, 0x65, 0x6d, 0x75, 0x00, 0x05, 0x00, 0x03, 0x57, 0x69, 0x32, 0x6b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x48, 0x00,
0x00, 0x79, 0x04, 0x11, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xef, 0xc4, 0xb6, 0x1f,
0x53, 0xca, 0xa7, 0x86, 0x45, 0x28, 0x90, 0xe2, 0x55, 0xba, 0x79, 0x1a, 0x1c, 0x4c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let expected_string = [
"00000000 63 6f 6e 65 63 74 69 78 00 00 00 02 00 01 00 00 conectix........",
"00000010 00 00 00 00 00 00 02 00 28 8c 38 27 71 65 6d 75 ........(.8'qemu",
"00000020 00 05 00 03 57 69 32 6b 00 00 00 00 00 40 48 00 ....Wi2k.....@H.",
"00000030 00 00 00 00 00 40 48 00 00 79 04 11 00 00 00 03 .....@H..y......",
"00000040 ff ff ef c4 b6 1f 53 ca a7 86 45 28 90 e2 55 ba ......S...E(..U.",
"00000050 79 1a 1c 4c 00 00 00 00 00 00 00 00 00 00 00 00 y..L............",
"00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................",
"...",
"000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................",
"",
"",
]
.join("\n");
let string: String = format_as_hexdump(&test_data, true);
assert_eq!(string, expected_string);
}
#[test]
fn test_format_as_string() {
let test_data: [u8; 16] = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f,
];
let string: String = format_as_string(&test_data);
assert_eq!(string, "000102030405060708090a0b0c0d0e0f");
}
}