use std::collections::linked_list::LinkedList;
use crate::{
action::{
CryptographicAction,
Direction,
},
code::Code,
ui::application::{
ApplicationError,
OPTION_CODE,
},
};
#[cfg(any(feature = "base16", feature = "hex"))]
use crate::code::base_encoding::Base16Context;
#[cfg(feature = "base32")]
use crate::code::base_encoding::Base32Context;
#[cfg(feature = "base32hex")]
use crate::code::base_encoding::Base32HexContext;
#[cfg(feature = "base64")]
use crate::code::base_encoding::Base64Context;
#[cfg(feature = "base64url")]
use crate::code::base_encoding::Base64UrlContext;
#[cfg(any(
feature = "base16",
feature = "hex"
))]
const ALGORITHM_BASE16: &str = "BASE16";
#[cfg(feature = "base32")]
const ALGORITHM_BASE32: &str = "BASE32";
#[cfg(feature = "base32hex")]
const ALGORITHM_BASE32HEX: &str = "BASE32HEX";
#[cfg(feature = "base64")]
const ALGORITHM_BASE64: &str = "BASE64";
#[cfg(feature = "base64url")]
const ALGORITHM_BASE64URL: &str = "BASE64URL";
#[cfg(any(
feature = "base16",
feature = "hex"
))]
const ALGORITHM_HEX: &str = "HEX";
const OPTION_DECODE: &str = "decode";
const OPTION_ENCODE: &str = "encode";
const OPTION_LOWERCASE: &str = "lowercase";
const OPTION_UPPERCASE: &str = "uppercase";
#[inline]
fn create_new_code_context(
arguments: Option<&String>
) -> Result<(Box<dyn Code>, String), ApplicationError> {
let arguments = if let Some(arg) = arguments {
arg
} else {
let mut description = "Missing argument for ".to_string();
description.push_str(OPTION_CODE);
description.push_str("!");
return Err(ApplicationError::MissingArgument(
description, "create_new_code_context()".to_string(),
));
};
let arguments = arguments
.split(":")
.collect::<Vec<&str>>();
if arguments.len() == 1 {
let mut description = "For algorithm class ".to_string();
description.push_str(OPTION_CODE);
description.push_str("!");
Err(ApplicationError::MissingArgument(
description, "create_new_code_context()".to_string(),
))
} else if arguments.len() > 2 {
let mut description = "For algorithm class ".to_string();
description.push_str(OPTION_CODE);
description.push_str("!");
Err(ApplicationError::TooManyArguments(
description, "create_new_code_context()".to_string(),
))
} else {
let ctx: Box<dyn Code> = match arguments[0] {
#[cfg(any(feature = "base16", feature = "hex"))]
algorithm if algorithm == ALGORITHM_BASE16 || algorithm == ALGORITHM_HEX => {
Box::from(Base16Context::new())
}
#[cfg(feature = "base32")]
algorithm if algorithm == ALGORITHM_BASE32 => {
Box::from(Base32Context::new())
}
#[cfg(feature = "base32hex")]
algorithm if algorithm == ALGORITHM_BASE32HEX => {
Box::from(Base32HexContext::new())
}
#[cfg(feature = "base64")]
algorithm if algorithm == ALGORITHM_BASE64 => {
Box::from(Base64Context::new())
}
#[cfg(feature = "base64url")]
algorithm if algorithm == ALGORITHM_BASE64URL => {
Box::from(Base64UrlContext::new())
}
algorithm => {
let mut description = "Algorithm ".to_string();
description.push_str(algorithm);
description.push_str(" unknown!");
return Err(ApplicationError::WrongCommandLineArgument(
description,
"create_new_code_context()".to_string(),
));
}
};
Ok((ctx, arguments[1].to_string()))
}
}
pub(crate) fn handle_code_option_arguments(
arguments: Option<&String>,
current_action: &mut Option<CryptographicAction>,
) -> Result<(), ApplicationError> {
let (mut ctx, arguments) = match create_new_code_context(
arguments
) {
Ok(ctx) => { ctx }
Err(error) => { return Err(error); }
};
let mut arguments = split_code_algorithm_arguments(&arguments);
let mut direction = None;
let mut maybe_arg = arguments.pop_front();
let mut case_argument_encountered = false;
while maybe_arg != None {
let code_arg = maybe_arg.unwrap();
match code_arg {
arg if arg == OPTION_DECODE || arg == OPTION_ENCODE => {
if direction.is_none() {
direction = Some(
if arg == OPTION_DECODE {
Direction::ToPlain
} else {
Direction::ToCipher
}
);
} else {
return Err(ApplicationError::TooManyArguments(
"Only exactly one of \"encode\" and \"decode\" may be \
supplied!".to_string(),
"handle_code_option_arguments()".to_string(),
));
}
}
arg if arg == OPTION_LOWERCASE || arg == OPTION_UPPERCASE => {
if case_argument_encountered {
return Err(ApplicationError::TooManyArguments(
"Only exactly one of \"uppercase\" and \"lowercase\" may be \
supplied!".to_string(),
"handle_code_option_arguments()".to_string(),
));
} else {
case_argument_encountered = true;
}
ctx.set_ciphertext_capitalization(arg == OPTION_UPPERCASE);
}
arg => {
let mut description = "For algorithm ".to_string();
description.push_str(ctx.get_atom_type().to_string().as_str());
description.push_str("! \"");
description.push_str(arg);
description.push_str("\" is unknown!");
return Err(ApplicationError::WrongCommandLineArgument(
description,
"handle_code_option_arguments()".to_string(),
));
}
}
maybe_arg = arguments.pop_front();
}
if let Some(direction) = direction {
*current_action = Some(CryptographicAction::new_code_action(
ctx, direction,
));
Ok(())
} else {
Err(ApplicationError::MissingArgument(
"Neither \"encode\" nor \"decode\" argument has been supplied!".to_string(),
"handle_code_option_arguments()".to_string(),
))
}
}
#[inline]
fn split_code_algorithm_arguments(
arguments: &String,
) -> LinkedList<&str> {
arguments
.as_str()
.split(",")
.collect::<LinkedList<&str>>()
}