1 /* wvWare
2 * Copyright (C) Caolan McNamara, Dom Lachowicz, and others
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <time.h>
27 #include "wv.h"
28
29 void
wvGetFILETIME(FILETIME * ft,wvStream * fd)30 wvGetFILETIME (FILETIME * ft, wvStream * fd)
31 {
32 ft->dwLowDateTime = read_32ubit (fd);
33 ft->dwHighDateTime = read_32ubit (fd);
34 }
35
36 void
wvInitFILETIME(FILETIME * ft)37 wvInitFILETIME (FILETIME * ft)
38 {
39 ft->dwLowDateTime = 0;
40 ft->dwHighDateTime = 0;
41 }
42
43 int
wvFileTimeToDosDateTime(const FILETIME * ft,U16 * fatdate,U16 * fattime)44 wvFileTimeToDosDateTime (const FILETIME * ft, U16 * fatdate, U16 * fattime)
45 {
46 time_t unixtime = wvDOSFS_FileTimeToUnixTime (ft, NULL);
47 struct tm *tm = localtime (&unixtime);
48 if (fattime)
49 *fattime = (tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2);
50 if (fatdate)
51 *fatdate = ((tm->tm_year - 80) << 9) + ((tm->tm_mon + 1) << 5)
52 + tm->tm_mday;
53 return (1);
54 }
55
56
57 /***********************************************************************
58 * DOSFS_FileTimeToUnixTime
59 *
60 * Convert a FILETIME format to Unix time.
61 * If not NULL, 'remainder' contains the fractional part of the filetime,
62 * in the range of [0..9999999] (even if time_t is negative).
63 */
64 time_t
wvDOSFS_FileTimeToUnixTime(const FILETIME * filetime,U32 * remainder)65 wvDOSFS_FileTimeToUnixTime (const FILETIME * filetime, U32 * remainder)
66 {
67 U32 a0; /* 16 bit, low bits */
68 U32 a1; /* 16 bit, medium bits */
69 U32 a2; /* 32 bit, high bits */
70 U32 r; /* remainder of division */
71 unsigned int carry; /* carry bit for subtraction */
72 int negative; /* whether a represents a negative value */
73
74 /* Copy the time values to a2/a1/a0 */
75 a2 = filetime->dwHighDateTime;
76 a1 = ((U32) filetime->dwLowDateTime) >> 16;
77 a0 = ((U32) filetime->dwLowDateTime) & 0xffff;
78
79 /* Subtract the time difference */
80 if (a0 >= 32768)
81 a0 -= 32768, carry = 0;
82 else
83 a0 += (1 << 16) - 32768, carry = 1;
84
85 if (a1 >= 54590 + carry)
86 a1 -= 54590 + carry, carry = 0;
87 else
88 a1 += (1 << 16) - 54590 - carry, carry = 1;
89
90 a2 -= 27111902 + carry;
91
92 /* If a is negative, replace a by (-1-a) */
93 negative = (a2 >= ((U32) 1) << 31);
94 if (negative)
95 {
96 /* Set a to -a - 1 (a is a2/a1/a0) */
97 a0 = 0xffff - a0;
98 a1 = 0xffff - a1;
99 a2 = ~a2;
100 }
101
102 /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r.
103 Split the divisor into 10000 * 1000 which are both less than 0xffff. */
104 a1 += (a2 % 10000) << 16;
105 a2 /= 10000;
106 a0 += (a1 % 10000) << 16;
107 a1 /= 10000;
108 r = a0 % 10000;
109 a0 /= 10000;
110
111 a1 += (a2 % 1000) << 16;
112 a2 /= 1000;
113 a0 += (a1 % 1000) << 16;
114 a1 /= 1000;
115 r += (a0 % 1000) * 10000;
116 a0 /= 1000;
117
118 /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
119 if (negative)
120 {
121 /* Set a to -a - 1 (a is a2/a1/a0) */
122 a0 = 0xffff - a0;
123 a1 = 0xffff - a1;
124 a2 = ~a2;
125
126 r = 9999999 - r;
127 }
128
129 if (remainder)
130 *remainder = r;
131 /* Do not replace this by << 32, it gives a compiler warning and it does
132 not work. */
133 return ((((time_t) a2) << 16) << 16) + (a1 << 16) + a0;
134
135 }
136