aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEdward Barnard2015-08-04 15:44:04 +0100
committerEdward Barnard2015-08-04 15:49:16 +0100
commit9e8196ba875e4f8602a8c619fbbac08a1559602d (patch)
treebc713b7255e9331d8b6645a49ac2b39e93d670ba /src
downloadrust-plist-9e8196ba875e4f8602a8c619fbbac08a1559602d.tar.bz2
Basic streaming pull parser support
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs4
-rw-r--r--src/reader.rs136
2 files changed, 140 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..87aca11
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,4 @@
+extern crate rustc_serialize;
+extern crate xml;
+
+pub mod reader; \ No newline at end of file
diff --git a/src/reader.rs b/src/reader.rs
new file mode 100644
index 0000000..03942d0
--- /dev/null
+++ b/src/reader.rs
@@ -0,0 +1,136 @@
+use rustc_serialize::base64::FromBase64;
+use std::io::Read;
+use std::str::FromStr;
+use xml::reader::ParserConfig;
+use xml::reader::EventReader as XmlEventReader;
+use xml::reader::events::XmlEvent;
+
+#[derive(PartialEq, Debug, Clone)]
+pub enum PlistEvent {
+ StartArray,
+ EndArray,
+
+ StartDictionary,
+ EndDictionary,
+ DictionaryKey(String),
+
+ BooleanValue(bool),
+ DataValue(Vec<u8>),
+ DateValue(String),
+ FloatValue(f64),
+ IntegerValue(i64),
+ StringValue(String),
+
+ Error(())
+}
+
+pub struct EventReader<R: Read> {
+ xml_reader: XmlEventReader<R>
+}
+
+impl<R: Read> EventReader<R> {
+ pub fn new(reader: R) -> EventReader<R> {
+ let config = ParserConfig {
+ trim_whitespace: false,
+ whitespace_to_characters: true,
+ cdata_to_characters: true,
+ ignore_comments: true,
+ coalesce_characters: true,
+ };
+
+ EventReader {
+ xml_reader: XmlEventReader::with_config(reader, config)
+ }
+ }
+
+ fn read_string<F>(&mut self, f: F) -> PlistEvent where F:FnOnce(String) -> PlistEvent {
+ match self.xml_reader.next() {
+ XmlEvent::Characters(s) => f(s),
+ _ => PlistEvent::Error(())
+ }
+ }
+
+ pub fn next(&mut self) -> Option<PlistEvent> {
+ loop {
+ let first_event = self.xml_reader.next();
+ match first_event {
+ XmlEvent::StartElement { name, .. } => match &name.local_name[..] {
+ "plist" => (),
+ "array" => return Some(PlistEvent::StartArray),
+ "dict" => return Some(PlistEvent::StartDictionary),
+ "key" => return Some(self.read_string(|s| PlistEvent::DictionaryKey(s))),
+ "true" => return Some(PlistEvent::BooleanValue(true)),
+ "false" => return Some(PlistEvent::BooleanValue(false)),
+ "data" => return Some(self.read_string(|s| {
+ match FromBase64::from_base64(&s[..]) {
+ Ok(b) => PlistEvent::DataValue(b),
+ Err(_) => PlistEvent::Error(())
+ }
+ })),
+ "date" => return Some(self.read_string(|s| PlistEvent::DateValue(s))),
+ "integer" => return Some(self.read_string(|s| {
+ match FromStr::from_str(&s) {
+ Ok(i) => PlistEvent::IntegerValue(i),
+ Err(_) => PlistEvent::Error(())
+ }
+ })),
+ "real" => return Some(self.read_string(|s| {
+ match FromStr::from_str(&s) {
+ Ok(f) => PlistEvent::FloatValue(f),
+ Err(_) => PlistEvent::Error(())
+ }
+ })),
+ "string" => return Some(self.read_string(|s| PlistEvent::StringValue(s))),
+ _ => return Some(PlistEvent::Error(()))
+ },
+ XmlEvent::EndElement { name, .. } => match &name.local_name[..] {
+ "array" => return Some(PlistEvent::EndArray),
+ "dict" => return Some(PlistEvent::EndDictionary),
+ _ => ()
+ },
+ XmlEvent::EndDocument => return None,
+ _ => ()
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::fs::File;
+ use std::path::Path;
+
+ use reader::*;
+
+ #[test]
+ fn simple() {
+ use reader::PlistEvent::*;
+
+ let reader = File::open(&Path::new("./tests/data/simple.plist")).unwrap();
+ let mut event_reader = EventReader::new(reader);
+ let mut events = Vec::new();
+ loop {
+ if let Some(event) = event_reader.next() {
+ events.push(event);
+ } else {
+ break;
+ }
+ }
+
+ let comparison = &[
+ StartDictionary,
+ DictionaryKey("Author".to_owned()),
+ StringValue("William Shakespeare".to_owned()),
+ DictionaryKey("Lines".to_owned()),
+ StartArray,
+ StringValue("It is a tale told by an idiot,".to_owned()),
+ StringValue("Full of sound and fury, signifying nothing.".to_owned()),
+ EndArray,
+ DictionaryKey("Birthdate".to_owned()),
+ IntegerValue(1564),
+ EndDictionary
+ ];
+
+ assert_eq!(events, comparison);
+ }
+} \ No newline at end of file