diff options
| author | Edward Barnard | 2017-01-07 13:57:37 +0000 | 
|---|---|---|
| committer | Edward Barnard | 2017-02-02 20:29:57 +0000 | 
| commit | 910c3eed3dc7895086a98bf7f5d373e22388a272 (patch) | |
| tree | f13113d119e618fa37feaaf25998b0ebd29556d7 | |
| parent | e0c687aa4dfa8a27982037efdf8692b39b7b9c97 (diff) | |
| download | rust-plist-910c3eed3dc7895086a98bf7f5d373e22388a272.tar.bz2 | |
Improve binary plist datetime decoding.
| -rw-r--r-- | src/binary/reader.rs | 26 | 
1 files changed, 18 insertions, 8 deletions
| diff --git a/src/binary/reader.rs b/src/binary/reader.rs index 56bb587..c3c0be4 100644 --- a/src/binary/reader.rs +++ b/src/binary/reader.rs @@ -1,5 +1,5 @@  use byteorder::{BigEndian, ReadBytesExt}; -use chrono::{TimeZone, UTC}; +use chrono::{Duration, TimeZone, UTC};  use std::io::{Cursor, Read, Seek, SeekFrom};  use std::string::{FromUtf8Error, FromUtf16Error}; @@ -189,18 +189,28 @@ impl<R: Read + Seek> EventReader<R> {              }              (0x2, 3) => Some(PlistEvent::RealValue(try!(self.reader.read_f64::<BigEndian>()))),              (0x2, _) => return Err(Error::InvalidData), // odd length float -            (0x3, 3) => { +            (0x3, 3) => {;                  // Date -                // Seconds since 1/1/2001 00:00:00 +                // 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 millis = timestamp * 1_000.0; +                // Chrono's Duration can only millisecond values between ::std::i64::MIN and +                // ::std::i64::MAX. +                if millis > ::std::i64::MAX as f64 || millis < ::std::i64::MIN as f64 { +                    return Err(Error::InvalidData); +                } + +                let whole_millis = millis.floor(); +                let submilli_nanos = ((millis - whole_millis) * 1_000_000.0).floor(); + +                let dur = Duration::milliseconds(whole_millis as i64); +                let dur = dur + Duration::nanoseconds(submilli_nanos as i64); -                let int_secs = (secs as i64) + (31 * 365 + 8) * 86400; -                let int_nanos = (subsecs * 1_000_000_000f64) as u32; +                let plist_epoch = UTC.ymd(2001, 1, 1).and_hms(0, 0, 0); +                let date = try!(plist_epoch.checked_add(dur).ok_or(Error::InvalidData)); -                Some(PlistEvent::DateValue(UTC.timestamp(int_secs, int_nanos))) +                Some(PlistEvent::DateValue(date))              }              (0x4, n) => {                  // Data | 
