Skip to main content

pcf_debug/render/
hexdump.rs

1//! A classic 16-column hexdump with absolute file offsets.
2
3use super::color::Palette;
4
5/// Hexdump `data`, labelling each row with its absolute offset (`base` is the
6/// file offset of `data[0]`). At most `max` bytes are shown; the remainder is
7/// summarised. Returns the formatted block (no trailing newline).
8pub fn dump(data: &[u8], base: u64, max: usize, pal: Palette) -> String {
9    let shown = data.len().min(max);
10    let mut out = String::new();
11    for (row, chunk) in data[..shown].chunks(16).enumerate() {
12        let off = base + (row * 16) as u64;
13        let mut hex = String::new();
14        let mut ascii = String::new();
15        for (i, &b) in chunk.iter().enumerate() {
16            if i == 8 {
17                hex.push(' ');
18            }
19            hex.push_str(&format!("{b:02x} "));
20            ascii.push(if (0x20..0x7f).contains(&b) {
21                b as char
22            } else {
23                '.'
24            });
25        }
26        // Pad a short final row so the ASCII column lines up.
27        let pad = 16 - chunk.len();
28        for i in 0..pad {
29            if chunk.len() + i == 8 {
30                hex.push(' ');
31            }
32            hex.push_str("   ");
33        }
34        out.push_str(&format!(
35            "{}  {hex} |{ascii}|\n",
36            pal.dim(&format!("{off:08x}"))
37        ));
38    }
39    if data.len() > shown {
40        out.push_str(&pal.dim(&format!(
41            "  ... {} more byte(s) (use --max-bytes to show)\n",
42            data.len() - shown
43        )));
44    }
45    // Trim the trailing newline.
46    if out.ends_with('\n') {
47        out.pop();
48    }
49    out
50}