Compare commits

...

3 commits

6 changed files with 280 additions and 31 deletions

View file

@ -5,6 +5,7 @@ pkgs.mkShell {
cargo cargo
rustc rustc
rustfmt rustfmt
gdb
]; ];
RUST_BACKTRACE = 1; RUST_BACKTRACE = 1;

View file

@ -0,0 +1,41 @@
pub struct Arguments {
pub hexadecimal: bool,
pub mode: u8,
pub program_name: String,
pub reverse_characters: bool,
pub value_to_convert: String,
}
pub fn parse_direction(args: &mut impl Iterator<Item = String>, opts: &Arguments, current_arg: String) -> Result<u8, String>{
let mut rvalue = opts.mode;
let direction = match args.next() {
None => return Err(format!("argument for {} was not provided", current_arg)),
Some(e) => e,
};
match direction.as_str() {
"row" => { rvalue &= !(1 << 1) ; rvalue &= !(1 << 2); }
"row-reverse" => { rvalue |= 1 << 1 ; rvalue &= !(1 << 2); }
"column" => { rvalue &= !(1 << 1) ; rvalue |= 1 << 2 ; }
"column-reverse" => { rvalue |= 1 << 1 ; rvalue |= 1 << 2 ; }
_ => return Err(
format!("invalid direction \"{}\" provided for {}", direction, current_arg)
)
};
return Ok(rvalue);
}
pub fn parse_wrap(args: &mut impl Iterator<Item = String>, opts: &Arguments, current_arg: String) -> Result<u8, String>{
let mut rvalue = opts.mode;
let wrap = match args.next() {
None => return Err(format!("argument for {} was not provided", current_arg)),
Some(e) => e,
};
match wrap.as_str() {
"normal" => rvalue &= !(1 << 0),
"reverse" => rvalue |= 1 << 0,
_ => return Err(
format!("invalid wrap \"{}\" provided for {}", wrap, current_arg)
)
};
return Ok(rvalue);
}

1
src/bin/common/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod argument_parsing;

View file

@ -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] <input>\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");
}

View file

@ -3,6 +3,9 @@ use std::process::exit;
use binary_braillie::to_binary_braillie; use binary_braillie::to_binary_braillie;
mod common;
use common::argument_parsing;
fn main() { fn main() {
let args = parse_args(); let args = parse_args();
if args.value_to_convert.len() <= 0 { if args.value_to_convert.len() <= 0 {
@ -24,17 +27,11 @@ fn main() {
print!("{}", to_binary_braillie(&value, value.len(), args.mode.try_into().unwrap())) print!("{}", to_binary_braillie(&value, value.len(), args.mode.try_into().unwrap()))
} }
struct Arguments {
pub hexadecimal: bool,
pub mode: u8,
pub program_name: String,
pub reverse_characters: bool,
pub value_to_convert: String,
}
fn parse_args() -> Arguments {
fn parse_args() -> argument_parsing::Arguments {
let mut args = env::args().peekable(); let mut args = env::args().peekable();
let mut rvalue = Arguments { let mut rvalue = argument_parsing::Arguments {
hexadecimal: false, hexadecimal: false,
mode: 0, mode: 0,
program_name: args.next().unwrap_or(String::from("t2br")), program_name: args.next().unwrap_or(String::from("t2br")),
@ -57,31 +54,19 @@ fn parse_args() -> Arguments {
rvalue.hexadecimal = true; rvalue.hexadecimal = true;
} }
else if arg == "--direction" { else if arg == "--direction" {
let direction = args.next().unwrap_or_else(|| { match argument_parsing::parse_direction(&mut args, &rvalue, arg) {
println!("{}: argument for {} was not provided", program_name, arg); Ok(e) => rvalue.mode = e,
exit(64); Err(e) => {
}); print!("{}: {}", program_name, e);
match direction.as_str() { exit(64);
"row" => { rvalue.mode &= !(1 << 1) ; rvalue.mode &= !(1 << 2); }
"row-reverse" => { rvalue.mode |= 1 << 1 ; rvalue.mode &= !(1 << 2); }
"column" => { rvalue.mode &= !(1 << 1) ; rvalue.mode |= 1 << 2 ; }
"column-reverse" => { rvalue.mode |= 1 << 1 ; rvalue.mode |= 1 << 2 ; }
_ => {
println!("{}: invalid direction \"{}\" provided", program_name, direction);
exit(65);
} }
} }
} }
else if arg == "--wrap" { else if arg == "--wrap" {
let wrap = args.next().unwrap_or_else(|| { match argument_parsing::parse_wrap(&mut args, &rvalue, arg) {
println!("{}: argument for {} was not provided", program_name, arg); Ok(e) => rvalue.mode = e,
exit(64); Err(e) => {
}); print!("{}: {}", program_name, e);
match wrap.as_str() {
"normal" => rvalue.mode &= !(1 << 0),
"reverse" => rvalue.mode |= 1 << 0,
_ => {
println!("{}: invalid wrap \"{}\" provided", program_name, wrap);
exit(65); exit(65);
} }
} }

View file

@ -81,9 +81,49 @@ pub fn to_binary_braillie_str(input: impl AsRef<str>, mode: EncodeOrientation) -
return to_binary_braillie(input.as_ref().as_bytes(), input.as_ref().len(), mode); 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<u8, ()>{
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<str>,
mode: EncodeOrientation
) -> Result<Vec<u8>, ()> {
let mut rvalue: Vec<u8> = 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<str>, mode: EncodeOrientation) -> Result<String, ()> {
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)] #[cfg(test)]
mod test_lib { mod test_lib_to_braillie {
use crate::{index_to_braillie_char, to_binary_braillie_str, EncodeOrientation}; use crate::{index_to_braillie_char, to_binary_braillie_str, EncodeOrientation};
#[test] #[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()
}
}
}
}