aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEdward Barnard2015-12-22 12:58:19 +0000
committerEdward Barnard2015-12-22 12:58:19 +0000
commiteef9d906b38def0091faa2dc955a4c0970fe251d (patch)
tree20d14ca56e2e8ee2ae9838b8ef806c48052126b2 /src
parente257aaef791ba83dc7cbdde358180c9394017459 (diff)
downloadrust-plist-eef9d906b38def0091faa2dc955a4c0970fe251d.tar.bz2
Rustfmt
Diffstat (limited to 'src')
-rw-r--r--src/binary/mod.rs2
-rw-r--r--src/binary/reader.rs600
-rw-r--r--src/builder.rs245
-rw-r--r--src/lib.rs270
-rw-r--r--src/xml/mod.rs2
-rw-r--r--src/xml/reader.rs364
-rw-r--r--src/xml/writer.rs433
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));
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index ca3aa3e..0334c15 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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);
+ }
+}