//! An abstraction of a plist file as a set of events. Used to support multiple encodings. mod binary_reader; pub use self::binary_reader::BinaryReader; mod xml_reader; pub use self::xml_reader::XmlReader; mod xml_writer; pub use self::xml_writer::XmlWriter; use std::io::{Read, Seek, SeekFrom}; use {Date, Error}; /// 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 Event { // 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), } pub struct Reader(ReaderInner); enum ReaderInner { Uninitialized(Option), Xml(XmlReader), Binary(BinaryReader), } impl Reader { pub fn new(reader: R) -> Reader { Reader(ReaderInner::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 Reader { type Item = Result; fn next(&mut self) -> Option> { let mut reader = match self.0 { ReaderInner::Xml(ref mut parser) => return parser.next(), ReaderInner::Binary(ref mut parser) => return parser.next(), ReaderInner::Uninitialized(ref mut reader) => reader.take().unwrap(), }; let event_reader = match Reader::is_binary(&mut reader) { Ok(true) => ReaderInner::Binary(BinaryReader::new(reader)), Ok(false) => ReaderInner::Xml(XmlReader::new(reader)), Err(err) => { ::std::mem::replace(&mut self.0, ReaderInner::Uninitialized(Some(reader))); return Some(Err(err)); } }; ::std::mem::replace(&mut self.0, event_reader); self.next() } } /// Supports writing event streams in different plist encodings. pub trait Writer { fn write(&mut self, event: &Event) -> Result<(), Error>; }