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 | 
