Calculate *Peek tagged timestamps in fixed-point.
[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/NS_PER_S);
187 }
188
189 /*
190  * This code is based on the Samba code:
191  *
192  *  Unix SMB/Netbios implementation.
193  *  Version 1.9.
194  *  time handling functions
195  *  Copyright (C) Andrew Tridgell 1992-1998
196  */
197
198 /*
199  * Number of seconds between the UN*X epoch (January 1, 1970, 00:00:00 GMT)
200  * and the Windows NT epoch (January 1, 1601 in the proleptic Gregorian
201  * calendar, 00:00:00 "GMT")
202  *
203  * This is
204  *
205  *     369*365.25*24*60*60-(3*24*60*60+6*60*60)
206  *
207  * 1970-1601 is 369; 365.25 is the average length of a year in days,
208  * including leap years.
209  *
210  * 3 days are subtracted because 1700, 1800, and 1900 were not leap
211  * years, as, while they're all evenly divisible by 4, they're also
212  * evently divisible by 100, but not evently divisible by 400, so
213  * we need to compensate for using the average length of a year in
214  * days, which assumes a leap year every 4 years, *including* every
215  * 100 years.
216  *
217  * I'm not sure what the extra 6 hours are that are being subtracted.
218  */
219 #define TIME_FIXUP_CONSTANT G_GUINT64_CONSTANT(11644473600)
220
221 #ifndef TIME_T_MIN
222 #define TIME_T_MIN ((time_t) ((time_t)0 < (time_t) -1 ? (time_t) 0 \
223                     : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))
224 #endif
225 #ifndef TIME_T_MAX
226 #define TIME_T_MAX ((time_t) (~ (time_t) 0 - TIME_T_MIN))
227 #endif
228
229 static gboolean
230 common_filetime_to_nstime(nstime_t *nstime, guint64 ftsecs, int nsecs)
231 {
232     gint64 secs;
233     /* The next two lines are a fix needed for the
234        broken SCO compiler. JRA. */
235     time_t l_time_min = TIME_T_MIN;
236     time_t l_time_max = TIME_T_MAX;
237
238     /*
239      * Shift the seconds from the Windows epoch to the UN*X epoch.
240      * ftsecs's value should fit in a 64-bit signed variable, as
241      * ftsecs is derived from a 64-bit fractions-of-a-second value,
242      * and is far from the maximum 64-bit signed value, and
243      * TIME_FIXUP_CONSTANT is also far from the maximum 64-bit
244      * signed value, so the difference between them should also
245      * fit in a 64-bit signed value.
246      */
247     secs = (gint64)ftsecs - TIME_FIXUP_CONSTANT;
248
249     if (!(l_time_min <= secs && secs <= l_time_max)) {
250         /* The result won't fit in a time_t */
251         return FALSE;
252     }
253
254     /*
255      * Get the time as seconds and nanoseconds.
256      */
257     nstime->secs = (time_t) secs;
258     nstime->nsecs = nsecs;
259     return TRUE;
260 }
261
262 /*
263  * function: filetime_to_nstime
264  * converts a Windows FILETIME value to an nstime_t
265  * returns TRUE if the conversion succeeds, FALSE if it doesn't
266  * (for example, with a 32-bit time_t, the time overflows or
267  * underflows time_t)
268  */
269 gboolean
270 filetime_to_nstime(nstime_t *nstime, guint64 filetime)
271 {
272     guint64 ftsecs;
273     int nsecs;
274
275     /*
276      * Split into seconds and tenths of microseconds, and
277      * then convert tenths of microseconds to nanoseconds.
278      */
279     ftsecs = filetime / 10000000;
280     nsecs = (int)((filetime % 10000000)*100);
281
282     return common_filetime_to_nstime(nstime, ftsecs, nsecs);
283 }
284
285 /*
286  * function: nsfiletime_to_nstime
287  * converts a Windows FILETIME-like value, but given in nanoseconds
288  * rather than 10ths of microseconds, to an nstime_t
289  * returns TRUE if the conversion succeeds, FALSE if it doesn't
290  * (for example, with a 32-bit time_t, the time overflows or
291  * underflows time_t)
292  */
293 gboolean
294 nsfiletime_to_nstime(nstime_t *nstime, guint64 nsfiletime)
295 {
296     guint64 ftsecs;
297     int nsecs;
298
299     /* Split into seconds and nanoseconds. */
300     ftsecs = nsfiletime / NS_PER_S;
301     nsecs = (int)(nsfiletime % NS_PER_S);
302
303     return common_filetime_to_nstime(nstime, ftsecs, nsecs);
304 }
305
306 /*
307  * Editor modelines
308  *
309  * Local Variables:
310  * c-basic-offset: 4
311  * tab-width: 8
312  * indent-tabs-mode: nil
313  * End:
314  *
315  * ex: set shiftwidth=4 tabstop=8 expandtab:
316  * :indentSize=4:tabSize=8:noTabs=true:
317  */