2022-04-22 01:28:04 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2022-04-09 18:34:15 +00:00
|
|
|
use std::fmt::{Display, Formatter};
|
2022-05-08 00:35:06 +00:00
|
|
|
use std::io::{BufRead, BufReader, Error, Read};
|
2022-04-09 18:40:37 +00:00
|
|
|
use std::num::ParseIntError;
|
2022-05-08 00:35:06 +00:00
|
|
|
use std::path::Path;
|
2022-04-22 01:28:04 +00:00
|
|
|
use std::str::FromStr;
|
2022-05-08 00:35:06 +00:00
|
|
|
use std::string::FromUtf8Error;
|
2022-04-22 01:28:04 +00:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
pub enum InputTypes {
|
|
|
|
Array,
|
|
|
|
String,
|
2022-05-08 00:35:06 +00:00
|
|
|
Binary,
|
2022-04-22 01:28:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for InputTypes {
|
|
|
|
type Err = String;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
let s = s.to_lowercase();
|
|
|
|
|
|
|
|
match s.as_str() {
|
|
|
|
"array" | "a" => Ok(Self::Array),
|
|
|
|
"string" | "s" => Ok(Self::String),
|
2022-05-08 00:35:06 +00:00
|
|
|
"binary" | "b" => Ok(Self::Binary),
|
2022-04-22 01:28:04 +00:00
|
|
|
_ => Err(format!("Invalid input type '{}'", s)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InputTypes {
|
|
|
|
fn parse_byte_default(element: &str) -> Result<u8, ParseIntError> {
|
|
|
|
if element.starts_with("0x") || element.starts_with("0X") {
|
|
|
|
u8::from_str_radix(&element[2..], 16)
|
|
|
|
} else if element.starts_with("0b") || element.starts_with("0B") {
|
|
|
|
u8::from_str_radix(&element[2..], 2)
|
|
|
|
} else if element.starts_with('h') || element.starts_with('H') {
|
|
|
|
u8::from_str_radix(&element[1..], 16)
|
|
|
|
} else if element.len() > 1 && element.starts_with('0') {
|
|
|
|
u8::from_str_radix(&element[1..], 8)
|
|
|
|
} else {
|
|
|
|
element.parse()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_byte_base(element: &str, base: u32) -> Result<u8, ParseIntError> {
|
|
|
|
u8::from_str_radix(element, base)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_array(elements: Vec<String>, base: Option<u32>) -> Result<Vec<u8>, ParseIntError> {
|
|
|
|
elements
|
|
|
|
.iter()
|
|
|
|
.map(|element| {
|
|
|
|
if let Some(base) = base {
|
|
|
|
Self::parse_byte_base(element, base)
|
|
|
|
} else {
|
|
|
|
Self::parse_byte_default(element)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
2022-05-08 00:35:06 +00:00
|
|
|
pub fn parse_arg_input(
|
2022-04-22 01:28:04 +00:00
|
|
|
&self,
|
|
|
|
src: Vec<String>,
|
|
|
|
base: Option<u32>,
|
|
|
|
) -> Result<Vec<u8>, ByteArrayParseErr> {
|
|
|
|
if src.is_empty() {
|
|
|
|
return Err(ByteArrayParseErr::EmptySrcArray);
|
|
|
|
}
|
|
|
|
|
|
|
|
let str_arr = if src.len() == 1 {
|
|
|
|
src[0]
|
|
|
|
.replace(',', " ")
|
2024-04-28 21:33:19 +00:00
|
|
|
.replace(['[', ']'], "")
|
2022-04-22 01:28:04 +00:00
|
|
|
.split_whitespace()
|
|
|
|
.map(|s| s.to_string())
|
|
|
|
.collect()
|
|
|
|
} else {
|
|
|
|
src
|
|
|
|
};
|
|
|
|
|
|
|
|
let data = match self {
|
|
|
|
InputTypes::Array => Self::parse_array(str_arr, base)?,
|
|
|
|
InputTypes::String => str_arr.join(" ").as_bytes().to_vec(),
|
2022-05-08 00:35:06 +00:00
|
|
|
InputTypes::Binary => return Err(ByteArrayParseErr::UnsupportedFormat),
|
2022-04-22 01:28:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(data)
|
|
|
|
}
|
2022-05-08 00:35:06 +00:00
|
|
|
|
|
|
|
#[allow(clippy::unused_io_amount)]
|
|
|
|
fn parse_data_from_file(
|
|
|
|
&self,
|
|
|
|
mut buf_reader: Box<dyn BufRead>,
|
|
|
|
base: Option<u32>,
|
|
|
|
) -> Result<Vec<u8>, ByteArrayParseErr> {
|
|
|
|
let mut data: Vec<u8> = Vec::new();
|
|
|
|
let mut done = false;
|
|
|
|
|
|
|
|
while !done {
|
|
|
|
let mut buf: Vec<u8> = vec![0; 2048];
|
|
|
|
let len = buf_reader.read(&mut buf)?;
|
|
|
|
|
|
|
|
if len < buf.len() {
|
|
|
|
buf.truncate(len);
|
|
|
|
data.append(&mut buf);
|
|
|
|
done = true;
|
|
|
|
} else if len > 0 {
|
|
|
|
data.append(&mut buf);
|
|
|
|
} else {
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match self {
|
|
|
|
InputTypes::Array | InputTypes::String => {
|
|
|
|
let str_data = String::from_utf8(data)?;
|
|
|
|
self.parse_arg_input(vec![str_data], base)
|
|
|
|
}
|
|
|
|
InputTypes::Binary => Ok(data),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn parse_file(
|
|
|
|
&self,
|
|
|
|
file_path: &Path,
|
|
|
|
base: Option<u32>,
|
|
|
|
) -> Result<Vec<u8>, ByteArrayParseErr> {
|
|
|
|
let reader = Box::new(BufReader::new(std::fs::File::open(file_path)?));
|
|
|
|
self.parse_data_from_file(reader, base)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn parse_stdin(&self, base: Option<u32>) -> Result<Vec<u8>, ByteArrayParseErr> {
|
|
|
|
let reader = Box::new(BufReader::new(std::io::stdin()));
|
|
|
|
self.parse_data_from_file(reader, base)
|
|
|
|
}
|
2022-04-22 01:28:04 +00:00
|
|
|
}
|
2021-09-11 18:21:34 +00:00
|
|
|
|
2022-05-08 00:35:06 +00:00
|
|
|
#[derive(Debug)]
|
2021-09-11 18:21:34 +00:00
|
|
|
pub enum ByteArrayParseErr {
|
|
|
|
EmptySrcArray,
|
|
|
|
ParseIntError(ParseIntError),
|
2022-05-08 00:35:06 +00:00
|
|
|
UnsupportedFormat,
|
|
|
|
FileError(std::io::Error),
|
|
|
|
ParseStringError(FromUtf8Error),
|
2021-09-11 18:21:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ParseIntError> for ByteArrayParseErr {
|
|
|
|
fn from(e: ParseIntError) -> Self {
|
|
|
|
ByteArrayParseErr::ParseIntError(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-08 00:35:06 +00:00
|
|
|
impl From<std::io::Error> for ByteArrayParseErr {
|
|
|
|
fn from(e: Error) -> Self {
|
|
|
|
Self::FileError(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<FromUtf8Error> for ByteArrayParseErr {
|
|
|
|
fn from(e: FromUtf8Error) -> Self {
|
|
|
|
Self::ParseStringError(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 18:34:15 +00:00
|
|
|
impl Display for ByteArrayParseErr {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
let err_msg = match self {
|
|
|
|
ByteArrayParseErr::EmptySrcArray => "Provided array is empty!".to_string(),
|
|
|
|
ByteArrayParseErr::ParseIntError(e) => format!("Failed to parse as int: {}", e),
|
2022-05-08 00:35:06 +00:00
|
|
|
ByteArrayParseErr::UnsupportedFormat => {
|
|
|
|
"Format is not support with the supplied input type".to_string()
|
|
|
|
}
|
|
|
|
ByteArrayParseErr::FileError(e) => format!("Unable to parse file: {}", e),
|
|
|
|
ByteArrayParseErr::ParseStringError(e) => format!("Unable to parse string: {}", e),
|
2022-04-09 18:34:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
write!(f, "{}", err_msg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-12 03:18:56 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2022-04-22 01:28:04 +00:00
|
|
|
use crate::parser::InputTypes;
|
2022-04-12 03:18:56 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_base_10_array() {
|
|
|
|
let array = vec!["[0, 1, 2, 3, 4]".to_string()];
|
|
|
|
|
2022-05-08 00:35:06 +00:00
|
|
|
let out = InputTypes::Array.parse_arg_input(array, None).unwrap();
|
2022-04-12 03:18:56 +00:00
|
|
|
|
|
|
|
assert_eq!(out, vec![0, 1, 2, 3, 4])
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_base_2_array() {
|
|
|
|
let array = vec!["[0b0, 0b1, 0b10, 0b11, 0b100]".to_string()];
|
|
|
|
|
2022-05-08 00:35:06 +00:00
|
|
|
let out = InputTypes::Array.parse_arg_input(array, None).unwrap();
|
2022-04-12 03:18:56 +00:00
|
|
|
|
|
|
|
assert_eq!(out, vec![0, 1, 2, 3, 4])
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_base_8_array() {
|
|
|
|
let array = vec!["[00, 01, 02, 03, 04]".to_string()];
|
|
|
|
|
2022-05-08 00:35:06 +00:00
|
|
|
let out = InputTypes::Array.parse_arg_input(array, None).unwrap();
|
2022-04-12 03:18:56 +00:00
|
|
|
|
|
|
|
assert_eq!(out, vec![0, 1, 2, 3, 4])
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_base_16_array() {
|
|
|
|
let array = vec!["[0x0, 0x1, 0x2, h3, H4]".to_string()];
|
|
|
|
|
2022-05-08 00:35:06 +00:00
|
|
|
let out = InputTypes::Array.parse_arg_input(array, None).unwrap();
|
2022-04-12 03:18:56 +00:00
|
|
|
|
|
|
|
assert_eq!(out, vec![0, 1, 2, 3, 4])
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_base_mixed() {
|
|
|
|
let array = vec!["[00 0x1, 2, h3, H4]".to_string()];
|
|
|
|
|
2022-05-08 00:35:06 +00:00
|
|
|
let out = InputTypes::Array.parse_arg_input(array, None).unwrap();
|
2022-04-12 03:18:56 +00:00
|
|
|
|
|
|
|
assert_eq!(out, vec![0, 1, 2, 3, 4])
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_no_braces_multi_args() {
|
|
|
|
let array = vec![
|
|
|
|
"0".to_string(),
|
|
|
|
"1".to_string(),
|
|
|
|
"2".to_string(),
|
|
|
|
"3".to_string(),
|
|
|
|
"4".to_string(),
|
|
|
|
];
|
2022-05-08 00:35:06 +00:00
|
|
|
let out = InputTypes::Array.parse_arg_input(array, None).unwrap();
|
2022-04-12 03:18:56 +00:00
|
|
|
|
|
|
|
assert_eq!(out, vec![0, 1, 2, 3, 4])
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_no_braces_one_arg() {
|
|
|
|
let array = vec!["0 1 2 3 4".to_string()];
|
2022-05-08 00:35:06 +00:00
|
|
|
let out = InputTypes::Array.parse_arg_input(array, None).unwrap();
|
2022-04-12 03:18:56 +00:00
|
|
|
|
|
|
|
assert_eq!(out, vec![0, 1, 2, 3, 4])
|
|
|
|
}
|
2022-04-22 01:28:04 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_string() {
|
|
|
|
let string = "Hello World!";
|
|
|
|
|
|
|
|
let out = InputTypes::String
|
2022-05-08 00:35:06 +00:00
|
|
|
.parse_arg_input(vec![string.to_string()], None)
|
2022-04-22 01:28:04 +00:00
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
assert_eq!(string.as_bytes(), out)
|
|
|
|
}
|
2022-04-12 03:18:56 +00:00
|
|
|
}
|