diff options
| author | Edward Barnard | 2015-12-22 12:58:19 +0000 |
|---|---|---|
| committer | Edward Barnard | 2015-12-22 12:58:19 +0000 |
| commit | eef9d906b38def0091faa2dc955a4c0970fe251d (patch) | |
| tree | 20d14ca56e2e8ee2ae9838b8ef806c48052126b2 /src | |
| parent | e257aaef791ba83dc7cbdde358180c9394017459 (diff) | |
| download | rust-plist-eef9d906b38def0091faa2dc955a4c0970fe251d.tar.bz2 | |
Rustfmt
Diffstat (limited to 'src')
| -rw-r--r-- | src/binary/mod.rs | 2 | ||||
| -rw-r--r-- | src/binary/reader.rs | 600 | ||||
| -rw-r--r-- | src/builder.rs | 245 | ||||
| -rw-r--r-- | src/lib.rs | 270 | ||||
| -rw-r--r-- | src/xml/mod.rs | 2 | ||||
| -rw-r--r-- | src/xml/reader.rs | 364 | ||||
| -rw-r--r-- | src/xml/writer.rs | 433 |
7 files changed, 980 insertions, 936 deletions
diff --git a/src/binary/mod.rs b/src/binary/mod.rs index 460dbd8..7c9ae75 100644 --- a/src/binary/mod.rs +++ b/src/binary/mod.rs @@ -1,3 +1,3 @@ mod reader; -pub use self::reader::EventReader;
\ No newline at end of file +pub use self::reader::EventReader; diff --git a/src/binary/reader.rs b/src/binary/reader.rs index 11c20cc..eec7554 100644 --- a/src/binary/reader.rs +++ b/src/binary/reader.rs @@ -7,320 +7,330 @@ use std::string::FromUtf16Error; use {ReadError, ReadResult, PlistEvent}; impl From<ByteorderError> for ReadError { - fn from(err: ByteorderError) -> ReadError { - match err { - ByteorderError::UnexpectedEOF => ReadError::UnexpectedEof, - ByteorderError::Io(err) => ReadError::Io(err) - } - } + fn from(err: ByteorderError) -> ReadError { + match err { + ByteorderError::UnexpectedEOF => ReadError::UnexpectedEof, + ByteorderError::Io(err) => ReadError::Io(err), + } + } } impl From<FromUtf16Error> for ReadError { - fn from(_: FromUtf16Error) -> ReadError { - ReadError::InvalidData - } + fn from(_: FromUtf16Error) -> ReadError { + ReadError::InvalidData + } } struct StackItem { - object_refs: Vec<u64>, - ty: StackType + object_refs: Vec<u64>, + ty: StackType, } enum StackType { - Array, - Dict, - Root + 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 + 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) -> ReadResult<()> { - try!(self.reader.seek(SeekFrom::Start(0))); - let mut magic = [0; 8]; - try!(self.reader.read(&mut magic)); - assert_eq!(&magic, b"bplist00"); - - - // 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) -> ReadResult<Vec<u64>> { - let mut ints = Vec::with_capacity(len as usize); - // 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(ReadError::InvalidData) - } - } - Ok(ints) - } - - fn read_refs(&mut self, len: u64) -> ReadResult<Vec<u64>> { - let ref_size = self.ref_size; - self.read_ints(len, ref_size) - } - - fn read_object_len(&mut self, len: u8) -> ReadResult<u64> { - if (len & 0xf) == 0xf { - let len_power_of_two = try!(self.reader.read_u8()) & 0x3; - 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(ReadError::InvalidData) - }) - } else { - Ok(len as u64) - } - } - - fn read_data(&mut self, len: u64) -> ReadResult<Vec<u8>> { - let mut data = vec![0; len as usize]; - let mut total_read = 0usize; - - while (total_read as u64) < len { - let read = try!(self.reader.read(&mut data[total_read..])); - if read == 0 { - return Err(ReadError::UnexpectedEof); - } - total_read += read; - } - - Ok(data) - } - - fn seek_to_object(&mut self, object_ref: u64) -> ReadResult<u64> { - let offset = *&self.object_offsets[object_ref as usize]; - let pos = try!(self.reader.seek(SeekFrom::Start(offset))); - Ok(pos) - } - - fn read_next(&mut self) -> ReadResult<Option<PlistEvent>> { - if self.ref_size == 0 { - // Initialise here rather than in new - try!(self.read_trailer()); - return Ok(Some(PlistEvent::StartPlist)) - } - - 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)), - StackType::Root => return Ok(Some(PlistEvent::EndPlist)) - } - } - } - - 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(ReadError::UnsupportedType), // null - (0x0, 0x08) => Some(PlistEvent::BooleanValue(false)), - (0x0, 0x09) => Some(PlistEvent::BooleanValue(true)), - (0x0, 0x0f) => return Err(ReadError::UnsupportedType), // 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(ReadError::UnsupportedType), // 128 bit int - (0x1, _) => return Err(ReadError::UnsupportedType), // 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(ReadError::UnsupportedType), // 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 = String::from_utf8(raw).unwrap(); - Some(PlistEvent::StringValue(string)) - }, - (0x6, n) => { // UTF-16 string - let len = try!(self.read_object_len(n)); - let raw = try!(self.read_data(len)); - let mut cursor = Cursor::new(raw); - - let mut raw_utf16 = Vec::with_capacity(len as usize / 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 = len as usize; - - let mut object_refs = Vec::with_capacity(len * 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(ReadError::InvalidData) - }; - - Ok(result) - } +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) -> ReadResult<()> { + try!(self.reader.seek(SeekFrom::Start(0))); + let mut magic = [0; 8]; + try!(self.reader.read(&mut magic)); + assert_eq!(&magic, b"bplist00"); + + + // 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) -> ReadResult<Vec<u64>> { + let mut ints = Vec::with_capacity(len as usize); + // 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(ReadError::InvalidData), + } + } + Ok(ints) + } + + fn read_refs(&mut self, len: u64) -> ReadResult<Vec<u64>> { + let ref_size = self.ref_size; + self.read_ints(len, ref_size) + } + + fn read_object_len(&mut self, len: u8) -> ReadResult<u64> { + if (len & 0xf) == 0xf { + let len_power_of_two = try!(self.reader.read_u8()) & 0x3; + 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(ReadError::InvalidData), + }) + } else { + Ok(len as u64) + } + } + + fn read_data(&mut self, len: u64) -> ReadResult<Vec<u8>> { + let mut data = vec![0; len as usize]; + let mut total_read = 0usize; + + while (total_read as u64) < len { + let read = try!(self.reader.read(&mut data[total_read..])); + if read == 0 { + return Err(ReadError::UnexpectedEof); + } + total_read += read; + } + + Ok(data) + } + + fn seek_to_object(&mut self, object_ref: u64) -> ReadResult<u64> { + let offset = *&self.object_offsets[object_ref as usize]; + let pos = try!(self.reader.seek(SeekFrom::Start(offset))); + Ok(pos) + } + + fn read_next(&mut self) -> ReadResult<Option<PlistEvent>> { + if self.ref_size == 0 { + // Initialise here rather than in new + try!(self.read_trailer()); + return Ok(Some(PlistEvent::StartPlist)); + } + + 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)), + StackType::Root => return Ok(Some(PlistEvent::EndPlist)), + } + } + } + + 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(ReadError::UnsupportedType), // null + (0x0, 0x08) => Some(PlistEvent::BooleanValue(false)), + (0x0, 0x09) => Some(PlistEvent::BooleanValue(true)), + (0x0, 0x0f) => return Err(ReadError::UnsupportedType), // 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(ReadError::UnsupportedType), // 128 bit int + (0x1, _) => return Err(ReadError::UnsupportedType), // 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(ReadError::UnsupportedType), // 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 = String::from_utf8(raw).unwrap(); + Some(PlistEvent::StringValue(string)) + } + (0x6, n) => { + // UTF-16 string + let len = try!(self.read_object_len(n)); + let raw = try!(self.read_data(len)); + let mut cursor = Cursor::new(raw); + + let mut raw_utf16 = Vec::with_capacity(len as usize / 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 = len as usize; + + let mut object_refs = Vec::with_capacity(len * 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(ReadError::InvalidData), + }; + + Ok(result) + } } -impl<R: Read+Seek> Iterator for EventReader<R> { - type Item = ReadResult<PlistEvent>; - - fn next(&mut self) -> Option<ReadResult<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 - } - } - } - } +impl<R: Read + Seek> Iterator for EventReader<R> { + type Item = ReadResult<PlistEvent>; + + fn next(&mut self) -> Option<ReadResult<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 = &[ - StartPlist, - 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, - EndPlist - ]; - - assert_eq!(events, comparison); - } -}
\ No newline at end of file + 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 = &[StartPlist, + 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, + EndPlist]; + + assert_eq!(events, comparison); + } +} diff --git a/src/builder.rs b/src/builder.rs index dcb3984..15fc523 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -6,129 +6,131 @@ pub type BuildResult<T> = Result<T, BuildError>; #[derive(Debug)] pub enum BuildError { - InvalidEvent, - UnsupportedDictionaryKey, - ReadError(ReadError) + InvalidEvent, + UnsupportedDictionaryKey, + ReadError(ReadError), } impl From<ReadError> for BuildError { - fn from(err: ReadError) -> BuildError { - BuildError::ReadError(err) - } + fn from(err: ReadError) -> BuildError { + BuildError::ReadError(err) + } } pub struct Builder<T> { - stream: T, - token: Option<PlistEvent>, + stream: T, + token: Option<PlistEvent>, } -impl<T:Iterator<Item=ReadResult<PlistEvent>>> Builder<T> { - pub fn new(stream: T) -> Builder<T> { - Builder { - stream: stream, - token: None - } - } - - pub fn build(mut self) -> BuildResult<Plist> { - try!(self.bump()); - if let Some(PlistEvent::StartPlist) = self.token { - try!(self.bump()); - } - - let plist = try!(self.build_value()); - try!(self.bump()); - match self.token { - None => (), - Some(PlistEvent::EndPlist) => try!(self.bump()), - // The stream should have finished - _ => return Err(BuildError::InvalidEvent) - }; - Ok(plist) - } - - fn bump(&mut self) -> BuildResult<()> { - self.token = match self.stream.next() { - Some(Ok(token)) => Some(token), - Some(Err(err)) => return Err(BuildError::ReadError(err)), - None => None, - }; - Ok(()) - } - - fn build_value(&mut self) -> BuildResult<Plist> { - match self.token.take() { - Some(PlistEvent::StartPlist) => Err(BuildError::InvalidEvent), - Some(PlistEvent::EndPlist) => Err(BuildError::InvalidEvent), - - 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(BuildError::InvalidEvent), - Some(PlistEvent::EndDictionary) => Err(BuildError::InvalidEvent), - - // The stream should not have ended here - None => Err(BuildError::InvalidEvent) - } - } - - fn build_array(&mut self, len: Option<u64>) -> Result<Vec<Plist>, BuildError> { - let mut values = match len { - Some(len) => Vec::with_capacity(len as usize), - 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>, BuildError> { - 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(BuildError::UnsupportedDictionaryKey) - } - } - } - } +impl<T: Iterator<Item = ReadResult<PlistEvent>>> Builder<T> { + pub fn new(stream: T) -> Builder<T> { + Builder { + stream: stream, + token: None, + } + } + + pub fn build(mut self) -> BuildResult<Plist> { + try!(self.bump()); + if let Some(PlistEvent::StartPlist) = self.token { + try!(self.bump()); + } + + let plist = try!(self.build_value()); + try!(self.bump()); + match self.token { + None => (), + Some(PlistEvent::EndPlist) => try!(self.bump()), + // The stream should have finished + _ => return Err(BuildError::InvalidEvent), + }; + Ok(plist) + } + + fn bump(&mut self) -> BuildResult<()> { + self.token = match self.stream.next() { + Some(Ok(token)) => Some(token), + Some(Err(err)) => return Err(BuildError::ReadError(err)), + None => None, + }; + Ok(()) + } + + fn build_value(&mut self) -> BuildResult<Plist> { + match self.token.take() { + Some(PlistEvent::StartPlist) => Err(BuildError::InvalidEvent), + Some(PlistEvent::EndPlist) => Err(BuildError::InvalidEvent), + + 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(BuildError::InvalidEvent), + Some(PlistEvent::EndDictionary) => Err(BuildError::InvalidEvent), + + // The stream should not have ended here + None => Err(BuildError::InvalidEvent), + } + } + + fn build_array(&mut self, len: Option<u64>) -> Result<Vec<Plist>, BuildError> { + let mut values = match len { + Some(len) => Vec::with_capacity(len as usize), + 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>, BuildError> { + 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(BuildError::UnsupportedDictionaryKey); + } + } + } + } } #[cfg(test)] mod tests { - use std::collections::BTreeMap; + use std::collections::BTreeMap; - use super::*; - use Plist; + use super::*; + use Plist; - #[test] - fn builder() { - use PlistEvent::*; + #[test] + fn builder() { + use PlistEvent::*; - // Input + // Input - let events = vec![ + let events = vec![ StartPlist, StartDictionary(None), StringValue("Author".to_owned()), @@ -146,21 +148,22 @@ mod tests { EndPlist, ]; - let builder = Builder::new(events.into_iter().map(|e| Ok(e))); - let plist = builder.build(); + let builder = Builder::new(events.into_iter().map(|e| Ok(e))); + let plist = builder.build(); - // Expected output + // 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 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)); + 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)); - } -}
\ No newline at end of file + assert_eq!(plist.unwrap(), Plist::Dictionary(dict)); + } +} @@ -15,165 +15,171 @@ use std::io::Error as IoError; #[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) + 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 from_events<T>(events: T) -> Result<Plist, ()> - where T: IntoIterator<Item = ReadResult<PlistEvent>> - { - let iter = events.into_iter(); - let builder = builder::Builder::new(iter); - - match builder.build() { - Ok(plist) => Ok(plist), - Err(_) => Err(()) - } - } - - 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), - } - } + pub fn from_events<T>(events: T) -> Result<Plist, ()> + where T: IntoIterator<Item = ReadResult<PlistEvent>> + { + let iter = events.into_iter(); + let builder = builder::Builder::new(iter); + + match builder.build() { + Ok(plist) => Ok(plist), + Err(_) => Err(()), + } + } + + 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), + } + } } #[derive(Clone, Debug, PartialEq)] pub enum PlistEvent { - StartPlist, - EndPlist, + StartPlist, + EndPlist, - StartArray(Option<u64>), - EndArray, + StartArray(Option<u64>), + EndArray, - StartDictionary(Option<u64>), - EndDictionary, + StartDictionary(Option<u64>), + EndDictionary, - BooleanValue(bool), - DataValue(Vec<u8>), - DateValue(DateTime<UTC>), - IntegerValue(i64), - RealValue(f64), - StringValue(String), + BooleanValue(bool), + DataValue(Vec<u8>), + DateValue(DateTime<UTC>), + IntegerValue(i64), + RealValue(f64), + StringValue(String), } pub type ReadResult<T> = Result<T, ReadError>; #[derive(Debug)] pub enum ReadError { - InvalidData, - UnexpectedEof, - UnsupportedType, - Io(IoError) + InvalidData, + UnexpectedEof, + UnsupportedType, + Io(IoError), } impl From<IoError> for ReadError { - fn from(io_error: IoError) -> ReadError { - ReadError::Io(io_error) - } + fn from(io_error: IoError) -> ReadError { + ReadError::Io(io_error) + } } impl From<ChronoParseError> for ReadError { - fn from(_: ChronoParseError) -> ReadError { - ReadError::InvalidData - } + fn from(_: ChronoParseError) -> ReadError { + ReadError::InvalidData + } } -pub enum EventReader<R: Read+Seek> { - Uninitialized(Option<R>), - Xml(xml::EventReader<R>), - Binary(binary::EventReader<R>) +pub enum EventReader<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::Uninitialized(Some(reader)) - } - - fn is_binary(reader: &mut R) -> Result<bool, IoError> { - 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> EventReader<R> { + pub fn new(reader: R) -> EventReader<R> { + EventReader::Uninitialized(Some(reader)) + } + + fn is_binary(reader: &mut R) -> Result<bool, IoError> { + 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 = ReadResult<PlistEvent>; - - fn next(&mut self) -> Option<ReadResult<PlistEvent>> { - let mut reader = match *self { - EventReader::Xml(ref mut parser) => return parser.next(), - EventReader::Binary(ref mut parser) => return parser.next(), - EventReader::Uninitialized(ref mut reader) => reader.take().unwrap() - }; - - let event_reader = match EventReader::is_binary(&mut reader) { - Ok(true) => EventReader::Binary(binary::EventReader::new(reader)), - Ok(false) => EventReader::Xml(xml::EventReader::new(reader)), - Err(err) => { - ::std::mem::replace(self, EventReader::Uninitialized(Some(reader))); - return Some(Err(ReadError::Io(err))) - } - }; - - ::std::mem::replace(self, event_reader); - - self.next() - } -}
\ No newline at end of file +impl<R: Read + Seek> Iterator for EventReader<R> { + type Item = ReadResult<PlistEvent>; + + fn next(&mut self) -> Option<ReadResult<PlistEvent>> { + let mut reader = match *self { + EventReader::Xml(ref mut parser) => return parser.next(), + EventReader::Binary(ref mut parser) => return parser.next(), + EventReader::Uninitialized(ref mut reader) => reader.take().unwrap(), + }; + + let event_reader = match EventReader::is_binary(&mut reader) { + Ok(true) => EventReader::Binary(binary::EventReader::new(reader)), + Ok(false) => EventReader::Xml(xml::EventReader::new(reader)), + Err(err) => { + ::std::mem::replace(self, EventReader::Uninitialized(Some(reader))); + return Some(Err(ReadError::Io(err))); + } + }; + + ::std::mem::replace(self, event_reader); + + self.next() + } +} diff --git a/src/xml/mod.rs b/src/xml/mod.rs index b82450a..0400e13 100644 --- a/src/xml/mod.rs +++ b/src/xml/mod.rs @@ -2,4 +2,4 @@ mod reader; mod writer; pub use self::reader::EventReader; -pub use self::writer::EventWriter;
\ No newline at end of file +pub use self::writer::EventWriter; diff --git a/src/xml/reader.rs b/src/xml/reader.rs index b8def8f..90422c2 100644 --- a/src/xml/reader.rs +++ b/src/xml/reader.rs @@ -7,190 +7,200 @@ use xml_rs::reader::{EventReader as XmlEventReader, ParserConfig, XmlEvent}; use super::super::{ReadError, ReadResult, PlistEvent}; pub struct EventReader<R: Read> { - xml_reader: XmlEventReader<R>, - queued_event: Option<XmlEvent>, - element_stack: Vec<String>, - finished: bool + 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) -> ReadResult<PlistEvent> where F:FnOnce(String) -> ReadResult<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(ReadError::InvalidData) - } - } - - fn next_event(&mut self) -> 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<ReadResult<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" => return Some(Ok(PlistEvent::StartPlist)), - "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(ReadError::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(ReadError::InvalidData) - } - })), - "real" => return Some(self.read_content(|s| { - match FromStr::from_str(&s) { - Ok(f) => Ok(PlistEvent::RealValue(f)), - Err(_) => Err(ReadError::InvalidData) - } - })), - "string" => return Some(self.read_content(|s| Ok(PlistEvent::StringValue(s)))), - _ => return Some(Err(ReadError::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(ReadError::InvalidData)), - None => return Some(Err(ReadError::InvalidData)) - } - - match &name.local_name[..] { - "array" => return Some(Ok(PlistEvent::EndArray)), - "dict" => return Some(Ok(PlistEvent::EndDictionary)), - "plist" => return Some(Ok(PlistEvent::EndPlist)), - _ => () - } - }, - Ok(XmlEvent::EndDocument) => { - match self.element_stack.is_empty() { - true => return None, - false => return Some(Err(ReadError::UnexpectedEof)) - } - }, - Err(_) => return Some(Err(ReadError::InvalidData)), - _ => () - } - } - } + 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) -> ReadResult<PlistEvent> + where F: FnOnce(String) -> ReadResult<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(ReadError::InvalidData), + } + } + + fn next_event(&mut self) -> 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<ReadResult<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" => return Some(Ok(PlistEvent::StartPlist)), + "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(ReadError::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(ReadError::InvalidData), + } + })) + } + "real" => { + return Some(self.read_content(|s| { + match FromStr::from_str(&s) { + Ok(f) => Ok(PlistEvent::RealValue(f)), + Err(_) => Err(ReadError::InvalidData), + } + })) + } + "string" => { + return Some(self.read_content(|s| Ok(PlistEvent::StringValue(s)))) + } + _ => return Some(Err(ReadError::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(ReadError::InvalidData)), + None => return Some(Err(ReadError::InvalidData)), + } + + match &name.local_name[..] { + "array" => return Some(Ok(PlistEvent::EndArray)), + "dict" => return Some(Ok(PlistEvent::EndDictionary)), + "plist" => return Some(Ok(PlistEvent::EndPlist)), + _ => (), + } + } + Ok(XmlEvent::EndDocument) => { + match self.element_stack.is_empty() { + true => return None, + false => return Some(Err(ReadError::UnexpectedEof)), + } + } + Err(_) => return Some(Err(ReadError::InvalidData)), + _ => (), + } + } + } } impl<R: Read> Iterator for EventReader<R> { - type Item = ReadResult<PlistEvent>; - - fn next(&mut self) -> Option<ReadResult<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 - } - } - } - } + type Item = ReadResult<PlistEvent>; + + fn next(&mut self) -> Option<ReadResult<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 = &[ - StartPlist, - 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, - EndPlist - ]; - - 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()); - } -}
\ No newline at end of file + 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 = &[StartPlist, + 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, + EndPlist]; + + 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()); + } +} diff --git a/src/xml/writer.rs b/src/xml/writer.rs index ec2d9db..efca29e 100644 --- a/src/xml/writer.rs +++ b/src/xml/writer.rs @@ -7,241 +7,256 @@ use xml_rs::namespace::Namespace; use xml_rs::writer::{EventWriter as XmlEventWriter, EmitterConfig}; use xml_rs::writer::events::XmlEvent as WriteXmlEvent; -use {PlistEvent}; +use PlistEvent; enum Element { - Dictionary(DictionaryState), - Array, - Root + Dictionary(DictionaryState), + Array, + Root, } enum DictionaryState { - ExpectKey, - ExpectValue + ExpectKey, + ExpectValue, } pub struct EventWriter<W: Write> { - xml_writer: XmlEventWriter<W>, - stack: Vec<Element>, - // Not very nice - empty_namespace: Namespace + 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<(), ()> { - let result = self.xml_writer.write(WriteXmlEvent::StartElement { - name: Name::local(name), - attributes: Cow::Borrowed(&[]), - namespace: Cow::Borrowed(&self.empty_namespace) - }); - - match result { - Ok(()) => Ok(()), - Err(_) => Err(()) - } - } - - fn end_element(&mut self, name: &str) -> Result<(), ()> { - let result = self.xml_writer.write(WriteXmlEvent::EndElement { - name: Some(Name::local(name)) - }); - - match result { - Ok(()) => Ok(()), - Err(_) => Err(()) - } - } - - fn write_value(&mut self, value: &str) -> Result<(), ()> { - let result = self.xml_writer.write(WriteXmlEvent::Characters(value)); - - match result { - Ok(()) => Ok(()), - Err(_) => Err(()) - } - } - - pub 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")), - _ => return Err(()) // Invalid event - }; - return Ok(()) - }, - Some(Element::Dictionary(DictionaryState::ExpectValue)) => self.stack.push(Element::Dictionary(DictionaryState::ExpectKey)), - Some(other) => self.stack.push(other), - None => match *event { - PlistEvent::StartPlist => { - let version_name = Name::local("version"); - let version_attr = Attribute::new(version_name, "1.0"); - - let result = self.xml_writer.write(WriteXmlEvent::StartElement { - name: Name::local("plist"), - attributes: Cow::Borrowed(&[version_attr]), - namespace: Cow::Borrowed(&self.empty_namespace) - }); - - match result { - Ok(()) => (), - Err(_) => return Err(()) - } - - self.stack.push(Element::Root); - return Ok(()) - }, - _ => return Err(()) // Invalid event - } - } - - Ok(match *event { - PlistEvent::StartPlist => return Err(()), // Invalid event - PlistEvent::EndPlist => { - try!(self.end_element("plist")); - if let Some(Element::Root) = self.stack.pop() {} else { - return Err(()); // Invalid 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(()); // Invalid event - } - } - - PlistEvent::StartDictionary(_) => { - try!(self.start_element("dict")); - self.stack.push(Element::Dictionary(DictionaryState::ExpectKey)); - } - PlistEvent::EndDictionary => return Err(()), // Invalid event - - 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 = value.to_rfc3339(); - 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)), - }) - } + 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<(), ()> { + let result = self.xml_writer.write(WriteXmlEvent::StartElement { + name: Name::local(name), + attributes: Cow::Borrowed(&[]), + namespace: Cow::Borrowed(&self.empty_namespace), + }); + + match result { + Ok(()) => Ok(()), + Err(_) => Err(()), + } + } + + fn end_element(&mut self, name: &str) -> Result<(), ()> { + let result = self.xml_writer + .write(WriteXmlEvent::EndElement { name: Some(Name::local(name)) }); + + match result { + Ok(()) => Ok(()), + Err(_) => Err(()), + } + } + + fn write_value(&mut self, value: &str) -> Result<(), ()> { + let result = self.xml_writer.write(WriteXmlEvent::Characters(value)); + + match result { + Ok(()) => Ok(()), + Err(_) => Err(()), + } + } + + pub 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")), + _ => return Err(()), // Invalid event + }; + return Ok(()); + } + Some(Element::Dictionary(DictionaryState::ExpectValue)) => { + self.stack.push(Element::Dictionary(DictionaryState::ExpectKey)) + } + Some(other) => self.stack.push(other), + None => { + match *event { + PlistEvent::StartPlist => { + let version_name = Name::local("version"); + let version_attr = Attribute::new(version_name, "1.0"); + + let result = self.xml_writer.write(WriteXmlEvent::StartElement { + name: Name::local("plist"), + attributes: Cow::Borrowed(&[version_attr]), + namespace: Cow::Borrowed(&self.empty_namespace), + }); + + match result { + Ok(()) => (), + Err(_) => return Err(()), + } + + self.stack.push(Element::Root); + return Ok(()); + } + _ => return Err(()), // Invalid event + } + } + } + + Ok(match *event { + PlistEvent::StartPlist => return Err(()), // Invalid event + PlistEvent::EndPlist => { + try!(self.end_element("plist")); + if let Some(Element::Root) = self.stack.pop() {} else { + return Err(()); // Invalid 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(()); // Invalid event + } + } + + PlistEvent::StartDictionary(_) => { + try!(self.start_element("dict")); + self.stack.push(Element::Dictionary(DictionaryState::ExpectKey)); + } + PlistEvent::EndDictionary => return Err(()), // Invalid event + + 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 = value.to_rfc3339(); + 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)) + } + }) + } } #[cfg(test)] mod tests { - use chrono::{TimeZone, UTC}; - use std::io::Cursor; - - use super::*; - - #[test] - fn streaming_parser() { - use PlistEvent::*; - - let plist = &[ - StartPlist, - 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, - EndPlist - ]; - - 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\"?> + use chrono::{TimeZone, UTC}; + use std::io::Cursor; + + use super::*; + + #[test] + fn streaming_parser() { + use PlistEvent::*; + + let plist = &[StartPlist, + 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, + EndPlist]; + + 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> + \ + <dict> <key>Author</key> - <string>William Shakespeare</string> + <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> + \ + <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> + \ + <key>Height</key> <real>1.6</real> <key>Data</key> - <data>AAAAvgAAAAMAAAAeAAAA</data> + \ + <data>AAAAvgAAAAMAAAAeAAAA</data> <key>Birthdate</key> - <date>1981-05-16T11:32:06+00:00</date> + \ + <date>1981-05-16T11:32:06+00:00</date> </dict> </plist>"; - let s = String::from_utf8(cursor.into_inner()).unwrap(); + let s = String::from_utf8(cursor.into_inner()).unwrap(); - assert_eq!(&s, comparison); - } -}
\ No newline at end of file + assert_eq!(&s, comparison); + } +} |
