From f273d5b13e0df07f8a0789d0a51c548f689f8689 Mon Sep 17 00:00:00 2001 From: Matt Bilker Date: Fri, 8 Nov 2019 20:04:49 +0000 Subject: [PATCH] cargo: rustfmt --- rustfmt.toml | 4 + src/bin/kbinxml.rs | 189 ++++---- src/byte_buffer.rs | 662 ++++++++++++++++------------- src/compression.rs | 34 +- src/encoding_type.rs | 346 ++++++++------- src/error.rs | 258 ++++++----- src/lib.rs | 67 +-- src/node/collection.rs | 310 +++++++------- src/node/definition.rs | 367 ++++++++-------- src/node/mod.rs | 593 +++++++++++++------------- src/node_types.rs | 18 +- src/options.rs | 69 ++- src/printer.rs | 92 ++-- src/reader.rs | 360 ++++++++-------- src/sixbit.rs | 249 +++++------ src/text_reader.rs | 410 +++++++++--------- src/to_text_xml/mod.rs | 43 +- src/to_text_xml/node.rs | 176 ++++---- src/to_text_xml/node_collection.rs | 183 ++++---- src/types/bytes.rs | 70 +-- src/types/string.rs | 94 ++-- src/value/array.rs | 282 ++++++------ src/value/mod.rs | 386 ++++++++++------- src/writer.rs | 452 ++++++++++++-------- 24 files changed, 2993 insertions(+), 2721 deletions(-) create mode 100644 rustfmt.toml diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..d9d8e77 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,4 @@ +binop_separator = "Back" +edition = "2018" +match_block_trailing_comma = true +overflow_delimited_expr = true diff --git a/src/bin/kbinxml.rs b/src/bin/kbinxml.rs index fdce6fb..370ee82 100644 --- a/src/bin/kbinxml.rs +++ b/src/bin/kbinxml.rs @@ -8,111 +8,124 @@ use encoding_rs::Encoding; use kbinxml::{EncodingType, Options, Printer}; fn display_buf(buf: &[u8]) -> Result<(), IoError> { - io::stdout().write_all(&buf)?; - println!(); + io::stdout().write_all(&buf)?; + println!(); - Ok(()) + Ok(()) } fn compare_slice(left: &[u8], right: &[u8]) { - let node_buf_length = BigEndian::read_u32(&left[4..8]); - let data_buf_start = 8 + node_buf_length as usize; + let node_buf_length = BigEndian::read_u32(&left[4..8]); + let data_buf_start = 8 + node_buf_length as usize; - let mut i = 0; - let mut mismatches = Vec::new(); - while i < left.len() && i < right.len() { - if left[i] != right[i] { - mismatches.push((i, left[i], right[i])); - } - i += 1; - } - - if let Some(ref first) = mismatches.first() { - eprintln!("Left does not equal right at the following indexes:"); - for (i, left, right) in &mismatches { - let (section, offset) = if *i < data_buf_start { - ("node buffer", (*i as isize) - 8) - } else { - ("data buffer", (*i as isize) - 4 - (data_buf_start as isize)) - }; - eprintln!("index {0} ({3}, offset: {4}), left: {1:3} (0x{1:x}),\tright: {2:3} (0x{2:x})", i, left, right, section, offset); + let mut i = 0; + let mut mismatches = Vec::new(); + while i < left.len() && i < right.len() { + if left[i] != right[i] { + mismatches.push((i, left[i], right[i])); + } + i += 1; } - let (i, _, _) = first; - eprintln!(r#" left: `0x{:02x?}` - right: `0x{:02x?}`"#, &left[*i..], &right[*i..]); - } + if let Some(ref first) = mismatches.first() { + eprintln!("Left does not equal right at the following indexes:"); + for (i, left, right) in &mismatches { + let (section, offset) = if *i < data_buf_start { + ("node buffer", (*i as isize) - 8) + } else { + ("data buffer", (*i as isize) - 4 - (data_buf_start as isize)) + }; + eprintln!( + "index {0} ({3}, offset: {4}), left: {1:3} (0x{1:x}),\tright: {2:3} (0x{2:x})", + i, left, right, section, offset + ); + } + + let (i, _, _) = first; + eprintln!( + r#" left: `0x{:02x?}` + right: `0x{:02x?}`"#, + &left[*i..], + &right[*i..] + ); + } } fn main() -> Result<(), anyhow::Error> { - pretty_env_logger::init(); + pretty_env_logger::init(); - let matches = App::new("kbinxml") - .about(env!("CARGO_PKG_DESCRIPTION")) - .version(env!("CARGO_PKG_VERSION")) - .author("Matt Bilker ") - .arg(Arg::with_name("printer") - .help("Turn on the NodeCollection and NodeDefinition debug printer") - .short("p") - .long("printer")) - .arg(Arg::with_name("encoding") - .help("Set the encoding used when encoding kbin data") - .short("e") - .long("encoding") - .takes_value(true)) - .arg(Arg::with_name("input") - .help("The file to convert") - .index(1) - .required(true)) - .get_matches(); + let matches = App::new("kbinxml") + .about(env!("CARGO_PKG_DESCRIPTION")) + .version(env!("CARGO_PKG_VERSION")) + .author("Matt Bilker ") + .arg( + Arg::with_name("printer") + .help("Turn on the NodeCollection and NodeDefinition debug printer") + .short("p") + .long("printer"), + ) + .arg( + Arg::with_name("encoding") + .help("Set the encoding used when encoding kbin data") + .short("e") + .long("encoding") + .takes_value(true), + ) + .arg( + Arg::with_name("input") + .help("The file to convert") + .index(1) + .required(true), + ) + .get_matches(); - let printer_enabled = matches.is_present("printer"); - let file_name = matches.value_of("input").unwrap(); - let output_encoding = if let Some(label) = matches.value_of("encoding") { - let encoding = Encoding::for_label(label.as_bytes()) - .with_context(|| "No encoding found for label")?; + let printer_enabled = matches.is_present("printer"); + let file_name = matches.value_of("input").unwrap(); + let output_encoding = if let Some(label) = matches.value_of("encoding") { + let encoding = + Encoding::for_label(label.as_bytes()).context("No encoding found for label")?; - Some(EncodingType::from_encoding(encoding)?) - } else { - None - }; + Some(EncodingType::from_encoding(encoding)?) + } else { + None + }; - eprintln!("file_name: {}", file_name); + eprintln!("file_name: {}", file_name); - // Read '-' as standard input. - let contents = if file_name == "-" { - let mut contents = Vec::new(); - io::stdin().read_to_end(&mut contents)?; + // Read '-' as standard input. + let contents = if file_name == "-" { + let mut contents = Vec::new(); + io::stdin().read_to_end(&mut contents)?; - contents - } else { - fs::read(file_name)? - }; + contents + } else { + fs::read(file_name)? + }; - if kbinxml::is_binary_xml(&contents) { - if printer_enabled { - Printer::run(&contents).unwrap(); + if kbinxml::is_binary_xml(&contents) { + if printer_enabled { + Printer::run(&contents).unwrap(); + } + + let (collection, _encoding) = kbinxml::from_slice(&contents)?; + let text_original = kbinxml::to_text_xml(&collection)?; + display_buf(&text_original)?; + + let (collection, encoding_original) = kbinxml::from_slice(&contents)?; + let options = Options::with_encoding(output_encoding.unwrap_or(encoding_original)); + let buf = kbinxml::to_binary_with_options(options, &collection)?; + compare_slice(&buf, &contents); + } else { + let (collection, encoding) = kbinxml::from_text_xml(&contents)?; + let options = Options::with_encoding(output_encoding.unwrap_or(encoding)); + let buf = kbinxml::to_binary_with_options(options, &collection)?; + + if printer_enabled { + Printer::run(&buf)?; + } + + io::stdout().write_all(&buf)?; } - let (collection, _encoding) = kbinxml::from_slice(&contents)?; - let text_original = kbinxml::to_text_xml(&collection)?; - display_buf(&text_original)?; - - let (collection, encoding_original) = kbinxml::from_slice(&contents)?; - let options = Options::with_encoding(output_encoding.unwrap_or(encoding_original)); - let buf = kbinxml::to_binary_with_options(options, &collection)?; - compare_slice(&buf, &contents); - } else { - let (collection, encoding) = kbinxml::from_text_xml(&contents)?; - let options = Options::with_encoding(output_encoding.unwrap_or(encoding)); - let buf = kbinxml::to_binary_with_options(options, &collection)?; - - if printer_enabled { - Printer::run(&buf)?; - } - - io::stdout().write_all(&buf)?; - } - - Ok(()) + Ok(()) } diff --git a/src/byte_buffer.rs b/src/byte_buffer.rs index 85f477c..00f13c2 100644 --- a/src/byte_buffer.rs +++ b/src/byte_buffer.rs @@ -12,371 +12,439 @@ use crate::node_types::KbinType; #[derive(Debug, Snafu)] pub enum ByteBufferError { - #[snafu(display("Out-of-bounds read attempted at offset: {} with size: {}", offset, size))] - OutOfBounds { - offset: usize, - size: usize, - }, + #[snafu(display( + "Out-of-bounds read attempted at offset: {} with size: {}", + offset, + size + ))] + OutOfBounds { offset: usize, size: usize }, - #[snafu(display("Failed to read {} byte(s) from data buffer", size))] - DataRead { - size: usize, - source: io::Error, - }, + #[snafu(display("Failed to read {} byte(s) from data buffer", size))] + DataRead { size: usize, source: io::Error }, - #[snafu(display("Failed to read aligned {} byte(s) from data buffer", size))] - ReadAligned { - size: usize, - source: Box, - }, + #[snafu(display("Failed to read aligned {} byte(s) from data buffer", size))] + ReadAligned { + size: usize, + source: Box, + }, - #[snafu(display("Failed to read data size from data buffer"))] - ReadSize { - source: io::Error, - }, + #[snafu(display("Failed to read data size from data buffer"))] + ReadSize { source: io::Error }, - #[snafu(display("Failed to seek forward {} byte(s) in data buffer after size read", size))] - ReadSizeSeek { - size: usize, - source: io::Error, - }, + #[snafu(display( + "Failed to seek forward {} byte(s) in data buffer after size read", + size + ))] + ReadSizeSeek { size: usize, source: io::Error }, - #[snafu(display("Failed to write length to data buffer (len: {})", len))] - WriteLength { - len: usize, - source: io::Error, - }, + #[snafu(display("Failed to write length to data buffer (len: {})", len))] + WriteLength { len: usize, source: io::Error }, - #[snafu(display("Failed to write data byte {} to data buffer", offset))] - WriteDataByte { - offset: usize, - source: io::Error, - }, + #[snafu(display("Failed to write data byte {} to data buffer", offset))] + WriteDataByte { offset: usize, source: io::Error }, - #[snafu(display("Failed to write data block to data buffer"))] - WriteDataBlock { - source: io::Error, - }, + #[snafu(display("Failed to write data block to data buffer"))] + WriteDataBlock { source: io::Error }, - #[snafu(display("Failed to write padding {} byte(s) to data buffer", size))] - WritePadding { - size: usize, - source: io::Error, - }, + #[snafu(display("Failed to write padding {} byte(s) to data buffer", size))] + WritePadding { size: usize, source: io::Error }, - #[snafu(display("Failed to seek to {} in data buffer", offset))] - SeekOffset { - offset: usize, - source: io::Error, - }, + #[snafu(display("Failed to seek to {} in data buffer", offset))] + SeekOffset { offset: usize, source: io::Error }, - #[snafu(display("Failed to seek forward {} byte(s) in data buffer", size))] - SeekForward { - size: usize, - source: io::Error, - }, + #[snafu(display("Failed to seek forward {} byte(s) in data buffer", size))] + SeekForward { size: usize, source: io::Error }, } /// Remove trailing null bytes, used for the `String` type pub(crate) fn strip_trailing_null_bytes<'a>(data: &'a [u8]) -> &'a [u8] { - let len = data.len(); + let len = data.len(); - if len == 0 { - return data; - } + if len == 0 { + return data; + } - let mut index = len - 1; - while index > 0 && index < len && data[index] == 0x00 { - index -= 1; - } + let mut index = len - 1; + while index > 0 && index < len && data[index] == 0x00 { + index -= 1; + } - // Handle case where the buffer is only a null byte - if index == 0 && data.len() == 1 && data[index] == 0x00 { - &[] - } else { - &data[..=index] - } + // Handle case where the buffer is only a null byte + if index == 0 && data.len() == 1 && data[index] == 0x00 { + &[] + } else { + &data[..=index] + } } pub struct ByteBufferRead { - cursor: Cursor, - buffer: Bytes, - offset_1: usize, - offset_2: usize, + cursor: Cursor, + buffer: Bytes, + offset_1: usize, + offset_2: usize, } pub struct ByteBufferWrite { - buffer: Cursor>, - offset_1: u64, - offset_2: u64, + buffer: Cursor>, + offset_1: u64, + offset_2: u64, } impl ByteBufferRead { - pub fn new(buffer: Bytes) -> Self { - Self { - cursor: Cursor::new(buffer.clone()), - buffer, - offset_1: 0, - offset_2: 0, - } - } - - #[inline] - fn data_buf_offset(&self) -> usize { - // Position is not the index of the previously read byte, it is the current - // index (offset). - // - // This is so much fun to debug. - //data_buf.position() - 1 - self.cursor.position() as usize - } - - fn check_read_size(&self, start: usize, size: usize) -> Result { - let end = start + size; - if end > self.buffer.len() { - Err(ByteBufferError::OutOfBounds { offset: start, size }) - } else { - Ok(end) - } - } - - fn buf_read_size(&mut self, size: usize) -> Result { - // To avoid an allocation of a `Vec` here, the raw input byte array is used - let start = self.data_buf_offset(); - let end = self.check_read_size(start, size)?; - - let data = self.buffer.slice(start, end); - trace!("buf_read_size => index: {}, size: {}, data: 0x{:02x?}", self.cursor.position(), data.len(), &*data); - - self.cursor.seek(SeekFrom::Current(size as i64)).context(ReadSizeSeek { size })?; - - Ok(data) - } - - pub fn buf_read(&mut self) -> Result { - let size = self.cursor.read_u32::().context(ReadSize)?; - debug!("buf_read => index: {}, size: {}", self.cursor.position(), size); - - let data = self.buf_read_size(size as usize)?; - self.realign_reads(None)?; - - Ok(data) - } - - pub fn get(&mut self, size: u32) -> Result { - let data = self.buf_read_size(size as usize)?; - trace!("get => size: {}, data: 0x{:02x?}", size, &*data); - - Ok(data) - } - - pub fn get_aligned(&mut self, data_type: KbinType) -> Result { - if self.offset_1 % 4 == 0 { - self.offset_1 = self.data_buf_offset(); - } - if self.offset_2 % 4 == 0 { - self.offset_2 = self.data_buf_offset(); + pub fn new(buffer: Bytes) -> Self { + Self { + cursor: Cursor::new(buffer.clone()), + buffer, + offset_1: 0, + offset_2: 0, + } } - let old_pos = self.data_buf_offset(); - let size = data_type.size * data_type.count; - trace!("get_aligned => old_pos: {}, size: {}", old_pos, size); + #[inline] + fn data_buf_offset(&self) -> usize { + // Position is not the index of the previously read byte, it is the current + // index (offset). + // + // This is so much fun to debug. + //data_buf.position() - 1 + self.cursor.position() as usize + } - let (check_old, data) = match size { - 1 => { - let end = self.check_read_size(self.offset_1, 1)?; - let data = self.buffer.slice(self.offset_1, end); - self.offset_1 += 1; + fn check_read_size(&self, start: usize, size: usize) -> Result { + let end = start + size; + if end > self.buffer.len() { + Err(ByteBufferError::OutOfBounds { + offset: start, + size, + }) + } else { + Ok(end) + } + } - (true, data) - }, - 2 => { - let end = self.check_read_size(self.offset_2, 2)?; - let data = self.buffer.slice(self.offset_2, end); - self.offset_2 += 2; + fn buf_read_size(&mut self, size: usize) -> Result { + // To avoid an allocation of a `Vec` here, the raw input byte array is used + let start = self.data_buf_offset(); + let end = self.check_read_size(start, size)?; - (true, data) - }, - size => { - let data = self.buf_read_size(size as usize).map_err(Box::new).context(ReadAligned { size })?; + let data = self.buffer.slice(start, end); + trace!( + "buf_read_size => index: {}, size: {}, data: 0x{:02x?}", + self.cursor.position(), + data.len(), + &*data + ); + + self.cursor + .seek(SeekFrom::Current(size as i64)) + .context(ReadSizeSeek { size })?; + + Ok(data) + } + + pub fn buf_read(&mut self) -> Result { + let size = self.cursor.read_u32::().context(ReadSize)?; + debug!( + "buf_read => index: {}, size: {}", + self.cursor.position(), + size + ); + + let data = self.buf_read_size(size as usize)?; self.realign_reads(None)?; - (false, data) - }, - }; - - if check_old { - let trailing = max(self.offset_1, self.offset_2); - trace!("get_aligned => old_pos: {}, trailing: {}", old_pos, trailing); - - if old_pos < trailing { - self.cursor.seek(SeekFrom::Start(trailing as u64)).context(SeekOffset { offset: trailing })?; - self.realign_reads(None)?; - } + Ok(data) } - Ok(data) - } + pub fn get(&mut self, size: u32) -> Result { + let data = self.buf_read_size(size as usize)?; + trace!("get => size: {}, data: 0x{:02x?}", size, &*data); - pub fn realign_reads(&mut self, size: Option) -> Result<(), ByteBufferError> { - let size = size.unwrap_or(4); - trace!("realign_reads => position: {}, size: {}", self.cursor.position(), size); - - while self.cursor.position() % size > 0 { - self.cursor.seek(SeekFrom::Current(1)).context(SeekForward { size: 1usize })?; + Ok(data) } - trace!("realign_reads => realigned to: {}", self.cursor.position()); - Ok(()) - } + pub fn get_aligned(&mut self, data_type: KbinType) -> Result { + if self.offset_1 % 4 == 0 { + self.offset_1 = self.data_buf_offset(); + } + if self.offset_2 % 4 == 0 { + self.offset_2 = self.data_buf_offset(); + } + + let old_pos = self.data_buf_offset(); + let size = data_type.size * data_type.count; + trace!("get_aligned => old_pos: {}, size: {}", old_pos, size); + + let (check_old, data) = match size { + 1 => { + let end = self.check_read_size(self.offset_1, 1)?; + let data = self.buffer.slice(self.offset_1, end); + self.offset_1 += 1; + + (true, data) + }, + 2 => { + let end = self.check_read_size(self.offset_2, 2)?; + let data = self.buffer.slice(self.offset_2, end); + self.offset_2 += 2; + + (true, data) + }, + size => { + let data = self + .buf_read_size(size as usize) + .map_err(Box::new) + .context(ReadAligned { size })?; + self.realign_reads(None)?; + + (false, data) + }, + }; + + if check_old { + let trailing = max(self.offset_1, self.offset_2); + trace!( + "get_aligned => old_pos: {}, trailing: {}", + old_pos, + trailing + ); + + if old_pos < trailing { + self.cursor + .seek(SeekFrom::Start(trailing as u64)) + .context(SeekOffset { offset: trailing })?; + self.realign_reads(None)?; + } + } + + Ok(data) + } + + pub fn realign_reads(&mut self, size: Option) -> Result<(), ByteBufferError> { + let size = size.unwrap_or(4); + trace!( + "realign_reads => position: {}, size: {}", + self.cursor.position(), + size + ); + + while self.cursor.position() % size > 0 { + self.cursor + .seek(SeekFrom::Current(1)) + .context(SeekForward { size: 1usize })?; + } + trace!("realign_reads => realigned to: {}", self.cursor.position()); + + Ok(()) + } } impl ByteBufferWrite { - pub fn new(buffer: Vec) -> Self { - Self { - buffer: Cursor::new(buffer), - offset_1: 0, - offset_2: 0, - } - } - - pub fn into_inner(self) -> Vec { - self.buffer.into_inner() - } - - #[inline] - fn data_buf_offset(&self) -> u64 { - // Position is not the index of the previously read byte, it is the current - // index (offset). - // - // This is so much fun to debug. - //data_buf.position() - 1 - self.buffer.position() - } - - pub fn buf_write(&mut self, data: &[u8]) -> Result<(), ByteBufferError> { - self.buffer.write_u32::(data.len() as u32).context(WriteLength { len: data.len() })?; - debug!("buf_write => index: {}, size: {}", self.buffer.position(), data.len()); - - self.buffer.write_all(data).context(WriteDataBlock)?; - trace!("buf_write => index: {}, size: {}, data: 0x{:02x?}", self.buffer.position(), data.len(), data); - - self.realign_writes(None)?; - - Ok(()) - } - - pub fn write_str(&mut self, encoding: EncodingType, data: &str) -> Result<(), KbinError> { - trace!("write_str => input: {}, data: 0x{:02x?}", data, data.as_bytes()); - - let bytes = encoding.encode_bytes(data)?; - self.buf_write(&bytes)?; - - Ok(()) - } - - pub fn write_aligned(&mut self, data_type: KbinType, data: &[u8]) -> Result<(), KbinError> { - if self.offset_1 % 4 == 0 { - self.offset_1 = self.data_buf_offset(); - } - if self.offset_2 % 4 == 0 { - self.offset_2 = self.data_buf_offset(); - } - - let old_pos = self.data_buf_offset(); - let size = data_type.size * data_type.count; - trace!("write_aligned => old_pos: {}, size: {}, data: 0x{:02x?}", old_pos, size, data); - - if size != data.len() { - return Err(KbinError::SizeMismatch { node_type: data_type.name, expected: size, actual: data.len() }); - } - - let check_old = match size { - 1 => { - // Make room for new DWORD - if self.offset_1 % 4 == 0 { - self.buffer.write_u32::(0).context(WritePadding { size: 4usize })?; + pub fn new(buffer: Vec) -> Self { + Self { + buffer: Cursor::new(buffer), + offset_1: 0, + offset_2: 0, } + } - self.buffer.seek(SeekFrom::Start(self.offset_1)).context(SeekOffset { offset: self.offset_1 as usize })?; - self.buffer.write_u8(data[0]).context(WriteDataByte { offset: 1usize })?; - self.offset_1 += 1; + pub fn into_inner(self) -> Vec { + self.buffer.into_inner() + } - true - }, - 2 => { - // Make room for new DWORD - if self.offset_2 % 4 == 0 { - self.buffer.write_u32::(0).context(WritePadding { size: 4usize })?; - } + #[inline] + fn data_buf_offset(&self) -> u64 { + // Position is not the index of the previously read byte, it is the current + // index (offset). + // + // This is so much fun to debug. + //data_buf.position() - 1 + self.buffer.position() + } - self.buffer.seek(SeekFrom::Start(self.offset_2)).context(SeekOffset { offset: self.offset_2 as usize })?; - self.buffer.write_u8(data[0]).context(WriteDataByte { offset: 1usize })?; - self.buffer.write_u8(data[1]).context(WriteDataByte { offset: 2usize })?; - self.offset_2 += 2; + pub fn buf_write(&mut self, data: &[u8]) -> Result<(), ByteBufferError> { + self.buffer + .write_u32::(data.len() as u32) + .context(WriteLength { len: data.len() })?; + debug!( + "buf_write => index: {}, size: {}", + self.buffer.position(), + data.len() + ); - true - }, - _ => { self.buffer.write_all(data).context(WriteDataBlock)?; + trace!( + "buf_write => index: {}, size: {}, data: 0x{:02x?}", + self.buffer.position(), + data.len(), + data + ); + self.realign_writes(None)?; - false - }, - }; - - if check_old { - self.buffer.seek(SeekFrom::Start(old_pos)).context(SeekOffset { offset: old_pos as usize })?; - - let trailing = max(self.offset_1, self.offset_2); - trace!("write_aligned => old_pos: {}, trailing: {}", old_pos, trailing); - if old_pos < trailing { - self.buffer.seek(SeekFrom::Start(trailing)).context(SeekOffset { offset: trailing as usize })?; - self.realign_writes(None)?; - } + Ok(()) } - Ok(()) - } + pub fn write_str(&mut self, encoding: EncodingType, data: &str) -> Result<(), KbinError> { + trace!( + "write_str => input: {}, data: 0x{:02x?}", + data, + data.as_bytes() + ); - pub fn realign_writes(&mut self, size: Option) -> Result<(), ByteBufferError> { - let size = size.unwrap_or(4); - trace!("realign_writes => position: {}, size: {}", self.buffer.position(), size); + let bytes = encoding.encode_bytes(data)?; + self.buf_write(&bytes)?; - while self.buffer.position() % size > 0 { - self.buffer.write_u8(0).context(WritePadding { size: 1usize })?; + Ok(()) } - trace!("realign_writes => realigned to: {}", self.buffer.position()); + pub fn write_aligned(&mut self, data_type: KbinType, data: &[u8]) -> Result<(), KbinError> { + if self.offset_1 % 4 == 0 { + self.offset_1 = self.data_buf_offset(); + } + if self.offset_2 % 4 == 0 { + self.offset_2 = self.data_buf_offset(); + } - Ok(()) - } + let old_pos = self.data_buf_offset(); + let size = data_type.size * data_type.count; + trace!( + "write_aligned => old_pos: {}, size: {}, data: 0x{:02x?}", + old_pos, + size, + data + ); + + if size != data.len() { + return Err(KbinError::SizeMismatch { + node_type: data_type.name, + expected: size, + actual: data.len(), + }); + } + + let check_old = match size { + 1 => { + // Make room for new DWORD + if self.offset_1 % 4 == 0 { + self.buffer + .write_u32::(0) + .context(WritePadding { size: 4usize })?; + } + + self.buffer + .seek(SeekFrom::Start(self.offset_1)) + .context(SeekOffset { + offset: self.offset_1 as usize, + })?; + self.buffer + .write_u8(data[0]) + .context(WriteDataByte { offset: 1usize })?; + self.offset_1 += 1; + + true + }, + 2 => { + // Make room for new DWORD + if self.offset_2 % 4 == 0 { + self.buffer + .write_u32::(0) + .context(WritePadding { size: 4usize })?; + } + + self.buffer + .seek(SeekFrom::Start(self.offset_2)) + .context(SeekOffset { + offset: self.offset_2 as usize, + })?; + self.buffer + .write_u8(data[0]) + .context(WriteDataByte { offset: 1usize })?; + self.buffer + .write_u8(data[1]) + .context(WriteDataByte { offset: 2usize })?; + self.offset_2 += 2; + + true + }, + _ => { + self.buffer.write_all(data).context(WriteDataBlock)?; + self.realign_writes(None)?; + + false + }, + }; + + if check_old { + self.buffer + .seek(SeekFrom::Start(old_pos)) + .context(SeekOffset { + offset: old_pos as usize, + })?; + + let trailing = max(self.offset_1, self.offset_2); + trace!( + "write_aligned => old_pos: {}, trailing: {}", + old_pos, + trailing + ); + if old_pos < trailing { + self.buffer + .seek(SeekFrom::Start(trailing)) + .context(SeekOffset { + offset: trailing as usize, + })?; + self.realign_writes(None)?; + } + } + + Ok(()) + } + + pub fn realign_writes(&mut self, size: Option) -> Result<(), ByteBufferError> { + let size = size.unwrap_or(4); + trace!( + "realign_writes => position: {}, size: {}", + self.buffer.position(), + size + ); + + while self.buffer.position() % size > 0 { + self.buffer + .write_u8(0) + .context(WritePadding { size: 1usize })?; + } + + trace!("realign_writes => realigned to: {}", self.buffer.position()); + + Ok(()) + } } impl Deref for ByteBufferRead { - type Target = Cursor; + type Target = Cursor; - fn deref(&self) -> &Self::Target { - &self.cursor - } + fn deref(&self) -> &Self::Target { + &self.cursor + } } impl DerefMut for ByteBufferRead { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.cursor - } + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.cursor + } } impl Deref for ByteBufferWrite { - type Target = Cursor>; + type Target = Cursor>; - fn deref(&self) -> &Self::Target { - &self.buffer - } + fn deref(&self) -> &Self::Target { + &self.buffer + } } impl DerefMut for ByteBufferWrite { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.buffer - } + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.buffer + } } diff --git a/src/compression.rs b/src/compression.rs index 311d83f..fb271ff 100644 --- a/src/compression.rs +++ b/src/compression.rs @@ -1,31 +1,31 @@ -use crate::error::KbinError; use super::{SIG_COMPRESSED, SIG_UNCOMPRESSED}; +use crate::error::KbinError; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Compression { - Compressed, - Uncompressed, + Compressed, + Uncompressed, } impl Compression { - pub fn from_byte(byte: u8) -> Result { - match byte { - SIG_COMPRESSED => Ok(Compression::Compressed), - SIG_UNCOMPRESSED => Ok(Compression::Uncompressed), - _ => Err(KbinError::UnknownCompression), + pub fn from_byte(byte: u8) -> Result { + match byte { + SIG_COMPRESSED => Ok(Compression::Compressed), + SIG_UNCOMPRESSED => Ok(Compression::Uncompressed), + _ => Err(KbinError::UnknownCompression), + } } - } - pub fn to_byte(&self) -> u8 { - match *self { - Compression::Compressed => SIG_COMPRESSED, - Compression::Uncompressed => SIG_UNCOMPRESSED, + pub fn to_byte(&self) -> u8 { + match *self { + Compression::Compressed => SIG_COMPRESSED, + Compression::Uncompressed => SIG_UNCOMPRESSED, + } } - } } impl Default for Compression { - fn default() -> Self { - Compression::Compressed - } + fn default() -> Self { + Compression::Compressed + } } diff --git a/src/encoding_type.rs b/src/encoding_type.rs index eafa5b8..17f9e03 100644 --- a/src/encoding_type.rs +++ b/src/encoding_type.rs @@ -10,215 +10,205 @@ use snafu::{ResultExt, Snafu}; #[derive(Debug, Snafu)] pub enum EncodingError { - #[snafu(display("Unknown encoding"))] - UnknownEncoding, + #[snafu(display("Unknown encoding"))] + UnknownEncoding, - #[snafu(display("Another encoding was used to decode the input: {:?}", actual))] - MismatchedDecode { - actual: &'static Encoding, - }, + #[snafu(display("Another encoding was used to decode the input: {:?}", actual))] + MismatchedDecode { actual: &'static Encoding }, - #[snafu(display("Another encoding was used to encode the output: {:?}", actual))] - MismatchedEncode { - actual: &'static Encoding, - }, + #[snafu(display("Another encoding was used to encode the output: {:?}", actual))] + MismatchedEncode { actual: &'static Encoding }, - #[snafu(display("Unmappable characters found in input"))] - UnmappableCharacters, + #[snafu(display("Unmappable characters found in input"))] + UnmappableCharacters, - #[snafu(display("Invalid ASCII character at index: {}", index))] - InvalidAscii { - index: usize, - }, + #[snafu(display("Invalid ASCII character at index: {}", index))] + InvalidAscii { index: usize }, - #[snafu(display("Failed to interpret string as UTF-8"))] - InvalidUtf8 { - source: FromUtf8Error, - }, + #[snafu(display("Failed to interpret string as UTF-8"))] + InvalidUtf8 { source: FromUtf8Error }, - #[snafu(display("Failed to convert string to alternate encoding"))] - Convert, + #[snafu(display("Failed to convert string to alternate encoding"))] + Convert, } #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum EncodingType { - None, - ASCII, - ISO_8859_1, - EUC_JP, - SHIFT_JIS, - UTF_8, + None, + ASCII, + ISO_8859_1, + EUC_JP, + SHIFT_JIS, + UTF_8, } impl Default for EncodingType { - fn default() -> Self { - EncodingType::SHIFT_JIS - } + fn default() -> Self { + EncodingType::SHIFT_JIS + } } impl fmt::Display for EncodingType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let encoding = match *self { - EncodingType::None => "None", - EncodingType::ASCII => "ASCII", - EncodingType::ISO_8859_1 => "ISO-8859-1", - EncodingType::EUC_JP => "EUC-JP", - EncodingType::SHIFT_JIS => "SHIFT-JIS", - EncodingType::UTF_8 => "UTF-8", - }; + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let encoding = match *self { + EncodingType::None => "None", + EncodingType::ASCII => "ASCII", + EncodingType::ISO_8859_1 => "ISO-8859-1", + EncodingType::EUC_JP => "EUC-JP", + EncodingType::SHIFT_JIS => "SHIFT-JIS", + EncodingType::UTF_8 => "UTF-8", + }; - write!(f, "{}", encoding) - } + write!(f, "{}", encoding) + } } impl EncodingType { - pub fn from_byte(byte: u8) -> Result { - let val = match byte { - 0x00 => EncodingType::None, - 0x20 => EncodingType::ASCII, - 0x40 => EncodingType::ISO_8859_1, - 0x60 => EncodingType::EUC_JP, - 0x80 => EncodingType::SHIFT_JIS, - 0xA0 => EncodingType::UTF_8, - _ => return Err(EncodingError::UnknownEncoding), - }; + pub fn from_byte(byte: u8) -> Result { + let val = match byte { + 0x00 => EncodingType::None, + 0x20 => EncodingType::ASCII, + 0x40 => EncodingType::ISO_8859_1, + 0x60 => EncodingType::EUC_JP, + 0x80 => EncodingType::SHIFT_JIS, + 0xA0 => EncodingType::UTF_8, + _ => return Err(EncodingError::UnknownEncoding), + }; - Ok(val) - } - - pub fn from_encoding(encoding: &'static Encoding) -> Result { - match encoding { - e if e == WINDOWS_1252 => Ok(EncodingType::ISO_8859_1), - e if e == EUC_JP => Ok(EncodingType::EUC_JP), - e if e == SHIFT_JIS => Ok(EncodingType::SHIFT_JIS), - e if e == UTF_8 => Ok(EncodingType::UTF_8), - _ => return Err(EncodingError::UnknownEncoding), - } - } - - pub fn from_label(label: &[u8]) -> Result { - Encoding::for_label(label) - .ok_or(EncodingError::UnknownEncoding) - .and_then(Self::from_encoding) - } - - 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 name(&self) -> Option<&'static str> { - match *self { - EncodingType::None => None, - EncodingType::ASCII => None, - EncodingType::ISO_8859_1 => Some(WINDOWS_1252.name()), - EncodingType::EUC_JP => Some(EUC_JP.name()), - EncodingType::SHIFT_JIS => Some(SHIFT_JIS.name()), - EncodingType::UTF_8 => Some(UTF_8.name()), - } - } - - fn decode_ascii(input: &[u8]) -> Result { - // ASCII only goes up to 0x7F - match input.iter().position(|&ch| ch >= 0x80) { - Some(index) => { - Err(EncodingError::InvalidAscii { index }) - }, - None => { - String::from_utf8(input.to_vec()).context(InvalidUtf8) - }, - } - } - - fn encode_ascii(input: &str) -> Result, EncodingError> { - // ASCII only goes up to 0x7F - match input.as_bytes().iter().position(|&ch| ch >= 0x80) { - Some(index) => { - Err(EncodingError::InvalidAscii { index }) - }, - None => { - Ok(input.as_bytes().to_vec()) - }, - } - } - - fn decode_with_encoding(encoding: &'static Encoding, input: &[u8]) -> Result { - let (output, actual, character_replaced) = encoding.decode(input); - - //eprintln!("character replaced: {}", character_replaced); - - if character_replaced { - warn!("Character replacement occured with: {:?}", output); + Ok(val) } - // `EncodingType::SHIFT_JIS` will ignore invalid characters because Konami's - // implementation will include invalid characters. - if encoding != actual { - Err(EncodingError::MismatchedDecode { actual }) - } else if !character_replaced || encoding == SHIFT_JIS { - Ok(output.into_owned()) - } else { - Err(EncodingError::UnmappableCharacters) + pub fn from_encoding(encoding: &'static Encoding) -> Result { + match encoding { + e if e == WINDOWS_1252 => Ok(EncodingType::ISO_8859_1), + e if e == EUC_JP => Ok(EncodingType::EUC_JP), + e if e == SHIFT_JIS => Ok(EncodingType::SHIFT_JIS), + e if e == UTF_8 => Ok(EncodingType::UTF_8), + _ => return Err(EncodingError::UnknownEncoding), + } } - } - fn encode_with_encoding(encoding: &'static Encoding, input: &str) -> Result, EncodingError> { - let (output, actual, had_unmappable_characters) = encoding.encode(input); - - if encoding != actual { - Err(EncodingError::MismatchedEncode { actual }) - } else if had_unmappable_characters { - Err(EncodingError::UnmappableCharacters) - } else { - Ok(output.into_owned()) + pub fn from_label(label: &[u8]) -> Result { + Encoding::for_label(label) + .ok_or(EncodingError::UnknownEncoding) + .and_then(Self::from_encoding) } - } - /// Decode bytes using the encoding definition from the `encoding` crate. - /// - /// A `Some` value indicates an encoding should be used from the `encoding` - /// crate. A `None` value indicates Rust's own UTF-8 handling should be used. - /// - /// `EncodingType::SHIFT_JIS` will ignore invalid characters because Konami's - /// implementation will include invalid characters. - pub fn decode_bytes(&self, input: &[u8]) -> Result { - match *self { - EncodingType::None | - EncodingType::UTF_8 => String::from_utf8(input.to_vec()).context(InvalidUtf8), - - EncodingType::ASCII => Self::decode_ascii(input), - EncodingType::ISO_8859_1 => Self::decode_with_encoding(WINDOWS_1252, input), - EncodingType::EUC_JP => Self::decode_with_encoding(EUC_JP, input), - EncodingType::SHIFT_JIS => Self::decode_with_encoding(SHIFT_JIS, input), + 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 + } } - } - /// Encode bytes using the encoding definition from the `encoding` crate. - /// - /// A `Some` value indicates the encoding should be used from the `encoding` - /// crate. A `None` value indicates Rust's own UTF-8 handling should be used. - pub fn encode_bytes(&self, input: &str) -> Result, EncodingError> { - let mut result = match *self { - EncodingType::None | - EncodingType::UTF_8 => input.as_bytes().to_vec(), + pub fn name(&self) -> Option<&'static str> { + match *self { + EncodingType::None => None, + EncodingType::ASCII => None, + EncodingType::ISO_8859_1 => Some(WINDOWS_1252.name()), + EncodingType::EUC_JP => Some(EUC_JP.name()), + EncodingType::SHIFT_JIS => Some(SHIFT_JIS.name()), + EncodingType::UTF_8 => Some(UTF_8.name()), + } + } - EncodingType::ASCII => Self::encode_ascii(input)?, - EncodingType::ISO_8859_1 => Self::encode_with_encoding(WINDOWS_1252, input)?, - EncodingType::EUC_JP => Self::encode_with_encoding(EUC_JP, input)?, - EncodingType::SHIFT_JIS => Self::encode_with_encoding(SHIFT_JIS, input)?, - }; + fn decode_ascii(input: &[u8]) -> Result { + // ASCII only goes up to 0x7F + match input.iter().position(|&ch| ch >= 0x80) { + Some(index) => Err(EncodingError::InvalidAscii { index }), + None => String::from_utf8(input.to_vec()).context(InvalidUtf8), + } + } - // Add trailing null byte - result.reserve_exact(1); - result.push(0); + fn encode_ascii(input: &str) -> Result, EncodingError> { + // ASCII only goes up to 0x7F + match input.as_bytes().iter().position(|&ch| ch >= 0x80) { + Some(index) => Err(EncodingError::InvalidAscii { index }), + None => Ok(input.as_bytes().to_vec()), + } + } - Ok(result) - } + fn decode_with_encoding( + encoding: &'static Encoding, + input: &[u8], + ) -> Result { + let (output, actual, character_replaced) = encoding.decode(input); + + //eprintln!("character replaced: {}", character_replaced); + + if character_replaced { + warn!("Character replacement occured with: {:?}", output); + } + + // `EncodingType::SHIFT_JIS` will ignore invalid characters because Konami's + // implementation will include invalid characters. + if encoding != actual { + Err(EncodingError::MismatchedDecode { actual }) + } else if !character_replaced || encoding == SHIFT_JIS { + Ok(output.into_owned()) + } else { + Err(EncodingError::UnmappableCharacters) + } + } + + fn encode_with_encoding( + encoding: &'static Encoding, + input: &str, + ) -> Result, EncodingError> { + let (output, actual, had_unmappable_characters) = encoding.encode(input); + + if encoding != actual { + Err(EncodingError::MismatchedEncode { actual }) + } else if had_unmappable_characters { + Err(EncodingError::UnmappableCharacters) + } else { + Ok(output.into_owned()) + } + } + + /// Decode bytes using the encoding definition from the `encoding` crate. + /// + /// A `Some` value indicates an encoding should be used from the `encoding` + /// crate. A `None` value indicates Rust's own UTF-8 handling should be used. + /// + /// `EncodingType::SHIFT_JIS` will ignore invalid characters because Konami's + /// implementation will include invalid characters. + pub fn decode_bytes(&self, input: &[u8]) -> Result { + match *self { + EncodingType::None | EncodingType::UTF_8 => { + String::from_utf8(input.to_vec()).context(InvalidUtf8) + }, + + EncodingType::ASCII => Self::decode_ascii(input), + EncodingType::ISO_8859_1 => Self::decode_with_encoding(WINDOWS_1252, input), + EncodingType::EUC_JP => Self::decode_with_encoding(EUC_JP, input), + EncodingType::SHIFT_JIS => Self::decode_with_encoding(SHIFT_JIS, input), + } + } + + /// Encode bytes using the encoding definition from the `encoding` crate. + /// + /// A `Some` value indicates the encoding should be used from the `encoding` + /// crate. A `None` value indicates Rust's own UTF-8 handling should be used. + pub fn encode_bytes(&self, input: &str) -> Result, EncodingError> { + let mut result = match *self { + EncodingType::None | EncodingType::UTF_8 => input.as_bytes().to_vec(), + + EncodingType::ASCII => Self::encode_ascii(input)?, + EncodingType::ISO_8859_1 => Self::encode_with_encoding(WINDOWS_1252, input)?, + EncodingType::EUC_JP => Self::encode_with_encoding(EUC_JP, input)?, + EncodingType::SHIFT_JIS => Self::encode_with_encoding(SHIFT_JIS, input)?, + }; + + // Add trailing null byte + result.reserve_exact(1); + result.push(0); + + Ok(result) + } } diff --git a/src/error.rs b/src/error.rs index 504217c..3664aa3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,8 +6,8 @@ use std::result::Result as StdResult; use std::str::Utf8Error; use std::string::FromUtf8Error; -use rustc_hex::FromHexError; use quick_xml::Error as QuickXmlError; +use rustc_hex::FromHexError; use snafu::Snafu; use crate::byte_buffer::ByteBufferError; @@ -22,185 +22,169 @@ pub type Result = StdResult; #[derive(Debug, Snafu)] #[snafu(visibility = "pub(crate)")] pub enum KbinError { - #[snafu(display("Unable to write {} header field", field))] - HeaderWrite { - field: &'static str, - source: io::Error, - }, + #[snafu(display("Unable to write {} header field", field))] + HeaderWrite { + field: &'static str, + source: io::Error, + }, - #[snafu(display("Invalid byte value for {} header field", field))] - HeaderValue { - field: &'static str, - }, + #[snafu(display("Invalid byte value for {} header field", field))] + HeaderValue { field: &'static str }, - #[snafu(display("Unable to read {} bytes from data buffer", size))] - DataRead { - size: usize, - source: io::Error, - }, + #[snafu(display("Unable to read {} bytes from data buffer", size))] + DataRead { size: usize, source: io::Error }, - #[snafu(display("Unable to write a {} to data buffer", node_type))] - DataWrite { - node_type: &'static str, - source: io::Error, - }, + #[snafu(display("Unable to write a {} to data buffer", node_type))] + DataWrite { + node_type: &'static str, + source: io::Error, + }, - #[snafu(display("Unable to read bytes or not enough data read"))] - DataConvert { - source: io::Error, - }, + #[snafu(display("Unable to read bytes or not enough data read"))] + DataConvert { source: io::Error }, - #[snafu(display("No node collection found"))] - NoNodeCollection, + #[snafu(display("No node collection found"))] + NoNodeCollection, - #[snafu(display("Failed to interpret string as UTF-8"))] - Utf8 { - source: FromUtf8Error, - }, + #[snafu(display("Failed to interpret string as UTF-8"))] + Utf8 { source: FromUtf8Error }, - #[snafu(display("Failed to interpret slice as UTF-8"))] - Utf8Slice { - source: Utf8Error, - }, + #[snafu(display("Failed to interpret slice as UTF-8"))] + Utf8Slice { source: Utf8Error }, - #[snafu(display("Unknown compression value"))] - UnknownCompression, + #[snafu(display("Unknown compression value"))] + UnknownCompression, - #[snafu(display("Size Mismatch, type: {}, expected size: {}, actual size: {}", node_type, expected, actual))] - SizeMismatch { - node_type: &'static str, - expected: usize, - actual: usize, - }, + #[snafu(display( + "Size Mismatch, type: {}, expected size: {}, actual size: {}", + node_type, + expected, + actual + ))] + SizeMismatch { + node_type: &'static str, + expected: usize, + actual: usize, + }, - #[snafu(display("Unable to interpret input as {}", node_type))] - StringParse { - node_type: &'static str, - source: Box, - }, + #[snafu(display("Unable to interpret input as {}", node_type))] + StringParse { + node_type: &'static str, + source: Box, + }, - #[snafu(display("Unable to interpret integer input as {}", node_type))] - StringParseInt { - node_type: &'static str, - source: ParseIntError, - }, + #[snafu(display("Unable to interpret integer input as {}", node_type))] + StringParseInt { + node_type: &'static str, + source: ParseIntError, + }, - #[snafu(display("Unable to interpret float input as {}", node_type))] - StringParseFloat { - node_type: &'static str, - source: ParseFloatError, - }, + #[snafu(display("Unable to interpret float input as {}", node_type))] + StringParseFloat { + node_type: &'static str, + source: ParseFloatError, + }, - #[snafu(display("Unable to convert from hexadecimal"))] - HexError { - source: FromHexError, - }, + #[snafu(display("Unable to convert from hexadecimal"))] + HexError { source: FromHexError }, - #[snafu(display("Type mismatch, expected: {}, found: {}", expected, found))] - TypeMismatch { - expected: StandardType, - found: StandardType, - }, + #[snafu(display("Type mismatch, expected: {}, found: {}", expected, found))] + TypeMismatch { + expected: StandardType, + found: StandardType, + }, - #[snafu(display("Value mismatch, expected {}, but found {:?}", node_type, value))] - ValueTypeMismatch { - node_type: StandardType, - value: Value, - }, + #[snafu(display("Value mismatch, expected {}, but found {:?}", node_type, value))] + ValueTypeMismatch { + node_type: StandardType, + value: Value, + }, - #[snafu(display("Value mismatch, expected an array, but found {:?}", value))] - ExpectedValueArray { - value: Value, - }, + #[snafu(display("Value mismatch, expected an array, but found {:?}", value))] + ExpectedValueArray { value: Value }, - #[snafu(display("Invalid input for boolean: {}", input))] - InvalidBooleanInput { - input: u8, - }, + #[snafu(display("Invalid input for boolean: {}", input))] + InvalidBooleanInput { input: u8 }, - #[snafu(display("Invalid node type for operation: {:?}", node_type))] - InvalidNodeType { - node_type: StandardType, - }, + #[snafu(display("Invalid node type for operation: {:?}", node_type))] + InvalidNodeType { node_type: StandardType }, - #[snafu(display("Invalid state"))] - InvalidState, + #[snafu(display("Invalid state"))] + InvalidState, - #[snafu(display("Failed to handle byte buffer operation"))] - ByteBuffer { - #[snafu(backtrace)] - source: ByteBufferError, - }, + #[snafu(display("Failed to handle byte buffer operation"))] + ByteBuffer { + #[snafu(backtrace)] + source: ByteBufferError, + }, - #[snafu(display("Failed to handle string encoding operation"))] - Encoding { - #[snafu(backtrace)] - source: EncodingError, - }, + #[snafu(display("Failed to handle string encoding operation"))] + Encoding { + #[snafu(backtrace)] + source: EncodingError, + }, - #[snafu(display("Failed to read binary XML"))] - Reader { - #[snafu(backtrace)] - source: ReaderError, - }, + #[snafu(display("Failed to read binary XML"))] + Reader { + #[snafu(backtrace)] + source: ReaderError, + }, - #[snafu(display("Failed to handle sixbit string operation"))] - Sixbit { - #[snafu(backtrace)] - source: SixbitError, - }, + #[snafu(display("Failed to handle sixbit string operation"))] + Sixbit { + #[snafu(backtrace)] + source: SixbitError, + }, - #[snafu(display("Error handling XML"))] - XmlError { - source: QuickXmlError, - }, + #[snafu(display("Error handling XML"))] + XmlError { source: QuickXmlError }, } impl From for KbinError { - #[inline] - fn from(source: FromUtf8Error) -> Self { - KbinError::Utf8 { source } - } + #[inline] + fn from(source: FromUtf8Error) -> Self { + KbinError::Utf8 { source } + } } impl From for KbinError { - #[inline] - fn from(source: Utf8Error) -> Self { - KbinError::Utf8Slice { source } - } + #[inline] + fn from(source: Utf8Error) -> Self { + KbinError::Utf8Slice { source } + } } impl From for KbinError { - #[inline] - fn from(source: ByteBufferError) -> Self { - KbinError::ByteBuffer { source } - } + #[inline] + fn from(source: ByteBufferError) -> Self { + KbinError::ByteBuffer { source } + } } impl From for KbinError { - #[inline] - fn from(source: EncodingError) -> Self { - KbinError::Encoding { source } - } + #[inline] + fn from(source: EncodingError) -> Self { + KbinError::Encoding { source } + } } impl From for KbinError { - #[inline] - fn from(source: ReaderError) -> Self { - KbinError::Reader { source } - } + #[inline] + fn from(source: ReaderError) -> Self { + KbinError::Reader { source } + } } impl From for KbinError { - #[inline] - fn from(source: SixbitError) -> Self { - KbinError::Sixbit { source } - } + #[inline] + fn from(source: SixbitError) -> Self { + KbinError::Sixbit { source } + } } impl From for KbinError { - #[inline] - fn from(source: QuickXmlError) -> Self { - KbinError::XmlError { source } - } + #[inline] + fn from(source: QuickXmlError) -> Self { + KbinError::XmlError { source } + } } diff --git a/src/lib.rs b/src/lib.rs index babbcf9..8063a8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,9 @@ #![cfg_attr(test, feature(test))] -#[macro_use] extern crate lazy_static; -#[macro_use] extern crate log; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; use bytes::Bytes; @@ -27,15 +29,15 @@ use crate::to_text_xml::TextXmlWriter; // Public exports pub use crate::compression::Compression; pub use crate::encoding_type::EncodingType; -pub use crate::printer::Printer; -pub use crate::reader::Reader; pub use crate::error::{KbinError, Result}; pub use crate::node::{Node, NodeCollection}; pub use crate::node_types::StandardType; pub use crate::options::{Options, OptionsBuilder}; +pub use crate::printer::Printer; +pub use crate::reader::Reader; pub use crate::to_text_xml::ToTextXml; pub use crate::value::{Value, ValueArray}; -pub use crate::writer::{Writer, Writeable}; +pub use crate::writer::{Writeable, Writer}; const SIGNATURE: u8 = 0xA0; @@ -45,55 +47,62 @@ const SIG_UNCOMPRESSED: u8 = 0x45; const ARRAY_MASK: u8 = 1 << 6; // 1 << 6 = 64 pub fn is_binary_xml(input: &[u8]) -> bool { - input.len() > 2 && input[0] == SIGNATURE && (input[1] == SIG_COMPRESSED || input[1] == SIG_UNCOMPRESSED) + input.len() > 2 && + input[0] == SIGNATURE && + (input[1] == SIG_COMPRESSED || input[1] == SIG_UNCOMPRESSED) } pub fn from_binary(input: Bytes) -> Result<(NodeCollection, EncodingType)> { - let mut reader = Reader::new(input)?; - let collection = NodeCollection::from_iter(&mut reader).ok_or(KbinError::NoNodeCollection)?; - let encoding = reader.encoding(); + let mut reader = Reader::new(input)?; + let collection = NodeCollection::from_iter(&mut reader).ok_or(KbinError::NoNodeCollection)?; + let encoding = reader.encoding(); - Ok((collection, encoding)) + Ok((collection, encoding)) } pub fn from_text_xml(input: &[u8]) -> Result<(NodeCollection, EncodingType)> { - let mut reader = TextXmlReader::new(input); - let collection = reader.as_node_collection()?.ok_or(KbinError::NoNodeCollection)?; - let encoding = reader.encoding(); + let mut reader = TextXmlReader::new(input); + let collection = reader + .as_node_collection()? + .ok_or(KbinError::NoNodeCollection)?; + let encoding = reader.encoding(); - Ok((collection, encoding)) + Ok((collection, encoding)) } pub fn from_bytes(input: Bytes) -> Result<(NodeCollection, EncodingType)> { - if is_binary_xml(&input) { - from_binary(input) - } else { - from_text_xml(&input) - } + if is_binary_xml(&input) { + from_binary(input) + } else { + from_text_xml(&input) + } } #[inline] pub fn from_slice(input: &[u8]) -> Result<(NodeCollection, EncodingType)> { - from_binary(Bytes::from(input)) + from_binary(Bytes::from(input)) } pub fn to_binary(input: &T) -> Result> - where T: Writeable +where + T: Writeable, { - let mut writer = Writer::new(); - writer.to_binary(input) + let mut writer = Writer::new(); + writer.to_binary(input) } pub fn to_binary_with_options(options: Options, input: &T) -> Result> - where T: Writeable +where + T: Writeable, { - let mut writer = Writer::with_options(options); - writer.to_binary(input) + let mut writer = Writer::with_options(options); + writer.to_binary(input) } pub fn to_text_xml(input: &T) -> Result> - where T: ToTextXml +where + T: ToTextXml, { - let writer = TextXmlWriter::new(); - writer.to_text_xml(input) + let writer = TextXmlWriter::new(); + writer.to_text_xml(input) } diff --git a/src/node/collection.rs b/src/node/collection.rs index efacc2e..9376db7 100644 --- a/src/node/collection.rs +++ b/src/node/collection.rs @@ -8,189 +8,201 @@ use crate::node_types::StandardType; use crate::value::Value; fn parse_index(s: &str) -> Option { - if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) { - return None; - } - s.parse().ok() + if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) { + return None; + } + s.parse().ok() } /// A collection of node definitions (`NodeDefinition`) #[derive(Clone, Debug, Eq, PartialEq)] pub struct NodeCollection { - base: NodeDefinition, - attributes: VecDeque, - children: VecDeque, + base: NodeDefinition, + attributes: VecDeque, + children: VecDeque, } impl NodeCollection { - pub fn new(base: NodeDefinition) -> Self { - Self { - base, - attributes: VecDeque::with_capacity(0), - children: VecDeque::with_capacity(0), - } - } - - pub fn with_attributes(base: NodeDefinition, attributes: VecDeque) -> Self { - Self { - base, - attributes, - children: VecDeque::with_capacity(0), - } - } - - pub fn from_iter(iter: &mut I) -> Option - where I: Iterator - { - let base = if let Some(def) = iter.next() { - def - } else { - return None; - }; - - NodeCollection::from_iter_base(base, iter) - } - - fn from_iter_base(base: NodeDefinition, iter: &mut I) -> Option - where I: Iterator - { - let mut attributes = VecDeque::new(); - let mut children = VecDeque::new(); - - loop { - if let Some(def) = iter.next() { - match def.node_type { - StandardType::Attribute => attributes.push_back(def), - StandardType::NodeEnd | - StandardType::FileEnd => break, - _ => match NodeCollection::from_iter_base(def, iter) { - Some(child) => children.push_back(child), - None => return None, - }, + pub fn new(base: NodeDefinition) -> Self { + Self { + base, + attributes: VecDeque::with_capacity(0), + children: VecDeque::with_capacity(0), } - } else { - break; - } } - Some(NodeCollection { - base, - attributes, - children, - }) - } - - #[inline] - pub fn base(&self) -> &NodeDefinition { - &self.base - } - - #[inline] - pub fn base_mut(&mut self) -> &mut NodeDefinition { - &mut self.base - } - - #[inline] - pub fn attributes(&self) -> &VecDeque { - &self.attributes - } - - #[inline] - pub fn attributes_mut(&mut self) -> &mut VecDeque { - &mut self.attributes - } - - #[inline] - pub fn children(&self) -> &VecDeque { - &self.children - } - - #[inline] - pub fn children_mut(&mut self) -> &mut VecDeque { - &mut self.children - } - - pub fn as_node(&self) -> Result { - let mut node = self.base.as_node()?; - - for attr in &self.attributes { - let key = attr.key()?.ok_or(KbinError::InvalidState)?; - - if let Value::Attribute(value) = attr.value()? { - node.set_attr(key, value); - } else { - return Err(KbinError::InvalidState.into()); - } + pub fn with_attributes(base: NodeDefinition, attributes: VecDeque) -> Self { + Self { + base, + attributes, + children: VecDeque::with_capacity(0), + } } - for child in &self.children { - node.append_child(child.as_node()?); + pub fn from_iter(iter: &mut I) -> Option + where + I: Iterator, + { + let base = if let Some(def) = iter.next() { + def + } else { + return None; + }; + + NodeCollection::from_iter_base(base, iter) } - Ok(node) - } + fn from_iter_base(base: NodeDefinition, iter: &mut I) -> Option + where + I: Iterator, + { + let mut attributes = VecDeque::new(); + let mut children = VecDeque::new(); - pub fn pointer<'a>(&'a self, pointer: &[&str]) -> Option<&'a NodeCollection> { - if pointer.is_empty() { - return Some(self); - } - let mut target = self; + loop { + if let Some(def) = iter.next() { + match def.node_type { + StandardType::Attribute => attributes.push_back(def), + StandardType::NodeEnd | StandardType::FileEnd => break, + _ => match NodeCollection::from_iter_base(def, iter) { + Some(child) => children.push_back(child), + None => return None, + }, + } + } else { + break; + } + } - for token in pointer { - let target_opt = if let Some(index) = parse_index(token) { - target.children().get(index) - } else { - target.children().iter().find(|ref child| { - child.base().key().ok().and_then(|x| x).expect("key not parseable") == *token + Some(NodeCollection { + base, + attributes, + children, }) - }; - - if let Some(t) = target_opt { - target = t; - } else { - return None; - } } - Some(target) - } + + #[inline] + pub fn base(&self) -> &NodeDefinition { + &self.base + } + + #[inline] + pub fn base_mut(&mut self) -> &mut NodeDefinition { + &mut self.base + } + + #[inline] + pub fn attributes(&self) -> &VecDeque { + &self.attributes + } + + #[inline] + pub fn attributes_mut(&mut self) -> &mut VecDeque { + &mut self.attributes + } + + #[inline] + pub fn children(&self) -> &VecDeque { + &self.children + } + + #[inline] + pub fn children_mut(&mut self) -> &mut VecDeque { + &mut self.children + } + + pub fn as_node(&self) -> Result { + let mut node = self.base.as_node()?; + + for attr in &self.attributes { + let key = attr.key()?.ok_or(KbinError::InvalidState)?; + + if let Value::Attribute(value) = attr.value()? { + node.set_attr(key, value); + } else { + return Err(KbinError::InvalidState.into()); + } + } + + for child in &self.children { + node.append_child(child.as_node()?); + } + + Ok(node) + } + + pub fn pointer<'a>(&'a self, pointer: &[&str]) -> Option<&'a NodeCollection> { + if pointer.is_empty() { + return Some(self); + } + let mut target = self; + + for token in pointer { + let target_opt = if let Some(index) = parse_index(token) { + target.children().get(index) + } else { + target.children().iter().find(|ref child| { + child + .base() + .key() + .ok() + .and_then(|x| x) + .expect("key not parseable") == + *token + }) + }; + + if let Some(t) = target_opt { + target = t; + } else { + return None; + } + } + Some(target) + } } struct DisplayDebugWrapper<'a, T: fmt::Display + 'a>(&'a T, bool); impl<'a, T> fmt::Debug for DisplayDebugWrapper<'a, T> - where T: fmt::Display +where + T: fmt::Display, { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.1 { - write!(f, "{:#}", self.0) - } else { - write!(f, "{}", self.0) + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.1 { + write!(f, "{:#}", self.0) + } else { + write!(f, "{}", self.0) + } } - } } struct VecDisplayDebugWrapper<'a, T: fmt::Display + 'a>(&'a VecDeque, bool); impl<'a, T> fmt::Debug for VecDisplayDebugWrapper<'a, T> - where T: fmt::Display +where + T: fmt::Display, { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut l = f.debug_list(); - for entry in self.0 { - l.entry(&DisplayDebugWrapper(&entry, self.1)); + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut l = f.debug_list(); + for entry in self.0 { + l.entry(&DisplayDebugWrapper(&entry, self.1)); + } + l.finish() } - l.finish() - } } impl fmt::Display for NodeCollection { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut d = f.debug_struct("NodeCollection"); + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut d = f.debug_struct("NodeCollection"); - d.field("base", &DisplayDebugWrapper(&self.base, false)); - d.field("attributes", &VecDisplayDebugWrapper(&self.attributes, false)); - d.field("children", &VecDisplayDebugWrapper(&self.children, true)); + d.field("base", &DisplayDebugWrapper(&self.base, false)); + d.field( + "attributes", + &VecDisplayDebugWrapper(&self.attributes, false), + ); + d.field("children", &VecDisplayDebugWrapper(&self.children, true)); - d.finish() - } + d.finish() + } } diff --git a/src/node/definition.rs b/src/node/definition.rs index 0ac69a2..c3ff111 100644 --- a/src/node/definition.rs +++ b/src/node/definition.rs @@ -12,232 +12,217 @@ use crate::value::Value; #[derive(Clone, Eq)] pub enum Key { - Compressed { - size: SixbitSize, - data: Bytes, - }, - Uncompressed { - encoding: EncodingType, - data: Bytes, - }, + Compressed { size: SixbitSize, data: Bytes }, + Uncompressed { encoding: EncodingType, data: Bytes }, } #[derive(Clone, Debug, Eq, PartialEq)] pub enum NodeData { - Some { - key: Key, - value_data: Bytes, - }, - None, + Some { key: Key, value_data: Bytes }, + None, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct NodeDefinition { - encoding: EncodingType, - pub node_type: StandardType, - pub is_array: bool, + encoding: EncodingType, + pub node_type: StandardType, + pub is_array: bool, - data: NodeData, + data: NodeData, } impl Key { - fn to_string(&self) -> Result { - match self { - Key::Compressed { ref size, ref data } => { - Sixbit::unpack(data, *size).map_err(Into::into) - }, - Key::Uncompressed { encoding, ref data } => { - encoding.decode_bytes(data).map_err(Into::into) - }, + fn to_string(&self) -> Result { + match self { + Key::Compressed { ref size, ref data } => { + Sixbit::unpack(data, *size).map_err(Into::into) + }, + Key::Uncompressed { encoding, ref data } => { + encoding.decode_bytes(data).map_err(Into::into) + }, + } } - } } impl NodeDefinition { - pub fn new(encoding: EncodingType, node_type: (StandardType, bool)) -> Self { - let (node_type, is_array) = node_type; + pub fn new(encoding: EncodingType, node_type: (StandardType, bool)) -> Self { + let (node_type, is_array) = node_type; - Self { - encoding, - node_type, - is_array, - data: NodeData::None, - } - } - - pub fn with_data(encoding: EncodingType, node_type: (StandardType, bool), data: NodeData) -> Self { - let (node_type, is_array) = node_type; - - Self { - encoding, - node_type, - is_array, - data, - } - } - - #[inline] - pub fn encoding(&self) -> EncodingType { - self.encoding - } - - #[inline] - pub fn node_type_tuple(&self) -> (StandardType, bool) { - (self.node_type, self.is_array) - } - - #[inline] - pub fn data<'a>(&'a self) -> &'a NodeData { - &self.data - } - - #[inline] - pub fn data_mut<'a>(&'a mut self) -> &'a mut NodeData { - &mut self.data - } - - pub fn key(&self) -> Result, KbinError> { - match self.data { - NodeData::Some { ref key, .. } => key.to_string().map(Some), - NodeData::None => Ok(None), - } - } - - pub fn value(&self) -> Result { - match (self.node_type, &self.data) { - (StandardType::Attribute, NodeData::Some { ref value_data, .. }) => { - let data = strip_trailing_null_bytes(value_data); - let value = self.encoding.decode_bytes(data)?; - Ok(Value::Attribute(value)) - }, - (StandardType::String, NodeData::Some { ref value_data, .. }) => { - let data = strip_trailing_null_bytes(value_data); - let value = self.encoding.decode_bytes(data)?; - Ok(Value::String(value)) - }, - (node_type, NodeData::Some { ref value_data, .. }) => { - let value = Value::from_standard_type(node_type, self.is_array, value_data)?; - match value { - Some(value) => Ok(value), - None => Err(KbinError::InvalidNodeType { node_type }), + Self { + encoding, + node_type, + is_array, + data: NodeData::None, } - }, - (node_type, NodeData::None) => { - Err(KbinError::InvalidNodeType { node_type }) - }, } - } - pub fn value_bytes<'a>(&'a self) -> Option<&'a [u8]> { - match self.data { - NodeData::Some { ref value_data, .. } => Some(value_data), - NodeData::None => None, - } - } + pub fn with_data( + encoding: EncodingType, + node_type: (StandardType, bool), + data: NodeData, + ) -> Self { + let (node_type, is_array) = node_type; - pub fn as_node(&self) -> Result { - trace!("parsing definition: {:?}", self); - match (self.node_type, &self.data) { - (StandardType::NodeEnd, _) | - (StandardType::FileEnd, _) => { - Err(KbinError::InvalidNodeType { node_type: self.node_type }) - }, - (StandardType::NodeStart, NodeData::Some { key, .. }) => { - let key = key.to_string()?; - Ok(Node::new(key)) - }, - (_, NodeData::Some { key, .. }) => { - let key = key.to_string()?; - let value = self.value()?; - Ok(Node::with_value(key, value)) - }, - (node_type, NodeData::None) => { - Err(KbinError::InvalidNodeType { node_type }) - }, + Self { + encoding, + node_type, + is_array, + data, + } + } + + #[inline] + pub fn encoding(&self) -> EncodingType { + self.encoding + } + + #[inline] + pub fn node_type_tuple(&self) -> (StandardType, bool) { + (self.node_type, self.is_array) + } + + #[inline] + pub fn data<'a>(&'a self) -> &'a NodeData { + &self.data + } + + #[inline] + pub fn data_mut<'a>(&'a mut self) -> &'a mut NodeData { + &mut self.data + } + + pub fn key(&self) -> Result, KbinError> { + match self.data { + NodeData::Some { ref key, .. } => key.to_string().map(Some), + NodeData::None => Ok(None), + } + } + + pub fn value(&self) -> Result { + match (self.node_type, &self.data) { + (StandardType::Attribute, NodeData::Some { ref value_data, .. }) => { + let data = strip_trailing_null_bytes(value_data); + let value = self.encoding.decode_bytes(data)?; + Ok(Value::Attribute(value)) + }, + (StandardType::String, NodeData::Some { ref value_data, .. }) => { + let data = strip_trailing_null_bytes(value_data); + let value = self.encoding.decode_bytes(data)?; + Ok(Value::String(value)) + }, + (node_type, NodeData::Some { ref value_data, .. }) => { + let value = Value::from_standard_type(node_type, self.is_array, value_data)?; + match value { + Some(value) => Ok(value), + None => Err(KbinError::InvalidNodeType { node_type }), + } + }, + (node_type, NodeData::None) => Err(KbinError::InvalidNodeType { node_type }), + } + } + + pub fn value_bytes<'a>(&'a self) -> Option<&'a [u8]> { + match self.data { + NodeData::Some { ref value_data, .. } => Some(value_data), + NodeData::None => None, + } + } + + pub fn as_node(&self) -> Result { + trace!("parsing definition: {:?}", self); + match (self.node_type, &self.data) { + (StandardType::NodeEnd, _) | (StandardType::FileEnd, _) => { + Err(KbinError::InvalidNodeType { + node_type: self.node_type, + }) + }, + (StandardType::NodeStart, NodeData::Some { key, .. }) => { + let key = key.to_string()?; + Ok(Node::new(key)) + }, + (_, NodeData::Some { key, .. }) => { + let key = key.to_string()?; + let value = self.value()?; + Ok(Node::with_value(key, value)) + }, + (node_type, NodeData::None) => Err(KbinError::InvalidNodeType { node_type }), + } } - } } impl PartialEq for Key { - fn eq(&self, other: &Key) -> bool { - match (self.to_string(), other.to_string()) { - (Ok(key1), Ok(key2)) => { - key1 == key2 - }, - (_, _) => { - // If the conversion fails, check if they have the same enum variant - // to check if the inner data is equal. - match (self, other) { - ( - Key::Compressed { data: data1, .. }, - Key::Compressed { data: data2, .. }, - ) => { - data1 == data2 - }, - ( - Key::Uncompressed { data: data1, .. }, - Key::Uncompressed { data: data2, .. }, - ) => { - data1 == data2 - }, - (_, _) => false, + fn eq(&self, other: &Key) -> bool { + match (self.to_string(), other.to_string()) { + (Ok(key1), Ok(key2)) => key1 == key2, + (_, _) => { + // If the conversion fails, check if they have the same enum variant + // to check if the inner data is equal. + match (self, other) { + (Key::Compressed { data: data1, .. }, Key::Compressed { data: data2, .. }) => { + data1 == data2 + }, + ( + Key::Uncompressed { data: data1, .. }, + Key::Uncompressed { data: data2, .. }, + ) => data1 == data2, + (_, _) => false, + } + }, } - }, } - } } impl fmt::Debug for Key { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Ok(key) = self.to_string() { - let variant = match self { - Key::Compressed { .. } => "Compressed", - Key::Uncompressed { .. } => "Uncompressed", - }; - write!(f, "{} {{ \"{}\" }}", variant, key) - } else { - match self { - Key::Compressed { ref size, ref data } => { - f.debug_struct("Compressed") - .field("size", &size) - .field("data", &data) - .finish() - }, - Key::Uncompressed { encoding, ref data } => { - f.debug_struct("Uncompressed") - .field("encoding", &encoding) - .field("data", &data) - .finish() - }, - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Ok(key) = self.to_string() { + let variant = match self { + Key::Compressed { .. } => "Compressed", + Key::Uncompressed { .. } => "Uncompressed", + }; + write!(f, "{} {{ \"{}\" }}", variant, key) + } else { + match self { + Key::Compressed { ref size, ref data } => f + .debug_struct("Compressed") + .field("size", &size) + .field("data", &data) + .finish(), + Key::Uncompressed { encoding, ref data } => f + .debug_struct("Uncompressed") + .field("encoding", &encoding) + .field("data", &data) + .finish(), + } + } } - } } impl fmt::Display for NodeDefinition { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut d = f.debug_struct("NodeDefinition"); - d.field("node_type", &self.node_type); + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut d = f.debug_struct("NodeDefinition"); + d.field("node_type", &self.node_type); - match self.node_type { - StandardType::Attribute | - StandardType::String => { - d.field("encoding", &self.encoding); - }, - _ => {}, - }; - - match self.data { - NodeData::Some { ref key, ref value_data } => { - match key.to_string() { - Ok(key) => d.field("key", &key), - Err(e) => d.field("key", &e), + match self.node_type { + StandardType::Attribute | StandardType::String => { + d.field("encoding", &self.encoding); + }, + _ => {}, }; - d.field("value_data", &value_data); - }, - NodeData::None => {}, - }; - d.finish() - } + match self.data { + NodeData::Some { + ref key, + ref value_data, + } => { + match key.to_string() { + Ok(key) => d.field("key", &key), + Err(e) => d.field("key", &e), + }; + d.field("value_data", &value_data); + }, + NodeData::None => {}, + }; + + d.finish() + } } diff --git a/src/node/mod.rs b/src/node/mod.rs index 245ee41..a7d68be 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -14,343 +14,352 @@ pub use self::definition::{Key, NodeData, NodeDefinition}; // The attributes argument is very hard to generalize fn convert_attributes(attrs: &[(&str, &str)]) -> IndexMap { - attrs.iter() - .map(|(key, value)| (String::from(*key), String::from(*value))) - .collect() + attrs + .iter() + .map(|(key, value)| (String::from(*key), String::from(*value))) + .collect() } fn parse_index(s: &str) -> Option { - if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) { - return None; - } - s.parse().ok() + if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) { + return None; + } + s.parse().ok() } pub struct OptionIterator { - inner: Option, + inner: Option, } #[derive(Clone, Default, PartialEq)] pub struct Node { - key: String, - attributes: Option>, - children: Option>, - value: Option, + key: String, + attributes: Option>, + children: Option>, + value: Option, } impl fmt::Debug for Node { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut d = f.debug_struct("Node"); - d.field("key", &self.key); + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut d = f.debug_struct("Node"); + d.field("key", &self.key); - if let Some(ref attributes) = self.attributes { - d.field("attributes", attributes); - } - if let Some(ref children) = self.children { - d.field("children", children); - } - if let Some(ref value) = self.value { - d.field("value", value); - } + if let Some(ref attributes) = self.attributes { + d.field("attributes", attributes); + } + if let Some(ref children) = self.children { + d.field("children", children); + } + if let Some(ref value) = self.value { + d.field("value", value); + } - d.finish() - } + d.finish() + } } impl Node { - pub fn new(key: K) -> Self - where K: Into - { - Self { - key: key.into(), - attributes: None, - children: None, - value: None, - } - } - - pub fn with_attrs(key: K, attrs: &[(&str, &str)]) -> Self - where K: Into - { - Self { - key: key.into(), - attributes: Some(convert_attributes(attrs)), - children: None, - value: None, - } - } - - pub fn with_value(key: K, value: Value) -> Self - where K: Into - { - Self { - key: key.into(), - attributes: None, - children: None, - value: Some(value), - } - } - - pub fn with_nodes(key: K, nodes: N) -> Self - where K: Into, - N: Into> - { - Self { - key: key.into(), - attributes: None, - children: Some(nodes.into()), - value: None, - } - } - - pub fn with(key: K, attrs: &[(&str, &str)], nodes: N) -> Self - where K: Into, - N: Into> - { - Self { - key: key.into(), - attributes: Some(convert_attributes(attrs)), - children: Some(nodes.into()), - value: None, - } - } - - pub fn with_attrs_value(key: K, attrs: &[(&str, &str)], value: Value) -> Self - where K: Into - { - Self { - key: key.into(), - attributes: Some(convert_attributes(attrs)), - children: None, - value: Some(value), - } - } - - #[inline] - pub fn key(&self) -> &str { - &self.key - } - - #[inline] - pub fn attributes(&self) -> Option<&IndexMap> { - self.attributes.as_ref() - } - - #[inline] - pub fn attributes_mut(&mut self) -> Option<&mut IndexMap> { - self.attributes.as_mut() - } - - #[inline] - pub fn children(&self) -> Option<&Vec> { - self.children.as_ref() - } - - #[inline] - pub fn children_mut(&mut self) -> Option<&mut Vec> { - self.children.as_mut() - } - - #[inline] - pub fn value(&self) -> Option<&Value> { - self.value.as_ref() - } - - #[inline] - pub fn value_mut(&mut self) -> Option<&mut Value> { - self.value.as_mut() - } - - #[inline] - pub fn children_iter(&self) -> OptionIterator<&Vec> { - OptionIterator::new(self.children()) - } - - #[inline] - pub fn children_iter_mut(&mut self) -> OptionIterator<&mut Vec> { - OptionIterator::new(self.children_mut()) - } - - pub fn attr(&self, key: &str) -> Option<&str> { - self.attributes().and_then(|attributes| { - attributes.get(key).map(String::as_str) - }) - } - - pub fn attr_mut(&mut self, key: &str) -> Option<&mut String> { - self.attributes_mut().and_then(|attributes| { - attributes.get_mut(key) - }) - } - - pub fn into_key_and_value(self) -> (String, Option) { - (self.key, self.value) - } - - pub fn set_key(&mut self, key: String) { - self.key = key; - } - - pub fn set_attr(&mut self, key: K, value: V) -> Option - where K: Into, - V: Into - { - let attributes = self.attributes.get_or_insert_with(Default::default); - attributes.insert(key.into(), value.into()) - } - - pub fn remove_attr(&mut self, key: &str) -> Option { - self.attributes.as_mut().and_then(|attributes| attributes.swap_remove(key)) - } - - pub fn sort_attrs(&mut self) { - if let Some(ref mut attributes) = self.attributes { - attributes.sort_keys(); - } - } - - pub fn append_child(&mut self, value: Node) { - let children = self.children.get_or_insert_with(Default::default); - children.push(value); - } - - pub fn set_value(&mut self, value: Option) -> Option { - mem::replace(&mut self.value, value) - } - - pub fn has(&self, key: &str) -> bool { - if let Some(ref children) = self.children { - for node in children { - if node.key == key { - return true; + pub fn new(key: K) -> Self + where + K: Into, + { + Self { + key: key.into(), + attributes: None, + children: None, + value: None, } - } } - false - } - - pub fn get_child(&self, key: &str) -> Option<&Node> { - if let Some(ref children) = self.children { - for node in children { - if node.key == key { - return Some(node); + pub fn with_attrs(key: K, attrs: &[(&str, &str)]) -> Self + where + K: Into, + { + Self { + key: key.into(), + attributes: Some(convert_attributes(attrs)), + children: None, + value: None, } - } } - None - } - - pub fn get_child_mut(&mut self, key: &str) -> Option<&mut Node> { - if let Some(ref mut children) = self.children { - for node in children { - if node.key == key { - return Some(node); + pub fn with_value(key: K, value: Value) -> Self + where + K: Into, + { + Self { + key: key.into(), + attributes: None, + children: None, + value: Some(value), } - } } - None - } - - pub fn remove_child(&mut self, key: &str) -> Option { - if let Some(ref mut children) = self.children { - let index = children.iter() - .enumerate() - .find(|(_, child)| child.key() == key) - .map(|(index, _)| index); - - if let Some(index) = index { - return Some(children.remove(index)); - } + pub fn with_nodes(key: K, nodes: N) -> Self + where + K: Into, + N: Into>, + { + Self { + key: key.into(), + attributes: None, + children: Some(nodes.into()), + value: None, + } } - None - } - - pub fn remove_child_at(&mut self, index: usize) -> Option { - self.children.as_mut().map(|children| children.remove(index)) - } - - pub fn pointer<'a>(&'a self, pointer: &[&str]) -> Option<&'a Node> { - if pointer.is_empty() { - return Some(self); + pub fn with(key: K, attrs: &[(&str, &str)], nodes: N) -> Self + where + K: Into, + N: Into>, + { + Self { + key: key.into(), + attributes: Some(convert_attributes(attrs)), + children: Some(nodes.into()), + value: None, + } } - let mut target = self; - for token in pointer { - let children = match target.children { - Some(ref v) => v, - None => return None, - }; - - let target_opt = if let Some(index) = parse_index(token) { - children.get(index) - } else { - children.iter().find(|ref child| { - child.key() == *token - }) - }; - - if let Some(t) = target_opt { - target = t; - } else { - return None; - } + pub fn with_attrs_value(key: K, attrs: &[(&str, &str)], value: Value) -> Self + where + K: Into, + { + Self { + key: key.into(), + attributes: Some(convert_attributes(attrs)), + children: None, + value: Some(value), + } } - Some(target) - } - pub fn pointer_mut<'a>(&'a mut self, pointer: &[&str]) -> Option<&'a mut Node> { - if pointer.is_empty() { - return Some(self); + #[inline] + pub fn key(&self) -> &str { + &self.key } - let mut target = self; - for token in pointer { - let children = match target.children { - Some(ref mut v) => v, - None => return None, - }; - - let target_opt = if let Some(index) = parse_index(token) { - children.get_mut(index) - } else { - children.iter_mut().find(|ref child| { - child.key() == *token - }) - }; - - if let Some(t) = target_opt { - target = t; - } else { - return None; - } + #[inline] + pub fn attributes(&self) -> Option<&IndexMap> { + self.attributes.as_ref() + } + + #[inline] + pub fn attributes_mut(&mut self) -> Option<&mut IndexMap> { + self.attributes.as_mut() + } + + #[inline] + pub fn children(&self) -> Option<&Vec> { + self.children.as_ref() + } + + #[inline] + pub fn children_mut(&mut self) -> Option<&mut Vec> { + self.children.as_mut() + } + + #[inline] + pub fn value(&self) -> Option<&Value> { + self.value.as_ref() + } + + #[inline] + pub fn value_mut(&mut self) -> Option<&mut Value> { + self.value.as_mut() + } + + #[inline] + pub fn children_iter(&self) -> OptionIterator<&Vec> { + OptionIterator::new(self.children()) + } + + #[inline] + pub fn children_iter_mut(&mut self) -> OptionIterator<&mut Vec> { + OptionIterator::new(self.children_mut()) + } + + pub fn attr(&self, key: &str) -> Option<&str> { + self.attributes() + .and_then(|attributes| attributes.get(key).map(String::as_str)) + } + + pub fn attr_mut(&mut self, key: &str) -> Option<&mut String> { + self.attributes_mut() + .and_then(|attributes| attributes.get_mut(key)) + } + + pub fn into_key_and_value(self) -> (String, Option) { + (self.key, self.value) + } + + pub fn set_key(&mut self, key: String) { + self.key = key; + } + + pub fn set_attr(&mut self, key: K, value: V) -> Option + where + K: Into, + V: Into, + { + let attributes = self.attributes.get_or_insert_with(Default::default); + attributes.insert(key.into(), value.into()) + } + + pub fn remove_attr(&mut self, key: &str) -> Option { + self.attributes + .as_mut() + .and_then(|attributes| attributes.swap_remove(key)) + } + + pub fn sort_attrs(&mut self) { + if let Some(ref mut attributes) = self.attributes { + attributes.sort_keys(); + } + } + + pub fn append_child(&mut self, value: Node) { + let children = self.children.get_or_insert_with(Default::default); + children.push(value); + } + + pub fn set_value(&mut self, value: Option) -> Option { + mem::replace(&mut self.value, value) + } + + pub fn has(&self, key: &str) -> bool { + if let Some(ref children) = self.children { + for node in children { + if node.key == key { + return true; + } + } + } + + false + } + + pub fn get_child(&self, key: &str) -> Option<&Node> { + if let Some(ref children) = self.children { + for node in children { + if node.key == key { + return Some(node); + } + } + } + + None + } + + pub fn get_child_mut(&mut self, key: &str) -> Option<&mut Node> { + if let Some(ref mut children) = self.children { + for node in children { + if node.key == key { + return Some(node); + } + } + } + + None + } + + pub fn remove_child(&mut self, key: &str) -> Option { + if let Some(ref mut children) = self.children { + let index = children + .iter() + .enumerate() + .find(|(_, child)| child.key() == key) + .map(|(index, _)| index); + + if let Some(index) = index { + return Some(children.remove(index)); + } + } + + None + } + + pub fn remove_child_at(&mut self, index: usize) -> Option { + self.children + .as_mut() + .map(|children| children.remove(index)) + } + + pub fn pointer<'a>(&'a self, pointer: &[&str]) -> Option<&'a Node> { + if pointer.is_empty() { + return Some(self); + } + let mut target = self; + + for token in pointer { + let children = match target.children { + Some(ref v) => v, + None => return None, + }; + + let target_opt = if let Some(index) = parse_index(token) { + children.get(index) + } else { + children.iter().find(|ref child| child.key() == *token) + }; + + if let Some(t) = target_opt { + target = t; + } else { + return None; + } + } + Some(target) + } + + pub fn pointer_mut<'a>(&'a mut self, pointer: &[&str]) -> Option<&'a mut Node> { + if pointer.is_empty() { + return Some(self); + } + let mut target = self; + + for token in pointer { + let children = match target.children { + Some(ref mut v) => v, + None => return None, + }; + + let target_opt = if let Some(index) = parse_index(token) { + children.get_mut(index) + } else { + children.iter_mut().find(|ref child| child.key() == *token) + }; + + if let Some(t) = target_opt { + target = t; + } else { + return None; + } + } + Some(target) } - Some(target) - } } impl OptionIterator - where T: IntoIterator +where + T: IntoIterator, { - pub fn new(inner: Option) -> Self { - OptionIterator { - inner: inner.map(|inner| inner.into_iter()), + pub fn new(inner: Option) -> Self { + OptionIterator { + inner: inner.map(|inner| inner.into_iter()), + } } - } } impl Iterator for OptionIterator - where T: IntoIterator +where + T: IntoIterator, { - type Item = T::Item; + type Item = T::Item; - fn next(&mut self) -> Option { - match self.inner { - Some(ref mut inner) => inner.next(), - None => None, + fn next(&mut self) -> Option { + match self.inner { + Some(ref mut inner) => inner.next(), + None => None, + } } - } } diff --git a/src/node_types.rs b/src/node_types.rs index 31a6fbe..ecec8a6 100644 --- a/src/node_types.rs +++ b/src/node_types.rs @@ -3,18 +3,18 @@ use std::ops::Deref; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct KbinType { - pub id: u8, - pub konst: &'static str, - pub name: &'static str, - pub alt_name: Option<&'static str>, - pub size: usize, - pub count: usize + pub id: u8, + pub konst: &'static str, + pub name: &'static str, + pub alt_name: Option<&'static str>, + pub size: usize, + pub count: usize, } impl fmt::Display for KbinType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} ({})", self.konst, self.name) - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} ({})", self.konst, self.name) + } } macro_rules! construct_types { diff --git a/src/options.rs b/src/options.rs index 40e3d83..fd697ce 100644 --- a/src/options.rs +++ b/src/options.rs @@ -3,54 +3,51 @@ use crate::encoding_type::EncodingType; #[derive(Clone, Debug, Default)] pub struct Options { - pub(crate) compression: Compression, - pub(crate) encoding: EncodingType, + pub(crate) compression: Compression, + pub(crate) encoding: EncodingType, } #[derive(Default)] pub struct OptionsBuilder { - compression: Compression, - encoding: EncodingType, + compression: Compression, + encoding: EncodingType, } impl Options { - pub fn new( - compression: Compression, - encoding: EncodingType, - ) -> Self { - Self { - compression, - encoding, + pub fn new(compression: Compression, encoding: EncodingType) -> Self { + Self { + compression, + encoding, + } } - } - pub fn builder() -> OptionsBuilder { - OptionsBuilder::default() - } - - pub fn with_encoding(encoding: EncodingType) -> Self { - Self { - encoding, - ..Default::default() + pub fn builder() -> OptionsBuilder { + OptionsBuilder::default() + } + + pub fn with_encoding(encoding: EncodingType) -> Self { + Self { + encoding, + ..Default::default() + } } - } } impl OptionsBuilder { - pub fn compression(&mut self, compression: Compression) -> &mut Self { - self.compression = compression; - self - } - - pub fn encoding(&mut self, encoding: EncodingType) -> &mut Self { - self.encoding = encoding; - self - } - - pub fn build(self) -> Options { - Options { - compression: self.compression, - encoding: self.encoding, + pub fn compression(&mut self, compression: Compression) -> &mut Self { + self.compression = compression; + self + } + + pub fn encoding(&mut self, encoding: EncodingType) -> &mut Self { + self.encoding = encoding; + self + } + + pub fn build(self) -> Options { + Options { + compression: self.compression, + encoding: self.encoding, + } } - } } diff --git a/src/printer.rs b/src/printer.rs index 32136ed..043c62f 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -8,51 +8,57 @@ use crate::reader::Reader; pub struct Printer; impl Printer { - pub fn run(input: &[u8]) -> Result<()> { - let mut reader = Reader::new(Bytes::from(input))?; - let mut nodes = Vec::new(); - let mut definitions = Vec::new(); + pub fn run(input: &[u8]) -> Result<()> { + let mut reader = Reader::new(Bytes::from(input))?; + let mut nodes = Vec::new(); + let mut definitions = Vec::new(); - while let Ok(def) = reader.read_node_definition() { - trace!("definition: {:?}", def); + while let Ok(def) = reader.read_node_definition() { + trace!("definition: {:?}", def); - let node_type = def.node_type; - let key = match def.key() { - Ok(v) => v, - Err(e) => { - error!("error processing key for definition {:?}: {}", def, e); - None - }, - }; - nodes.push((node_type, def.is_array, key)); - definitions.push(def); + let node_type = def.node_type; + let key = match def.key() { + Ok(v) => v, + Err(e) => { + error!("error processing key for definition {:?}: {}", def, e); + None + }, + }; + nodes.push((node_type, def.is_array, key)); + definitions.push(def); - if node_type == StandardType::FileEnd { - break; - } + if node_type == StandardType::FileEnd { + break; + } + } + + let mut indent = 0; + for (node_type, is_array, identifier) in nodes { + eprint!( + "{:indent$} - {:?} (is_array: {}", + "", + node_type, + is_array, + indent = indent + ); + if let Some(identifier) = identifier { + eprint!(", identifier: {}", identifier); + } + eprintln!(")"); + + match node_type { + StandardType::Attribute => {}, + StandardType::NodeEnd => indent -= 2, + _ => indent += 2, + }; + } + + let collection = NodeCollection::from_iter(&mut definitions.into_iter()); + match collection { + Some(ref collection) => eprintln!("collection: {:#}", collection), + None => eprintln!("collection: {:?}", collection), + }; + + Ok(()) } - - let mut indent = 0; - for (node_type, is_array, identifier) in nodes { - eprint!("{:indent$} - {:?} (is_array: {}", "", node_type, is_array, indent = indent); - if let Some(identifier) = identifier { - eprint!(", identifier: {}", identifier); - } - eprintln!(")"); - - match node_type { - StandardType::Attribute => {}, - StandardType::NodeEnd => indent -= 2, - _ => indent += 2, - }; - } - - let collection = NodeCollection::from_iter(&mut definitions.into_iter()); - match collection { - Some(ref collection) => eprintln!("collection: {:#}", collection), - None => eprintln!("collection: {:?}", collection), - }; - - Ok(()) - } } diff --git a/src/reader.rs b/src/reader.rs index 3d57d83..5d433b0 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -1,7 +1,7 @@ use std::io; -use bytes::Bytes; use byteorder::{BigEndian, ReadBytesExt}; +use bytes::Bytes; use snafu::{ResultExt, Snafu}; use crate::byte_buffer::{ByteBufferError, ByteBufferRead}; @@ -16,230 +16,224 @@ use super::{ARRAY_MASK, SIGNATURE}; #[derive(Debug, Snafu)] pub enum ReaderError { - #[snafu(display("Failed to read signature from header"))] - Signature { - source: io::Error, - }, + #[snafu(display("Failed to read signature from header"))] + Signature { source: io::Error }, - #[snafu(display("Failed to read compression type from header"))] - Compression { - source: io::Error, - }, + #[snafu(display("Failed to read compression type from header"))] + Compression { source: io::Error }, - #[snafu(display("Failed to read encoding type from header"))] - Encoding { - source: io::Error, - }, + #[snafu(display("Failed to read encoding type from header"))] + Encoding { source: io::Error }, - #[snafu(display("Failed to read encoding type inverted value from header"))] - EncodingNegate { - source: io::Error, - }, + #[snafu(display("Failed to read encoding type inverted value from header"))] + EncodingNegate { source: io::Error }, - #[snafu(display("Failed to read node buffer length"))] - NodeBufferLength { - source: io::Error, - }, + #[snafu(display("Failed to read node buffer length"))] + NodeBufferLength { source: io::Error }, - #[snafu(display("Failed to read data buffer length"))] - DataBufferLength { - source: io::Error, - }, + #[snafu(display("Failed to read data buffer length"))] + DataBufferLength { source: io::Error }, - #[snafu(display("Reached the end of the node buffer"))] - EndOfNodeBuffer, + #[snafu(display("Reached the end of the node buffer"))] + EndOfNodeBuffer, - #[snafu(display("Failed to read node type"))] - NodeType { - source: io::Error, - }, + #[snafu(display("Failed to read node type"))] + NodeType { source: io::Error }, - #[snafu(display("Failed to read array node length"))] - ArrayLength { - source: io::Error, - }, + #[snafu(display("Failed to read array node length"))] + ArrayLength { source: io::Error }, - #[snafu(display("Failed to read node name length"))] - NameLength { - source: io::Error, - }, + #[snafu(display("Failed to read node name length"))] + NameLength { source: io::Error }, - #[snafu(display("Failed to read {} bytes from data buffer", size))] - DataRead { - size: usize, - source: io::Error, - }, + #[snafu(display("Failed to read {} bytes from data buffer", size))] + DataRead { size: usize, source: io::Error }, } pub struct Reader { - compression: CompressionType, - encoding: EncodingType, + compression: CompressionType, + encoding: EncodingType, - pub(crate) node_buf: ByteBufferRead, - pub(crate) data_buf: ByteBufferRead, + pub(crate) node_buf: ByteBufferRead, + pub(crate) data_buf: ByteBufferRead, - data_buf_start: u64, + data_buf_start: u64, } impl Reader { - pub fn new(input: Bytes) -> Result { - // Node buffer starts from the beginning. - // Data buffer starts later after reading `len_data`. - let mut node_buf = ByteBufferRead::new(input.clone()); + pub fn new(input: Bytes) -> Result { + // Node buffer starts from the beginning. + // Data buffer starts later after reading `len_data`. + let mut node_buf = ByteBufferRead::new(input.clone()); - let signature = node_buf.read_u8().context(Signature)?; - if signature != SIGNATURE { - return Err(KbinError::HeaderValue { field: "signature" }); + let signature = node_buf.read_u8().context(Signature)?; + if signature != SIGNATURE { + return Err(KbinError::HeaderValue { field: "signature" }); + } + + let compress_byte = node_buf.read_u8().context(Compression)?; + let compression = CompressionType::from_byte(compress_byte)?; + + let encoding_byte = node_buf.read_u8().context(Encoding)?; + let encoding_negation = node_buf.read_u8().context(EncodingNegate)?; + let encoding = EncodingType::from_byte(encoding_byte)?; + if encoding_negation != !encoding_byte { + return Err(KbinError::HeaderValue { + field: "encoding negation", + }); + } + + info!( + "signature: 0x{:X}, compression: 0x{:X} ({:?}), encoding: 0x{:X} ({:?})", + signature, compress_byte, compression, encoding_byte, encoding + ); + + let len_node = node_buf.read_u32::().context(NodeBufferLength)?; + info!("len_node: {0} (0x{0:x})", len_node); + + // We have read 8 bytes so far, so offset the start of the data buffer from + // the start of the input data. + let data_buf_start = len_node + 8; + let mut data_buf = ByteBufferRead::new(input.slice_from(data_buf_start as usize)); + + let len_data = data_buf.read_u32::().context(DataBufferLength)?; + info!("len_data: {0} (0x{0:x})", len_data); + + Ok(Self { + compression, + encoding, + + node_buf, + data_buf, + + data_buf_start: data_buf_start as u64, + }) } - let compress_byte = node_buf.read_u8().context(Compression)?; - let compression = CompressionType::from_byte(compress_byte)?; + fn parse_node_type(raw_node_type: u8) -> Result<(StandardType, bool), KbinError> { + let is_array = raw_node_type & ARRAY_MASK == ARRAY_MASK; + let node_type = raw_node_type & !ARRAY_MASK; - let encoding_byte = node_buf.read_u8().context(Encoding)?; - let encoding_negation = node_buf.read_u8().context(EncodingNegate)?; - let encoding = EncodingType::from_byte(encoding_byte)?; - if encoding_negation != !encoding_byte { - return Err(KbinError::HeaderValue { field: "encoding negation" }); + let xml_type = StandardType::from_u8(node_type); + debug!( + "Reader::parse_node_type() => raw_node_type: {}, node_type: {:?} ({}), is_array: {}", + raw_node_type, xml_type, node_type, is_array + ); + + Ok((xml_type, is_array)) } - info!("signature: 0x{:X}, compression: 0x{:X} ({:?}), encoding: 0x{:X} ({:?})", signature, compress_byte, compression, encoding_byte, encoding); - - let len_node = node_buf.read_u32::().context(NodeBufferLength)?; - info!("len_node: {0} (0x{0:x})", len_node); - - // We have read 8 bytes so far, so offset the start of the data buffer from - // the start of the input data. - let data_buf_start = len_node + 8; - let mut data_buf = ByteBufferRead::new(input.slice_from(data_buf_start as usize)); - - let len_data = data_buf.read_u32::().context(DataBufferLength)?; - info!("len_data: {0} (0x{0:x})", len_data); - - Ok(Self { - compression, - encoding, - - node_buf, - data_buf, - - data_buf_start: data_buf_start as u64, - }) - } - - fn parse_node_type(raw_node_type: u8) -> Result<(StandardType, bool), KbinError> { - let is_array = raw_node_type & ARRAY_MASK == ARRAY_MASK; - let node_type = raw_node_type & !ARRAY_MASK; - - let xml_type = StandardType::from_u8(node_type); - debug!("Reader::parse_node_type() => raw_node_type: {}, node_type: {:?} ({}), is_array: {}", - raw_node_type, - xml_type, - node_type, - is_array); - - Ok((xml_type, is_array)) - } - - #[inline] - pub fn encoding(&self) -> EncodingType { - self.encoding - } - - pub fn check_if_node_buffer_end(&self) -> Result<(), ReaderError> { - if self.node_buf.position() >= self.data_buf_start { - Err(ReaderError::EndOfNodeBuffer) - } else { - Ok(()) + #[inline] + pub fn encoding(&self) -> EncodingType { + self.encoding } - } - pub fn read_node_type(&mut self) -> Result<(StandardType, bool), KbinError> { - self.check_if_node_buffer_end()?; + pub fn check_if_node_buffer_end(&self) -> Result<(), ReaderError> { + if self.node_buf.position() >= self.data_buf_start { + Err(ReaderError::EndOfNodeBuffer) + } else { + Ok(()) + } + } - let raw_node_type = self.node_buf.read_u8().context(NodeType)?; - let value = Self::parse_node_type(raw_node_type)?; + pub fn read_node_type(&mut self) -> Result<(StandardType, bool), KbinError> { + self.check_if_node_buffer_end()?; - Ok(value) - } + let raw_node_type = self.node_buf.read_u8().context(NodeType)?; + let value = Self::parse_node_type(raw_node_type)?; - pub fn read_node_data(&mut self, node_type: (StandardType, bool)) -> Result { - let (node_type, is_array) = node_type; - trace!("Reader::read_node_data(node_type: {:?}, is_array: {})", node_type, is_array); + Ok(value) + } - let value = match node_type { - StandardType::Attribute | - StandardType::String => self.data_buf.buf_read()?, - StandardType::Binary => self.read_bytes()?, + pub fn read_node_data(&mut self, node_type: (StandardType, bool)) -> Result { + let (node_type, is_array) = node_type; + trace!( + "Reader::read_node_data(node_type: {:?}, is_array: {})", + node_type, + is_array + ); - StandardType::NodeStart | - StandardType::NodeEnd | - StandardType::FileEnd => Bytes::new(), + let value = match node_type { + StandardType::Attribute | StandardType::String => self.data_buf.buf_read()?, + StandardType::Binary => self.read_bytes()?, - _ if is_array => { - let arr_size = self.data_buf.read_u32::().context(ArrayLength)?; - let data = self.data_buf.get(arr_size)?; - self.data_buf.realign_reads(None)?; + StandardType::NodeStart | StandardType::NodeEnd | StandardType::FileEnd => Bytes::new(), - data - }, - node_type => self.data_buf.get_aligned(*node_type)?, - }; - debug!("Reader::read_node_data(node_type: {:?}, is_array: {}) => value: 0x{:02x?}", node_type, is_array, value); + _ if is_array => { + let arr_size = self.data_buf.read_u32::().context(ArrayLength)?; + let data = self.data_buf.get(arr_size)?; + self.data_buf.realign_reads(None)?; - Ok(value) - } - - pub fn read_node_definition(&mut self) -> Result { - let node_type = self.read_node_type()?; - match node_type.0 { - StandardType::NodeEnd | - StandardType::FileEnd => { - Ok(NodeDefinition::new(self.encoding, node_type)) - } - _ => { - let key = match self.compression { - CompressionType::Compressed => { - let size = Sixbit::size(&mut *self.node_buf)?; - let data = self.node_buf.get(size.real_len as u32)?; - Key::Compressed { size, data } - }, - CompressionType::Uncompressed => { - let encoding = self.encoding; - let length = (self.node_buf.read_u8().context(NameLength)? & !ARRAY_MASK) + 1; - let data = self.node_buf.get(length as u32)?; - Key::Uncompressed { encoding, data } - }, + data + }, + node_type => self.data_buf.get_aligned(*node_type)?, }; - let value_data = self.read_node_data(node_type)?; - let node_data = NodeData::Some { key, value_data }; - Ok(NodeDefinition::with_data(self.encoding, node_type, node_data)) - }, + debug!( + "Reader::read_node_data(node_type: {:?}, is_array: {}) => value: 0x{:02x?}", + node_type, is_array, value + ); + + Ok(value) } - } - pub fn read_u32(&mut self) -> Result { - let value = self.data_buf.read_u32::().context(DataRead { size: 4usize })?; - debug!("Reader::read_u32() => result: {}", value); + pub fn read_node_definition(&mut self) -> Result { + let node_type = self.read_node_type()?; + match node_type.0 { + StandardType::NodeEnd | StandardType::FileEnd => { + Ok(NodeDefinition::new(self.encoding, node_type)) + }, + _ => { + let key = match self.compression { + CompressionType::Compressed => { + let size = Sixbit::size(&mut *self.node_buf)?; + let data = self.node_buf.get(size.real_len as u32)?; + Key::Compressed { size, data } + }, + CompressionType::Uncompressed => { + let encoding = self.encoding; + let length = + (self.node_buf.read_u8().context(NameLength)? & !ARRAY_MASK) + 1; + let data = self.node_buf.get(length as u32)?; + Key::Uncompressed { encoding, data } + }, + }; + let value_data = self.read_node_data(node_type)?; + let node_data = NodeData::Some { key, value_data }; + Ok(NodeDefinition::with_data( + self.encoding, + node_type, + node_data, + )) + }, + } + } - Ok(value) - } + pub fn read_u32(&mut self) -> Result { + let value = self + .data_buf + .read_u32::() + .context(DataRead { size: 4usize })?; + debug!("Reader::read_u32() => result: {}", value); - #[inline] - pub fn read_bytes(&mut self) -> Result { - self.data_buf.buf_read() - } + Ok(value) + } + + #[inline] + pub fn read_bytes(&mut self) -> Result { + self.data_buf.buf_read() + } } impl Iterator for Reader { - type Item = NodeDefinition; + type Item = NodeDefinition; - fn next(&mut self) -> Option { - match self.read_node_definition() { - Ok(v) => Some(v), - Err(e) => { - error!("Error reading node definition in `next()`: {}", e); - None - }, + fn next(&mut self) -> Option { + match self.read_node_definition() { + Ok(v) => Some(v), + Err(e) => { + error!("Error reading node definition in `next()`: {}", e); + None + }, + } } - } } diff --git a/src/sixbit.rs b/src/sixbit.rs index 4d9ceff..a2a1870 100644 --- a/src/sixbit.rs +++ b/src/sixbit.rs @@ -4,165 +4,174 @@ use std::io::{self, Read, Write}; use byteorder::{ReadBytesExt, WriteBytesExt}; use snafu::{ResultExt, Snafu}; -static CHAR_MAP: &'static [u8] = b"0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; +static CHAR_MAP: &'static [u8] = + b"0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; lazy_static! { - static ref BYTE_MAP: HashMap = { - CHAR_MAP - .iter() - .enumerate() - .map(|(i, value)| { - (*value, i as u8) - }) - .collect() - }; + static ref BYTE_MAP: HashMap = { + CHAR_MAP + .iter() + .enumerate() + .map(|(i, value)| (*value, i as u8)) + .collect() + }; } #[derive(Debug, Snafu)] pub enum SixbitError { - #[snafu(display("Failed to read sixbit string length"))] - LengthRead { - source: io::Error, - }, + #[snafu(display("Failed to read sixbit string length"))] + LengthRead { source: io::Error }, - #[snafu(display("Failed to write sixbit string length"))] - LengthWrite { - source: io::Error, - }, + #[snafu(display("Failed to write sixbit string length"))] + LengthWrite { source: io::Error }, - #[snafu(display("Failed to read sixbit string data (expected: {} bytes, got: {} bytes)", expected, actual))] - DataRead { - expected: usize, - actual: usize, - }, + #[snafu(display( + "Failed to read sixbit string data (expected: {} bytes, got: {} bytes)", + expected, + actual + ))] + DataRead { expected: usize, actual: usize }, - #[snafu(display("Failed to write sixbit string data"))] - DataWrite { - source: io::Error, - }, + #[snafu(display("Failed to write sixbit string data"))] + DataWrite { source: io::Error }, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct SixbitSize { - pub sixbit_len: u8, - pub real_len: usize, + pub sixbit_len: u8, + pub real_len: usize, } pub struct Sixbit; impl Sixbit { - pub fn size(reader: &mut T) -> Result - where T: Read, - { - let sixbit_len = reader.read_u8().context(LengthRead)?; - let real_len = (f32::from(sixbit_len * 6) / 8f32).ceil(); - let real_len = (real_len as u32) as usize; - debug!("sixbit_len: {}, real_len: {}", sixbit_len, real_len); + pub fn size(reader: &mut T) -> Result + where + T: Read, + { + let sixbit_len = reader.read_u8().context(LengthRead)?; + let real_len = (f32::from(sixbit_len * 6) / 8f32).ceil(); + let real_len = (real_len as u32) as usize; + debug!("sixbit_len: {}, real_len: {}", sixbit_len, real_len); - Ok(SixbitSize { sixbit_len, real_len }) - } - - pub fn pack(writer: &mut T, input: &str) -> Result<(), SixbitError> - where T: Write, - { - let sixbit_chars = input - .bytes() - .map(|ch| { - *BYTE_MAP.get(&ch).expect("Character must be a valid sixbit character") - }); - - let len = input.len(); - let real_len = (f64::from(len as u32 * 6) / 8f64).ceil() as usize; - debug!("sixbit_len: {}, real_len: {}", len, real_len); - - let mut i = 0; - let mut bytes = vec![0; real_len]; - for ch in sixbit_chars { - for _ in 0..6 { - // Some crazy math that works on a single bit at a time, but - // it still performs better than a `BigUint` calculation - bytes[i / 8] |= (ch >> (5 - (i % 6)) & 1) << (7 - (i % 8)); - i += 1; - } + Ok(SixbitSize { + sixbit_len, + real_len, + }) } - writer.write_u8(len as u8).context(LengthWrite)?; - writer.write_all(&bytes).context(DataWrite)?; + pub fn pack(writer: &mut T, input: &str) -> Result<(), SixbitError> + where + T: Write, + { + let sixbit_chars = input.bytes().map(|ch| { + *BYTE_MAP + .get(&ch) + .expect("Character must be a valid sixbit character") + }); - Ok(()) - } + let len = input.len(); + let real_len = (f64::from(len as u32 * 6) / 8f64).ceil() as usize; + debug!("sixbit_len: {}, real_len: {}", len, real_len); - pub fn unpack(buf: &[u8], size: SixbitSize) -> Result { - let SixbitSize { sixbit_len, real_len } = size; + let mut i = 0; + let mut bytes = vec![0; real_len]; + for ch in sixbit_chars { + for _ in 0..6 { + // Some crazy math that works on a single bit at a time, but + // it still performs better than a `BigUint` calculation + bytes[i / 8] |= (ch >> (5 - (i % 6)) & 1) << (7 - (i % 8)); + i += 1; + } + } - if buf.len() < real_len { - return Err(SixbitError::DataRead { expected: real_len, actual: buf.len() }); + writer.write_u8(len as u8).context(LengthWrite)?; + writer.write_all(&bytes).context(DataWrite)?; + + Ok(()) } - let sixbit_len = sixbit_len as usize; - let mut result = String::with_capacity(sixbit_len); - for i in 0..sixbit_len { - let mut current = 0u8; - for j in 0..6 { - let k = (i * 6) + j; - current |= (buf[k / 8] >> (7 - (k % 8)) & 1) << (5 - (k % 6)); - } - result.push(CHAR_MAP[current as usize] as char); - } + pub fn unpack(buf: &[u8], size: SixbitSize) -> Result { + let SixbitSize { + sixbit_len, + real_len, + } = size; - Ok(result) - } + if buf.len() < real_len { + return Err(SixbitError::DataRead { + expected: real_len, + actual: buf.len(), + }); + } + + let sixbit_len = sixbit_len as usize; + let mut result = String::with_capacity(sixbit_len); + for i in 0..sixbit_len { + let mut current = 0u8; + for j in 0..6 { + let k = (i * 6) + j; + current |= (buf[k / 8] >> (7 - (k % 8)) & 1) << (5 - (k % 6)); + } + result.push(CHAR_MAP[current as usize] as char); + } + + Ok(result) + } } #[cfg(test)] mod tests { - extern crate test; + extern crate test; - use std::io::{Cursor, Seek, SeekFrom}; + use std::io::{Cursor, Seek, SeekFrom}; - use test::{Bencher, black_box}; + use test::{black_box, Bencher}; - use super::Sixbit; + use super::Sixbit; - const TEST1_STR: &str = "hello"; - const TEST1_BYTES: &[u8] = &[5,182,172,113,208]; + const TEST1_STR: &str = "hello"; + const TEST1_BYTES: &[u8] = &[5, 182, 172, 113, 208]; - #[test] - fn test_pack() { - let mut data: Cursor> = Cursor::new(Vec::new()); - Sixbit::pack(&mut data, TEST1_STR).expect("Failed to pack sixbit"); - assert_eq!(data.into_inner(), TEST1_BYTES); - } + #[test] + fn test_pack() { + let mut data: Cursor> = Cursor::new(Vec::new()); + Sixbit::pack(&mut data, TEST1_STR).expect("Failed to pack sixbit"); + assert_eq!(data.into_inner(), TEST1_BYTES); + } - #[test] - fn test_unpack() { - let size = Sixbit::size(&mut Cursor::new(TEST1_BYTES)).expect("Failed to get size of sixbit string"); - let result = Sixbit::unpack(&TEST1_BYTES[1..], size).expect("Failed to unpack sixbit string"); - assert_eq!(result, TEST1_STR); - } + #[test] + fn test_unpack() { + let size = Sixbit::size(&mut Cursor::new(TEST1_BYTES)) + .expect("Failed to get size of sixbit string"); + let result = + Sixbit::unpack(&TEST1_BYTES[1..], size).expect("Failed to unpack sixbit string"); + assert_eq!(result, TEST1_STR); + } - #[bench] - fn bench_pack(b: &mut Bencher) { - let mut data: Cursor> = Cursor::new(Vec::with_capacity(10)); + #[bench] + fn bench_pack(b: &mut Bencher) { + let mut data: Cursor> = Cursor::new(Vec::with_capacity(10)); - b.iter(|| { - for _ in 0..100 { - data.seek(SeekFrom::Start(0)).unwrap(); - black_box(Sixbit::pack(&mut data, TEST1_STR).unwrap()); - } - }); + b.iter(|| { + for _ in 0..100 { + data.seek(SeekFrom::Start(0)).unwrap(); + black_box(Sixbit::pack(&mut data, TEST1_STR).unwrap()); + } + }); - assert_eq!(data.into_inner(), TEST1_BYTES); - } + assert_eq!(data.into_inner(), TEST1_BYTES); + } - #[bench] - fn bench_unpack(b: &mut Bencher) { - b.iter(|| { - for _ in 0..100 { - let size = Sixbit::size(&mut Cursor::new(TEST1_BYTES)).expect("Failed to get size of sixbit string"); - let result = Sixbit::unpack(&TEST1_BYTES[1..], size).expect("Failed to unpack sixbit string"); - black_box(result); - } - }); - } + #[bench] + fn bench_unpack(b: &mut Bencher) { + b.iter(|| { + for _ in 0..100 { + let size = Sixbit::size(&mut Cursor::new(TEST1_BYTES)) + .expect("Failed to get size of sixbit string"); + let result = Sixbit::unpack(&TEST1_BYTES[1..], size) + .expect("Failed to unpack sixbit string"); + black_box(result); + } + }); + } } diff --git a/src/text_reader.rs b/src/text_reader.rs index 081d062..138c427 100644 --- a/src/text_reader.rs +++ b/src/text_reader.rs @@ -1,237 +1,257 @@ use std::str; use bytes::{BufMut, Bytes, BytesMut}; -use quick_xml::Reader; -use quick_xml::events::{BytesStart, BytesText, Event}; use quick_xml::events::attributes::Attributes; +use quick_xml::events::{BytesStart, BytesText, Event}; +use quick_xml::Reader; use snafu::ResultExt; use crate::encoding_type::EncodingType; use crate::error::*; -use crate::node::{Key, NodeData, NodeCollection, NodeDefinition}; +use crate::node::{Key, NodeCollection, NodeData, NodeDefinition}; use crate::node_types::StandardType; use crate::value::Value; const EMPTY_STRING_DATA: &[u8] = &[0]; pub struct TextXmlReader<'a> { - xml_reader: Reader<&'a [u8]>, - encoding: EncodingType, + xml_reader: Reader<&'a [u8]>, + encoding: EncodingType, - stack: Vec<(NodeCollection, usize, Option)>, + stack: Vec<(NodeCollection, usize, Option)>, } impl<'a> TextXmlReader<'a> { - pub fn new(input: &'a [u8]) -> Self { - let mut xml_reader = Reader::from_reader(input); - xml_reader.trim_text(true); + pub fn new(input: &'a [u8]) -> Self { + let mut xml_reader = Reader::from_reader(input); + xml_reader.trim_text(true); - Self { - xml_reader, - encoding: EncodingType::UTF_8, + Self { + xml_reader, + encoding: EncodingType::UTF_8, - // Most kbinxml files that I have come across do not have too - // many inner layers. - stack: Vec::with_capacity(6), - } - } - - #[inline] - pub fn encoding(&self) -> EncodingType { - self.encoding - } - - fn parse_attribute(&self, key: &[u8], value: &[u8]) -> Result { - let mut value = BytesMut::from(value.to_vec()); - - // Add the trailing null byte that kbin has at the end of strings - value.reserve(1); - value.put_u8(0); - - // `Attribute` nodes do not have the `is_array` flag set - let node_type = (StandardType::Attribute, false); - let data = NodeData::Some { - key: Key::Uncompressed { - encoding: self.encoding, - data: Bytes::from(key), - }, - value_data: value.freeze(), - }; - - Ok(NodeDefinition::with_data(self.encoding, node_type, data)) - } - - fn parse_attributes(&self, attrs: Attributes<'a>) -> Result<(StandardType, usize, Option, Vec)> { - let mut node_type = None; - let mut count = 0; - let mut size = None; - let mut attributes = Vec::new(); - - for attr in attrs { - match attr { - Ok(attr) => { - let value = match attr.unescaped_value() { - Ok(v) => v, - Err(e) => { - error!("Error decoding attribute value: {:?}", e); - attr.value.clone() - }, - }; - - if attr.key == b"__type" { - let value = str::from_utf8(&*value)?; - - node_type = Some(StandardType::from_name(value)); - } else if attr.key == b"__count" { - let value = str::from_utf8(&*value)?; - let num_count = value.parse::().context(StringParseInt { node_type: "array count" })?; - - count = num_count as usize; - } else if attr.key == b"__size" { - let value = str::from_utf8(&*value)? - .parse::() - .context(StringParseInt { node_type: "binary size" })?; - - size = Some(value); - } else { - let definition = self.parse_attribute(attr.key, &value)?; - attributes.push(definition); - } - }, - Err(e) => { - error!("Error reading attribute: {:?}", e); - }, - } + // Most kbinxml files that I have come across do not have too + // many inner layers. + stack: Vec::with_capacity(6), + } } - let node_type = match node_type { - Some(node_type) => node_type, - None => { - // Default to `NodeStart`, set to `String` if there is a `Event::Text` event before - // the `Event::End` event. - StandardType::NodeStart - }, - }; + #[inline] + pub fn encoding(&self) -> EncodingType { + self.encoding + } - Ok((node_type, count, size, attributes)) - } - - fn handle_start(&self, e: BytesStart) -> Result<(NodeCollection, usize, Option)> { - let (node_type, count, size, attributes) = self.parse_attributes(e.attributes())?; - - // Stub the value for now, handle with `Event::Text`. - let value_data = match node_type { - StandardType::String => Bytes::from(EMPTY_STRING_DATA), - _ => Bytes::new(), - }; - - let node_type = (node_type, count > 0); - let data = NodeData::Some { - key: Key::Uncompressed { - encoding: self.encoding, - data: Bytes::from(e.name()), - }, - value_data, - }; - - let base = NodeDefinition::with_data(self.encoding, node_type, data); - let collection = NodeCollection::with_attributes(base, attributes.into()); - - Ok((collection, count, size)) - } - - fn handle_text(event: BytesText, definition: &mut NodeDefinition, count: usize, size: Option) -> Result<()> { - let data = event.unescaped()?; - let data = match definition.node_type { - StandardType::String | - StandardType::NodeStart => { - let mut data = BytesMut::from(data.into_owned()); + fn parse_attribute(&self, key: &[u8], value: &[u8]) -> Result { + let mut value = BytesMut::from(value.to_vec()); // Add the trailing null byte that kbin has at the end of strings - data.reserve(1); - data.put_u8(0); + value.reserve(1); + value.put_u8(0); - data.freeze() - }, - _ => { - let text = str::from_utf8(&*data)?; - let value = Value::from_string(definition.node_type, text, definition.is_array, count)?; + // `Attribute` nodes do not have the `is_array` flag set + let node_type = (StandardType::Attribute, false); + let data = NodeData::Some { + key: Key::Uncompressed { + encoding: self.encoding, + data: Bytes::from(key), + }, + value_data: value.freeze(), + }; - if let Value::Binary(data) = &value { - // The read number of bytes must match the size attribute, if set - if let Some(size) = size { - if data.len() != size { - return Err(KbinError::InvalidState.into()); + Ok(NodeDefinition::with_data(self.encoding, node_type, data)) + } + + fn parse_attributes( + &self, + attrs: Attributes<'a>, + ) -> Result<(StandardType, usize, Option, Vec)> { + let mut node_type = None; + let mut count = 0; + let mut size = None; + let mut attributes = Vec::new(); + + for attr in attrs { + match attr { + Ok(attr) => { + let value = match attr.unescaped_value() { + Ok(v) => v, + Err(e) => { + error!("Error decoding attribute value: {:?}", e); + attr.value.clone() + }, + }; + + if attr.key == b"__type" { + let value = str::from_utf8(&*value)?; + + node_type = Some(StandardType::from_name(value)); + } else if attr.key == b"__count" { + let value = str::from_utf8(&*value)?; + let num_count = value.parse::().context(StringParseInt { + node_type: "array count", + })?; + + count = num_count as usize; + } else if attr.key == b"__size" { + let value = + str::from_utf8(&*value)? + .parse::() + .context(StringParseInt { + node_type: "binary size", + })?; + + size = Some(value); + } else { + let definition = self.parse_attribute(attr.key, &value)?; + attributes.push(definition); + } + }, + Err(e) => { + error!("Error reading attribute: {:?}", e); + }, } - } } - Bytes::from(value.to_bytes()?) - }, - }; + let node_type = match node_type { + Some(node_type) => node_type, + None => { + // Default to `NodeStart`, set to `String` if there is a `Event::Text` event before + // the `Event::End` event. + StandardType::NodeStart + }, + }; - if definition.node_type == StandardType::NodeStart { - definition.node_type = StandardType::String; + Ok((node_type, count, size, attributes)) } - if let NodeData::Some { ref mut value_data, .. } = definition.data_mut() { - *value_data = data; - } else { - // There should be a valid `NodeData` structure from the `Event::Start` handler - return Err(KbinError::InvalidState.into()); + fn handle_start(&self, e: BytesStart) -> Result<(NodeCollection, usize, Option)> { + let (node_type, count, size, attributes) = self.parse_attributes(e.attributes())?; + + // Stub the value for now, handle with `Event::Text`. + let value_data = match node_type { + StandardType::String => Bytes::from(EMPTY_STRING_DATA), + _ => Bytes::new(), + }; + + let node_type = (node_type, count > 0); + let data = NodeData::Some { + key: Key::Uncompressed { + encoding: self.encoding, + data: Bytes::from(e.name()), + }, + value_data, + }; + + let base = NodeDefinition::with_data(self.encoding, node_type, data); + let collection = NodeCollection::with_attributes(base, attributes.into()); + + Ok((collection, count, size)) } - Ok(()) - } + fn handle_text( + event: BytesText, + definition: &mut NodeDefinition, + count: usize, + size: Option, + ) -> Result<()> { + let data = event.unescaped()?; + let data = match definition.node_type { + StandardType::String | StandardType::NodeStart => { + let mut data = BytesMut::from(data.into_owned()); - pub fn as_node_collection(&mut self) -> Result> { - // A buffer size for reading a `quick_xml::events::Event` that I pulled - // out of my head. - let mut buf = Vec::with_capacity(1024); + // Add the trailing null byte that kbin has at the end of strings + data.reserve(1); + data.put_u8(0); - loop { - match self.xml_reader.read_event(&mut buf)? { - Event::Start(e) => { - let start = self.handle_start(e)?; - self.stack.push(start); - }, - Event::Text(e) => { - if let Some((ref mut collection, ref count, ref size)) = self.stack.last_mut() { - let base = collection.base_mut(); - Self::handle_text(e, base, *count, *size)?; - } - }, - Event::End(_) => { - if let Some((collection, _count, _size)) = self.stack.pop() { - if let Some((parent_collection, _count, _size)) = self.stack.last_mut() { - parent_collection.children_mut().push_back(collection); - } else { - // The end of the structure has been reached. - return Ok(Some(collection)); - } - } - }, - Event::Empty(e) => { - let (collection, count, size) = self.handle_start(e)?; - assert!(count == 0, "empty node should not signal an array"); - assert!(size.is_none() || size == Some(0), "empty node should not signal binary data"); + data.freeze() + }, + _ => { + let text = str::from_utf8(&*data)?; + let value = + Value::from_string(definition.node_type, text, definition.is_array, count)?; - if let Some((ref mut parent_collection, _count, _size)) = self.stack.last_mut() { - parent_collection.children_mut().push_back(collection); - } - }, - Event::Decl(e) => { - if let Some(encoding) = e.encoding() { - self.encoding = EncodingType::from_label(&encoding?)?; - } - }, - Event::Eof => break, - _ => {}, - }; + if let Value::Binary(data) = &value { + // The read number of bytes must match the size attribute, if set + if let Some(size) = size { + if data.len() != size { + return Err(KbinError::InvalidState.into()); + } + } + } - buf.clear(); + Bytes::from(value.to_bytes()?) + }, + }; + + if definition.node_type == StandardType::NodeStart { + definition.node_type = StandardType::String; + } + + if let NodeData::Some { + ref mut value_data, .. + } = definition.data_mut() + { + *value_data = data; + } else { + // There should be a valid `NodeData` structure from the `Event::Start` handler + return Err(KbinError::InvalidState.into()); + } + + Ok(()) } - Ok(None) - } + pub fn as_node_collection(&mut self) -> Result> { + // A buffer size for reading a `quick_xml::events::Event` that I pulled + // out of my head. + let mut buf = Vec::with_capacity(1024); + + loop { + match self.xml_reader.read_event(&mut buf)? { + Event::Start(e) => { + let start = self.handle_start(e)?; + self.stack.push(start); + }, + Event::Text(e) => { + if let Some((ref mut collection, ref count, ref size)) = self.stack.last_mut() { + let base = collection.base_mut(); + Self::handle_text(e, base, *count, *size)?; + } + }, + Event::End(_) => { + if let Some((collection, _count, _size)) = self.stack.pop() { + if let Some((parent_collection, _count, _size)) = self.stack.last_mut() { + parent_collection.children_mut().push_back(collection); + } else { + // The end of the structure has been reached. + return Ok(Some(collection)); + } + } + }, + Event::Empty(e) => { + let (collection, count, size) = self.handle_start(e)?; + assert!(count == 0, "empty node should not signal an array"); + assert!( + size.is_none() || size == Some(0), + "empty node should not signal binary data" + ); + + if let Some((ref mut parent_collection, _count, _size)) = self.stack.last_mut() + { + parent_collection.children_mut().push_back(collection); + } + }, + Event::Decl(e) => { + if let Some(encoding) = e.encoding() { + self.encoding = EncodingType::from_label(&encoding?)?; + } + }, + Event::Eof => break, + _ => {}, + }; + + buf.clear(); + } + + Ok(None) + } } diff --git a/src/to_text_xml/mod.rs b/src/to_text_xml/mod.rs index f1a23b9..e069495 100644 --- a/src/to_text_xml/mod.rs +++ b/src/to_text_xml/mod.rs @@ -1,7 +1,7 @@ use std::io::{Cursor, Write}; -use quick_xml::Writer; use quick_xml::events::{BytesDecl, Event}; +use quick_xml::Writer; use crate::encoding_type::EncodingType; use crate::error::KbinError; @@ -10,35 +10,34 @@ mod node; mod node_collection; pub trait ToTextXml { - fn encoding(&self) -> EncodingType; - fn write(&self, writer: &mut Writer) -> Result<(), KbinError>; + fn encoding(&self) -> EncodingType; + fn write(&self, writer: &mut Writer) -> Result<(), KbinError>; } pub struct TextXmlWriter { - xml_writer: Writer>>, + xml_writer: Writer>>, } impl TextXmlWriter { - pub fn new() -> Self { - let inner = Cursor::new(Vec::new()); - let xml_writer = Writer::new_with_indent(inner, b' ', 2); + pub fn new() -> Self { + let inner = Cursor::new(Vec::new()); + let xml_writer = Writer::new_with_indent(inner, b' ', 2); - Self { - xml_writer, - } - } - - pub fn to_text_xml(mut self, value: &T) -> Result, KbinError> - where T: ToTextXml - { - if let Some(encoding) = value.encoding().name() { - let header = BytesDecl::new(b"1.0", Some(encoding.as_bytes()), None); - - self.xml_writer.write_event(Event::Decl(header))?; + Self { xml_writer } } - value.write(&mut self.xml_writer)?; + pub fn to_text_xml(mut self, value: &T) -> Result, KbinError> + where + T: ToTextXml, + { + if let Some(encoding) = value.encoding().name() { + let header = BytesDecl::new(b"1.0", Some(encoding.as_bytes()), None); - Ok(self.xml_writer.into_inner().into_inner()) - } + self.xml_writer.write_event(Event::Decl(header))?; + } + + value.write(&mut self.xml_writer)?; + + Ok(self.xml_writer.into_inner().into_inner()) + } } diff --git a/src/to_text_xml/node.rs b/src/to_text_xml/node.rs index 8e190f8..5c6042c 100644 --- a/src/to_text_xml/node.rs +++ b/src/to_text_xml/node.rs @@ -1,9 +1,9 @@ use std::borrow::Cow; use std::io::Write; -use quick_xml::Writer; -use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::events::attributes::Attribute; +use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; +use quick_xml::Writer; use crate::encoding_type::EncodingType; use crate::error::KbinError; @@ -13,94 +13,94 @@ use crate::to_text_xml::ToTextXml; use crate::value::Value; impl ToTextXml for Node { - /// At the moment, a `Node` will always contain UTF-8 data. - fn encoding(&self) -> EncodingType { - EncodingType::UTF_8 - } - - fn write(&self, writer: &mut Writer) -> Result<(), KbinError> { - let key = self.key(); - let mut elem = BytesStart::borrowed(key.as_bytes(), key.as_bytes().len()); - - // Write the attributes for the value, but not the value contents. - if let Some(value) = self.value() { - let node_type = value.standard_type(); - - match value { - Value::Binary(ref data) => { - elem.push_attribute(Attribute { - key: b"__size", - value: Cow::Owned(data.len().to_string().into_bytes()), - }); - }, - Value::Array(ref values) => { - elem.push_attribute(Attribute { - key: b"__count", - value: Cow::Owned(values.len().to_string().into_bytes()), - }); - }, - _ => {}, - }; - - // Only add a `__type` attribute if this is not a `NodeStart` node - if node_type != StandardType::NodeStart { - elem.push_attribute(Attribute { - key: b"__type", - value: Cow::Borrowed(node_type.name.as_bytes()), - }); - } + /// At the moment, a `Node` will always contain UTF-8 data. + fn encoding(&self) -> EncodingType { + EncodingType::UTF_8 } - if let Some(attributes) = self.attributes() { - for (key, value) in attributes { - let value = BytesText::from_plain_str(&value); + fn write(&self, writer: &mut Writer) -> Result<(), KbinError> { + let key = self.key(); + let mut elem = BytesStart::borrowed(key.as_bytes(), key.as_bytes().len()); - elem.push_attribute(Attribute { - key: key.as_bytes(), - value: Cow::Borrowed(value.escaped()), - }); - } + // Write the attributes for the value, but not the value contents. + if let Some(value) = self.value() { + let node_type = value.standard_type(); + + match value { + Value::Binary(ref data) => { + elem.push_attribute(Attribute { + key: b"__size", + value: Cow::Owned(data.len().to_string().into_bytes()), + }); + }, + Value::Array(ref values) => { + elem.push_attribute(Attribute { + key: b"__count", + value: Cow::Owned(values.len().to_string().into_bytes()), + }); + }, + _ => {}, + }; + + // Only add a `__type` attribute if this is not a `NodeStart` node + if node_type != StandardType::NodeStart { + elem.push_attribute(Attribute { + key: b"__type", + value: Cow::Borrowed(node_type.name.as_bytes()), + }); + } + } + + if let Some(attributes) = self.attributes() { + for (key, value) in attributes { + let value = BytesText::from_plain_str(&value); + + elem.push_attribute(Attribute { + key: key.as_bytes(), + value: Cow::Borrowed(value.escaped()), + }); + } + } + + // Now write the value contents. + let start_elem = if let Some(value) = self.value() { + writer.write_event(Event::Start(elem))?; + + let value = value.to_string(); + let elem = BytesText::from_plain_str(&value); + writer.write_event(Event::Text(elem))?; + + None + } else { + Some(elem) + }; + + let has_value = start_elem.is_none(); + let has_children = match self.children() { + Some(children) => !children.is_empty(), + None => false, + }; + + // A `Some` value here means the start element was not written + if let Some(start_elem) = start_elem { + if !has_children { + writer.write_event(Event::Empty(start_elem))?; + } else { + writer.write_event(Event::Start(start_elem))?; + } + } + + if let Some(children) = self.children() { + for child in children { + child.write(writer)?; + } + } + + if has_value || has_children { + let end_elem = BytesEnd::borrowed(key.as_bytes()); + writer.write_event(Event::End(end_elem))?; + } + + Ok(()) } - - // Now write the value contents. - let start_elem = if let Some(value) = self.value() { - writer.write_event(Event::Start(elem))?; - - let value = value.to_string(); - let elem = BytesText::from_plain_str(&value); - writer.write_event(Event::Text(elem))?; - - None - } else { - Some(elem) - }; - - let has_value = start_elem.is_none(); - let has_children = match self.children() { - Some(children) => !children.is_empty(), - None => false, - }; - - // A `Some` value here means the start element was not written - if let Some(start_elem) = start_elem { - if !has_children { - writer.write_event(Event::Empty(start_elem))?; - } else { - writer.write_event(Event::Start(start_elem))?; - } - } - - if let Some(children) = self.children() { - for child in children { - child.write(writer)?; - } - } - - if has_value || has_children { - let end_elem = BytesEnd::borrowed(key.as_bytes()); - writer.write_event(Event::End(end_elem))?; - } - - Ok(()) - } } diff --git a/src/to_text_xml/node_collection.rs b/src/to_text_xml/node_collection.rs index bcdbb97..a9f7ca6 100644 --- a/src/to_text_xml/node_collection.rs +++ b/src/to_text_xml/node_collection.rs @@ -1,9 +1,9 @@ use std::borrow::Cow; use std::io::Write; -use quick_xml::Writer; -use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::events::attributes::Attribute; +use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; +use quick_xml::Writer; use crate::encoding_type::EncodingType; use crate::error::KbinError; @@ -12,96 +12,99 @@ use crate::node_types::StandardType; use crate::to_text_xml::ToTextXml; impl ToTextXml for NodeCollection { - /// At the moment, decoding the value of a `NodeDefinition` will decode - /// strings into UTF-8. - fn encoding(&self) -> EncodingType { - EncodingType::UTF_8 - } - - fn write(&self, writer: &mut Writer) -> Result<(), KbinError> { - let base = self.base(); - let key = base.key()?.ok_or(KbinError::InvalidState)?; - let value = match base.value() { - Ok(value) => Some(value), - Err(e) => match e { - KbinError::InvalidNodeType { .. } => None, - _ => return Err(e), - }, - }; - - let mut elem = BytesStart::borrowed(key.as_bytes(), key.as_bytes().len()); - - if base.is_array { - let values = value.as_ref().ok_or(KbinError::InvalidState)?.as_array()?; - - elem.push_attribute(Attribute { - key: b"__count", - value: Cow::Owned(values.len().to_string().into_bytes()), - }); + /// At the moment, decoding the value of a `NodeDefinition` will decode + /// strings into UTF-8. + fn encoding(&self) -> EncodingType { + EncodingType::UTF_8 } - if base.node_type == StandardType::Binary { - let value = value.as_ref().ok_or(KbinError::InvalidState)?.as_slice()?; + fn write(&self, writer: &mut Writer) -> Result<(), KbinError> { + let base = self.base(); + let key = base.key()?.ok_or(KbinError::InvalidState)?; + let value = match base.value() { + Ok(value) => Some(value), + Err(e) => match e { + KbinError::InvalidNodeType { .. } => None, + _ => return Err(e), + }, + }; - elem.push_attribute(Attribute { - key: b"__size", - value: Cow::Owned(value.len().to_string().into_bytes()), - }); + let mut elem = BytesStart::borrowed(key.as_bytes(), key.as_bytes().len()); + + if base.is_array { + let values = value.as_ref().ok_or(KbinError::InvalidState)?.as_array()?; + + elem.push_attribute(Attribute { + key: b"__count", + value: Cow::Owned(values.len().to_string().into_bytes()), + }); + } + + if base.node_type == StandardType::Binary { + let value = value.as_ref().ok_or(KbinError::InvalidState)?.as_slice()?; + + elem.push_attribute(Attribute { + key: b"__size", + value: Cow::Owned(value.len().to_string().into_bytes()), + }); + } + + // Only add a `__type` attribute if this is not a `NodeStart` node + if base.node_type != StandardType::NodeStart { + elem.push_attribute(Attribute { + key: b"__type", + value: Cow::Borrowed(base.node_type.name.as_bytes()), + }); + } + + for attribute in self.attributes() { + let key = attribute + .key()? + .ok_or(KbinError::InvalidState)? + .into_bytes(); + let value = attribute.value()?.to_string(); + let value = BytesText::from_plain_str(&value); + + elem.push_attribute(Attribute { + key: &key, + value: Cow::Borrowed(value.escaped()), + }); + } + + let start_elem = match value { + Some(value) => { + writer.write_event(Event::Start(elem))?; + + let value = value.to_string(); + let elem = BytesText::from_plain_str(&value); + writer.write_event(Event::Text(elem))?; + + None + }, + None => Some(elem), + }; + + let has_value = start_elem.is_none(); + let has_children = !self.children().is_empty(); + + // A `Some` value here means the start element was not written + if let Some(start_elem) = start_elem { + if !has_children { + writer.write_event(Event::Empty(start_elem))?; + } else { + writer.write_event(Event::Start(start_elem))?; + } + } + + for child in self.children() { + child.write(writer)?; + } + + if has_value || has_children { + let end_elem = BytesEnd::borrowed(key.as_bytes()); + writer.write_event(Event::End(end_elem))?; + } + + Ok(()) } - - // Only add a `__type` attribute if this is not a `NodeStart` node - if base.node_type != StandardType::NodeStart { - elem.push_attribute(Attribute { - key: b"__type", - value: Cow::Borrowed(base.node_type.name.as_bytes()), - }); - } - - for attribute in self.attributes() { - let key = attribute.key()?.ok_or(KbinError::InvalidState)?.into_bytes(); - let value = attribute.value()?.to_string(); - let value = BytesText::from_plain_str(&value); - - elem.push_attribute(Attribute { - key: &key, - value: Cow::Borrowed(value.escaped()), - }); - } - - let start_elem = match value { - Some(value) => { - writer.write_event(Event::Start(elem))?; - - let value = value.to_string(); - let elem = BytesText::from_plain_str(&value); - writer.write_event(Event::Text(elem))?; - - None - }, - None => Some(elem), - }; - - let has_value = start_elem.is_none(); - let has_children = !self.children().is_empty(); - - // A `Some` value here means the start element was not written - if let Some(start_elem) = start_elem { - if !has_children { - writer.write_event(Event::Empty(start_elem))?; - } else { - writer.write_event(Event::Start(start_elem))?; - } - } - - for child in self.children() { - child.write(writer)?; - } - - if has_value || has_children { - let end_elem = BytesEnd::borrowed(key.as_bytes()); - writer.write_event(Event::End(end_elem))?; - } - - Ok(()) - } } diff --git a/src/types/bytes.rs b/src/types/bytes.rs index c1d8add..c87dd69 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -8,74 +8,74 @@ use snafu::ResultExt; use crate::error::*; pub trait IntoKbinBytes { - fn write_kbin_bytes(self, buf: &mut B); + fn write_kbin_bytes(self, buf: &mut B); } pub trait FromKbinBytes: Sized { - fn from_kbin_bytes(input: &mut R) -> Result; + fn from_kbin_bytes(input: &mut R) -> Result; } impl IntoKbinBytes for i8 { - fn write_kbin_bytes(self, buf: &mut B) { - buf.put_i8(self); - } + fn write_kbin_bytes(self, buf: &mut B) { + buf.put_i8(self); + } } impl FromKbinBytes for i8 { - fn from_kbin_bytes(input: &mut R) -> Result { - input.read_i8().context(DataConvert) - } + fn from_kbin_bytes(input: &mut R) -> Result { + input.read_i8().context(DataConvert) + } } impl IntoKbinBytes for u8 { - fn write_kbin_bytes(self, buf: &mut B) { - buf.put_u8(self); - } + fn write_kbin_bytes(self, buf: &mut B) { + buf.put_u8(self); + } } impl FromKbinBytes for u8 { - fn from_kbin_bytes(input: &mut R) -> Result { - input.read_u8().context(DataConvert) - } + fn from_kbin_bytes(input: &mut R) -> Result { + input.read_u8().context(DataConvert) + } } impl IntoKbinBytes for bool { - fn write_kbin_bytes(self, buf: &mut B) { - buf.put_u8(if self { 0x01 } else { 0x00 }) - } + fn write_kbin_bytes(self, buf: &mut B) { + buf.put_u8(if self { 0x01 } else { 0x00 }) + } } impl FromKbinBytes for bool { - fn from_kbin_bytes(input: &mut R) -> Result { - match u8::from_kbin_bytes(input)? { - 0x00 => Ok(false), - 0x01 => Ok(true), - input => Err(KbinError::InvalidBooleanInput { input }), + fn from_kbin_bytes(input: &mut R) -> Result { + match u8::from_kbin_bytes(input)? { + 0x00 => Ok(false), + 0x01 => Ok(true), + input => Err(KbinError::InvalidBooleanInput { input }), + } } - } } impl<'a> IntoKbinBytes for &'a [u8] { - fn write_kbin_bytes(self, buf: &mut B) { - buf.put(self); - } + fn write_kbin_bytes(self, buf: &mut B) { + buf.put(self); + } } impl IntoKbinBytes for Ipv4Addr { - fn write_kbin_bytes(self, buf: &mut B) { - let octets = self.octets(); + fn write_kbin_bytes(self, buf: &mut B) { + let octets = self.octets(); - buf.put(&octets[..]) - } + buf.put(&octets[..]) + } } impl FromKbinBytes for Ipv4Addr { - fn from_kbin_bytes(input: &mut R) -> Result { - let mut octets = [0; 4]; - input.read_exact(&mut octets).context(DataConvert)?; + fn from_kbin_bytes(input: &mut R) -> Result { + let mut octets = [0; 4]; + input.read_exact(&mut octets).context(DataConvert)?; - Ok(Ipv4Addr::from(octets)) - } + Ok(Ipv4Addr::from(octets)) + } } macro_rules! multibyte_impl { diff --git a/src/types/string.rs b/src/types/string.rs index bf02463..5fd6745 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -7,66 +7,78 @@ use snafu::ResultExt; use crate::error::*; pub trait FromKbinString: Sized { - fn from_kbin_string(input: &str) -> Result; + fn from_kbin_string(input: &str) -> Result; } fn space_check(input: &str) -> Result<()> { - // check for space character - if input.find(' ').is_some() { - return Err(KbinError::InvalidState.into()); - } + // check for space character + if input.find(' ').is_some() { + return Err(KbinError::InvalidState.into()); + } - Ok(()) + Ok(()) } fn parse_tuple(node_type: &'static str, input: &str, output: &mut [T]) -> Result<()> - where T: FromStr, - T::Err: Error + Send + Sync + 'static, +where + T: FromStr, + T::Err: Error + Send + Sync + 'static, { - let count = input.split(' ').count(); - if count != output.len() { - return Err(KbinError::SizeMismatch { node_type, expected: output.len(), actual: count }); - } + let count = input.split(' ').count(); + if count != output.len() { + return Err(KbinError::SizeMismatch { + node_type, + expected: output.len(), + actual: count, + }); + } - for (i, part) in input.split(' ').enumerate() { - output[i] = part.parse::() - .map_err(|e| Box::new(e) as Box<(dyn Error + Send + Sync + 'static)>) - .context(StringParse { node_type })?; - } + for (i, part) in input.split(' ').enumerate() { + output[i] = part + .parse::() + .map_err(|e| Box::new(e) as Box<(dyn Error + Send + Sync + 'static)>) + .context(StringParse { node_type })?; + } - Ok(()) + Ok(()) } impl FromKbinString for bool { - fn from_kbin_string(input: &str) -> Result { - match input { - "false" | - "0" => Ok(false), - "true" | - "1" => Ok(true), - input => Err(KbinError::InvalidBooleanInput { input: u8::from_kbin_string(input)? }), + fn from_kbin_string(input: &str) -> Result { + match input { + "false" | "0" => Ok(false), + "true" | "1" => Ok(true), + input => Err(KbinError::InvalidBooleanInput { + input: u8::from_kbin_string(input)?, + }), + } } - } } impl FromKbinString for Ipv4Addr { - fn from_kbin_string(input: &str) -> Result { - space_check(input)?; + fn from_kbin_string(input: &str) -> Result { + space_check(input)?; - let count = input.split('.').count(); - if count != 4 { - return Err(KbinError::SizeMismatch { node_type: "Ipv4Addr", expected: 4, actual: count }); + let count = input.split('.').count(); + if count != 4 { + return Err(KbinError::SizeMismatch { + node_type: "Ipv4Addr", + expected: 4, + actual: count, + }); + } + + let mut octets = [0; 4]; + + // IP addresses are split by a period, so do not use `parse_tuple` + for (i, part) in input.split('.').enumerate() { + octets[i] = part.parse::().context(StringParseInt { + node_type: "Ipv4Addr", + })?; + } + + Ok(Ipv4Addr::from(octets)) } - - let mut octets = [0; 4]; - - // IP addresses are split by a period, so do not use `parse_tuple` - for (i, part) in input.split('.').enumerate() { - octets[i] = part.parse::().context(StringParseInt { node_type: "Ipv4Addr" })?; - } - - Ok(Ipv4Addr::from(octets)) - } } macro_rules! basic_int_parse { diff --git a/src/value/array.rs b/src/value/array.rs index f131789..f8083f3 100644 --- a/src/value/array.rs +++ b/src/value/array.rs @@ -4,61 +4,61 @@ use std::net::Ipv4Addr; use crate::error::KbinError; use crate::node_types::StandardType; -use crate::types::{FromKbinBytes, IntoKbinBytes}; use crate::types::FromKbinString; +use crate::types::{FromKbinBytes, IntoKbinBytes}; #[derive(Clone, Debug, PartialEq)] pub enum ValueArray { - S8(Vec), - U8(Vec), - S16(Vec), - U16(Vec), - S32(Vec), - U32(Vec), - S64(Vec), - U64(Vec), - Ip4(Vec), - Float(Vec), - Double(Vec), - S8_2(Vec<[i8; 2]>), - U8_2(Vec<[u8; 2]>), - S16_2(Vec<[i16; 2]>), - U16_2(Vec<[u16; 2]>), - S32_2(Vec<[i32; 2]>), - U32_2(Vec<[u32; 2]>), - S64_2(Vec<[i64; 2]>), - U64_2(Vec<[u64; 2]>), - Float2(Vec<[f32; 2]>), - Double2(Vec<[f64; 2]>), - S8_3(Vec<[i8; 3]>), - U8_3(Vec<[u8; 3]>), - S16_3(Vec<[i16; 3]>), - U16_3(Vec<[u16; 3]>), - S32_3(Vec<[i32; 3]>), - U32_3(Vec<[u32; 3]>), - S64_3(Vec<[i64; 3]>), - U64_3(Vec<[u64; 3]>), - Float3(Vec<[f32; 3]>), - Double3(Vec<[f64; 3]>), - S8_4(Vec<[i8; 4]>), - U8_4(Vec<[u8; 4]>), - S16_4(Vec<[i16; 4]>), - U16_4(Vec<[u16; 4]>), - S32_4(Vec<[i32; 4]>), - U32_4(Vec<[u32; 4]>), - S64_4(Vec<[i64; 4]>), - U64_4(Vec<[u64; 4]>), - Float4(Vec<[f32; 4]>), - Double4(Vec<[f64; 4]>), - Vs8(Vec<[i8; 16]>), - Vu8(Vec<[u8; 16]>), - Vs16(Vec<[i16; 8]>), - Vu16(Vec<[u16; 8]>), - Boolean(Vec), - Boolean2(Vec<[bool; 2]>), - Boolean3(Vec<[bool; 3]>), - Boolean4(Vec<[bool; 4]>), - Vb(Vec<[bool; 16]>), + S8(Vec), + U8(Vec), + S16(Vec), + U16(Vec), + S32(Vec), + U32(Vec), + S64(Vec), + U64(Vec), + Ip4(Vec), + Float(Vec), + Double(Vec), + S8_2(Vec<[i8; 2]>), + U8_2(Vec<[u8; 2]>), + S16_2(Vec<[i16; 2]>), + U16_2(Vec<[u16; 2]>), + S32_2(Vec<[i32; 2]>), + U32_2(Vec<[u32; 2]>), + S64_2(Vec<[i64; 2]>), + U64_2(Vec<[u64; 2]>), + Float2(Vec<[f32; 2]>), + Double2(Vec<[f64; 2]>), + S8_3(Vec<[i8; 3]>), + U8_3(Vec<[u8; 3]>), + S16_3(Vec<[i16; 3]>), + U16_3(Vec<[u16; 3]>), + S32_3(Vec<[i32; 3]>), + U32_3(Vec<[u32; 3]>), + S64_3(Vec<[i64; 3]>), + U64_3(Vec<[u64; 3]>), + Float3(Vec<[f32; 3]>), + Double3(Vec<[f64; 3]>), + S8_4(Vec<[i8; 4]>), + U8_4(Vec<[u8; 4]>), + S16_4(Vec<[i16; 4]>), + U16_4(Vec<[u16; 4]>), + S32_4(Vec<[i32; 4]>), + U32_4(Vec<[u32; 4]>), + S64_4(Vec<[i64; 4]>), + U64_4(Vec<[u64; 4]>), + Float4(Vec<[f32; 4]>), + Double4(Vec<[f64; 4]>), + Vs8(Vec<[i8; 16]>), + Vu8(Vec<[u8; 16]>), + Vs16(Vec<[i16; 8]>), + Vu16(Vec<[u16; 8]>), + Boolean(Vec), + Boolean2(Vec<[bool; 2]>), + Boolean3(Vec<[bool; 3]>), + Boolean4(Vec<[bool; 4]>), + Vb(Vec<[bool; 16]>), } macro_rules! type_impl { @@ -185,51 +185,51 @@ macro_rules! type_impl { } impl ValueArray { - type_impl! { - S8, U8, - S16, U16, - S32, U32, - S64, U64, - Ip4, - Float, - Double, - Boolean, - S8_2, S8_3, S8_4, Vs8, - U8_2, U8_3, U8_4, Vu8, - Boolean2, Boolean3, Boolean4, Vb, - S16_2, S16_3, S16_4, Vs16, - S32_2, S32_3, S32_4, - S64_2, S64_3, S64_4, - U16_2, U16_3, U16_4, Vu16, - U32_2, U32_3, U32_4, - U64_2, U64_3, U64_4, - Float2, Float3, Float4, - Double2, Double3, Double4, - } + type_impl! { + S8, U8, + S16, U16, + S32, U32, + S64, U64, + Ip4, + Float, + Double, + Boolean, + S8_2, S8_3, S8_4, Vs8, + U8_2, U8_3, U8_4, Vu8, + Boolean2, Boolean3, Boolean4, Vb, + S16_2, S16_3, S16_4, Vs16, + S32_2, S32_3, S32_4, + S64_2, S64_3, S64_4, + U16_2, U16_3, U16_4, Vu16, + U32_2, U32_3, U32_4, + U64_2, U64_3, U64_4, + Float2, Float3, Float4, + Double2, Double3, Double4, + } } fn write_values(f: &mut fmt::Formatter, values: &[T]) -> fmt::Result { - for (i, v) in values.iter().enumerate() { - if i > 0 { - f.write_str(" ")?; + for (i, v) in values.iter().enumerate() { + if i > 0 { + f.write_str(" ")?; + } + fmt::Display::fmt(v, f)?; } - fmt::Display::fmt(v, f)?; - } - Ok(()) + Ok(()) } macro_rules! write_array { - ($method:ident, $num:expr) => { - fn $method(f: &mut fmt::Formatter, values: &[[T; $num]]) -> fmt::Result { - for (i, v) in values.iter().flat_map(|v| v.into_iter()).enumerate() { - if i > 0 { - f.write_str(" ")?; + ($method:ident, $num:expr) => { + fn $method(f: &mut fmt::Formatter, values: &[[T; $num]]) -> fmt::Result { + for (i, v) in values.iter().flat_map(|v| v.into_iter()).enumerate() { + if i > 0 { + f.write_str(" ")?; + } + fmt::Display::fmt(v, f)?; + } + Ok(()) } - fmt::Display::fmt(v, f)?; - } - Ok(()) - } - }; + }; } write_array!(write_array_2, 2); @@ -239,58 +239,58 @@ write_array!(write_array_8, 8); write_array!(write_array_16, 16); impl fmt::Display for ValueArray { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - ValueArray::S8(v) => write_values(f, v), - ValueArray::U8(v) => write_values(f, v), - ValueArray::S16(v) => write_values(f, v), - ValueArray::U16(v) => write_values(f, v), - ValueArray::S32(v) => write_values(f, v), - ValueArray::U32(v) => write_values(f, v), - ValueArray::S64(v) => write_values(f, v), - ValueArray::U64(v) => write_values(f, v), - ValueArray::Ip4(v) => write_values(f, v), - ValueArray::Float(v) => write_values(f, v), - ValueArray::Double(v) => write_values(f, v), - ValueArray::S8_2(v) => write_array_2(f, v), - ValueArray::U8_2(v) => write_array_2(f, v), - ValueArray::S16_2(v) => write_array_2(f, v), - ValueArray::U16_2(v) => write_array_2(f, v), - ValueArray::S32_2(v) => write_array_2(f, v), - ValueArray::U32_2(v) => write_array_2(f, v), - ValueArray::S64_2(v) => write_array_2(f, v), - ValueArray::U64_2(v) => write_array_2(f, v), - ValueArray::Float2(v) => write_array_2(f, v), - ValueArray::Double2(v) => write_array_2(f, v), - ValueArray::S8_3(v) => write_array_3(f, v), - ValueArray::U8_3(v) => write_array_3(f, v), - ValueArray::S16_3(v) => write_array_3(f, v), - ValueArray::U16_3(v) => write_array_3(f, v), - ValueArray::S32_3(v) => write_array_3(f, v), - ValueArray::U32_3(v) => write_array_3(f, v), - ValueArray::S64_3(v) => write_array_3(f, v), - ValueArray::U64_3(v) => write_array_3(f, v), - ValueArray::Float3(v) => write_array_3(f, v), - ValueArray::Double3(v) => write_array_3(f, v), - ValueArray::S8_4(v) => write_array_4(f, v), - ValueArray::U8_4(v) => write_array_4(f, v), - ValueArray::S16_4(v) => write_array_4(f, v), - ValueArray::U16_4(v) => write_array_4(f, v), - ValueArray::S32_4(v) => write_array_4(f, v), - ValueArray::U32_4(v) => write_array_4(f, v), - ValueArray::S64_4(v) => write_array_4(f, v), - ValueArray::U64_4(v) => write_array_4(f, v), - ValueArray::Float4(v) => write_array_4(f, v), - ValueArray::Double4(v) => write_array_4(f, v), - ValueArray::Vs8(v) => write_array_16(f, v), - ValueArray::Vu8(v) => write_array_16(f, v), - ValueArray::Vs16(v) => write_array_8(f, v), - ValueArray::Vu16(v) => write_array_8(f, v), - ValueArray::Boolean(v) => write_values(f, &v), - ValueArray::Boolean2(v) => write_array_2(f, v), - ValueArray::Boolean3(v) => write_array_3(f, v), - ValueArray::Boolean4(v) => write_array_4(f, v), - ValueArray::Vb(v) => write_array_16(f, v), + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ValueArray::S8(v) => write_values(f, v), + ValueArray::U8(v) => write_values(f, v), + ValueArray::S16(v) => write_values(f, v), + ValueArray::U16(v) => write_values(f, v), + ValueArray::S32(v) => write_values(f, v), + ValueArray::U32(v) => write_values(f, v), + ValueArray::S64(v) => write_values(f, v), + ValueArray::U64(v) => write_values(f, v), + ValueArray::Ip4(v) => write_values(f, v), + ValueArray::Float(v) => write_values(f, v), + ValueArray::Double(v) => write_values(f, v), + ValueArray::S8_2(v) => write_array_2(f, v), + ValueArray::U8_2(v) => write_array_2(f, v), + ValueArray::S16_2(v) => write_array_2(f, v), + ValueArray::U16_2(v) => write_array_2(f, v), + ValueArray::S32_2(v) => write_array_2(f, v), + ValueArray::U32_2(v) => write_array_2(f, v), + ValueArray::S64_2(v) => write_array_2(f, v), + ValueArray::U64_2(v) => write_array_2(f, v), + ValueArray::Float2(v) => write_array_2(f, v), + ValueArray::Double2(v) => write_array_2(f, v), + ValueArray::S8_3(v) => write_array_3(f, v), + ValueArray::U8_3(v) => write_array_3(f, v), + ValueArray::S16_3(v) => write_array_3(f, v), + ValueArray::U16_3(v) => write_array_3(f, v), + ValueArray::S32_3(v) => write_array_3(f, v), + ValueArray::U32_3(v) => write_array_3(f, v), + ValueArray::S64_3(v) => write_array_3(f, v), + ValueArray::U64_3(v) => write_array_3(f, v), + ValueArray::Float3(v) => write_array_3(f, v), + ValueArray::Double3(v) => write_array_3(f, v), + ValueArray::S8_4(v) => write_array_4(f, v), + ValueArray::U8_4(v) => write_array_4(f, v), + ValueArray::S16_4(v) => write_array_4(f, v), + ValueArray::U16_4(v) => write_array_4(f, v), + ValueArray::S32_4(v) => write_array_4(f, v), + ValueArray::U32_4(v) => write_array_4(f, v), + ValueArray::S64_4(v) => write_array_4(f, v), + ValueArray::U64_4(v) => write_array_4(f, v), + ValueArray::Float4(v) => write_array_4(f, v), + ValueArray::Double4(v) => write_array_4(f, v), + ValueArray::Vs8(v) => write_array_16(f, v), + ValueArray::Vu8(v) => write_array_16(f, v), + ValueArray::Vs16(v) => write_array_8(f, v), + ValueArray::Vu16(v) => write_array_8(f, v), + ValueArray::Boolean(v) => write_values(f, &v), + ValueArray::Boolean2(v) => write_array_2(f, v), + ValueArray::Boolean3(v) => write_array_3(f, v), + ValueArray::Boolean4(v) => write_array_4(f, v), + ValueArray::Vb(v) => write_array_16(f, v), + } } - } } diff --git a/src/value/mod.rs b/src/value/mod.rs index 0a77460..d6bb173 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -228,136 +228,180 @@ macro_rules! tuple { } impl Value { - tuple! { - S8_2, S8_3, S8_4, Vs8, - U8_2, U8_3, U8_4, Vu8, - Boolean2, Boolean3, Boolean4, Vb, - S16_2, S16_3, S16_4, Vs16, - S32_2, S32_3, S32_4, - S64_2, S64_3, S64_4, - U16_2, U16_3, U16_4, Vu16, - U32_2, U32_3, U32_4, - U64_2, U64_3, U64_4, - Float2, Float3, Float4, - Double2, Double3, Double4, - } - - pub fn to_bytes(&self) -> Result> { - let mut output = Vec::new(); - self.to_bytes_inner(&mut output)?; - - Ok(output) - } - - #[inline] - pub fn to_bytes_into(&self, output: &mut Vec) -> Result<()> { - self.to_bytes_inner(output) - } - - pub fn as_i8(&self) -> Result { - match self { - Value::S8(ref n) => Ok(*n), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S8, value: value.clone() }), + tuple! { + S8_2, S8_3, S8_4, Vs8, + U8_2, U8_3, U8_4, Vu8, + Boolean2, Boolean3, Boolean4, Vb, + S16_2, S16_3, S16_4, Vs16, + S32_2, S32_3, S32_4, + S64_2, S64_3, S64_4, + U16_2, U16_3, U16_4, Vu16, + U32_2, U32_3, U32_4, + U64_2, U64_3, U64_4, + Float2, Float3, Float4, + Double2, Double3, Double4, } - } - pub fn as_u8(&self) -> Result { - match self { - Value::U8(ref n) => Ok(*n), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U8, value: value.clone() }), - } - } + pub fn to_bytes(&self) -> Result> { + let mut output = Vec::new(); + self.to_bytes_inner(&mut output)?; - pub fn as_i16(&self) -> Result { - match self { - Value::S16(ref n) => Ok(*n), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S16, value: value.clone() }), + Ok(output) } - } - pub fn as_u16(&self) -> Result { - match self { - Value::U16(ref n) => Ok(*n), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U16, value: value.clone() }), + #[inline] + pub fn to_bytes_into(&self, output: &mut Vec) -> Result<()> { + self.to_bytes_inner(output) } - } - pub fn as_i32(&self) -> Result { - match self { - Value::S32(ref n) => Ok(*n), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S32, value: value.clone() }), + pub fn as_i8(&self) -> Result { + match self { + Value::S8(ref n) => Ok(*n), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::S8, + value: value.clone(), + }), + } } - } - pub fn as_u32(&self) -> Result { - match self { - Value::U32(ref n) => Ok(*n), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U32, value: value.clone() }), + pub fn as_u8(&self) -> Result { + match self { + Value::U8(ref n) => Ok(*n), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::U8, + value: value.clone(), + }), + } } - } - pub fn as_i64(&self) -> Result { - match self { - Value::S64(ref n) => Ok(*n), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S64, value: value.clone() }), + pub fn as_i16(&self) -> Result { + match self { + Value::S16(ref n) => Ok(*n), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::S16, + value: value.clone(), + }), + } } - } - pub fn as_u64(&self) -> Result { - match self { - Value::U64(ref n) => Ok(*n), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U64, value: value.clone() }), + pub fn as_u16(&self) -> Result { + match self { + Value::U16(ref n) => Ok(*n), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::U16, + value: value.clone(), + }), + } } - } - pub fn as_slice(&self) -> Result<&[u8]> { - match self { - Value::Binary(ref data) => Ok(data), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value: value.clone() }), + pub fn as_i32(&self) -> Result { + match self { + Value::S32(ref n) => Ok(*n), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::S32, + value: value.clone(), + }), + } } - } - pub fn as_str(&self) -> Result<&str> { - match self { - Value::String(ref s) => Ok(s), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::String, value: value.clone() }), + pub fn as_u32(&self) -> Result { + match self { + Value::U32(ref n) => Ok(*n), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::U32, + value: value.clone(), + }), + } } - } - pub fn as_string(self) -> Result { - match self { - Value::String(s) => Ok(s), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::String, value }), + pub fn as_i64(&self) -> Result { + match self { + Value::S64(ref n) => Ok(*n), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::S64, + value: value.clone(), + }), + } } - } - pub fn as_attribute(self) -> Result { - match self { - Value::Attribute(s) => Ok(s), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Attribute, value }), + pub fn as_u64(&self) -> Result { + match self { + Value::U64(ref n) => Ok(*n), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::U64, + value: value.clone(), + }), + } } - } - pub fn as_binary(&self) -> Result<&[u8]> { - match self { - Value::Binary(ref data) => Ok(data), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value: value.clone() }), + pub fn as_slice(&self) -> Result<&[u8]> { + match self { + Value::Binary(ref data) => Ok(data), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::Binary, + value: value.clone(), + }), + } } - } - pub fn as_array(&self) -> Result<&ValueArray> { - match self { - Value::Array(ref values) => Ok(values), - value => Err(KbinError::ExpectedValueArray { value: value.clone() }), + pub fn as_str(&self) -> Result<&str> { + match self { + Value::String(ref s) => Ok(s), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::String, + value: value.clone(), + }), + } } - } - pub fn into_binary(self) -> Result> { - match self { - Value::Binary(data) => Ok(data), - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value }), + pub fn as_string(self) -> Result { + match self { + Value::String(s) => Ok(s), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::String, + value, + }), + } + } + + pub fn as_attribute(self) -> Result { + match self { + Value::Attribute(s) => Ok(s), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::Attribute, + value, + }), + } + } + + pub fn as_binary(&self) -> Result<&[u8]> { + match self { + Value::Binary(ref data) => Ok(data), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::Binary, + value: value.clone(), + }), + } + } + + pub fn as_array(&self) -> Result<&ValueArray> { + match self { + Value::Array(ref values) => Ok(values), + value => Err(KbinError::ExpectedValueArray { + value: value.clone(), + }), + } + } + + pub fn into_binary(self) -> Result> { + match self { + Value::Binary(data) => Ok(data), + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::Binary, + value, + }), + } } - } } /* @@ -374,46 +418,58 @@ impl TryFrom for Vec { */ impl TryFrom for Vec { - type Error = KbinError; + type Error = KbinError; - fn try_from(value: Value) -> Result { - // An array of unsigned 8-bit integers can either be `Binary` or a literal - // array of unsigned 8-bit integers. - match value { - Value::Binary(data) => Ok(data), - Value::Array(values) => match values { - ValueArray::U8(values) => Ok(values), - values => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U8, value: Value::Array(values) }), - }, - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value }), + fn try_from(value: Value) -> Result { + // An array of unsigned 8-bit integers can either be `Binary` or a literal + // array of unsigned 8-bit integers. + match value { + Value::Binary(data) => Ok(data), + Value::Array(values) => match values { + ValueArray::U8(values) => Ok(values), + values => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::U8, + value: Value::Array(values), + }), + }, + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::Binary, + value, + }), + } } - } } impl TryFrom<&Value> for Vec { - type Error = KbinError; + type Error = KbinError; - fn try_from(value: &Value) -> Result { - match value { - Value::Binary(ref data) => Ok(data.to_vec()), - Value::Array(ref values) => match values.clone() { - ValueArray::U8(values) => Ok(values), - values => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U8, value: Value::Array(values) }), - }, - value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value: value.clone() }), + fn try_from(value: &Value) -> Result { + match value { + Value::Binary(ref data) => Ok(data.to_vec()), + Value::Array(ref values) => match values.clone() { + ValueArray::U8(values) => Ok(values), + values => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::U8, + value: Value::Array(values), + }), + }, + value => Err(KbinError::ValueTypeMismatch { + node_type: StandardType::Binary, + value: value.clone(), + }), + } } - } } impl From> for Value { - fn from(value: Vec) -> Value { - Value::Binary(value) - } + fn from(value: Vec) -> Value { + Value::Binary(value) + } } impl fmt::Debug for Value { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - macro_rules! field { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + macro_rules! field { ( display: [$($konst_display:ident),*], debug: [$($konst_debug:ident),*] @@ -435,28 +491,28 @@ impl fmt::Debug for Value { }; } - field! { - display: [ - S8, S16, S32, S64, - U8, U16, U32, U64, - Float, Double, Boolean - ], - debug: [ - String, Time, Ip4, - Attribute, - S8_2, U8_2, S16_2, U16_2, S32_2, U32_2, S64_2, U64_2, Float2, Double2, Boolean2, - S8_3, U8_3, S16_3, U16_3, S32_3, U32_3, S64_3, U64_3, Float3, Double3, Boolean3, - S8_4, U8_4, S16_4, U16_4, S32_4, U32_4, S64_4, U64_4, Float4, Double4, Boolean4, - Vs16, Vu16, - Vs8, Vu8, Vb - ] + field! { + display: [ + S8, S16, S32, S64, + U8, U16, U32, U64, + Float, Double, Boolean + ], + debug: [ + String, Time, Ip4, + Attribute, + S8_2, U8_2, S16_2, U16_2, S32_2, U32_2, S64_2, U64_2, Float2, Double2, Boolean2, + S8_3, U8_3, S16_3, U16_3, S32_3, U32_3, S64_3, U64_3, Float3, Double3, Boolean3, + S8_4, U8_4, S16_4, U16_4, S32_4, U32_4, S64_4, U64_4, Float4, Double4, Boolean4, + Vs16, Vu16, + Vs8, Vu8, Vb + ] + } } - } } impl fmt::Display for Value { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - macro_rules! display_value { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + macro_rules! display_value { ( simple: [$($simple:ident),*], tuple: [$($tuple:ident),*], @@ -506,25 +562,25 @@ impl fmt::Display for Value { }; } - display_value! { - simple: [ - S8, U8, S16, U16, S32, U32, S64, U64, - String, Ip4, Time, Attribute, - Array - ], - tuple: [ - S8_2, U8_2, S16_2, U16_2, S32_2, U32_2, S64_2, U64_2, - S8_3, U8_3, S16_3, U16_3, S32_3, U32_3, S64_3, U64_3, - S8_4, U8_4, S16_4, U16_4, S32_4, U32_4, S64_4, U64_4, - Vs8, Vu8, Vs16, Vu16 - ], - value: [ - Float => [Float2, Float3, Float4], - Double => [Double2, Double3, Double4], - Boolean => [Boolean2, Boolean3, Boolean4, Vb] - ] + display_value! { + simple: [ + S8, U8, S16, U16, S32, U32, S64, U64, + String, Ip4, Time, Attribute, + Array + ], + tuple: [ + S8_2, U8_2, S16_2, U16_2, S32_2, U32_2, S64_2, U64_2, + S8_3, U8_3, S16_3, U16_3, S32_3, U32_3, S64_3, U64_3, + S8_4, U8_4, S16_4, U16_4, S32_4, U32_4, S64_4, U64_4, + Vs8, Vu8, Vs16, Vu16 + ], + value: [ + Float => [Float2, Float3, Float4], + Double => [Double2, Double3, Double4], + Boolean => [Boolean2, Boolean3, Boolean4, Vb] + ] + } } - } } construct_types! { diff --git a/src/writer.rs b/src/writer.rs index 155b105..c352509 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -14,223 +14,325 @@ use crate::value::Value; use super::{ARRAY_MASK, SIGNATURE}; -fn write_value(options: &Options, data_buf: &mut ByteBufferWrite, node_type: StandardType, is_array: bool, value: &Value) -> Result<()> { - match value { - Value::Binary(data) => { - trace!("data: 0x{:02x?}", data); +fn write_value( + options: &Options, + data_buf: &mut ByteBufferWrite, + node_type: StandardType, + is_array: bool, + value: &Value, +) -> Result<()> { + match value { + Value::Binary(data) => { + trace!("data: 0x{:02x?}", data); - let size = (data.len() as u32) * (node_type.size as u32); - data_buf.write_u32::(size).context(DataWrite { node_type: "binary node size" })?; - data_buf.write_all(&data).context(DataWrite { node_type: "binary" })?; - data_buf.realign_writes(None)?; - }, - Value::String(text) => { - data_buf.write_str(options.encoding, &text)?; - }, - Value::Array(values) => { - if !is_array { - return Err(KbinError::InvalidState); - } + let size = (data.len() as u32) * (node_type.size as u32); + data_buf.write_u32::(size).context(DataWrite { + node_type: "binary node size", + })?; + data_buf.write_all(&data).context(DataWrite { + node_type: "binary", + })?; + data_buf.realign_writes(None)?; + }, + Value::String(text) => { + data_buf.write_str(options.encoding, &text)?; + }, + Value::Array(values) => { + if !is_array { + return Err(KbinError::InvalidState); + } - let total_size = values.len() * node_type.count * node_type.size; + let total_size = values.len() * node_type.count * node_type.size; - let mut data = Vec::with_capacity(total_size); - values.to_bytes_into(&mut data)?; + let mut data = Vec::with_capacity(total_size); + values.to_bytes_into(&mut data)?; - data_buf.write_u32::(total_size as u32).context(DataWrite { node_type: "node size" })?; - data_buf.write_all(&data).context(DataWrite { node_type: node_type.name })?; - data_buf.realign_writes(None)?; - }, - value => { - if is_array { - return Err(KbinError::InvalidState); - } else { - let data = value.to_bytes()?; - data_buf.write_aligned(*node_type, &data)?; - } - }, - }; + data_buf + .write_u32::(total_size as u32) + .context(DataWrite { + node_type: "node size", + })?; + data_buf.write_all(&data).context(DataWrite { + node_type: node_type.name, + })?; + data_buf.realign_writes(None)?; + }, + value => { + if is_array { + return Err(KbinError::InvalidState); + } else { + let data = value.to_bytes()?; + data_buf.write_aligned(*node_type, &data)?; + } + }, + }; - Ok(()) + Ok(()) } pub trait Writeable { - fn write_node(&self, options: &Options, node_buf: &mut ByteBufferWrite, data_buf: &mut ByteBufferWrite) -> Result<()>; + fn write_node( + &self, + options: &Options, + node_buf: &mut ByteBufferWrite, + data_buf: &mut ByteBufferWrite, + ) -> Result<()>; } impl Writeable for NodeCollection { - fn write_node(&self, options: &Options, node_buf: &mut ByteBufferWrite, data_buf: &mut ByteBufferWrite) -> Result<()> { - let (node_type, is_array) = self.base().node_type_tuple(); - let array_mask = if is_array { ARRAY_MASK } else { 0 }; - let name = self.base().key()?.ok_or(KbinError::InvalidState)?; + fn write_node( + &self, + options: &Options, + node_buf: &mut ByteBufferWrite, + data_buf: &mut ByteBufferWrite, + ) -> Result<()> { + let (node_type, is_array) = self.base().node_type_tuple(); + let array_mask = if is_array { ARRAY_MASK } else { 0 }; + let name = self.base().key()?.ok_or(KbinError::InvalidState)?; - debug!("NodeCollection write_node => name: {}, type: {:?}, type_size: {}, type_count: {}, is_array: {}", + debug!("NodeCollection write_node => name: {}, type: {:?}, type_size: {}, type_count: {}, is_array: {}", name, node_type, node_type.size, node_type.count, is_array); - node_buf.write_u8(node_type as u8 | array_mask).context(DataWrite { node_type: node_type.name })?; - match options.compression { - Compression::Compressed => Sixbit::pack(&mut **node_buf, &name)?, - Compression::Uncompressed => { - let data = options.encoding.encode_bytes(&name)?; - let len = (data.len() - 1) as u8; - node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { node_type: "node name length" })?; - node_buf.write_all(&data).context(DataWrite { node_type: "node name bytes" })?; - }, - }; + node_buf + .write_u8(node_type as u8 | array_mask) + .context(DataWrite { + node_type: node_type.name, + })?; + match options.compression { + Compression::Compressed => Sixbit::pack(&mut **node_buf, &name)?, + Compression::Uncompressed => { + let data = options.encoding.encode_bytes(&name)?; + let len = (data.len() - 1) as u8; + node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { + node_type: "node name length", + })?; + node_buf.write_all(&data).context(DataWrite { + node_type: "node name bytes", + })?; + }, + }; - if node_type != StandardType::NodeStart { - let value = self.base().value()?; - write_value(options, data_buf, node_type, is_array, &value)?; + if node_type != StandardType::NodeStart { + let value = self.base().value()?; + write_value(options, data_buf, node_type, is_array, &value)?; + } + + for attr in self.attributes() { + let key = attr.key()?.ok_or(KbinError::InvalidState)?; + let value = attr.value_bytes().ok_or(KbinError::InvalidState)?; + + trace!( + "NodeCollection write_node => attr: {}, value: 0x{:02x?}", + key, + value + ); + + data_buf.buf_write(value)?; + + node_buf + .write_u8(StandardType::Attribute as u8) + .context(DataWrite { + node_type: StandardType::Attribute.name, + })?; + match options.compression { + Compression::Compressed => Sixbit::pack(&mut **node_buf, &key)?, + Compression::Uncompressed => { + let data = options.encoding.encode_bytes(&key)?; + let len = (data.len() - 1) as u8; + node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { + node_type: "attribute name length", + })?; + node_buf.write_all(&data).context(DataWrite { + node_type: "node name bytes", + })?; + }, + }; + } + + for child in self.children() { + child.write_node(options, node_buf, data_buf)?; + } + + // node end always has the array bit set + node_buf + .write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK) + .context(DataWrite { + node_type: "node end", + })?; + + Ok(()) } - - for attr in self.attributes() { - let key = attr.key()?.ok_or(KbinError::InvalidState)?; - let value = attr.value_bytes().ok_or(KbinError::InvalidState)?; - - trace!("NodeCollection write_node => attr: {}, value: 0x{:02x?}", key, value); - - data_buf.buf_write(value)?; - - node_buf.write_u8(StandardType::Attribute as u8).context(DataWrite { node_type: StandardType::Attribute.name })?; - match options.compression { - Compression::Compressed => Sixbit::pack(&mut **node_buf, &key)?, - Compression::Uncompressed => { - let data = options.encoding.encode_bytes(&key)?; - let len = (data.len() - 1) as u8; - node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { node_type: "attribute name length" })?; - node_buf.write_all(&data).context(DataWrite { node_type: "node name bytes" })?; - }, - }; - } - - for child in self.children() { - child.write_node(options, node_buf, data_buf)?; - } - - // node end always has the array bit set - node_buf.write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK).context(DataWrite { node_type: "node end" })?; - - Ok(()) - } } impl Writeable for Node { - fn write_node(&self, options: &Options, node_buf: &mut ByteBufferWrite, data_buf: &mut ByteBufferWrite) -> Result<()> { - let (node_type, is_array) = match self.value() { - Some(Value::Array(ref values)) => (values.standard_type(), true), - Some(ref value) => (value.standard_type(), false), - None => (StandardType::NodeStart, false), - }; - let array_mask = if is_array { ARRAY_MASK } else { 0 }; - - debug!("Node write_node => name: {}, type: {:?}, type_size: {}, type_count: {}, is_array: {}", - self.key(), - node_type, - node_type.size, - node_type.count, - is_array); - - node_buf.write_u8(node_type as u8 | array_mask).context(DataWrite { node_type: node_type.name })?; - match options.compression { - Compression::Compressed => Sixbit::pack(&mut **node_buf, &self.key())?, - Compression::Uncompressed => { - let data = options.encoding.encode_bytes(&self.key())?; - let len = (data.len() - 1) as u8; - node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { node_type: "node name length" })?; - node_buf.write_all(&data).context(DataWrite { node_type: "node name bytes" })?; - }, - }; - - if let Some(value) = self.value() { - write_value(options, data_buf, node_type, is_array, value)?; - } - - if let Some(attributes) = self.attributes() { - for (key, value) in attributes { - trace!("Node write_node => attr: {}, value: {}", key, value); - - data_buf.write_str(options.encoding, value)?; - - node_buf.write_u8(StandardType::Attribute as u8).context(DataWrite { node_type: StandardType::Attribute.name })?; - match options.compression { - Compression::Compressed => Sixbit::pack(&mut **node_buf, &key)?, - Compression::Uncompressed => { - let data = options.encoding.encode_bytes(&key)?; - let len = (data.len() - 1) as u8; - node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { node_type: "attribute name length" })?; - node_buf.write_all(&data).context(DataWrite { node_type: "node name bytes" })?; - }, + fn write_node( + &self, + options: &Options, + node_buf: &mut ByteBufferWrite, + data_buf: &mut ByteBufferWrite, + ) -> Result<()> { + let (node_type, is_array) = match self.value() { + Some(Value::Array(ref values)) => (values.standard_type(), true), + Some(ref value) => (value.standard_type(), false), + None => (StandardType::NodeStart, false), }; - } + let array_mask = if is_array { ARRAY_MASK } else { 0 }; + + debug!( + "Node write_node => name: {}, type: {:?}, type_size: {}, type_count: {}, is_array: {}", + self.key(), + node_type, + node_type.size, + node_type.count, + is_array + ); + + node_buf + .write_u8(node_type as u8 | array_mask) + .context(DataWrite { + node_type: node_type.name, + })?; + match options.compression { + Compression::Compressed => Sixbit::pack(&mut **node_buf, &self.key())?, + Compression::Uncompressed => { + let data = options.encoding.encode_bytes(&self.key())?; + let len = (data.len() - 1) as u8; + node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { + node_type: "node name length", + })?; + node_buf.write_all(&data).context(DataWrite { + node_type: "node name bytes", + })?; + }, + }; + + if let Some(value) = self.value() { + write_value(options, data_buf, node_type, is_array, value)?; + } + + if let Some(attributes) = self.attributes() { + for (key, value) in attributes { + trace!("Node write_node => attr: {}, value: {}", key, value); + + data_buf.write_str(options.encoding, value)?; + + node_buf + .write_u8(StandardType::Attribute as u8) + .context(DataWrite { + node_type: StandardType::Attribute.name, + })?; + match options.compression { + Compression::Compressed => Sixbit::pack(&mut **node_buf, &key)?, + Compression::Uncompressed => { + let data = options.encoding.encode_bytes(&key)?; + let len = (data.len() - 1) as u8; + node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { + node_type: "attribute name length", + })?; + node_buf.write_all(&data).context(DataWrite { + node_type: "node name bytes", + })?; + }, + }; + } + } + + if let Some(children) = self.children() { + for child in children { + child.write_node(options, node_buf, data_buf)?; + } + } + + // node end always has the array bit set + node_buf + .write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK) + .context(DataWrite { + node_type: "node end", + })?; + + Ok(()) } - - if let Some(children) = self.children() { - for child in children { - child.write_node(options, node_buf, data_buf)?; - } - } - - // node end always has the array bit set - node_buf.write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK).context(DataWrite { node_type: "node end" })?; - - Ok(()) - } } pub struct Writer { - options: Options, + options: Options, } impl Writer { - pub fn new() -> Self { - Self { - options: Options::default(), + pub fn new() -> Self { + Self { + options: Options::default(), + } } - } - pub fn with_options(options: Options) -> Self { - Self { - options, + pub fn with_options(options: Options) -> Self { + Self { options } } - } - pub fn to_binary(&mut self, input: &T) -> Result> - where T: Writeable - { - let mut header = Cursor::new(Vec::with_capacity(8)); - header.write_u8(SIGNATURE).context(HeaderWrite { field: "signature" })?; + pub fn to_binary(&mut self, input: &T) -> Result> + where + T: Writeable, + { + let mut header = Cursor::new(Vec::with_capacity(8)); + header + .write_u8(SIGNATURE) + .context(HeaderWrite { field: "signature" })?; - let compression = self.options.compression.to_byte(); - header.write_u8(compression).context(HeaderWrite { field: "compression" })?; + let compression = self.options.compression.to_byte(); + header.write_u8(compression).context(HeaderWrite { + field: "compression", + })?; - let encoding = self.options.encoding.to_byte(); - header.write_u8(encoding).context(HeaderWrite { field: "encoding" })?; - header.write_u8(0xFF ^ encoding).context(HeaderWrite { field: "encoding negation" })?; + let encoding = self.options.encoding.to_byte(); + header + .write_u8(encoding) + .context(HeaderWrite { field: "encoding" })?; + header.write_u8(0xFF ^ encoding).context(HeaderWrite { + field: "encoding negation", + })?; - let mut node_buf = ByteBufferWrite::new(Vec::new()); - let mut data_buf = ByteBufferWrite::new(Vec::new()); + let mut node_buf = ByteBufferWrite::new(Vec::new()); + let mut data_buf = ByteBufferWrite::new(Vec::new()); - input.write_node(&self.options, &mut node_buf, &mut data_buf)?; + input.write_node(&self.options, &mut node_buf, &mut data_buf)?; - node_buf.write_u8(StandardType::FileEnd as u8 | ARRAY_MASK).context(DataWrite { node_type: "file end" })?; - node_buf.realign_writes(None)?; + node_buf + .write_u8(StandardType::FileEnd as u8 | ARRAY_MASK) + .context(DataWrite { + node_type: "file end", + })?; + node_buf.realign_writes(None)?; - let mut output = header.into_inner(); + let mut output = header.into_inner(); - let node_buf = node_buf.into_inner(); - debug!("to_binary_internal => node_buf len: {0} (0x{0:x})", node_buf.len()); - output.write_u32::(node_buf.len() as u32).context(HeaderWrite { field: "node buffer length" })?; - output.extend_from_slice(&node_buf); + let node_buf = node_buf.into_inner(); + debug!( + "to_binary_internal => node_buf len: {0} (0x{0:x})", + node_buf.len() + ); + output + .write_u32::(node_buf.len() as u32) + .context(HeaderWrite { + field: "node buffer length", + })?; + output.extend_from_slice(&node_buf); - let data_buf = data_buf.into_inner(); - debug!("to_binary_internal => data_buf len: {0} (0x{0:x})", data_buf.len()); - output.write_u32::(data_buf.len() as u32).context(HeaderWrite { field: "data buffer length" })?; - output.extend_from_slice(&data_buf); + let data_buf = data_buf.into_inner(); + debug!( + "to_binary_internal => data_buf len: {0} (0x{0:x})", + data_buf.len() + ); + output + .write_u32::(data_buf.len() as u32) + .context(HeaderWrite { + field: "data buffer length", + })?; + output.extend_from_slice(&data_buf); - Ok(output) - } + Ok(output) + } }