aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binary/mod.rs3
-rw-r--r--src/binary/reader.rs (renamed from src/binary.rs)23
-rw-r--r--src/builder.rs176
-rw-r--r--src/lib.rs191
-rw-r--r--src/xml/mod.rs5
-rw-r--r--src/xml/reader.rs (renamed from src/xml.rs)107
-rw-r--r--src/xml/writer.rs101
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
diff --git a/src/lib.rs b/src/lib.rs
index 7a00ca0..9a8da49 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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