diff --git a/src/bin/convert_from_baillie.rs b/src/bin/convert_from_baillie.rs new file mode 100644 index 0000000..5e9d353 --- /dev/null +++ b/src/bin/convert_from_baillie.rs @@ -0,0 +1,105 @@ +use std::{env, process::exit}; + +use binary_braillie::binary_braillie_to_bytes; + +mod common; +use common::argument_parsing; + +fn main() { + let args = parse_args(); + if args.value_to_convert.len() <= 0 { + print!("{}: No input specified!", args.program_name) + } + let decoded_ = binary_braillie_to_bytes( + if !args.reverse_characters { + args.value_to_convert + } else { + args.value_to_convert.chars().rev().collect() + }, + args.mode.try_into().unwrap() + ); + + let decoded = match decoded_ { + Ok(e) => e, + Err(()) => { + print!("{}: Invalid input provided", args.program_name); + exit(128); + } + }; + + if args.hexadecimal { + print!("{}", hex::encode(decoded)); + } else { + print!("{}", match String::from_utf8(decoded) { + Ok(e) => e, + Err(e) => { + print!("{}: decoded string is invalid: {}", args.program_name, e.utf8_error()); + exit(130); + } + }); + } +} + +fn parse_args() -> argument_parsing::Arguments { + let mut args = env::args().peekable(); + let mut rvalue = argument_parsing::Arguments { + hexadecimal: false, + mode: 0, + program_name: args.next().unwrap_or(String::from("t2br")), + reverse_characters: false, + value_to_convert: String::new() + }; + let program_name = &rvalue.program_name; + + while args.peek() != None { + let arg = args.next().unwrap(); + if arg == "--help" + || arg == "-h" + || arg == "-?" + { + print_help(rvalue.program_name); + exit(1); + } + else if arg == "--hex" { + rvalue.hexadecimal = true; + } + else if arg == "--direction" { + match argument_parsing::parse_direction(&mut args, &rvalue, arg) { + Ok(e) => rvalue.mode = e, + Err(e) => { + print!("{}: {}", program_name, e); + exit(64); + } + } + } + else if arg == "--wrap" { + match argument_parsing::parse_wrap(&mut args, &rvalue, arg) { + Ok(e) => rvalue.mode = e, + Err(e) => { + print!("{}: {}", program_name, e); + exit(65); + } + } + } + else if arg == "-r" + || arg == "--reverse" { + rvalue.reverse_characters = true; + } + else { + rvalue.value_to_convert.push_str(&arg); + } + } + return rvalue; +} + +fn print_help(program_name: String) { + print!("Usage: {program_name} [options] \n"); + print!("Convert binary represented in braillie characters to readable text\n\n"); + print!(" --hex convert to hexadecimal instead of text\n\n"); + print!(" --direction [mode] direction of bits per character\n"); + print!(" possible values: row, row-reverse, column, column-reverse\n\n"); + print!(" --wrap [mode] direction of bits wrapping per character\n"); + print!(" possible values: normal, reverse\n\n"); + print!(" -r, --reverse reverse outputted characters\n\n"); + print!(" -h, -?, --help display this help and exit"); +} diff --git a/src/lib.rs b/src/lib.rs index 25149a1..23c9c9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,9 +81,49 @@ pub fn to_binary_braillie_str(input: impl AsRef, mode: EncodeOrientation) - return to_binary_braillie(input.as_ref().as_bytes(), input.as_ref().len(), mode); } +pub fn binary_braillie_char_to_index(input: char, mode: EncodeOrientation) -> Result{ + if !(0x2800 <= input as u32 && input as u32 <= 0x28ff) { return Err(()) } + let mapping = MAPPINGS[mode as usize]; + let _index: u8 = (input as u32 - 0x2800) as u8; + return Ok( + ((_index >> mapping[7]) & 1) << 0 + | ((_index >> mapping[6]) & 1) << 1 + | ((_index >> mapping[5]) & 1) << 2 + | ((_index >> mapping[4]) & 1) << 3 + | ((_index >> mapping[3]) & 1) << 4 + | ((_index >> mapping[2]) & 1) << 5 + | ((_index >> mapping[1]) & 1) << 6 + | ((_index >> mapping[0]) & 1) << 7 + ); +} + +pub fn binary_braillie_to_bytes( + input: impl AsRef, + mode: EncodeOrientation +) -> Result, ()> { + let mut rvalue: Vec = Vec::with_capacity(input.as_ref().chars().count()); + for char in input.as_ref().chars() { + rvalue.push(match binary_braillie_char_to_index(char, mode) { + Ok(e) => e, + Err(e) => return Err(e), + }) + } + return Ok(rvalue); +} + +pub fn binary_braillie_to_str(input: impl AsRef, mode: EncodeOrientation) -> Result { + let bytes = match binary_braillie_to_bytes(input, mode) { + Ok(e) => e, + Err(e) => return Err(e) + }; + return match String::from_utf8(bytes) { + Ok(e) => Ok(e), + Err(_e) => Err(()) + } +} #[cfg(test)] -mod test_lib { +mod test_lib_to_braillie { use crate::{index_to_braillie_char, to_binary_braillie_str, EncodeOrientation}; #[test] @@ -146,3 +186,79 @@ mod test_lib { ); } } + +#[cfg(test)] +mod test_lib_from_braillie { + use crate::{binary_braillie_char_to_index, EncodeOrientation}; + + #[test] + fn check_characters_out_of_range() { + for i in 0..0x10ffff { + if 0x2800 <= i && i <= 0x28ff { continue; }; + let char = match char::from_u32(i) { + Some(c) => c, + // Continue for invalid characters + None => continue, + }; + binary_braillie_char_to_index(char, EncodeOrientation::Rows) + .expect_err("Expected error for invalid char"); + } + } + + #[test] + fn check_characters_in_range() { + for _char in 0x2800..0x28ff { + let char = char::from_u32(_char).unwrap(); + binary_braillie_char_to_index(char, EncodeOrientation::Rows) + .expect("Expected no error"); + } + } +} + +#[cfg(test)] +mod test_lib_all { + use crate::{ + binary_braillie_char_to_index, + binary_braillie_to_bytes, + index_to_braillie_char, + to_binary_braillie, + EncodeOrientation + }; + + #[test] + fn check_coding_multiple() { + for i in 0x00..0xff { + let mut as_char = index_to_braillie_char( + i, + EncodeOrientation::Rows + ); + for _ in 0..10 { + let as_index = binary_braillie_char_to_index( + as_char, + EncodeOrientation::Rows + ).unwrap(); + assert_eq!(as_index, i); + as_char = index_to_braillie_char(as_index, EncodeOrientation::Rows) + } + } + } + + #[test] + fn check_coding_multiple_bytes() { + for i in 0x00..0xff { + let mut as_str = index_to_braillie_char(i, EncodeOrientation::Rows).to_string(); + for _ in 0..10 { + let as_bytes = binary_braillie_to_bytes( + as_str, + EncodeOrientation::Rows + ).unwrap(); + assert_eq!(i, as_bytes[0]); + as_str = to_binary_braillie( + &as_bytes, + as_bytes.len(), + EncodeOrientation::Rows + ).to_string() + } + } + } +}