bitformat/
qword_table.rs

1const BITS_IN_BYTE: u8 = 8;
2
3pub struct QwordTable<'a> {
4    data: &'a Vec<u8>,
5}
6
7impl<'a> QwordTable<'a> {
8    pub fn from_bytes(data: &Vec<u8>) -> QwordTable {
9        QwordTable { data }
10    }
11
12    /// Formats a vector of bytes as a qword table.
13    ///
14    /// # Arguments
15    ///
16    /// * `data` - The bytes to format.
17    pub fn format(self: &QwordTable<'a>) -> String {
18        let mut result = self.format_qword_table_header();
19        let num_qwords = self.data.len().div_euclid(BITS_IN_BYTE as usize);
20        // Append full qwords
21        for i in 0..num_qwords {
22            let from_byte_ix = i * BITS_IN_BYTE as usize;
23            let to_byte_ix = from_byte_ix + BITS_IN_BYTE as usize;
24            let qword_number: usize = i + 1;
25            result.push_str(&self.format_qword_row(
26                qword_number,
27                &self.data[from_byte_ix..to_byte_ix],
28                BITS_IN_BYTE as usize,
29            ));
30        }
31        // Append final bytes
32        let remaining_bytes = self.data.len().rem_euclid(BITS_IN_BYTE as usize);
33        let from_byte_ix: usize = num_qwords * BITS_IN_BYTE as usize;
34        let to_byte_ix: usize = from_byte_ix + remaining_bytes as usize;
35        let qword_number: usize = num_qwords + 1;
36        result.push_str(&self.format_qword_row(
37            qword_number,
38            &self.data[from_byte_ix..to_byte_ix],
39            remaining_bytes,
40        ));
41        result
42    }
43
44    /// Formats the header for a qword table.
45    fn format_qword_table_header(self: &QwordTable<'a>) -> String {
46        // Top border
47        let mut result = String::from("       +");
48        result.push_str(&(0..BITS_IN_BYTE).map(|_| "--------+").collect::<String>());
49        // Append table label
50        result.push_str("\n Bytes |");
51        // Append column labels
52        result.push_str(
53            &(0..BITS_IN_BYTE)
54                .map(|i| format!(" Byte {} |", i))
55                .collect::<String>(),
56        );
57        // Append bottom border
58        result.push_str("\n+------+");
59        result.push_str(&(0..BITS_IN_BYTE).map(|_| "--------+").collect::<String>());
60        result.push_str("\n");
61        result
62    }
63
64    /// Formats a row of bytes in a qword table.
65    ///
66    /// # Arguments
67    ///
68    /// * `qword_number` - The sequence number of this qword.
69    /// * `data` - The bytes within the qword to format.
70    /// * `num_bytes` - The number of bytes to format.
71    fn format_qword_row(
72        self: &QwordTable<'a>,
73        qword_number: usize,
74        data: &[u8],
75        num_bytes: usize,
76    ) -> String {
77        if data.len() != num_bytes {
78            return format!(
79                "ERROR: Data must contain exactly {} bytes. QWORD: {}\n",
80                num_bytes, qword_number
81            );
82        }
83
84        // Row header
85        let mut result = String::from("|QWORD |");
86        // Append byte values
87        result.push_str(
88            &(0..num_bytes)
89                .map(|i| format!("{:0>8b}|", data[i]))
90                .collect::<String>(),
91        );
92        // Append qword number
93        result.push_str(&format!("\n|{:^6}|", qword_number));
94        // Append byte value
95        result.push_str(
96            &(0..num_bytes)
97                .map(|i| format!("{:>8}|", format!("({})", data[i])))
98                .collect::<String>(),
99        );
100        // Append bottom border
101        result.push_str("\n+------+");
102        result.push_str(&(0..num_bytes).map(|_| "--------+").collect::<String>());
103        result.push_str("\n");
104        result
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn test_one_byte() {
114        let data = vec![129];
115        let table: QwordTable = QwordTable::from_bytes(&data);
116
117        let expected = "       +--------+--------+--------+--------+--------+--------+--------+--------+\n Bytes | Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 |\n+------+--------+--------+--------+--------+--------+--------+--------+--------+\n|QWORD |10000001|\n|  1   |   (129)|\n+------+--------+\n";
118
119        assert_eq!(expected, table.format());
120    }
121}