//! # Plist //! //! A rusty plist parser. //! //! ## Usage //! //! Put this in your `Cargo.toml`: //! //! ```toml //! [dependencies] //! plist = "0.2" //! ``` //! //! And put this in your crate root: //! //! ```rust //! extern crate plist; //! ``` //! //! ## Examples //! //! ```rust //! use plist::Plist; //! use std::fs::File; //! //! let file = File::open("tests/data/xml.plist").unwrap(); //! let plist = Plist::read(file).unwrap(); //! //! match plist { //! Plist::Array(_array) => (), //! _ => () //! } //! ``` //! //! ```rust //! # #[cfg(feature = "serde")] //! #[macro_use] //! extern crate serde_derive; //! # extern crate plist; //! //! # #[cfg(feature = "serde")] //! # fn main() { //! use plist::serde::deserialize; //! use std::fs::File; //! //! #[derive(Deserialize)] //! #[serde(rename_all = "PascalCase")] //! struct Info { //! author: String, //! height: f32, //! } //! //! let file = File::open("tests/data/xml.plist").unwrap(); //! let info: Info = deserialize(file).unwrap(); //! # } //! # //! # #[cfg(not(feature = "serde"))] //! # fn main() {} //! ``` extern crate base64; extern crate byteorder; extern crate humantime; extern crate xml as xml_rs; pub mod binary; pub mod xml; mod builder; mod date; mod plist; pub use date::Date; pub use plist::Plist; // Optional serde module #[cfg(feature = "serde")] #[macro_use] extern crate serde as serde_base; #[cfg(feature = "serde")] pub mod serde; use std::fmt; use std::io::{self, Read, Seek, SeekFrom}; /// An encoding of a plist as a flat structure. /// /// Output by the event readers. /// /// Dictionary keys and values are represented as pairs of values e.g.: /// /// ```ignore rust /// StartDictionary /// StringValue("Height") // Key /// RealValue(181.2) // Value /// StringValue("Age") // Key /// IntegerValue(28) // Value /// EndDictionary /// ``` #[derive(Clone, Debug, PartialEq)] pub enum PlistEvent { // While the length of an array or dict cannot be feasably greater than max(usize) this better // conveys the concept of an effectively unbounded event stream. StartArray(Option), EndArray, StartDictionary(Option), EndDictionary, BooleanValue(bool), DataValue(Vec), DateValue(Date), IntegerValue(i64), RealValue(f64), StringValue(String), } type Result = ::std::result::Result; #[derive(Debug)] pub enum Error { InvalidData, UnexpectedEof, Io(io::Error), 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), _ => ::description(self).fmt(fmt), } } } impl From for Error { fn from(err: io::Error) -> Error { Error::Io(err) } } pub struct EventReader(EventReaderInner); enum EventReaderInner { Uninitialized(Option), Xml(xml::EventReader), Binary(binary::EventReader), } impl EventReader { pub fn new(reader: R) -> EventReader { EventReader(EventReaderInner::Uninitialized(Some(reader))) } fn is_binary(reader: &mut R) -> Result { reader.seek(SeekFrom::Start(0))?; let mut magic = [0; 8]; reader.read_exact(&mut magic)?; reader.seek(SeekFrom::Start(0))?; Ok(&magic == b"bplist00") } } impl Iterator for EventReader { type Item = Result; fn next(&mut self) -> Option> { 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 { let len = len_u64 as usize; if len as u64 != len_u64 { return Err(Error::InvalidData); // Too long } Ok(len) } fn u64_option_to_usize(len: Option) -> Result> { match len { Some(len) => Ok(Some(u64_to_usize(len)?)), None => Ok(None), } }