diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/binary/mod.rs | 3 | ||||
| -rw-r--r-- | src/binary/reader.rs (renamed from src/binary.rs) | 23 | ||||
| -rw-r--r-- | src/builder.rs | 176 | ||||
| -rw-r--r-- | src/lib.rs | 191 | ||||
| -rw-r--r-- | src/xml/mod.rs | 5 | ||||
| -rw-r--r-- | src/xml/reader.rs (renamed from src/xml.rs) | 107 | ||||
| -rw-r--r-- | src/xml/writer.rs | 101 |
7 files changed, 313 insertions, 293 deletions
diff --git a/src/binary/mod.rs b/src/binary/mod.rs new file mode 100644 index 0000000..0ac39d4 --- /dev/null +++ b/src/binary/mod.rs @@ -0,0 +1,3 @@ +mod reader; + +pub use self::reader::StreamingParser;
\ No newline at end of file diff --git a/src/binary.rs b/src/binary/reader.rs index 0f1b707..36c27f2 100644 --- a/src/binary.rs +++ b/src/binary/reader.rs @@ -1,8 +1,25 @@ use byteorder::{BigEndian, ReadBytesExt}; +use byteorder::Error as ByteorderError; use itertools::Interleave; use std::io::{Cursor, Read, Seek, SeekFrom}; +use std::string::FromUtf16Error; -use super::{ParserError, ParserResult, PlistEvent}; +use {ParserError, ParserResult, PlistEvent}; + +impl From<ByteorderError> for ParserError { + fn from(err: ByteorderError) -> ParserError { + match err { + ByteorderError::UnexpectedEOF => ParserError::UnexpectedEof, + ByteorderError::Io(err) => ParserError::Io(err) + } + } +} + +impl From<FromUtf16Error> for ParserError { + fn from(_: FromUtf16Error) -> ParserError { + ParserError::InvalidData + } +} struct StackItem { object_refs: Vec<u64>, @@ -242,11 +259,11 @@ mod tests { use std::path::Path; use super::*; - use super::super::PlistEvent; + use PlistEvent; #[test] fn streaming_parser() { - use super::super::PlistEvent::*; + use PlistEvent::*; let reader = File::open(&Path::new("./tests/data/binary.plist")).unwrap(); let streaming_parser = StreamingParser::new(reader); diff --git a/src/builder.rs b/src/builder.rs new file mode 100644 index 0000000..50afad7 --- /dev/null +++ b/src/builder.rs @@ -0,0 +1,176 @@ +use std::collections::HashMap; +use std::io::{Read, Seek}; + +use {ParserError, ParserResult, Plist, PlistEvent, StreamingParser}; + +pub type BuilderResult<T> = Result<T, BuilderError>; + +#[derive(Debug)] +pub enum BuilderError { + InvalidEvent, + UnsupportedDictionaryKey, + ParserError(ParserError) +} + +impl From<ParserError> for BuilderError { + fn from(err: ParserError) -> BuilderError { + BuilderError::ParserError(err) + } +} + +pub struct Builder<T> { + stream: T, + token: Option<PlistEvent>, +} + +impl<R: Read + Seek> Builder<StreamingParser<R>> { + pub fn new(reader: R) -> Builder<StreamingParser<R>> { + Builder::from_event_stream(StreamingParser::new(reader)) + } +} + +impl<T:Iterator<Item=ParserResult<PlistEvent>>> Builder<T> { + pub fn from_event_stream(stream: T) -> Builder<T> { + Builder { + stream: stream, + token: None + } + } + + pub fn build(mut self) -> BuilderResult<Plist> { + try!(self.bump()); + if let Some(PlistEvent::StartPlist) = self.token { + try!(self.bump()); + } + + let plist = try!(self.build_value()); + try!(self.bump()); + match self.token { + None => (), + Some(PlistEvent::EndPlist) => try!(self.bump()), + // The stream should have finished + _ => return Err(BuilderError::InvalidEvent) + }; + Ok(plist) + } + + fn bump(&mut self) -> BuilderResult<()> { + self.token = match self.stream.next() { + Some(Ok(token)) => Some(token), + Some(Err(err)) => return Err(BuilderError::ParserError(err)), + None => None, + }; + Ok(()) + } + + fn build_value(&mut self) -> BuilderResult<Plist> { + match self.token.take() { + Some(PlistEvent::StartPlist) => Err(BuilderError::InvalidEvent), + Some(PlistEvent::EndPlist) => Err(BuilderError::InvalidEvent), + + Some(PlistEvent::StartArray(len)) => Ok(Plist::Array(try!(self.build_array(len)))), + Some(PlistEvent::StartDictionary(len)) => Ok(Plist::Dictionary(try!(self.build_dict(len)))), + + Some(PlistEvent::BooleanValue(b)) => Ok(Plist::Boolean(b)), + Some(PlistEvent::DataValue(d)) => Ok(Plist::Data(d)), + Some(PlistEvent::DateValue(d)) => Ok(Plist::Date(d)), + Some(PlistEvent::IntegerValue(i)) => Ok(Plist::Integer(i)), + Some(PlistEvent::RealValue(f)) => Ok(Plist::Real(f)), + Some(PlistEvent::StringValue(s)) => Ok(Plist::String(s)), + + Some(PlistEvent::EndArray) => Err(BuilderError::InvalidEvent), + Some(PlistEvent::EndDictionary) => Err(BuilderError::InvalidEvent), + + // The stream should not have ended here + None => Err(BuilderError::InvalidEvent) + } + } + + fn build_array(&mut self, len: Option<u64>) -> Result<Vec<Plist>, BuilderError> { + let mut values = match len { + Some(len) => Vec::with_capacity(len as usize), + None => Vec::new() + }; + + loop { + try!(self.bump()); + if let Some(PlistEvent::EndArray) = self.token { + self.token.take(); + return Ok(values); + } + values.push(try!(self.build_value())); + } + } + + fn build_dict(&mut self, len: Option<u64>) -> Result<HashMap<String, Plist>, BuilderError> { + let mut values = match len { + Some(len) => HashMap::with_capacity(len as usize), + None => HashMap::new() + }; + + loop { + try!(self.bump()); + match self.token.take() { + Some(PlistEvent::EndDictionary) => return Ok(values), + Some(PlistEvent::StringValue(s)) => { + try!(self.bump()); + values.insert(s, try!(self.build_value())); + }, + _ => { + // Only string keys are supported in plists + return Err(BuilderError::UnsupportedDictionaryKey) + } + } + } + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use super::*; + use Plist; + + #[test] + fn builder() { + use PlistEvent::*; + + // Input + + let events = vec![ + StartPlist, + StartDictionary(None), + StringValue("Author".to_owned()), + StringValue("William Shakespeare".to_owned()), + StringValue("Lines".to_owned()), + StartArray(None), + StringValue("It is a tale told by an idiot,".to_owned()), + StringValue("Full of sound and fury, signifying nothing.".to_owned()), + EndArray, + StringValue("Birthdate".to_owned()), + IntegerValue(1564), + StringValue("Height".to_owned()), + RealValue(1.60), + EndDictionary, + EndPlist, + ]; + + let builder = Builder::from_event_stream(events.into_iter().map(|e| Ok(e))); + let plist = builder.build(); + + // Expected output + + let mut lines = Vec::new(); + lines.push(Plist::String("It is a tale told by an idiot,".to_owned())); + lines.push(Plist::String("Full of sound and fury, signifying nothing.".to_owned())); + + let mut dict = HashMap::new(); + dict.insert("Author".to_owned(), Plist::String("William Shakespeare".to_owned())); + dict.insert("Lines".to_owned(), Plist::Array(lines)); + dict.insert("Birthdate".to_owned(), Plist::Integer(1564)); + dict.insert("Height".to_owned(), Plist::Real(1.60)); + + assert_eq!(plist.unwrap(), Plist::Dictionary(dict)); + } +}
\ No newline at end of file @@ -5,12 +5,13 @@ extern crate xml as xml_rs; pub mod binary; pub mod xml; +mod builder; + +pub use builder::{Builder, BuilderError, BuilderResult}; -use byteorder::Error as ByteorderError; use std::collections::HashMap; use std::io::{Read, Seek, SeekFrom}; use std::io::Error as IoError; -use std::string::FromUtf16Error; #[derive(Clone, Debug, PartialEq)] pub enum Plist { @@ -59,21 +60,6 @@ impl From<IoError> for ParserError { } } -impl From<ByteorderError> for ParserError { - fn from(err: ByteorderError) -> ParserError { - match err { - ByteorderError::UnexpectedEOF => ParserError::UnexpectedEof, - ByteorderError::Io(err) => ParserError::Io(err) - } - } -} - -impl From<FromUtf16Error> for ParserError { - fn from(_: FromUtf16Error) -> ParserError { - ParserError::InvalidData - } -} - pub enum StreamingParser<R: Read+Seek> { Xml(xml::StreamingParser<R>), Binary(binary::StreamingParser<R>) @@ -109,175 +95,4 @@ impl<R: Read+Seek> Iterator for StreamingParser<R> { StreamingParser::Binary(ref mut parser) => parser.next() } } -} - -pub type BuilderResult<T> = Result<T, BuilderError>; - -#[derive(Debug)] -pub enum BuilderError { - InvalidEvent, - UnsupportedDictionaryKey, - ParserError(ParserError) -} - -impl From<ParserError> for BuilderError { - fn from(err: ParserError) -> BuilderError { - BuilderError::ParserError(err) - } -} - -pub struct Builder<T> { - stream: T, - token: Option<PlistEvent>, -} - -impl<R: Read + Seek> Builder<StreamingParser<R>> { - pub fn new(reader: R) -> Builder<StreamingParser<R>> { - Builder::from_event_stream(StreamingParser::new(reader)) - } -} - -impl<T:Iterator<Item=ParserResult<PlistEvent>>> Builder<T> { - pub fn from_event_stream(stream: T) -> Builder<T> { - Builder { - stream: stream, - token: None - } - } - - pub fn build(mut self) -> BuilderResult<Plist> { - try!(self.bump()); - if let Some(PlistEvent::StartPlist) = self.token { - try!(self.bump()); - } - - let plist = try!(self.build_value()); - try!(self.bump()); - match self.token { - None => (), - Some(PlistEvent::EndPlist) => try!(self.bump()), - // The stream should have finished - _ => return Err(BuilderError::InvalidEvent) - }; - Ok(plist) - } - - fn bump(&mut self) -> BuilderResult<()> { - self.token = match self.stream.next() { - Some(Ok(token)) => Some(token), - Some(Err(err)) => return Err(BuilderError::ParserError(err)), - None => None, - }; - Ok(()) - } - - fn build_value(&mut self) -> BuilderResult<Plist> { - match self.token.take() { - Some(PlistEvent::StartPlist) => Err(BuilderError::InvalidEvent), - Some(PlistEvent::EndPlist) => Err(BuilderError::InvalidEvent), - - Some(PlistEvent::StartArray(len)) => Ok(Plist::Array(try!(self.build_array(len)))), - Some(PlistEvent::StartDictionary(len)) => Ok(Plist::Dictionary(try!(self.build_dict(len)))), - - Some(PlistEvent::BooleanValue(b)) => Ok(Plist::Boolean(b)), - Some(PlistEvent::DataValue(d)) => Ok(Plist::Data(d)), - Some(PlistEvent::DateValue(d)) => Ok(Plist::Date(d)), - Some(PlistEvent::IntegerValue(i)) => Ok(Plist::Integer(i)), - Some(PlistEvent::RealValue(f)) => Ok(Plist::Real(f)), - Some(PlistEvent::StringValue(s)) => Ok(Plist::String(s)), - - Some(PlistEvent::EndArray) => Err(BuilderError::InvalidEvent), - Some(PlistEvent::EndDictionary) => Err(BuilderError::InvalidEvent), - - // The stream should not have ended here - None => Err(BuilderError::InvalidEvent) - } - } - - fn build_array(&mut self, len: Option<u64>) -> Result<Vec<Plist>, BuilderError> { - let mut values = match len { - Some(len) => Vec::with_capacity(len as usize), - None => Vec::new() - }; - - loop { - try!(self.bump()); - if let Some(PlistEvent::EndArray) = self.token { - self.token.take(); - return Ok(values); - } - values.push(try!(self.build_value())); - } - } - - fn build_dict(&mut self, len: Option<u64>) -> Result<HashMap<String, Plist>, BuilderError> { - let mut values = match len { - Some(len) => HashMap::with_capacity(len as usize), - None => HashMap::new() - }; - - loop { - try!(self.bump()); - match self.token.take() { - Some(PlistEvent::EndDictionary) => return Ok(values), - Some(PlistEvent::StringValue(s)) => { - try!(self.bump()); - values.insert(s, try!(self.build_value())); - }, - _ => { - // Only string keys are supported in plists - return Err(BuilderError::UnsupportedDictionaryKey) - } - } - } - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - - use super::*; - - #[test] - fn builder() { - use super::PlistEvent::*; - - // Input - - let events = vec![ - StartPlist, - StartDictionary(None), - StringValue("Author".to_owned()), - StringValue("William Shakespeare".to_owned()), - StringValue("Lines".to_owned()), - StartArray(None), - StringValue("It is a tale told by an idiot,".to_owned()), - StringValue("Full of sound and fury, signifying nothing.".to_owned()), - EndArray, - StringValue("Birthdate".to_owned()), - IntegerValue(1564), - StringValue("Height".to_owned()), - RealValue(1.60), - EndDictionary, - EndPlist, - ]; - - let builder = Builder::from_event_stream(events.into_iter().map(|e| Ok(e))); - let plist = builder.build(); - - // Expected output - - let mut lines = Vec::new(); - lines.push(Plist::String("It is a tale told by an idiot,".to_owned())); - lines.push(Plist::String("Full of sound and fury, signifying nothing.".to_owned())); - - let mut dict = HashMap::new(); - dict.insert("Author".to_owned(), Plist::String("William Shakespeare".to_owned())); - dict.insert("Lines".to_owned(), Plist::Array(lines)); - dict.insert("Birthdate".to_owned(), Plist::Integer(1564)); - dict.insert("Height".to_owned(), Plist::Real(1.60)); - - assert_eq!(plist.unwrap(), Plist::Dictionary(dict)); - } }
\ No newline at end of file diff --git a/src/xml/mod.rs b/src/xml/mod.rs new file mode 100644 index 0000000..71c098e --- /dev/null +++ b/src/xml/mod.rs @@ -0,0 +1,5 @@ +mod reader; +mod writer; + +pub use self::reader::StreamingParser; +pub use self::writer::Writer;
\ No newline at end of file diff --git a/src/xml.rs b/src/xml/reader.rs index a85d321..f047db4 100644 --- a/src/xml.rs +++ b/src/xml/reader.rs @@ -1,107 +1,10 @@ use rustc_serialize::base64::FromBase64; -use std::io::{Read, Write}; +use std::io::Read; use std::str::FromStr; -use xml_rs::namespace::Namespace; use xml_rs::reader::{EventReader, ParserConfig}; use xml_rs::reader::events::XmlEvent; -use xml_rs::writer::{EventWriter, EmitterConfig}; -use xml_rs::writer::events::XmlEvent as WriteXmlEvent; - -use super::{ParserError, ParserResult, PlistEvent}; - -pub struct Writer<W: Write> { - xml_writer: EventWriter<W>, - // Not very nice - empty_namespace: Namespace -} - -impl<W: Write> Writer<W> { - fn new(writer: W) -> Writer<W> { - let config = EmitterConfig { - line_separator: "\n".to_owned(), - indent_string: " ".to_owned(), - perform_indent: true, - write_document_declaration: true, - normalize_empty_elements: true, - cdata_to_characters: true, - }; - - Writer { - xml_writer: EventWriter::new_with_config(writer, config), - empty_namespace: Namespace::empty() - } - } - - fn write_element_and_value(&mut self, name: &str, value: &str) -> Result<(), ()> { - try!(self.start_element(name)); - try!(self.write_value(value)); - try!(self.end_element(name)); - Ok(()) - } - - fn start_element(&mut self, name: &str) -> Result<(), ()> { - let result = self.xml_writer.write(WriteXmlEvent::StartElement { - name: ::xml_rs::name::Name::local(name), - attributes: Vec::new(), - namespace: &self.empty_namespace - }); - - match result { - Ok(()) => Ok(()), - Err(_) => Err(()) - } - } - - fn end_element(&mut self, name: &str) -> Result<(), ()> { - let result = self.xml_writer.write(WriteXmlEvent::EndElement { - name: ::xml_rs::name::Name::local(name) - }); - - match result { - Ok(()) => Ok(()), - Err(_) => Err(()) - } - } - - fn write_value(&mut self, value: &str) -> Result<(), ()> { - let result = self.xml_writer.write(WriteXmlEvent::Characters(value)); - - match result { - Ok(()) => Ok(()), - Err(_) => Err(()) - } - } - - fn write(&mut self, event: PlistEvent) -> Result<(), ()> { - Ok(match event { - PlistEvent::StartPlist => try!(self.start_element("plist")), - PlistEvent::EndPlist => try!(self.end_element("plist")), - - PlistEvent::StartArray(_) => try!(self.start_element("array")), - PlistEvent::EndArray => try!(self.end_element("array")), - - PlistEvent::StartDictionary(_) => try!(self.start_element("dict")), - PlistEvent::EndDictionary => try!(self.end_element("dict")), - - PlistEvent::BooleanValue(true) => { - try!(self.start_element("true")); - try!(self.end_element("true")); - }, - PlistEvent::BooleanValue(false) => { - try!(self.start_element("false")); - try!(self.end_element("false")); - }, - PlistEvent::DataValue(value) => { - panic!(); - }, - PlistEvent::DateValue(value) => panic!("unimpl"), - PlistEvent::IntegerValue(value) => try!(self.write_element_and_value("integer", &value.to_string())), - PlistEvent::RealValue(value) => try!(self.write_element_and_value("real", &value.to_string())), - PlistEvent::StringValue(value) => try!(self.write_element_and_value("string", &value)), - }) - } -} +use super::super::{ParserError, ParserResult, PlistEvent}; pub struct StreamingParser<R: Read> { xml_reader: EventReader<R>, @@ -176,7 +79,7 @@ impl<R: Read> Iterator for StreamingParser<R> { // Check the corrent element is being closed match self.element_stack.pop() { Some(ref open_name) if &name.local_name == open_name => (), - Some(ref open_name) => return Some(Err(ParserError::InvalidData)), + Some(ref _open_name) => return Some(Err(ParserError::InvalidData)), None => return Some(Err(ParserError::InvalidData)) } @@ -205,11 +108,11 @@ mod tests { use std::path::Path; use super::*; - use super::super::PlistEvent; + use PlistEvent; #[test] fn streaming_parser() { - use super::super::PlistEvent::*; + use PlistEvent::*; let reader = File::open(&Path::new("./tests/data/xml.plist")).unwrap(); let streaming_parser = StreamingParser::new(reader); diff --git a/src/xml/writer.rs b/src/xml/writer.rs new file mode 100644 index 0000000..0e476c0 --- /dev/null +++ b/src/xml/writer.rs @@ -0,0 +1,101 @@ +use rustc_serialize::base64::{MIME, ToBase64}; +use std::io::Write; +use xml_rs::namespace::Namespace; +use xml_rs::writer::{EventWriter, EmitterConfig}; +use xml_rs::writer::events::XmlEvent as WriteXmlEvent; + +use {PlistEvent}; + +pub struct Writer<W: Write> { + xml_writer: EventWriter<W>, + // Not very nice + empty_namespace: Namespace +} + +impl<W: Write> Writer<W> { + pub fn new(writer: W) -> Writer<W> { + let config = EmitterConfig { + line_separator: "\n".to_owned(), + indent_string: " ".to_owned(), + perform_indent: true, + write_document_declaration: true, + normalize_empty_elements: true, + cdata_to_characters: true, + }; + + Writer { + xml_writer: EventWriter::new_with_config(writer, config), + empty_namespace: Namespace::empty() + } + } + + fn write_element_and_value(&mut self, name: &str, value: &str) -> Result<(), ()> { + try!(self.start_element(name)); + try!(self.write_value(value)); + try!(self.end_element(name)); + Ok(()) + } + + fn start_element(&mut self, name: &str) -> Result<(), ()> { + let result = self.xml_writer.write(WriteXmlEvent::StartElement { + name: ::xml_rs::name::Name::local(name), + attributes: Vec::new(), + namespace: &self.empty_namespace + }); + + match result { + Ok(()) => Ok(()), + Err(_) => Err(()) + } + } + + fn end_element(&mut self, name: &str) -> Result<(), ()> { + let result = self.xml_writer.write(WriteXmlEvent::EndElement { + name: ::xml_rs::name::Name::local(name) + }); + + match result { + Ok(()) => Ok(()), + Err(_) => Err(()) + } + } + + fn write_value(&mut self, value: &str) -> Result<(), ()> { + let result = self.xml_writer.write(WriteXmlEvent::Characters(value)); + + match result { + Ok(()) => Ok(()), + Err(_) => Err(()) + } + } + + pub fn write(&mut self, event: PlistEvent) -> Result<(), ()> { + Ok(match event { + PlistEvent::StartPlist => try!(self.start_element("plist")), + PlistEvent::EndPlist => try!(self.end_element("plist")), + + PlistEvent::StartArray(_) => try!(self.start_element("array")), + PlistEvent::EndArray => try!(self.end_element("array")), + + PlistEvent::StartDictionary(_) => try!(self.start_element("dict")), + PlistEvent::EndDictionary => try!(self.end_element("dict")), + + PlistEvent::BooleanValue(true) => { + try!(self.start_element("true")); + try!(self.end_element("true")); + }, + PlistEvent::BooleanValue(false) => { + try!(self.start_element("false")); + try!(self.end_element("false")); + }, + PlistEvent::DataValue(value) => { + let base64_data = value.to_base64(MIME); + try!(self.write_element_and_value("data", &base64_data)); + } + PlistEvent::DateValue(_value) => panic!("unimpl"), + PlistEvent::IntegerValue(value) => try!(self.write_element_and_value("integer", &value.to_string())), + PlistEvent::RealValue(value) => try!(self.write_element_and_value("real", &value.to_string())), + PlistEvent::StringValue(value) => try!(self.write_element_and_value("string", &value)), + }) + } +}
\ No newline at end of file |
