From 00f5283429c047c3f6899870be4a57dbd4b48e2a Mon Sep 17 00:00:00 2001 From: Matt Bilker Date: Fri, 1 Jun 2018 05:46:28 +0000 Subject: [PATCH] Proper array decoding --- src/lib.rs | 3 +- src/node_types.rs | 108 +++++++++++++++++++++++++++++++++------------- 2 files changed, 80 insertions(+), 31 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 813aa28..b014c66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -190,8 +190,7 @@ impl KbinXml { let len_data = data_buf.read_u32::().expect("Unable to read len_data"); println!("len_data: {} (0x{:x})", len_data, len_data); - let root = Element::bare("root"); - let mut stack = vec![root]; + let mut stack: Vec = Vec::new(); { let node_buf_end = data_buf_start.into(); while node_buf.position() < node_buf_end { diff --git a/src/node_types.rs b/src/node_types.rs index 9b12010..d97d838 100644 --- a/src/node_types.rs +++ b/src/node_types.rs @@ -1,18 +1,20 @@ +use std::fmt::Write; + trait KbinWrapperType { - fn from_kbin_bytes(input: &[u8]) -> String; + fn from_kbin_bytes(output: &mut String, input: &[u8]); } macro_rules! number_impl { (integer; $($inner_type:ident),*) => { $( impl KbinWrapperType<$inner_type> for $inner_type { - fn from_kbin_bytes(input: &[u8]) -> String { + fn from_kbin_bytes(output: &mut String, input: &[u8]) { println!("KbinWrapperType<{}> => input: {:02x?}", stringify!($inner_type), input); - //String::from(concat!("integer ", stringify!($inner_type))) let mut data = [0; ::std::mem::size_of::<$inner_type>()]; data.clone_from_slice(input); - format!("{}", $inner_type::from_be($inner_type::from_bytes(data))) + write!(output, "{}", $inner_type::from_be($inner_type::from_bytes(data))) + .expect(concat!("Failed to write ", stringify!($inner_type), " to output string")); } } )* @@ -20,15 +22,15 @@ macro_rules! number_impl { (float; $($intermediate:ident => $inner_type:ident),*) => { $( impl KbinWrapperType<$inner_type> for $inner_type { - fn from_kbin_bytes(input: &[u8]) -> String { + fn from_kbin_bytes(output: &mut String, input: &[u8]) { println!("KbinWrapperType<{}> => input: {:02x?}", stringify!($inner_type), input); - //String::from(concat!("float ", stringify!($inner_type))) let mut data = [0; ::std::mem::size_of::<$inner_type>()]; data.clone_from_slice(input); let bits = $intermediate::from_be($intermediate::from_bytes(data)); - format!("{:.6}", $inner_type::from_bits(bits)) + write!(output, "{:.6}", $inner_type::from_bits(bits)) + .expect(concat!("Failed to write ", stringify!($inner_type), " to output string")); } } )* @@ -39,7 +41,7 @@ number_impl!(integer; i8, u8, i16, u16, i32, u32, i64, u64); number_impl!(float; u32 => f32, u64 => f64); impl KbinWrapperType for bool { - fn from_kbin_bytes(input: &[u8]) -> String { + fn from_kbin_bytes(output: &mut String, input: &[u8]) { println!("KbinWrapperType => input: {:02x?}", input); //String::from("bool") @@ -48,20 +50,32 @@ impl KbinWrapperType for bool { 0x01 => "1", v => panic!("Unsupported value for boolean: {}", v), }; - String::from(value) + output.push_str(value); + } +} + +struct Ip4; +impl KbinWrapperType for Ip4 { + fn from_kbin_bytes(output: &mut String, input: &[u8]) { + println!("KbinWrapperType => input: {:02x?}", input); + + if input.len() < 4 { + panic!("Ip4 type requires 4 bytes of data, input: {:02x?}", input); + } + + write!(output, "{}.{}.{}.{}", input[0], input[1], input[2], input[3]) + .expect("Failed to write IP address to output string"); } } struct DummyConverter; impl KbinWrapperType for DummyConverter { - fn from_kbin_bytes(_input: &[u8]) -> String { - String::from("") - } + fn from_kbin_bytes(_output: &mut String, _input: &[u8]) {} } struct InvalidConverter; impl KbinWrapperType for InvalidConverter { - fn from_kbin_bytes(input: &[u8]) -> String { + fn from_kbin_bytes(_output: &mut String, input: &[u8]) { panic!("Invalid kbin type converter called for input: {:02x?}", input); } } @@ -122,22 +136,58 @@ macro_rules! construct_types { } } + fn parse_array(output: &mut String, input: &[u8], size: usize, count: usize, arr_count: usize) + where T: KbinWrapperType + { + { + let first = &input[..size]; + T::from_kbin_bytes(output, first); + } + + let total_nodes = count * arr_count; + for i in 1..total_nodes { + let offset = i * size; + let end = (i + 1) * size; + let data = &input[offset..end]; + output.push(' '); + T::from_kbin_bytes(output, data); + } + } + + fn parse_bytes_inner(&self, input: &[u8], name: &str, size: u8, count: i8) -> String + where T: KbinWrapperType + { + let type_size = (size as usize) * (count as usize); + let arr_count = input.len() / type_size; + println!("parse_bytes({}) => size: {}, count: {}, input_len: {}, arr_count: {}", name, size, count, input.len(), arr_count); + + let mut result = String::new(); + + if count == -1 { + panic!("Tried to parse special type: {}", self.name()); + } else if count == 0 { + // Do nothing + } else if count == 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, size as usize, count as usize, arr_count); + } + } else if count > 1 { + Self::parse_array::(&mut result, input, size as usize, count as usize, arr_count); + } else { + unimplemented!(); + } + + result + } + pub fn parse_bytes(&self, input: &[u8]) -> String { match *self { $( - KbinType::$konst => { - if $count == -1 { - panic!("Tried to parse special type: {}", self.name()); - } else if $count == 0 { - String::new() - } else if $count == 1 { - $inner_type::from_kbin_bytes(input) - } else if $count > 1 { - String::new() - } else { - unimplemented!(); - } - }, + KbinType::$konst => self.parse_bytes_inner::<$inner_type>(input, $name, $size, $count), )+ } } @@ -156,7 +206,7 @@ construct_types! { ( 9, U64, "u64", None, 8, 1, u64); (10, Binary, "bin", Some("binary"), 1, -1, DummyConverter); (11, String, "str", Some("string"), 1, -1, DummyConverter); - (12, Ip4, "ip4", None, 1, 4, DummyConverter); // TODO: implement IP address parsing + (12, Ip4, "ip4", None, 4, 1, Ip4); // Using size of 4 rather than count of 4 (13, Time, "time", None, 4, 1, u32); (14, Float, "float", Some("f"), 4, 1, f32); (15, Double, "double", Some("d"), 8, 1, f64); @@ -194,8 +244,8 @@ construct_types! { // no 47 (48, Vs8, "vs8", None, 1, 16, i8); (49, Vu8, "vu8", None, 1, 16, u8); - (50, Vs16, "vs16", None, 1, 8, i16); - (51, Vu16, "vu16", None, 1, 8, u16); + (50, Vs16, "vs16", None, 2, 8, i16); + (51, Vu16, "vu16", None, 2, 8, u16); (52, Boolean, "bool", Some("b"), 1, 1, bool); (53, Boolean2, "2b", None, 1, 2, bool); (54, Boolean3, "3b", None, 1, 3, bool);