2020-04-29 08:22:03 +02:00
|
|
|
|
pub(crate) mod input;
|
2019-07-14 17:38:30 +01:00
|
|
|
|
|
2020-04-29 08:22:03 +02:00
|
|
|
|
pub use input::*;
|
|
|
|
|
|
|
2022-10-13 12:33:12 -04:00
|
|
|
|
use std::io::{self, BufReader, Read, Write};
|
2019-07-14 17:38:30 +01:00
|
|
|
|
|
2022-11-18 08:19:13 -05:00
|
|
|
|
use anstyle::{AnsiColor, Reset};
|
2019-07-14 17:38:30 +01:00
|
|
|
|
|
2022-11-27 17:11:21 -05:00
|
|
|
|
pub enum Base {
|
|
|
|
|
|
Binary,
|
|
|
|
|
|
Octal,
|
|
|
|
|
|
Decimal,
|
|
|
|
|
|
Hexadecimal,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-19 10:50:31 -05:00
|
|
|
|
#[derive(PartialEq, Eq)]
|
|
|
|
|
|
#[repr(usize)]
|
|
|
|
|
|
enum ByteColor {
|
|
|
|
|
|
Null = 0,
|
|
|
|
|
|
Offset = 1,
|
|
|
|
|
|
AsciiPrintable = 2,
|
|
|
|
|
|
AsciiWhitespace = 3,
|
|
|
|
|
|
AsciiOther = 4,
|
|
|
|
|
|
NonAscii = 5,
|
|
|
|
|
|
Reset = 6,
|
|
|
|
|
|
}
|
2022-11-18 10:39:54 -05:00
|
|
|
|
|
2022-11-18 08:19:13 -05:00
|
|
|
|
const COLOR_NULL: AnsiColor = AnsiColor::BrightBlack;
|
|
|
|
|
|
const COLOR_OFFSET: AnsiColor = AnsiColor::BrightBlack;
|
|
|
|
|
|
const COLOR_ASCII_PRINTABLE: AnsiColor = AnsiColor::Cyan;
|
|
|
|
|
|
const COLOR_ASCII_WHITESPACE: AnsiColor = AnsiColor::Green;
|
|
|
|
|
|
const COLOR_ASCII_OTHER: AnsiColor = AnsiColor::Magenta;
|
|
|
|
|
|
const COLOR_NONASCII: AnsiColor = AnsiColor::Yellow;
|
2019-07-14 17:38:30 +01:00
|
|
|
|
|
|
|
|
|
|
pub enum ByteCategory {
|
|
|
|
|
|
Null,
|
|
|
|
|
|
AsciiPrintable,
|
|
|
|
|
|
AsciiWhitespace,
|
|
|
|
|
|
AsciiOther,
|
|
|
|
|
|
NonAscii,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-13 10:55:49 -04:00
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
|
|
enum Squeezer {
|
|
|
|
|
|
Print,
|
|
|
|
|
|
Delete,
|
|
|
|
|
|
Ignore,
|
|
|
|
|
|
Disabled,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-07-14 17:38:30 +01:00
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
|
struct Byte(u8);
|
|
|
|
|
|
|
|
|
|
|
|
impl Byte {
|
|
|
|
|
|
fn category(self) -> ByteCategory {
|
|
|
|
|
|
if self.0 == 0x00 {
|
|
|
|
|
|
ByteCategory::Null
|
2020-06-07 15:26:07 +02:00
|
|
|
|
} else if self.0.is_ascii_graphic() {
|
2019-07-14 17:38:30 +01:00
|
|
|
|
ByteCategory::AsciiPrintable
|
|
|
|
|
|
} else if self.0.is_ascii_whitespace() {
|
|
|
|
|
|
ByteCategory::AsciiWhitespace
|
|
|
|
|
|
} else if self.0.is_ascii() {
|
|
|
|
|
|
ByteCategory::AsciiOther
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ByteCategory::NonAscii
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-19 10:50:31 -05:00
|
|
|
|
fn color(self) -> ByteColor {
|
2019-07-14 17:38:30 +01:00
|
|
|
|
use crate::ByteCategory::*;
|
|
|
|
|
|
|
|
|
|
|
|
match self.category() {
|
2022-11-19 10:50:31 -05:00
|
|
|
|
Null => ByteColor::Null,
|
|
|
|
|
|
AsciiPrintable => ByteColor::AsciiPrintable,
|
|
|
|
|
|
AsciiWhitespace => ByteColor::AsciiWhitespace,
|
|
|
|
|
|
AsciiOther => ByteColor::AsciiOther,
|
|
|
|
|
|
NonAscii => ByteColor::NonAscii,
|
2019-07-14 17:38:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn as_char(self) -> char {
|
|
|
|
|
|
use crate::ByteCategory::*;
|
|
|
|
|
|
|
|
|
|
|
|
match self.category() {
|
|
|
|
|
|
Null => '0',
|
|
|
|
|
|
AsciiPrintable => self.0 as char,
|
|
|
|
|
|
AsciiWhitespace if self.0 == 0x20 => ' ',
|
|
|
|
|
|
AsciiWhitespace => '_',
|
|
|
|
|
|
AsciiOther => '•',
|
|
|
|
|
|
NonAscii => '×',
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct BorderElements {
|
|
|
|
|
|
left_corner: char,
|
|
|
|
|
|
horizontal_line: char,
|
|
|
|
|
|
column_separator: char,
|
|
|
|
|
|
right_corner: char,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-17 09:46:15 -04:00
|
|
|
|
#[derive(Clone, Copy)]
|
2019-07-14 17:38:30 +01:00
|
|
|
|
pub enum BorderStyle {
|
|
|
|
|
|
Unicode,
|
|
|
|
|
|
Ascii,
|
|
|
|
|
|
None,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl BorderStyle {
|
|
|
|
|
|
fn header_elems(&self) -> Option<BorderElements> {
|
|
|
|
|
|
match self {
|
|
|
|
|
|
BorderStyle::Unicode => Some(BorderElements {
|
|
|
|
|
|
left_corner: '┌',
|
|
|
|
|
|
horizontal_line: '─',
|
|
|
|
|
|
column_separator: '┬',
|
|
|
|
|
|
right_corner: '┐',
|
|
|
|
|
|
}),
|
|
|
|
|
|
BorderStyle::Ascii => Some(BorderElements {
|
|
|
|
|
|
left_corner: '+',
|
|
|
|
|
|
horizontal_line: '-',
|
|
|
|
|
|
column_separator: '+',
|
|
|
|
|
|
right_corner: '+',
|
|
|
|
|
|
}),
|
|
|
|
|
|
BorderStyle::None => None,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn footer_elems(&self) -> Option<BorderElements> {
|
|
|
|
|
|
match self {
|
|
|
|
|
|
BorderStyle::Unicode => Some(BorderElements {
|
|
|
|
|
|
left_corner: '└',
|
|
|
|
|
|
horizontal_line: '─',
|
|
|
|
|
|
column_separator: '┴',
|
|
|
|
|
|
right_corner: '┘',
|
|
|
|
|
|
}),
|
|
|
|
|
|
BorderStyle::Ascii => Some(BorderElements {
|
|
|
|
|
|
left_corner: '+',
|
|
|
|
|
|
horizontal_line: '-',
|
|
|
|
|
|
column_separator: '+',
|
|
|
|
|
|
right_corner: '+',
|
|
|
|
|
|
}),
|
|
|
|
|
|
BorderStyle::None => None,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn outer_sep(&self) -> char {
|
|
|
|
|
|
match self {
|
|
|
|
|
|
BorderStyle::Unicode => '│',
|
|
|
|
|
|
BorderStyle::Ascii => '|',
|
|
|
|
|
|
BorderStyle::None => ' ',
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn inner_sep(&self) -> char {
|
|
|
|
|
|
match self {
|
|
|
|
|
|
BorderStyle::Unicode => '┊',
|
|
|
|
|
|
BorderStyle::Ascii => '|',
|
|
|
|
|
|
BorderStyle::None => ' ',
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-17 09:46:15 -04:00
|
|
|
|
pub struct PrinterBuilder<'a, Writer: Write> {
|
|
|
|
|
|
writer: &'a mut Writer,
|
|
|
|
|
|
show_color: bool,
|
|
|
|
|
|
show_char_panel: bool,
|
|
|
|
|
|
show_position_panel: bool,
|
|
|
|
|
|
border_style: BorderStyle,
|
|
|
|
|
|
use_squeeze: bool,
|
2022-10-13 10:55:49 -04:00
|
|
|
|
panels: u64,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
group_bytes: u8,
|
2022-11-27 17:11:21 -05:00
|
|
|
|
base: Base,
|
2022-09-17 09:46:15 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
|
|
|
|
|
|
pub fn new(writer: &'a mut Writer) -> Self {
|
|
|
|
|
|
PrinterBuilder {
|
|
|
|
|
|
writer,
|
|
|
|
|
|
show_color: true,
|
|
|
|
|
|
show_char_panel: true,
|
|
|
|
|
|
show_position_panel: true,
|
|
|
|
|
|
border_style: BorderStyle::Unicode,
|
|
|
|
|
|
use_squeeze: true,
|
|
|
|
|
|
panels: 2,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
group_bytes: 1,
|
2022-11-27 17:11:21 -05:00
|
|
|
|
base: Base::Hexadecimal,
|
2022-09-17 09:46:15 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn show_color(mut self, show_color: bool) -> Self {
|
|
|
|
|
|
self.show_color = show_color;
|
|
|
|
|
|
self
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn show_char_panel(mut self, show_char_panel: bool) -> Self {
|
|
|
|
|
|
self.show_char_panel = show_char_panel;
|
|
|
|
|
|
self
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn show_position_panel(mut self, show_position_panel: bool) -> Self {
|
|
|
|
|
|
self.show_position_panel = show_position_panel;
|
|
|
|
|
|
self
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn with_border_style(mut self, border_style: BorderStyle) -> Self {
|
|
|
|
|
|
self.border_style = border_style;
|
|
|
|
|
|
self
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-03 23:07:52 -04:00
|
|
|
|
pub fn enable_squeezing(mut self, enable: bool) -> Self {
|
|
|
|
|
|
self.use_squeeze = enable;
|
2022-09-17 09:46:15 -04:00
|
|
|
|
self
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-13 10:55:49 -04:00
|
|
|
|
pub fn num_panels(mut self, num: u64) -> Self {
|
2022-10-04 08:49:19 -04:00
|
|
|
|
self.panels = num;
|
2022-09-17 09:46:15 -04:00
|
|
|
|
self
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-03 20:52:57 +08:00
|
|
|
|
pub fn num_group_bytes(mut self, num: u8) -> Self {
|
|
|
|
|
|
self.group_bytes = num;
|
|
|
|
|
|
self
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-27 17:11:21 -05:00
|
|
|
|
pub fn with_base(mut self, base: Base) -> Self {
|
|
|
|
|
|
self.base = base;
|
|
|
|
|
|
self
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-17 09:46:15 -04:00
|
|
|
|
pub fn build(self) -> Printer<'a, Writer> {
|
|
|
|
|
|
Printer::new(
|
|
|
|
|
|
self.writer,
|
|
|
|
|
|
self.show_color,
|
|
|
|
|
|
self.show_char_panel,
|
|
|
|
|
|
self.show_position_panel,
|
|
|
|
|
|
self.border_style,
|
|
|
|
|
|
self.use_squeeze,
|
|
|
|
|
|
self.panels,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
self.group_bytes,
|
2022-11-27 17:11:21 -05:00
|
|
|
|
self.base,
|
2022-09-17 09:46:15 -04:00
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-07-14 18:18:13 +01:00
|
|
|
|
pub struct Printer<'a, Writer: Write> {
|
2020-06-01 12:31:21 -06:00
|
|
|
|
idx: u64,
|
2022-10-07 17:28:35 -04:00
|
|
|
|
/// the buffer containing all the bytes in a line for character printing
|
|
|
|
|
|
line_buf: Vec<u8>,
|
2019-07-14 18:18:13 +01:00
|
|
|
|
writer: &'a mut Writer,
|
2022-05-22 14:14:07 -05:00
|
|
|
|
show_char_panel: bool,
|
|
|
|
|
|
show_position_panel: bool,
|
2022-11-18 08:19:13 -05:00
|
|
|
|
show_color: bool,
|
2022-11-19 10:50:31 -05:00
|
|
|
|
colors: Vec<String>,
|
|
|
|
|
|
curr_color: Option<ByteColor>,
|
2019-07-14 17:38:30 +01:00
|
|
|
|
border_style: BorderStyle,
|
2022-05-22 14:14:07 -05:00
|
|
|
|
byte_hex_panel: Vec<String>,
|
|
|
|
|
|
byte_char_panel: Vec<String>,
|
2022-10-13 18:59:09 -04:00
|
|
|
|
// same as previous but in Fixed(242) gray color, for position panel
|
2022-10-07 18:36:22 -04:00
|
|
|
|
byte_hex_panel_g: Vec<String>,
|
|
|
|
|
|
byte_char_panel_g: Vec<String>,
|
2019-07-14 17:38:30 +01:00
|
|
|
|
squeezer: Squeezer,
|
2020-06-01 12:31:21 -06:00
|
|
|
|
display_offset: u64,
|
2022-07-12 11:39:24 -04:00
|
|
|
|
/// The number of panels to draw.
|
2022-10-13 10:55:49 -04:00
|
|
|
|
panels: u64,
|
2022-11-05 11:45:19 -04:00
|
|
|
|
squeeze_byte: usize,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
/// The number of octets per group.
|
|
|
|
|
|
group_bytes: u8,
|
2022-11-27 17:11:21 -05:00
|
|
|
|
/// The number of digits used to write the base.
|
|
|
|
|
|
base_digits: u8,
|
2019-07-14 17:38:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-07-14 18:18:13 +01:00
|
|
|
|
impl<'a, Writer: Write> Printer<'a, Writer> {
|
2022-09-17 09:46:15 -04:00
|
|
|
|
fn new(
|
2019-07-14 18:18:13 +01:00
|
|
|
|
writer: &'a mut Writer,
|
2019-07-14 17:38:30 +01:00
|
|
|
|
show_color: bool,
|
2022-05-22 14:14:07 -05:00
|
|
|
|
show_char_panel: bool,
|
|
|
|
|
|
show_position_panel: bool,
|
2019-07-14 17:38:30 +01:00
|
|
|
|
border_style: BorderStyle,
|
|
|
|
|
|
use_squeeze: bool,
|
2022-10-13 10:55:49 -04:00
|
|
|
|
panels: u64,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
group_bytes: u8,
|
2022-11-27 17:11:21 -05:00
|
|
|
|
base: Base,
|
2019-07-14 18:18:13 +01:00
|
|
|
|
) -> Printer<'a, Writer> {
|
2019-07-14 17:38:30 +01:00
|
|
|
|
Printer {
|
2022-10-07 17:28:35 -04:00
|
|
|
|
idx: 0,
|
2022-10-13 10:55:49 -04:00
|
|
|
|
line_buf: vec![0x0; 8 * panels as usize],
|
2019-07-14 18:18:13 +01:00
|
|
|
|
writer,
|
2022-05-22 14:14:07 -05:00
|
|
|
|
show_char_panel,
|
|
|
|
|
|
show_position_panel,
|
2022-11-18 08:19:13 -05:00
|
|
|
|
show_color,
|
|
|
|
|
|
curr_color: None,
|
2022-11-19 10:50:31 -05:00
|
|
|
|
colors: vec![
|
|
|
|
|
|
COLOR_NULL.render_fg().to_string(),
|
|
|
|
|
|
COLOR_OFFSET.render_fg().to_string(),
|
|
|
|
|
|
COLOR_ASCII_PRINTABLE.render_fg().to_string(),
|
|
|
|
|
|
COLOR_ASCII_WHITESPACE.render_fg().to_string(),
|
|
|
|
|
|
COLOR_ASCII_OTHER.render_fg().to_string(),
|
|
|
|
|
|
COLOR_NONASCII.render_fg().to_string(),
|
|
|
|
|
|
Reset.render().to_string(),
|
|
|
|
|
|
],
|
2019-07-14 17:38:30 +01:00
|
|
|
|
border_style,
|
2022-11-27 17:11:55 -05:00
|
|
|
|
byte_hex_panel: (0u8..=u8::MAX)
|
|
|
|
|
|
.map(|i| match base {
|
|
|
|
|
|
Base::Binary => format!("{i:08b}"),
|
|
|
|
|
|
Base::Octal => format!("{i:03o}"),
|
|
|
|
|
|
Base::Decimal => format!("{i:03}"),
|
|
|
|
|
|
Base::Hexadecimal => format!("{i:02x}"),
|
|
|
|
|
|
})
|
|
|
|
|
|
.collect(),
|
2022-10-07 21:29:30 -04:00
|
|
|
|
byte_char_panel: (0u8..=u8::MAX)
|
2022-11-18 08:19:13 -05:00
|
|
|
|
.map(|i| format!("{}", Byte(i).as_char()))
|
2022-10-07 18:36:22 -04:00
|
|
|
|
.collect(),
|
2022-11-27 17:11:55 -05:00
|
|
|
|
byte_hex_panel_g: (0u8..=u8::MAX).map(|i| format!("{i:02x}")).collect(),
|
2022-10-07 21:29:30 -04:00
|
|
|
|
byte_char_panel_g: (0u8..=u8::MAX)
|
2022-11-18 10:39:54 -05:00
|
|
|
|
.map(|i| format!("{}", Byte(i).as_char()))
|
2022-10-07 21:29:30 -04:00
|
|
|
|
.collect(),
|
2022-10-13 10:55:49 -04:00
|
|
|
|
squeezer: if use_squeeze {
|
|
|
|
|
|
Squeezer::Ignore
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Squeezer::Disabled
|
|
|
|
|
|
},
|
2019-10-07 19:20:02 +01:00
|
|
|
|
display_offset: 0,
|
2022-09-05 09:51:34 -04:00
|
|
|
|
panels,
|
2022-10-09 15:40:44 -04:00
|
|
|
|
squeeze_byte: 0x00,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
group_bytes,
|
2022-11-27 17:11:21 -05:00
|
|
|
|
base_digits: match base {
|
|
|
|
|
|
Base::Binary => 8,
|
|
|
|
|
|
Base::Octal => 3,
|
|
|
|
|
|
Base::Decimal => 3,
|
|
|
|
|
|
Base::Hexadecimal => 2,
|
|
|
|
|
|
},
|
2019-07-14 17:38:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-01 12:31:21 -06:00
|
|
|
|
pub fn display_offset(&mut self, display_offset: u64) -> &mut Self {
|
2019-10-07 19:20:02 +01:00
|
|
|
|
self.display_offset = display_offset;
|
|
|
|
|
|
self
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-03 20:52:57 +08:00
|
|
|
|
fn panel_sz(&self) -> usize {
|
|
|
|
|
|
// add one to include the trailing space of a group
|
2022-11-27 17:15:26 -05:00
|
|
|
|
let group_sz = self.base_digits as usize * self.group_bytes as usize + 1;
|
2022-10-03 20:52:57 +08:00
|
|
|
|
let group_per_panel = 8 / self.group_bytes as usize;
|
|
|
|
|
|
// add one to include the leading space
|
|
|
|
|
|
1 + group_sz * group_per_panel
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-07 19:54:07 -04:00
|
|
|
|
fn write_border(&mut self, border_elements: BorderElements) -> io::Result<()> {
|
2022-04-22 15:33:26 -05:00
|
|
|
|
let h = border_elements.horizontal_line;
|
|
|
|
|
|
let c = border_elements.column_separator;
|
|
|
|
|
|
let l = border_elements.left_corner;
|
|
|
|
|
|
let r = border_elements.right_corner;
|
|
|
|
|
|
let h8 = h.to_string().repeat(8);
|
2022-10-03 20:52:57 +08:00
|
|
|
|
let h_repeat = h.to_string().repeat(self.panel_sz());
|
2019-07-14 17:38:30 +01:00
|
|
|
|
|
2022-05-22 14:14:07 -05:00
|
|
|
|
if self.show_position_panel {
|
2022-04-22 15:33:26 -05:00
|
|
|
|
write!(self.writer, "{l}{h8}{c}", l = l, c = c, h8 = h8).ok();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
write!(self.writer, "{}", l).ok();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-05 09:51:34 -04:00
|
|
|
|
for _ in 0..self.panels - 1 {
|
2022-10-03 20:52:57 +08:00
|
|
|
|
write!(self.writer, "{h_repeat}{c}", h_repeat = h_repeat, c = c).ok();
|
2022-07-12 11:39:24 -04:00
|
|
|
|
}
|
|
|
|
|
|
if self.show_char_panel {
|
2022-10-03 20:52:57 +08:00
|
|
|
|
write!(self.writer, "{h_repeat}{c}", h_repeat = h_repeat, c = c).ok();
|
2022-07-12 11:39:24 -04:00
|
|
|
|
} else {
|
2022-10-03 20:52:57 +08:00
|
|
|
|
write!(self.writer, "{h_repeat}", h_repeat = h_repeat).ok();
|
2022-07-12 11:39:24 -04:00
|
|
|
|
}
|
2022-04-22 15:33:26 -05:00
|
|
|
|
|
2022-05-22 14:14:07 -05:00
|
|
|
|
if self.show_char_panel {
|
2022-09-05 09:51:34 -04:00
|
|
|
|
for _ in 0..self.panels - 1 {
|
2022-07-12 11:39:24 -04:00
|
|
|
|
write!(self.writer, "{h8}{c}", h8 = h8, c = c).ok();
|
|
|
|
|
|
}
|
|
|
|
|
|
writeln!(self.writer, "{h8}{r}", h8 = h8, r = r).ok();
|
2022-04-22 15:33:26 -05:00
|
|
|
|
} else {
|
|
|
|
|
|
writeln!(self.writer, "{r}", r = r).ok();
|
2019-07-14 17:38:30 +01:00
|
|
|
|
}
|
2022-10-07 19:54:07 -04:00
|
|
|
|
|
|
|
|
|
|
Ok(())
|
2019-07-14 17:38:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-07 19:54:07 -04:00
|
|
|
|
pub fn print_header(&mut self) -> io::Result<()> {
|
2022-04-22 15:48:54 -05:00
|
|
|
|
if let Some(e) = self.border_style.header_elems() {
|
2022-10-07 19:54:07 -04:00
|
|
|
|
self.write_border(e)?
|
2022-04-22 15:48:54 -05:00
|
|
|
|
}
|
2022-10-07 19:54:07 -04:00
|
|
|
|
Ok(())
|
2022-04-22 15:33:26 -05:00
|
|
|
|
}
|
2019-07-14 17:38:30 +01:00
|
|
|
|
|
2022-10-07 19:54:07 -04:00
|
|
|
|
pub fn print_footer(&mut self) -> io::Result<()> {
|
2022-04-22 15:48:54 -05:00
|
|
|
|
if let Some(e) = self.border_style.footer_elems() {
|
2022-10-07 19:54:07 -04:00
|
|
|
|
self.write_border(e)?
|
2022-04-22 15:48:54 -05:00
|
|
|
|
}
|
2022-10-07 19:54:07 -04:00
|
|
|
|
Ok(())
|
2019-07-14 17:38:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-07 17:28:35 -04:00
|
|
|
|
fn print_position_panel(&mut self) -> io::Result<()> {
|
2022-10-13 10:55:49 -04:00
|
|
|
|
self.writer.write_all(
|
|
|
|
|
|
self.border_style
|
|
|
|
|
|
.outer_sep()
|
|
|
|
|
|
.encode_utf8(&mut [0; 4])
|
|
|
|
|
|
.as_bytes(),
|
|
|
|
|
|
)?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
if self.show_color {
|
2022-11-19 11:04:13 -05:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.colors[ByteColor::Offset as usize].as_bytes())?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
}
|
2022-10-13 13:43:47 -04:00
|
|
|
|
if self.show_position_panel {
|
|
|
|
|
|
match self.squeezer {
|
|
|
|
|
|
Squeezer::Print => {
|
2022-10-07 19:54:07 -04:00
|
|
|
|
self.writer
|
2022-10-13 13:43:47 -04:00
|
|
|
|
.write_all(self.byte_char_panel_g[b'*' as usize].as_bytes())?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
if self.show_color {
|
2022-11-19 11:04:13 -05:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
}
|
2022-10-13 13:43:47 -04:00
|
|
|
|
self.writer.write_all(b" ")?;
|
|
|
|
|
|
}
|
|
|
|
|
|
Squeezer::Ignore | Squeezer::Disabled | Squeezer::Delete => {
|
|
|
|
|
|
let byte_index: [u8; 8] = (self.idx + self.display_offset).to_be_bytes();
|
|
|
|
|
|
let mut i = 0;
|
|
|
|
|
|
while byte_index[i] == 0x0 && i < 4 {
|
|
|
|
|
|
i += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
for &byte in byte_index.iter().skip(i) {
|
|
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.byte_hex_panel_g[byte as usize].as_bytes())?;
|
|
|
|
|
|
}
|
2022-11-18 08:19:13 -05:00
|
|
|
|
if self.show_color {
|
2022-11-19 11:04:13 -05:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
}
|
2022-10-07 18:36:22 -04:00
|
|
|
|
}
|
2022-10-07 17:28:35 -04:00
|
|
|
|
}
|
2022-10-13 13:43:47 -04:00
|
|
|
|
self.writer.write_all(
|
|
|
|
|
|
self.border_style
|
|
|
|
|
|
.outer_sep()
|
|
|
|
|
|
.encode_utf8(&mut [0; 4])
|
|
|
|
|
|
.as_bytes(),
|
|
|
|
|
|
)?;
|
2019-07-14 17:38:30 +01:00
|
|
|
|
}
|
2022-10-07 17:28:35 -04:00
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
2019-07-14 17:38:30 +01:00
|
|
|
|
|
2022-10-13 13:38:41 -04:00
|
|
|
|
fn print_char(&mut self, i: u64) -> io::Result<()> {
|
|
|
|
|
|
match self.squeezer {
|
|
|
|
|
|
Squeezer::Print | Squeezer::Delete => self.writer.write_all(b" ")?,
|
|
|
|
|
|
Squeezer::Ignore | Squeezer::Disabled => {
|
|
|
|
|
|
if let Some(&b) = self.line_buf.get(i as usize) {
|
2022-11-19 10:50:31 -05:00
|
|
|
|
if self.show_color && self.curr_color != Some(Byte(b).color()) {
|
2022-11-19 11:04:13 -05:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.colors[Byte(b).color() as usize].as_bytes())?;
|
2022-11-19 10:50:31 -05:00
|
|
|
|
self.curr_color = Some(Byte(b).color());
|
2022-11-18 08:19:13 -05:00
|
|
|
|
}
|
2022-10-13 13:38:41 -04:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.byte_char_panel[b as usize].as_bytes())?;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
self.squeezer = Squeezer::Print;
|
2022-10-13 10:59:33 -04:00
|
|
|
|
}
|
2022-10-07 17:28:35 -04:00
|
|
|
|
}
|
2022-10-13 13:38:41 -04:00
|
|
|
|
}
|
|
|
|
|
|
if i == 8 * self.panels - 1 {
|
2022-11-18 08:19:13 -05:00
|
|
|
|
if self.show_color {
|
2022-11-19 11:04:13 -05:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
self.curr_color = None;
|
|
|
|
|
|
}
|
2022-10-13 13:38:41 -04:00
|
|
|
|
self.writer.write_all(
|
|
|
|
|
|
self.border_style
|
|
|
|
|
|
.outer_sep()
|
|
|
|
|
|
.encode_utf8(&mut [0; 4])
|
|
|
|
|
|
.as_bytes(),
|
|
|
|
|
|
)?;
|
|
|
|
|
|
} else if i % 8 == 7 {
|
2022-11-18 08:19:13 -05:00
|
|
|
|
if self.show_color {
|
2022-11-19 11:04:13 -05:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
self.curr_color = None;
|
|
|
|
|
|
}
|
2022-10-13 13:38:41 -04:00
|
|
|
|
self.writer.write_all(
|
|
|
|
|
|
self.border_style
|
|
|
|
|
|
.inner_sep()
|
|
|
|
|
|
.encode_utf8(&mut [0; 4])
|
|
|
|
|
|
.as_bytes(),
|
|
|
|
|
|
)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn print_char_panel(&mut self) -> io::Result<()> {
|
|
|
|
|
|
for i in 0..self.line_buf.len() {
|
|
|
|
|
|
self.print_char(i as u64)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn print_byte(&mut self, i: usize, b: u8) -> io::Result<()> {
|
|
|
|
|
|
match self.squeezer {
|
2022-10-15 09:10:11 -04:00
|
|
|
|
Squeezer::Print => {
|
|
|
|
|
|
if !self.show_position_panel && i == 0 {
|
2022-11-18 08:19:13 -05:00
|
|
|
|
if self.show_color {
|
2022-11-19 11:04:13 -05:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.colors[ByteColor::Offset as usize].as_bytes())?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
}
|
2022-10-15 09:12:29 -04:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.byte_char_panel_g[b'*' as usize].as_bytes())?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
if self.show_color {
|
2022-11-19 11:04:13 -05:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
}
|
2022-10-15 09:10:11 -04:00
|
|
|
|
} else {
|
2022-10-03 20:52:57 +08:00
|
|
|
|
if i % (self.group_bytes as usize) == 0 {
|
|
|
|
|
|
self.writer.write_all(b" ")?;
|
|
|
|
|
|
}
|
2022-10-15 09:10:11 -04:00
|
|
|
|
}
|
2022-11-27 17:15:26 -05:00
|
|
|
|
for _ in 0..self.base_digits {
|
|
|
|
|
|
self.writer.write_all(b" ")?;
|
|
|
|
|
|
}
|
2022-10-15 09:10:11 -04:00
|
|
|
|
}
|
|
|
|
|
|
Squeezer::Delete => self.writer.write_all(b" ")?,
|
|
|
|
|
|
Squeezer::Ignore | Squeezer::Disabled => {
|
2022-10-03 20:52:57 +08:00
|
|
|
|
if i % (self.group_bytes as usize) == 0 {
|
|
|
|
|
|
self.writer.write_all(b" ")?;
|
|
|
|
|
|
}
|
2022-11-19 10:50:31 -05:00
|
|
|
|
if self.show_color && self.curr_color != Some(Byte(b).color()) {
|
2022-11-19 11:04:13 -05:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.colors[Byte(b).color() as usize].as_bytes())?;
|
2022-11-19 10:50:31 -05:00
|
|
|
|
self.curr_color = Some(Byte(b).color());
|
2022-11-18 08:19:13 -05:00
|
|
|
|
}
|
2022-10-15 09:10:11 -04:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.byte_hex_panel[b as usize].as_bytes())?;
|
|
|
|
|
|
}
|
2022-10-13 13:38:41 -04:00
|
|
|
|
}
|
|
|
|
|
|
// byte is last in panel
|
|
|
|
|
|
if i % 8 == 7 {
|
2022-11-18 08:19:13 -05:00
|
|
|
|
if self.show_color {
|
|
|
|
|
|
self.curr_color = None;
|
2022-11-19 11:04:13 -05:00
|
|
|
|
self.writer
|
|
|
|
|
|
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
|
2022-11-18 08:19:13 -05:00
|
|
|
|
}
|
2022-10-13 18:58:01 -04:00
|
|
|
|
self.writer.write_all(b" ")?;
|
2022-10-13 13:38:41 -04:00
|
|
|
|
// byte is last in last panel
|
|
|
|
|
|
if i as u64 % (8 * self.panels) == 8 * self.panels - 1 {
|
2022-10-07 19:54:07 -04:00
|
|
|
|
self.writer.write_all(
|
|
|
|
|
|
self.border_style
|
|
|
|
|
|
.outer_sep()
|
|
|
|
|
|
.encode_utf8(&mut [0; 4])
|
|
|
|
|
|
.as_bytes(),
|
|
|
|
|
|
)?;
|
2022-10-13 13:38:41 -04:00
|
|
|
|
} else {
|
2022-10-07 19:54:07 -04:00
|
|
|
|
self.writer.write_all(
|
|
|
|
|
|
self.border_style
|
|
|
|
|
|
.inner_sep()
|
|
|
|
|
|
.encode_utf8(&mut [0; 4])
|
|
|
|
|
|
.as_bytes(),
|
|
|
|
|
|
)?;
|
2022-10-07 17:28:35 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-07-14 17:38:30 +01:00
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-13 10:55:49 -04:00
|
|
|
|
pub fn print_bytes(&mut self) -> io::Result<()> {
|
2022-10-13 13:38:41 -04:00
|
|
|
|
for (i, &b) in self.line_buf.clone().iter().enumerate() {
|
|
|
|
|
|
self.print_byte(i, b)?;
|
2019-07-14 21:31:51 +01:00
|
|
|
|
}
|
2022-10-07 17:28:35 -04:00
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Loop through the given `Reader`, printing until the `Reader` buffer
|
|
|
|
|
|
/// is exhausted.
|
|
|
|
|
|
pub fn print_all<Reader: Read>(&mut self, reader: Reader) -> io::Result<()> {
|
|
|
|
|
|
let mut is_empty = true;
|
|
|
|
|
|
|
2022-10-13 10:55:49 -04:00
|
|
|
|
let mut buf = BufReader::new(reader);
|
2022-10-07 17:28:35 -04:00
|
|
|
|
|
2022-11-05 12:03:49 -04:00
|
|
|
|
let leftover = loop {
|
2022-11-05 12:15:42 -04:00
|
|
|
|
// read a maximum of 8 * self.panels bytes from the reader
|
2022-10-13 13:38:41 -04:00
|
|
|
|
if let Ok(n) = buf.read(&mut self.line_buf) {
|
|
|
|
|
|
if n > 0 && n < 8 * self.panels as usize {
|
2022-11-05 12:15:42 -04:00
|
|
|
|
// if less are read, that indicates end of file after
|
2022-11-27 17:14:30 -05:00
|
|
|
|
if is_empty {
|
|
|
|
|
|
self.print_header()?;
|
2022-10-13 13:38:41 -04:00
|
|
|
|
is_empty = false;
|
2022-11-27 17:14:30 -05:00
|
|
|
|
}
|
2022-11-05 12:03:49 -04:00
|
|
|
|
|
2022-11-04 18:24:48 -04:00
|
|
|
|
// perform second check on read
|
|
|
|
|
|
if let Ok(0) = buf.read(&mut self.line_buf[n..]) {
|
|
|
|
|
|
self.line_buf.resize(n, 0);
|
2022-11-05 12:03:49 -04:00
|
|
|
|
break Some(n);
|
2022-11-04 18:24:48 -04:00
|
|
|
|
};
|
2022-10-13 13:38:41 -04:00
|
|
|
|
} else if n == 0 {
|
2022-11-05 12:15:42 -04:00
|
|
|
|
// if no bytes are read, that indicates end of file
|
2022-10-15 09:12:29 -04:00
|
|
|
|
if self.squeezer == Squeezer::Delete {
|
2022-11-05 12:15:42 -04:00
|
|
|
|
// empty the last line when ending is squeezed
|
2022-10-15 09:12:29 -04:00
|
|
|
|
self.line_buf.clear();
|
2022-11-05 12:03:49 -04:00
|
|
|
|
break Some(0);
|
2022-10-15 09:12:29 -04:00
|
|
|
|
}
|
2022-11-05 12:03:49 -04:00
|
|
|
|
break None;
|
2022-10-13 10:55:49 -04:00
|
|
|
|
}
|
2022-10-07 17:28:35 -04:00
|
|
|
|
}
|
2022-11-27 17:14:30 -05:00
|
|
|
|
if is_empty {
|
|
|
|
|
|
self.print_header()?;
|
2022-10-13 10:55:49 -04:00
|
|
|
|
is_empty = false;
|
2022-11-27 17:14:30 -05:00
|
|
|
|
}
|
2022-10-13 10:55:49 -04:00
|
|
|
|
|
2022-11-05 12:15:42 -04:00
|
|
|
|
// squeeze is active, check if the line is the same
|
|
|
|
|
|
// skip print if still squeezed, otherwise print and deactivate squeeze
|
2022-11-05 11:45:19 -04:00
|
|
|
|
if matches!(self.squeezer, Squeezer::Print | Squeezer::Delete) {
|
2022-11-04 18:24:48 -04:00
|
|
|
|
if self
|
|
|
|
|
|
.line_buf
|
|
|
|
|
|
.chunks_exact(std::mem::size_of::<usize>())
|
2022-11-05 11:45:19 -04:00
|
|
|
|
.all(|w| usize::from_ne_bytes(w.try_into().unwrap()) == self.squeeze_byte)
|
2022-10-13 10:59:33 -04:00
|
|
|
|
{
|
2022-11-05 12:03:49 -04:00
|
|
|
|
if self.squeezer == Squeezer::Delete {
|
2022-10-13 10:55:49 -04:00
|
|
|
|
self.idx += 8 * self.panels;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
self.squeezer = Squeezer::Ignore;
|
|
|
|
|
|
}
|
2022-10-07 17:28:35 -04:00
|
|
|
|
}
|
2022-11-05 12:15:42 -04:00
|
|
|
|
|
|
|
|
|
|
// print the line
|
2022-10-13 13:43:47 -04:00
|
|
|
|
self.print_position_panel()?;
|
2022-10-13 10:55:49 -04:00
|
|
|
|
self.print_bytes()?;
|
|
|
|
|
|
if self.show_char_panel {
|
|
|
|
|
|
self.print_char_panel()?;
|
|
|
|
|
|
}
|
2022-10-13 10:59:33 -04:00
|
|
|
|
self.writer.write_all(b"\n")?;
|
2022-10-13 10:55:49 -04:00
|
|
|
|
|
2022-11-05 12:15:42 -04:00
|
|
|
|
// increment index to next line
|
2022-10-13 10:59:33 -04:00
|
|
|
|
self.idx += 8 * self.panels;
|
2022-10-13 11:07:12 -04:00
|
|
|
|
|
2022-11-05 12:15:42 -04:00
|
|
|
|
// change from print to delete if squeeze is still active
|
2022-11-05 12:03:49 -04:00
|
|
|
|
if self.squeezer == Squeezer::Print {
|
2022-10-13 10:55:49 -04:00
|
|
|
|
self.squeezer = Squeezer::Delete;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-05 12:15:42 -04:00
|
|
|
|
// repeat the first byte in the line until it's a usize
|
|
|
|
|
|
// compare that usize with each usize chunk in the line
|
|
|
|
|
|
// if they are all the same, change squeezer to print
|
2022-11-05 12:08:13 -04:00
|
|
|
|
let repeat_byte = (self.line_buf[0] as usize) * (usize::MAX / 255);
|
2022-10-13 10:55:49 -04:00
|
|
|
|
if !matches!(self.squeezer, Squeezer::Disabled | Squeezer::Delete)
|
2022-11-05 12:08:13 -04:00
|
|
|
|
&& self
|
|
|
|
|
|
.line_buf
|
|
|
|
|
|
.chunks_exact(std::mem::size_of::<usize>())
|
|
|
|
|
|
.all(|w| usize::from_ne_bytes(w.try_into().unwrap()) == repeat_byte)
|
2022-10-13 10:55:49 -04:00
|
|
|
|
{
|
|
|
|
|
|
self.squeezer = Squeezer::Print;
|
2022-11-05 12:08:13 -04:00
|
|
|
|
self.squeeze_byte = repeat_byte;
|
2022-10-13 10:55:49 -04:00
|
|
|
|
};
|
2022-11-05 12:03:49 -04:00
|
|
|
|
};
|
2022-10-07 17:28:35 -04:00
|
|
|
|
|
|
|
|
|
|
// special ending
|
|
|
|
|
|
|
|
|
|
|
|
if is_empty {
|
2022-11-27 17:14:30 -05:00
|
|
|
|
self.base_digits = 2;
|
|
|
|
|
|
self.print_header()?;
|
2022-05-22 14:14:07 -05:00
|
|
|
|
if self.show_position_panel {
|
2022-10-07 17:28:35 -04:00
|
|
|
|
write!(self.writer, "{0:9}", "│")?;
|
2022-04-22 15:33:26 -05:00
|
|
|
|
}
|
|
|
|
|
|
write!(
|
2020-11-01 21:04:39 +01:00
|
|
|
|
self.writer,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
"{0:2}{1:2$}{0}{0:>3$}",
|
|
|
|
|
|
"│",
|
|
|
|
|
|
"No content",
|
|
|
|
|
|
self.panel_sz() - 1,
|
|
|
|
|
|
self.panel_sz() + 1,
|
2022-10-13 10:55:49 -04:00
|
|
|
|
)?;
|
2022-05-22 14:14:07 -05:00
|
|
|
|
if self.show_char_panel {
|
2022-10-07 17:28:35 -04:00
|
|
|
|
write!(self.writer, "{0:>9}{0:>9}", "│")?;
|
|
|
|
|
|
}
|
|
|
|
|
|
writeln!(self.writer)?;
|
2022-10-13 13:38:41 -04:00
|
|
|
|
} else if let Some(n) = leftover {
|
|
|
|
|
|
// last line is incomplete
|
2022-10-13 13:43:47 -04:00
|
|
|
|
self.print_position_panel()?;
|
2022-10-15 08:57:50 -04:00
|
|
|
|
self.squeezer = Squeezer::Ignore;
|
2022-10-13 13:38:41 -04:00
|
|
|
|
self.print_bytes()?;
|
|
|
|
|
|
self.squeezer = Squeezer::Print;
|
|
|
|
|
|
for i in n..8 * self.panels as usize {
|
|
|
|
|
|
self.print_byte(i, 0)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
if self.show_char_panel {
|
|
|
|
|
|
self.squeezer = Squeezer::Ignore;
|
|
|
|
|
|
self.print_char_panel()?;
|
|
|
|
|
|
self.squeezer = Squeezer::Print;
|
|
|
|
|
|
for i in n..8 * self.panels as usize {
|
|
|
|
|
|
self.print_char(i as u64)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
self.writer.write_all(b"\n")?;
|
2019-07-14 21:31:51 +01:00
|
|
|
|
}
|
2022-10-07 17:28:35 -04:00
|
|
|
|
|
2022-10-07 19:54:07 -04:00
|
|
|
|
self.print_footer()?;
|
2019-07-14 21:31:51 +01:00
|
|
|
|
|
2022-10-07 17:28:35 -04:00
|
|
|
|
self.writer.flush()?;
|
|
|
|
|
|
|
2019-07-14 21:31:51 +01:00
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
|
mod tests {
|
|
|
|
|
|
use std::io;
|
|
|
|
|
|
use std::str;
|
|
|
|
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
2022-04-22 15:59:10 -05:00
|
|
|
|
fn assert_print_all_output<Reader: Read>(input: Reader, expected_string: String) {
|
2019-07-14 21:31:51 +01:00
|
|
|
|
let mut output = vec![];
|
2022-07-12 11:49:50 -04:00
|
|
|
|
let mut printer = Printer::new(
|
|
|
|
|
|
&mut output,
|
|
|
|
|
|
false,
|
|
|
|
|
|
true,
|
|
|
|
|
|
true,
|
|
|
|
|
|
BorderStyle::Unicode,
|
|
|
|
|
|
true,
|
|
|
|
|
|
2,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
1,
|
2022-11-27 17:13:36 -05:00
|
|
|
|
Base::Hexadecimal,
|
2022-07-12 11:49:50 -04:00
|
|
|
|
);
|
2019-07-14 21:31:51 +01:00
|
|
|
|
|
2020-03-09 20:23:46 +01:00
|
|
|
|
printer.print_all(input).unwrap();
|
2019-07-14 21:31:51 +01:00
|
|
|
|
|
|
|
|
|
|
let actual_string: &str = str::from_utf8(&output).unwrap();
|
2022-04-22 15:33:26 -05:00
|
|
|
|
assert_eq!(actual_string, expected_string,)
|
2019-07-14 21:31:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn empty_file_passes() {
|
|
|
|
|
|
let input = io::empty();
|
2020-05-28 10:21:04 -06:00
|
|
|
|
let expected_string = "\
|
|
|
|
|
|
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
|
2022-10-03 20:52:57 +08:00
|
|
|
|
│ │ No content │ │ │ │
|
2019-07-14 21:31:51 +01:00
|
|
|
|
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
|
2019-10-07 19:20:02 +01:00
|
|
|
|
"
|
2020-05-28 10:21:04 -06:00
|
|
|
|
.to_owned();
|
2019-07-14 21:31:51 +01:00
|
|
|
|
assert_print_all_output(input, expected_string);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn short_input_passes() {
|
|
|
|
|
|
let input = io::Cursor::new(b"spam");
|
2020-05-28 10:21:04 -06:00
|
|
|
|
let expected_string = "\
|
|
|
|
|
|
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
|
2019-10-01 13:00:09 -04:00
|
|
|
|
│00000000│ 73 70 61 6d ┊ │spam ┊ │
|
2019-07-14 21:31:51 +01:00
|
|
|
|
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
|
2019-10-07 19:20:02 +01:00
|
|
|
|
"
|
2020-05-28 10:21:04 -06:00
|
|
|
|
.to_owned();
|
2019-07-14 21:31:51 +01:00
|
|
|
|
assert_print_all_output(input, expected_string);
|
|
|
|
|
|
}
|
2019-10-07 19:20:02 +01:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn display_offset() {
|
|
|
|
|
|
let input = io::Cursor::new(b"spamspamspamspamspam");
|
2020-05-28 10:21:04 -06:00
|
|
|
|
let expected_string = "\
|
|
|
|
|
|
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
|
2019-10-07 19:20:02 +01:00
|
|
|
|
│deadbeef│ 73 70 61 6d 73 70 61 6d ┊ 73 70 61 6d 73 70 61 6d │spamspam┊spamspam│
|
|
|
|
|
|
│deadbeff│ 73 70 61 6d ┊ │spam ┊ │
|
|
|
|
|
|
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
|
|
|
|
|
|
"
|
2020-05-28 10:21:04 -06:00
|
|
|
|
.to_owned();
|
2019-10-07 19:20:02 +01:00
|
|
|
|
|
|
|
|
|
|
let mut output = vec![];
|
2022-07-12 11:49:50 -04:00
|
|
|
|
let mut printer: Printer<Vec<u8>> = Printer::new(
|
|
|
|
|
|
&mut output,
|
|
|
|
|
|
false,
|
|
|
|
|
|
true,
|
|
|
|
|
|
true,
|
|
|
|
|
|
BorderStyle::Unicode,
|
|
|
|
|
|
true,
|
|
|
|
|
|
2,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
1,
|
2022-11-27 17:13:36 -05:00
|
|
|
|
Base::Hexadecimal,
|
2022-07-12 11:49:50 -04:00
|
|
|
|
);
|
2019-10-07 19:20:02 +01:00
|
|
|
|
printer.display_offset(0xdeadbeef);
|
|
|
|
|
|
|
2020-03-09 20:23:46 +01:00
|
|
|
|
printer.print_all(input).unwrap();
|
2019-10-07 19:20:02 +01:00
|
|
|
|
|
|
|
|
|
|
let actual_string: &str = str::from_utf8(&output).unwrap();
|
|
|
|
|
|
assert_eq!(actual_string, expected_string)
|
|
|
|
|
|
}
|
2022-07-17 13:37:25 -04:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
2022-09-05 09:51:34 -04:00
|
|
|
|
fn multiple_panels() {
|
2022-07-17 13:37:25 -04:00
|
|
|
|
let input = io::Cursor::new(b"supercalifragilisticexpialidocioussupercalifragilisticexpialidocioussupercalifragilisticexpialidocious");
|
|
|
|
|
|
let expected_string = "\
|
|
|
|
|
|
┌────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┬────────┬────────┬────────┬────────┐
|
|
|
|
|
|
│00000000│ 73 75 70 65 72 63 61 6c ┊ 69 66 72 61 67 69 6c 69 ┊ 73 74 69 63 65 78 70 69 ┊ 61 6c 69 64 6f 63 69 6f │supercal┊ifragili┊sticexpi┊alidocio│
|
|
|
|
|
|
│00000020│ 75 73 73 75 70 65 72 63 ┊ 61 6c 69 66 72 61 67 69 ┊ 6c 69 73 74 69 63 65 78 ┊ 70 69 61 6c 69 64 6f 63 │ussuperc┊alifragi┊listicex┊pialidoc│
|
|
|
|
|
|
│00000040│ 69 6f 75 73 73 75 70 65 ┊ 72 63 61 6c 69 66 72 61 ┊ 67 69 6c 69 73 74 69 63 ┊ 65 78 70 69 61 6c 69 64 │ioussupe┊rcalifra┊gilistic┊expialid│
|
|
|
|
|
|
│00000060│ 6f 63 69 6f 75 73 ┊ ┊ ┊ │ocious ┊ ┊ ┊ │
|
|
|
|
|
|
└────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┴────────┴────────┴────────┴────────┘
|
|
|
|
|
|
"
|
|
|
|
|
|
.to_owned();
|
|
|
|
|
|
|
|
|
|
|
|
let mut output = vec![];
|
|
|
|
|
|
let mut printer: Printer<Vec<u8>> = Printer::new(
|
|
|
|
|
|
&mut output,
|
|
|
|
|
|
false,
|
|
|
|
|
|
true,
|
|
|
|
|
|
true,
|
|
|
|
|
|
BorderStyle::Unicode,
|
|
|
|
|
|
true,
|
|
|
|
|
|
4,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
1,
|
2022-11-27 17:13:36 -05:00
|
|
|
|
Base::Hexadecimal,
|
2022-07-17 13:37:25 -04:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
printer.print_all(input).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
let actual_string: &str = str::from_utf8(&output).unwrap();
|
|
|
|
|
|
assert_eq!(actual_string, expected_string)
|
|
|
|
|
|
}
|
2022-11-04 18:23:27 -04:00
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn squeeze_works() {
|
|
|
|
|
|
let input = io::Cursor::new(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");
|
|
|
|
|
|
let expected_string = "\
|
|
|
|
|
|
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
|
|
|
|
|
|
│00000000│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │00000000┊00000000│
|
|
|
|
|
|
│* │ ┊ │ ┊ │
|
|
|
|
|
|
│00000020│ 00 ┊ │0 ┊ │
|
|
|
|
|
|
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
|
|
|
|
|
|
"
|
|
|
|
|
|
.to_owned();
|
|
|
|
|
|
assert_print_all_output(input, expected_string);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn squeeze_nonzero() {
|
|
|
|
|
|
let input = io::Cursor::new(b"000000000000000000000000000000000");
|
|
|
|
|
|
let expected_string = "\
|
|
|
|
|
|
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
|
|
|
|
|
|
│00000000│ 30 30 30 30 30 30 30 30 ┊ 30 30 30 30 30 30 30 30 │00000000┊00000000│
|
|
|
|
|
|
│* │ ┊ │ ┊ │
|
|
|
|
|
|
│00000020│ 30 ┊ │0 ┊ │
|
|
|
|
|
|
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
|
|
|
|
|
|
"
|
|
|
|
|
|
.to_owned();
|
|
|
|
|
|
assert_print_all_output(input, expected_string);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn squeeze_multiple_panels() {
|
|
|
|
|
|
let input = io::Cursor::new(b"0000000000000000000000000000000000000000000000000");
|
|
|
|
|
|
let expected_string = "\
|
|
|
|
|
|
┌────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┬────────┬────────┬────────┐
|
|
|
|
|
|
│00000000│ 30 30 30 30 30 30 30 30 ┊ 30 30 30 30 30 30 30 30 ┊ 30 30 30 30 30 30 30 30 │00000000┊00000000┊00000000│
|
|
|
|
|
|
│* │ ┊ ┊ │ ┊ ┊ │
|
|
|
|
|
|
│00000030│ 30 ┊ ┊ │0 ┊ ┊ │
|
|
|
|
|
|
└────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┴────────┴────────┴────────┘
|
|
|
|
|
|
"
|
|
|
|
|
|
.to_owned();
|
|
|
|
|
|
|
|
|
|
|
|
let mut output = vec![];
|
|
|
|
|
|
let mut printer: Printer<Vec<u8>> = Printer::new(
|
|
|
|
|
|
&mut output,
|
|
|
|
|
|
false,
|
|
|
|
|
|
true,
|
|
|
|
|
|
true,
|
|
|
|
|
|
BorderStyle::Unicode,
|
|
|
|
|
|
true,
|
|
|
|
|
|
3,
|
2022-10-03 20:52:57 +08:00
|
|
|
|
1,
|
2022-11-27 17:13:36 -05:00
|
|
|
|
Base::Hexadecimal,
|
2022-11-04 18:23:27 -04:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
printer.print_all(input).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
let actual_string: &str = str::from_utf8(&output).unwrap();
|
|
|
|
|
|
assert_eq!(actual_string, expected_string)
|
|
|
|
|
|
}
|
2019-07-14 17:38:30 +01:00
|
|
|
|
}
|