lib: convert remaining functions to use failure

This commit is contained in:
Matt Bilker
2018-06-02 05:56:40 +00:00
parent db020e0192
commit e3d00de2c1
6 changed files with 133 additions and 55 deletions

View File

@@ -1,3 +1,5 @@
use error::{KbinError, KbinErrorKind};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Compression {
Compressed,
@@ -5,11 +7,11 @@ pub enum Compression {
}
impl Compression {
pub fn from_byte(byte: u8) -> Option<Self> {
pub fn from_byte(byte: u8) -> Result<Self, KbinError> {
match byte {
0x42 => Some(Compression::Compressed),
0x45 => Some(Compression::Uncompressed),
_ => None,
0x42 => Ok(Compression::Compressed),
0x45 => Ok(Compression::Uncompressed),
_ => Err(KbinErrorKind::UnknownCompression.into()),
}
}

View File

@@ -1,3 +1,5 @@
use error::{KbinError, KbinErrorKind};
use encoding::{DecoderTrap, Encoding};
use encoding::all::{ASCII, EUC_JP, ISO_8859_1, WINDOWS_31J};
@@ -25,7 +27,7 @@ impl EncodingType {
}
}
pub fn from_byte(byte: u8) -> Option<Self> {
pub fn from_byte(byte: u8) -> Result<Self, KbinError> {
let val = match byte {
0x00 => EncodingType::None,
0x20 => EncodingType::ASCII,
@@ -33,29 +35,31 @@ impl EncodingType {
0x60 => EncodingType::EUC_JP,
0x80 => EncodingType::SHIFT_JIS,
0xA0 => EncodingType::UTF_8,
_ => return None,
_ => return Err(KbinErrorKind::UnknownEncoding.into()),
};
Some(val)
Ok(val)
}
/// Decode bytes using the encoding definition from the `encoding` crate.
///
/// A `Some` value indicates an encoding should be used from the `encoding`
/// crate. A `None` value indicates Rust's own UTF-8 handling should be used.
pub fn decode_bytes(&self, input: Vec<u8>) -> String {
const DECODER_FAIL: &str = "Unable to interpret string as alternate encoding";
pub fn decode_bytes(&self, input: Vec<u8>) -> Result<String, KbinError> {
let decoder_fail = |e| {
format_err!("{}", e).context(KbinErrorKind::EncodingDecode)
};
match *self {
let result = match *self {
EncodingType::None |
EncodingType::UTF_8 => {
String::from_utf8(input).expect("Unable to interpret string as UTF-8")
},
EncodingType::UTF_8 => String::from_utf8(input)?,
EncodingType::ASCII => ASCII.decode(&input, DecoderTrap::Strict).expect(DECODER_FAIL),
EncodingType::ISO_8859_1 => ISO_8859_1.decode(&input, DecoderTrap::Strict).expect(DECODER_FAIL),
EncodingType::EUC_JP => EUC_JP.decode(&input, DecoderTrap::Strict).expect(DECODER_FAIL),
EncodingType::SHIFT_JIS => WINDOWS_31J.decode(&input, DecoderTrap::Strict).expect(DECODER_FAIL),
}
EncodingType::ASCII => ASCII.decode(&input, DecoderTrap::Strict).map_err(decoder_fail)?,
EncodingType::ISO_8859_1 => ISO_8859_1.decode(&input, DecoderTrap::Strict).map_err(decoder_fail)?,
EncodingType::EUC_JP => EUC_JP.decode(&input, DecoderTrap::Strict).map_err(decoder_fail)?,
EncodingType::SHIFT_JIS => WINDOWS_31J.decode(&input, DecoderTrap::Strict).map_err(decoder_fail)?,
};
Ok(result)
}
}

View File

@@ -1,4 +1,5 @@
use std::fmt;
use std::string::FromUtf8Error;
use failure::{Backtrace, Context, Fail};
@@ -26,6 +27,54 @@ pub enum KbinErrorKind {
#[fail(display = "Unable to seek data buffer")]
Seek,
#[fail(display = "Unable to read signature byte")]
SignatureRead,
#[fail(display = "Unable to read compression byte")]
CompressionRead,
#[fail(display = "Unknown compression value")]
UnknownCompression,
#[fail(display = "Unable to read encoding byte")]
EncodingRead,
#[fail(display = "Unable to read encoding negation byte")]
EncodingNegationRead,
#[fail(display = "Unknown encoding")]
UnknownEncoding,
#[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 = "Failed to write {} to output string", _0)]
ByteParse(&'static str),
#[fail(display = "Unable to read sixbit string length")]
SixbitLengthRead,
#[fail(display = "Unable to read sixbit string content")]
SixbitRead,
#[fail(display = "Unable to interpret string as UTF-8")]
Utf8,
#[fail(display = "Unable to interpret string as alternate encoding")]
EncodingDecode,
}
impl fmt::Display for KbinError {
@@ -55,3 +104,9 @@ impl From<Context<KbinErrorKind>> for KbinError {
KbinError { inner }
}
}
impl From<FromUtf8Error> for KbinError {
fn from(inner: FromUtf8Error) -> KbinError {
inner.context(KbinErrorKind::Utf8).into()
}
}

View File

@@ -79,7 +79,7 @@ impl KbinXml {
data.truncate(index + 1);
trace!("data_buf_read_str => size: {}, data: 0x{:02x?}", data.len(), data);
Ok(encoding.decode_bytes(data))
encoding.decode_bytes(data)
}
fn data_buf_get(&mut self, data_buf: &mut Cursor<&[u8]>, size: u32) -> Result<Vec<u8>, KbinError> {
@@ -159,25 +159,25 @@ impl KbinXml {
// Data buffer starts later after reading `len_data`.
let mut node_buf = Cursor::new(&input[..]);
let signature = node_buf.read_u8().expect("Unable to read signature byte");
let signature = node_buf.read_u8().context(KbinErrorKind::SignatureRead)?;
assert_eq!(signature, SIGNATURE);
// TODO: support uncompressed
let compress_byte = node_buf.read_u8().expect("Unable to read compression byte");
let compress_byte = node_buf.read_u8().context(KbinErrorKind::CompressionRead)?;
assert_eq!(compress_byte, SIG_COMPRESSED);
let compressed = Compression::from_byte(compress_byte).expect("Unknown compression value");
let compressed = Compression::from_byte(compress_byte)?;
let encoding_byte = node_buf.read_u8().expect("Unable to read encoding byte");
let encoding_negation = node_buf.read_u8().expect("Unable to read encoding negation byte");
let encoding = EncodingType::from_byte(encoding_byte).expect("Unknown encoding");
let encoding_byte = node_buf.read_u8().context(KbinErrorKind::EncodingRead)?;
let encoding_negation = node_buf.read_u8().context(KbinErrorKind::EncodingNegationRead)?;
let encoding = EncodingType::from_byte(encoding_byte)?;
assert_eq!(encoding_negation, 0xFF ^ encoding_byte);
info!("signature: 0x{:x}", signature);
info!("compression: 0x{:x} ({:?})", compress_byte, compressed);
info!("encoding: 0x{:x} ({:?})", encoding_byte, encoding);
let len_node = node_buf.read_u32::<BigEndian>().expect("Unable to read len_node");
let len_node = node_buf.read_u32::<BigEndian>().context(KbinErrorKind::LenNodeRead)?;
info!("len_node: {} (0x{:x})", len_node, len_node);
// We have read 8 bytes so far, so offset the start of the data buffer from
@@ -192,14 +192,14 @@ impl KbinXml {
trace!("offset_1: {}, offset_2: {}", self.offset_1, self.offset_2);
}
let len_data = data_buf.read_u32::<BigEndian>().expect("Unable to read len_data");
let len_data = data_buf.read_u32::<BigEndian>().context(KbinErrorKind::LenDataRead)?;
info!("len_data: {} (0x{:x})", len_data, len_data);
let mut stack: Vec<Element> = Vec::new();
{
let node_buf_end = data_buf_start.into();
while node_buf.position() < node_buf_end {
let raw_node_type = node_buf.read_u8().expect("Unable to read node type");
let raw_node_type = node_buf.read_u8().context(KbinErrorKind::NodeTypeRead)?;
let is_array = raw_node_type & 64 == 64;
let node_type = raw_node_type & !64;
@@ -224,7 +224,7 @@ impl KbinXml {
_ => {},
};
let name = unpack_sixbit(&mut node_buf);
let name = unpack_sixbit(&mut node_buf)?;
if xml_type == KbinType::NodeStart {
stack.push(Element::bare(name));
@@ -256,10 +256,10 @@ impl KbinXml {
let type_size = xml_type.size();
let type_count = xml_type.count();
let (is_array, size) = if type_count == -1 {
(true, data_buf.read_u32::<BigEndian>().expect("Unable to read binary/string byte length"))
(true, data_buf.read_u32::<BigEndian>().context(KbinErrorKind::BinaryLengthRead)?)
} else if is_array {
let node_size = type_size * type_count;
let arr_count = data_buf.read_u32::<BigEndian>().expect("Unable to read array node length") / node_size as u32;
let arr_count = data_buf.read_u32::<BigEndian>().context(KbinErrorKind::ArrayLengthRead)? / node_size as u32;
to.set_attr("__count", arr_count);
let size = (node_size as u32) * arr_count;
@@ -296,7 +296,7 @@ impl KbinXml {
debug!("name: {}, string: {}", name, val);
to.append_text_node(val);
} else {
let inner_value = xml_type.parse_bytes(&data);
let inner_value = xml_type.parse_bytes(&data)?;
debug!("name: {}, string: {}", name, inner_value);
to.append_text_node(inner_value);
}

View File

@@ -1,20 +1,26 @@
use error::{KbinError, KbinErrorKind};
use std::fmt::Write;
use failure::ResultExt;
trait KbinWrapperType<T> {
fn from_kbin_bytes(output: &mut String, input: &[u8]);
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError>;
}
macro_rules! number_impl {
(integer; $($inner_type:ident),*) => {
$(
impl KbinWrapperType<$inner_type> for $inner_type {
fn from_kbin_bytes(output: &mut String, input: &[u8]) {
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
trace!("KbinWrapperType<{}> => input: {:02x?}", stringify!($inner_type), input);
let mut data = [0; ::std::mem::size_of::<$inner_type>()];
data.clone_from_slice(input);
write!(output, "{}", $inner_type::from_be($inner_type::from_bytes(data)))
.expect(concat!("Failed to write ", stringify!($inner_type), " to output string"));
.context(KbinErrorKind::ByteParse(stringify!($inner_type)))?;
Ok(())
}
}
)*
@@ -22,7 +28,7 @@ macro_rules! number_impl {
(float; $($intermediate:ident => $inner_type:ident),*) => {
$(
impl KbinWrapperType<$inner_type> for $inner_type {
fn from_kbin_bytes(output: &mut String, input: &[u8]) {
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
trace!("KbinWrapperType<{}> => input: {:02x?}", stringify!($inner_type), input);
let mut data = [0; ::std::mem::size_of::<$inner_type>()];
@@ -30,7 +36,9 @@ macro_rules! number_impl {
let bits = $intermediate::from_be($intermediate::from_bytes(data));
write!(output, "{:.6}", $inner_type::from_bits(bits))
.expect(concat!("Failed to write ", stringify!($inner_type), " to output string"));
.context(KbinErrorKind::ByteParse(stringify!($inner_type)))?;
Ok(())
}
}
)*
@@ -41,7 +49,7 @@ number_impl!(integer; i8, u8, i16, u16, i32, u32, i64, u64);
number_impl!(float; u32 => f32, u64 => f64);
impl KbinWrapperType<bool> for bool {
fn from_kbin_bytes(output: &mut String, input: &[u8]) {
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
trace!("KbinWrapperType<bool> => input: {:02x?}", input);
let value = match input[0] {
@@ -50,12 +58,14 @@ impl KbinWrapperType<bool> for bool {
v => panic!("Unsupported value for boolean: {}", v),
};
output.push_str(value);
Ok(())
}
}
struct Ip4;
impl KbinWrapperType<Ip4> for Ip4 {
fn from_kbin_bytes(output: &mut String, input: &[u8]) {
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
trace!("KbinWrapperType<Ip4> => input: {:02x?}", input);
if input.len() < 4 {
@@ -63,18 +73,20 @@ impl KbinWrapperType<Ip4> for Ip4 {
}
write!(output, "{}.{}.{}.{}", input[0], input[1], input[2], input[3])
.expect("Failed to write IP address to output string");
.context(KbinErrorKind::ByteParse("Ip4"))?;
Ok(())
}
}
struct DummyConverter;
impl KbinWrapperType<DummyConverter> for DummyConverter {
fn from_kbin_bytes(_output: &mut String, _input: &[u8]) {}
fn from_kbin_bytes(_output: &mut String, _input: &[u8]) -> Result<(), KbinError> { Ok(()) }
}
struct InvalidConverter;
impl KbinWrapperType<InvalidConverter> for InvalidConverter {
fn from_kbin_bytes(_output: &mut String, input: &[u8]) {
fn from_kbin_bytes(_output: &mut String, input: &[u8]) -> Result<(), KbinError> {
panic!("Invalid kbin type converter called for input: {:02x?}", input);
}
}
@@ -135,12 +147,12 @@ macro_rules! construct_types {
}
}
fn parse_array<T>(output: &mut String, input: &[u8], size: usize, count: usize, arr_count: usize)
fn parse_array<T>(output: &mut String, input: &[u8], size: usize, count: usize, arr_count: usize) -> Result<(), KbinError>
where T: KbinWrapperType<T>
{
{
let first = &input[..size];
T::from_kbin_bytes(output, first);
T::from_kbin_bytes(output, first)?;
}
let total_nodes = count * arr_count;
@@ -149,11 +161,13 @@ macro_rules! construct_types {
let end = (i + 1) * size;
let data = &input[offset..end];
output.push(' ');
T::from_kbin_bytes(output, data);
T::from_kbin_bytes(output, data)?;
}
Ok(())
}
fn parse_bytes_inner<T>(&self, input: &[u8], name: &str, size: u8, count: i8) -> String
fn parse_bytes_inner<T>(&self, input: &[u8], name: &str, size: u8, count: i8) -> Result<String, KbinError>
where T: KbinWrapperType<T>
{
let type_size = (size as usize) * (count as usize);
@@ -170,20 +184,20 @@ macro_rules! construct_types {
// May have a node (i.e. Ip4) that is only a single count, but it
// can be part of an array
if arr_count == 1 {
T::from_kbin_bytes(&mut result, input);
T::from_kbin_bytes(&mut result, input)?;
} else {
Self::parse_array::<T>(&mut result, input, size as usize, count as usize, arr_count);
Self::parse_array::<T>(&mut result, input, size as usize, count as usize, arr_count)?;
}
} else if count > 1 {
Self::parse_array::<T>(&mut result, input, size as usize, count as usize, arr_count);
Self::parse_array::<T>(&mut result, input, size as usize, count as usize, arr_count)?;
} else {
unimplemented!();
}
result
Ok(result)
}
pub fn parse_bytes(&self, input: &[u8]) -> String {
pub fn parse_bytes(&self, input: &[u8]) -> Result<String, KbinError> {
match *self {
$(
KbinType::$konst => self.parse_bytes_inner::<$inner_type>(input, $name, $size, $count),

View File

@@ -2,8 +2,11 @@ use std::collections::HashMap;
use std::io::{Read, Write};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use failure::ResultExt;
use num::{BigUint, FromPrimitive, ToPrimitive};
use error::{KbinError, KbinErrorKind};
static CHAR_MAP: &'static [u8] = b"0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
lazy_static! {
@@ -42,10 +45,10 @@ pub fn pack_sixbit<T>(writer: &mut T, input: &str)
writer.write_uint::<BigEndian>(bits, (input.len() * 6 + padding) / 8).expect("Unable to write sixbit contents");
}
pub fn unpack_sixbit<T>(reader: &mut T) -> String
pub fn unpack_sixbit<T>(reader: &mut T) -> Result<String, KbinError>
where T: Read
{
let len = reader.read_u8().expect("Unable to read sixbit string length");
let len = reader.read_u8().context(KbinErrorKind::SixbitLengthRead)?;
let real_len = (f32::from(len * 6) / 8f32).ceil();
let real_len = (real_len as u32) as usize;
let padding = (8 - ((len * 6) % 8)) as usize;
@@ -53,7 +56,7 @@ pub fn unpack_sixbit<T>(reader: &mut T) -> String
debug!("sixbit_len: {}, real_len: {}, padding: {}", len, real_len, padding);
let mut buf = vec![0; real_len];
reader.read_exact(&mut buf).expect("Unable to read sixbit string content");
reader.read_exact(&mut buf).context(KbinErrorKind::SixbitRead)?;
let bits = BigUint::from_bytes_be(&buf);
let bits = bits >> padding;
@@ -76,5 +79,5 @@ pub fn unpack_sixbit<T>(reader: &mut T) -> String
}).collect();
debug!("result: {}", result);
result
Ok(result)
}