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 /src | |
| download | rust-plist-9e8196ba875e4f8602a8c619fbbac08a1559602d.tar.bz2 | |
Basic streaming pull parser support
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 4 | ||||
| -rw-r--r-- | src/reader.rs | 136 |
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 |
