error: replace failure with snafu

This commit is contained in:
Matt Bilker 2019-11-08 05:02:35 +00:00
parent 8be89649f3
commit a840cc63fa
No known key found for this signature in database
GPG Key ID: 69ADF8AEB6C8B5D1
17 changed files with 638 additions and 442 deletions

View File

@ -9,12 +9,12 @@ edition = "2018"
byteorder = "1.3.2"
bytes = "0.4.10"
encoding_rs = "0.8.6"
failure = "0.1.1"
indexmap = "1.0.1"
lazy_static = "1.0.0"
log = "0.4.6"
quick-xml = { version = "0.16.0", features = ["failure"] }
quick-xml = "0.17.0"
rustc-hex = "2.0.1"
snafu = "0.6.0"
clap = { version = "2.32.0", optional = true }
pretty_env_logger = { version = "0.3.0", optional = true }

View File

@ -1,15 +1,81 @@
use std::cmp::max;
use std::io::{Cursor, Seek, SeekFrom, Write};
use std::io::{self, Cursor, Seek, SeekFrom, Write};
use std::ops::{Deref, DerefMut};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use bytes::Bytes;
use failure::ResultExt;
use snafu::{ResultExt, Snafu};
use crate::encoding_type::EncodingType;
use crate::error::KbinError;
use crate::node_types::KbinType;
pub use crate::encoding_type::EncodingType;
pub use crate::error::{KbinError, KbinErrorKind, Result};
#[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("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<ByteBufferError>,
},
#[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 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 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 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,
},
}
/// Remove trailing null bytes, used for the `String` type
pub(crate) fn strip_trailing_null_bytes<'a>(data: &'a [u8]) -> &'a [u8] {
@ -65,16 +131,16 @@ impl ByteBufferRead {
self.cursor.position() as usize
}
fn check_read_size(&self, start: usize, size: usize) -> Result<usize> {
fn check_read_size(&self, start: usize, size: usize) -> Result<usize, ByteBufferError> {
let end = start + size;
if end > self.buffer.len() {
Err(KbinErrorKind::DataRead(size).into())
Err(ByteBufferError::OutOfBounds { offset: start, size })
} else {
Ok(end)
}
}
fn buf_read_size(&mut self, size: usize) -> Result<Bytes> {
fn buf_read_size(&mut self, size: usize) -> Result<Bytes, ByteBufferError> {
// 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)?;
@ -82,13 +148,13 @@ impl ByteBufferRead {
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(KbinErrorKind::DataRead(size))?;
self.cursor.seek(SeekFrom::Current(size as i64)).context(ReadSizeSeek { size })?;
Ok(data)
}
pub fn buf_read(&mut self) -> Result<Bytes> {
let size = self.cursor.read_u32::<BigEndian>().context(KbinErrorKind::DataReadSize)?;
pub fn buf_read(&mut self) -> Result<Bytes, ByteBufferError> {
let size = self.cursor.read_u32::<BigEndian>().context(ReadSize)?;
debug!("buf_read => index: {}, size: {}", self.cursor.position(), size);
let data = self.buf_read_size(size as usize)?;
@ -97,14 +163,14 @@ impl ByteBufferRead {
Ok(data)
}
pub fn get(&mut self, size: u32) -> Result<Bytes> {
pub fn get(&mut self, size: u32) -> Result<Bytes, ByteBufferError> {
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<Bytes> {
pub fn get_aligned(&mut self, data_type: KbinType) -> Result<Bytes, ByteBufferError> {
if self.offset_1 % 4 == 0 {
self.offset_1 = self.data_buf_offset();
}
@ -132,7 +198,7 @@ impl ByteBufferRead {
(true, data)
},
size => {
let data = self.buf_read_size(size as usize).context(KbinErrorKind::DataReadAligned)?;
let data = self.buf_read_size(size as usize).map_err(Box::new).context(ReadAligned { size })?;
self.realign_reads(None)?;
(false, data)
@ -142,8 +208,9 @@ impl ByteBufferRead {
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(KbinErrorKind::Seek)?;
self.cursor.seek(SeekFrom::Start(trailing as u64)).context(SeekOffset { offset: trailing })?;
self.realign_reads(None)?;
}
}
@ -151,12 +218,12 @@ impl ByteBufferRead {
Ok(data)
}
pub fn realign_reads(&mut self, size: Option<u64>) -> Result<()> {
pub fn realign_reads(&mut self, size: Option<u64>) -> 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(KbinErrorKind::Seek)?;
self.cursor.seek(SeekFrom::Current(1)).context(SeekForward { size: 1usize })?;
}
trace!("realign_reads => realigned to: {}", self.cursor.position());
@ -187,11 +254,11 @@ impl ByteBufferWrite {
self.buffer.position()
}
pub fn buf_write(&mut self, data: &[u8]) -> Result<()> {
self.buffer.write_u32::<BigEndian>(data.len() as u32).context(KbinErrorKind::DataWrite("data length integer"))?;
pub fn buf_write(&mut self, data: &[u8]) -> Result<(), ByteBufferError> {
self.buffer.write_u32::<BigEndian>(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(KbinErrorKind::DataWrite("data block"))?;
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)?;
@ -199,7 +266,7 @@ impl ByteBufferWrite {
Ok(())
}
pub fn write_str(&mut self, encoding: EncodingType, data: &str) -> Result<()> {
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)?;
@ -208,7 +275,7 @@ impl ByteBufferWrite {
Ok(())
}
pub fn write_aligned(&mut self, data_type: KbinType, data: &[u8]) -> Result<()> {
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();
}
@ -221,18 +288,18 @@ impl ByteBufferWrite {
trace!("write_aligned => old_pos: {}, size: {}, data: 0x{:02x?}", old_pos, size, data);
if size != data.len() {
return Err(KbinErrorKind::SizeMismatch(data_type.name, size, data.len()).into());
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::<BigEndian>(0).context(KbinErrorKind::DataWrite("empty DWORD"))?;
self.buffer.write_u32::<BigEndian>(0).context(WritePadding { size: 4usize })?;
}
self.buffer.seek(SeekFrom::Start(self.offset_1)).context(KbinErrorKind::Seek)?;
self.buffer.write_u8(data[0]).context(KbinErrorKind::DataWrite("1 byte value"))?;
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
@ -240,18 +307,18 @@ impl ByteBufferWrite {
2 => {
// Make room for new DWORD
if self.offset_2 % 4 == 0 {
self.buffer.write_u32::<BigEndian>(0).context(KbinErrorKind::DataWrite("empty DWORD"))?;
self.buffer.write_u32::<BigEndian>(0).context(WritePadding { size: 4usize })?;
}
self.buffer.seek(SeekFrom::Start(self.offset_2)).context(KbinErrorKind::Seek)?;
self.buffer.write_u8(data[0]).context(KbinErrorKind::DataWrite("first byte of 2 byte value"))?;
self.buffer.write_u8(data[1]).context(KbinErrorKind::DataWrite("second byte of 2 byte value"))?;
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(KbinErrorKind::DataWrite("large value"))?;
self.buffer.write_all(data).context(WriteDataBlock)?;
self.realign_writes(None)?;
false
@ -259,12 +326,12 @@ impl ByteBufferWrite {
};
if check_old {
self.buffer.seek(SeekFrom::Start(old_pos)).context(KbinErrorKind::Seek)?;
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(KbinErrorKind::Seek)?;
self.buffer.seek(SeekFrom::Start(trailing)).context(SeekOffset { offset: trailing as usize })?;
self.realign_writes(None)?;
}
}
@ -272,13 +339,14 @@ impl ByteBufferWrite {
Ok(())
}
pub fn realign_writes(&mut self, size: Option<u64>) -> Result<()> {
pub fn realign_writes(&mut self, size: Option<u64>) -> 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(KbinErrorKind::Seek)?;
self.buffer.write_u8(0).context(WritePadding { size: 1usize })?;
}
trace!("realign_writes => realigned to: {}", self.buffer.position());
Ok(())

View File

@ -1,4 +1,4 @@
use crate::error::{KbinError, KbinErrorKind};
use crate::error::KbinError;
use super::{SIG_COMPRESSED, SIG_UNCOMPRESSED};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -12,7 +12,7 @@ impl Compression {
match byte {
SIG_COMPRESSED => Ok(Compression::Compressed),
SIG_UNCOMPRESSED => Ok(Compression::Uncompressed),
_ => Err(KbinErrorKind::UnknownCompression.into()),
_ => Err(KbinError::UnknownCompression),
}
}

View File

@ -1,13 +1,44 @@
use std::fmt;
use crate::error::{KbinError, KbinErrorKind};
use failure::ResultExt;
use std::string::FromUtf8Error;
/// The `encoding_rs` crate uses the following to describe their counterparts:
///
/// `SHIFT_JIS` => `WINDOWS_31J`
/// `WINDOWS_1252` => `ISO-8859-1`
use encoding_rs::{Encoding, EUC_JP, SHIFT_JIS, UTF_8, WINDOWS_1252};
use snafu::{ResultExt, Snafu};
#[derive(Debug, Snafu)]
pub enum EncodingError {
#[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 encode the output: {:?}", actual))]
MismatchedEncode {
actual: &'static Encoding,
},
#[snafu(display("Unmappable characters found in input"))]
UnmappableCharacters,
#[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 convert string to alternate encoding"))]
Convert,
}
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -42,7 +73,7 @@ impl fmt::Display for EncodingType {
}
impl EncodingType {
pub fn from_byte(byte: u8) -> Result<Self, KbinError> {
pub fn from_byte(byte: u8) -> Result<Self, EncodingError> {
let val = match byte {
0x00 => EncodingType::None,
0x20 => EncodingType::ASCII,
@ -50,27 +81,25 @@ impl EncodingType {
0x60 => EncodingType::EUC_JP,
0x80 => EncodingType::SHIFT_JIS,
0xA0 => EncodingType::UTF_8,
_ => return Err(KbinErrorKind::UnknownEncoding.into()),
_ => return Err(EncodingError::UnknownEncoding),
};
Ok(val)
}
pub fn from_encoding(encoding: &'static Encoding) -> Result<Self, KbinError> {
let val = match encoding {
e if e == WINDOWS_1252 => EncodingType::ISO_8859_1,
e if e == EUC_JP => EncodingType::EUC_JP,
e if e == SHIFT_JIS => EncodingType::SHIFT_JIS,
e if e == UTF_8 => EncodingType::UTF_8,
_ => return Err(KbinErrorKind::UnknownEncoding.into()),
};
Ok(val)
pub fn from_encoding(encoding: &'static Encoding) -> Result<Self, EncodingError> {
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<Self, KbinError> {
pub fn from_label(label: &[u8]) -> Result<Self, EncodingError> {
Encoding::for_label(label)
.ok_or(KbinErrorKind::UnknownEncoding.into())
.ok_or(EncodingError::UnknownEncoding)
.and_then(Self::from_encoding)
}
@ -96,29 +125,23 @@ impl EncodingType {
}
}
fn decode_ascii(input: &[u8]) -> Result<String, KbinError> {
fn decode_ascii(input: &[u8]) -> Result<String, EncodingError> {
// ASCII only goes up to 0x7F
match input.iter().position(|&ch| ch >= 0x80) {
Some(first_error) => {
Err(format_err!("Invalid ASCII character at index: {}", first_error)
.context(KbinErrorKind::Encoding)
.into())
Some(index) => {
Err(EncodingError::InvalidAscii { index })
},
None => {
let output = String::from_utf8(input.to_vec()).context(KbinErrorKind::Utf8)?;
Ok(output)
String::from_utf8(input.to_vec()).context(InvalidUtf8)
},
}
}
fn encode_ascii(input: &str) -> Result<Vec<u8>, KbinError> {
fn encode_ascii(input: &str) -> Result<Vec<u8>, EncodingError> {
// ASCII only goes up to 0x7F
match input.as_bytes().iter().position(|&ch| ch >= 0x80) {
Some(first_error) => {
Err(format_err!("Unrepresentable character found at index: {}", first_error)
.context(KbinErrorKind::Encoding)
.into())
Some(index) => {
Err(EncodingError::InvalidAscii { index })
},
None => {
Ok(input.as_bytes().to_vec())
@ -126,8 +149,8 @@ impl EncodingType {
}
}
fn decode_with_encoding(encoding: &'static Encoding, input: &[u8]) -> Result<String, KbinError> {
let (output, actual_encoding, character_replaced) = encoding.decode(input);
fn decode_with_encoding(encoding: &'static Encoding, input: &[u8]) -> Result<String, EncodingError> {
let (output, actual, character_replaced) = encoding.decode(input);
//eprintln!("character replaced: {}", character_replaced);
@ -137,26 +160,22 @@ impl EncodingType {
// `EncodingType::SHIFT_JIS` will ignore invalid characters because Konami's
// implementation will include invalid characters.
if encoding != actual_encoding {
Err(format_err!("Another encoding was used to decode the output: {:?}", actual_encoding)
.context(KbinErrorKind::Encoding)
.into())
if encoding != actual {
Err(EncodingError::MismatchedDecode { actual })
} else if !character_replaced || encoding == SHIFT_JIS {
Ok(output.into_owned())
} else {
Err(KbinErrorKind::Encoding.into())
Err(EncodingError::UnmappableCharacters)
}
}
fn encode_with_encoding(encoding: &'static Encoding, input: &str) -> Result<Vec<u8>, KbinError> {
let (output, actual_encoding, had_unmappable_characters) = encoding.encode(input);
fn encode_with_encoding(encoding: &'static Encoding, input: &str) -> Result<Vec<u8>, EncodingError> {
let (output, actual, had_unmappable_characters) = encoding.encode(input);
if encoding != actual_encoding {
Err(format_err!("Another encoding was used to encode the output: {:?}", actual_encoding)
.context(KbinErrorKind::Encoding)
.into())
if encoding != actual {
Err(EncodingError::MismatchedEncode { actual })
} else if had_unmappable_characters {
Err(format_err!("had unmappable characters").context(KbinErrorKind::Encoding).into())
Err(EncodingError::UnmappableCharacters)
} else {
Ok(output.into_owned())
}
@ -169,10 +188,10 @@ impl EncodingType {
///
/// `EncodingType::SHIFT_JIS` will ignore invalid characters because Konami's
/// implementation will include invalid characters.
pub fn decode_bytes(&self, input: &[u8]) -> Result<String, KbinError> {
pub fn decode_bytes(&self, input: &[u8]) -> Result<String, EncodingError> {
match *self {
EncodingType::None |
EncodingType::UTF_8 => String::from_utf8(input.to_vec()).map_err(KbinError::from),
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),
@ -185,7 +204,7 @@ impl EncodingType {
///
/// 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<Vec<u8>, KbinError> {
pub fn encode_bytes(&self, input: &str) -> Result<Vec<u8>, EncodingError> {
let mut result = match *self {
EncodingType::None |
EncodingType::UTF_8 => input.as_bytes().to_vec(),

View File

@ -1,175 +1,206 @@
use std::fmt;
use std::error::Error;
//use std::fmt;
use std::io;
use std::num::{ParseFloatError, ParseIntError};
use std::result::Result as StdResult;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use failure::{Backtrace, Context, Fail};
use rustc_hex::FromHexError;
use quick_xml::Error as QuickXmlError;
use snafu::Snafu;
use crate::byte_buffer::ByteBufferError;
use crate::encoding_type::EncodingError;
use crate::node_types::StandardType;
use crate::reader::ReaderError;
use crate::sixbit::SixbitError;
use crate::value::Value;
pub type Result<T> = StdResult<T, KbinError>;
#[derive(Debug)]
pub struct KbinError {
inner: Context<KbinErrorKind>,
}
#[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,
},
#[derive(Debug, Fail)]
pub enum KbinErrorKind {
#[fail(display = "Unable to read {} byte from header", _0)]
HeaderRead(&'static str),
#[snafu(display("Invalid byte value for {} header field", field))]
HeaderValue {
field: &'static str,
},
#[fail(display = "Unable to write {} header field", _0)]
HeaderWrite(&'static str),
#[snafu(display("Unable to read {} bytes from data buffer", size))]
DataRead {
size: usize,
source: io::Error,
},
#[fail(display = "Invalid byte value for {} header field", _0)]
HeaderValue(&'static str),
#[snafu(display("Unable to write a {} to data buffer", node_type))]
DataWrite {
node_type: &'static str,
source: io::Error,
},
#[fail(display = "Unable to read {} bytes from data buffer", _0)]
DataRead(usize),
#[snafu(display("Unable to read bytes or not enough data read"))]
DataConvert {
source: io::Error,
},
#[fail(display = "Unable to write a {} to data buffer", _0)]
DataWrite(&'static str),
#[fail(display = "Unable to read bytes or not enough data read")]
DataConvert,
#[fail(display = "Unable to read data size")]
DataReadSize,
#[fail(display = "Unable to read aligned data from data buffer")]
DataReadAligned,
#[fail(display = "Unable to seek data buffer")]
Seek,
#[fail(display = "Reached the end of the node buffer")]
EndOfNodeBuffer,
#[fail(display = "Unable to read len_node")]
LenNodeRead,
#[fail(display = "Unable to read len_data")]
LenDataRead,
#[fail(display = "Unable to read node type")]
NodeTypeRead,
#[fail(display = "Unable to read binary/string byte length")]
BinaryLengthRead,
#[fail(display = "Unable to read array node length")]
ArrayLengthRead,
#[fail(display = "Unable to read sixbit string length")]
SixbitLengthRead,
#[fail(display = "Unable to read sixbit string content")]
SixbitRead,
#[fail(display = "Unable to write sixbit string length")]
SixbitLengthWrite,
#[fail(display = "Unable to write sixbit string content")]
SixbitWrite,
#[fail(display = "No node collection found")]
#[snafu(display("No node collection found"))]
NoNodeCollection,
#[fail(display = "Unable to interpret string as UTF-8")]
Utf8,
#[snafu(display("Failed to interpret string as UTF-8"))]
Utf8 {
source: FromUtf8Error,
},
#[fail(display = "Unknown compression value")]
#[snafu(display("Failed to interpret slice as UTF-8"))]
Utf8Slice {
source: Utf8Error,
},
#[snafu(display("Unknown compression value"))]
UnknownCompression,
#[fail(display = "Unknown encoding")]
UnknownEncoding,
#[snafu(display("Size Mismatch, type: {}, expected size: {}, actual size: {}", node_type, expected, actual))]
SizeMismatch {
node_type: &'static str,
expected: usize,
actual: usize,
},
#[fail(display = "Unable to interpret string as alternate encoding")]
Encoding,
#[snafu(display("Unable to interpret input as {}", node_type))]
StringParse {
node_type: &'static str,
source: Box<dyn Error>,
},
#[fail(display = "Size Mismatch, type: {}, expected size: {}, actual size: {}", _0, _1, _2)]
SizeMismatch(&'static str, usize, usize),
#[snafu(display("Unable to interpret integer input as {}", node_type))]
StringParseInt {
node_type: &'static str,
source: ParseIntError,
},
#[fail(display = "Unable to interpret input as {}", _0)]
StringParse(&'static str),
#[snafu(display("Unable to interpret float input as {}", node_type))]
StringParseFloat {
node_type: &'static str,
source: ParseFloatError,
},
#[fail(display = "Unable to convert from hexadecimal")]
HexError,
#[snafu(display("Unable to convert from hexadecimal"))]
HexError {
source: FromHexError,
},
#[fail(display = "Missing base kbin type where one is required")]
MissingBaseType,
#[snafu(display("Type mismatch, expected: {}, found: {}", expected, found))]
TypeMismatch {
expected: StandardType,
found: StandardType,
},
#[fail(display = "Missing type hint where one is required")]
MissingTypeHint,
#[snafu(display("Value mismatch, expected {}, but found {:?}", node_type, value))]
ValueTypeMismatch {
node_type: StandardType,
value: Value,
},
#[fail(display = "Type mismatch, expected: {}, found: {}", _0, _1)]
TypeMismatch(StandardType, StandardType),
#[snafu(display("Value mismatch, expected an array, but found {:?}", value))]
ExpectedValueArray {
value: Value,
},
#[fail(display = "Value mismatch, expected {}, but found {:?}", _0, _1)]
ValueTypeMismatch(StandardType, Value),
#[snafu(display("Invalid input for boolean: {}", input))]
InvalidBooleanInput {
input: u8,
},
#[fail(display = "Value mismatch, expected an array, but found {:?}", _0)]
ExpectedValueArray(Value),
#[snafu(display("Invalid node type for operation: {:?}", node_type))]
InvalidNodeType {
node_type: StandardType,
},
#[fail(display = "Invalid input for boolean: {}", _0)]
InvalidBooleanInput(u8),
#[fail(display = "Invalid node type for operation: {:?}", _0)]
InvalidNodeType(StandardType),
#[fail(display = "Invalid state")]
#[snafu(display("Invalid state"))]
InvalidState,
#[fail(display = "Error handling XML")]
XmlError(#[cause] QuickXmlError),
}
#[snafu(display("Failed to handle byte buffer operation"))]
ByteBuffer {
#[snafu(backtrace)]
source: ByteBufferError,
},
impl KbinError {
pub fn get_context(&self) -> &KbinErrorKind {
self.inner.get_context()
}
}
#[snafu(display("Failed to handle string encoding operation"))]
Encoding {
#[snafu(backtrace)]
source: EncodingError,
},
impl fmt::Display for KbinError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.inner, f)
}
}
#[snafu(display("Failed to read binary XML"))]
Reader {
#[snafu(backtrace)]
source: ReaderError,
},
impl Fail for KbinError {
fn cause(&self) -> Option<&dyn Fail> {
self.inner.cause()
}
#[snafu(display("Failed to handle sixbit string operation"))]
Sixbit {
#[snafu(backtrace)]
source: SixbitError,
},
fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}
impl From<KbinErrorKind> for KbinError {
fn from(kind: KbinErrorKind) -> Self {
Self { inner: Context::new(kind) }
}
}
impl From<Context<KbinErrorKind>> for KbinError {
fn from(inner: Context<KbinErrorKind>) -> Self {
Self { inner }
}
#[snafu(display("Error handling XML"))]
XmlError {
source: QuickXmlError,
},
}
impl From<FromUtf8Error> for KbinError {
fn from(inner: FromUtf8Error) -> Self {
inner.context(KbinErrorKind::Utf8).into()
#[inline]
fn from(source: FromUtf8Error) -> Self {
KbinError::Utf8 { source }
}
}
impl From<Utf8Error> for KbinError {
#[inline]
fn from(source: Utf8Error) -> Self {
KbinError::Utf8Slice { source }
}
}
impl From<ByteBufferError> for KbinError {
#[inline]
fn from(source: ByteBufferError) -> Self {
KbinError::ByteBuffer { source }
}
}
impl From<EncodingError> for KbinError {
#[inline]
fn from(source: EncodingError) -> Self {
KbinError::Encoding { source }
}
}
impl From<ReaderError> for KbinError {
#[inline]
fn from(source: ReaderError) -> Self {
KbinError::Reader { source }
}
}
impl From<SixbitError> for KbinError {
#[inline]
fn from(source: SixbitError) -> Self {
KbinError::Sixbit { source }
}
}
impl From<QuickXmlError> for KbinError {
fn from(inner: QuickXmlError) -> Self {
Self {
inner: Context::new(KbinErrorKind::XmlError(inner)),
}
#[inline]
fn from(source: QuickXmlError) -> Self {
KbinError::XmlError { source }
}
}

View File

@ -1,6 +1,5 @@
#![cfg_attr(test, feature(test))]
#[macro_use] extern crate failure;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate log;
@ -30,7 +29,7 @@ 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, KbinErrorKind, Result};
pub use crate::error::{KbinError, Result};
pub use crate::node::{Node, NodeCollection};
pub use crate::node_types::StandardType;
pub use crate::options::{Options, OptionsBuilder};
@ -51,7 +50,7 @@ pub fn is_binary_xml(input: &[u8]) -> bool {
pub fn from_binary(input: Bytes) -> Result<(NodeCollection, EncodingType)> {
let mut reader = Reader::new(input)?;
let collection = NodeCollection::from_iter(&mut reader).ok_or(KbinErrorKind::NoNodeCollection)?;
let collection = NodeCollection::from_iter(&mut reader).ok_or(KbinError::NoNodeCollection)?;
let encoding = reader.encoding();
Ok((collection, encoding))
@ -59,7 +58,7 @@ pub fn from_binary(input: Bytes) -> Result<(NodeCollection, EncodingType)> {
pub fn from_text_xml(input: &[u8]) -> Result<(NodeCollection, EncodingType)> {
let mut reader = TextXmlReader::new(input);
let collection = reader.as_node_collection()?.ok_or(KbinErrorKind::NoNodeCollection)?;
let collection = reader.as_node_collection()?.ok_or(KbinError::NoNodeCollection)?;
let encoding = reader.encoding();
Ok((collection, encoding))

View File

@ -2,7 +2,7 @@ use std::collections::VecDeque;
use std::fmt;
use std::iter::Iterator;
use crate::error::{KbinError, KbinErrorKind};
use crate::error::KbinError;
use crate::node::{Node, NodeDefinition};
use crate::node_types::StandardType;
use crate::value::Value;
@ -114,12 +114,12 @@ impl NodeCollection {
let mut node = self.base.as_node()?;
for attr in &self.attributes {
let key = attr.key()?.ok_or(KbinErrorKind::InvalidState)?;
let key = attr.key()?.ok_or(KbinError::InvalidState)?;
if let Value::Attribute(value) = attr.value()? {
node.set_attr(key, value);
} else {
return Err(KbinErrorKind::InvalidState.into());
return Err(KbinError::InvalidState.into());
}
}

View File

@ -4,7 +4,7 @@ use bytes::Bytes;
use crate::byte_buffer::strip_trailing_null_bytes;
use crate::encoding_type::EncodingType;
use crate::error::{KbinError, KbinErrorKind};
use crate::error::KbinError;
use crate::node::Node;
use crate::node_types::StandardType;
use crate::sixbit::{Sixbit, SixbitSize};
@ -44,10 +44,10 @@ impl Key {
fn to_string(&self) -> Result<String, KbinError> {
match self {
Key::Compressed { ref size, ref data } => {
Sixbit::unpack(data, *size)
Sixbit::unpack(data, *size).map_err(Into::into)
},
Key::Uncompressed { encoding, ref data } => {
encoding.decode_bytes(data)
encoding.decode_bytes(data).map_err(Into::into)
},
}
}
@ -119,11 +119,11 @@ impl NodeDefinition {
let value = Value::from_standard_type(node_type, self.is_array, value_data)?;
match value {
Some(value) => Ok(value),
None => Err(KbinErrorKind::InvalidNodeType(node_type).into()),
None => Err(KbinError::InvalidNodeType { node_type }),
}
},
(node_type, NodeData::None) => {
Err(KbinErrorKind::InvalidNodeType(node_type).into())
Err(KbinError::InvalidNodeType { node_type })
},
}
}
@ -140,7 +140,7 @@ impl NodeDefinition {
match (self.node_type, &self.data) {
(StandardType::NodeEnd, _) |
(StandardType::FileEnd, _) => {
Err(KbinErrorKind::InvalidNodeType(self.node_type).into())
Err(KbinError::InvalidNodeType { node_type: self.node_type })
},
(StandardType::NodeStart, NodeData::Some { key, .. }) => {
let key = key.to_string()?;
@ -152,7 +152,7 @@ impl NodeDefinition {
Ok(Node::with_value(key, value))
},
(node_type, NodeData::None) => {
Err(KbinErrorKind::InvalidNodeType(node_type).into())
Err(KbinError::InvalidNodeType { node_type })
},
}
}

View File

@ -1,19 +1,78 @@
use std::io;
use bytes::Bytes;
use byteorder::{BigEndian, ReadBytesExt};
use failure::ResultExt;
use snafu::{ResultExt, Snafu};
use crate::byte_buffer::ByteBufferRead;
use crate::compression::Compression;
use crate::byte_buffer::{ByteBufferError, ByteBufferRead};
use crate::compression::Compression as CompressionType;
use crate::encoding_type::EncodingType;
use crate::error::{KbinErrorKind, Result};
use crate::error::KbinError;
use crate::node::{Key, NodeData, NodeDefinition};
use crate::node_types::StandardType;
use crate::sixbit::Sixbit;
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 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 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 data buffer length"))]
DataBufferLength {
source: io::Error,
},
#[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 array node length"))]
ArrayLength {
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,
},
}
pub struct Reader {
compression: Compression,
compression: CompressionType,
encoding: EncodingType,
pub(crate) node_buf: ByteBufferRead,
@ -23,29 +82,29 @@ pub struct Reader {
}
impl Reader {
pub fn new(input: Bytes) -> Result<Self> {
pub fn new(input: Bytes) -> Result<Self, KbinError> {
// 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(KbinErrorKind::HeaderRead("signature"))?;
let signature = node_buf.read_u8().context(Signature)?;
if signature != SIGNATURE {
return Err(KbinErrorKind::HeaderValue("signature").into());
return Err(KbinError::HeaderValue { field: "signature" });
}
let compress_byte = node_buf.read_u8().context(KbinErrorKind::HeaderRead("compression"))?;
let compression = Compression::from_byte(compress_byte)?;
let compress_byte = node_buf.read_u8().context(Compression)?;
let compression = CompressionType::from_byte(compress_byte)?;
let encoding_byte = node_buf.read_u8().context(KbinErrorKind::HeaderRead("encoding"))?;
let encoding_negation = node_buf.read_u8().context(KbinErrorKind::HeaderRead("encoding negation"))?;
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(KbinErrorKind::HeaderValue("encoding negation").into());
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::<BigEndian>().context(KbinErrorKind::LenNodeRead)?;
let len_node = node_buf.read_u32::<BigEndian>().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
@ -53,7 +112,7 @@ impl Reader {
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::<BigEndian>().context(KbinErrorKind::LenDataRead)?;
let len_data = data_buf.read_u32::<BigEndian>().context(DataBufferLength)?;
info!("len_data: {0} (0x{0:x})", len_data);
Ok(Self {
@ -67,7 +126,7 @@ impl Reader {
})
}
fn parse_node_type(raw_node_type: u8) -> Result<(StandardType, bool)> {
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;
@ -86,24 +145,24 @@ impl Reader {
self.encoding
}
pub fn check_if_node_buffer_end(&self) -> Result<()> {
pub fn check_if_node_buffer_end(&self) -> Result<(), ReaderError> {
if self.node_buf.position() >= self.data_buf_start {
Err(KbinErrorKind::EndOfNodeBuffer.into())
Err(ReaderError::EndOfNodeBuffer)
} else {
Ok(())
}
}
pub fn read_node_type(&mut self) -> Result<(StandardType, bool)> {
pub fn read_node_type(&mut self) -> Result<(StandardType, bool), KbinError> {
self.check_if_node_buffer_end()?;
let raw_node_type = self.node_buf.read_u8().context(KbinErrorKind::NodeTypeRead)?;
let raw_node_type = self.node_buf.read_u8().context(NodeType)?;
let value = Self::parse_node_type(raw_node_type)?;
Ok(value)
}
pub fn read_node_data(&mut self, node_type: (StandardType, bool)) -> Result<Bytes> {
pub fn read_node_data(&mut self, node_type: (StandardType, bool)) -> Result<Bytes, KbinError> {
let (node_type, is_array) = node_type;
trace!("Reader::read_node_data(node_type: {:?}, is_array: {})", node_type, is_array);
@ -117,7 +176,7 @@ impl Reader {
StandardType::FileEnd => Bytes::new(),
_ if is_array => {
let arr_size = self.read_u32().context(KbinErrorKind::ArrayLengthRead)?;
let arr_size = self.data_buf.read_u32::<BigEndian>().context(ArrayLength)?;
let data = self.data_buf.get(arr_size)?;
self.data_buf.realign_reads(None)?;
@ -130,7 +189,7 @@ impl Reader {
Ok(value)
}
pub fn read_node_definition(&mut self) -> Result<NodeDefinition> {
pub fn read_node_definition(&mut self) -> Result<NodeDefinition, KbinError> {
let node_type = self.read_node_type()?;
match node_type.0 {
StandardType::NodeEnd |
@ -139,14 +198,14 @@ impl Reader {
}
_ => {
let key = match self.compression {
Compression::Compressed => {
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 }
},
Compression::Uncompressed => {
CompressionType::Uncompressed => {
let encoding = self.encoding;
let length = (self.node_buf.read_u8().context(KbinErrorKind::DataRead(1))? & !ARRAY_MASK) + 1;
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 }
},
@ -158,15 +217,15 @@ impl Reader {
}
}
pub fn read_u32(&mut self) -> Result<u32> {
let value = self.data_buf.read_u32::<BigEndian>().context(KbinErrorKind::DataRead(4))?;
pub fn read_u32(&mut self) -> Result<u32, ReaderError> {
let value = self.data_buf.read_u32::<BigEndian>().context(DataRead { size: 4usize })?;
debug!("Reader::read_u32() => result: {}", value);
Ok(value)
}
#[inline]
pub fn read_bytes(&mut self) -> Result<Bytes> {
pub fn read_bytes(&mut self) -> Result<Bytes, ByteBufferError> {
self.data_buf.buf_read()
}
}

View File

@ -1,10 +1,8 @@
use std::collections::HashMap;
use std::io::{Read, Write};
use std::io::{self, Read, Write};
use byteorder::{ReadBytesExt, WriteBytesExt};
use failure::ResultExt;
use crate::error::{KbinError, KbinErrorKind};
use snafu::{ResultExt, Snafu};
static CHAR_MAP: &'static [u8] = b"0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
@ -20,6 +18,30 @@ lazy_static! {
};
}
#[derive(Debug, Snafu)]
pub enum SixbitError {
#[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 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,
},
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SixbitSize {
pub sixbit_len: u8,
@ -29,10 +51,10 @@ pub struct SixbitSize {
pub struct Sixbit;
impl Sixbit {
pub fn size<T>(reader: &mut T) -> Result<SixbitSize, KbinError>
where T: Read
pub fn size<T>(reader: &mut T) -> Result<SixbitSize, SixbitError>
where T: Read,
{
let sixbit_len = reader.read_u8().context(KbinErrorKind::SixbitLengthRead)?;
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);
@ -40,8 +62,8 @@ impl Sixbit {
Ok(SixbitSize { sixbit_len, real_len })
}
pub fn pack<T>(writer: &mut T, input: &str) -> Result<(), KbinError>
where T: Write
pub fn pack<T>(writer: &mut T, input: &str) -> Result<(), SixbitError>
where T: Write,
{
let sixbit_chars = input
.bytes()
@ -64,17 +86,17 @@ impl Sixbit {
}
}
writer.write_u8(len as u8).context(KbinErrorKind::SixbitLengthWrite)?;
writer.write_all(&bytes).context(KbinErrorKind::SixbitWrite)?;
writer.write_u8(len as u8).context(LengthWrite)?;
writer.write_all(&bytes).context(DataWrite)?;
Ok(())
}
pub fn unpack(buf: &[u8], size: SixbitSize) -> Result<String, KbinError> {
pub fn unpack(buf: &[u8], size: SixbitSize) -> Result<String, SixbitError> {
let SixbitSize { sixbit_len, real_len } = size;
if buf.len() < real_len {
return Err(KbinErrorKind::SixbitRead.into());
return Err(SixbitError::DataRead { expected: real_len, actual: buf.len() });
}
let sixbit_len = sixbit_len as usize;

View File

@ -1,13 +1,13 @@
use std::str;
use bytes::{BufMut, Bytes, BytesMut};
use failure::{Fail, ResultExt};
use quick_xml::Reader;
use quick_xml::events::{BytesStart, BytesText, Event};
use quick_xml::events::attributes::Attributes;
use snafu::ResultExt;
use crate::encoding_type::EncodingType;
use crate::error::{KbinErrorKind, Result};
use crate::error::*;
use crate::node::{Key, NodeData, NodeCollection, NodeDefinition};
use crate::node_types::StandardType;
use crate::value::Value;
@ -79,19 +79,18 @@ impl<'a> TextXmlReader<'a> {
};
if attr.key == b"__type" {
let value = str::from_utf8(&*value).context(KbinErrorKind::Utf8)?;
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).context(KbinErrorKind::Utf8)?;
let num_count = value.parse::<u32>().context(KbinErrorKind::StringParse("array count"))?;
let value = str::from_utf8(&*value)?;
let num_count = value.parse::<u32>().context(StringParseInt { node_type: "array count" })?;
count = num_count as usize;
} else if attr.key == b"__size" {
let value = str::from_utf8(&*value)
.context(KbinErrorKind::Utf8)?
let value = str::from_utf8(&*value)?
.parse::<usize>()
.context(KbinErrorKind::StringParse("binary size"))?;
.context(StringParseInt { node_type: "binary size" })?;
size = Some(value);
} else {
@ -142,7 +141,7 @@ impl<'a> TextXmlReader<'a> {
}
fn handle_text(event: BytesText, definition: &mut NodeDefinition, count: usize, size: Option<usize>) -> Result<()> {
let data = event.unescaped().context(KbinErrorKind::Utf8)?;
let data = event.unescaped()?;
let data = match definition.node_type {
StandardType::String |
StandardType::NodeStart => {
@ -155,14 +154,14 @@ impl<'a> TextXmlReader<'a> {
data.freeze()
},
_ => {
let text = str::from_utf8(&*data).context(KbinErrorKind::Utf8)?;
let text = str::from_utf8(&*data)?;
let value = Value::from_string(definition.node_type, text, definition.is_array, count)?;
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(KbinErrorKind::InvalidState.into());
return Err(KbinError::InvalidState.into());
}
}
}
@ -179,7 +178,7 @@ impl<'a> TextXmlReader<'a> {
*value_data = data;
} else {
// There should be a valid `NodeData` structure from the `Event::Start` handler
return Err(KbinErrorKind::InvalidState.into());
return Err(KbinError::InvalidState.into());
}
Ok(())
@ -191,18 +190,18 @@ impl<'a> TextXmlReader<'a> {
let mut buf = Vec::with_capacity(1024);
loop {
match self.xml_reader.read_event(&mut buf) {
Ok(Event::Start(e)) => {
match self.xml_reader.read_event(&mut buf)? {
Event::Start(e) => {
let start = self.handle_start(e)?;
self.stack.push(start);
},
Ok(Event::Text(e)) => {
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)?;
}
},
Ok(Event::End(_)) => {
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);
@ -212,7 +211,7 @@ impl<'a> TextXmlReader<'a> {
}
}
},
Ok(Event::Empty(e)) => {
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");
@ -221,16 +220,13 @@ impl<'a> TextXmlReader<'a> {
parent_collection.children_mut().push_back(collection);
}
},
Ok(Event::Decl(e)) => {
Event::Decl(e) => {
if let Some(encoding) = e.encoding() {
self.encoding = EncodingType::from_label(&encoding?)?;
}
},
Ok(Event::Eof) => break,
Ok(_) => {},
Err(e) => {
return Err(e.context(KbinErrorKind::InvalidState).into())
},
Event::Eof => break,
_ => {},
};
buf.clear();

View File

@ -6,7 +6,7 @@ use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::events::attributes::Attribute;
use crate::encoding_type::EncodingType;
use crate::error::{KbinError, KbinErrorKind};
use crate::error::KbinError;
use crate::node::NodeCollection;
use crate::node_types::StandardType;
use crate::to_text_xml::ToTextXml;
@ -20,21 +20,19 @@ impl ToTextXml for NodeCollection {
fn write<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), KbinError> {
let base = self.base();
let key = base.key()?.ok_or(KbinErrorKind::InvalidState)?;
let key = base.key()?.ok_or(KbinError::InvalidState)?;
let value = match base.value() {
Ok(value) => Some(value),
Err(e) => {
match e.get_context() {
KbinErrorKind::InvalidNodeType(_) => None,
_ => return Err(e),
}
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(KbinErrorKind::InvalidState)?.as_array()?;
let values = value.as_ref().ok_or(KbinError::InvalidState)?.as_array()?;
elem.push_attribute(Attribute {
key: b"__count",
@ -43,7 +41,7 @@ impl ToTextXml for NodeCollection {
}
if base.node_type == StandardType::Binary {
let value = value.as_ref().ok_or(KbinErrorKind::InvalidState)?.as_slice()?;
let value = value.as_ref().ok_or(KbinError::InvalidState)?.as_slice()?;
elem.push_attribute(Attribute {
key: b"__size",
@ -60,7 +58,7 @@ impl ToTextXml for NodeCollection {
}
for attribute in self.attributes() {
let key = attribute.key()?.ok_or(KbinErrorKind::InvalidState)?.into_bytes();
let key = attribute.key()?.ok_or(KbinError::InvalidState)?.into_bytes();
let value = attribute.value()?.to_string();
let value = BytesText::from_plain_str(&value);

View File

@ -3,16 +3,16 @@ use std::net::Ipv4Addr;
use byteorder::ReadBytesExt;
use bytes::{BigEndian, BufMut};
use failure::ResultExt;
use snafu::ResultExt;
use crate::error::{KbinError, KbinErrorKind};
use crate::error::*;
pub trait IntoKbinBytes {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B);
}
pub trait FromKbinBytes: Sized {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError>;
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self>;
}
impl IntoKbinBytes for i8 {
@ -22,8 +22,8 @@ impl IntoKbinBytes for i8 {
}
impl FromKbinBytes for i8 {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
input.read_i8().context(KbinErrorKind::DataConvert).map_err(Into::into)
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
input.read_i8().context(DataConvert)
}
}
@ -34,8 +34,8 @@ impl IntoKbinBytes for u8 {
}
impl FromKbinBytes for u8 {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
input.read_u8().context(KbinErrorKind::DataConvert).map_err(Into::into)
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
input.read_u8().context(DataConvert)
}
}
@ -46,11 +46,11 @@ impl IntoKbinBytes for bool {
}
impl FromKbinBytes for bool {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
match u8::from_kbin_bytes(input)? {
0x00 => Ok(false),
0x01 => Ok(true),
input => Err(KbinErrorKind::InvalidBooleanInput(input).into()),
input => Err(KbinError::InvalidBooleanInput { input }),
}
}
}
@ -70,9 +70,9 @@ impl IntoKbinBytes for Ipv4Addr {
}
impl FromKbinBytes for Ipv4Addr {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
let mut octets = [0; 4];
input.read_exact(&mut octets).context(KbinErrorKind::DataConvert)?;
input.read_exact(&mut octets).context(DataConvert)?;
Ok(Ipv4Addr::from(octets))
}
@ -90,8 +90,8 @@ macro_rules! multibyte_impl {
}
impl FromKbinBytes for $type {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
input.$read_method::<BigEndian>().context(KbinErrorKind::DataConvert).map_err(Into::into)
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
input.$read_method::<BigEndian>().context(DataConvert)
}
}
)*
@ -117,9 +117,9 @@ macro_rules! tuple_impl {
}
impl FromKbinBytes for [i8; $i8_count] {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
let mut values = Self::default();
input.read_i8_into(&mut values).context(KbinErrorKind::DataConvert)?;
input.read_i8_into(&mut values).context(DataConvert)?;
Ok(values)
}
@ -133,9 +133,9 @@ macro_rules! tuple_impl {
}
impl FromKbinBytes for [u8; $u8_count] {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
let mut values = Self::default();
input.read_exact(&mut values).context(KbinErrorKind::DataConvert)?;
input.read_exact(&mut values).context(DataConvert)?;
Ok(values)
}
@ -151,7 +151,7 @@ macro_rules! tuple_impl {
}
impl FromKbinBytes for [bool; $bool_count] {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
let mut values = Self::default();
for i in 0..$bool_count {
@ -173,9 +173,9 @@ macro_rules! tuple_impl {
}
impl FromKbinBytes for [$type; $count] {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
let mut values = Self::default();
input.$read_method::<BigEndian>(&mut values).context(KbinErrorKind::DataConvert)?;
input.$read_method::<BigEndian>(&mut values).context(DataConvert)?;
Ok(values)
}

View File

@ -1,65 +1,66 @@
use std::error::Error;
use std::net::Ipv4Addr;
use std::str::FromStr;
use failure::{Fail, ResultExt};
use snafu::ResultExt;
use crate::error::{KbinError, KbinErrorKind};
use crate::error::*;
pub trait FromKbinString: Sized {
fn from_kbin_string(input: &str) -> Result<Self, KbinError>;
fn from_kbin_string(input: &str) -> Result<Self>;
}
fn space_check(input: &str) -> Result<(), KbinError> {
fn space_check(input: &str) -> Result<()> {
// check for space character
if input.find(' ').is_some() {
return Err(KbinErrorKind::InvalidState.into());
return Err(KbinError::InvalidState.into());
}
Ok(())
}
fn parse_tuple<T>(node_type: &'static str, input: &str, output: &mut [T]) -> Result<(), KbinError>
fn parse_tuple<T>(node_type: &'static str, input: &str, output: &mut [T]) -> Result<()>
where T: FromStr,
T::Err: Fail
T::Err: Error + 'static,
{
let count = input.split(' ').count();
if count != output.len() {
return Err(KbinErrorKind::SizeMismatch(node_type, output.len(), count).into());
return Err(KbinError::SizeMismatch { node_type, expected: output.len(), actual: count });
}
for (i, part) in input.split(' ').enumerate() {
output[i] = part.parse::<T>().context(KbinErrorKind::StringParse(node_type))?;
output[i] = part.parse::<T>().map_err(|e| Box::new(e) as Box<dyn Error>).context(StringParse { node_type })?;
}
Ok(())
}
impl FromKbinString for bool {
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
fn from_kbin_string(input: &str) -> Result<Self> {
match input {
"false" |
"0" => Ok(false),
"true" |
"1" => Ok(true),
input => Err(KbinErrorKind::InvalidBooleanInput(u8::from_kbin_string(input)?).into()),
input => Err(KbinError::InvalidBooleanInput { input: u8::from_kbin_string(input)? }),
}
}
}
impl FromKbinString for Ipv4Addr {
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
fn from_kbin_string(input: &str) -> Result<Self> {
space_check(input)?;
let count = input.split('.').count();
if count != 4 {
return Err(KbinErrorKind::SizeMismatch("Ipv4Addr", 4, count).into());
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::<u8>().context(KbinErrorKind::StringParse("Ipv4Addr"))?;
octets[i] = part.parse::<u8>().context(StringParseInt { node_type: "Ipv4Addr" })?;
}
Ok(Ipv4Addr::from(octets))
@ -72,17 +73,15 @@ macro_rules! basic_int_parse {
) => {
$(
impl FromKbinString for $type {
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
fn from_kbin_string(input: &str) -> Result<Self> {
space_check(input)?;
if input.starts_with("0x") {
<$type>::from_str_radix(&input[2..], 16)
.context(KbinErrorKind::StringParse(stringify!($type)))
.map_err(Into::into)
.context(StringParseInt { node_type: stringify!($type) })
} else {
input.parse::<$type>()
.context(KbinErrorKind::StringParse(stringify!($type)))
.map_err(Into::into)
.context(StringParseInt { node_type: stringify!($type) })
}
}
}
@ -96,12 +95,11 @@ macro_rules! basic_float_parse {
) => {
$(
impl FromKbinString for $type {
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
fn from_kbin_string(input: &str) -> Result<Self> {
space_check(input)?;
input.parse::<$type>()
.context(KbinErrorKind::StringParse(stringify!($type)))
.map_err(Into::into)
.context(StringParseFloat { node_type: stringify!($type) })
}
}
)*
@ -117,12 +115,12 @@ macro_rules! tuple_parse {
) => {
$(
impl FromKbinString for [bool; $bool_count] {
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
fn from_kbin_string(input: &str) -> Result<Self> {
const TYPE_NAME: &'static str = concat!("[bool; ", stringify!($bool_count), "]");
let count = input.split(' ').count();
if count != $bool_count {
return Err(KbinErrorKind::SizeMismatch(TYPE_NAME, $bool_count, count).into());
return Err(KbinError::SizeMismatch { node_type: TYPE_NAME, expected: $bool_count, actual: count });
}
let mut value = Self::default();
@ -138,7 +136,7 @@ macro_rules! tuple_parse {
$(
$(
impl FromKbinString for [$type; $count] {
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
fn from_kbin_string(input: &str) -> Result<Self> {
let mut value = Self::default();
parse_tuple(concat!("[", stringify!($type), "; ", stringify!($count), "]"), input, &mut value)?;

View File

@ -1,12 +1,8 @@
//use std::convert::TryFrom;
use std::fmt;
use std::io::Cursor;
use std::net::Ipv4Addr;
//use std::str::FromStr;
//use rustc_hex::FromHex;
use crate::error::{KbinError, KbinErrorKind};
use crate::error::KbinError;
use crate::node_types::StandardType;
use crate::types::{FromKbinBytes, IntoKbinBytes};
use crate::types::FromKbinString;
@ -75,7 +71,7 @@ macro_rules! type_impl {
// Prevent reading incomplete input data
if node_size * len != input.len() {
return Err(KbinErrorKind::SizeMismatch(node_type.name, node_size, input.len()).into());
return Err(KbinError::SizeMismatch { node_type: node_type.name, expected: node_size, actual: input.len() });
}
let mut reader = Cursor::new(input);
@ -136,7 +132,7 @@ macro_rules! type_impl {
StandardType::Attribute |
StandardType::Binary |
StandardType::String |
StandardType::Time => return Err(KbinErrorKind::InvalidState.into()),
StandardType::Time => return Err(KbinError::InvalidState.into()),
$(
StandardType::$konst => {
let mut values = Vec::new();

View File

@ -3,10 +3,10 @@ use std::fmt;
use std::io::Cursor;
use std::net::Ipv4Addr;
use failure::ResultExt;
use rustc_hex::FromHex;
use snafu::ResultExt;
use crate::error::{KbinError, KbinErrorKind};
use crate::error::*;
use crate::node_types::StandardType;
use crate::types::{FromKbinBytes, FromKbinString, IntoKbinBytes};
@ -42,10 +42,15 @@ macro_rules! construct_types {
impl TryFrom<Value> for $($value_type)* {
type Error = KbinError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
fn try_from(value: Value) -> Result<Self> {
match value {
Value::$konst(v) => Ok(v),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::$konst, value).into()),
value => {
Err(KbinError::ValueTypeMismatch {
node_type: StandardType::$konst,
value,
})
},
}
}
}
@ -53,10 +58,15 @@ macro_rules! construct_types {
impl TryFrom<&Value> for $($value_type)* {
type Error = KbinError;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
fn try_from(value: &Value) -> Result<Self> {
match value {
Value::$konst(ref v) => Ok(v.clone()),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::$konst, value.clone()).into()),
value => {
Err(KbinError::ValueTypeMismatch {
node_type: StandardType::$konst,
value: value.clone(),
})
},
}
}
}
@ -82,13 +92,13 @@ macro_rules! tuple {
(
$($konst:ident),*$(,)?
) => {
pub fn from_standard_type(node_type: StandardType, is_array: bool, input: &[u8]) -> Result<Option<Value>, KbinError> {
pub fn from_standard_type(node_type: StandardType, is_array: bool, input: &[u8]) -> Result<Option<Value>> {
let node_size = node_type.size * node_type.count;
if is_array {
let value = match ValueArray::from_standard_type(node_type, input)? {
Some(value) => value,
None => return Err(KbinErrorKind::InvalidState.into()),
None => return Err(KbinError::InvalidState),
};
debug!("Value::from_standard_type({:?}) input: 0x{:02x?} => {:?}", node_type, input, value);
@ -100,7 +110,7 @@ macro_rules! tuple {
StandardType::Binary => {},
_ => {
if input.len() != node_size {
return Err(KbinErrorKind::SizeMismatch(node_type.name, node_size, input.len()).into());
return Err(KbinError::SizeMismatch { node_type: node_type.name, expected: node_size, actual: input.len() });
}
},
};
@ -138,12 +148,12 @@ macro_rules! tuple {
Ok(Some(value))
}
pub fn from_string(node_type: StandardType, input: &str, is_array: bool, arr_count: usize) -> Result<Value, KbinError> {
pub fn from_string(node_type: StandardType, input: &str, is_array: bool, arr_count: usize) -> Result<Value> {
trace!("Value::from_string({:?}, is_array: {}, arr_count: {}) => input: {:?}", node_type, is_array, arr_count, input);
if is_array {
let value = match node_type.count {
0 => return Err(KbinErrorKind::InvalidState.into()),
0 => return Err(KbinError::InvalidState.into()),
count => Value::Array(ValueArray::from_string(node_type, count, input, arr_count)?),
};
debug!("Value::from_string({:?}) input: {:?} => {:?}", node_type, input, value);
@ -154,7 +164,7 @@ macro_rules! tuple {
let value = match node_type {
StandardType::NodeStart |
StandardType::NodeEnd |
StandardType::FileEnd => return Err(KbinErrorKind::InvalidNodeType(node_type).into()),
StandardType::FileEnd => return Err(KbinError::InvalidNodeType { node_type }),
StandardType::S8 => i8::from_kbin_string(input).map(Value::S8)?,
StandardType::U8 => u8::from_kbin_string(input).map(Value::U8)?,
StandardType::S16 => i16::from_kbin_string(input).map(Value::S16)?,
@ -164,7 +174,7 @@ macro_rules! tuple {
StandardType::S64 => i64::from_kbin_string(input).map(Value::S64)?,
StandardType::U64 => u64::from_kbin_string(input).map(Value::U64)?,
StandardType::Binary => {
let data: Vec<u8> = input.from_hex().context(KbinErrorKind::HexError)?;
let data: Vec<u8> = input.from_hex().context(HexError)?;
Value::Binary(data)
},
StandardType::String => Value::String(input.to_owned()),
@ -183,7 +193,7 @@ macro_rules! tuple {
Ok(value)
}
fn to_bytes_inner(&self, output: &mut Vec<u8>) -> Result<(), KbinError> {
fn to_bytes_inner(&self, output: &mut Vec<u8>) -> Result<()> {
debug!("Value::to_bytes_inner(self: {:?})", self);
match self {
@ -203,7 +213,7 @@ macro_rules! tuple {
Value::Boolean(v) => v.write_kbin_bytes(output),
Value::Array(value) => value.to_bytes_into(output)?,
Value::Attribute(_) |
Value::String(_) => return Err(KbinErrorKind::InvalidNodeType(self.standard_type()).into()),
Value::String(_) => return Err(KbinError::InvalidNodeType { node_type: self.standard_type() }),
$(
Value::$konst(value) => {
output.reserve(value.len() * StandardType::$konst.size);
@ -232,7 +242,7 @@ impl Value {
Double2, Double3, Double4,
}
pub fn to_bytes(&self) -> Result<Vec<u8>, KbinError> {
pub fn to_bytes(&self) -> Result<Vec<u8>> {
let mut output = Vec::new();
self.to_bytes_inner(&mut output)?;
@ -240,112 +250,112 @@ impl Value {
}
#[inline]
pub fn to_bytes_into(&self, output: &mut Vec<u8>) -> Result<(), KbinError> {
pub fn to_bytes_into(&self, output: &mut Vec<u8>) -> Result<()> {
self.to_bytes_inner(output)
}
pub fn as_i8(&self) -> Result<i8, KbinError> {
pub fn as_i8(&self) -> Result<i8> {
match self {
Value::S8(ref n) => Ok(*n),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::S8, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S8, value: value.clone() }),
}
}
pub fn as_u8(&self) -> Result<u8, KbinError> {
pub fn as_u8(&self) -> Result<u8> {
match self {
Value::U8(ref n) => Ok(*n),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::U8, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U8, value: value.clone() }),
}
}
pub fn as_i16(&self) -> Result<i16, KbinError> {
pub fn as_i16(&self) -> Result<i16> {
match self {
Value::S16(ref n) => Ok(*n),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::S16, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S16, value: value.clone() }),
}
}
pub fn as_u16(&self) -> Result<u16, KbinError> {
pub fn as_u16(&self) -> Result<u16> {
match self {
Value::U16(ref n) => Ok(*n),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::U16, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U16, value: value.clone() }),
}
}
pub fn as_i32(&self) -> Result<i32, KbinError> {
pub fn as_i32(&self) -> Result<i32> {
match self {
Value::S32(ref n) => Ok(*n),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::S32, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S32, value: value.clone() }),
}
}
pub fn as_u32(&self) -> Result<u32, KbinError> {
pub fn as_u32(&self) -> Result<u32> {
match self {
Value::U32(ref n) => Ok(*n),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::U32, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U32, value: value.clone() }),
}
}
pub fn as_i64(&self) -> Result<i64, KbinError> {
pub fn as_i64(&self) -> Result<i64> {
match self {
Value::S64(ref n) => Ok(*n),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::S64, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S64, value: value.clone() }),
}
}
pub fn as_u64(&self) -> Result<u64, KbinError> {
pub fn as_u64(&self) -> Result<u64> {
match self {
Value::U64(ref n) => Ok(*n),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::U64, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U64, value: value.clone() }),
}
}
pub fn as_slice(&self) -> Result<&[u8], KbinError> {
pub fn as_slice(&self) -> Result<&[u8]> {
match self {
Value::Binary(ref data) => Ok(data),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::Binary, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value: value.clone() }),
}
}
pub fn as_str(&self) -> Result<&str, KbinError> {
pub fn as_str(&self) -> Result<&str> {
match self {
Value::String(ref s) => Ok(s),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::String, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::String, value: value.clone() }),
}
}
pub fn as_string(self) -> Result<String, KbinError> {
pub fn as_string(self) -> Result<String> {
match self {
Value::String(s) => Ok(s),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::String, value).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::String, value }),
}
}
pub fn as_attribute(self) -> Result<String, KbinError> {
pub fn as_attribute(self) -> Result<String> {
match self {
Value::Attribute(s) => Ok(s),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::Attribute, value).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Attribute, value }),
}
}
pub fn as_binary(&self) -> Result<&[u8], KbinError> {
pub fn as_binary(&self) -> Result<&[u8]> {
match self {
Value::Binary(ref data) => Ok(data),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::Binary, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value: value.clone() }),
}
}
pub fn as_array(&self) -> Result<&ValueArray, KbinError> {
pub fn as_array(&self) -> Result<&ValueArray> {
match self {
Value::Array(ref values) => Ok(values),
value => Err(KbinErrorKind::ExpectedValueArray(value.clone()).into()),
value => Err(KbinError::ExpectedValueArray { value: value.clone() }),
}
}
pub fn into_binary(self) -> Result<Vec<u8>, KbinError> {
pub fn into_binary(self) -> Result<Vec<u8>> {
match self {
Value::Binary(data) => Ok(data),
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::Binary, value).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value }),
}
}
}
@ -357,7 +367,7 @@ impl TryFrom<Value> for Vec<Value> {
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Array(values) => Ok(values),
value => Err(KbinErrorKind::ExpectedValueArray(value).into()),
value => Err(KbinError::ExpectedValueArray(value).into()),
}
}
}
@ -366,16 +376,16 @@ impl TryFrom<Value> for Vec<Value> {
impl TryFrom<Value> for Vec<u8> {
type Error = KbinError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
fn try_from(value: Value) -> Result<Self> {
// 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(KbinErrorKind::ValueTypeMismatch(StandardType::U8, Value::Array(values)).into()),
values => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U8, value: Value::Array(values) }),
},
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::Binary, value).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value }),
}
}
}
@ -383,14 +393,14 @@ impl TryFrom<Value> for Vec<u8> {
impl TryFrom<&Value> for Vec<u8> {
type Error = KbinError;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
fn try_from(value: &Value) -> Result<Self> {
match value {
Value::Binary(ref data) => Ok(data.to_vec()),
Value::Array(ref values) => match values.clone() {
ValueArray::U8(values) => Ok(values),
values => Err(KbinErrorKind::ValueTypeMismatch(StandardType::U8, Value::Array(values)).into()),
values => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U8, value: Value::Array(values) }),
},
value => Err(KbinErrorKind::ValueTypeMismatch(StandardType::Binary, value.clone()).into()),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value: value.clone() }),
}
}
}

View File

@ -1,11 +1,11 @@
use std::io::{Cursor, Write};
use byteorder::{BigEndian, WriteBytesExt};
use failure::ResultExt;
use snafu::ResultExt;
use crate::byte_buffer::ByteBufferWrite;
use crate::compression::Compression;
use crate::error::{KbinErrorKind, Result};
use crate::error::*;
use crate::node::{Node, NodeCollection};
use crate::node_types::StandardType;
use crate::options::Options;
@ -20,8 +20,8 @@ fn write_value(options: &Options, data_buf: &mut ByteBufferWrite, node_type: Sta
trace!("data: 0x{:02x?}", data);
let size = (data.len() as u32) * (node_type.size as u32);
data_buf.write_u32::<BigEndian>(size).context(KbinErrorKind::DataWrite("binary node size"))?;
data_buf.write_all(&data).context(KbinErrorKind::DataWrite("binary"))?;
data_buf.write_u32::<BigEndian>(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) => {
@ -29,7 +29,7 @@ fn write_value(options: &Options, data_buf: &mut ByteBufferWrite, node_type: Sta
},
Value::Array(values) => {
if !is_array {
return Err(KbinErrorKind::InvalidState.into());
return Err(KbinError::InvalidState);
}
let total_size = values.len() * node_type.count * node_type.size;
@ -37,13 +37,13 @@ fn write_value(options: &Options, data_buf: &mut ByteBufferWrite, node_type: Sta
let mut data = Vec::with_capacity(total_size);
values.to_bytes_into(&mut data)?;
data_buf.write_u32::<BigEndian>(total_size as u32).context(KbinErrorKind::DataWrite("node size"))?;
data_buf.write_all(&data).context(KbinErrorKind::DataWrite(node_type.name))?;
data_buf.write_u32::<BigEndian>(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(KbinErrorKind::InvalidState.into());
return Err(KbinError::InvalidState);
} else {
let data = value.to_bytes()?;
data_buf.write_aligned(*node_type, &data)?;
@ -62,7 +62,7 @@ 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(KbinErrorKind::InvalidState)?;
let name = self.base().key()?.ok_or(KbinError::InvalidState)?;
debug!("NodeCollection write_node => name: {}, type: {:?}, type_size: {}, type_count: {}, is_array: {}",
name,
@ -71,14 +71,14 @@ impl Writeable for NodeCollection {
node_type.count,
is_array);
node_buf.write_u8(node_type as u8 | array_mask).context(KbinErrorKind::DataWrite(node_type.name))?;
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(KbinErrorKind::DataWrite("node name length"))?;
node_buf.write_all(&data).context(KbinErrorKind::DataWrite("node name bytes"))?;
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" })?;
},
};
@ -88,21 +88,21 @@ impl Writeable for NodeCollection {
}
for attr in self.attributes() {
let key = attr.key()?.ok_or(KbinErrorKind::InvalidState)?;
let value = attr.value_bytes().ok_or(KbinErrorKind::InvalidState)?;
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(KbinErrorKind::DataWrite(StandardType::Attribute.name))?;
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(KbinErrorKind::DataWrite("attribute name length"))?;
node_buf.write_all(&data).context(KbinErrorKind::DataWrite("node name bytes"))?;
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" })?;
},
};
}
@ -112,7 +112,7 @@ impl Writeable for NodeCollection {
}
// node end always has the array bit set
node_buf.write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?;
node_buf.write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK).context(DataWrite { node_type: "node end" })?;
Ok(())
}
@ -134,14 +134,14 @@ impl Writeable for Node {
node_type.count,
is_array);
node_buf.write_u8(node_type as u8 | array_mask).context(KbinErrorKind::DataWrite(node_type.name))?;
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(KbinErrorKind::DataWrite("node name length"))?;
node_buf.write_all(&data).context(KbinErrorKind::DataWrite("node name bytes"))?;
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" })?;
},
};
@ -155,14 +155,14 @@ impl Writeable for Node {
data_buf.write_str(options.encoding, value)?;
node_buf.write_u8(StandardType::Attribute as u8).context(KbinErrorKind::DataWrite(StandardType::Attribute.name))?;
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(KbinErrorKind::DataWrite("attribute name length"))?;
node_buf.write_all(&data).context(KbinErrorKind::DataWrite("node name bytes"))?;
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" })?;
},
};
}
@ -175,7 +175,7 @@ impl Writeable for Node {
}
// node end always has the array bit set
node_buf.write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?;
node_buf.write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK).context(DataWrite { node_type: "node end" })?;
Ok(())
}
@ -202,33 +202,33 @@ impl Writer {
where T: Writeable
{
let mut header = Cursor::new(Vec::with_capacity(8));
header.write_u8(SIGNATURE).context(KbinErrorKind::HeaderWrite("signature"))?;
header.write_u8(SIGNATURE).context(HeaderWrite { field: "signature" })?;
let compression = self.options.compression.to_byte();
header.write_u8(compression).context(KbinErrorKind::HeaderWrite("compression"))?;
header.write_u8(compression).context(HeaderWrite { field: "compression" })?;
let encoding = self.options.encoding.to_byte();
header.write_u8(encoding).context(KbinErrorKind::HeaderWrite("encoding"))?;
header.write_u8(0xFF ^ encoding).context(KbinErrorKind::HeaderWrite("encoding negation"))?;
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());
input.write_node(&self.options, &mut node_buf, &mut data_buf)?;
node_buf.write_u8(StandardType::FileEnd as u8 | ARRAY_MASK).context(KbinErrorKind::DataWrite("file end"))?;
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 node_buf = node_buf.into_inner();
debug!("to_binary_internal => node_buf len: {0} (0x{0:x})", node_buf.len());
output.write_u32::<BigEndian>(node_buf.len() as u32).context(KbinErrorKind::HeaderWrite("node buffer length"))?;
output.write_u32::<BigEndian>(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::<BigEndian>(data_buf.len() as u32).context(KbinErrorKind::HeaderWrite("data buffer length"))?;
output.write_u32::<BigEndian>(data_buf.len() as u32).context(HeaderWrite { field: "data buffer length" })?;
output.extend_from_slice(&data_buf);
Ok(output)