diff options
| author | Edward Barnard | 2015-08-28 23:08:03 +0700 |
|---|---|---|
| committer | Edward Barnard | 2015-08-28 23:08:03 +0700 |
| commit | 361aa56bf877cd4210018c97ebaf6aa92ab4f608 (patch) | |
| tree | 82c6a47a8e9e597f221cc096c4f86d93fdae436e /src | |
| parent | 3e41485288049b1d7a9be60b84b4d78dcd400f39 (diff) | |
| download | rust-plist-361aa56bf877cd4210018c97ebaf6aa92ab4f608.tar.bz2 | |
Add date support via chrono
Diffstat (limited to 'src')
| -rw-r--r-- | src/binary/reader.rs | 21 | ||||
| -rw-r--r-- | src/lib.rs | 13 | ||||
| -rw-r--r-- | src/xml/reader.rs | 11 |
3 files changed, 38 insertions, 7 deletions
diff --git a/src/binary/reader.rs b/src/binary/reader.rs index 36c27f2..a8d146e 100644 --- a/src/binary/reader.rs +++ b/src/binary/reader.rs @@ -1,5 +1,6 @@ use byteorder::{BigEndian, ReadBytesExt}; use byteorder::Error as ByteorderError; +use chrono::{TimeZone, UTC}; use itertools::Interleave; use std::io::{Cursor, Read, Seek, SeekFrom}; use std::string::FromUtf16Error; @@ -181,7 +182,18 @@ impl<R: Read+Seek> StreamingParser<R> { (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(ParserError::UnsupportedType), // odd length float - (0x3, 3) => return Err(ParserError::UnsupportedType), // date + (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)))) @@ -255,6 +267,7 @@ impl<R: Read+Seek> Iterator for StreamingParser<R> { #[cfg(test)] mod tests { + use chrono::{TimeZone, UTC}; use std::fs::File; use std::path::Path; @@ -271,16 +284,18 @@ mod tests { let comparison = &[ StartPlist, - StartDictionary(Some(5)), + 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()), - IntegerValue(1564), + DateValue(UTC.ymd(1981, 05, 16).and_hms(11, 32, 06)), StringValue("Author".to_owned()), StringValue("William Shakespeare".to_owned()), StringValue("Data".to_owned()), @@ -1,4 +1,5 @@ extern crate byteorder; +extern crate chrono; extern crate itertools; extern crate rustc_serialize; extern crate xml as xml_rs; @@ -9,6 +10,8 @@ mod builder; pub use builder::{Builder, BuilderError, BuilderResult}; +use chrono::{DateTime, UTC}; +use chrono::format::ParseError as ChronoParseError; use std::collections::HashMap; use std::io::{Read, Seek, SeekFrom}; use std::io::Error as IoError; @@ -19,7 +22,7 @@ pub enum Plist { Dictionary(HashMap<String, Plist>), Boolean(bool), Data(Vec<u8>), - Date(String), + Date(DateTime<UTC>), Real(f64), Integer(i64), String(String) @@ -38,7 +41,7 @@ pub enum PlistEvent { BooleanValue(bool), DataValue(Vec<u8>), - DateValue(String), + DateValue(DateTime<UTC>), IntegerValue(i64), RealValue(f64), StringValue(String), @@ -60,6 +63,12 @@ impl From<IoError> for ParserError { } } +impl From<ChronoParseError> for ParserError { + fn from(_: ChronoParseError) -> ParserError { + ParserError::InvalidData + } +} + pub enum StreamingParser<R: Read+Seek> { Xml(xml::StreamingParser<R>), Binary(binary::StreamingParser<R>) diff --git a/src/xml/reader.rs b/src/xml/reader.rs index f047db4..006a04e 100644 --- a/src/xml/reader.rs +++ b/src/xml/reader.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, UTC}; use rustc_serialize::base64::FromBase64; use std::io::Read; use std::str::FromStr; @@ -58,7 +59,10 @@ impl<R: Read> Iterator for StreamingParser<R> { Err(_) => Err(ParserError::InvalidData) } })), - "date" => return Some(self.read_content(|s| Ok(PlistEvent::DateValue(s)))), + "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)), @@ -104,6 +108,7 @@ impl<R: Read> Iterator for StreamingParser<R> { #[cfg(test)] mod tests { + use chrono::{TimeZone, UTC}; use std::fs::File; use std::path::Path; @@ -128,12 +133,14 @@ mod tests { StringValue("It is a tale told by an idiot,".to_owned()), StringValue("Full of sound and fury, signifying nothing.".to_owned()), EndArray, - StringValue("Birthdate".to_owned()), + 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 ]; |
