hexdump? idk what this was
This commit is contained in:
commit
24dedd4b57
4 changed files with 236 additions and 0 deletions
1
hexdump/.gitignore
vendored
Normal file
1
hexdump/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
5
hexdump/Cargo.lock
generated
Normal file
5
hexdump/Cargo.lock
generated
Normal file
|
@ -0,0 +1,5 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "hexdump"
|
||||
version = "0.1.0"
|
9
hexdump/Cargo.toml
Normal file
9
hexdump/Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "hexdump"
|
||||
version = "0.1.0"
|
||||
authors = ["Michael Zhang <iptq@protonmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
221
hexdump/src/lib.rs
Normal file
221
hexdump/src/lib.rs
Normal file
|
@ -0,0 +1,221 @@
|
|||
use std::io::{Error, Read, Write};
|
||||
|
||||
const HEXCHARS: &[u8] = b"0123456789abcdef";
|
||||
|
||||
pub enum Size {
|
||||
Word8(u8),
|
||||
Word16(u16),
|
||||
Word32(u32),
|
||||
Word64(u64),
|
||||
}
|
||||
|
||||
pub fn hexdump<R: Read, W: Write>(
|
||||
mut w: W,
|
||||
starting_addr: Size,
|
||||
mut input: R,
|
||||
) -> Result<(), Error> {
|
||||
let (starting_value, mut offset) = match starting_addr {
|
||||
Size::Word8(n) => (n as u64, (n % 16) as u8),
|
||||
Size::Word16(n) => (n as u64, (n % 16) as u8),
|
||||
Size::Word32(n) => (n as u64, (n % 16) as u8),
|
||||
Size::Word64(n) => (n as u64, (n % 16) as u8),
|
||||
};
|
||||
|
||||
// first row
|
||||
match starting_addr {
|
||||
Size::Word8(_) => write!(w, "{:>4}", "Addr")?,
|
||||
Size::Word16(_) => write!(w, "{:>6}", "Addr")?,
|
||||
Size::Word32(_) => write!(w, "{:>10}", "Addr")?,
|
||||
Size::Word64(_) => write!(w, "{:>18}", "Addr")?,
|
||||
};
|
||||
for (i, c) in HEXCHARS.iter().enumerate() {
|
||||
if i == 8 {
|
||||
write!(w, " ")?;
|
||||
}
|
||||
write!(w, " {}", *c as char)?;
|
||||
}
|
||||
write!(w, " ")?;
|
||||
for (i, c) in HEXCHARS.iter().enumerate() {
|
||||
if i == 8 {
|
||||
write!(w, " ")?;
|
||||
}
|
||||
write!(w, "{}", *c as char)?;
|
||||
}
|
||||
write!(w, "\n")?;
|
||||
|
||||
// write every row
|
||||
let mut row_offset = starting_value;
|
||||
let mut buf = vec![0; 16 - offset as usize];
|
||||
loop {
|
||||
let is_first_line = if offset > 0 {
|
||||
row_offset -= offset as u64;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !is_first_line && buf.len() < 16 {
|
||||
buf.resize(16, 0);
|
||||
}
|
||||
|
||||
let bytes = input.read(&mut buf)?;
|
||||
if bytes == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
match starting_addr {
|
||||
Size::Word8(_) => write!(w, "0x{:02x}", row_offset)?,
|
||||
Size::Word16(_) => write!(w, "0x{:04x}", row_offset)?,
|
||||
Size::Word32(_) => write!(w, "0x{:08x}", row_offset)?,
|
||||
Size::Word64(_) => write!(w, "0x{:16x}", row_offset)?,
|
||||
};
|
||||
|
||||
if is_first_line {
|
||||
write!(w, "{}", " ".repeat(offset as usize))?;
|
||||
if offset > 8 {
|
||||
write!(w, " ")?;
|
||||
}
|
||||
}
|
||||
for (i, c) in buf.iter().enumerate() {
|
||||
if (i + offset as usize) == 8 {
|
||||
write!(w, " ")?;
|
||||
}
|
||||
if i < bytes {
|
||||
write!(w, " {:02x}", c)?;
|
||||
} else {
|
||||
write!(w, " ")?;
|
||||
}
|
||||
}
|
||||
write!(w, " ")?;
|
||||
if is_first_line {
|
||||
write!(w, "{}", " ".repeat(offset as usize))?;
|
||||
if offset > 8 {
|
||||
write!(w, " ")?;
|
||||
}
|
||||
}
|
||||
for (i, c) in buf.iter().enumerate() {
|
||||
if (i + offset as usize) == 8 {
|
||||
write!(w, " ")?;
|
||||
}
|
||||
if i < bytes {
|
||||
let ascii = match c {
|
||||
0 => '0',
|
||||
b' ' | b'\n' | b'\r' | b'\t' => '_',
|
||||
c if 0x20 < *c && *c < 0x7f => *c as char,
|
||||
_ => '.',
|
||||
};
|
||||
write!(w, "{}", ascii)?;
|
||||
} else {
|
||||
write!(w, " ")?;
|
||||
}
|
||||
}
|
||||
|
||||
row_offset += 16;
|
||||
offset = 0;
|
||||
write!(w, "\n")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{hexdump, Size};
|
||||
use std::io::Cursor;
|
||||
|
||||
macro_rules! generate_test {
|
||||
($test_name:ident, $start:expr, $input:expr, $expected:expr) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
const EXPECTED: &[u8] = $expected;
|
||||
let mut buf = Cursor::new(Vec::new());
|
||||
let input = Cursor::new($input);
|
||||
hexdump(&mut buf, $start, input).unwrap();
|
||||
println!("{}", std::str::from_utf8(buf.get_ref()).unwrap());
|
||||
println!("{}", std::str::from_utf8(EXPECTED).unwrap());
|
||||
println!(
|
||||
"{:?}",
|
||||
std::str::from_utf8(EXPECTED)
|
||||
.unwrap()
|
||||
.trim_start_matches(std::str::from_utf8(buf.get_ref()).unwrap())
|
||||
);
|
||||
assert_eq!(buf.get_ref().as_slice(), &EXPECTED[..]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
generate_test!(
|
||||
test1,
|
||||
Size::Word8(0),
|
||||
(0..=0x7f).collect::<Vec<u8>>(),
|
||||
br##"Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f 01234567 89abcdef
|
||||
0x00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 0....... .__.._..
|
||||
0x10 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ........ ........
|
||||
0x20 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f _!"#$%&' ()*+,-./
|
||||
0x30 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 01234567 89:;<=>?
|
||||
0x40 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFG HIJKLMNO
|
||||
0x50 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVW XYZ[\]^_
|
||||
0x60 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f `abcdefg hijklmno
|
||||
0x70 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f pqrstuvw xyz{|}~.
|
||||
"##
|
||||
);
|
||||
|
||||
generate_test!(
|
||||
test2,
|
||||
Size::Word32(0x012c),
|
||||
b"Hello, world!\n",
|
||||
br##" Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f 01234567 89abcdef
|
||||
0x00000120 48 65 6c 6c Hell
|
||||
0x00000130 6f 2c 20 77 6f 72 6c 64 21 0a o,_world !_
|
||||
"##
|
||||
);
|
||||
|
||||
generate_test!(
|
||||
test3,
|
||||
Size::Word32(0x032c),
|
||||
b"Hello, world!\nGoodbye, world!\n",
|
||||
br##" Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f 01234567 89abcdef
|
||||
0x00000320 48 65 6c 6c Hell
|
||||
0x00000330 6f 2c 20 77 6f 72 6c 64 21 0a 47 6f 6f 64 62 79 o,_world !_Goodby
|
||||
0x00000340 65 2c 20 77 6f 72 6c 64 21 0a e,_world !_
|
||||
"##
|
||||
);
|
||||
|
||||
generate_test!(
|
||||
test4,
|
||||
Size::Word32(0x0526),
|
||||
b"Hello, world!\nGoodbye, world!\n",
|
||||
br##" Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f 01234567 89abcdef
|
||||
0x00000520 48 65 6c 6c 6f 2c 20 77 6f 72 He llo,_wor
|
||||
0x00000530 6c 64 21 0a 47 6f 6f 64 62 79 65 2c 20 77 6f 72 ld!_Good bye,_wor
|
||||
0x00000540 6c 64 21 0a ld!_
|
||||
"##
|
||||
);
|
||||
|
||||
generate_test!(
|
||||
test5,
|
||||
Size::Word16(0x0201),
|
||||
b"Hello, world!\n",
|
||||
br##" Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f 01234567 89abcdef
|
||||
0x0200 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0a Hello,_ world!_
|
||||
"##
|
||||
);
|
||||
|
||||
generate_test!(
|
||||
test6,
|
||||
Size::Word8(0xf4),
|
||||
b"foo",
|
||||
br##"Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f 01234567 89abcdef
|
||||
0xf0 66 6f 6f foo
|
||||
"##
|
||||
);
|
||||
|
||||
generate_test!(
|
||||
test7,
|
||||
Size::Word32(0xff00ff0a),
|
||||
b"foo",
|
||||
br##" Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f 01234567 89abcdef
|
||||
0xff00ff00 66 6f 6f foo
|
||||
"##
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue