1use std::io;
2
3pub struct HexTable {
4 columns: usize,
5 offset: usize,
6 header: bool,
7 ascii: bool,
8 zeros: bool,
9}
10
11impl Default for HexTable {
12 fn default() -> Self {
13 HexTable { columns: 16, offset: 0, header: false, ascii: true, zeros: true }
14 }
15}
16
17impl HexTable {
18 pub fn new(columns: usize, offset: usize, header: bool, ascii: bool, zeros: bool) -> HexTable {
19 HexTable { columns, offset, header, ascii, zeros }
20 }
21
22 pub fn format<Writer: io::Write>(&self, data: &[u8], out: &mut Writer) -> io::Result<()> {
23 let mut col_pos = 0;
24 let mut row_pos = 0;
25 let mut ascii_pos = 0;
26
27 let data_len = data.len();
28 let col_pad_len = Self::count_hex_digits(self.columns).max(2);
29 let columns_remaining = data_len % self.columns;
30
31 let columns_empty = if columns_remaining != 0 {
32 self.columns - columns_remaining
33 } else {
34 0
35 };
36
37 let offset_str_len = Self::count_hex_digits(
38 if columns_remaining != 0 {
39 self.offset + data.len() - columns_remaining
40 } else {
41 self.offset + data.len() - columns_remaining - 1
42 }
43 );
44
45 let last_row_pad_len = columns_empty * (col_pad_len + 1);
46 let table_len_needed = data_len + columns_empty;
47
48 if self.header {
49 let offset = " ".repeat(offset_str_len + 2);
50 let line = "-".repeat((self.columns * (col_pad_len + 1)) - 1);
51
52 write!(out, "{}", offset)?;
53
54 for i in 0..self.columns {
55 write!(out, "{:0>1$X} ", i, col_pad_len)?;
56 }
57
58 write!(out, "\n{}{}\n", offset, line)?;
59 }
60
61 for _ in 0..(table_len_needed / self.columns) {
62 write!(out, "{:0>1$X}: ", self.offset + row_pos, offset_str_len)?;
63
64 for _ in 0..self.columns {
65 if !self.zeros && data[col_pos] == 0 {
66 write!(out, "{} ", ".".repeat(col_pad_len))?;
67 } else {
68 write!(out, "{:0>1$X} ", data[col_pos], col_pad_len)?;
69 }
70
71 col_pos += 1;
72
73 if col_pos >= data_len {
74 break
75 }
76 }
77
78 if self.ascii {
79 if col_pos >= data_len {
80 write!(out, "{}", " ".repeat(last_row_pad_len))?;
81 }
82
83 write!(out, "| ")?;
84
85 for _ in 0..self.columns {
86 if data[ascii_pos].is_ascii_alphanumeric() {
87 write!(out, "{}", data[ascii_pos] as char)?;
88 } else {
89 write!(out, ".")?;
90 }
91
92 ascii_pos += 1;
93
94 if ascii_pos >= data_len {
95 break
96 }
97 }
98 }
99
100 row_pos += self.columns;
101
102 if row_pos >= data_len {
103 break
104 }
105
106 write!(out, "\n")?;
107 }
108
109 write!(out, "\n")?;
110
111 Ok(())
112 }
113
114 fn count_hex_digits(x: usize) -> usize {
117 (8 * std::mem::size_of::<usize>() - 1 - x.leading_zeros() as usize) / (7 - 16u8.leading_zeros() as usize) + 1
118 }
119}