From 8d8df1de0f06d9446f7dfcee2711bde76437359e Mon Sep 17 00:00:00 2001 From: Matt Bilker Date: Sun, 10 Jun 2018 23:45:16 +0000 Subject: [PATCH] lib: begin work on encoding --- Cargo.toml | 1 + src/bin/kbinxml.rs | 3 + src/encoding_type.rs | 23 ++- src/error.rs | 15 ++ src/lib.rs | 142 +++++++++++++--- src/node_types.rs | 394 +++++++++++++++++++++++++++---------------- src/sixbit.rs | 22 ++- 7 files changed, 408 insertions(+), 192 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8591583..64b45ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,4 @@ minidom = "0.9.0" num = "0.1.42" pretty_env_logger = "0.2.3" quick-xml = "0.12.1" +rustc-hex = "1.0.0" diff --git a/src/bin/kbinxml.rs b/src/bin/kbinxml.rs index 99b69af..ee32916 100644 --- a/src/bin/kbinxml.rs +++ b/src/bin/kbinxml.rs @@ -46,6 +46,9 @@ fn main() -> std::io::Result<()> { let stdout = stdout(); stdout.lock().write_all(&buf)?; println!(); + + let buf = KbinXml::to_binary(&element).map_err(display_err)?; + assert_eq!(buf, contents); } Ok(()) } diff --git a/src/encoding_type.rs b/src/encoding_type.rs index 68f8a5c..82d315c 100644 --- a/src/encoding_type.rs +++ b/src/encoding_type.rs @@ -15,18 +15,6 @@ pub enum EncodingType { } impl EncodingType { - #[allow(dead_code)] - pub fn to_byte(&self) -> u8 { - match *self { - EncodingType::None => 0x00, // 0x00 >> 5 = 0 - EncodingType::ASCII => 0x20, // 0x20 >> 5 = 1 - EncodingType::ISO_8859_1 => 0x40, // 0x40 >> 5 = 2 - EncodingType::EUC_JP => 0x60, // 0x60 >> 5 = 3 - EncodingType::SHIFT_JIS => 0x80, // 0x80 >> 5 = 4 - EncodingType::UTF_8 => 0xA0, // 0xA0 >> 5 = 5 - } - } - pub fn from_byte(byte: u8) -> Result { let val = match byte { 0x00 => EncodingType::None, @@ -41,6 +29,17 @@ impl EncodingType { Ok(val) } + pub fn to_byte(&self) -> u8 { + match *self { + EncodingType::None => 0x00, // 0x00 >> 5 = 0 + EncodingType::ASCII => 0x20, // 0x20 >> 5 = 1 + EncodingType::ISO_8859_1 => 0x40, // 0x40 >> 5 = 2 + EncodingType::EUC_JP => 0x60, // 0x60 >> 5 = 3 + EncodingType::SHIFT_JIS => 0x80, // 0x80 >> 5 = 4 + EncodingType::UTF_8 => 0xA0, // 0xA0 >> 5 = 5 + } + } + /// Decode bytes using the encoding definition from the `encoding` crate. /// /// A `Some` value indicates an encoding should be used from the `encoding` diff --git a/src/error.rs b/src/error.rs index 7c1cc91..3bd5a60 100644 --- a/src/error.rs +++ b/src/error.rs @@ -70,11 +70,26 @@ pub enum KbinErrorKind { #[fail(display = "Unable to read sixbit string content")] SixbitRead, + #[fail(display = "Unable to write sixbit string length")] + SixbitLengthWrite, + + #[fail(display = "Unable to write sixbit string content")] + SixbitWrite, + #[fail(display = "Unable to interpret string as UTF-8")] Utf8, #[fail(display = "Unable to interpret string as alternate encoding")] EncodingDecode, + + #[fail(display = "Unable to write {} header field", _0)] + HeaderWrite(&'static str), + + #[fail(display = "Unable to write a {} node", _0)] + DataWrite(&'static str), + + #[fail(display = "Unable to interpret input as {}", _0)] + StringParse(&'static str), } impl fmt::Display for KbinError { diff --git a/src/lib.rs b/src/lib.rs index 687322c..0a52514 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,16 +4,17 @@ extern crate byteorder; extern crate encoding; extern crate minidom; extern crate num; +extern crate rustc_hex; #[macro_use] extern crate failure; #[macro_use] extern crate lazy_static; #[macro_use] extern crate log; use std::cmp::max; -use std::fmt::Write; -use std::io::{Cursor, Read, Seek, SeekFrom}; +use std::fmt::Write as FmtWrite; +use std::io::{Cursor, Read, Seek, SeekFrom, Write}; -use byteorder::{BigEndian, ReadBytesExt}; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use failure::ResultExt; use minidom::Element; @@ -25,8 +26,9 @@ mod sixbit; use compression::Compression; use encoding_type::EncodingType; -use node_types::KbinType; -use sixbit::unpack_sixbit; +use node_types::{KbinType, StandardType}; +use sixbit::{pack_sixbit, unpack_sixbit}; +use rustc_hex::FromHex; pub use error::{KbinError, KbinErrorKind}; @@ -63,7 +65,7 @@ impl KbinXml { data_buf.read_exact(&mut data).context(KbinErrorKind::DataRead)?; trace!("data_buf_read => size: {}, data: 0x{:02x?}", data.len(), data); - self.data_buf_realign(data_buf, None)?; + self.data_buf_realign_reads(data_buf, None)?; Ok(data) } @@ -99,7 +101,7 @@ impl KbinXml { } let old_pos = self.data_buf_offset(data_buf); - let size = data_type.size() * data_type.count(); + let size = data_type.size * data_type.count; trace!("data_buf_get_aligned => old_pos: {}, size: {}", old_pos, size); let (check_old, data) = match size { 1 => { @@ -122,7 +124,7 @@ impl KbinXml { size => { let mut data = vec![0; size as usize]; data_buf.read_exact(&mut data).context(KbinErrorKind::DataReadAligned)?; - self.data_buf_realign(data_buf, None)?; + self.data_buf_realign_reads(data_buf, None)?; (false, data) }, @@ -136,14 +138,14 @@ impl KbinXml { trace!("data_buf_get_aligned => old_pos: {}, trailing: {}", old_pos, trailing); if old_pos < trailing { data_buf.seek(SeekFrom::Start(trailing)).context(KbinErrorKind::Seek)?; - self.data_buf_realign(data_buf, None)?; + self.data_buf_realign_reads(data_buf, None)?; } } Ok(data) } - fn data_buf_realign(&mut self, data_buf: &mut Cursor<&[u8]>, size: Option) -> Result<(), KbinError> { + fn data_buf_realign_reads(&mut self, data_buf: &mut Cursor<&[u8]>, size: Option) -> Result<(), KbinError> { let size = size.unwrap_or(4); trace!("data_buf_realign => position: {}, size: {}", data_buf.position(), size); @@ -204,11 +206,11 @@ impl KbinXml { let is_array = raw_node_type & 64 == 64; let node_type = raw_node_type & !64; - let xml_type = KbinType::from_u8(node_type); + let xml_type = StandardType::from_u8(node_type); debug!("raw_node_type: {}, node_type: {:?} ({}), is_array: {}", raw_node_type, xml_type, node_type, is_array); match xml_type { - KbinType::NodeEnd | KbinType::FileEnd => { + StandardType::NodeEnd | StandardType::FileEnd => { if stack.len() > 1 { let node = stack.pop().expect("Stack must have last node"); if let Some(to) = stack.last_mut() { @@ -216,9 +218,9 @@ impl KbinXml { } } - if xml_type == KbinType::NodeEnd { + if xml_type == StandardType::NodeEnd { continue; - } else if xml_type == KbinType::FileEnd { + } else if xml_type == StandardType::FileEnd { break; } }, @@ -227,15 +229,15 @@ impl KbinXml { let name = unpack_sixbit(&mut node_buf)?; - if xml_type == KbinType::NodeStart { + if xml_type == StandardType::NodeStart { stack.push(Element::bare(name)); } else { - if xml_type != KbinType::Attribute { + if xml_type != StandardType::Attribute { stack.push(Element::bare(name.clone())); } if let Some(to) = stack.last_mut() { match xml_type { - KbinType::Attribute => { + StandardType::Attribute => { let val = self.data_buf_read_str(&mut data_buf, encoding)?; debug!("attr name: {}, val: {}", name, val); to.set_attr(name, val); @@ -244,18 +246,18 @@ impl KbinXml { // // Handle String nodes separately to use the string reading logic // which automatically removes trailing null bytes. - KbinType::String => { - to.set_attr("__type", xml_type.name()); + StandardType::String => { + to.set_attr("__type", xml_type.name); let val = self.data_buf_read_str(&mut data_buf, encoding)?; debug!("name: {}, val: {}", name, val); to.append_text_node(val); }, _ => { - to.set_attr("__type", xml_type.name()); + to.set_attr("__type", xml_type.name); - let type_size = xml_type.size(); - let type_count = xml_type.count(); + let type_size = xml_type.size; + let type_count = xml_type.count; let (is_array, size) = if type_count == -1 { (true, data_buf.read_u32::().context(KbinErrorKind::BinaryLengthRead)?) } else if is_array { @@ -278,15 +280,15 @@ impl KbinXml { let data = if is_array { let data = self.data_buf_get(&mut data_buf, size)?; - self.data_buf_realign(&mut data_buf, None)?; + self.data_buf_realign_reads(&mut data_buf, None)?; data } else { - self.data_buf_get_aligned(&mut data_buf, xml_type)? + self.data_buf_get_aligned(&mut data_buf, *xml_type)? }; debug!("data: 0x{:02x?}", data); - if xml_type == KbinType::Binary { + if xml_type == StandardType::Binary { to.set_attr("__size", data.len()); let len = data.len() * 2; @@ -314,8 +316,98 @@ impl KbinXml { Ok(stack.pop().expect("Stack must have root node")) } + fn write_node(&mut self, node_buf: &mut W, data_buf: &mut W, input: &Element) -> Result<(), KbinError> + where W: Write + { + let text = input.text(); + let node_type = match input.attr("__type") { + Some(name) => StandardType::from_name(name), + None => { + if text.len() == 0 { + StandardType::NodeStart + } else { + StandardType::String + } + }, + }; + + let (array_mask, count) = match input.attr("__count") { + Some(count) => { + let array_mask = 1 << 6; + let count = count.parse::().context(KbinErrorKind::StringParse("array count"))?; + (array_mask, count) + }, + None => { + (0, 0) + }, + }; + + println!("input name: {}", input.name()); + + node_buf.write_u8(node_type.id | array_mask).context(KbinErrorKind::DataWrite(node_type.name))?; + pack_sixbit(node_buf, input.name())?; + + match node_type { + StandardType::NodeStart => {}, + + StandardType::Binary => { + let bin = text.from_hex(); + println!("data: {:?}", bin); + }, + StandardType::String => { + println!("str: {}", text); + }, + + _ => { + }, + } + + for child in input.children() { + self.write_node(node_buf, data_buf, child)?; + } + + // Always has the array bit set + node_buf.write_u8(StandardType::NodeEnd.id | 64).context(KbinErrorKind::DataWrite("node end"))?; + + Ok(()) + } + + fn to_binary_internal(&mut self, input: &Element) -> Result, KbinError> { + let mut header = Cursor::new(Vec::with_capacity(8)); + header.write_u8(SIGNATURE).context(KbinErrorKind::HeaderWrite("signature"))?; + header.write_u8(SIG_COMPRESSED).context(KbinErrorKind::HeaderWrite("compression"))?; + + let encoding = EncodingType::SHIFT_JIS.to_byte(); + header.write_u8(encoding).context(KbinErrorKind::HeaderWrite("encoding"))?; + header.write_u8(0xFF ^ encoding).context(KbinErrorKind::HeaderWrite("encoding negation"))?; + + let mut node_buf = Cursor::new(Vec::new()); + let mut data_buf = Cursor::new(Vec::new()); + + self.write_node(&mut node_buf, &mut data_buf, input)?; + + node_buf.write_u8(StandardType::FileEnd.id | 64).context(KbinErrorKind::DataWrite("file end"))?; + + let mut output = header.into_inner(); + + let node_buf = node_buf.into_inner(); + output.write_u32::(node_buf.len() as u32).context(KbinErrorKind::HeaderWrite("node buffer length"))?; + output.extend_from_slice(&node_buf); + + let data_buf = data_buf.into_inner(); + output.write_u32::(data_buf.len() as u32).context(KbinErrorKind::HeaderWrite("data buffer length"))?; + output.extend_from_slice(&data_buf); + + Ok(output) + } + pub fn from_binary(input: &[u8]) -> Result { let mut kbinxml = KbinXml::new(); kbinxml.from_binary_internal(input) } + + pub fn to_binary(input: &Element) -> Result, KbinError> { + let mut kbinxml = KbinXml::new(); + kbinxml.to_binary_internal(input) + } } diff --git a/src/node_types.rs b/src/node_types.rs index bfeab3c..642165c 100644 --- a/src/node_types.rs +++ b/src/node_types.rs @@ -1,11 +1,14 @@ use error::{KbinError, KbinErrorKind}; use std::fmt::Write; +use std::ops::Deref; +use byteorder::WriteBytesExt; use failure::ResultExt; 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 { @@ -13,7 +16,7 @@ macro_rules! number_impl { $( impl KbinWrapperType<$inner_type> for $inner_type { fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType<{}> => input: {:02x?}", stringify!($inner_type), input); + 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); @@ -22,6 +25,16 @@ macro_rules! number_impl { Ok(()) } + + fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { + trace!("KbinWrapperType<{}> to bytes => input: {}", stringify!($inner_type), input); + + let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?; + let data = $inner_type::to_bytes($inner_type::to_be(num)); + output.extend_from_slice(&data); + + Ok(()) + } } )* }; @@ -29,7 +42,7 @@ macro_rules! number_impl { $( impl KbinWrapperType<$inner_type> for $inner_type { fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType<{}> => input: {:02x?}", stringify!($inner_type), input); + 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); @@ -40,6 +53,16 @@ macro_rules! number_impl { Ok(()) } + + fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { + trace!("KbinWrapperType<{}> to bytes => input: {}", stringify!($inner_type), input); + + let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?; + let data = $intermediate::to_bytes($intermediate::to_be(num.to_bits())); + output.extend_from_slice(&data); + + Ok(()) + } } )* }; @@ -50,7 +73,7 @@ number_impl!(float; u32 => f32, u64 => f64); impl KbinWrapperType for bool { fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType => input: {:02x?}", input); + trace!("KbinWrapperType from bytes => input: {:02x?}", input); let value = match input[0] { 0x00 => "0", @@ -61,6 +84,19 @@ impl KbinWrapperType for bool { Ok(()) } + + fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { + trace!("KbinWrapperType to bytes => input: {}", input); + + let value = match input { + "0" => 0x00, + "1" => 0x01, + v => panic!("Unsupported value for boolean: {}", v), + }; + output.write_u8(value).context(KbinErrorKind::DataWrite("bool"))?; + + Ok(()) + } } struct Ip4; @@ -68,8 +104,8 @@ impl KbinWrapperType for Ip4 { fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { trace!("KbinWrapperType => input: {:02x?}", input); - if input.len() < 4 { - panic!("Ip4 type requires 4 bytes of data, 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]) @@ -77,11 +113,23 @@ impl KbinWrapperType for Ip4 { Ok(()) } + + fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { + trace!("KbinWrapperType => self: Ip4 (needs implementation!)"); + + for part in input.split('.') { + let num = part.parse::().context(KbinErrorKind::StringParse("ip4 segment"))?; + output.write_u8(num).context(KbinErrorKind::DataWrite("ip4"))?; + } + + Ok(()) + } } struct DummyConverter; 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(()) } } struct InvalidConverter; @@ -89,118 +137,172 @@ 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); + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct KbinType { + pub id: u8, + pub name: &'static str, + pub alt_name: Option<&'static str>, + pub size: i8, + pub count: i8 +} + +impl KbinType { + fn parse_array(&self, output: &mut String, input: &[u8], arr_count: usize) -> Result<(), KbinError> + where T: KbinWrapperType + { + let size = self.size as usize; + let count = self.count as usize; + + { + 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)?; + } + + Ok(()) + } + + fn parse_bytes_inner(&self, input: &[u8]) -> Result + where T: KbinWrapperType + { + let type_size = (self.size as usize) * (self.count as usize); + 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(); + + if self.count == -1 { + panic!("Tried to parse special type: {}", self.name); + } else if self.count == 0 { + // Do nothing + } else if self.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, arr_count)?; + } + } else if self.count > 1 { + self.parse_array::(&mut result, input, arr_count)?; + } else { + unimplemented!(); + } + + Ok(result) + } + + fn to_array(&self, output: &mut Vec, input: &str, arr_count: usize) -> Result<(), KbinError> + where T: KbinWrapperType + { + Ok(()) + } + + #[allow(dead_code)] + fn to_bytes_inner(&self, data_buf: &mut Vec, 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); + + if self.count == -1 { + panic!("Tried to write special type: {}", self.name); + } else if self.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::to_kbin_bytes(data_buf, input)?; + } else { + self.to_array::(data_buf, input, arr_count)?; + } + } else if self.count > 1 { + self.to_array::(data_buf, input, arr_count)?; + } + + Ok(()) + } } macro_rules! construct_types { ( $( - ($id:expr, $konst:ident, $name:expr, $alt_name:expr, $size:expr, $count:expr, $inner_type:ident); + ($id:expr, $upcase:ident, $konst:ident, $name:expr, $alt_name:expr, $size:expr, $count:expr, $inner_type:ident); )+ ) => { #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] - pub enum KbinType { + pub enum StandardType { $( $konst, )+ } - impl KbinType { - pub fn from_u8(input: u8) -> KbinType { + $( + pub const $upcase: KbinType = KbinType { + id: $id, + name: $name, + alt_name: $alt_name, + size: $size, + count: $count, + }; + )+ + + impl StandardType { + pub fn from_u8(input: u8) -> StandardType { match input { $( - $id => KbinType::$konst, + $id => StandardType::$konst, )+ _ => panic!("Node type {} not implemented", input), } } - pub fn name(&self) -> &'static str { - match *self { + pub fn from_name(input: &str) -> StandardType { + match input { $( - KbinType::$konst => $name, + $name => StandardType::$konst, )+ + _ => panic!("Node name {} not implemented", input), } } - #[allow(dead_code)] - pub fn alt_name(&self) -> Option<&'static str> { - match *self { - $( - KbinType::$konst => $alt_name, - )+ - } - } - - pub fn size(&self) -> i8 { - match *self { - $( - KbinType::$konst => $size, - )+ - } - } - - pub fn count(&self) -> i8 { - match *self { - $( - KbinType::$konst => $count, - )+ - } - } - - fn parse_array(output: &mut String, input: &[u8], size: usize, count: usize, arr_count: usize) -> Result<(), KbinError> - 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)?; - } - - Ok(()) - } - - fn parse_bytes_inner(&self, input: &[u8], name: &str, size: u8, count: i8) -> Result - where T: KbinWrapperType - { - let type_size = (size as usize) * (count as usize); - let arr_count = input.len() / type_size; - debug!("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!(); - } - - Ok(result) - } - pub fn parse_bytes(&self, input: &[u8]) -> Result { match *self { $( - KbinType::$konst => self.parse_bytes_inner::<$inner_type>(input, $name, $size, $count), + StandardType::$konst => self.parse_bytes_inner::<$inner_type>(input), + )+ + } + } + + #[allow(dead_code)] + pub fn to_bytes(&self, output: &mut Vec, input: &str, arr_count: usize) -> Result<(), KbinError> { + match *self { + $( + StandardType::$konst => self.to_bytes_inner::<$inner_type>(output, input, arr_count), + )+ + } + } + } + + impl Deref for StandardType { + type Target = KbinType; + + fn deref(&self) -> &KbinType { + match *self { + $( + StandardType::$konst => &$upcase, )+ } } @@ -209,65 +311,65 @@ macro_rules! construct_types { } construct_types! { - ( 2, S8, "s8", None, 1, 1, i8); - ( 3, U8, "u8", None, 1, 1, u8); - ( 4, S16, "s16", None, 2, 1, i16); - ( 5, U16, "u16", None, 2, 1, u16); - ( 6, S32, "s32", None, 4, 1, i32); - ( 7, U32, "u32", None, 4, 1, u32); - ( 8, S64, "s64", None, 8, 1, i64); - ( 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, 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); - (16, S8_2, "2s8", None, 1, 2, i8); - (17, U8_2, "2u8", None, 1, 2, u8); - (18, S16_2, "2s16", None, 2, 2, i16); - (19, U16_2, "2u16", None, 2, 2, u16); - (20, S32_2, "2s32", None, 4, 2, i32); - (21, U32_2, "2u32", None, 4, 2, u32); - (22, S64_2, "2s64", Some("vs64"), 8, 2, i64); - (23, U64_2, "2u64", Some("vu64"), 8, 2, u64); - (24, Float2, "2f", None, 4, 2, f32); - (25, Double2, "2d", Some("vd"), 8, 2, f64); - (26, S8_3, "3s8", None, 1, 3, i8); - (27, U8_3, "3u8", None, 1, 3, u8); - (28, S16_3, "3s16", None, 2, 3, i16); - (29, U16_3, "3u16", None, 2, 3, u16); - (30, S32_3, "3s32", None, 4, 3, i32); - (31, U32_3, "3u32", None, 4, 3, u32); - (32, S64_3, "3s64", None, 8, 3, i64); - (33, U64_3, "3u64", None, 8, 3, u64); - (34, Float3, "3f", None, 4, 3, f32); - (35, Double3, "3d", None, 8, 3, f64); - (36, S8_4, "4s8", None, 1, 4, i8); - (37, U8_4, "4u8", None, 1, 4, u8); - (38, S16_4, "4s16", None, 2, 4, i16); - (39, U16_4, "4u16", None, 2, 4, u16); - (40, S32_4, "4s32", Some("vs32"), 4, 4, i32); - (41, U32_4, "4u32", Some("vu32"), 4, 4, u32); - (42, S64_4, "4s64", None, 8, 4, i64); - (43, U64_4, "4u64", None, 8, 4, u64); - (44, Float4, "4f", Some("vf"), 4, 4, f32); - (45, Double4, "4d", None, 8, 4, f64); + ( 2, S8, S8, "s8", None, 1, 1, i8); + ( 3, U8, U8, "u8", None, 1, 1, u8); + ( 4, S16, S16, "s16", None, 2, 1, i16); + ( 5, U16, U16, "u16", None, 2, 1, u16); + ( 6, S32, S32, "s32", None, 4, 1, i32); + ( 7, U32, U32, "u32", None, 4, 1, u32); + ( 8, S64, S64, "s64", None, 8, 1, i64); + ( 9, U64, U64, "u64", None, 8, 1, u64); + (10, BINARY, Binary, "bin", Some("binary"), 1, -1, DummyConverter); + (11, STRING, String, "str", Some("string"), 1, -1, DummyConverter); + (12, IP4, Ip4, "ip4", None, 4, 1, Ip4); // Using size of 4 rather than count of 4 + (13, TIME, Time, "time", None, 4, 1, u32); + (14, FLOAT, Float, "float", Some("f"), 4, 1, f32); + (15, DOUBLE, Double, "double", Some("d"), 8, 1, f64); + (16, S8_2, S8_2, "2s8", None, 1, 2, i8); + (17, U8_2, U8_2, "2u8", None, 1, 2, u8); + (18, S16_2, S16_2, "2s16", None, 2, 2, i16); + (19, U16_2, U16_2, "2u16", None, 2, 2, u16); + (20, S32_2, S32_2, "2s32", None, 4, 2, i32); + (21, U32_2, U32_2, "2u32", None, 4, 2, u32); + (22, S64_2, S64_2, "2s64", Some("vs64"), 8, 2, i64); + (23, U64_2, U64_2, "2u64", Some("vu64"), 8, 2, u64); + (24, FLOAT_2, Float2, "2f", None, 4, 2, f32); + (25, DOUBLE_2, Double2, "2d", Some("vd"), 8, 2, f64); + (26, S8_3, S8_3, "3s8", None, 1, 3, i8); + (27, U8_3, U8_3, "3u8", None, 1, 3, u8); + (28, S16_3, S16_3, "3s16", None, 2, 3, i16); + (29, U16_3, U16_3, "3u16", None, 2, 3, u16); + (30, S32_3, S32_3, "3s32", None, 4, 3, i32); + (31, U32_3, U32_3, "3u32", None, 4, 3, u32); + (32, S64_3, S64_3, "3s64", None, 8, 3, i64); + (33, U64_3, U64_3, "3u64", None, 8, 3, u64); + (34, FLOAT_3, Float3, "3f", None, 4, 3, f32); + (35, DOUBLE_3, Double3, "3d", None, 8, 3, f64); + (36, S8_4, S8_4, "4s8", None, 1, 4, i8); + (37, U8_4, U8_4, "4u8", None, 1, 4, u8); + (38, S16_4, S16_4, "4s16", None, 2, 4, i16); + (39, U16_4, U16_4, "4u16", None, 2, 4, u16); + (40, S32_4, S32_4, "4s32", Some("vs32"), 4, 4, i32); + (41, U32_4, U32_4, "4u32", Some("vu32"), 4, 4, u32); + (42, S64_4, S64_4, "4s64", None, 8, 4, i64); + (43, U64_4, U64_4, "4u64", None, 8, 4, u64); + (44, FLOAT_4, Float4, "4f", Some("vf"), 4, 4, f32); + (45, DOUBLE_4, Double4, "4d", None, 8, 4, f64); // 46 = Attribute // no 47 - (48, Vs8, "vs8", None, 1, 16, i8); - (49, Vu8, "vu8", None, 1, 16, u8); - (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); - (55, Boolean4, "4b", None, 1, 4, bool); - (56, Vb, "vb", None, 1, 16, bool); + (48, VS8, Vs8, "vs8", None, 1, 16, i8); + (49, VU8, Vu8, "vu8", None, 1, 16, u8); + (50, VS16, Vs16, "vs16", None, 2, 8, i16); + (51, VU16, Vu16, "vu16", None, 2, 8, u16); + (52, BOOL, Boolean, "bool", Some("b"), 1, 1, bool); + (53, BOOL_2, Boolean2, "2b", None, 1, 2, bool); + (54, BOOL_3, Boolean3, "3b", None, 1, 3, bool); + (55, BOOL_4, Boolean4, "4b", None, 1, 4, bool); + (56, VB, Vb, "vb", None, 1, 16, bool); - ( 1, NodeStart, "void", None, 0, 0, InvalidConverter); - (46, Attribute, "attr", None, 0, 0, InvalidConverter); + ( 1, NODE_START, NodeStart, "void", None, 0, 0, InvalidConverter); + (46, ATTRIBUTE, Attribute, "attr", None, 0, 0, InvalidConverter); - (190, NodeEnd, "nodeEnd", None, 0, 0, InvalidConverter); - (191, FileEnd, "fileEnd", None, 0, 0, InvalidConverter); + (190, NODE_END, NodeEnd, "nodeEnd", None, 0, 0, InvalidConverter); + (191, FILE_END, FileEnd, "fileEnd", None, 0, 0, InvalidConverter); } diff --git a/src/sixbit.rs b/src/sixbit.rs index 288182e..13122d7 100644 --- a/src/sixbit.rs +++ b/src/sixbit.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::io::{Read, Write}; -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use byteorder::{ReadBytesExt, WriteBytesExt}; use failure::ResultExt; use num::{BigUint, FromPrimitive, ToPrimitive}; @@ -21,8 +21,7 @@ lazy_static! { }; } -#[allow(dead_code)] -pub fn pack_sixbit(writer: &mut T, input: &str) +pub fn pack_sixbit(writer: &mut T, input: &str) -> Result<(), KbinError> where T: Write { let sixbit_chars = input @@ -30,19 +29,24 @@ pub fn pack_sixbit(writer: &mut T, input: &str) .map(|ch| { *BYTE_MAP.get(&ch).expect("Character must be a valid sixbit character") }); - let padding = 8 - input.len() * 6 % 8; + let len = input.len() as usize; + let padding = 8 - len * 6 % 8; let padding = if padding == 8 { 0 } else { padding }; + let real_len = (len * 6 + padding) / 8; + debug!("sixbit_len: {}, real_len: {}, padding: {}", len, real_len, padding); - let mut bits = 0; + let mut bits = BigUint::new(vec![0; real_len]); for ch in sixbit_chars { bits <<= 6; - bits |= ch as u64; + bits |= BigUint::from_u8(ch).unwrap(); } bits <<= padding; - let len = input.len() as u8; - writer.write_u8(len).expect("Unable to write sixbit string length"); - writer.write_uint::(bits, (input.len() * 6 + padding) / 8).expect("Unable to write sixbit contents"); + let bytes = bits.to_bytes_be(); + writer.write_u8(len as u8).context(KbinErrorKind::SixbitLengthWrite)?; + writer.write(&bytes).context(KbinErrorKind::SixbitWrite)?; + + Ok(()) } pub fn unpack_sixbit(reader: &mut T) -> Result