From 77ccd5504157cc300d78edc5c2355d7298940e8d Mon Sep 17 00:00:00 2001 From: Matt Bilker Date: Thu, 6 Sep 2018 07:06:45 +0000 Subject: [PATCH] node_types: use Value for handling byte serialization --- Cargo.toml | 2 +- src/error.rs | 3 - src/kbin_wrapper.rs | 145 ---------------------- src/lib.rs | 7 +- src/node_types.rs | 119 ------------------ src/value/mod.rs | 287 +++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 274 insertions(+), 289 deletions(-) delete mode 100644 src/kbin_wrapper.rs diff --git a/Cargo.toml b/Cargo.toml index c214243..e3ca40d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kbinxml" -version = "0.8.0" +version = "0.9.2" authors = ["Matt Bilker "] [dependencies] diff --git a/src/error.rs b/src/error.rs index 3304322..3f0242b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -65,9 +65,6 @@ pub enum KbinErrorKind { #[fail(display = "Unable to read array node length")] ArrayLengthRead, - #[fail(display = "Failed to write {} to output string", _0)] - ByteParse(&'static str), - #[fail(display = "Unable to read sixbit string length")] SixbitLengthRead, diff --git a/src/kbin_wrapper.rs b/src/kbin_wrapper.rs deleted file mode 100644 index cd84cf6..0000000 --- a/src/kbin_wrapper.rs +++ /dev/null @@ -1,145 +0,0 @@ -use std::fmt::Write; - -use byteorder::WriteBytesExt; -use failure::ResultExt; - -use error::{KbinError, KbinErrorKind}; - -pub(crate) trait KbinWrapperType { - fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError>; - fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError>; -} - -macro_rules! number_impl { - (int; $($inner_type:ident),*) => { - $( - impl KbinWrapperType<$inner_type> for $inner_type { - fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType<{}> from bytes => input: {:02x?}", stringify!($inner_type), input); - - let mut data = [0; ::std::mem::size_of::<$inner_type>()]; - data.clone_from_slice(input); - write!(output, "{}", $inner_type::from_be_bytes(data)) - .context(KbinErrorKind::ByteParse(stringify!($inner_type)))?; - - Ok(()) - } - - fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { - let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?; - trace!("KbinWrapperType<{}> to bytes => input: '{}', output: {}", stringify!($inner_type), input, num); - - let data = $inner_type::to_be_bytes(num); - output.extend_from_slice(&data); - - Ok(()) - } - } - )* - }; - (float; $($intermediate:ident => $inner_type:ident),*) => { - $( - impl KbinWrapperType<$inner_type> for $inner_type { - fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType<{}> from bytes => input: {:02x?}", stringify!($inner_type), input); - - let mut data = [0; ::std::mem::size_of::<$inner_type>()]; - data.clone_from_slice(input); - let bits = $intermediate::from_be_bytes(data); - - write!(output, "{:.6}", $inner_type::from_bits(bits)) - .context(KbinErrorKind::ByteParse(stringify!($inner_type)))?; - - Ok(()) - } - - fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { - let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?; - trace!("KbinWrapperType<{}> to bytes => input: '{}', output: {}", stringify!($inner_type), input, num); - - let data = $intermediate::to_be_bytes(num.to_bits()); - output.extend_from_slice(&data); - - Ok(()) - } - } - )* - }; -} - -number_impl!(int; u8, u16, u32, u64); -number_impl!(int; i8, i16, i32, i64); -number_impl!(float; u32 => f32, u64 => f64); - -impl KbinWrapperType for bool { - fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType from bytes => input: {:02x?}", input); - - let value = match input[0] { - 0x00 => "0", - 0x01 => "1", - v => panic!("Unsupported value for boolean: {}", v), - }; - output.push_str(value); - - Ok(()) - } - - fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { - let value = match input { - "0" => 0x00, - "1" => 0x01, - v => panic!("Unsupported value for boolean: {}", v), - }; - - trace!("KbinWrapperType to bytes => input: '{}', output: {}", input, value); - output.write_u8(value).context(KbinErrorKind::DataWrite("bool"))?; - - Ok(()) - } -} - -pub(crate) struct Ip4; -pub(crate) struct DummyConverter; -pub(crate) struct InvalidConverter; - -impl KbinWrapperType for Ip4 { - fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType from bytes => input: {:02x?}", input); - - if input.len() != 4 { - panic!("Ip4 type requires exactly 4 bytes of data, input: {:02x?}", input); - } - - write!(output, "{}.{}.{}.{}", input[0], input[1], input[2], input[3]) - .context(KbinErrorKind::ByteParse("Ip4"))?; - - Ok(()) - } - - fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { - trace!("KbinWrapperType to bytes => input: '{}'", input); - - for part in input.split('.') { - let num = part.parse::().context(KbinErrorKind::StringParse("ip4 segment"))?; - output.write_u8(num).context(KbinErrorKind::DataWrite("ip4"))?; - } - - Ok(()) - } -} - -impl KbinWrapperType for DummyConverter { - fn from_kbin_bytes(_output: &mut String, _input: &[u8]) -> Result<(), KbinError> { Ok(()) } - fn to_kbin_bytes(_output: &mut Vec, _input: &str) -> Result<(), KbinError> { Ok(()) } -} - -impl KbinWrapperType for InvalidConverter { - fn from_kbin_bytes(_output: &mut String, input: &[u8]) -> Result<(), KbinError> { - panic!("Invalid kbin type converter called for input: {:02x?}", input); - } - - fn to_kbin_bytes(_output: &mut Vec, input: &str) -> Result<(), KbinError> { - panic!("Invalid kbin type converter called for input: {}", input); - } -} diff --git a/src/lib.rs b/src/lib.rs index 0fa66e3..7c22a02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(int_to_from_bytes)] - #![cfg_attr(test, feature(test))] extern crate byteorder; @@ -27,7 +25,6 @@ mod compression; mod encoding_type; mod error; mod ip4; -mod kbin_wrapper; mod node; mod node_types; mod options; @@ -227,7 +224,9 @@ impl KbinXml { }, _ => { - let data = node_type.to_bytes(&text, count as usize)?; + let value = Value::from_string(node_type, &text, array_mask > 0, count as usize)?; + let data = value.to_bytes()?; + if array_mask > 0 { let total_size = (count as u32) * (node_type.count as u32) * (node_type.size as u32); trace!("write_node data_buf array => total_size: {}, data: 0x{:02x?}", total_size, data); diff --git a/src/node_types.rs b/src/node_types.rs index fd9e5f4..ccacb02 100644 --- a/src/node_types.rs +++ b/src/node_types.rs @@ -1,9 +1,6 @@ use std::fmt; use std::ops::Deref; -use error::{KbinError, KbinErrorKind}; -use kbin_wrapper::*; - #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct KbinType { pub id: u8, @@ -14,106 +11,6 @@ pub struct KbinType { pub count: usize } -impl KbinType { - fn parse_array(&self, output: &mut String, input: &[u8], arr_count: usize) -> Result<(), KbinError> - where T: KbinWrapperType - { - let total_nodes = self.count * arr_count; - let total_size = self.size * total_nodes; - if total_size != input.len() { - return Err(KbinErrorKind::SizeMismatch(*self, total_size, input.len()).into()); - } - - // Guard when the input is of zero elements - if arr_count == 0 { - return Ok(()); - } - - { - let first = &input[..self.size]; - T::from_kbin_bytes(output, first)?; - } - - for i in 1..total_nodes { - let offset = i * self.size; - let end = (i + 1) * self.size; - let data = &input[offset..end]; - output.push(' '); - T::from_kbin_bytes(output, data)?; - } - - Ok(()) - } - - fn parse_bytes_inner(&self, input: &[u8]) -> Result - where T: KbinWrapperType - { - let type_size = self.size * self.count; - let arr_count = input.len() / type_size; - debug!("parse_bytes({}) => size: {}, count: {}, input_len: {}, arr_count: {}", self.name, self.size, self.count, input.len(), arr_count); - - let mut result = String::new(); - - match self.count { - 0 => panic!("Tried to parse special type: {}", self.name), - 1 => { - // May have a node (i.e. Ip4) that is only a single count, but it - // can be part of an array - if arr_count == 1 { - T::from_kbin_bytes(&mut result, input)?; - } else { - self.parse_array::(&mut result, input, arr_count)?; - } - }, - count if count > 1 => self.parse_array::(&mut result, input, arr_count)?, - _ => return Err(KbinErrorKind::InvalidState.into()), - }; - - Ok(result) - } - - fn to_array(&self, output: &mut Vec, input: &str, arr_count: usize) -> Result<(), KbinError> - where T: KbinWrapperType - { - for part in input.split(' ') { - T::to_kbin_bytes(output, part)?; - } - - let type_size = self.size * self.count; - let total_size = arr_count * type_size; - if total_size != output.len() { - return Err(KbinErrorKind::SizeMismatch(*self, total_size, output.len()).into()); - } - - Ok(()) - } - - fn to_bytes_inner(&self, input: &str, arr_count: usize) -> Result, KbinError> - where T: KbinWrapperType - { - debug!("to_bytes_inner({}) => size: {}, count: {}, input_len: {}, arr_count: {}", self.name, self.size, self.count, input.len(), arr_count); - - let mut output = Vec::new(); - - match self.count { - 0 => panic!("Tried to write special type: {}", self.name), - 1 => { - // May have a node (i.e. Ip4) that is only a single count, but it - // can be part of an array - match arr_count { - 0 => {}, - 1 => T::to_kbin_bytes(&mut output, input)?, - _ => self.to_array::(&mut output, input, arr_count)?, - }; - }, - count if count > 1 => self.to_array::(&mut output, input, arr_count)?, - _ => return Err(KbinErrorKind::InvalidState.into()), - }; - - Ok(output) - } -} - impl fmt::Display for KbinType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} ({})", self.konst, self.name) @@ -183,22 +80,6 @@ macro_rules! construct_types { } } - pub fn parse_bytes(&self, input: &[u8]) -> Result { - match *self { - $( - StandardType::$konst => self.parse_bytes_inner::<$inner_type>(input), - )+ - } - } - - pub fn to_bytes(&self, input: &str, arr_count: usize) -> Result, KbinError> { - match *self { - $( - StandardType::$konst => self.to_bytes_inner::<$inner_type>(input, arr_count), - )+ - } - } - find_type! { S8 => [ 2 S8_2 3 S8_3 4 S8_4 ] U8 => [ 2 U8_2 3 U8_3 4 U8_4 ] diff --git a/src/value/mod.rs b/src/value/mod.rs index a8a988a..18b41be 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,11 +1,14 @@ use std::fmt; use std::net::Ipv4Addr; +use std::str::FromStr; -use byteorder::{BigEndian, ByteOrder}; -use error::{KbinError, KbinErrorKind}; +use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; +use failure::{Fail, ResultExt}; +use rustc_hex::FromHex; use serde::de::{Deserialize, Deserializer, DeserializeSeed}; use serde_bytes::ByteBuf; +use error::{KbinError, KbinErrorKind}; use node::Node; use node::de::NodeSeed; use node_types::{self, StandardType}; @@ -21,7 +24,7 @@ macro_rules! tuple { bool: [$($bool_konst:ident),*] ], multi: [ - $($read_method:ident => [$($multi_konst:ident),*]),* + $($read_method:ident $write_method:ident $inner_type:ty => [$($multi_konst:ident),*]),* ] ) => { pub fn from_standard_type(node_type: StandardType, is_array: bool, input: &[u8]) -> Result, KbinError> { @@ -31,14 +34,15 @@ macro_rules! tuple { let mut values = Vec::new(); for chunk in input.chunks(node_size) { - trace!("chunk: {:?}", chunk); match Value::from_standard_type(node_type, false, chunk)? { Some(value) => values.push(value), None => return Err(KbinErrorKind::InvalidState.into()), } } - debug!("values: {:?}", values); - return Ok(Some(Value::Array(node_type, values))); + let value = Value::Array(node_type, values); + debug!("Value::from_standard_type({:?}) input: 0x{:02x?} => {:?}", node_type, input, value); + + return Ok(Some(value)); } match node_type { @@ -54,7 +58,9 @@ macro_rules! tuple { let value = match node_type { StandardType::NodeStart | StandardType::NodeEnd | - StandardType::FileEnd => return Ok(None), + StandardType::FileEnd | + StandardType::Attribute | + StandardType::String => return Ok(None), StandardType::S8 => Value::S8(input[0] as i8), StandardType::U8 => Value::U8(input[0]), StandardType::S16 => Value::S16(BigEndian::read_i16(input)), @@ -63,8 +69,6 @@ macro_rules! tuple { StandardType::U32 => Value::U32(BigEndian::read_u32(input)), StandardType::S64 => Value::S64(BigEndian::read_i64(input)), StandardType::U64 => Value::U64(BigEndian::read_u64(input)), - StandardType::Attribute | - StandardType::String => unimplemented!(), StandardType::Binary => Value::Binary(input.to_vec()), StandardType::Time => Value::Time(BigEndian::read_u32(input)), StandardType::Ip4 => { @@ -123,9 +127,251 @@ macro_rules! tuple { )* )* }; + debug!("Value::from_standard_type({:?}) input: 0x{:02x?} => {:?}", node_type, input, value); Ok(Some(value)) } + + pub fn from_string(node_type: StandardType, input: &str, is_array: bool, arr_count: usize) -> Result { + #[inline] + fn parse(node_type: StandardType, input: &str) -> Result + where T: FromStr, + T::Err: Fail + { + // TODO(mbilker): Add string check for spaces + let n = input.parse::().context(KbinErrorKind::StringParse(node_type.name))?; + Ok(n) + } + + #[inline] + fn parse_tuple(node_type: StandardType, input: &str, output: &mut [T]) -> Result<(), KbinError> + where T: FromStr, + T::Err: Fail + { + + let mut i = 0; + for part in input.split(' ') { + output[i] = part.parse::().context(KbinErrorKind::StringParse(node_type.name))?; + i += 1; + } + + if i != node_type.count { + return Err(KbinErrorKind::SizeMismatch(*node_type, node_type.count, i).into()); + } + + Ok(()) + } + + fn to_array(node_type: StandardType, count: usize, input: &str, arr_count: usize) -> Result { + let mut i = 0; + trace!("to_array(count: {}, input: {:?}, arr_count: {})", count, input, arr_count); + let iter = input.split(|c| { + if c == ' ' { + // Increment the space counter + i += 1; + + // If the space counter is equal to count, then split + i == count + } else { + false + } + }); + + let mut values = Vec::new(); + + for part in iter { + debug!("part: {:?}", part); + values.push(Value::from_string(node_type, part, false, 1)?); + } + + Ok(Value::Array(node_type, values)) + } + + if is_array { + let value = match node_type.count { + //0 => return Err(KbinErrorKind::InvalidState.into()), + 1 => { + // May have a node (i.e. `Ip4`) that is only a single count, but it + // can be part of an array + match arr_count { + 0 => return Err(KbinErrorKind::InvalidState.into()), + 1 => Value::from_string(node_type, input, false, arr_count)?, + _ => to_array(node_type, node_type.count, input, arr_count)?, + } + }, + count if count > 1 => to_array(node_type, count, input, arr_count)?, + _ => return Err(KbinErrorKind::InvalidState.into()), + }; + debug!("Value::from_string({:?}) input: {:?} => {:?}", node_type, input, value); + + return Ok(value); + } + + let value = match node_type { + StandardType::S8 => Value::S8(parse::(node_type, input)?), + StandardType::U8 => Value::U8(parse::(node_type, input)?), + StandardType::S16 => Value::S16(parse::(node_type, input)?), + StandardType::U16 => Value::U16(parse::(node_type, input)?), + StandardType::S32 => Value::S32(parse::(node_type, input)?), + StandardType::U32 => Value::U32(parse::(node_type, input)?), + StandardType::S64 => Value::S64(parse::(node_type, input)?), + StandardType::U64 => Value::U64(parse::(node_type, input)?), + StandardType::Binary => { + let data: Vec = input.from_hex().context(KbinErrorKind::HexError)?; + Value::Binary(data) + }, + StandardType::String => Value::String(input.to_owned()), + StandardType::Attribute => Value::Attribute(input.to_owned()), + StandardType::Ip4 => { + let mut i = 0; + let mut octets = [0; 4]; + + // IP Addresses are split by a period, don't use `parse_tuple` + for part in input.split('.') { + octets[i] = parse::(node_type, part)?; + i += 1; + } + + if i != 4 { + return Err(KbinErrorKind::SizeMismatch(*node_type, 4, i).into()); + } + + Value::Ip4(Ipv4Addr::from(octets)) + }, + StandardType::Time => Value::Time(parse::(node_type, input)?), + StandardType::Float => Value::Float(parse::(node_type, input)?), + StandardType::Double => Value::Double(parse::(node_type, input)?), + StandardType::Boolean => Value::Boolean(match input { + "0" => false, + "1" => true, + v => return Err(KbinErrorKind::InvalidBooleanInput(parse::(node_type, v)?).into()), + }), + StandardType::NodeEnd | + StandardType::FileEnd | + StandardType::NodeStart => return Err(KbinErrorKind::InvalidNodeType(node_type).into()), + $( + StandardType::$s8_konst => { + const COUNT: usize = node_types::$s8_konst.count; + let mut value = [0; COUNT]; + parse_tuple::(node_type, input, &mut value)?; + Value::$s8_konst(value) + }, + )* + $( + StandardType::$u8_konst => { + const COUNT: usize = node_types::$u8_konst.count; + let mut value = [0; COUNT]; + parse_tuple::(node_type, input, &mut value)?; + Value::$u8_konst(value) + }, + )* + $( + StandardType::$bool_konst => { + const COUNT: usize = node_types::$bool_konst.count; + let mut i = 0; + let mut value: [_; COUNT] = Default::default(); + for part in input.split(' ') { + value[i] = match part { + "0" => false, + "1" => true, + v => return Err(KbinErrorKind::InvalidBooleanInput(parse::(node_type, v)?).into()), + }; + i += 1; + } + + if i != COUNT { + return Err(KbinErrorKind::SizeMismatch(*node_type, COUNT, i).into()); + } + + Value::$bool_konst(value) + }, + )* + $( + $( + StandardType::$multi_konst => { + const COUNT: usize = node_types::$multi_konst.count; + let mut value: [_; COUNT] = Default::default(); + parse_tuple::<$inner_type>(node_type, input, &mut value)?; + Value::$multi_konst(value) + }, + )* + )* + }; + debug!("Value::from_string({:?}) input: {:?} => {:?}", node_type, input, value); + + Ok(value) + } + + fn to_bytes_inner(self, output: &mut Vec) -> Result<(), KbinError> { + debug!("Value::to_bytes_inner(self: {:?})", self); + + macro_rules! gen_error { + ($konst:ident) => { + KbinErrorKind::DataWrite(StandardType::$konst.name) + }; + } + + match self { + Value::S8(n) => output.push(n as u8), + Value::U8(n) => output.push(n), + Value::S16(n) => output.write_i16::(n).context(gen_error!(S16))?, + Value::U16(n) => output.write_u16::(n).context(gen_error!(U16))?, + Value::S32(n) => output.write_i32::(n).context(gen_error!(S32))?, + Value::U32(n) => output.write_u32::(n).context(gen_error!(U32))?, + Value::S64(n) => output.write_i64::(n).context(gen_error!(S64))?, + Value::U64(n) => output.write_u64::(n).context(gen_error!(U64))?, + Value::Binary(data) => output.extend_from_slice(&data), + Value::Time(n) => output.write_u32::(n).context(gen_error!(Time))?, + Value::Ip4(addr) => output.extend_from_slice(&addr.octets()), + Value::Float(n) => output.write_f32::(n).context(gen_error!(Float))?, + Value::Double(n) => output.write_f64::(n).context(gen_error!(Double))?, + Value::Boolean(v) => output.push(if v { 0x01 } else { 0x00 }), + Value::Array(_, values) => { + for value in values { + value.to_bytes_inner(output)?; + } + }, + Value::Attribute(_) | + Value::String(_) | + Value::Node(_) => return Err(KbinErrorKind::InvalidNodeType(self.standard_type()).into()), + $( + Value::$s8_konst(value) => { + output.reserve(value.len()); + for n in value.into_iter() { + output.push(*n as u8); + } + }, + )* + $( + Value::$u8_konst(value) => { + output.reserve(value.len()); + for n in value.into_iter() { + output.push(*n); + } + }, + )* + $( + Value::$bool_konst(value) => { + output.reserve(value.len()); + for v in value.into_iter() { + output.push(if *v { 0x01 } else { 0x00 }); + } + }, + )* + $( + $( + Value::$multi_konst(value) => { + output.reserve(value.len() * StandardType::$multi_konst.size); + for v in value.into_iter() { + output.$write_method::(*v).context(gen_error!($multi_konst))?; + } + }, + )* + )* + }; + + Ok(()) + } }; } @@ -164,17 +410,24 @@ macro_rules! construct_types { bool: [Boolean2, Boolean3, Boolean4, Vb] ], multi: [ - read_i16_into => [S16_2, S16_3, S16_4, Vs16], - read_i32_into => [S32_2, S32_3, S32_4], - read_i64_into => [S64_2, S64_3, S64_4], - read_u16_into => [U16_2, U16_3, U16_4, Vu16], - read_u32_into => [U32_2, U32_3, U32_4], - read_u64_into => [U64_2, U64_3, U64_4], - read_f32_into_unchecked => [Float2, Float3, Float4], - read_f64_into_unchecked => [Double2, Double3, Double4] + read_i16_into write_i16 i16 => [S16_2, S16_3, S16_4, Vs16], + read_i32_into write_i32 i32 => [S32_2, S32_3, S32_4], + read_i64_into write_i64 i64 => [S64_2, S64_3, S64_4], + read_u16_into write_u16 u16 => [U16_2, U16_3, U16_4, Vu16], + read_u32_into write_u32 u32 => [U32_2, U32_3, U32_4], + read_u64_into write_u64 u64 => [U64_2, U64_3, U64_4], + read_f32_into_unchecked write_f32 f32 => [Float2, Float3, Float4], + read_f64_into_unchecked write_f64 f64 => [Double2, Double3, Double4] ] } + pub fn to_bytes(self) -> Result, KbinError> { + let mut output = Vec::new(); + self.to_bytes_inner(&mut output)?; + + Ok(output) + } + pub fn standard_type(&self) -> StandardType { match *self { $(