aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Barnard2015-08-28 23:08:03 +0700
committerEdward Barnard2015-08-28 23:08:03 +0700
commit361aa56bf877cd4210018c97ebaf6aa92ab4f608 (patch)
tree82c6a47a8e9e597f221cc096c4f86d93fdae436e
parent3e41485288049b1d7a9be60b84b4d78dcd400f39 (diff)
downloadrust-plist-361aa56bf877cd4210018c97ebaf6aa92ab4f608.tar.bz2
Add date support via chrono
-rw-r--r--Cargo.toml3
-rw-r--r--src/binary/reader.rs21
-rw-r--r--src/lib.rs13
-rw-r--r--src/xml/reader.rs11
-rw-r--r--tests/data/binary.plistbin233 -> 252 bytes
-rw-r--r--tests/data/xml.plist32
6 files changed, 57 insertions, 23 deletions
diff --git a/Cargo.toml b/Cargo.toml
index e946c66..282888d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,4 +11,5 @@ documentation = "https://ebarnard.github.io/rust-plist/doc/plist/"
rustc-serialize = "0.3.16"
xml-rs = "0.1.26"
byteorder = "0.3.11"
-itertools = "0.3.25" \ No newline at end of file
+itertools = "0.3.25"
+chrono = "0.2.15" \ No newline at end of file
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()),
diff --git a/src/lib.rs b/src/lib.rs
index 9a8da49..4ac9e8f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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
];
diff --git a/tests/data/binary.plist b/tests/data/binary.plist
index 8b92066..3d0cfd5 100644
--- a/tests/data/binary.plist
+++ b/tests/data/binary.plist
Binary files differ
diff --git a/tests/data/xml.plist b/tests/data/xml.plist
index d2599f2..4db2173 100644
--- a/tests/data/xml.plist
+++ b/tests/data/xml.plist
@@ -1,19 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
- <key>Author</key>
- <string>William Shakespeare</string>
- <key>Lines</key>
- <array>
- <string>It is a tale told by an idiot,</string>
- <string>Full of sound and fury, signifying nothing.</string>
- </array>
- <key>Birthdate</key>
- <integer>1564</integer>
- <key>Height</key>
- <real>1.60</real>
- <key>Data</key>
- <data>AAAAvgAAAAMAAAAeAAAA</data>
+ <key>Author</key>
+ <string>William Shakespeare</string>
+ <key>Lines</key>
+ <array>
+ <string>It is a tale told by an idiot,</string>
+ <string>Full of sound and fury, signifying nothing.</string>
+ </array>
+ <key>Death</key>
+ <integer>1564</integer>
+ <key>Height</key>
+ <real>1.6</real>
+ <key>Data</key>
+ <data>AAAAvgAAAAMAAAAeAAAA</data>
+ <key>Birthdate</key>
+ <date>1981-05-16T11:32:06Z</date>
</dict>
-</plist> \ No newline at end of file
+</plist>