use bstr::ByteSlice;
use hex;
#[cfg(target_family = "wasm")]
use serde::{Deserialize, Serialize};
use crate::Operation;
use crate::OperationError;
#[derive(Clone)]
#[cfg_attr(target_family = "wasm", derive(Serialize, Deserialize))]
pub struct HexDecode {
delimiter: Option<String>,
}
#[derive(Clone)]
#[cfg_attr(target_family = "wasm", derive(Serialize, Deserialize))]
pub enum HexFormat {
Upper,
Lower,
}
impl Operation for HexDecode {
fn execute(&self, input: &[u8]) -> Result<Vec<u8>, OperationError> {
let mut hex_byte_str = input.to_vec();
if let Some(del) = &self.delimiter {
hex_byte_str = input
.split_str(&del)
.flatten()
.cloned()
.filter(|c| *c != b'\n')
.collect();
};
Ok(hex::decode(hex_byte_str.to_ascii_uppercase())?)
}
}
impl HexDecode {
pub fn new(delimiter: Option<String>) -> Self {
HexDecode { delimiter }
}
}
#[derive(Clone)]
#[cfg_attr(target_family = "wasm", derive(Serialize, Deserialize))]
pub struct HexEncode {
format: HexFormat,
delimiter: Option<String>,
bytes_per_line: usize,
}
impl Operation for HexEncode {
fn execute(&self, input: &[u8]) -> Result<Vec<u8>, OperationError> {
let hex_string = match self.format {
HexFormat::Lower => hex::encode(input),
HexFormat::Upper => hex::encode_upper(input),
};
let mut output = vec![];
let mut i = if self.bytes_per_line == 0 {
hex_string.len()
} else {
1
};
let delimiter = self
.delimiter
.clone()
.and_then(|d| if d.is_empty() { None } else { Some(d) });
for hex in hex_string.as_bytes().chunks(2) {
if let Some(del) = &delimiter {
output.extend_from_slice(del.as_bytes());
}
output.extend_from_slice(hex);
if i == self.bytes_per_line {
output.push(b'\n');
i %= self.bytes_per_line;
}
i += 1
}
if let Some(char) = output.last() {
if *char == b'\n' {
output.pop();
}
}
Ok(output)
}
}
impl HexEncode {
pub fn new(format: HexFormat, delimiter: Option<String>, bytes_per_line: usize) -> Self {
HexEncode {
format,
bytes_per_line,
delimiter,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hex_decode_0x() {
let encoder = HexDecode::new(None);
let actual = encoder.execute("636169646f".as_bytes()).unwrap();
let expected = "caido".as_bytes().to_vec();
assert_eq!(actual, expected);
}
#[test]
fn hex_decode_no_prefix() {
let encoder = HexDecode::new(Some("\\x".to_string()));
let actual = encoder
.execute("\\x63\\x61\n\\x69\\x64\n\\x6f".as_bytes())
.unwrap();
let expected = "caido".as_bytes().to_vec();
assert_eq!(actual, expected);
}
#[test]
fn hex_encode_upper() {
let encoder = HexEncode::new(HexFormat::Upper, Some("\\x".to_string()), 0);
let actual = encoder.execute("caido".as_bytes()).unwrap();
let expected = "\\x63\\x61\\x69\\x64\\x6F".as_bytes().to_vec();
assert_eq!(actual, expected);
}
#[test]
fn hex_encode_lower() {
let encoder = HexEncode::new(HexFormat::Lower, Some("0x".to_string()), 0);
let actual = encoder.execute("caido".as_bytes()).unwrap();
let expected = "0x630x610x690x640x6f".as_bytes().to_vec();
assert_eq!(actual, expected);
}
#[test]
fn hex_encode_prefix_lower() {
let encoder = HexEncode::new(HexFormat::Lower, None, 2);
let actual = encoder.execute("caido".as_bytes()).unwrap();
let expected = "6361\n6964\n6f".as_bytes().to_vec();
assert_eq!(actual, expected);
}
#[test]
fn hex_encode_prefix_upper() {
let encoder = HexEncode::new(HexFormat::Upper, None, 0);
let actual = encoder.execute("caido".as_bytes()).unwrap();
let expected = "636169646F".as_bytes().to_vec();
assert_eq!(actual, expected);
}
}