aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Barnard2015-08-04 15:44:04 +0100
committerEdward Barnard2015-08-04 15:49:16 +0100
commit9e8196ba875e4f8602a8c619fbbac08a1559602d (patch)
treebc713b7255e9331d8b6645a49ac2b39e93d670ba
downloadrust-plist-9e8196ba875e4f8602a8c619fbbac08a1559602d.tar.bz2
Basic streaming pull parser support
-rw-r--r--.gitignore2
-rw-r--r--Cargo.toml10
-rw-r--r--LICENCE19
-rw-r--r--src/lib.rs4
-rw-r--r--src/reader.rs136
-rw-r--r--tests/data/simple.plist15
6 files changed, 186 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a9d37c5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..809c32d
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "plist"
+version = "0.0.1"
+authors = ["Ed Barnard <eabarnard@gmail.com>"]
+description = "A rusty plist parser. Very much a work in progress."
+license = "MIT"
+
+[dependencies]
+rustc-serialize = "0.3.15"
+xml-rs = "0.1.25" \ No newline at end of file
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..33953bb
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,19 @@
+Copyright (c) 2015 Edward Barnard
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. \ No newline at end of file
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
diff --git a/tests/data/simple.plist b/tests/data/simple.plist
new file mode 100644
index 0000000..c48e224
--- /dev/null
+++ b/tests/data/simple.plist
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="1.0">
+<dict>
+ <key>Author</key>
+ <string>William Shakespeare</string>
+ <key>Lines</key>
+ <array>
+ <string>It is a tale told by an idiot,</string>
+ <string>Full of sound and fury, signifying nothing.</string>
+ </array>
+ <key>Birthdate</key>
+ <integer>1564</integer>
+</dict>
+</plist> \ No newline at end of file