Implement character table control and codepage 437 option

This commit is contained in:
Sharif Haason committed 2023-12-10 13:21:23 -05:00
1 parent 663e4c19ff
commit 6a230d34a4
2 files changed
+80 -5

No files matched your search

+56 -4
View File
@@ -21,6 +21,29 @@ const COLOR_ASCII_OTHER: &[u8] = colors::Green::ANSI_FG.as_bytes();
const COLOR_NONASCII: &[u8] = colors::Yellow::ANSI_FG.as_bytes(); const COLOR_NONASCII: &[u8] = colors::Yellow::ANSI_FG.as_bytes();
const COLOR_RESET: &[u8] = colors::Default::ANSI_FG.as_bytes(); const COLOR_RESET: &[u8] = colors::Default::ANSI_FG.as_bytes();
#[rustfmt::skip]
const CP437: [char; 256] = [
// use https://en.wikipedia.org/w/index.php?title=Code_page_437&oldid=978947122
// not ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT
// because we want the graphic versions of 01h–1Fh + 7Fh
'⋄','☺','☻','♥','♦','♣','♠','•','◘','○','◙','♂','♀','♪','♫','☼',
'►','◄','↕','‼','¶','§','▬','↨','↑','↓','→','←','∟','↔','▲','▼',
' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/',
'0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
'@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_',
'`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~','⌂',
'Ç','ü','é','â','ä','à','å','ç','ê','ë','è','ï','î','ì','Ä','Å',
'É','æ','Æ','ô','ö','ò','û','ù','ÿ','Ö','Ü','¢','£','¥','₧','ƒ',
'á','í','ó','ú','ñ','Ñ','ª','º','¿','⌐','¬','½','¼','¡','«','»',
'░','▒','▓','│','┤','╡','╢','╖','╕','╣','║','╗','╝','╜','╛','┐',
'└','┴','┬','├','─','┼','╞','╟','╚','╔','╩','╦','╠','═','╬','╧',
'╨','╤','╥','╙','╘','╒','╓','╫','╪','┘','┌','█','▄','▌','▐','▀',
'α','ß','Γ','π','Σ','σ','µ','τ','Φ','Θ','Ω','δ','∞','φ','ε','∩',
'≡','±','≥','≤','⌠','⌡','÷','≈','°','∙','·','√','ⁿ','²','■',' ',
];
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum ByteCategory { pub enum ByteCategory {
Null, Null,
@@ -30,6 +53,12 @@ pub enum ByteCategory {
NonAscii, NonAscii,
} }
#[derive(Copy, Clone)]
pub enum CharTable {
AsciiOnly,
CP437,
}
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum Endianness { pub enum Endianness {
Little, Little,
@@ -74,17 +103,27 @@ impl Byte {
} }
} }
fn as_char(self) -> char { fn as_char(self, char_table: CharTable) -> char {
use crate::ByteCategory::*; use crate::ByteCategory::*;
match char_table {
match self.category() { CharTable::AsciiOnly => match self.category() {
Null => '⋄', Null => '⋄',
AsciiPrintable => self.0 as char, AsciiPrintable => self.0 as char,
AsciiWhitespace if self.0 == 0x20 => ' ', AsciiWhitespace if self.0 == 0x20 => ' ',
AsciiWhitespace => '_', AsciiWhitespace => '_',
AsciiOther => '•', AsciiOther => '•',
NonAscii => '×', NonAscii => '×',
},
CharTable::CP437 => CP437[self.0.to_ne_bytes()[0] as usize],
} }
// match self.category() {
// Null => '⋄',
// AsciiPrintable => self.0 as char,
// AsciiWhitespace if self.0 == 0x20 => ' ',
// AsciiWhitespace => '_',
// AsciiOther => '•',
// NonAscii => '×',
// }
} }
} }
@@ -167,6 +206,7 @@ pub struct PrinterBuilder<'a, Writer: Write> {
group_size: u8, group_size: u8,
base: Base, base: Base,
endianness: Endianness, endianness: Endianness,
char_table: CharTable,
} }
impl<'a, Writer: Write> PrinterBuilder<'a, Writer> { impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
@@ -182,6 +222,7 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
group_size: 1, group_size: 1,
base: Base::Hexadecimal, base: Base::Hexadecimal,
endianness: Endianness::Big, endianness: Endianness::Big,
char_table: CharTable::AsciiOnly,
} }
} }
@@ -230,6 +271,11 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
self self
} }
pub fn char_table(mut self, char_table: CharTable) -> Self {
self.char_table = char_table;
self
}
pub fn build(self) -> Printer<'a, Writer> { pub fn build(self) -> Printer<'a, Writer> {
Printer::new( Printer::new(
self.writer, self.writer,
@@ -242,6 +288,7 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
self.group_size, self.group_size,
self.base, self.base,
self.endianness, self.endianness,
self.char_table,
) )
} }
} }
@@ -285,6 +332,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
group_size: u8, group_size: u8,
base: Base, base: Base,
endianness: Endianness, endianness: Endianness,
char_table: CharTable,
) -> Printer<'a, Writer> { ) -> Printer<'a, Writer> {
Printer { Printer {
idx: 0, idx: 0,
@@ -304,7 +352,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
}) })
.collect(), .collect(),
byte_char_panel: (0u8..=u8::MAX) byte_char_panel: (0u8..=u8::MAX)
.map(|i| format!("{}", Byte(i).as_char())) .map(|i| format!("{}", Byte(i).as_char(char_table)))
.collect(), .collect(),
byte_hex_panel_g: (0u8..=u8::MAX).map(|i| format!("{i:02x}")).collect(), byte_hex_panel_g: (0u8..=u8::MAX).map(|i| format!("{i:02x}")).collect(),
squeezer: if use_squeeze { squeezer: if use_squeeze {
@@ -732,6 +780,7 @@ mod tests {
1, 1,
Base::Hexadecimal, Base::Hexadecimal,
Endianness::Big, Endianness::Big,
CharTable::AsciiOnly,
); );
printer.print_all(input).unwrap(); printer.print_all(input).unwrap();
@@ -787,6 +836,7 @@ mod tests {
1, 1,
Base::Hexadecimal, Base::Hexadecimal,
Endianness::Big, Endianness::Big,
CharTable::AsciiOnly,
); );
printer.display_offset(0xdeadbeef); printer.display_offset(0xdeadbeef);
@@ -821,6 +871,7 @@ mod tests {
1, 1,
Base::Hexadecimal, Base::Hexadecimal,
Endianness::Big, Endianness::Big,
CharTable::AsciiOnly,
); );
printer.print_all(input).unwrap(); printer.print_all(input).unwrap();
@@ -881,6 +932,7 @@ mod tests {
1, 1,
Base::Hexadecimal, Base::Hexadecimal,
Endianness::Big, Endianness::Big,
CharTable::AsciiOnly,
); );
printer.print_all(input).unwrap(); printer.print_all(input).unwrap();
+24 -1
View File
@@ -17,7 +17,7 @@ use thiserror::Error as ThisError;
use terminal_size::terminal_size; use terminal_size::terminal_size;
use hexyl::{Base, BorderStyle, Endianness, Input, PrinterBuilder}; use hexyl::{Base, BorderStyle, CharTable, Endianness, Input, PrinterBuilder};
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@@ -212,6 +212,17 @@ fn run() -> Result<()> {
.hide(true) .hide(true)
.help("An alias for '--endianness=little'."), .help("An alias for '--endianness=little'."),
) )
.arg(
Arg::new("character_table")
.long("character_table")
.value_name("FORMAT")
.value_parser(["codepage-437", "ascii-only"])
.help(
"The character table that should be used. 'ascii-only' \
will show dots for non-ASCII characters, and 'codepage-437 \
will use Code page 437 for those characters."
),
)
.arg( .arg(
Arg::new("base") Arg::new("base")
.short('b') .short('b')
@@ -469,6 +480,17 @@ fn run() -> Result<()> {
("big", _) => Endianness::Big, ("big", _) => Endianness::Big,
_ => unreachable!(), _ => unreachable!(),
}; };
let char_table = match matches
.get_one::<String>("character_table")
.unwrap_or(&String::from("ascii-only"))
.as_ref()
{
"ascii-only" => CharTable::AsciiOnly,
"codepage-437" => CharTable::CP437,
_ => unreachable!(),
};
let stdout = io::stdout(); let stdout = io::stdout();
let mut stdout_lock = BufWriter::new(stdout.lock()); let mut stdout_lock = BufWriter::new(stdout.lock());
@@ -482,6 +504,7 @@ fn run() -> Result<()> {
.group_size(group_size) .group_size(group_size)
.with_base(base) .with_base(base)
.endianness(endianness) .endianness(endianness)
.char_table(char_table)
.build(); .build();
printer.display_offset(skip_offset + display_offset); printer.display_offset(skip_offset + display_offset);
printer.print_all(&mut reader).map_err(|e| anyhow!(e))?; printer.print_all(&mut reader).map_err(|e| anyhow!(e))?;