From ecef2627a7421001da9a026b0bff5d9598a75491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Harabie=C5=84?= Date: Thu, 28 Jun 2018 18:53:51 +0200 Subject: [PATCH] Move time related code to 'time' module --- src/dir_entry.rs | 125 +----------------------------------- src/file.rs | 3 +- src/fs.rs | 37 +---------- src/lib.rs | 2 + src/time.rs | 161 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+), 160 deletions(-) create mode 100644 src/time.rs diff --git a/src/dir_entry.rs b/src/dir_entry.rs index 1cc9727..29ca9e1 100644 --- a/src/dir_entry.rs +++ b/src/dir_entry.rs @@ -9,14 +9,11 @@ use io::Cursor; use byteorder::LittleEndian; use byteorder_ext::{ReadBytesExt, WriteBytesExt}; -#[cfg(feature = "chrono")] -use chrono; -#[cfg(feature = "chrono")] -use chrono::{Datelike, Local, TimeZone, Timelike}; use dir::{Dir, DirRawStream}; use file::File; use fs::{FatType, FileSystem, OemCpConverter, ReadWriteSeek}; +use time::{Date, DateTime}; bitflags! { /// A FAT file attributes. @@ -429,126 +426,6 @@ impl DirEntryData { } } -/// A DOS compatible date. -/// -/// Used by `DirEntry` time-related methods. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct Date { - /// Full year - [1980, 2107] - pub year: u16, - /// Month of the year - [1, 12] - pub month: u16, - /// Day of the month - [1, 31] - pub day: u16, -} - -impl Date { - pub(crate) fn decode(dos_date: u16) -> Self { - let (year, month, day) = ((dos_date >> 9) + 1980, (dos_date >> 5) & 0xF, dos_date & 0x1F); - Date { year, month, day } - } - - fn encode(&self) -> u16 { - ((self.year - 1980) << 9) | (self.month << 5) | self.day - } -} - -/// A DOS compatible time. -/// -/// Used by `DirEntry` time-related methods. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct Time { - /// Hours after midnight - [0, 23] - pub hour: u16, - /// Minutes after the hour - [0, 59] - pub min: u16, - /// Seconds after the minute - [0, 59] - pub sec: u16, - /// Milliseconds after the second - [0, 999] - pub millis: u16, -} - -impl Time { - pub(crate) fn decode(dos_time: u16, dos_time_hi_res: u8) -> Self { - let hour = dos_time >> 11; - let min = (dos_time >> 5) & 0x3F; - let sec = (dos_time & 0x1F) * 2 + (dos_time_hi_res as u16) / 2; - let millis = (dos_time_hi_res as u16 % 100) * 10; - Time { hour, min, sec, millis } - } - - fn encode(&self) -> (u16, u8) { - let dos_time = (self.hour << 11) | (self.min << 5) | (self.sec / 2); - let dos_time_hi_res = ((self.millis / 100) + (self.sec % 2) * 100) as u8; - (dos_time, dos_time_hi_res) - } -} - -/// A DOS compatible date and time. -/// -/// Used by `DirEntry` time-related methods. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct DateTime { - /// A date part - pub date: Date, - // A time part - pub time: Time, -} - -impl DateTime { - pub(crate) fn decode(dos_date: u16, dos_time: u16, dos_time_hi_res: u8) -> Self { - DateTime { - date: Date::decode(dos_date), - time: Time::decode(dos_time, dos_time_hi_res), - } - } -} - -#[cfg(feature = "chrono")] -impl From for chrono::Date { - fn from(date: Date) -> Self { - Local.ymd(date.year as i32, date.month as u32, date.day as u32) - } -} - -#[cfg(feature = "chrono")] -impl From for chrono::DateTime { - fn from(date_time: DateTime) -> Self { - chrono::Date::::from(date_time.date).and_hms_milli( - date_time.time.hour as u32, - date_time.time.min as u32, - date_time.time.sec as u32, - date_time.time.millis as u32, - ) - } -} - -#[cfg(feature = "chrono")] -impl From> for Date { - fn from(date: chrono::Date) -> Self { - Date { - year: date.year() as u16, - month: date.month() as u16, - day: date.day() as u16, - } - } -} - -#[cfg(feature = "chrono")] -impl From> for DateTime { - fn from(date_time: chrono::DateTime) -> Self { - DateTime { - date: Date::from(date_time.date()), - time: Time { - hour: date_time.hour() as u16, - min: date_time.minute() as u16, - sec: date_time.second() as u16, - millis: (date_time.nanosecond() / 1_000_000) as u16, - }, - } - } -} - #[derive(Clone, Debug)] pub(crate) struct DirEntryEditor { data: DirFileEntryData, diff --git a/src/file.rs b/src/file.rs index 6732b35..17b0242 100644 --- a/src/file.rs +++ b/src/file.rs @@ -4,8 +4,9 @@ use io; use io::prelude::*; use io::{ErrorKind, SeekFrom}; -use dir_entry::{Date, DateTime, DirEntryEditor}; +use dir_entry::DirEntryEditor; use fs::{FileSystem, ReadWriteSeek}; +use time::{Date, DateTime}; const MAX_FILE_SIZE: u32 = core::u32::MAX; diff --git a/src/fs.rs b/src/fs.rs index ac85def..559f130 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -12,9 +12,10 @@ use byteorder::LittleEndian; use byteorder_ext::{ReadBytesExt, WriteBytesExt}; use dir::{Dir, DirRawStream}; -use dir_entry::{self, DIR_ENTRY_SIZE}; +use dir_entry::DIR_ENTRY_SIZE; use file::File; use table::{alloc_cluster, count_free_clusters, read_fat_flags, ClusterIterator}; +use time::{TimeProvider, DEFAULT_TIME_PROVIDER}; // FAT implementation based on: // http://wiki.osdev.org/FAT @@ -753,37 +754,3 @@ impl OemCpConverter for LossyOemCpConverter { } pub(crate) static LOSSY_OEM_CP_CONVERTER: LossyOemCpConverter = LossyOemCpConverter { _dummy: () }; - -pub trait TimeProvider { - fn get_current_date(&self) -> dir_entry::Date; - fn get_current_date_time(&self) -> dir_entry::DateTime; -} - -#[derive(Clone)] -pub(crate) struct DefaultTimeProvider { - _dummy: (), -} - -impl TimeProvider for DefaultTimeProvider { - #[cfg(feature = "chrono")] - fn get_current_date(&self) -> dir_entry::Date { - use chrono; - dir_entry::Date::from(chrono::Local::now().date()) - } - #[cfg(not(feature = "chrono"))] - fn get_current_date(&self) -> dir_entry::Date { - dir_entry::Date::decode(0) - } - - #[cfg(feature = "chrono")] - fn get_current_date_time(&self) -> dir_entry::DateTime { - use chrono; - dir_entry::DateTime::from(chrono::Local::now()) - } - #[cfg(not(feature = "chrono"))] - fn get_current_date_time(&self) -> dir_entry::DateTime { - dir_entry::DateTime::decode(0, 0, 0) - } -} - -pub(crate) static DEFAULT_TIME_PROVIDER: DefaultTimeProvider = DefaultTimeProvider { _dummy: () }; diff --git a/src/lib.rs b/src/lib.rs index 322e7f3..34f5e09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,6 +81,7 @@ mod dir_entry; mod file; mod fs; mod table; +mod time; #[cfg(not(feature = "std"))] mod byteorder_core_io; @@ -101,3 +102,4 @@ pub use dir::*; pub use dir_entry::*; pub use file::*; pub use fs::*; +pub use time::*; diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 0000000..e11489c --- /dev/null +++ b/src/time.rs @@ -0,0 +1,161 @@ +#[cfg(feature = "chrono")] +use chrono; +#[cfg(feature = "chrono")] +use chrono::{Datelike, Local, TimeZone, Timelike}; + +/// A DOS compatible date. +/// +/// Used by `DirEntry` time-related methods. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct Date { + /// Full year - [1980, 2107] + pub year: u16, + /// Month of the year - [1, 12] + pub month: u16, + /// Day of the month - [1, 31] + pub day: u16, +} + +impl Date { + pub(crate) fn decode(dos_date: u16) -> Self { + let (year, month, day) = ((dos_date >> 9) + 1980, (dos_date >> 5) & 0xF, dos_date & 0x1F); + Date { year, month, day } + } + + pub(crate) fn encode(&self) -> u16 { + ((self.year - 1980) << 9) | (self.month << 5) | self.day + } +} + +/// A DOS compatible time. +/// +/// Used by `DirEntry` time-related methods. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct Time { + /// Hours after midnight - [0, 23] + pub hour: u16, + /// Minutes after the hour - [0, 59] + pub min: u16, + /// Seconds after the minute - [0, 59] + pub sec: u16, + /// Milliseconds after the second - [0, 999] + pub millis: u16, +} + +impl Time { + pub(crate) fn decode(dos_time: u16, dos_time_hi_res: u8) -> Self { + let hour = dos_time >> 11; + let min = (dos_time >> 5) & 0x3F; + let sec = (dos_time & 0x1F) * 2 + (dos_time_hi_res as u16) / 2; + let millis = (dos_time_hi_res as u16 % 100) * 10; + Time { hour, min, sec, millis } + } + + pub(crate) fn encode(&self) -> (u16, u8) { + let dos_time = (self.hour << 11) | (self.min << 5) | (self.sec / 2); + let dos_time_hi_res = ((self.millis / 100) + (self.sec % 2) * 100) as u8; + (dos_time, dos_time_hi_res) + } +} + +/// A DOS compatible date and time. +/// +/// Used by `DirEntry` time-related methods. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct DateTime { + /// A date part + pub date: Date, + // A time part + pub time: Time, +} + +impl DateTime { + pub(crate) fn decode(dos_date: u16, dos_time: u16, dos_time_hi_res: u8) -> Self { + DateTime { + date: Date::decode(dos_date), + time: Time::decode(dos_time, dos_time_hi_res), + } + } +} + +#[cfg(feature = "chrono")] +impl From for chrono::Date { + fn from(date: Date) -> Self { + Local.ymd(date.year as i32, date.month as u32, date.day as u32) + } +} + +#[cfg(feature = "chrono")] +impl From for chrono::DateTime { + fn from(date_time: DateTime) -> Self { + chrono::Date::::from(date_time.date).and_hms_milli( + date_time.time.hour as u32, + date_time.time.min as u32, + date_time.time.sec as u32, + date_time.time.millis as u32, + ) + } +} + +#[cfg(feature = "chrono")] +impl From> for Date { + fn from(date: chrono::Date) -> Self { + Date { + year: date.year() as u16, + month: date.month() as u16, + day: date.day() as u16, + } + } +} + +#[cfg(feature = "chrono")] +impl From> for DateTime { + fn from(date_time: chrono::DateTime) -> Self { + DateTime { + date: Date::from(date_time.date()), + time: Time { + hour: date_time.hour() as u16, + min: date_time.minute() as u16, + sec: date_time.second() as u16, + millis: (date_time.nanosecond() / 1_000_000) as u16, + }, + } + } +} + +/// A current time and date provider. +/// +/// Provides a custom implementation for a time resolution used when updating directory entry time fields. +/// Default implementation gets time from `chrono` crate if `chrono` feature is enabled. +/// Otherwise default implementation returns DOS minimal date-time (1980/1/1 0:00:00). +pub trait TimeProvider { + fn get_current_date(&self) -> Date; + fn get_current_date_time(&self) -> DateTime; +} + +#[derive(Clone)] +pub(crate) struct DefaultTimeProvider { + _dummy: (), +} + +impl TimeProvider for DefaultTimeProvider { + #[cfg(feature = "chrono")] + fn get_current_date(&self) -> Date { + Date::from(chrono::Local::now().date()) + } + #[cfg(not(feature = "chrono"))] + fn get_current_date(&self) -> Date { + Date::decode(0) + } + + #[cfg(feature = "chrono")] + fn get_current_date_time(&self) -> DateTime { + DateTime::from(chrono::Local::now()) + } + #[cfg(not(feature = "chrono"))] + fn get_current_date_time(&self) -> DateTime { + DateTime::decode(0, 0, 0) + } +} + +pub(crate) static DEFAULT_TIME_PROVIDER: DefaultTimeProvider = DefaultTimeProvider { _dummy: () };