1 /*
2   Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
3 
4   See the accompanying file LICENSE, version 2000-Apr-09 or later
5   (the contents of which are also included in zip.h) for terms of use.
6   If, for some reason, all these files are missing, the Info-ZIP license
7   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /* -----------------------------------------------------------------------------
10 
11 The original functions (Metrowerks Codewarrior pro 3.0) gmtime, localtime,
12 mktime and time do not work correctly. The supplied link library mactime.c
13 contains replacement functions for them.
14 
15  *     Caveat: On a Mac, we only know the GMT and DST offsets for
16  *     the current time, not for the time in question.
17  *     Mac has no support for DST handling.
18  *     DST changeover is all manually set by the user.
19 
20 
21 ------------------------------------------------------------------------------*/
22 
23 /*****************************************************************************/
24 /*  Includes                                                                 */
25 /*****************************************************************************/
26 
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <time.h>
31 #include <OSUtils.h>
32 
33 #include "mactime.h"
34 
35 
36 /*
37 The MacOS function GetDateTime returns  the
38 number of seconds elapsed since midnight, January 1, 1904.
39 */
40 const unsigned long MacOS_2_Unix = 2082844800L;
41 
42 
43 /*****************************************************************************/
44 /*  Macros, typedefs                                                         */
45 /*****************************************************************************/
46 
47 
48 #ifndef TEST_TIME_LIB
49 #define my_gmtime    gmtime
50 #define my_localtime localtime
51 #define my_mktime    mktime
52 #define my_time      time
53 #endif
54 
55 
56 /*****************************************************************************/
57 /*  Prototypes                                                               */
58 /*****************************************************************************/
59 /* internal prototypes */
60 static void clear_tm(struct tm * tm);
61 static long GMTDelta(void);
62 static Boolean DaylightSaving(void);
63 static time_t GetTimeMac(void);
64 static time_t Mactime(time_t *timer);
65 static void   normalize(int *i,int *j,int norm);
66 static struct tm *time2tm(const time_t *timer);
67 static time_t tm2time(struct tm *tp);
68 
69 /* Because serial port and SLIP conflict with ReadXPram calls,
70    we cache the call here so we don't hang on calling ReadLocation()  */
71 static void myReadLocation(MachineLocation * loc);
72 
73 
74 /* prototypes for STD lib replacement functions */
75 struct tm *my_gmtime(const time_t *t);
76 struct tm *my_localtime(const time_t *t);
77 time_t my_mktime(struct tm *tp);
78 time_t my_time(time_t *t);
79 
80 
81 /*****************************************************************************/
82 /*  Functions                                                                */
83 /*****************************************************************************/
84 
85  /*
86  *  Mac file times are based on 1904 Jan 1 00:00 local time,
87  *  not 1970 Jan 1 00:00 UTC.
88  *  So we have to convert the time stamps into UNIX UTC
89  *  compatible values.
90  */
MacFtime2UnixFtime(unsigned long macftime)91 time_t MacFtime2UnixFtime(unsigned long macftime)
92 {
93     long UTCoffset;
94 
95     GetGMToffsetMac(macftime, &UTCoffset);
96     MACOS_TO_UNIX(macftime);
97     macftime -= UTCoffset;
98 
99     return macftime;
100 }
101 
102 
103  /*
104  *  Mac file times are based on 1904 Jan 1 00:00 local time,
105  *  not 1970 Jan 1 00:00 UTC.
106  *  So we have to convert the time stamps into MacOS local
107  *  compatible values.
108  */
UnixFtime2MacFtime(time_t unxftime)109 unsigned long UnixFtime2MacFtime(time_t unxftime)
110 {
111     long UTCoffset;
112     unsigned long macftime = unxftime;
113 
114     UNIX_TO_MACOS(macftime);
115     GetGMToffsetMac(macftime, &UTCoffset);
116     macftime += UTCoffset;
117 
118     return macftime;
119 }
120 
121 
122 
123 
124 
125 /*
126 * This function convert a file-localtime to an another
127 * file-localtime.
128 */
AdjustForTZmoveMac(unsigned long macloctim,long s_gmtoffs)129 time_t AdjustForTZmoveMac(unsigned long macloctim, long s_gmtoffs)
130 {
131     time_t MacGMTTime;
132     long UTCoffset;
133 
134     /* convert macloctim into corresponding UTC value */
135     MacGMTTime = macloctim - s_gmtoffs;
136     GetGMToffsetMac(macloctim, &UTCoffset);
137 
138     return (MacGMTTime + UTCoffset);
139 } /* AdjustForTZmove() */
140 
141 
142 
143 
144 /*
145  * This function calculates the difference between the supplied Mac
146  * ftime value (local time) and the corresponding UTC time in seconds.
147  */
GetGMToffsetMac(unsigned long mactime,long * UTCoffset)148 Boolean GetGMToffsetMac(unsigned long mactime, long *UTCoffset)
149 {
150 
151 mactime = mactime;
152 /*
153  *     Caveat: On a Mac, we only know the GMT and DST offsets for
154  *     the current time, not for the time in question.
155  *     Mac has no support for DST handling.
156  *     DST changeover is all manually set by the user.
157 
158  May be later I can include a support of GMT offset calculation for the
159  time in question here.
160 */
161     *UTCoffset = GMTDelta();
162 
163     return true;
164 }
165 
166 
167 
168 
169 
170 
171 
172 /*****************************************************************************
173  *  Standard Library Replacement Functions
174  *  gmtime(), mktime(), localtime(), time()
175  *
176  *  The unix epoch is used here.
177  *  These functions gmtime(), mktime(), localtime() and time()
178  *  expects and returns unix times.
179  *
180  * At midnight Jan. 1, 1970 GMT, the local time was
181  *    midnight Jan. 1, 1970 + GMTDelta().
182  *
183  *
184  *****************************************************************************/
185 
186 
my_gmtime(const time_t * timer)187 struct tm *my_gmtime(const time_t *timer)
188 {
189     return time2tm(timer);
190 }
191 
192 
193 
194 
my_localtime(const time_t * timer)195 struct tm *my_localtime(const time_t *timer)
196 {
197     time_t maclocal;
198 
199     maclocal = *timer;
200     maclocal += GMTDelta();
201 
202     return time2tm(&maclocal);
203 }
204 
205 
206 
207 
my_mktime(struct tm * tp)208 time_t my_mktime(struct tm *tp)
209 {
210     time_t maclocal;
211 
212     maclocal = tm2time(tp);
213     maclocal -= GMTDelta();
214 
215     return maclocal;
216 }
217 
218 
219 
220 
221 
222 
my_time(time_t * time)223 time_t my_time(time_t *time)
224 {
225 time_t tmp_time;
226 
227 GetDateTime(&tmp_time);
228 
229 MACOS_TO_UNIX(tmp_time);
230 
231 if (time)
232     {
233     *time = tmp_time;
234     }
235 
236 return tmp_time;
237 }
238 
239 
240 
241 /*****************************************************************************/
242 /*  static module level functions
243 /*****************************************************************************/
244 
245 
246 /*
247  * The geographic location and time zone information of a Mac
248  * are stored in extended parameter RAM.  The ReadLocation
249  * produdure uses the geographic location record, MachineLocation,
250  * to read the geographic location and time zone information in
251  * extended parameter RAM.
252  *
253  * Because serial port and SLIP conflict with ReadXPram calls,
254  * we cache the call here.
255  *
256  * Caveat: this caching will give the wrong result if a session
257  * extend across the DST changeover time, but
258  * this function resets itself every 2 hours.
259  */
myReadLocation(MachineLocation * loc)260 static void myReadLocation(MachineLocation * loc)
261 {
262     static MachineLocation storedLoc;   /* InsideMac, OSUtilities, page 4-20  */
263     static time_t first_call = 0, last_call = 86400;
264 
265     if ((last_call - first_call) > 7200)
266         {
267         GetDateTime(&first_call);
268         ReadLocation(&storedLoc);
269         }
270 
271     GetDateTime(&last_call);
272     *loc = storedLoc;
273 }
274 
275 
276 
277 
DaylightSaving(void)278 static Boolean DaylightSaving(void)
279 {
280     MachineLocation loc;
281     unsigned char dlsDelta;
282 
283     myReadLocation(&loc);
284     dlsDelta =  loc.u.dlsDelta;
285 
286     return (dlsDelta != 0);
287 }
288 
289 
290 
291 
292 /* current local time = GMTDelta() + GMT
293    GMT = local time - GMTDelta()    */
GMTDelta(void)294 static long GMTDelta(void)
295 {
296     MachineLocation loc;
297     long gmtDelta;
298 
299     myReadLocation(&loc);
300 
301     /*
302      * On a Mac, the GMT value is in seconds east of GMT.  For example,
303      * San Francisco is at -28,800 seconds (8 hours * 3600 seconds per hour)
304      * east of GMT.  The gmtDelta field is a 3-byte value contained in a
305      * long word, so you must take care to get it properly.
306      */
307     gmtDelta = loc.u.gmtDelta & 0x00FFFFFF;
308     if ((gmtDelta & 0x00800000) != 0)
309         {
310         gmtDelta |= 0xFF000000;
311         }
312 
313     return gmtDelta;
314 }
315 
316 
317 
318 /* This routine simulates stdclib time(), time in seconds since 1.1.1970
319    The time is in GMT  */
GetTimeMac(void)320 static time_t GetTimeMac(void)
321 {
322     unsigned long maclocal;
323 
324 
325     /*
326      * Get the current time expressed as the number of seconds
327      * elapsed since the Mac epoch, midnight, Jan. 1, 1904 (local time).
328      * On a Mac, current time accuracy is up to a second.
329      */
330 
331     GetDateTime(&maclocal);     /* Get Mac local time  */
332     maclocal -= GMTDelta();     /* Get Mac GMT  */
333     MACOS_TO_UNIX(maclocal);
334 
335     return maclocal;            /* return unix GMT  */
336 }
337 
338 
339 
340 
341 /*
342  *  clear_tm - sets a broken-down time to the equivalent of 1970/1/1 00:00:00
343  */
344 
clear_tm(struct tm * tm)345 static void clear_tm(struct tm * tm)
346 {
347     tm->tm_sec   =  0;
348     tm->tm_min   =  0;
349     tm->tm_hour  =  0;
350     tm->tm_mday  =  1;
351     tm->tm_mon   =  0;
352     tm->tm_year  =  0;
353     tm->tm_wday  =  1;
354     tm->tm_yday  =  0;
355     tm->tm_isdst = -1;
356 }
357 
358 
normalize(int * i,int * j,int norm)359 static void normalize(int *i,int *j,int norm)
360 {
361   while(*i < 0)
362     {
363     *i += norm;
364     (*j)--;
365     }
366 
367   while(*i >= norm)
368     {
369     *i -= norm;
370     (*j)++;
371     }
372 }
373 
374 
375 
376 /*  Returns the GMT times  */
Mactime(time_t * timer)377 static time_t Mactime(time_t *timer)
378 {
379     time_t t = GetTimeMac();
380 
381     if (timer != NULL)
382         *timer = t;
383 
384     return t;
385 }
386 
387 
388 
389 
time2tm(const time_t * timer)390 static struct tm *time2tm(const time_t *timer)
391 {
392     DateTimeRec dtr;
393     MachineLocation loc;
394     time_t macLocal = *timer;
395 
396     static struct tm statictime;
397     static const short monthday[12] =
398         {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
399 
400     UNIX_TO_MACOS(macLocal);
401     SecondsToDate(macLocal, &dtr);
402 
403     statictime.tm_sec  = dtr.second;         /* second, from 0 to 59 */
404     statictime.tm_min  = dtr.minute;         /* minute, from 0 to 59 */
405     statictime.tm_hour = dtr.hour;           /* hour, from 0 to 23 */
406     statictime.tm_mday = dtr.day;            /* day of the month, from 1 to 31 */
407     statictime.tm_mon  = dtr.month     - 1;  /* month, 1= January and 12 = December */
408     statictime.tm_year = dtr.year   - 1900;  /* year, ranging from 1904 to 2040 */
409     statictime.tm_wday = dtr.dayOfWeek - 1;  /* day of the week, 1 = Sun, 7 = Sat */
410 
411     statictime.tm_yday = monthday[statictime.tm_mon]
412                          + statictime.tm_mday - 1;
413 
414     if (2 < statictime.tm_mon && !(statictime.tm_year & 3))
415         {
416         ++statictime.tm_yday;
417         }
418 
419     myReadLocation(&loc);
420     statictime.tm_isdst = DaylightSaving();
421 
422     return(&statictime);
423 }
424 
425 
426 
427 
428 
tm2time(struct tm * tp)429 static time_t tm2time(struct tm *tp)
430 {
431 time_t intMacTime;
432 DateTimeRec  dtr;
433 
434  normalize(&tp->tm_sec, &tp->tm_min, 60);
435  normalize(&tp->tm_min, &tp->tm_hour,60);
436  normalize(&tp->tm_hour,&tp->tm_mday,24);
437  normalize(&tp->tm_mon, &tp->tm_year,12);
438 
439  dtr.year    = tp->tm_year + 1900;  /* years since 1900 */
440  dtr.month   = tp->tm_mon  +    1;  /* month, 0 = January and 11 = December */
441  dtr.day     = tp->tm_mday;         /* day of the month, from 1 to 31 */
442  dtr.hour    = tp->tm_hour;         /* hour, from 0 to 23 */
443  dtr.minute  = tp->tm_min;          /* minute, from 0 to 59 */
444  dtr.second  = tp->tm_sec;          /* second, from 0 to 59 */
445 
446  DateToSeconds(&dtr, &intMacTime);
447 
448  MACOS_TO_UNIX(intMacTime);
449 
450  return intMacTime;
451 }
452