1 +2 +3 +
+mod reader; + +pub use self::reader::EventReader; ++
From b1ac8db3f8c3d8f393701a2f644a85cb44e7c24d Mon Sep 17 00:00:00 2001 From: Date: Wed, 1 Feb 2017 11:18:05 +0000 Subject: Documentation for ebarnard/rust-plist@bf6b567 --- src/plist/src/binary/mod.rs.html | 114 ++++ src/plist/src/binary/reader.rs.html | 814 +++++++++++++++++++++++ src/plist/src/builder.rs.html | 396 ++++++++++++ src/plist/src/de.rs.html | 660 +++++++++++++++++++ src/plist/src/lib.rs.html | 1216 +++++++++++++++++++++++++++++++++++ src/plist/src/ser.rs.html | 480 ++++++++++++++ src/plist/src/xml/mod.rs.html | 118 ++++ src/plist/src/xml/reader.rs.html | 530 +++++++++++++++ src/plist/src/xml/writer.rs.html | 614 ++++++++++++++++++ 9 files changed, 4942 insertions(+) create mode 100644 src/plist/src/binary/mod.rs.html create mode 100644 src/plist/src/binary/reader.rs.html create mode 100644 src/plist/src/builder.rs.html create mode 100644 src/plist/src/de.rs.html create mode 100644 src/plist/src/lib.rs.html create mode 100644 src/plist/src/ser.rs.html create mode 100644 src/plist/src/xml/mod.rs.html create mode 100644 src/plist/src/xml/reader.rs.html create mode 100644 src/plist/src/xml/writer.rs.html (limited to 'src') diff --git a/src/plist/src/binary/mod.rs.html b/src/plist/src/binary/mod.rs.html new file mode 100644 index 0000000..8fe81c2 --- /dev/null +++ b/src/plist/src/binary/mod.rs.html @@ -0,0 +1,114 @@ + + +
+ + + + + + +1 +2 +3 +
+mod reader; + +pub use self::reader::EventReader; ++
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +
+use byteorder::{BigEndian, ReadBytesExt}; +use chrono::{TimeZone, UTC}; +use std::io::{Cursor, Read, Seek, SeekFrom}; +use std::string::{FromUtf8Error, FromUtf16Error}; + +use {Error, Result, PlistEvent, u64_to_usize}; + +impl From<FromUtf8Error> for Error { + fn from(_: FromUtf8Error) -> Error { + Error::InvalidData + } +} + +impl From<FromUtf16Error> for Error { + fn from(_: FromUtf16Error) -> Error { + Error::InvalidData + } +} + +struct StackItem { + object_refs: Vec<u64>, + ty: StackType, +} + +enum StackType { + Array, + Dict, + Root, +} + +/// https://opensource.apple.com/source/CF/CF-550/CFBinaryPList.c +/// https://hg.python.org/cpython/file/3.4/Lib/plistlib.py +pub struct EventReader<R> { + stack: Vec<StackItem>, + object_offsets: Vec<u64>, + reader: R, + ref_size: u8, + finished: bool, +} + +impl<R: Read + Seek> EventReader<R> { + pub fn new(reader: R) -> EventReader<R> { + EventReader { + stack: Vec::new(), + object_offsets: Vec::new(), + reader: reader, + ref_size: 0, + finished: false, + } + } + + fn read_trailer(&mut self) -> Result<()> { + try!(self.reader.seek(SeekFrom::Start(0))); + let mut magic = [0; 8]; + try!(self.reader.read(&mut magic)); + if &magic != b"bplist00" { + return Err(Error::InvalidData); + } + + // Trailer starts with 6 bytes of padding + try!(self.reader.seek(SeekFrom::End(-32 + 6))); + let offset_size = try!(self.reader.read_u8()); + self.ref_size = try!(self.reader.read_u8()); + let num_objects = try!(self.reader.read_u64::<BigEndian>()); + let top_object = try!(self.reader.read_u64::<BigEndian>()); + let offset_table_offset = try!(self.reader.read_u64::<BigEndian>()); + + // Read offset table + try!(self.reader.seek(SeekFrom::Start(offset_table_offset))); + self.object_offsets = try!(self.read_ints(num_objects, offset_size)); + + // Seek to top object + self.stack.push(StackItem { + object_refs: vec![top_object], + ty: StackType::Root, + }); + + Ok(()) + } + + fn read_ints(&mut self, len: u64, size: u8) -> Result<Vec<u64>> { + let len = try!(u64_to_usize(len)); + let mut ints = Vec::with_capacity(len); + // TODO: Is the match hoisted out of the loop? + for _ in 0..len { + match size { + 1 => ints.push(try!(self.reader.read_u8()) as u64), + 2 => ints.push(try!(self.reader.read_u16::<BigEndian>()) as u64), + 4 => ints.push(try!(self.reader.read_u32::<BigEndian>()) as u64), + 8 => ints.push(try!(self.reader.read_u64::<BigEndian>()) as u64), + _ => return Err(Error::InvalidData), + } + } + Ok(ints) + } + + fn read_refs(&mut self, len: u64) -> Result<Vec<u64>> { + let ref_size = self.ref_size; + self.read_ints(len, ref_size) + } + + fn read_object_len(&mut self, len: u8) -> Result<u64> { + if (len & 0x0f) == 0x0f { + let len_power_of_two = try!(self.reader.read_u8()) & 0x03; + Ok(match len_power_of_two { + 0 => try!(self.reader.read_u8()) as u64, + 1 => try!(self.reader.read_u16::<BigEndian>()) as u64, + 2 => try!(self.reader.read_u32::<BigEndian>()) as u64, + 3 => try!(self.reader.read_u64::<BigEndian>()), + _ => return Err(Error::InvalidData), + }) + } else { + Ok(len as u64) + } + } + + fn read_data(&mut self, len: u64) -> Result<Vec<u8>> { + let len = try!(u64_to_usize(len)); + let mut data = vec![0; len]; + let mut total_read = 0; + + while total_read < len { + let read = try!(self.reader.read(&mut data[total_read..])); + if read == 0 { + return Err(Error::UnexpectedEof); + } + total_read += read; + } + + Ok(data) + } + + fn seek_to_object(&mut self, object_ref: u64) -> Result<u64> { + let object_ref = try!(u64_to_usize(object_ref)); + let offset = *&self.object_offsets[object_ref]; + let pos = try!(self.reader.seek(SeekFrom::Start(offset))); + Ok(pos) + } + + fn read_next(&mut self) -> Result<Option<PlistEvent>> { + if self.ref_size == 0 { + // Initialise here rather than in new + try!(self.read_trailer()); + } + + let object_ref = match self.stack.last_mut() { + Some(stack_item) => stack_item.object_refs.pop(), + // Reached the end of the plist + None => return Ok(None), + }; + + match object_ref { + Some(object_ref) => { + try!(self.seek_to_object(object_ref)); + } + None => { + // We're at the end of an array or dict. Pop the top stack item and return + let item = self.stack.pop().unwrap(); + match item.ty { + StackType::Array => return Ok(Some(PlistEvent::EndArray)), + StackType::Dict => return Ok(Some(PlistEvent::EndDictionary)), + // We're at the end of the plist + StackType::Root => return Ok(None), + } + } + } + + let token = try!(self.reader.read_u8()); + let ty = (token & 0xf0) >> 4; + let size = token & 0x0f; + + let result = match (ty, size) { + (0x0, 0x00) => return Err(Error::InvalidData), // null + (0x0, 0x08) => Some(PlistEvent::BooleanValue(false)), + (0x0, 0x09) => Some(PlistEvent::BooleanValue(true)), + (0x0, 0x0f) => return Err(Error::InvalidData), // fill + (0x1, 0) => Some(PlistEvent::IntegerValue(try!(self.reader.read_u8()) as i64)), + (0x1, 1) => { + Some(PlistEvent::IntegerValue(try!(self.reader.read_u16::<BigEndian>()) as i64)) + } + (0x1, 2) => { + Some(PlistEvent::IntegerValue(try!(self.reader.read_u32::<BigEndian>()) as i64)) + } + (0x1, 3) => Some(PlistEvent::IntegerValue(try!(self.reader.read_i64::<BigEndian>()))), + (0x1, 4) => return Err(Error::InvalidData), // 128 bit int + (0x1, _) => return Err(Error::InvalidData), // variable length int + (0x2, 2) => { + Some(PlistEvent::RealValue(try!(self.reader.read_f32::<BigEndian>()) as f64)) + } + (0x2, 3) => Some(PlistEvent::RealValue(try!(self.reader.read_f64::<BigEndian>()))), + (0x2, _) => return Err(Error::InvalidData), // odd length float + (0x3, 3) => { + // Date + // Seconds since 1/1/2001 00:00:00 + let timestamp = try!(self.reader.read_f64::<BigEndian>()); + + let secs = timestamp.floor(); + let subsecs = timestamp - secs; + + let int_secs = (secs as i64) + (31 * 365 + 8) * 86400; + let int_nanos = (subsecs * 1_000_000_000f64) as u32; + + Some(PlistEvent::DateValue(UTC.timestamp(int_secs, int_nanos))) + } + (0x4, n) => { + // Data + let len = try!(self.read_object_len(n)); + Some(PlistEvent::DataValue(try!(self.read_data(len)))) + } + (0x5, n) => { + // ASCII string + let len = try!(self.read_object_len(n)); + let raw = try!(self.read_data(len)); + let string = try!(String::from_utf8(raw)); + Some(PlistEvent::StringValue(string)) + } + (0x6, n) => { + // UTF-16 string + // n is the length of 16 bit code units + // len is the number of bytes + let len = try!(self.read_object_len(n)) * 2; + let raw = try!(self.read_data(len)); + let mut cursor = Cursor::new(raw); + + let len_div_2 = try!(u64_to_usize(len / 2)); + let mut raw_utf16 = Vec::with_capacity(len_div_2); + while cursor.position() < len { + raw_utf16.push(try!(cursor.read_u16::<BigEndian>())) + } + + let string = try!(String::from_utf16(&raw_utf16)); + Some(PlistEvent::StringValue(string)) + } + (0xa, n) => { + // Array + let len = try!(self.read_object_len(n)); + let mut object_refs = try!(self.read_refs(len)); + // Reverse so we can pop off the end of the stack in order + object_refs.reverse(); + + self.stack.push(StackItem { + ty: StackType::Array, + object_refs: object_refs, + }); + + Some(PlistEvent::StartArray(Some(len))) + } + (0xd, n) => { + // Dict + let len = try!(self.read_object_len(n)); + let key_refs = try!(self.read_refs(len)); + let value_refs = try!(self.read_refs(len)); + + let len_mul_2 = try!(u64_to_usize(len * 2)); + let len = try!(u64_to_usize(len)); + + let mut object_refs = Vec::with_capacity(len_mul_2); + + for i in 1..len + 1 { + // Reverse so we can pop off the end of the stack in order + object_refs.push(value_refs[len - i]); + object_refs.push(key_refs[len - i]); + } + + self.stack.push(StackItem { + ty: StackType::Dict, + object_refs: object_refs, + }); + + Some(PlistEvent::StartDictionary(Some(len as u64))) + } + (_, _) => return Err(Error::InvalidData), + }; + + Ok(result) + } +} + +impl<R: Read + Seek> Iterator for EventReader<R> { + type Item = Result<PlistEvent>; + + fn next(&mut self) -> Option<Result<PlistEvent>> { + if self.finished { + None + } else { + match self.read_next() { + Ok(Some(event)) => Some(Ok(event)), + Err(err) => { + self.finished = true; + Some(Err(err)) + } + Ok(None) => { + self.finished = true; + None + } + } + } + } +} + +#[cfg(test)] +mod tests { + use chrono::{TimeZone, UTC}; + use std::fs::File; + use std::path::Path; + + use super::*; + use PlistEvent; + + #[test] + fn streaming_parser() { + use PlistEvent::*; + + let reader = File::open(&Path::new("./tests/data/binary.plist")).unwrap(); + let streaming_parser = EventReader::new(reader); + let events: Vec<PlistEvent> = streaming_parser.map(|e| e.unwrap()).collect(); + + let comparison = &[StartDictionary(Some(6)), + StringValue("Lines".to_owned()), + StartArray(Some(2)), + StringValue("It is a tale told by an idiot,".to_owned()), + StringValue("Full of sound and fury, signifying nothing.".to_owned()), + EndArray, + StringValue("Death".to_owned()), + IntegerValue(1564), + StringValue("Height".to_owned()), + RealValue(1.60), + StringValue("Birthdate".to_owned()), + DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06)), + StringValue("Author".to_owned()), + StringValue("William Shakespeare".to_owned()), + StringValue("Data".to_owned()), + DataValue(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]), + EndDictionary]; + + assert_eq!(events, comparison); + } + + #[test] + fn utf16_plist() { + use PlistEvent::*; + + let reader = File::open(&Path::new("./tests/data/utf16_bplist.plist")).unwrap(); + let streaming_parser = EventReader::new(reader); + let mut events: Vec<PlistEvent> = streaming_parser.map(|e| e.unwrap()).collect(); + + assert_eq!(events[2], StringValue("\u{2605} or better".to_owned())); + + let poem = if let StringValue(ref mut poem) = events[4] { poem } else { panic!("not a string") }; + assert_eq!(poem.len(), 643); + assert_eq!(poem.pop().unwrap(), '\u{2605}'); + } +} ++
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +
+use std::collections::BTreeMap; + +use {Error, Result, Plist, PlistEvent, u64_option_to_usize}; + +pub struct Builder<T> { + stream: T, + token: Option<PlistEvent>, +} + +impl<T: Iterator<Item = Result<PlistEvent>>> Builder<T> { + pub fn new(stream: T) -> Builder<T> { + Builder { + stream: stream, + token: None, + } + } + + pub fn build(mut self) -> Result<Plist> { + try!(self.bump()); + + let plist = try!(self.build_value()); + try!(self.bump()); + match self.token { + None => (), + // The stream should have finished + _ => return Err(Error::InvalidData), + }; + Ok(plist) + } + + fn bump(&mut self) -> Result<()> { + self.token = match self.stream.next() { + Some(Ok(token)) => Some(token), + Some(Err(err)) => return Err(err), + None => None, + }; + Ok(()) + } + + fn build_value(&mut self) -> Result<Plist> { + match self.token.take() { + Some(PlistEvent::StartArray(len)) => Ok(Plist::Array(try!(self.build_array(len)))), + Some(PlistEvent::StartDictionary(len)) => { + Ok(Plist::Dictionary(try!(self.build_dict(len)))) + } + + Some(PlistEvent::BooleanValue(b)) => Ok(Plist::Boolean(b)), + Some(PlistEvent::DataValue(d)) => Ok(Plist::Data(d)), + Some(PlistEvent::DateValue(d)) => Ok(Plist::Date(d)), + Some(PlistEvent::IntegerValue(i)) => Ok(Plist::Integer(i)), + Some(PlistEvent::RealValue(f)) => Ok(Plist::Real(f)), + Some(PlistEvent::StringValue(s)) => Ok(Plist::String(s)), + + Some(PlistEvent::EndArray) => Err(Error::InvalidData), + Some(PlistEvent::EndDictionary) => Err(Error::InvalidData), + + // The stream should not have ended here + None => Err(Error::InvalidData), + } + } + + fn build_array(&mut self, len: Option<u64>) -> Result<Vec<Plist>> { + let len = try!(u64_option_to_usize(len)); + let mut values = match len { + Some(len) => Vec::with_capacity(len), + None => Vec::new(), + }; + + loop { + try!(self.bump()); + if let Some(PlistEvent::EndArray) = self.token { + self.token.take(); + return Ok(values); + } + values.push(try!(self.build_value())); + } + } + + fn build_dict(&mut self, _len: Option<u64>) -> Result<BTreeMap<String, Plist>> { + let mut values = BTreeMap::new(); + + loop { + try!(self.bump()); + match self.token.take() { + Some(PlistEvent::EndDictionary) => return Ok(values), + Some(PlistEvent::StringValue(s)) => { + try!(self.bump()); + values.insert(s, try!(self.build_value())); + } + _ => { + // Only string keys are supported in plists + return Err(Error::InvalidData); + } + } + } + } +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use super::*; + use Plist; + + #[test] + fn builder() { + use PlistEvent::*; + + // Input + + let events = vec![StartDictionary(None), + StringValue("Author".to_owned()), + StringValue("William Shakespeare".to_owned()), + StringValue("Lines".to_owned()), + StartArray(None), + StringValue("It is a tale told by an idiot,".to_owned()), + StringValue("Full of sound and fury, signifying nothing.".to_owned()), + EndArray, + StringValue("Birthdate".to_owned()), + IntegerValue(1564), + StringValue("Height".to_owned()), + RealValue(1.60), + EndDictionary]; + + let builder = Builder::new(events.into_iter().map(|e| Ok(e))); + let plist = builder.build(); + + // Expected output + + let mut lines = Vec::new(); + lines.push(Plist::String("It is a tale told by an idiot,".to_owned())); + lines.push(Plist::String("Full of sound and fury, signifying nothing.".to_owned())); + + let mut dict = BTreeMap::new(); + dict.insert("Author".to_owned(), + Plist::String("William Shakespeare".to_owned())); + dict.insert("Lines".to_owned(), Plist::Array(lines)); + dict.insert("Birthdate".to_owned(), Plist::Integer(1564)); + dict.insert("Height".to_owned(), Plist::Real(1.60)); + + assert_eq!(plist.unwrap(), Plist::Dictionary(dict)); + } +} ++
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +
+// Tests for the serializer and deserializer are located in tests/serde_/mod.rs. +// They can be run with `cargo test --features serde_tests`. + +use serde::de::{Deserializer as SerdeDeserializer, Error as SerdeError, Visitor, SeqVisitor, + MapVisitor, VariantVisitor, Deserialize, EnumVisitor}; +use std::iter::Peekable; + +use {Error, PlistEvent, u64_option_to_usize}; + +macro_rules! expect { + ($next:expr, $pat:pat) => { + match $next { + Some(Ok(v@$pat)) => v, + None => return Err(Error::UnexpectedEof), + _ => return Err(event_mismatch_error()) + } + }; + ($next:expr, $pat:pat => $save:expr) => { + match $next { + Some(Ok($pat)) => $save, + None => return Err(Error::UnexpectedEof), + _ => return Err(event_mismatch_error()) + } + }; +} + +macro_rules! try_next { + ($next:expr) => { + match $next { + Some(Ok(v)) => v, + Some(Err(_)) => return Err(event_mismatch_error()), + None => return Err(Error::UnexpectedEof) + } + } +} + +fn event_mismatch_error() -> Error { + Error::InvalidData +} + +impl SerdeError for Error { + fn custom<T: Into<String>>(msg: T) -> Self { + Error::Serde(msg.into()) + } + + fn end_of_stream() -> Self { + Error::UnexpectedEof + } +} + +pub struct Deserializer<I> + where I: IntoIterator<Item = Result<PlistEvent, Error>> +{ + events: Peekable<<I as IntoIterator>::IntoIter>, +} + +impl<I> Deserializer<I> where I: IntoIterator<Item = Result<PlistEvent, Error>> +{ + pub fn new(iter: I) -> Deserializer<I> { + Deserializer { events: iter.into_iter().peekable() } + } +} + +impl<I> SerdeDeserializer for Deserializer<I> + where I: IntoIterator<Item = Result<PlistEvent, Error>> +{ + type Error = Error; + + fn deserialize<V>(&mut self, mut visitor: V) -> Result<V::Value, Self::Error> + where V: Visitor + { + match try_next!(self.events.next()) { + PlistEvent::StartArray(len) => { + let len = try!(u64_option_to_usize(len)); + visitor.visit_seq(MapSeq::new(self, len)) + } + PlistEvent::EndArray => return Err(event_mismatch_error()), + + PlistEvent::StartDictionary(len) => { + let len = try!(u64_option_to_usize(len)); + visitor.visit_map(MapSeq::new(self, len)) + } + PlistEvent::EndDictionary => return Err(event_mismatch_error()), + + PlistEvent::BooleanValue(v) => visitor.visit_bool(v), + PlistEvent::DataValue(v) => visitor.visit_byte_buf(v), + PlistEvent::DateValue(v) => visitor.visit_string(v.to_rfc3339()), + PlistEvent::IntegerValue(v) if v.is_positive() => visitor.visit_u64(v as u64), + PlistEvent::IntegerValue(v) => visitor.visit_i64(v as i64), + PlistEvent::RealValue(v) => visitor.visit_f64(v), + PlistEvent::StringValue(v) => visitor.visit_string(v), + } + } + + fn deserialize_unit<V>(&mut self, mut visitor: V) -> Result<V::Value, Self::Error> + where V: Visitor + { + expect!(self.events.next(), PlistEvent::StringValue(_)); + visitor.visit_unit() + } + + fn deserialize_option<V>(&mut self, mut visitor: V) -> Result<V::Value, Self::Error> + where V: Visitor + { + expect!(self.events.next(), PlistEvent::StartDictionary(_)); + + let ret = match try_next!(self.events.next()) { + PlistEvent::StringValue(ref s) if &s[..] == "None" => { + let ret = match visitor.visit_none() { + Ok(ret) => ret, + Err(e) => return Err(e), + }; + // For some reason the try! below doesn't work - probably a macro hygene issue + // with Error and ::Error + // let ret = try!(visitor.visit_none()); + expect!(self.events.next(), PlistEvent::StringValue(_)); + ret + } + PlistEvent::StringValue(ref s) if &s[..] == "Some" => try!(visitor.visit_some(self)), + _ => return Err(event_mismatch_error()), + }; + + expect!(self.events.next(), PlistEvent::EndDictionary); + + Ok(ret) + } + + fn deserialize_newtype_struct<V>(&mut self, + _name: &'static str, + mut visitor: V) + -> Result<V::Value, Self::Error> + where V: Visitor + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_enum<V>(&mut self, + _enum: &'static str, + _variants: &'static [&'static str], + mut visitor: V) + -> Result<V::Value, Self::Error> + where V: EnumVisitor + { + expect!(self.events.next(), PlistEvent::StartDictionary(_)); + let ret = try!(visitor.visit(&mut *self)); + expect!(self.events.next(), PlistEvent::EndDictionary); + Ok(ret) + } +} + +impl<I> VariantVisitor for Deserializer<I> where I: IntoIterator<Item = Result<PlistEvent, Error>> +{ + type Error = Error; + + fn visit_variant<V>(&mut self) -> Result<V, Self::Error> + where V: Deserialize + { + <V as Deserialize>::deserialize(self) + } + + fn visit_unit(&mut self) -> Result<(), Self::Error> { + <() as Deserialize>::deserialize(self) + } + + fn visit_newtype<T>(&mut self) -> Result<T, Self::Error> + where T: Deserialize + { + <T as Deserialize>::deserialize(self) + } + + fn visit_tuple<V>(&mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error> + where V: Visitor + { + <Self as SerdeDeserializer>::deserialize_tuple(self, len, visitor) + } + + fn visit_struct<V>(&mut self, + fields: &'static [&'static str], + visitor: V) + -> Result<V::Value, Self::Error> + where V: Visitor + { + let name = ""; + <Self as SerdeDeserializer>::deserialize_struct(self, name, fields, visitor) + } +} + +struct MapSeq<'a, I> + where I: 'a + IntoIterator<Item = Result<PlistEvent, Error>> +{ + de: &'a mut Deserializer<I>, + remaining: Option<usize>, + finished: bool, +} + +impl<'a, I> MapSeq<'a, I> where I: 'a + IntoIterator<Item = Result<PlistEvent, Error>> +{ + fn new(de: &'a mut Deserializer<I>, len: Option<usize>) -> MapSeq<'a, I> { + MapSeq { + de: de, + remaining: len, + finished: false, + } + } +} + +impl<'a, I> SeqVisitor for MapSeq<'a, I> + where I: 'a + IntoIterator<Item = Result<PlistEvent, Error>> +{ + type Error = Error; + + fn visit<T>(&mut self) -> Result<Option<T>, Self::Error> + where T: Deserialize + { + match self.de.events.peek() { + Some(&Ok(PlistEvent::EndArray)) => { + self.de.events.next(); + self.finished = true; + return Ok(None); + } + _ => <T as Deserialize>::deserialize(self.de).map(|k| Some(k)), + } + } + + fn end(&mut self) -> Result<(), Self::Error> { + if !self.finished { + self.finished = true; + expect!(self.de.events.next(), PlistEvent::EndArray); + } + Ok(()) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + <Self as MapVisitor>::size_hint(self) + } +} + +impl<'a, I> MapVisitor for MapSeq<'a, I> + where I: 'a + IntoIterator<Item = Result<PlistEvent, Error>> +{ + type Error = Error; + + fn visit_key<K>(&mut self) -> Result<Option<K>, Self::Error> + where K: Deserialize + { + match self.de.events.peek() { + Some(&Ok(PlistEvent::EndDictionary)) => { + self.de.events.next(); + self.finished = true; + return Ok(None); + } + _ => <K as Deserialize>::deserialize(self.de).map(|k| Some(k)), + } + } + + fn visit_value<V>(&mut self) -> Result<V, Self::Error> + where V: Deserialize + { + <V as Deserialize>::deserialize(self.de) + } + + fn end(&mut self) -> Result<(), Self::Error> { + if !self.finished { + self.finished = true; + expect!(self.de.events.next(), PlistEvent::EndDictionary); + } + Ok(()) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + match self.remaining { + Some(len) => (len, Some(len)), + None => (0, None), + } + } +} ++
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +
+//! # Plist +//! +//! A rusty plist parser. +//! +//! ## Usage +//! +//! Put this in your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! plist = "0.0.12" +//! ``` +//! +//! And put this in your crate root: +//! +//! ```rust +//! extern crate plist; +//! ``` +//! +//! ## Examples +//! +//! ```rust ignore +//! use plist::Plist; +//! use std::fs::File; +//! +//! let file = File::open("tests/data/xml.plist").unwrap(); +//! let plist = Plist::read(file).unwrap(); +//! +//! match plist { +//! Plist::Array(_array) => (), +//! _ => () +//! } +//! +//! ``` +//! +//! + +extern crate byteorder; +extern crate chrono; +extern crate rustc_serialize; +extern crate serde; +extern crate xml as xml_rs; + +pub mod binary; +pub mod xml; + +mod builder; +mod de; +mod ser; + +pub use de::Deserializer; +pub use ser::Serializer; + +use chrono::{DateTime, UTC}; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use std::fmt; +use std::io::{Read, Seek, SeekFrom, Write}; +use std::io::Error as IoError; + +pub fn deserialize<R: Read + Seek, T: Deserialize>(reader: R) -> Result<T> { + let reader = EventReader::new(reader); + let mut de = Deserializer::new(reader); + Deserialize::deserialize(&mut de) +} + +pub fn serialize_to_xml<W: Write, T: Serialize>(writer: W, value: &T) -> Result<()> { + let writer = xml::EventWriter::new(writer); + let mut ser = Serializer::new(writer); + value.serialize(&mut ser) +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Plist { + Array(Vec<Plist>), + Dictionary(BTreeMap<String, Plist>), + Boolean(bool), + Data(Vec<u8>), + Date(DateTime<UTC>), + Real(f64), + Integer(i64), + String(String), +} + +use rustc_serialize::base64::{STANDARD, ToBase64}; +use rustc_serialize::json::Json as RustcJson; + +impl Plist { + pub fn read<R: Read + Seek>(reader: R) -> Result<Plist> { + let reader = EventReader::new(reader); + Plist::from_events(reader) + } + + pub fn from_events<T>(events: T) -> Result<Plist> + where T: IntoIterator<Item = Result<PlistEvent>> + { + let iter = events.into_iter(); + let builder = builder::Builder::new(iter); + builder.build() + } + + pub fn into_events(self) -> Vec<PlistEvent> { + let mut events = Vec::new(); + self.into_events_inner(&mut events); + events + } + + fn into_events_inner(self, events: &mut Vec<PlistEvent>) { + match self { + Plist::Array(array) => { + events.push(PlistEvent::StartArray(Some(array.len() as u64))); + for value in array.into_iter() { + value.into_events_inner(events); + } + events.push(PlistEvent::EndArray); + } + Plist::Dictionary(dict) => { + events.push(PlistEvent::StartDictionary(Some(dict.len() as u64))); + for (key, value) in dict.into_iter() { + events.push(PlistEvent::StringValue(key)); + value.into_events_inner(events); + } + events.push(PlistEvent::EndDictionary); + } + Plist::Boolean(value) => events.push(PlistEvent::BooleanValue(value)), + Plist::Data(value) => events.push(PlistEvent::DataValue(value)), + Plist::Date(value) => events.push(PlistEvent::DateValue(value)), + Plist::Real(value) => events.push(PlistEvent::RealValue(value)), + Plist::Integer(value) => events.push(PlistEvent::IntegerValue(value)), + Plist::String(value) => events.push(PlistEvent::StringValue(value)), + } + } + + pub fn into_rustc_serialize_json(self) -> RustcJson { + match self { + Plist::Array(value) => { + RustcJson::Array(value.into_iter().map(|p| p.into_rustc_serialize_json()).collect()) + } + Plist::Dictionary(value) => { + RustcJson::Object(value.into_iter() + .map(|(k, v)| (k, v.into_rustc_serialize_json())) + .collect()) + } + Plist::Boolean(value) => RustcJson::Boolean(value), + Plist::Data(value) => RustcJson::String(value.to_base64(STANDARD)), + Plist::Date(value) => RustcJson::String(value.to_rfc3339()), + Plist::Real(value) => RustcJson::F64(value), + Plist::Integer(value) => RustcJson::I64(value), + Plist::String(value) => RustcJson::String(value), + } + } +} + +impl Plist { + /// If the `Plist` is an Array, returns the associated Vec. + /// Returns None otherwise. + pub fn as_array(&self) -> Option<&Vec<Plist>> { + match self { + &Plist::Array(ref array) => Some(array), + _ => None, + } + } + + /// If the `Plist` is an Array, returns the associated mutable Vec. + /// Returns None otherwise. + pub fn as_array_mut(&mut self) -> Option<&mut Vec<Plist>> { + match self { + &mut Plist::Array(ref mut array) => Some(array), + _ => None, + } + } + + /// If the `Plist` is a Dictionary, returns the associated BTreeMap. + /// Returns None otherwise. + pub fn as_dictionary(&self) -> Option<&BTreeMap<String, Plist>> { + match self { + &Plist::Dictionary(ref map) => Some(map), + _ => None, + } + } + + /// If the `Plist` is a Dictionary, returns the associated mutable BTreeMap. + /// Returns None otherwise. + pub fn as_dictionary_mut(&mut self) -> Option<&mut BTreeMap<String, Plist>> { + match self { + &mut Plist::Dictionary(ref mut map) => Some(map), + _ => None, + } + } + + /// If the `Plist` is a Boolean, returns the associated bool. + /// Returns None otherwise. + pub fn as_boolean(&self) -> Option<bool> { + match self { + &Plist::Boolean(v) => Some(v), + _ => None, + } + } + + /// If the `Plist` is a Data, returns the underlying Vec. + /// Returns None otherwise. + /// + /// This method consumes the `Plist`. If this is not desired, please use + /// `as_data` method. + pub fn into_data(self) -> Option<Vec<u8>> { + match self { + Plist::Data(data) => Some(data), + _ => None, + } + } + + /// If the `Plist` is a Data, returns the associated Vec. + /// Returns None otherwise. + pub fn as_data(&self) -> Option<&[u8]> { + match self { + &Plist::Data(ref data) => Some(data), + _ => None, + } + } + + /// If the `Plist` is a Date, returns the associated DateTime. + /// Returns None otherwise. + pub fn as_date(&self) -> Option<DateTime<UTC>> { + match self { + &Plist::Date(date) => Some(date), + _ => None, + } + } + + /// If the `Plist` is a Real, returns the associated f64. + /// Returns None otherwise. + pub fn as_real(&self) -> Option<f64> { + match self { + &Plist::Real(v) => Some(v), + _ => None, + } + } + + /// If the `Plist` is an Integer, returns the associated i64. + /// Returns None otherwise. + pub fn as_integer(&self) -> Option<i64> { + match self { + &Plist::Integer(v) => Some(v), + _ => None, + } + } + + /// If the `Plist` is a String, returns the underlying String. + /// Returns None otherwise. + /// + /// This method consumes the `Plist`. If this is not desired, please use + /// `as_string` method. + pub fn into_string(self) -> Option<String> { + match self { + Plist::String(v) => Some(v), + _ => None, + } + } + + /// If the `Plist` is a String, returns the associated str. + /// Returns None otherwise. + pub fn as_string(&self) -> Option<&str> { + match self { + &Plist::String(ref v) => Some(v), + _ => None, + } + } +} + +impl From<Vec<Plist>> for Plist { + fn from(from: Vec<Plist>) -> Plist { Plist::Array(from) } +} + +impl From<BTreeMap<String, Plist>> for Plist { + fn from(from: BTreeMap<String, Plist>) -> Plist { Plist::Dictionary(from) } +} + +impl From<bool> for Plist { + fn from(from: bool) -> Plist { Plist::Boolean(from) } +} + +impl<'a> From<&'a bool> for Plist { + fn from(from: &'a bool) -> Plist { Plist::Boolean(*from) } +} + +impl From<DateTime<UTC>> for Plist { + fn from(from: DateTime<UTC>) -> Plist { Plist::Date(from) } +} + +impl<'a> From<&'a DateTime<UTC>> for Plist { + fn from(from: &'a DateTime<UTC>) -> Plist { Plist::Date(from.clone()) } +} + +impl From<f64> for Plist { + fn from(from: f64) -> Plist { Plist::Real(from) } +} + +impl From<f32> for Plist { + fn from(from: f32) -> Plist { Plist::Real(from as f64) } +} + +impl From<i64> for Plist { + fn from(from: i64) -> Plist { Plist::Integer(from) } +} + +impl From<i32> for Plist { + fn from(from: i32) -> Plist { Plist::Integer(from as i64) } +} + +impl From<i16> for Plist { + fn from(from: i16) -> Plist { Plist::Integer(from as i64) } +} + +impl From<i8> for Plist { + fn from(from: i8) -> Plist { Plist::Integer(from as i64) } +} + +impl From<u32> for Plist { + fn from(from: u32) -> Plist { Plist::Integer(from as i64) } +} + +impl From<u16> for Plist { + fn from(from: u16) -> Plist { Plist::Integer(from as i64) } +} + +impl From<u8> for Plist { + fn from(from: u8) -> Plist { Plist::Integer(from as i64) } +} + +impl<'a> From<&'a f64> for Plist { + fn from(from: &'a f64) -> Plist { Plist::Real(*from) } +} + +impl<'a> From<&'a f32> for Plist { + fn from(from: &'a f32) -> Plist { Plist::Real(*from as f64) } +} + +impl<'a> From<&'a i64> for Plist { + fn from(from: &'a i64) -> Plist { Plist::Integer(*from) } +} + +impl<'a> From<&'a i32> for Plist { + fn from(from: &'a i32) -> Plist { Plist::Integer(*from as i64) } +} + +impl<'a> From<&'a i16> for Plist { + fn from(from: &'a i16) -> Plist { Plist::Integer(*from as i64) } +} + +impl<'a> From<&'a i8> for Plist { + fn from(from: &'a i8) -> Plist { Plist::Integer(*from as i64) } +} + +impl<'a> From<&'a u32> for Plist { + fn from(from: &'a u32) -> Plist { Plist::Integer(*from as i64) } +} + +impl<'a> From<&'a u16> for Plist { + fn from(from: &'a u16) -> Plist { Plist::Integer(*from as i64) } +} + +impl<'a> From<&'a u8> for Plist { + fn from(from: &'a u8) -> Plist { Plist::Integer(*from as i64) } +} + +impl From<String> for Plist { + fn from(from: String) -> Plist { Plist::String(from) } +} + +impl<'a> From<&'a str> for Plist { + fn from(from: &'a str) -> Plist { Plist::String(from.into()) } +} + +/// An encoding of a plist as a flat structure. +/// +/// Output by the event readers. +/// +/// Dictionary keys and values are represented as pairs of values e.g.: +/// +/// ```ignore rust +/// StartDictionary +/// StringValue("Height") // Key +/// RealValue(181.2) // Value +/// StringValue("Age") // Key +/// IntegerValue(28) // Value +/// EndDictionary +/// ``` +#[derive(Clone, Debug, PartialEq)] +pub enum PlistEvent { + // While the length of an array or dict cannot be feasably greater than max(usize) this better + // conveys the concept of an effectively unbounded event stream. + StartArray(Option<u64>), + EndArray, + + StartDictionary(Option<u64>), + EndDictionary, + + BooleanValue(bool), + DataValue(Vec<u8>), + DateValue(DateTime<UTC>), + IntegerValue(i64), + RealValue(f64), + StringValue(String), +} + +pub type Result<T> = ::std::result::Result<T, Error>; + +#[derive(Debug)] +pub enum Error { + InvalidData, + UnexpectedEof, + Io(IoError), + Serde(String) +} + +impl ::std::error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::InvalidData => "invalid data", + Error::UnexpectedEof => "unexpected eof", + Error::Io(ref err) => err.description(), + Error::Serde(ref err) => &err + } + } + + fn cause(&self) -> Option<&::std::error::Error> { + match *self { + Error::Io(ref err) => Some(err), + _ => None, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Io(ref err) => err.fmt(fmt), + _ => <Self as ::std::error::Error>::description(self).fmt(fmt), + } + } +} + +impl From<IoError> for Error { + fn from(err: IoError) -> Error { + Error::Io(err) + } +} + +pub struct EventReader<R: Read + Seek>(EventReaderInner<R>); + +enum EventReaderInner<R: Read + Seek> { + Uninitialized(Option<R>), + Xml(xml::EventReader<R>), + Binary(binary::EventReader<R>), +} + +impl<R: Read + Seek> EventReader<R> { + pub fn new(reader: R) -> EventReader<R> { + EventReader(EventReaderInner::Uninitialized(Some(reader))) + } + + fn is_binary(reader: &mut R) -> Result<bool> { + try!(reader.seek(SeekFrom::Start(0))); + let mut magic = [0; 8]; + try!(reader.read(&mut magic)); + try!(reader.seek(SeekFrom::Start(0))); + + Ok(if &magic == b"bplist00" { + true + } else { + false + }) + } +} + +impl<R: Read + Seek> Iterator for EventReader<R> { + type Item = Result<PlistEvent>; + + fn next(&mut self) -> Option<Result<PlistEvent>> { + let mut reader = match self.0 { + EventReaderInner::Xml(ref mut parser) => return parser.next(), + EventReaderInner::Binary(ref mut parser) => return parser.next(), + EventReaderInner::Uninitialized(ref mut reader) => reader.take().unwrap(), + }; + + let event_reader = match EventReader::is_binary(&mut reader) { + Ok(true) => EventReaderInner::Binary(binary::EventReader::new(reader)), + Ok(false) => EventReaderInner::Xml(xml::EventReader::new(reader)), + Err(err) => { + ::std::mem::replace(&mut self.0, EventReaderInner::Uninitialized(Some(reader))); + return Some(Err(err)); + } + }; + + ::std::mem::replace(&mut self.0, event_reader); + + self.next() + } +} + +pub trait EventWriter { + fn write(&mut self, event: &PlistEvent) -> Result<()>; +} + +fn u64_to_usize(len_u64: u64) -> Result<usize> { + let len = len_u64 as usize; + if len as u64 != len_u64 { + return Err(Error::InvalidData); // Too long + } + Ok(len) +} + +fn u64_option_to_usize(len: Option<u64>) -> Result<Option<usize>> { + match len { + Some(len) => Ok(Some(try!(u64_to_usize(len)))), + None => Ok(None), + } +} + +#[cfg(test)] +mod tests { + use super::Plist; + + #[test] + fn test_plist_access() { + use std::collections::BTreeMap; + use chrono::*; + + let vec = vec![Plist::Real(0.0)]; + let mut array = Plist::Array(vec.clone()); + assert_eq!(array.as_array(), Some(&vec.clone())); + assert_eq!(array.as_array_mut(), Some(&mut vec.clone())); + + let mut map = BTreeMap::new(); + map.insert("key1".to_owned(), Plist::String("value1".to_owned())); + let mut dict = Plist::Dictionary(map.clone()); + assert_eq!(dict.as_dictionary(), Some(&map.clone())); + assert_eq!(dict.as_dictionary_mut(), Some(&mut map.clone())); + + assert_eq!(Plist::Boolean(true).as_boolean(), Some(true)); + + let slice: &[u8] = &[1, 2, 3]; + assert_eq!(Plist::Data(slice.to_vec()).as_data(), Some(slice)); + assert_eq!(Plist::Data(slice.to_vec()).into_data(), Some(slice.to_vec())); + + let date: DateTime<UTC> = UTC::now(); + assert_eq!(Plist::Date(date).as_date(), Some(date)); + + assert_eq!(Plist::Real(0.0).as_real(), Some(0.0)); + assert_eq!(Plist::Integer(1).as_integer(), Some(1)); + assert_eq!(Plist::String("2".to_owned()).as_string(), Some("2")); + assert_eq!(Plist::String("t".to_owned()).into_string(), Some("t".to_owned())); + } +} ++
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +
+// Tests for the serializer and deserializer are located in tests/serde_/mod.rs. +// They can be run with `cargo test --features serde_tests`. + +use serde::ser::{Error as SerdeError, MapVisitor, Serialize, Serializer as SerdeSerializer, SeqVisitor}; + +use {Error, EventWriter, PlistEvent}; + +impl SerdeError for Error { + fn custom<T: Into<String>>(msg: T) -> Self { + Error::Serde(msg.into()) + } + + fn invalid_value(_: &str) -> Self { + Error::InvalidData + } +} + +pub struct Serializer<W: EventWriter> { + writer: W, +} + +impl<W: EventWriter> Serializer<W> { + pub fn new(writer: W) -> Serializer<W> { + Serializer { writer: writer } + } + + #[inline] + fn emit(&mut self, event: PlistEvent) -> Result<(), Error> { + self.writer.write(&event) + } + + pub fn into_inner(self) -> W { + self.writer + } + + fn single_key_dict<F>(&mut self, + key: String, + value_fn: F) + -> Result<(), <Self as SerdeSerializer>::Error> + where F: FnOnce(&mut Serializer<W>) -> Result<(), <Self as SerdeSerializer>::Error> + { + // Emit {key: value} + try!(self.emit(PlistEvent::StartDictionary(Some(1)))); + try!(self.emit(PlistEvent::StringValue(key))); + try!(value_fn(self)); + try!(self.emit(PlistEvent::EndDictionary)); + Ok(()) + } +} + +impl<W: EventWriter> SerdeSerializer for Serializer<W> { + type Error = Error; + + fn serialize_bool(&mut self, v: bool) -> Result<(), Self::Error> { + self.emit(PlistEvent::BooleanValue(v)) + } + + fn serialize_i64(&mut self, v: i64) -> Result<(), Self::Error> { + self.emit(PlistEvent::IntegerValue(v)) + } + + fn serialize_u64(&mut self, v: u64) -> Result<(), Self::Error> { + self.emit(PlistEvent::IntegerValue(v as i64)) + } + + fn serialize_f64(&mut self, v: f64) -> Result<(), Self::Error> { + self.emit(PlistEvent::RealValue(v)) + } + + fn serialize_str(&mut self, value: &str) -> Result<(), Self::Error> { + self.emit(PlistEvent::StringValue(value.to_owned())) + } + + fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error> { + self.emit(PlistEvent::DataValue(value.to_owned())) + } + + fn serialize_unit(&mut self) -> Result<(), Self::Error> { + // Emit empty string + self.emit(PlistEvent::StringValue(String::new())) + } + + fn serialize_none(&mut self) -> Result<(), Self::Error> { + self.single_key_dict("None".to_owned(), |this| this.serialize_unit()) + } + + fn serialize_some<V>(&mut self, value: V) -> Result<(), Self::Error> + where V: Serialize + { + self.single_key_dict("Some".to_owned(), |this| value.serialize(this)) + } + + fn serialize_seq<V>(&mut self, mut visitor: V) -> Result<(), Self::Error> + where V: SeqVisitor + { + let len = visitor.len().map(|len| len as u64); + try!(self.emit(PlistEvent::StartArray(len))); + loop { + match try!(visitor.visit(self)) { + Some(()) => (), + None => break, + } + } + try!(self.emit(PlistEvent::EndArray)); + Ok(()) + } + + fn serialize_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error> + where T: Serialize + { + value.serialize(self) + } + + fn serialize_map<V>(&mut self, mut visitor: V) -> Result<(), Self::Error> + where V: MapVisitor + { + let len = visitor.len().map(|len| len as u64); + try!(self.emit(PlistEvent::StartDictionary(len))); + loop { + match try!(visitor.visit(self)) { + Some(()) => (), + None => break, + } + } + try!(self.emit(PlistEvent::EndDictionary)); + Ok(()) + } + + fn serialize_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error> + where K: Serialize, + V: Serialize + { + try!(key.serialize(self)); + try!(value.serialize(self)); + Ok(()) + } + + fn serialize_unit_variant(&mut self, + _name: &'static str, + _variant_index: usize, + variant: &'static str) + -> Result<(), Self::Error> { + self.single_key_dict(variant.to_owned(), |this| this.serialize_unit()) + } + + fn serialize_newtype_struct<T>(&mut self, _name: &'static str, value: T) -> Result<(), Self::Error> + where T: Serialize + { + value.serialize(self) + } + + fn serialize_newtype_variant<T>(&mut self, + _name: &'static str, + _variant_index: usize, + variant: &'static str, + value: T) + -> Result<(), Self::Error> + where T: Serialize + { + self.single_key_dict(variant.to_owned(), |this| value.serialize(this)) + } + + fn serialize_tuple_variant<V>(&mut self, + _name: &'static str, + _variant_index: usize, + variant: &'static str, + visitor: V) + -> Result<(), Self::Error> + where V: SeqVisitor + { + self.single_key_dict(variant.to_owned(), + |this| this.serialize_tuple_struct(variant, visitor)) + } + + fn serialize_struct_variant<V>(&mut self, + _name: &'static str, + _variant_index: usize, + variant: &'static str, + visitor: V) + -> Result<(), Self::Error> + where V: MapVisitor + { + self.single_key_dict(variant.to_owned(), + |this| this.serialize_struct(variant, visitor)) + } +} ++
1 +2 +3 +4 +5 +
+mod reader; +mod writer; + +pub use self::reader::EventReader; +pub use self::writer::EventWriter; ++
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +
+use chrono::{DateTime, UTC}; +use chrono::format::ParseError as ChronoParseError; +use rustc_serialize::base64::FromBase64; +use std::io::Read; +use std::str::FromStr; +use xml_rs::reader::{EventReader as XmlEventReader, ParserConfig, XmlEvent}; + +use {Error, Result, PlistEvent}; + +impl From<ChronoParseError> for Error { + fn from(_: ChronoParseError) -> Error { + Error::InvalidData + } +} + +pub struct EventReader<R: Read> { + xml_reader: XmlEventReader<R>, + queued_event: Option<XmlEvent>, + element_stack: Vec<String>, + finished: bool, +} + +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::new_with_config(reader, config), + queued_event: None, + element_stack: Vec::new(), + finished: false, + } + } + + fn read_content<F>(&mut self, f: F) -> Result<PlistEvent> + where F: FnOnce(String) -> Result<PlistEvent> + { + match self.xml_reader.next() { + Ok(XmlEvent::Characters(s)) => f(s), + Ok(event @ XmlEvent::EndElement{..}) => { + self.queued_event = Some(event); + f("".to_owned()) + } + _ => Err(Error::InvalidData), + } + } + + fn next_event(&mut self) -> ::std::result::Result<XmlEvent, ()> { + if let Some(event) = self.queued_event.take() { + Ok(event) + } else { + self.xml_reader.next().map_err(|_| ()) + } + } + + fn read_next(&mut self) -> Option<Result<PlistEvent>> { + loop { + match self.next_event() { + Ok(XmlEvent::StartElement { name, .. }) => { + // Add the current element to the element stack + self.element_stack.push(name.local_name.clone()); + + match &name.local_name[..] { + "plist" => (), + "array" => return Some(Ok(PlistEvent::StartArray(None))), + "dict" => return Some(Ok(PlistEvent::StartDictionary(None))), + "key" => return Some(self.read_content(|s| Ok(PlistEvent::StringValue(s)))), + "true" => return Some(Ok(PlistEvent::BooleanValue(true))), + "false" => return Some(Ok(PlistEvent::BooleanValue(false))), + "data" => { + return Some(self.read_content(|s| { + let s: String = s.replace(" ", "").replace("\t", ""); + match FromBase64::from_base64(&s[..]) { + Ok(b) => Ok(PlistEvent::DataValue(b)), + Err(_) => Err(Error::InvalidData), + } + })) + } + "date" => { + return Some(self.read_content(|s| { + let date = try!(DateTime::parse_from_rfc3339(&s)); + Ok(PlistEvent::DateValue(date.with_timezone(&UTC))) + })) + } + "integer" => { + return Some(self.read_content(|s| { + match FromStr::from_str(&s) { + Ok(i) => Ok(PlistEvent::IntegerValue(i)), + Err(_) => Err(Error::InvalidData), + } + })) + } + "real" => { + return Some(self.read_content(|s| { + match FromStr::from_str(&s) { + Ok(f) => Ok(PlistEvent::RealValue(f)), + Err(_) => Err(Error::InvalidData), + } + })) + } + "string" => { + return Some(self.read_content(|s| Ok(PlistEvent::StringValue(s)))) + } + _ => return Some(Err(Error::InvalidData)), + } + } + Ok(XmlEvent::EndElement { name, .. }) => { + // Check the corrent element is being closed + match self.element_stack.pop() { + Some(ref open_name) if &name.local_name == open_name => (), + Some(ref _open_name) => return Some(Err(Error::InvalidData)), + None => return Some(Err(Error::InvalidData)), + } + + match &name.local_name[..] { + "array" => return Some(Ok(PlistEvent::EndArray)), + "dict" => return Some(Ok(PlistEvent::EndDictionary)), + "plist" => (), + _ => (), + } + } + Ok(XmlEvent::EndDocument) => { + match self.element_stack.is_empty() { + true => return None, + false => return Some(Err(Error::UnexpectedEof)), + } + } + Err(_) => return Some(Err(Error::InvalidData)), + _ => (), + } + } + } +} + +impl<R: Read> Iterator for EventReader<R> { + type Item = Result<PlistEvent>; + + fn next(&mut self) -> Option<Result<PlistEvent>> { + if self.finished { + None + } else { + match self.read_next() { + Some(Ok(event)) => Some(Ok(event)), + Some(Err(err)) => { + self.finished = true; + Some(Err(err)) + } + None => { + self.finished = true; + None + } + } + } + } +} + +#[cfg(test)] +mod tests { + use chrono::{TimeZone, UTC}; + use std::fs::File; + use std::path::Path; + + use super::*; + use PlistEvent; + + #[test] + fn streaming_parser() { + use PlistEvent::*; + + let reader = File::open(&Path::new("./tests/data/xml.plist")).unwrap(); + let streaming_parser = EventReader::new(reader); + let events: Vec<PlistEvent> = streaming_parser.map(|e| e.unwrap()).collect(); + + let comparison = &[StartDictionary(None), + StringValue("Author".to_owned()), + StringValue("William Shakespeare".to_owned()), + StringValue("Lines".to_owned()), + StartArray(None), + StringValue("It is a tale told by an idiot,".to_owned()), + StringValue("Full of sound and fury, signifying nothing.".to_owned()), + EndArray, + StringValue("Death".to_owned()), + IntegerValue(1564), + StringValue("Height".to_owned()), + RealValue(1.60), + StringValue("Data".to_owned()), + DataValue(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]), + StringValue("Birthdate".to_owned()), + DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06)), + StringValue("Blank".to_owned()), + StringValue("".to_owned()), + EndDictionary]; + + assert_eq!(events, comparison); + } + + #[test] + fn bad_data() { + let reader = File::open(&Path::new("./tests/data/xml_error.plist")).unwrap(); + let streaming_parser = EventReader::new(reader); + let events: Vec<_> = streaming_parser.collect(); + + assert!(events.last().unwrap().is_err()); + } +} ++
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +
+use rustc_serialize::base64::{MIME, ToBase64}; +use std::borrow::Cow; +use std::io::Write; +use xml_rs::attribute::Attribute; +use xml_rs::name::Name; +use xml_rs::namespace::Namespace; +use xml_rs::writer::{Error as XmlWriterError, EventWriter as XmlEventWriter, EmitterConfig}; +use xml_rs::writer::events::XmlEvent as WriteXmlEvent; + +use {Error, EventWriter as PlistEventWriter, PlistEvent, Result}; + +impl From<XmlWriterError> for Error { + fn from(err: XmlWriterError) -> Error { + match err { + XmlWriterError::Io(err) => Error::Io(err), + _ => Error::InvalidData, + } + } +} + +enum Element { + Dictionary(DictionaryState), + Array, + Root, +} + +enum DictionaryState { + ExpectKey, + ExpectValue, +} + +pub struct EventWriter<W: Write> { + xml_writer: XmlEventWriter<W>, + stack: Vec<Element>, + // Not very nice + empty_namespace: Namespace, +} + +impl<W: Write> EventWriter<W> { + pub fn new(writer: W) -> EventWriter<W> { + let config = EmitterConfig { + line_separator: "\n".into(), + indent_string: " ".into(), + perform_indent: true, + perform_escaping: true, + write_document_declaration: true, + normalize_empty_elements: true, + cdata_to_characters: true, + keep_element_names_stack: false, + autopad_comments: true, + }; + + EventWriter { + xml_writer: XmlEventWriter::new_with_config(writer, config), + stack: Vec::new(), + empty_namespace: Namespace::empty(), + } + } + + fn write_element_and_value(&mut self, name: &str, value: &str) -> Result<()> { + try!(self.start_element(name)); + try!(self.write_value(value)); + try!(self.end_element(name)); + Ok(()) + } + + fn start_element(&mut self, name: &str) -> Result<()> { + try!(self.xml_writer.write(WriteXmlEvent::StartElement { + name: Name::local(name), + attributes: Cow::Borrowed(&[]), + namespace: Cow::Borrowed(&self.empty_namespace), + })); + Ok(()) + } + + fn end_element(&mut self, name: &str) -> Result<()> { + try!(self.xml_writer.write(WriteXmlEvent::EndElement { name: Some(Name::local(name)) })); + Ok(()) + } + + fn write_value(&mut self, value: &str) -> Result<()> { + try!(self.xml_writer.write(WriteXmlEvent::Characters(value))); + Ok(()) + } + + fn maybe_end_plist(&mut self) -> Result<()> { + // If there are no more open tags then write the </plist> element + if self.stack.len() == 1 { + try!(self.end_element("plist")); + if let Some(Element::Root) = self.stack.pop() {} else { + return Err(Error::InvalidData); + } + } + Ok(()) + } + + pub fn write(&mut self, event: &PlistEvent) -> Result<()> { + <Self as PlistEventWriter>::write(self, event) + } +} + +impl<W: Write> PlistEventWriter for EventWriter<W> { + fn write(&mut self, event: &PlistEvent) -> Result<()> { + match self.stack.pop() { + Some(Element::Dictionary(DictionaryState::ExpectKey)) => { + match *event { + PlistEvent::StringValue(ref value) => { + try!(self.write_element_and_value("key", &*value)); + self.stack.push(Element::Dictionary(DictionaryState::ExpectValue)); + } + PlistEvent::EndDictionary => { + try!(self.end_element("dict")); + // We might be closing the last tag here as well + try!(self.maybe_end_plist()); + } + _ => return Err(Error::InvalidData), + }; + return Ok(()); + } + Some(Element::Dictionary(DictionaryState::ExpectValue)) => { + self.stack.push(Element::Dictionary(DictionaryState::ExpectKey)) + } + Some(other) => self.stack.push(other), + None => { + let version_name = Name::local("version"); + let version_attr = Attribute::new(version_name, "1.0"); + + try!(self.xml_writer.write(WriteXmlEvent::StartElement { + name: Name::local("plist"), + attributes: Cow::Borrowed(&[version_attr]), + namespace: Cow::Borrowed(&self.empty_namespace), + })); + + self.stack.push(Element::Root); + } + } + + match *event { + PlistEvent::StartArray(_) => { + try!(self.start_element("array")); + self.stack.push(Element::Array); + } + PlistEvent::EndArray => { + try!(self.end_element("array")); + if let Some(Element::Array) = self.stack.pop() {} else { + return Err(Error::InvalidData); + } + } + + PlistEvent::StartDictionary(_) => { + try!(self.start_element("dict")); + self.stack.push(Element::Dictionary(DictionaryState::ExpectKey)); + } + PlistEvent::EndDictionary => return Err(Error::InvalidData), + + PlistEvent::BooleanValue(true) => { + try!(self.start_element("true")); + try!(self.end_element("true")); + } + PlistEvent::BooleanValue(false) => { + try!(self.start_element("false")); + try!(self.end_element("false")); + } + PlistEvent::DataValue(ref value) => { + let base64_data = value.to_base64(MIME); + try!(self.write_element_and_value("data", &base64_data)); + } + PlistEvent::DateValue(ref value) => { + let date = format!("{:?}", value); + try!(self.write_element_and_value("date", &date)); + } + PlistEvent::IntegerValue(ref value) => { + try!(self.write_element_and_value("integer", &value.to_string())) + } + PlistEvent::RealValue(ref value) => { + try!(self.write_element_and_value("real", &value.to_string())) + } + PlistEvent::StringValue(ref value) => { + try!(self.write_element_and_value("string", &*value)) + } + }; + + try!(self.maybe_end_plist()); + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use chrono::{TimeZone, UTC}; + use std::io::Cursor; + + use super::*; + + #[test] + fn streaming_parser() { + use PlistEvent::*; + + let plist = &[StartDictionary(None), + StringValue("Author".to_owned()), + StringValue("William Shakespeare".to_owned()), + StringValue("Lines".to_owned()), + StartArray(None), + StringValue("It is a tale told by an idiot,".to_owned()), + StringValue("Full of sound and fury, signifying nothing.".to_owned()), + EndArray, + StringValue("Death".to_owned()), + IntegerValue(1564), + StringValue("Height".to_owned()), + RealValue(1.60), + StringValue("Data".to_owned()), + DataValue(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]), + StringValue("Birthdate".to_owned()), + DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06)), + EndDictionary]; + + let mut cursor = Cursor::new(Vec::new()); + + { + let mut plist_w = EventWriter::new(&mut cursor); + + for item in plist { + plist_w.write(item).unwrap(); + } + } + + let comparison = "<?xml version=\"1.0\" encoding=\"utf-8\"?> +<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>Death</key> + <integer>1564</integer> + <key>Height</key> + <real>1.6</real> + <key>Data</key> + <data>AAAAvgAAAAMAAAAeAAAA</data> + <key>Birthdate</key> + <date>1981-05-16T11:32:06Z</date> + </dict> +</plist>"; + + let s = String::from_utf8(cursor.into_inner()).unwrap(); + + assert_eq!(s, comparison); + } +} ++