use binarytext::base16::Base16;
use binarytext::base32::Base32;
use binarytext::base45::Base45;
use binarytext::base64::Base64;
use binarytext::base85::Base85;
use binarytext::binarytext::BinaryText;
use binarytext::error::BinTxtError;
use binarytext::int::IntEncoder;
use binarytext::stream::*;
use std::env;
use std::str::FromStr;
fn help() {
println!("usage: bintxt -options- -string or filename-");
println!("Options:");
println!(" -g Guess encoding by trying all valid encodings");
println!(" Can't be combined with option \"-f\"");
println!(" and can only be used with \"-d\"");
println!(" -f Argument is a file instead of a string");
println!(" -o -filename- Output result to file");
println!(" -e Encode string with specified algorithm");
println!(" -d Decode string with specified algorithm");
println!(" -t -encoding- Name of encoding type");
println!(" The following encoders are available:");
println!(" Base16, Base32, Base32Hex, Base45, Base64, Base64URL, Base85");
println!(" And the integer based encoders:");
println!(" Base36, Base56, Base58, Base62");
println!(" -b -buffer length- Length of the read buffer for streaming (default: 8000 bytes)");
println!(" -w -width- Number of columns for output (default 0 - no linebreaks)");
println!(" -h Print this help");
}
fn all_encodings() -> Vec<Box<dyn BinaryText>> {
vec![
Box::new(Base16::default()),
Box::new(Base32::default()),
Box::new(Base32::base32hex()),
Box::new(IntEncoder::base36()),
Box::new(Base45::default()),
Box::new(IntEncoder::base56()),
Box::new(IntEncoder::base58()),
Box::new(IntEncoder::base62()),
Box::new(Base64::default()),
Box::new(Base64::base64url()),
Box::new(Base85::default()),
]
}
fn encoding_by_name(name: &str) -> Result<Box<dyn BinaryText>, BinTxtError> {
let name_lower = name.to_lowercase();
for enc in all_encodings() {
if enc.name().to_lowercase() == name_lower {
return Ok(enc);
}
}
Err(BinTxtError::UnknownEncoding(String::from(name)))
}
fn valid_encodings(input: &str) -> Result<Vec<Box<dyn BinaryText>>, BinTxtError> {
let mut ret = vec![];
for enc in all_encodings() {
if enc.is_decodable(input) {
ret.push(enc);
}
}
if ret.is_empty() {
let msg = "No suitable encoding found".to_string();
return Err(BinTxtError::UnknownEncoding(msg));
}
Ok(ret)
}
fn run() -> Result<(), BinTxtError> {
let mut args = env::args().skip(1);
let mut mode = Mode::Encode;
let mut file = false;
let mut name_encoding = String::new();
let mut input = String::new();
let mut width = 0usize;
let mut buf_len = 8000usize;
let mut filename_out = String::new();
let mut guess = false;
while let Some(arg) = args.next() {
match arg.as_str() {
"-h" => {
help();
return Ok(());
}
"-d" => {
mode = Mode::Decode;
}
"-e" => {
mode = Mode::Encode;
}
"-f" => {
file = true;
}
"-g" => {
guess = true;
}
"-b" => match args.next() {
Some(buf_len_str) => match usize::from_str(&buf_len_str) {
Ok(bl) => {
buf_len = bl;
}
Err(_) => {
return Err(BinTxtError::InvalidArg(arg));
}
},
None => {
return Err(BinTxtError::MissingArg(arg));
}
},
"-w" => match args.next() {
Some(width_string) => match usize::from_str(&width_string) {
Ok(w) => {
width = w;
}
Err(_) => {
return Err(BinTxtError::InvalidArg(arg));
}
},
None => {
return Err(BinTxtError::MissingArg(arg));
}
},
"-t" => match args.next() {
Some(name) => {
name_encoding = name;
}
None => {
return Err(BinTxtError::MissingArg(arg));
}
},
"-o" => match args.next() {
Some(name) => {
filename_out = name;
}
None => {
return Err(BinTxtError::MissingArg(arg));
}
},
_ => {
if !input.is_empty() {
return Err(BinTxtError::InvalidArg(input));
}
input = arg;
}
}
}
if name_encoding.is_empty() {
guess = true;
}
if guess {
if file {
let msg = "Unable to guess encoding of file - Encoding type needs to be provided using switch \"-f\"".to_string();
return Err(BinTxtError::UnknownEncoding(msg));
}
if mode == Mode::Encode {
let msg = "No encoding type provided - Use switch \"-t\" for encoding string with a specific type or \"-d\" for decoding".to_string();
return Err(BinTxtError::UnknownEncoding(msg));
}
for enc in valid_encodings(&input)? {
let res = enc.decode_from_str(input.as_str());
if let Ok(s) = res {
println!("{}:", enc.name());
println!("\"{}\"", s);
}
}
} else {
let enc = encoding_by_name(&name_encoding)?;
let buf_writer = buf_writer_stdout()?;
if file {
let buf_reader = buf_reader_file(&input)?;
if filename_out.is_empty() {
let mut bintxt_stream =
BinTxtStream::new(buf_reader, buf_writer, &enc, mode, buf_len, width);
bintxt_stream.stream()?;
} else {
let buf_writer = buf_writer_file(&filename_out)?;
let mut bintxt_stream =
BinTxtStream::new(buf_reader, buf_writer, &enc, mode, buf_len, width);
bintxt_stream.stream()?;
}
} else {
let buf_reader = buf_reader_bytes(input.as_bytes())?;
let mut bintxt_stream =
BinTxtStream::new(buf_reader, buf_writer, &enc, mode, buf_len, width);
bintxt_stream.stream()?;
}
println!();
}
Ok(())
}
fn main() {
if let Err(err) = run() {
eprintln!("{err}");
}
}