diff --git a/Cargo.lock b/Cargo.lock index 327baa4..4958e5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ [[package]] name = "binary_utils" -version = "0.2.0" +version = "0.2.1" dependencies = [ "bin_macro", "byteorder", diff --git a/Cargo.toml b/Cargo.toml index fd8e239..5032ab2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "binary_utils" -version = "0.2.0" +version = "0.2.1" authors = ["Bavfalcon9 "] edition = "2018" include = ["src/**/*", "README.md"] diff --git a/bin_macro/src/lib.rs b/bin_macro/src/lib.rs index a1e4fdc..be46294 100644 --- a/bin_macro/src/lib.rs +++ b/bin_macro/src/lib.rs @@ -1,6 +1,3 @@ -// #![feature(trace_macros)] -// trace_macros!(true); - use proc_macro::TokenStream; use syn::{parse_macro_input, DeriveInput}; mod stream; diff --git a/bin_macro/src/stream.rs b/bin_macro/src/stream.rs index 271240b..1b059e2 100644 --- a/bin_macro/src/stream.rs +++ b/bin_macro/src/stream.rs @@ -16,23 +16,23 @@ pub fn stream_parse(input: DeriveInput) -> Result { Ok(quote! { #[automatically_derived] impl Streamable for #name { - fn parse(&self) -> Vec { + fn parse(&self) -> Result, ::binary_utils::error::BinaryError> { use ::std::io::Write; use binary_utils::varint::{VarInt, VarIntWriter}; use binary_utils::u24::{u24, u24Writer}; let mut writer = Vec::new(); #writes - writer + Ok(writer) } - fn compose(source: &[u8], position: &mut usize) -> Self { + fn compose(source: &[u8], position: &mut usize) -> Result { use ::std::io::Read; use binary_utils::varint::{VarInt, VarIntReader}; use binary_utils::u24::{u24, u24Reader}; - Self { + Ok(Self { #reads - } + }) } } }) @@ -61,9 +61,9 @@ pub fn stream_parse(input: DeriveInput) -> Result { match &variant.fields { Fields::Unit => { // writers - writers.push(quote!(Self::#var_name => (#discrim as #enum_ty).parse(),)); + writers.push(quote!(Self::#var_name => Ok((#discrim as #enum_ty).parse()?),)); // readers - readers.push(quote!(#discrim => Self::#var_name,)); + readers.push(quote!(#discrim => Ok(Self::#var_name),)); }, Fields::Unnamed(_fields) => { return Err(Error::new_spanned(variant, "Variant fields are not explicitly supported yet.")); @@ -78,21 +78,20 @@ pub fn stream_parse(input: DeriveInput) -> Result { Ok(quote!{ #[automatically_derived] impl Streamable for #name { - fn parse(&self) -> Vec { + fn parse(&self) -> Result, ::binary_utils::error::BinaryError> { match self { #(#writers)* } } - fn compose(source: &[u8], offset: &mut usize) -> Self { + fn compose(source: &[u8], offset: &mut usize) -> Result { // get the repr type and read it - let v = <#enum_ty>::compose(source, offset); + let v = <#enum_ty>::compose(source, offset)?; match v { #(#readers)* _ => panic!("Will not fit in enum!") } - } } }) @@ -133,8 +132,8 @@ pub fn impl_named_fields(fields: Fields) -> (Vec, Vec) pub fn impl_streamable_lazy(name: &Ident, ty: &Type) -> (TokenStream, TokenStream) { ( - quote! { writer.write(&self.#name.parse()[..]).unwrap(); }, - quote!(#name: #ty::compose(&source, position)), + quote! { writer.write(&self.#name.parse()?[..])?; }, + quote!(#name: #ty::compose(&source, position)?), ) } diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..16d05ed --- /dev/null +++ b/src/error.rs @@ -0,0 +1,45 @@ +/// An enum consisting of a Binary Error +/// (recoverable) +#[derive(Debug, PartialEq)] +pub enum BinaryError { + /// Offset is out of bounds + /// + /// **Tuple Values:** + /// - `usize` = Given Offset. + /// - `usize` = Stream length. + /// - `&'static str` = Message to add on to the error. + OutOfBounds(usize, usize, &'static str), + + /// Similar to `OutOfBounds` except it means; + /// the stream tried to read more than possible. + /// + /// **Tuple Values:** + /// - `usize` = Stream length. + EOF(usize), + + /// A known error that was recoverable to safely proceed the stack. + RecoverableKnown(String), + + /// An unknown error occurred, but it wasn't critical, + /// we can safely proceed on the stack. + RecoverableUnknown, +} + +impl BinaryError { + pub fn get_message(&self) -> String { + match self { + Self::OutOfBounds(offset, length, append) => { + format!("Offset {} out of range for a buffer size with: {}. {}", offset, length, append) + }, + Self::EOF(length) => format!("Buffer reached End Of File at offset: {}", length), + Self::RecoverableKnown(msg) => msg.clone(), + Self::RecoverableUnknown => "An interruption occurred when performing a binary operation, however this error was recovered safely.".to_string() + } + } +} + +impl From for BinaryError { + fn from(_error: std::io::Error) -> Self { + Self::RecoverableUnknown + } +} diff --git a/src/lib.rs b/src/lib.rs index 21ab707..52d81c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,8 +8,10 @@ use std::net::{IpAddr, Ipv6Addr, SocketAddr, SocketAddrV6}; pub use bin_macro::*; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use error::BinaryError; use std::io::{Cursor, Read, Write}; +pub mod error; pub mod u24; pub mod varint; @@ -27,38 +29,57 @@ macro_rules! includes { /// A trait to parse and unparse header structs from a given buffer. /// /// **Example:** -/// ```rust ignore +/// ```rust +/// use binary_utils::{Streamable, error::BinaryError}; +/// /// struct Foo { /// bar: u8, /// foo_bar: u16 /// } -/// /// impl Streamable for Foo { -/// fn parse(&self) -> Vec { +/// fn parse(&self) -> Result, BinaryError> { /// use std::io::Write; /// let mut stream = Vec::::new(); -/// stream.write_all(bar.parse()[..]); -/// stream.write_all(bar.parse()[..]); -/// stream +/// stream.write_all(&self.bar.parse()?[..])?; +/// stream.write_all(&self.bar.parse()?[..])?; +/// Ok(stream) /// } /// -/// fn compose(source: &[u8], position: &mut usize) -> Self { +/// fn compose(source: &[u8], position: &mut usize) -> Result { /// // Streamable is implemented for all primitives, so we can /// // just use this implementation to read our properties. -/// Self { -/// bar: u8::compose(&source, &mut position), -/// foo_bar: u16::compose(&source, &mut position) -/// } +/// Ok(Self { +/// bar: u8::compose(&source, position)?, +/// foo_bar: u16::compose(&source, position)? +/// }) /// } /// } /// ``` pub trait Streamable { /// Writes `self` to the given buffer. - fn parse(&self) -> Vec; + fn parse(&self) -> Result, BinaryError>; + + /// Writes and unwraps `self` to the given buffer. + /// + /// ⚠️ This method is not fail safe, and will panic if result is Err. + fn fparse(&self) -> Vec { + self.parse().unwrap() + } + /// Reads `self` from the given buffer. - fn compose(source: &[u8], position: &mut usize) -> Self + fn compose(source: &[u8], position: &mut usize) -> Result where Self: Sized; + + /// Reads and unwraps `self` from the given buffer. + /// + /// ⚠️ This method is not fail safe, and will panic if result is Err. + fn fcompose(source: &[u8], position: &mut usize) -> Self + where + Self: Sized, + { + Self::compose(source, position).unwrap() + } } /// Little Endian Type @@ -67,27 +88,39 @@ pub trait Streamable { /// This struct assumes the incoming buffer is BE and needs to be transformed. /// /// For LE decoding in BE streams use: -/// ```rust ignore -/// fn read_u16_le(source: &[u8], offset: &mut usize) { +/// ```rust +/// use binary_utils::{LE, Streamable, error::BinaryError}; +/// +/// fn read_u16_le(source: &[u8], offset: &mut usize) -> LE { /// // get the size of your type, in this case it's 2 bytes. -/// let be_source = &source[offset..2]; +/// let be_source = &source[*offset..2]; /// *offset += 2; /// // now we can form the little endian -/// return LE::::compose(&be_source, &mut 0); +/// return LE::::compose(&be_source, &mut 0).unwrap(); /// } +/// +/// assert_eq!(LE::(10).inner(), read_u16_le(&[10, 0], &mut 0).inner()); /// ``` #[derive(Debug, Clone, Copy)] pub struct LE(pub T); +impl LE { + /// Grabs the `inner` type, similar to `unwrap`. + pub fn inner(self) -> T { + self.0 + } +} + impl Streamable for LE where T: Streamable + Sized, { - fn parse(&self) -> Vec { - reverse_vec(self.0.parse()) + fn parse(&self) -> Result, BinaryError> { + let bytes = self.0.parse()?; + Ok(reverse_vec(bytes)) } - fn compose(source: &[u8], position: &mut usize) -> Self { + fn compose(source: &[u8], position: &mut usize) -> Result { // If the source is expected to be LE we can swap it to BE bytes // Doing this makes the byte stream officially BE. // We actually need to do some hacky stuff here, @@ -115,17 +148,19 @@ where // we need to get the stream releative to the current source, and "inject" into the current source. // we can do this by getting the position and the length of the stream. let mut hacked_stream = Vec::::new(); - hacked_stream.write_all(&source[..*position]).unwrap(); - // now we write the rest of our changed stream - hacked_stream.write_all(&stream).unwrap(); - - LE(T::compose(&hacked_stream[..], position)) - } -} - -impl LE { - pub fn inner(self) -> T { - self.0 + let (q1, q2) = ( + hacked_stream.write_all(&source[..*position]), + hacked_stream.write_all(&stream), + ); + + // check if any of the queries were invalid or failed. + if q1.is_err() || q2.is_err() { + Err(BinaryError::RecoverableKnown( + "Write operation was interupted.".to_owned(), + )) + } else { + Ok(LE(T::compose(&hacked_stream[..], position)?)) + } } } @@ -145,17 +180,17 @@ pub struct BE(pub T); macro_rules! impl_streamable_primitive { ($ty: ty) => { impl Streamable for $ty { - fn parse(&self) -> Vec { - self.to_be_bytes().to_vec() + fn parse(&self) -> Result, BinaryError> { + Ok(self.to_be_bytes().to_vec()) } - fn compose(source: &[u8], position: &mut usize) -> Self { + fn compose(source: &[u8], position: &mut usize) -> Result { // get the size let size = ::std::mem::size_of::<$ty>(); let range = position.clone()..(size + position.clone()); let data = <$ty>::from_be_bytes(source.get(range).unwrap().try_into().unwrap()); *position += size; - data + Ok(data) } } @@ -192,19 +227,19 @@ impl_streamable_primitive!(i128); macro_rules! impl_streamable_vec_primitive { ($ty: ty) => { impl Streamable for Vec<$ty> { - fn parse(&self) -> Vec { + fn parse(&self) -> Result, BinaryError> { use ::std::io::Write; // write the length as a varint let mut v: Vec = Vec::new(); v.write_all(&VarInt(v.len() as u32).to_be_bytes()[..]) .unwrap(); for x in self.iter() { - v.extend(x.parse().iter()); + v.extend(x.parse()?.iter()); } - v + Ok(v) } - fn compose(source: &[u8], position: &mut usize) -> Self { + fn compose(source: &[u8], position: &mut usize) -> Result { // use ::std::io::Read; // read a var_int let mut ret: Vec<$ty> = Vec::new(); @@ -215,9 +250,9 @@ macro_rules! impl_streamable_vec_primitive { // read each length for _ in 0..length { - ret.push(<$ty>::compose(&source, position)); + ret.push(<$ty>::compose(&source, position)?); } - ret + Ok(ret) } } }; @@ -238,81 +273,89 @@ impl_streamable_vec_primitive!(i128); // implements bools impl Streamable for bool { - fn parse(&self) -> Vec { - vec![if *self { 1 } else { 0 }] + fn parse(&self) -> Result, BinaryError> { + Ok(vec![if *self { 1 } else { 0 }]) } - fn compose(source: &[u8], position: &mut usize) -> Self { - let v = source[*position] == 1; - *position += 1; - v + fn compose(source: &[u8], position: &mut usize) -> Result { + // header validation + if source[*position] > 1 { + Err(BinaryError::RecoverableKnown(format!( + "Tried composing binary from non-binary byte: {}", + source[*position] + ))) + } else { + let v = source[*position] == 1; + *position += 1; + Ok(v) + } } } impl Streamable for String { - fn parse(&self) -> Vec { + fn parse(&self) -> Result, BinaryError> { let mut buffer = Vec::::new(); - buffer.write_u16::(self.len() as u16).unwrap(); - buffer.write_all(self.as_bytes()).unwrap(); - buffer + buffer.write_u16::(self.len() as u16)?; + buffer.write_all(self.as_bytes())?; + Ok(buffer) } - fn compose(source: &[u8], position: &mut usize) -> Self { + fn compose(source: &[u8], position: &mut usize) -> Result { let mut stream = Cursor::new(source); stream.set_position(position.clone() as u64); // Maybe do this in the future? - let len: usize = stream.read_u16::().unwrap().into(); + let len: usize = stream.read_u16::()?.into(); *position = (stream.position() as usize) + len; unsafe { // todo: Remove this nasty hack. // todo: The hack being, remove the 2 from indexing on read_short // todo: And utilize stream. - String::from_utf8_unchecked( + Ok(String::from_utf8_unchecked( stream.get_ref()[2..len + stream.position() as usize].to_vec(), - ) + )) } } } impl Streamable for SocketAddr { - fn parse(&self) -> Vec { + fn parse(&self) -> Result, BinaryError> { let mut stream = Vec::::new(); match *self { Self::V4(_) => { - stream.write_u8(4).unwrap(); + stream.write_u8(4)?; let partstr = self.to_string(); let parts: Vec<&str> = partstr.split(".").collect(); for part in parts { let mask = u8::from_str_radix(part, 10).unwrap_or(0); - stream.write_u8(mask).unwrap(); + stream.write_u8(mask)?; } stream .write_u16::(self.port()) .expect("Could not write port to stream."); - stream + Ok(stream) } Self::V6(addr) => { - stream.write_u8(6).unwrap(); + stream.write_u8(6)?; // family? or length?? - stream.write_u16::(0).unwrap(); + stream.write_u16::(0)?; // port - stream.write_u16::(self.port()).unwrap(); + stream.write_u16::(self.port())?; // flow - stream.write_u32::(addr.flowinfo()).unwrap(); + stream.write_u32::(addr.flowinfo())?; // actual address here - stream.write(&addr.ip().octets()).unwrap(); + stream.write(&addr.ip().octets())?; // scope - stream.write_u32::(addr.scope_id()).unwrap(); - stream + stream.write_u32::(addr.scope_id())?; + Ok(stream) } } } - fn compose(source: &[u8], position: &mut usize) -> Self { + fn compose(source: &[u8], position: &mut usize) -> Result { let mut stream = Cursor::new(source); stream.set_position(*position as u64); - match stream.read_u8().unwrap() { + match stream.read_u8()? { 4 => { let from = stream.position() as usize; let to = stream.position() as usize + 4; @@ -320,7 +363,10 @@ impl Streamable for SocketAddr { stream.set_position(to as u64); let port = stream.read_u16::().unwrap(); *position = stream.position() as usize; - SocketAddr::new(IpAddr::from([parts[0], parts[1], parts[2], parts[3]]), port) + Ok(SocketAddr::new( + IpAddr::from([parts[0], parts[1], parts[2], parts[3]]), + port, + )) } 6 => { let _family = stream.read_u16::().unwrap(); @@ -345,18 +391,12 @@ impl Streamable for SocketAddr { }; let scope = stream.read_u32::().unwrap(); *position = stream.position() as usize; - SocketAddr::from(SocketAddrV6::new(address, port, flow, scope)) + Ok(SocketAddr::from(SocketAddrV6::new( + address, port, flow, scope, + ))) } _ => panic!("Unknown Address type!"), } - // let addr_type = self.read_byte(); - // if addr_type == 4 { - // let parts = self.read_slice(Some(4 as usize)); - // let port = self.read_ushort(); - // SocketAddr::new(IpAddr::from([parts[0], parts[1], parts[2], parts[3]]), port) - // } else { - // SocketAddr::new(IpAddr::from([0, 0, 0, 0]), 0) - // } } } @@ -365,26 +405,26 @@ impl Streamable for Vec> where T: Streamable, { - fn parse(&self) -> Vec { + fn parse(&self) -> Result, BinaryError> { // write the length as a varint let mut v: Vec = Vec::new(); - v.write_u16::(self.len() as u16).unwrap(); + v.write_u16::(self.len() as u16)?; for x in self.iter() { - v.extend(x.parse().iter()); + v.extend(x.parse()?.iter()); } - v + Ok(v) } - fn compose(source: &[u8], position: &mut usize) -> Self { + fn compose(source: &[u8], position: &mut usize) -> Result { // read a var_int let mut stream = Cursor::new(source); let mut ret: Vec> = Vec::new(); - let length = stream.read_u16::().unwrap(); + let length = stream.read_u16::()?; *position = stream.position() as usize; // read each length for _ in 0..length { - ret.push(LE::::compose(&source[*position..], &mut 0)); + ret.push(LE::::compose(&source[*position..], &mut 0)?); } - ret + Ok(ret) } } diff --git a/src/u24.rs b/src/u24.rs index e99ac71..d8935bb 100644 --- a/src/u24.rs +++ b/src/u24.rs @@ -6,6 +6,7 @@ use std::convert::{From, Into}; use std::io; use std::ops::{Add, BitOr, Div, Mul, Sub}; +use crate::error::BinaryError; use crate::Streamable; /// Base Implementation for a u24 /// A u24 is 3 bytes (24 bits) wide number. @@ -38,13 +39,13 @@ impl u24 { impl Streamable for u24 { /// Writes `self` to the given buffer. - fn parse(&self) -> Vec { - self.to_be_bytes().to_vec().clone() + fn parse(&self) -> Result, BinaryError> { + Ok(self.to_be_bytes().to_vec().clone()) } /// Reads `self` from the given buffer. - fn compose(source: &[u8], position: &mut usize) -> Self { + fn compose(source: &[u8], position: &mut usize) -> Result { *position += 2; - Self::from_be_bytes(source) + Ok(Self::from_be_bytes(source)) } } diff --git a/src/varint.rs b/src/varint.rs index 1978570..f88388c 100644 --- a/src/varint.rs +++ b/src/varint.rs @@ -100,14 +100,14 @@ macro_rules! varint_impl_generic { impl Streamable for VarInt<$ty> { /// Writes `self` to the given buffer. - fn parse(&self) -> Vec { - self.to_be_bytes().to_vec().clone() + fn parse(&self) -> Result, crate::error::BinaryError> { + Ok(self.to_be_bytes().to_vec().clone()) } /// Reads `self` from the given buffer. - fn compose(source: &[u8], position: &mut usize) -> Self { + fn compose(source: &[u8], position: &mut usize) -> Result { let v = Self::from_be_bytes(source); *position += v.get_byte_length() as usize; - v + Ok(v) } } @@ -207,14 +207,14 @@ macro_rules! varint_impl_generic64 { impl Streamable for VarInt<$ty> { /// Writes `self` to the given buffer. - fn parse(&self) -> Vec { - self.to_be_bytes().to_vec().clone() + fn parse(&self) -> Result, crate::error::BinaryError> { + Ok(self.to_be_bytes().to_vec().clone()) } /// Reads `self` from the given buffer. - fn compose(source: &[u8], position: &mut usize) -> Self { + fn compose(source: &[u8], position: &mut usize) -> Result { let v = Self::from_be_bytes(&mut Cursor::new(source.to_vec())); *position += v.get_byte_length() as usize; - v + Ok(v) } } }; diff --git a/tests/enum.rs b/tests/enum.rs index 9cf6865..61f928d 100644 --- a/tests/enum.rs +++ b/tests/enum.rs @@ -1,30 +1,37 @@ use bin_macro::*; -use binary_utils::Streamable; +use binary_utils::{error::BinaryError, Streamable}; #[derive(Debug, BinaryStream, PartialEq)] #[repr(u8)] pub enum Test { - Apple = 0, - Pair = 1 + Apple = 0, + Pair = 1, } #[test] fn read_test_from_buffer() { - let buffer: &[u8] = &[0]; - let result = Test::compose(buffer, &mut 0); - assert_eq!(Test::Apple, result); + let buffer: &[u8] = &[0]; + let result = Test::compose(buffer, &mut 0).unwrap(); + assert_eq!(Test::Apple, result); } #[test] -fn write_read_buffer() { - // write first - let variant = Test::Pair; - let buffer = variant.parse(); +fn write_read_buffer() -> Result<(), BinaryError> { + // write first + let variant = Test::Pair; + let buffer = variant.parse()?; - assert_eq!(buffer, vec![1]); + assert_eq!(buffer, vec![1]); - // read now - let compose = Test::compose(&buffer[..], &mut 0); + // read now + let compose = Test::compose(&buffer[..], &mut 0)?; - assert!(match compose { Test::Pair => true, _ => false }, "Reconstruction was not equivelant to Test::Pair"); -} \ No newline at end of file + assert!( + match compose { + Test::Pair => true, + _ => false, + }, + "Reconstruction was not equivelant to Test::Pair" + ); + Ok(()) +} diff --git a/tests/le_test.rs b/tests/le_test.rs index d3e427e..6c346cc 100644 --- a/tests/le_test.rs +++ b/tests/le_test.rs @@ -3,42 +3,46 @@ use std::io::Write; use binary_utils::*; #[test] -fn read_write_le_mixed() { - // LE encoded size, but BE data - // The first 3 bytes are dummy bytes - let buff_one: Vec = vec![32, 32, 32, 12, 0, 0, 0, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 32, 32, 32, 32]; - - // read first 3 bytes. - // this makes our offset 3 - let le_header = &buff_one[3..]; - let mut offset: usize = 0; - - // get the length - let length = LE::::compose(&le_header, &mut offset).0 as usize; - assert_eq!(12, length); - - // now get the rest of the buffer based on the length - let decoded = String::from_utf8(le_header[offset..(length + offset)].to_vec()).unwrap(); - assert_eq!(decoded, "Hello World!".to_string()); - - // get the rest of the buffer, there should be 4 more bytes - assert_eq!(&le_header[(length + offset)..], &[32, 32, 32, 32]); - - // Writing test - let mut buff_two: Vec = vec![32, 32, 32, 32]; - let to_encode = "Hello World!".to_string(); - - // The length of the string in LE: - let length = LE::(to_encode.len() as u32); - buff_two.write_all(&length.parse()[..]).unwrap(); - // we should now have the length of 12 written in LE - - // write the contents of the string now... - buff_two.write_all(&to_encode.as_bytes()).unwrap(); - - // Write magic to buffer. - buff_two.write_all(&[32, 32, 32, 32]).unwrap(); - - // Now check - assert_eq!(buff_one, &buff_one[..]); -} \ No newline at end of file +fn read_write_le_mixed() -> Result<(), error::BinaryError> { + // LE encoded size, but BE data + // The first 3 bytes are dummy bytes + let buff_one: Vec = vec![ + 32, 32, 32, 12, 0, 0, 0, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 32, 32, + 32, 32, + ]; + + // read first 3 bytes. + // this makes our offset 3 + let le_header = &buff_one[3..]; + let mut offset: usize = 0; + + // get the length + let length = LE::::compose(&le_header, &mut offset)?.0 as usize; + assert_eq!(12, length); + + // now get the rest of the buffer based on the length + let decoded = String::from_utf8(le_header[offset..(length + offset)].to_vec()).unwrap(); + assert_eq!(decoded, "Hello World!".to_string()); + + // get the rest of the buffer, there should be 4 more bytes + assert_eq!(&le_header[(length + offset)..], &[32, 32, 32, 32]); + + // Writing test + let mut buff_two: Vec = vec![32, 32, 32, 32]; + let to_encode = "Hello World!".to_string(); + + // The length of the string in LE: + let length = LE::(to_encode.len() as u32); + buff_two.write_all(&length.parse()?[..])?; + // we should now have the length of 12 written in LE + + // write the contents of the string now... + buff_two.write_all(&to_encode.as_bytes())?; + + // Write magic to buffer. + buff_two.write_all(&[32, 32, 32, 32])?; + + // Now check + assert_eq!(buff_one, &buff_one[..]); + Ok(()) +} diff --git a/tests/lstring.rs b/tests/lstring.rs index 91c9faf..664a7c3 100644 --- a/tests/lstring.rs +++ b/tests/lstring.rs @@ -1,66 +1,65 @@ use binary_utils::*; -use std::{io::Write}; - +use std::io::Write; // Extracted from protocol. #[derive(Debug, Clone)] pub struct LString32(pub String); impl Streamable for LString32 { - fn parse(&self) -> Vec { - // get the length - let mut buffer: Vec = Vec::new(); - buffer.write_all(&LE::(self.0.len() as u32).parse()[..]).unwrap(); - // now we write string buffer. - buffer.write_all(&self.0.clone().into_bytes()[..]).unwrap(); - buffer - } + fn parse(&self) -> Result, error::BinaryError> { + // get the length + let mut buffer: Vec = Vec::new(); + buffer.write_all(&LE::(self.0.len() as u32).parse()?[..])?; + // now we write string buffer. + buffer.write_all(&self.0.clone().into_bytes()[..])?; + Ok(buffer) + } - fn compose(source: &[u8], position: &mut usize) -> Self { - let length = LE::::compose(&source[..], position); - let bytes = &source[*position..(*position + length.0 as usize)]; + fn compose(source: &[u8], position: &mut usize) -> Result { + let length = LE::::compose(&source[..], position)?; + let bytes = &source[*position..(*position + length.0 as usize)]; - *position += bytes.len(); + *position += bytes.len(); - Self(unsafe { String::from_utf8_unchecked(bytes.to_vec()) }) - } + Ok(Self(unsafe { String::from_utf8_unchecked(bytes.to_vec()) })) + } } - pub const HW_TEST_DATA: &[u8] = &[ - // Length of the string in Little Endian Format - 12, 0, 0, 0, - // Contents of string - 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33 + // Length of the string in Little Endian Format + 12, 0, 0, 0, // Contents of string + 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, ]; #[test] fn write_l32string() { - let hello_world = "Hello World!".to_string(); - let data = LString32(hello_world).parse(); + let hello_world = "Hello World!".to_string(); + let data = LString32(hello_world).parse().unwrap(); - assert_eq!(HW_TEST_DATA, &data[..]); + assert_eq!(HW_TEST_DATA, &data[..]); } #[test] fn read_l32string() { - let hello_world = "Hello World!".to_string(); - let data = LString32::compose(HW_TEST_DATA, &mut 0); - assert_eq!(data.0, hello_world); + let hello_world = "Hello World!".to_string(); + let data = LString32::compose(HW_TEST_DATA, &mut 0).unwrap(); + assert_eq!(data.0, hello_world); } #[test] fn read_twice() { - let hello_world = "Hello World!".to_string(); - let mut stream = Vec::::new(); - stream.write_all(&LString32(hello_world.clone()).parse()[..]).unwrap(); - stream.write_all(&LString32(hello_world).parse()[..]).unwrap(); - // ok read it. - let mut pos: usize = 0; - let one = LString32::compose(&stream[..], &mut pos).0; - dbg!(&one); - dbg!(&pos); - let two = LString32::compose(&stream[..], &mut pos).0; + let hello_world = "Hello World!".to_string(); + let mut stream = Vec::::new(); + stream + .write_all(&LString32(hello_world.clone()).parse().unwrap()[..]) + .unwrap(); + stream + .write_all(&LString32(hello_world).parse().unwrap()[..]) + .unwrap(); + // ok read it. + let mut pos: usize = 0; + let one = LString32::compose(&stream[..], &mut pos).unwrap().0; + let two = LString32::compose(&stream[..], &mut pos).unwrap().0; - assert_eq!(one, two); -} \ No newline at end of file + assert_eq!(one, two); +} diff --git a/tests/macro_tests.rs b/tests/macro_tests.rs index b681c6b..f7987df 100644 --- a/tests/macro_tests.rs +++ b/tests/macro_tests.rs @@ -1,5 +1,5 @@ use bin_macro::*; -use binary_utils::{LE, Streamable, reverse_vec}; +use binary_utils::{reverse_vec, Streamable, LE}; #[derive(Debug, BinaryStream)] pub struct TestPacket { pub some_int: u8, @@ -10,80 +10,40 @@ pub struct TestPacket { #[test] fn construct_struct() { let buf = vec![1, 30]; - let pk = TestPacket::compose(&buf, &mut 0); - assert_eq!(buf, pk.parse()) + let pk = TestPacket::compose(&buf, &mut 0).unwrap(); + assert_eq!(buf, pk.parse().unwrap()) } - #[test] fn write_string() { let string = String::from("Hello world!"); - let hello_world_vec= vec![ - 0, - 12, - 72, - 101, - 108, - 108, - 111, - 32, - 119, - 111, - 114, - 108, - 100, - 33 + let hello_world_vec = vec![ + 0, 12, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, ]; - assert_eq!(hello_world_vec, string.parse()); + assert_eq!(hello_world_vec, string.parse().unwrap()); } #[test] fn read_string() { - let hello_world_vec= vec![ - 0, - 12, - 72, - 101, - 108, - 108, - 111, - 32, - 119, - 111, - 114, - 108, - 100, - 33 + let hello_world_vec = vec![ + 0, 12, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, ]; - let string = String::compose(&hello_world_vec[..], &mut 0); + let string = String::compose(&hello_world_vec[..], &mut 0).unwrap(); assert_eq!("Hello world!".to_string(), string); } #[derive(BinaryStream)] pub struct HelloWorld { - data: LE:: + data: LE::, } #[test] fn endianness() { - let hello_world_vec_le= reverse_vec(vec![ - 0, - 12, - 72, - 101, - 108, - 108, - 111, - 32, - 119, - 111, - 114, - 108, - 100, - 33 + let hello_world_vec_le = reverse_vec(vec![ + 0, 12, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, ]); - let data = HelloWorld::compose(&hello_world_vec_le, &mut 0); + let data = HelloWorld::compose(&hello_world_vec_le, &mut 0).unwrap(); assert_eq!("Hello world!".to_string(), data.data.inner()); -} \ No newline at end of file +} diff --git a/tests/tests.rs b/tests/tests.rs index dceee37..6c383c1 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,6 +1,6 @@ // make a test +mod le_test; +mod lstring; mod macro_tests; -mod vec; mod var_int; -mod le_test; -mod lstring; \ No newline at end of file +mod vec; diff --git a/tests/var_int.rs b/tests/var_int.rs index a40b7f6..7d23ac1 100644 --- a/tests/var_int.rs +++ b/tests/var_int.rs @@ -2,16 +2,22 @@ use binary_utils::*; #[test] fn read_write_var_int() { - let one = VarInt::(2147483647); - let two = VarInt::(255); - let buf_one = one.parse(); - let buf_two = two.parse(); + let one = VarInt::(2147483647); + let two = VarInt::(255); + let buf_one = one.parse().unwrap(); + let buf_two = two.parse().unwrap(); - assert_eq!(buf_one, vec![255, 255, 255, 255, 7]); - assert_eq!(buf_two, vec![255, 1]); + assert_eq!(buf_one, vec![255, 255, 255, 255, 7]); + assert_eq!(buf_two, vec![255, 1]); - let buf_long_one = VarInt::(9223372036854775807).parse(); - assert_eq!(buf_long_one, vec![255, 255, 255, 255, 255, 255, 255, 255, 127]); + let buf_long_one = VarInt::(9223372036854775807).parse().unwrap(); + assert_eq!( + buf_long_one, + vec![255, 255, 255, 255, 255, 255, 255, 255, 127] + ); - assert_eq!(one.0, VarInt::::compose(&buf_one[..], &mut 0).0); -} \ No newline at end of file + assert_eq!( + one.0, + VarInt::::compose(&buf_one[..], &mut 0).unwrap().0 + ); +} diff --git a/tests/vec.rs b/tests/vec.rs index b21dd74..015f67e 100644 --- a/tests/vec.rs +++ b/tests/vec.rs @@ -1,4 +1,4 @@ -use binary_utils::{LE, varint::VarInt, Streamable}; +use binary_utils::{varint::VarInt, Streamable, LE}; #[test] fn test_varint() { @@ -14,17 +14,17 @@ fn test_le_vec() { // LE bytes for "Netrex" let le_bytes_netrex: Vec = vec![120, 101, 114, 116, 101, 78, 6, 0]; let str_bytes = LE("Netrex".to_string()); - println!("{:?}", str_bytes.parse()); + println!("{:?}", str_bytes.fparse()); - assert_eq!(str_bytes.parse(), le_bytes_netrex); + assert_eq!(str_bytes.fparse(), le_bytes_netrex); - let mut test: Vec> = Vec::new(); + let mut test: Vec> = Vec::new(); test.push(str_bytes.clone()); // Vectors store length {stream, stream } // where "stream" in this case is [length, string bytes] - let vector = test.parse(); + let vector = test.fparse(); println!("{:?}", vector); - let restored = Vec::>::compose(&vector[..], &mut 0); + let restored = Vec::>::fcompose(&vector[..], &mut 0); assert_eq!(restored[0].clone().inner(), str_bytes.inner()) -} \ No newline at end of file +}