Have a common routine to convert FILETIME to nstime_t.
[metze/wireshark/wip.git] / wsutil / nstime.c
1 /* nstime.c
2  * Routines for manipulating nstime_t structures
3  *
4  * Copyright (c) 2005 MX Telecom Ltd. <richardv@mxtelecom.com>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  *
24  */
25
26 #include <glib.h>
27 #include "nstime.h"
28
29 /* this is #defined so that we can clearly see that we have the right number of
30    zeros, rather than as a guard against the number of nanoseconds in a second
31    changing ;) */
32 #define NS_PER_S 1000000000
33
34 /* set the given nstime_t to zero */
35 void nstime_set_zero(nstime_t *nstime)
36 {
37     nstime->secs  = 0;
38     nstime->nsecs = 0;
39 }
40
41 /* is the given nstime_t currently zero? */
42 gboolean nstime_is_zero(nstime_t *nstime)
43 {
44     if(nstime->secs == 0 && nstime->nsecs == 0) {
45         return TRUE;
46     } else {
47         return FALSE;
48     }
49 }
50
51 /* set the given nstime_t to (0,maxint) to mark it as "unset"
52  * That way we can find the first frame even when a timestamp
53  * is zero (fix for bug 1056)
54  */
55 void nstime_set_unset(nstime_t *nstime)
56 {
57     nstime->secs  = 0;
58     nstime->nsecs = G_MAXINT;
59 }
60
61 /* is the given nstime_t currently (0,maxint)? */
62 gboolean nstime_is_unset(const nstime_t *nstime)
63 {
64     if(nstime->secs == 0 && nstime->nsecs == G_MAXINT) {
65         return TRUE;
66     } else {
67         return FALSE;
68     }
69 }
70
71
72 /** funcion: nstime_copy
73  *
74  * a = b
75  */
76 void nstime_copy(nstime_t *a, const nstime_t *b)
77 {
78     a->secs = b->secs;
79     a->nsecs = b->nsecs;
80 }
81
82 /*
83  * function: nstime_delta
84  * delta = b - a
85  */
86
87 void nstime_delta(nstime_t *delta, const nstime_t *b, const nstime_t *a )
88 {
89     if (b->secs == a->secs) {
90         /* The seconds part of b is the same as the seconds part of a, so if
91            the nanoseconds part of the first time is less than the nanoseconds
92            part of a, b is before a.  The nanoseconds part of the delta should
93            just be the difference between the nanoseconds part of b and the
94            nanoseconds part of a; don't adjust the seconds part of the delta,
95            as it's OK if the nanoseconds part is negative, and an overflow
96            can never result. */
97         delta->secs = 0;
98         delta->nsecs = b->nsecs - a->nsecs;
99     } else if (b->secs <= a->secs) {
100         /* The seconds part of b is less than the seconds part of a, so b is
101            before a.
102
103            Both the "seconds" and "nanoseconds" value of the delta
104            should have the same sign, so if the difference between the
105            nanoseconds values would be *positive*, subtract 1,000,000,000
106            from it, and add one to the seconds value. */
107         delta->secs = b->secs - a->secs;
108         delta->nsecs = b->nsecs - a->nsecs;
109         if(delta->nsecs > 0) {
110             delta->nsecs -= NS_PER_S;
111             delta->secs ++;
112         }
113     } else {
114         delta->secs = b->secs - a->secs;
115         delta->nsecs = b->nsecs - a->nsecs;
116         if(delta->nsecs < 0) {
117             delta->nsecs += NS_PER_S;
118             delta->secs --;
119         }
120     }
121 }
122
123 /*
124  * function: nstime_sum
125  * sum = a + b
126  */
127
128 void nstime_sum(nstime_t *sum, const nstime_t *a, const nstime_t *b)
129 {
130     sum->secs = a->secs + b->secs;
131     sum->nsecs = a->nsecs + b->nsecs;
132     if(sum->nsecs>=NS_PER_S || (sum->nsecs>0 && sum->secs<0)){
133         sum->nsecs-=NS_PER_S;
134         sum->secs++;
135     } else if(sum->nsecs<=-NS_PER_S || (sum->nsecs<0 && sum->secs>0)) {
136         sum->nsecs+=NS_PER_S;
137         sum->secs--;
138     }
139 }
140
141 /*
142  * function: nstime_cmp
143  *
144  * a > b : > 0
145  * a = b : 0
146  * a < b : < 0
147  */
148
149 int nstime_cmp (const nstime_t *a, const nstime_t *b )
150 {
151     if (G_UNLIKELY(nstime_is_unset(a))) {
152         if (G_UNLIKELY(nstime_is_unset(b))) {
153             return 0;    /* "no time stamp" is "equal" to "no time stamp" */
154         } else {
155             return -1;   /* and is less than all time stamps */
156         }
157     } else {
158         if (G_UNLIKELY(nstime_is_unset(b))) {
159             return 1;
160         }
161     }
162     if (a->secs == b->secs) {
163         return a->nsecs - b->nsecs;
164     } else {
165         return (int) (a->secs - b->secs);
166     }
167 }
168
169 /*
170  * function: nstime_to_msec
171  * converts nstime to double, time base is milli seconds
172  */
173
174 double nstime_to_msec(const nstime_t *nstime)
175 {
176     return ((double)nstime->secs*1000 + (double)nstime->nsecs/1000000);
177 }
178
179 /*
180  * function: nstime_to_sec
181  * converts nstime to double, time base is seconds
182  */
183
184 double nstime_to_sec(const nstime_t *nstime)
185 {
186     return ((double)nstime->secs + (double)nstime->nsecs/1000000000);
187 }
188
189 /*
190  * Number of seconds between the UN*X epoch (January 1, 1970, 00:00:00 GMT)
191  * and the Windows NT epoch (January 1, 1601 in the proleptic Gregorian
192  * calendar, 00:00:00 "GMT")
193  *
194  * This is
195  *
196  *     369*365.25*24*60*60-(3*24*60*60+6*60*60)
197  *
198  * 1970-1601 is 369; 365.25 is the average length of a year in days,
199  * including leap years.
200  *
201  * 3 days are subtracted because 1700, 1800, and 1900 were not leap
202  * years, as, while they're all evenly divisible by 4, they're also
203  * evently divisible by 100, but not evently divisible by 400, so
204  * we need to compensate for using the average length of a year in
205  * days, which assumes a leap year every 4 years, *including* every
206  * 100 years.
207  *
208  * I'm not sure what the extra 6 hours are that are being subtracted.  
209  */
210 #define TIME_FIXUP_CONSTANT G_GUINT64_CONSTANT(11644473600)
211
212 #ifndef TIME_T_MIN
213 #define TIME_T_MIN ((time_t) ((time_t)0 < (time_t) -1 ? (time_t) 0 \
214                     : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))
215 #endif
216 #ifndef TIME_T_MAX
217 #define TIME_T_MAX ((time_t) (~ (time_t) 0 - TIME_T_MIN))
218 #endif
219
220 /*
221  * function: filetime_to_nstime
222  * converts a Windows FILETIME value to an nstime_t
223  * returns TRUE if the conversion succeeds, FALSE if it doesn't
224  * (for example, with a 32-bit time_t, the time overflows or
225  * underflows time_t)
226  */
227 gboolean
228 filetime_to_nstime(nstime_t *nstime, guint64 filetime)
229 {
230     /*
231      * This code is based on the Samba code:
232      *
233      *  Unix SMB/Netbios implementation.
234      *  Version 1.9.
235      *  time handling functions
236      *  Copyright (C) Andrew Tridgell 1992-1998
237      */
238     gint64 secs;
239     int nsecs;
240     /* The next two lines are a fix needed for the
241        broken SCO compiler. JRA. */
242     time_t l_time_min = TIME_T_MIN;
243     time_t l_time_max = TIME_T_MAX;
244
245     /* Split into seconds and nanoseconds. */
246     secs = filetime / 10000000;
247     nsecs = (int)((filetime % 10000000)*100);
248
249     /* Now adjust the seconds. */
250     secs -= TIME_FIXUP_CONSTANT;
251
252     if (!(l_time_min <= secs && secs <= l_time_max)) {
253         /* The result won't fit in a time_t */
254         return FALSE;
255     }
256
257     /*
258      * Get the time as seconds and nanoseconds.
259      */
260     nstime->secs = (time_t) secs;
261     nstime->nsecs = nsecs;
262     return TRUE;
263 }
264
265 /*
266  * Editor modelines
267  *
268  * Local Variables:
269  * c-basic-offset: 4
270  * tab-width: 8
271  * indent-tabs-mode: nil
272  * End:
273  *
274  * ex: set shiftwidth=4 tabstop=8 expandtab:
275  * :indentSize=4:tabSize=8:noTabs=true:
276  */
277