diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Cargo.toml | 20 | ||||
-rw-r--r-- | main.rs | 140 |
3 files changed, 162 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa8d85a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..673a8a6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[package] + +name = "hexedit" +version = "0.0.1" +authors = [ "iximeow <me@iximeow.net>" ] +license = "MIT" +repository = "lol" +description = """ +A nice hex editor. +""" + +[[bin]] +name = "hexedit" +path = "main.rs" +test = false +bench = false + +[dependencies] +"terminal_size" = "0.1.7" +"termios" = "0.2.2" @@ -0,0 +1,140 @@ +use std::io; +use std::io::{Seek, SeekFrom}; +use std::fs; +use std::fmt::Write; +use std::io::Read; +use std::env; +use std::path::Path; + +extern crate termios; +use termios::{Termios, TCSANOW, ECHO, ICANON, tcsetattr}; + +extern crate terminal_size; +use terminal_size::{Width, Height, terminal_size}; + +fn main() { + println!("hello"); + if let Some((Width(w), Height(h))) = terminal_size() { + if let Some(arg1) = env::args().nth(1) { + println!("You would like to work with {}.", arg1); + launch_interface(w, h, &arg1); + } else { + usage(); + } + } else { + println!("Wasn't able to get terminal dimensions for some reason"); + } +} + +fn usage() { + println!("usage: this_thing filename"); +} + +fn launch_interface(w: u16, h: u16, filename: &String) { + println!("Launching interface with width {} and height {}...", w, h); + + // 4 = columns per group, 3 = xx xx xx xx , ... + // + (x + 7) / 8 is for ascii at the end of line, rounded up to 8 characters + // width = 8-20 + (3 * 4) * x + (x + 7) / 8 + // 8 * width = 87 + 57x + // x = (8 * width - 87) / 57 + let hex_cols = (w * 8 - 87) / 57; + println!("0x________: {} {}", hex_cols, hex_cols); + match fs::metadata(&filename) { + Ok(fs_meta) => { + println!("{} is {} bytes, and is it readable? {}", filename, fs_meta.len(), true); + let termios = Termios::from_fd(0).unwrap(); + + let mut new_termios = termios.clone(); + // fix terminal to not echo, thanks + new_termios.c_lflag &= !(ICANON | ECHO); + tcsetattr(0, TCSANOW, &mut new_termios).unwrap(); + + interface_loop(w, h, filename); + + tcsetattr(0, TCSANOW, &termios).unwrap(); + }, + Err(e) => + println!("{} does not exist.", filename), + } +} + +fn interface_loop(w: u16, h: u16, filename: &String) { + let mut cursor: u64 = 0; + let mut buffer = [0; 0x200]; + populate_buf(filename, cursor, &mut buffer); + render_interface(w, h, cursor, &buffer); + + let stdin = io::stdin(); + + for byte in stdin.lock().bytes() { + match byte { + Ok(value) => { + render_interface(w, h, cursor, &buffer); + }, + Err(e) => { + println!("Err: {}", e); + } + } + } +} + +fn ascii_or_dot(c: u8) -> u8 { + let u = c as char; + if (u >= 'a' && u <= 'z' || u >= '0' && u <= '9' || u >= 'A' && u <= 'Z' || u == '~' || u == '!' || u == '@' || u == '#' || u == '$' || u == '%' || u == '^' || u == '&' || u == '*' || u == '(' || u == ')' || u == '_' || u == '+' || u == '{' || u == '}' || u == '|' || u == ':' || u == '"' || u == '>' || u == '?' || u == '-' || u == '=' || u == '[' || u == ']' || u == '\\' || u == ';' || u == '\'' || u == '.' || u == '/' || u == '<' || u == ',' || u == '`') { c } else { '.' as u8 } +} + +fn render_interface(w: u16, h: u16, cursor: u64, buffer: &[u8]) { + println!("Dimensions: {}x{} Cursor: {} cursor_pos: ({}, {})", w, h, cursor, 0, 0); + let addr_width = 8; + // w = 10 + 1 + 1 + 4 * 3 * x + x + 1 + 4 * x + // w = 13 + 17 * x + // w - 13 / 17 = x + let cols = (w - 13) / 17; + let col_width = 4; +// let ascii = bytes_width * cols; + + let mut idx: usize = 0; + for i in 1..(h-1) { + let mut hex_line = String::new(); + let mut ascii_line = String::new(); + for col in 0..cols { + for c in 0..col_width { + if (idx < buffer.len()) { + let chr = buffer[idx]; + write!(&mut hex_line, "{:02x} ", chr).unwrap(); + write!(&mut ascii_line, "{}", ascii_or_dot(chr) as char).unwrap(); + } else { + write!(&mut hex_line, " ").unwrap(); + write!(&mut ascii_line, " ").unwrap(); + } + idx += 1; + } + write!(&mut hex_line, " ").unwrap(); + } + + let lineaddr = ((i as u64) - 1) * (cols as u64 * 4); + let addr = if (lineaddr as usize) < buffer.len() { + format!("0x{:08x}:", lineaddr) + } else { + " ".to_string() + }; + println!("{} {} {}", addr, hex_line, ascii_line); + } +} + +fn populate_buf(arg: &String, cursor: u64, buffer: &mut [u8]) { + match fs::File::open(&arg) { + Ok(mut fd) => { + /*..*/ + fd.seek(SeekFrom::Start(cursor)); + fd.read(buffer); + for b in buffer.into_iter() { + print!("{:02x}", b); + } + println!(""); + }, + Err(_) => + println!("Failed to open {}", arg) + } +} |