1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Print a + or - based on whether a given field is true.
pub fn is_set(field: bool) -> char {
    match field {
        true => '+',
        false => '-',
    }
}

// Turn bytes into a human readable value.
pub fn format_bytes(size: u64) -> String {
    let mut s = size;
    let mut divs: u8 = 0;
    while s / 1024 >= 1 {
        s /= 1024;
        divs += 1;
    }

    format!(
        "{}{}",
        s.to_string(),
        match divs {
            0 => "B",
            1 => "K",
            2 => "M",
            3 => "G",
            4 => "T",
            _ => return size.to_string(),
        }
    )
}

const SLICE_SIZE: usize = 16;
pub struct Hexdumper<'a> {
    pub bytes: &'a [u8],
    pub show_header: bool,
    pub show_ascii: bool,
    pub offset: Option<u64>,
}

impl std::fmt::Display for Hexdumper<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let size = std::cmp::min(self.bytes.len(), SLICE_SIZE);
        // Weep for those who do not use monospace terminal fonts.
        if self.show_header {
            write!(f, "        ")?;
            for col in 0..size {
                write!(f, " {:1x} ", col)?;
                if col == 7 {
                    write!(f, " ")?;
                }
            }
            writeln!(f)?;
        }

        let start_addr = self.offset.unwrap_or(0) as usize;
        for (addr, slice) in self.bytes.chunks(SLICE_SIZE).enumerate() {
            write!(f, "  {:04x}: ", start_addr + (addr * SLICE_SIZE))?;
            for (i, byte) in slice.iter().enumerate() {
                write!(f, "{:02x} ", byte)?;
                if i == 7 {
                    write!(f, " ")?;
                }
            }
            if self.show_ascii {
                write!(f, " ")?;
                for byte in slice {
                    if byte.is_ascii_graphic() {
                        write!(f, "{}", *byte as char)?;
                    } else {
                        write!(f, ".")?;
                    }
                }
            }
            writeln!(f)?;
        }
        Ok(())
    }
}