extern crate byteorder;
extern crate chrono;
extern crate rustc_serialize;
extern crate xml as xml_rs;
pub mod binary;
pub mod xml;
mod builder;
mod plist;
pub use plist::Plist;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde as serde_base;
#[cfg(feature = "serde")]
pub mod serde;
use chrono::{DateTime, UTC};
use std::fmt;
use std::io::{Read, Seek, SeekFrom};
use std::io::Error as IoError;
#[derive(Clone, Debug, PartialEq)]
pub enum PlistEvent {
StartArray(Option<u64>),
EndArray,
StartDictionary(Option<u64>),
EndDictionary,
BooleanValue(bool),
DataValue(Vec<u8>),
DateValue(DateTime<UTC>),
IntegerValue(i64),
RealValue(f64),
StringValue(String),
}
pub type Result<T> = ::std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
InvalidData,
UnexpectedEof,
Io(IoError),
Serde(String),
}
impl ::std::error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::InvalidData => "invalid data",
Error::UnexpectedEof => "unexpected eof",
Error::Io(ref err) => err.description(),
Error::Serde(ref err) => &err,
}
}
fn cause(&self) -> Option<&::std::error::Error> {
match *self {
Error::Io(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Io(ref err) => err.fmt(fmt),
_ => <Self as ::std::error::Error>::description(self).fmt(fmt),
}
}
}
impl From<IoError> for Error {
fn from(err: IoError) -> Error {
Error::Io(err)
}
}
pub struct EventReader<R: Read + Seek>(EventReaderInner<R>);
enum EventReaderInner<R: Read + Seek> {
Uninitialized(Option<R>),
Xml(xml::EventReader<R>),
Binary(binary::EventReader<R>),
}
impl<R: Read + Seek> EventReader<R> {
pub fn new(reader: R) -> EventReader<R> {
EventReader(EventReaderInner::Uninitialized(Some(reader)))
}
fn is_binary(reader: &mut R) -> Result<bool> {
try!(reader.seek(SeekFrom::Start(0)));
let mut magic = [0; 8];
try!(reader.read(&mut magic));
try!(reader.seek(SeekFrom::Start(0)));
Ok(if &magic == b"bplist00" { true } else { false })
}
}
impl<R: Read + Seek> Iterator for EventReader<R> {
type Item = Result<PlistEvent>;
fn next(&mut self) -> Option<Result<PlistEvent>> {
let mut reader = match self.0 {
EventReaderInner::Xml(ref mut parser) => return parser.next(),
EventReaderInner::Binary(ref mut parser) => return parser.next(),
EventReaderInner::Uninitialized(ref mut reader) => reader.take().unwrap(),
};
let event_reader = match EventReader::is_binary(&mut reader) {
Ok(true) => EventReaderInner::Binary(binary::EventReader::new(reader)),
Ok(false) => EventReaderInner::Xml(xml::EventReader::new(reader)),
Err(err) => {
::std::mem::replace(&mut self.0, EventReaderInner::Uninitialized(Some(reader)));
return Some(Err(err));
}
};
::std::mem::replace(&mut self.0, event_reader);
self.next()
}
}
pub trait EventWriter {
fn write(&mut self, event: &PlistEvent) -> Result<()>;
}
fn u64_to_usize(len_u64: u64) -> Result<usize> {
let len = len_u64 as usize;
if len as u64 != len_u64 {
return Err(Error::InvalidData); }
Ok(len)
}
fn u64_option_to_usize(len: Option<u64>) -> Result<Option<usize>> {
match len {
Some(len) => Ok(Some(try!(u64_to_usize(len)))),
None => Ok(None),
}
}