text_reader: add custom error type

This commit is contained in:
Matt Bilker
2019-11-09 08:20:20 +00:00
parent d0c6192057
commit 3b9c1ae079
2 changed files with 127 additions and 67 deletions

View File

@@ -1,10 +1,7 @@
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 quick_xml::Error as QuickXmlError;
use rustc_hex::FromHexError;
@@ -12,9 +9,10 @@ use snafu::Snafu;
use crate::byte_buffer::ByteBufferError;
use crate::encoding_type::EncodingError;
use crate::node_types::{StandardType, UnknownKbinType};
use crate::node_types::StandardType;
use crate::reader::ReaderError;
use crate::sixbit::SixbitError;
use crate::text_reader::TextReaderError;
use crate::value::Value;
use crate::writer::WriterError;
@@ -23,28 +21,12 @@ pub type Result<T> = StdResult<T, KbinError>;
#[derive(Debug, Snafu)]
#[snafu(visibility = "pub(crate)")]
pub enum KbinError {
#[snafu(display("Unable to write {} header field", field))]
HeaderWrite {
field: &'static str,
source: io::Error,
},
#[snafu(display("Unable to read bytes or not enough data read"))]
DataConvert { source: io::Error },
#[snafu(display("No node collection found"))]
NoNodeCollection,
#[snafu(display("Failed to interpret string as UTF-8"))]
Utf8 { source: FromUtf8Error },
#[snafu(display("Failed to interpret slice as UTF-8"))]
Utf8Slice { source: Utf8Error },
// TODO(felix): remove when text reader has own error type
#[snafu(display("Invalid kbin type read"))]
InvalidKbinType { source: UnknownKbinType },
#[snafu(display(
"Size Mismatch, type: {}, expected size: {}, actual size: {}",
node_type,
@@ -114,6 +96,12 @@ pub enum KbinError {
source: EncodingError,
},
#[snafu(display("Failed to handle sixbit string operation"))]
Sixbit {
#[snafu(backtrace)]
source: SixbitError,
},
#[snafu(display("Failed to read binary XML"))]
Reader {
#[snafu(backtrace)]
@@ -126,30 +114,16 @@ pub enum KbinError {
source: WriterError,
},
#[snafu(display("Failed to handle sixbit string operation"))]
Sixbit {
#[snafu(display("Failed to read text XML"))]
TextReader {
#[snafu(backtrace)]
source: SixbitError,
source: TextReaderError,
},
#[snafu(display("Error handling XML"))]
XmlError { source: QuickXmlError },
}
impl From<FromUtf8Error> for KbinError {
#[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 {
@@ -164,6 +138,13 @@ impl From<EncodingError> for KbinError {
}
}
impl From<SixbitError> for KbinError {
#[inline]
fn from(source: SixbitError) -> Self {
KbinError::Sixbit { source }
}
}
impl From<ReaderError> for KbinError {
#[inline]
fn from(source: ReaderError) -> Self {
@@ -178,10 +159,10 @@ impl From<WriterError> for KbinError {
}
}
impl From<SixbitError> for KbinError {
impl From<TextReaderError> for KbinError {
#[inline]
fn from(source: SixbitError) -> Self {
KbinError::Sixbit { source }
fn from(source: TextReaderError) -> Self {
KbinError::TextReader { source }
}
}

View File

@@ -1,19 +1,89 @@
use std::str;
use std::num::{ParseFloatError, ParseIntError};
use std::str::{self, Utf8Error};
use std::string::FromUtf8Error;
use bytes::{BufMut, Bytes, BytesMut};
use quick_xml::events::attributes::Attributes;
use quick_xml::events::{BytesStart, BytesText, Event};
use quick_xml::Error as QuickXmlError;
use quick_xml::Reader;
use snafu::ResultExt;
use snafu::{ResultExt, Snafu};
use crate::encoding_type::EncodingType;
use crate::error::*;
use crate::encoding_type::{EncodingError, EncodingType};
use crate::node::{Key, NodeCollection, NodeData, NodeDefinition};
use crate::node_types::StandardType;
use crate::node_types::{StandardType, UnknownKbinType};
use crate::value::Value;
const EMPTY_STRING_DATA: &[u8] = &[0];
#[derive(Debug, Snafu)]
pub enum TextReaderError {
#[snafu(display("Invalid kbin type found"))]
InvalidKbinType { source: UnknownKbinType },
#[snafu(display("Invalid encoding type read from declaration"))]
InvalidEncoding { source: EncodingError },
#[snafu(display(
"Mismatched binary node length and size attribute value (value length: {}, size attribute: {})",
len,
size
))]
MismatchedBinaryNodeLength { len: usize, size: usize },
#[snafu(display("No node data found"))]
NoNodeData,
#[snafu(display("Failed to interpret bytes as UTF-8"))]
Utf8 { source: FromUtf8Error },
#[snafu(display("Failed to interpret byte slice as UTF-8"))]
Utf8Slice { source: Utf8Error },
#[snafu(display("Failed to parse integer input as node type {}", node_type))]
StringParseInt {
node_type: &'static str,
source: ParseIntError,
},
#[snafu(display("Failed to parse float input as node type {}", node_type))]
StringParseFloat {
node_type: &'static str,
source: ParseFloatError,
},
#[snafu(display("Failed to decode value from string for node type {}", node_type))]
ValueDecode {
node_type: StandardType,
#[snafu(source(from(crate::KbinError, Box::new)))]
source: Box<crate::KbinError>,
},
#[snafu(display("Failed to encode value for node type {}", node_type))]
ValueEncode {
node_type: StandardType,
#[snafu(source(from(crate::KbinError, Box::new)))]
source: Box<crate::KbinError>,
},
#[snafu(display("Failed to handle XML operation"))]
Xml { source: QuickXmlError },
}
impl From<Utf8Error> for TextReaderError {
#[inline]
fn from(source: Utf8Error) -> Self {
Self::Utf8Slice { source }
}
}
impl From<QuickXmlError> for TextReaderError {
#[inline]
fn from(source: QuickXmlError) -> Self {
Self::Xml { source }
}
}
pub struct TextXmlReader<'a> {
xml_reader: Reader<&'a [u8]>,
encoding: EncodingType,
@@ -41,7 +111,7 @@ impl<'a> TextXmlReader<'a> {
self.encoding
}
fn parse_attribute(&self, key: &[u8], value: &[u8]) -> Result<NodeDefinition> {
fn parse_attribute(&self, key: &[u8], value: &[u8]) -> Result<NodeDefinition, TextReaderError> {
let mut value = BytesMut::from(value.to_vec());
// Add the trailing null byte that kbin has at the end of strings
@@ -68,7 +138,7 @@ impl<'a> TextXmlReader<'a> {
fn parse_attributes(
&self,
attrs: Attributes<'a>,
) -> Result<(StandardType, usize, Option<usize>, Vec<NodeDefinition>)> {
) -> Result<(StandardType, usize, Option<usize>, Vec<NodeDefinition>), TextReaderError> {
let mut node_type = None;
let mut count = 0;
let mut size = None;
@@ -113,7 +183,7 @@ impl<'a> TextXmlReader<'a> {
Err(e) => {
error!("Error reading attribute: {:?}", e);
},
}
};
}
let node_type = match node_type {
@@ -128,7 +198,10 @@ impl<'a> TextXmlReader<'a> {
Ok((node_type, count, size, attributes))
}
fn handle_start(&self, e: BytesStart) -> Result<(NodeCollection, usize, Option<usize>)> {
fn handle_start(
&self,
e: BytesStart,
) -> Result<(NodeCollection, usize, Option<usize>), TextReaderError> {
let (node_type, count, size, attributes) = self.parse_attributes(e.attributes())?;
let is_array = count > 0;
@@ -156,7 +229,7 @@ impl<'a> TextXmlReader<'a> {
definition: &mut NodeDefinition,
count: usize,
size: Option<usize>,
) -> Result<()> {
) -> Result<(), TextReaderError> {
let data = event.unescaped()?;
let data = match definition.node_type {
StandardType::String | StandardType::NodeStart => {
@@ -168,21 +241,24 @@ impl<'a> TextXmlReader<'a> {
data.freeze()
},
_ => {
node_type => {
let text = str::from_utf8(&*data)?;
let value =
Value::from_string(definition.node_type, text, definition.is_array, count)?;
let value = Value::from_string(node_type, text, definition.is_array, count)
.context(ValueDecode { node_type })?;
// The read number of bytes must match the size attribute, if set
if let Value::Binary(data) = &value {
// The read number of bytes must match the size attribute, if set
if let Some(size) = size {
if data.len() != size {
return Err(KbinError::InvalidState.into());
return Err(TextReaderError::MismatchedBinaryNodeLength {
len: data.len(),
size,
});
}
}
}
Bytes::from(value.to_bytes()?)
Bytes::from(value.to_bytes().context(ValueEncode { node_type })?)
},
};
@@ -190,20 +266,22 @@ impl<'a> TextXmlReader<'a> {
definition.node_type = StandardType::String;
}
if let NodeData::Some {
ref mut value_data, ..
} = definition.data_mut()
{
*value_data = data;
} else {
// There should be a valid `NodeData` structure from the `Event::Start` handler
return Err(KbinError::InvalidState.into());
}
match definition.data_mut() {
NodeData::Some {
ref mut value_data, ..
} => {
*value_data = data;
},
NodeData::None => {
// There should be a valid `NodeData` structure from the `Event::Start` handler
return Err(TextReaderError::NoNodeData);
},
};
Ok(())
}
pub fn as_node_collection(&mut self) -> Result<Option<NodeCollection>> {
pub fn as_node_collection(&mut self) -> Result<Option<NodeCollection>, TextReaderError> {
// A buffer size for reading a `quick_xml::events::Event` that I pulled
// out of my head.
let mut buf = Vec::with_capacity(1024);
@@ -245,7 +323,8 @@ impl<'a> TextXmlReader<'a> {
},
Event::Decl(e) => {
if let Some(encoding) = e.encoding() {
self.encoding = EncodingType::from_label(&encoding?)?;
self.encoding =
EncodingType::from_label(&encoding?).context(InvalidEncoding)?;
}
},
Event::Eof => break,