use std::fmt::{Display, Formatter, Write}; use std::io::Cursor; use std::string::FromUtf8Error; use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt}; use num_bigint::{BigInt, BigUint}; use serde::Deserialize; use crate::byte_stream::{bit_mask, ByteStream, ByteStreamError}; use crate::formatter::printers::PrintType; pub trait ByteOrderOperations: ByteOrder { fn last_byte(buf: &mut Vec) -> Option<&mut u8>; fn big_int(buf: &[u8], trim: usize) -> BigInt; fn big_uint(buf: &[u8], trim: usize) -> BigUint; fn big_u_int_to_bytes(big_int: BigUint) -> Vec; fn big_int_to_bytes(big_int: BigInt) -> Vec; fn pad_bytes(buf: &mut Vec, size: usize); fn flip() -> bool; } impl ByteOrderOperations for BigEndian { fn last_byte(buf: &mut Vec) -> Option<&mut u8> { buf.first_mut() } fn big_int(buf: &[u8], trim: usize) -> BigInt { let mut buf = buf.to_vec(); let byte = buf.first_mut().unwrap(); *byte = (*byte << trim) >> trim; BigInt::from_signed_bytes_be(&buf) } fn big_uint(buf: &[u8], trim: usize) -> BigUint { let mut buf = buf.to_vec(); let byte = buf.first_mut().unwrap(); *byte = (*byte << trim) >> trim; BigUint::from_bytes_be(&buf) } fn big_u_int_to_bytes(big_int: BigUint) -> Vec { big_int.to_bytes_be() } fn big_int_to_bytes(big_int: BigInt) -> Vec { big_int.to_signed_bytes_be() } fn pad_bytes(buf: &mut Vec, size: usize) { if size <= buf.len() { return; } let pad_to = size - buf.len(); buf.splice(0..0, vec![0_u8; pad_to].iter().cloned()); } fn flip() -> bool { true } } impl ByteOrderOperations for LittleEndian { fn last_byte(buf: &mut Vec) -> Option<&mut u8> { buf.last_mut() } fn big_int(buf: &[u8], trim: usize) -> BigInt { BigInt::from_signed_bytes_le(buf) >> trim } fn big_uint(buf: &[u8], trim: usize) -> BigUint { BigUint::from_bytes_le(buf) >> trim } fn big_u_int_to_bytes(big_int: BigUint) -> Vec { big_int.to_bytes_le() } fn big_int_to_bytes(big_int: BigInt) -> Vec { big_int.to_signed_bytes_le() } fn pad_bytes(buf: &mut Vec, size: usize) { if size <= buf.len() { return; } let pad_to = size - buf.len(); let mut pad = vec![0_u8; pad_to]; buf.append(&mut pad); } fn flip() -> bool { false } } #[derive(Debug, Clone)] pub enum FormatError { ByteSteamError(ByteStreamError), #[allow(dead_code)] NotSupported, StringParseError(FromUtf8Error), } impl From for FormatError { fn from(e: ByteStreamError) -> Self { FormatError::ByteSteamError(e) } } impl From for FormatError { fn from(e: FromUtf8Error) -> Self { FormatError::StringParseError(e) } } impl Display for FormatError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { FormatError::ByteSteamError(e) => writeln!(f, "Byte stream error: {}", e), FormatError::NotSupported => write!(f, "Field type not supported"), FormatError::StringParseError(e) => write!(f, "String parse error: {}", e), } } } #[derive(Debug, Deserialize, Clone)] #[serde(tag = "type")] pub enum FieldType { /// Unsigned Int UInt { bit_width: usize, endianness: Endianness, }, /// Unsigned Int Int { bit_width: usize, endianness: Endianness, }, /// Single Precession Float Float { endianness: Endianness }, /// Double Precession Float Double { endianness: Endianness }, /// Null Terminated String Field String { max_len: usize, endianness: Endianness, }, /// Fixed Byte Length Field Bytes { max_len: usize, endianness: Endianness, }, } #[derive(Debug, Deserialize, Clone, PartialOrd, PartialEq, Copy)] pub enum Endianness { LittleEndian, BigEndian, } #[derive(Debug, Deserialize, Clone)] pub struct Field { /// Field Name pub name: String, /// Field Type pub field_type: FieldType, /// How to display the field #[serde(default = "PrintType::default")] pub print_type: PrintType, /// Flip Bit Order pub bit_flip: Option, //#[serde(default = "BitOffset::default")] //pub bit_offset: BitOffset } impl Field { fn format_int( &self, byte_stream: &ByteStream, bit_ndx: usize, bit_width: usize, ) -> Result<(String, usize), FormatError> { let mut bytes = byte_stream.get_bytes::(bit_ndx, bit_width)?; if let Some(last_byte) = T::last_byte(&mut bytes) { let last_bit = ((bit_width - 1) % 8) as u8; let sign_bit = (*last_byte >> last_bit) & 0x1 == 1; if sign_bit { // Sign extend *last_byte |= !bit_mask(last_bit + 1) } let big_int = T::big_int(&bytes, 0); Ok((self.print_type.print_big_int::(big_int), bit_width)) } else { Err(ByteStreamError::OutOfRange.into()) } } fn format_uint( &self, byte_stream: &ByteStream, bit_ndx: usize, bit_width: usize, ) -> Result<(String, usize), FormatError> { let bytes = byte_stream.get_bytes::(bit_ndx, bit_width)?; let big_int = T::big_uint(&bytes, 0); Ok((self.print_type.print_big_u_int::(big_int), bit_width)) } fn format_float( &self, byte_stream: &ByteStream, bit_ndx: usize, ) -> Result<(String, usize), FormatError> { let bytes = byte_stream.get_bytes::(bit_ndx, 32)?; let mut cursor = Cursor::new(bytes); let float = cursor.read_f32::().unwrap(); Ok(( self.print_type.print_float::(float), std::mem::size_of::() * 8, )) } fn format_double( &self, byte_stream: &ByteStream, bit_ndx: usize, ) -> Result<(String, usize), FormatError> { let bytes = byte_stream.get_bytes::(bit_ndx, 64)?; let mut cursor = Cursor::new(bytes); let double = cursor.read_f64::().unwrap(); Ok(( self.print_type.print_double::(double), std::mem::size_of::() * 8, )) } fn format_string( &self, byte_stream: &ByteStream, bit_ndx: usize, max_byte_len: usize, ) -> Result<(String, usize), FormatError> { let mut string_bytes = Vec::new(); let mut bit_count = 0; for _ in 0..max_byte_len { let byte = byte_stream.get_bytes::(bit_ndx + bit_count, 8)?[0]; bit_count += 8; if byte == 0 { break; } string_bytes.push(byte); } let s = String::from_utf8(string_bytes)?; Ok((self.print_type.print_string(&s), bit_count)) } fn format_bytes( &self, byte_stream: &ByteStream, bit_ndx: usize, max_byte_len: usize, ) -> Result<(String, usize), FormatError> { let data_remaining = byte_stream.len() - bit_ndx / 8; let width = if max_byte_len < data_remaining { max_byte_len * 8 } else { data_remaining * 8 }; let data = byte_stream.get_bytes::(bit_ndx, width)?; Ok((self.print_type.print_bytes(&data), width)) } fn format_data( &self, byte_stream: &mut ByteStream, bit_ndx: usize, ) -> Result<(String, usize), FormatError> { let global_bit_flip = byte_stream.get_reverse_bits(); if let Some(bit_flip) = self.bit_flip { byte_stream.set_reverse_bits(bit_flip); } let fmt = match self.field_type { FieldType::UInt { bit_width, endianness, } => match endianness { Endianness::LittleEndian => { self.format_uint::(byte_stream, bit_ndx, bit_width) } Endianness::BigEndian => { self.format_uint::(byte_stream, bit_ndx, bit_width) } }, FieldType::Int { bit_width, endianness, } => match endianness { Endianness::LittleEndian => { self.format_int::(byte_stream, bit_ndx, bit_width) } Endianness::BigEndian => { self.format_int::(byte_stream, bit_ndx, bit_width) } }, FieldType::Float { endianness } => match endianness { Endianness::LittleEndian => self.format_float::(byte_stream, bit_ndx), Endianness::BigEndian => self.format_float::(byte_stream, bit_ndx), }, FieldType::Double { endianness } => match endianness { Endianness::LittleEndian => { self.format_double::(byte_stream, bit_ndx) } Endianness::BigEndian => self.format_double::(byte_stream, bit_ndx), }, FieldType::String { max_len, endianness, } => match endianness { Endianness::LittleEndian => { self.format_string::(byte_stream, bit_ndx, max_len) } Endianness::BigEndian => { self.format_string::(byte_stream, bit_ndx, max_len) } }, FieldType::Bytes { max_len, endianness, } => match endianness { Endianness::LittleEndian => { self.format_bytes::(byte_stream, bit_ndx, max_len) } Endianness::BigEndian => { self.format_bytes::(byte_stream, bit_ndx, max_len) } }, }?; byte_stream.set_reverse_bits(global_bit_flip); Ok(fmt) } } #[derive(Debug, Deserialize, Clone)] pub struct Format { /// Format Name pub name: String, /// Flip bits pub bit_flip: bool, /// Elements of the format pub fields: Vec, } impl Format { pub fn format_data(&self, data: &[u8]) -> Result { let mut format_str = String::new(); let mut byte_stream = ByteStream::from(data); let mut bit_ndx: usize = 0; byte_stream.set_reverse_bits(self.bit_flip); for field in &self.fields { match field.format_data(&mut byte_stream, bit_ndx) { Ok((data_str, bit_width)) => { bit_ndx += bit_width; writeln!(format_str, "{}: {}", field.name, data_str).unwrap(); } Err(e) => { println!( "Error formatting field (bit_ndx = {}): \"{}\": {}", bit_ndx, field.name, e ); return Err(e); } } } Ok(format_str) } } #[cfg(test)] mod tests { use crate::byte_stream::ByteStream; use crate::formatter::format::{Endianness, Field, FieldType}; #[test] fn test_format_int_4_bits() { let field = Field { field_type: FieldType::Int { bit_width: 4, endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; for i in 0i8..7i8 { let mut byte_vec = Vec::new(); byte_vec.push(i as u8); byte_vec.push((-i) as u8); let mut byte_stream = ByteStream::from(byte_vec); let (pos_output, width1) = field.format_data(&mut byte_stream, 4).unwrap(); let (neg_output, width2) = field.format_data(&mut byte_stream, 12).unwrap(); assert_eq!(width1, 4); assert_eq!(width2, 4); assert_eq!(pos_output, i.to_string()); assert_eq!(neg_output, (-i).to_string()); } } #[test] fn test_format_int_5_bits() { let field = Field { field_type: FieldType::Int { bit_width: 5, endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: Some(true), print_type: Default::default(), }; let mut byte_stream = ByteStream::from(vec![0x1B]); let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); assert_eq!(width, 5); assert_eq!(output, "-5") } #[test] fn test_format_int_16_bits() { let field = Field { field_type: FieldType::Int { bit_width: 16, endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; let mut byte_stream = ByteStream::from(vec![0xFC, 0xA5]); let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); assert_eq!(width, 16); assert_eq!(output, "-23044") } #[test] fn test_format_int_16_bits_not_aligned() { let field = Field { field_type: FieldType::Int { bit_width: 16, endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; let mut byte_stream = ByteStream::from(vec![0x0C, 0xF5, 0xA0]); let (output, width) = field.format_data(&mut byte_stream, 4).unwrap(); assert_eq!(width, 16); assert_eq!(output, "-23044") } #[test] fn test_format_float() { let field = Field { field_type: FieldType::Float { endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; let mut byte_stream = ByteStream::from(b"\x52\x58\xd2\xc3".to_vec()); let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); assert_eq!(width, 32); assert_eq!(output, "-420.69") } #[test] fn test_format_double() { let field = Field { field_type: FieldType::Double { endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; let mut byte_stream = ByteStream::from(b"\xD7\xA3\x70\x3D\x0A\x4B\x7A\xC0".to_vec()); let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); assert_eq!(width, 64); assert_eq!(output, "-420.69") } #[test] fn test_format_float_err() { let field = Field { field_type: FieldType::Double { endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; let mut byte_stream = ByteStream::from(b"\x3D\x70\xA3\xD7".to_vec()); assert!(field.format_data(&mut byte_stream, 0).is_err()) } #[test] fn test_format_string() { let test_string = "Hello World!"; let field = Field { field_type: FieldType::String { max_len: 16, endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; let mut bytes = test_string.as_bytes().to_vec(); bytes.push('\0' as u8); let mut byte_stream = ByteStream::from(bytes); let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); assert_eq!(width, (test_string.len() + 1) * 8); //extra byte to account for the '\0' char assert_eq!(output, test_string) } #[test] fn test_format_bytes() { let field = Field { field_type: FieldType::Bytes { max_len: 2, endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; let mut byte_stream = ByteStream::from(vec![0xDE, 0xAD, 0xBE, 0xEF]); let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); assert_eq!(width, 16); assert_eq!(output, "[222, 173]") } #[test] fn test_format_bytes_max_len_bigger_than_data() { let field = Field { field_type: FieldType::Bytes { max_len: 64, endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; let mut byte_stream = ByteStream::from(vec![0xDE, 0xAD]); let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); assert_eq!(width, 16); assert_eq!(output, "[222, 173]") } #[test] fn test_parse_str_big_endian() { let field = Field { field_type: FieldType::String { max_len: 64, endianness: Endianness::BigEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; let src_str = b"Test\x00abcdefg"; let mut byte_stream = ByteStream::from(src_str.to_vec()); let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); assert_eq!(width, 40); assert_eq!(output, "Test") } #[test] fn test_parse_str_little_endian() { let field = Field { field_type: FieldType::String { max_len: 64, endianness: Endianness::LittleEndian, }, name: "test".to_string(), bit_flip: None, print_type: Default::default(), }; let src_str = b"Test\x00abcdefg"; let mut byte_stream = ByteStream::from(src_str.to_vec()); let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); assert_eq!(width, 40); assert_eq!(output, "Test") } }