diff options
Diffstat (limited to 'src/xml')
| -rw-r--r-- | src/xml/mod.rs | 2 | ||||
| -rw-r--r-- | src/xml/reader.rs | 364 | ||||
| -rw-r--r-- | src/xml/writer.rs | 433 |
3 files changed, 412 insertions, 387 deletions
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); + } +} |
