summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Wortman <me@iximeow.net>2017-07-08 13:31:20 -0700
committerAndy Wortman <me@iximeow.net>2017-07-08 13:31:20 -0700
commit3b3028f90e99ae4ec573fe6ff8d1755fe5718e91 (patch)
tree98608c508b85c42314eeef2218a7b2c90de73078
initial commit (lol)
-rw-r--r--.gitignore2
-rw-r--r--Cargo.toml20
-rw-r--r--main.rs140
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"
diff --git a/main.rs b/main.rs
new file mode 100644
index 0000000..fa22374
--- /dev/null
+++ b/main.rs
@@ -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)
+ }
+}