diff options
| author | Edward Barnard | 2015-08-04 15:44:04 +0100 |
|---|---|---|
| committer | Edward Barnard | 2015-08-04 15:49:16 +0100 |
| commit | 9e8196ba875e4f8602a8c619fbbac08a1559602d (patch) | |
| tree | bc713b7255e9331d8b6645a49ac2b39e93d670ba | |
| download | rust-plist-9e8196ba875e4f8602a8c619fbbac08a1559602d.tar.bz2 | |
Basic streaming pull parser support
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Cargo.toml | 10 | ||||
| -rw-r--r-- | LICENCE | 19 | ||||
| -rw-r--r-- | src/lib.rs | 4 | ||||
| -rw-r--r-- | src/reader.rs | 136 | ||||
| -rw-r--r-- | tests/data/simple.plist | 15 |
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 @@ -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 |
