use std::error;
use std::io::{self, Read};
use std::fmt::{self, Display, Formatter};
use std::str::{Utf8Error, from_utf8};
use Marker;
use super::{read_marker, read_data_u8, read_data_u16, read_data_u32, Error, ValueReadError};
#[derive(Debug)]
pub enum DecodeStringError<'a> {
InvalidMarkerRead(Error),
InvalidDataRead(Error),
TypeMismatch(Marker),
BufferSizeTooSmall(u32),
InvalidUtf8(&'a [u8], Utf8Error),
}
impl<'a> error::Error for DecodeStringError<'a> {
fn description(&self) -> &str {
"error while decoding string"
}
fn cause(&self) -> Option<&error::Error> {
match *self {
DecodeStringError::InvalidMarkerRead(ref err) => Some(err),
DecodeStringError::InvalidDataRead(ref err) => Some(err),
DecodeStringError::TypeMismatch(..) => None,
DecodeStringError::BufferSizeTooSmall(_) => None,
DecodeStringError::InvalidUtf8(_, ref err) => Some(err),
}
}
}
impl<'a> Display for DecodeStringError<'a> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
error::Error::description(self).fmt(f)
}
}
impl<'a> From<ValueReadError> for DecodeStringError<'a> {
fn from(err: ValueReadError) -> DecodeStringError<'a> {
match err {
ValueReadError::InvalidMarkerRead(err) => DecodeStringError::InvalidMarkerRead(err),
ValueReadError::InvalidDataRead(err) => DecodeStringError::InvalidDataRead(err),
ValueReadError::TypeMismatch(marker) => DecodeStringError::TypeMismatch(marker),
}
}
}
pub fn read_str_len<R: Read>(rd: &mut R) -> Result<u32, ValueReadError> {
match try!(read_marker(rd)) {
Marker::FixStr(size) => Ok(size as u32),
Marker::Str8 => Ok(try!(read_data_u8(rd)) as u32),
Marker::Str16 => Ok(try!(read_data_u16(rd)) as u32),
Marker::Str32 => Ok(try!(read_data_u32(rd))),
marker => Err(ValueReadError::TypeMismatch(marker)),
}
}
pub fn read_str<'r, R>(rd: &mut R, mut buf: &'r mut [u8]) -> Result<&'r str, DecodeStringError<'r>>
where R: Read
{
let len = try!(read_str_len(rd));
let ulen = len as usize;
if buf.len() < ulen {
return Err(DecodeStringError::BufferSizeTooSmall(len));
}
read_str_data(rd, len, &mut buf[0..ulen])
}
pub fn read_str_data<'r, R>(rd: &mut R,
len: u32,
buf: &'r mut [u8])
-> Result<&'r str, DecodeStringError<'r>>
where R: Read
{
debug_assert_eq!(len as usize, buf.len());
match rd.read_exact(buf) {
Ok(()) => {
match from_utf8(buf) {
Ok(decoded) => Ok(decoded),
Err(err) => Err(DecodeStringError::InvalidUtf8(buf, err)),
}
}
Err(err) => Err(DecodeStringError::InvalidDataRead(From::from(err))),
}
}
pub fn read_str_ref(rd: &[u8]) -> Result<&[u8], DecodeStringError> {
let mut cur = io::Cursor::new(rd);
let len = try!(read_str_len(&mut cur));
let start = cur.position() as usize;
Ok(&rd[start..start + len as usize])
}