CS3700-project3/hptp/src/encoding.rs

113 lines
3.2 KiB
Rust

use lazy_static::lazy_static;
use regex::bytes::Regex;
lazy_static! {
static ref ENCODING_DETECTOR: Regex = Regex::new(r"^([0-9a-fA-F]{60}\n)*[0-9a-fA-F]{0,60}$").unwrap();
}
static WRAP_SIZE: usize = 60;
pub fn can_be_encoded(data: &[u8]) -> bool {
ENCODING_DETECTOR.is_match(data)
}
#[derive(Clone)]
pub struct MeowCoder {
line_index: usize,
}
impl MeowCoder {
pub fn new() -> MeowCoder {
MeowCoder{line_index: 0}
}
fn hex_to_nibble(chr: u8) -> u8 {
const _AL: u8 = 'a' as u8;
const _FL: u8 = 'f' as u8;
const _A: u8 = 'A' as u8;
const _F: u8 = 'F' as u8;
const _0: u8 = '0' as u8;
const _9: u8 = '9' as u8;
match chr {
_AL..=_FL => chr - _AL + 10,
_A..=_F => chr - _A + 10,
_0..=_9 => chr - _0,
_ => panic!("bad hex"),
}
}
fn u8_to_hex(val: u8) -> (u8, u8) {
let first = val >> 4;
let second = val & 0xF;
const LOOKUP: &'static [u8; 16] = b"0123456789abcdef";
(LOOKUP[first as usize], LOOKUP[second as usize])
}
pub fn encode(input: &Vec<u8>) -> Vec<u8> {
let mut out: Vec<u8> = Vec::new();
let mut prev_char: u8 = 0;
let mut pair_first = false;
for chr in input {
if *chr == '\n' as u8 {
continue
}
if !pair_first {
prev_char = *chr;
pair_first = true;
} else {
let byte_value: u8 = MeowCoder::hex_to_nibble(prev_char) * 16
+ MeowCoder::hex_to_nibble(*chr);
out.push(byte_value);
pair_first = false;
}
}
out
}
pub fn decode(&mut self, input: &Vec<u8>) -> Vec<u8> {
let mut out: Vec<u8> = Vec::new();
for byte in input {
let (first, second) = MeowCoder::u8_to_hex(*byte);
out.push(first);
out.push(second);
self.line_index += 2;
if self.line_index == WRAP_SIZE {
self.line_index = 0;
out.push('\n' as u8);
}
}
out
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_match() {
assert_eq!(can_be_encoded(b"abcd1234"), true);
assert_eq!(can_be_encoded(b"abcXd1234"), false);
assert_eq!(can_be_encoded(b"012345678901234567890123456789012345678901234567890123456789\nabcdef"), true);
assert_eq!(can_be_encoded(b"01234567890123456789012345678901234567890123456789012345678\nabcdef"), false);
assert_eq!(can_be_encoded(b"\x12\xab\x45\n"), false);
}
#[test]
fn test_encode() {
let vec = vec!['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8,
'\n' as u8, 'e' as u8, 'f' as u8];
assert_eq!(MeowCoder::encode(&vec), vec![0xab, 0xcd, 0xef]);
}
#[test]
fn test_encode_decode() {
let hex_str: &[u8] = b"012345678901234567890123456789012345678901234567890123456789\nabcdef";
let vec: Vec<u8> = Vec::from(hex_str);
let vec2 = MeowCoder::encode(&vec);
let mut coder = MeowCoder::new();
let out = coder.decode(&vec2);
assert_eq!(out, vec);
}
}