LCOV - code coverage report
Current view: top level - src - dostime.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 39 39 100.0 %
Date: 2015-04-12 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   dostime.c - routines for converting UNIX time to MS-DOS time and vice versa.
       3             : 
       4             :   Various Copyrights:
       5             : 
       6             :   First written by Mark Adler, Richard B. Wales, Jean-loup Gailly,
       7             :   Kai Uwe Rommel, Onno van der Linden and Igor Mandrichenko (1990-1997).
       8             :   Tweaked further by Bryan Burns (1999).
       9             :   Redesigned with full error checks by Alexis Wilke (2015).
      10             : 
      11             :   This program is free software; you can redistribute it and/or
      12             :   modify it under the terms of the GNU General Public License
      13             :   as published by the Free Software Foundation; either version 2
      14             :   of the License, or (at your option) any later version.
      15             : 
      16             :   This program is distributed in the hope that it will be useful,
      17             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :   GNU General Public License for more details.
      20             : 
      21             :   You should have received a copy of the GNU General Public License
      22             :   along with this program; if not, write to the Free Software
      23             :   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
      24             : */
      25             : 
      26             : /** \file
      27             :  * \brief Functions to convert times between Unix and MS-DOS times.
      28             :  *
      29             :  * These functions make use of the old date and time format
      30             :  * defined to implement the FAT file system. This is defined
      31             :  * on the Microsoft website here:
      32             :  *
      33             :  * https://msdn.microsoft.com/en-us/library/windows/desktop/ms724247%28v=vs.85%29.aspx
      34             :  *
      35             :  * As a quick recap, we have:
      36             :  *
      37             :  * Date (actually we view those as bit 16 to 31)
      38             :  *
      39             :  * \code
      40             :  * 0-4    Day of the month (1-31)
      41             :  * 5-8    Month (1 = January, 2 = February, and so on)
      42             :  * 9-15   Year offset from 1980 (add 1980 to get actual year)
      43             :  * \endcode
      44             :  *
      45             :  * Time
      46             :  *
      47             :  * \code
      48             :  * 0-4    Second divided by 2
      49             :  * 5-10   Minute (0-59)
      50             :  * 11-15  Hour (0-23 on a 24-hour clock)
      51             :  * \endcode
      52             :  *
      53             :  * \note
      54             :  * This implementation uses C code.
      55             :  */
      56             : 
      57             : #include "dostime.h"
      58             : 
      59             : #include <stdio.h>
      60             : #include <stdlib.h>
      61             : #include <string.h>
      62             : 
      63             : 
      64             : /** \brief Return the minimum possible value.
      65             :  *
      66             :  * This function returns the minimum DOS time that can be represented
      67             :  * in a dostime_t parameter.
      68             :  *
      69             :  * At this time we use a 32 bit field (like the Zip archive) so the
      70             :  * maximum is Dec 31, 2107 23:59:59.
      71             :  *
      72             :  * \note
      73             :  * To get the corresponding Unix time, use the dos2unixtime() as in:
      74             :  *
      75             :  * \code
      76             :  *      time_t min(dos2unixtime(mindostime()));
      77             :  * \endcode
      78             :  *
      79             :  * \return The smallest possible DOS time.
      80             :  */
      81           1 : dostime_t mindostime()
      82             : {
      83             :     // Jan 1, 1980 00:00:00 is the minimum
      84           1 :     return 0x00210000;
      85             : }
      86             : 
      87             : 
      88             : /** \brief Return the maximum possible value .
      89             :  *
      90             :  * This function returns the maximum DOS time that can be represented
      91             :  * in a dostime_t parameter.
      92             :  *
      93             :  * At this time we use a 32 bit field (like the Zip archive) so the
      94             :  * maximum is Dec 31, 2107 23:59:59.
      95             :  *
      96             :  * \note
      97             :  * To get the corresponding Unix time, use the dos2unixtime() as in:
      98             :  *
      99             :  * \code
     100             :  *      time_t max(dos2unixtime(maxdostime()));
     101             :  * \endcode
     102             :  *
     103             :  * \return The largest possible DOS time.
     104             :  */
     105           1 : dostime_t maxdostime()
     106             : {
     107             :     // Dec 31, 2107 23:59:59 is the maximum
     108           1 :     return 0xFF9FBF7D;
     109             : }
     110             : 
     111             : 
     112             : /** \brief Convert a DOS time to a Unix time
     113             :  *
     114             :  * This function returns the Unix time_t value (GMT/UTC time) from
     115             :  * the DOS format (local) time dostime, where dostime is a four
     116             :  * byte value (date in most significant word, time in least
     117             :  * significant word), see dostime() function.
     118             :  *
     119             :  * If the input DOS time is invalid, then the function returns -1.
     120             :  *
     121             :  * \note
     122             :  * If the dostime is not valid (one of the parameters is out of
     123             :  * range) then the function returns -1.
     124             :  *
     125             :  * \param[in] dostime  A DOS time value as found in a zip file.
     126             :  *
     127             :  * \return The DOS time converted to a Unix time or -1.
     128             :  *
     129             :  * \sa dostime()
     130             :  */
     131      400610 : time_t dos2unixtime(dostime_t dostime)
     132             : {
     133             :     struct tm t;         /* argument for mktime() */
     134             : 
     135      400610 :     memset(&t, 0, sizeof(t));
     136             : 
     137      400610 :     t.tm_isdst = -1;     /* let mktime() determine if DST is in effect */
     138             :     /* Convert DOS time to UNIX time_t format */
     139      400610 :     t.tm_sec  = (((int)dostime <<  1) & 0x3E);
     140      400610 :     t.tm_min  = (((int)dostime >>  5) & 0x3F);
     141      400610 :     t.tm_hour = (((int)dostime >> 11) & 0x1F);
     142      400610 :     t.tm_mday = (((int)dostime >> 16) & 0x1F);
     143      400610 :     t.tm_mon  = (((int)dostime >> 21) & 0x0F) - 1;
     144      400610 :     t.tm_year = (((int)dostime >> 25) & 0x7F) + 80;
     145             : 
     146      400610 :     if(t.tm_year < 80 || t.tm_year > 207
     147      400610 :     || t.tm_mon  <  0 || t.tm_mon  >  11
     148      390828 :     || t.tm_mday <  1 || t.tm_mday >  31 /** \FIXME Maximum for tm_mday depends on month/year. */
     149      390828 :     || t.tm_hour <  0 || t.tm_hour >  23
     150      390828 :     || t.tm_min  <  0 || t.tm_min  >  59
     151      390828 :     || t.tm_sec  <  0 || t.tm_sec  >  59)
     152             :     {
     153        9782 :         return -1;
     154             :     }
     155             : 
     156             :     // A full round trip between Unix date to DOS and back to Unix works
     157             :     // as is (without worry about the current timezone) because the DOS
     158             :     // format makes use of localdate() and that's 1 to 1 compatible with
     159             :     // mktime() which expects a local date too.
     160      390828 :     return mktime(&t);
     161             : }
     162             : 
     163             : 
     164             : /* \brief Convert a broken up date to a DOS date.
     165             :  *
     166             :  * Convert the date y/n/d and time h:m:s to a four byte DOS date and
     167             :  * time (date in high two bytes, time in low two bytes allowing magnitude
     168             :  * comparison).
     169             :  *
     170             :  * The function returns zero if the month, day, hour, minute, second are
     171             :  * out of range.
     172             :  *
     173             :  * \todo
     174             :  * The dostime_t type is 32 bits, although if it were 64 bits we would
     175             :  * never have an overflow with the maximum. However, the Zip archive
     176             :  * format only supports 32 bits as far as I know.
     177             :  *
     178             :  * \param[in] year  The year.
     179             :  * \param[in] month  The month.
     180             :  * \param[in] day  The day.
     181             :  * \param[in] hour  The hour.
     182             :  * \param[in] minute  The minute.
     183             :  * \param[in] second  The second.
     184             :  *
     185             :  * \return The date parameters transformed in a DOS time value or zero if the
     186             :  *         date is considered invalid.
     187             :  */
     188      719932 : dostime_t dostime(int year, int month, int day, int hour, int minute, int second)
     189             : {
     190      719932 :     if(year < 1980 || year > 2107
     191      709926 :     || month < 1 || month > 12
     192      709926 :     || day < 1 || day > 31
     193      709926 :     || hour < 0 || hour > 23
     194      709926 :     || minute < 0 || minute > 59
     195      709926 :     || second < 0 || second > 59)
     196             :     {
     197       10006 :         return 0;
     198             :     }
     199             : 
     200     1419852 :     return (((dostime_t) year - 1980) << 25)
     201      709926 :          | (((dostime_t) month      ) << 21)
     202      709926 :          | (((dostime_t) day        ) << 16)
     203      709926 :          | (((dostime_t) hour       ) << 11)
     204      709926 :          | (((dostime_t) minute     ) <<  5)
     205      709926 :          | (((dostime_t) second     ) >>  1);  // 1 every other second
     206             : }
     207             : 
     208             : 
     209             : /** \brief Convert a Unix date to a DOS date.
     210             :  *
     211             :  * This function return the Unix time_t converted in DOS format,
     212             :  * rounded up to the next even second.
     213             :  *
     214             :  * \param[in] unix_time  A Unix time_t value.
     215             :  *
     216             :  * \return The Unix date in DOS format unless it is out of range for
     217             :  *         a DOS time and date in which case zero (0) is returned.
     218             :  */
     219      719930 : dostime_t unix2dostime(time_t unix_time)
     220             : {
     221             :     time_t even_time;
     222             :     struct tm *s;         /* result of localtime() */
     223             : 
     224      719930 :     even_time = (unix_time + 1) & ~1;         /* Round up to even seconds. */
     225      719930 :     s = localtime(&even_time);         /* Use local time since MSDOS does. */
     226      719930 :     return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
     227             :                    s->tm_hour, s->tm_min, s->tm_sec);
     228             : }
     229             : 
     230             : 
     231             : // Local Variables:
     232             : // mode: cpp
     233             : // indent-tabs-mode: nil
     234             : // c-basic-offset: 4
     235             : // tab-width: 4
     236             : // End:
     237             : 
     238             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10