From 4e9f4bff1d266d1fc054fa96c7a982e598e528dc Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sat, 9 Oct 2021 10:05:32 -0600 Subject: [PATCH] Added string and bytes formatting + String fields are always null terminated and have a max length + Byte fields are made of raw bytes, and read data until they hit a max length or the end of data is reached --- src/byte_stream/mod.rs | 4 +++ src/formatter/format.rs | 73 +++++++++++++++++++++++++++++++++++++-- src/formatter/mod.rs | 1 + src/formatter/printers.rs | 5 +++ 4 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 src/formatter/printers.rs diff --git a/src/byte_stream/mod.rs b/src/byte_stream/mod.rs index c84d7bf..6a6196c 100644 --- a/src/byte_stream/mod.rs +++ b/src/byte_stream/mod.rs @@ -72,6 +72,10 @@ impl ByteStream { Ok(byte_stream) } + + pub fn len(&self) -> usize { + self.data.len() + } } impl From<&[u8]> for ByteStream { diff --git a/src/formatter/format.rs b/src/formatter/format.rs index 0f4fdfb..c534ec9 100644 --- a/src/formatter/format.rs +++ b/src/formatter/format.rs @@ -4,11 +4,15 @@ use std::fmt::{Write, Display, Formatter}; use num_bigint::{BigUint, BigInt}; use std::io::Cursor; use byteorder::{BigEndian, ReadBytesExt}; +use std::string::FromUtf8Error; +use crate::formatter::printers::print_bytes_as_array; #[derive(Debug, Clone)] pub enum FormatError { ByteSteamError(ByteStreamError), - NotSupported + #[allow(dead_code)] + NotSupported, + StringParseError(FromUtf8Error), } impl From for FormatError { @@ -17,11 +21,18 @@ impl From for FormatError { } } +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 steam error: {}", e), - FormatError::NotSupported => write!(f, "Field type not supported") + FormatError::NotSupported => write!(f, "Field type not supported"), + FormatError::StringParseError(e) => write!(f, "String parse error: {}", e) } } } @@ -94,13 +105,47 @@ impl Field { Ok((cursor.read_f64::().unwrap().to_string(), 4)) } + fn format_string(byte_stream: &ByteStream, mut bit_ndx: usize, max_byte_len: usize) -> Result<(String, usize), FormatError> { + let mut string_bytes = Vec::new(); + + for _ in 0..max_byte_len { + let byte = byte_stream.get_bytes(bit_ndx, 8)?[0]; + + if byte == 0 { + break; + } + + string_bytes.push(byte); + bit_ndx += 8; + } + + let byte_count = string_bytes.len(); + Ok((String::from_utf8(string_bytes)?, byte_count)) + } + + fn format_bytes(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((print_bytes_as_array(&data), width)) + } + fn format_data(&self, byte_stream: &ByteStream, bit_ndx: usize) -> Result<(String, usize), FormatError> { match self.field_type { FieldType::UInt { bit_width } => Self::format_uint(byte_stream, bit_ndx, bit_width), FieldType::Int { bit_width } => Self::format_int(byte_stream, bit_ndx, bit_width), FieldType::Float => Self::format_float(byte_stream, bit_ndx), FieldType::Double => Self::format_double(byte_stream, bit_ndx), - _ => Err(FormatError::NotSupported), + FieldType::String {max_len} => Self::format_string(byte_stream, bit_ndx, max_len), + FieldType::Bytes {max_len} => Self::format_bytes(byte_stream, bit_ndx, max_len) } } } @@ -211,4 +256,26 @@ mod tests { assert!(field.format_data(&byte_steam, 0).is_err()) } + + #[test] + fn test_format_string() { + let field = Field {field_type: FieldType::String {max_len: 16}, name: "test".to_string()}; + + let byte_steam = ByteStream::from(b"Hello World!\0".to_vec()); + + let (output, _) = field.format_data(&byte_steam, 0).unwrap(); + + assert_eq!(output, "Hello World!".to_string()) + } + + #[test] + fn test_format_bytes() { + let field = Field {field_type: FieldType::Bytes {max_len: 2}, name: "test".to_string()}; + + let byte_steam = ByteStream::from(vec![0xDE, 0xAD, 0xBE, 0xEF]); + + let (output, _) = field.format_data(&byte_steam, 0).unwrap(); + + assert_eq!(output, "[222, 173]") + } } diff --git a/src/formatter/mod.rs b/src/formatter/mod.rs index 2a43a79..21292b3 100644 --- a/src/formatter/mod.rs +++ b/src/formatter/mod.rs @@ -1,4 +1,5 @@ pub mod format; +mod printers; use crate::formatter::format::Format; use serde::Deserialize; diff --git a/src/formatter/printers.rs b/src/formatter/printers.rs new file mode 100644 index 0000000..08d0122 --- /dev/null +++ b/src/formatter/printers.rs @@ -0,0 +1,5 @@ + + +pub fn print_bytes_as_array(data: &[u8]) -> String { + format!("{:?}", data) +} \ No newline at end of file