mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-04-24 06:57:15 -05:00
error: replace failure with snafu
This commit is contained in:
parent
8be89649f3
commit
a840cc63fa
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
291
src/error.rs
291
src/error.rs
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 })
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
117
src/reader.rs
117
src/reader.rs
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
118
src/value/mod.rs
118
src/value/mod.rs
|
|
@ -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() }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user