replace SPDX identifier GPL-2.0+ with GPL-2.0-or-later.
[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  * SPDX-License-Identifier: GPL-2.0-or-later
11  */
12
13 #include <glib.h>
14 #include "nstime.h"
15
16 /* this is #defined so that we can clearly see that we have the right number of
17    zeros, rather than as a guard against the number of nanoseconds in a second
18    changing ;) */
19 #define NS_PER_S 1000000000
20
21 /* set the given nstime_t to zero */
22 void nstime_set_zero(nstime_t *nstime)
23 {
24     nstime->secs  = 0;
25     nstime->nsecs = 0;
26 }
27
28 /* is the given nstime_t currently zero? */
29 gboolean nstime_is_zero(nstime_t *nstime)
30 {
31     if(nstime->secs == 0 && nstime->nsecs == 0) {
32         return TRUE;
33     } else {
34         return FALSE;
35     }
36 }
37
38 /* set the given nstime_t to (0,maxint) to mark it as "unset"
39  * That way we can find the first frame even when a timestamp
40  * is zero (fix for bug 1056)
41  */
42 void nstime_set_unset(nstime_t *nstime)
43 {
44     nstime->secs  = 0;
45     nstime->nsecs = G_MAXINT;
46 }
47
48 /* is the given nstime_t currently (0,maxint)? */
49 gboolean nstime_is_unset(const nstime_t *nstime)
50 {
51     if(nstime->secs == 0 && nstime->nsecs == G_MAXINT) {
52         return TRUE;
53     } else {
54         return FALSE;
55     }
56 }
57
58
59 /** funcion: nstime_copy
60  *
61  * a = b
62  */
63 void nstime_copy(nstime_t *a, const nstime_t *b)
64 {
65     a->secs = b->secs;
66     a->nsecs = b->nsecs;
67 }
68
69 /*
70  * function: nstime_delta
71  * delta = b - a
72  */
73
74 void nstime_delta(nstime_t *delta, const nstime_t *b, const nstime_t *a )
75 {
76     if (b->secs == a->secs) {
77         /* The seconds part of b is the same as the seconds part of a, so if
78            the nanoseconds part of the first time is less than the nanoseconds
79            part of a, b is before a.  The nanoseconds part of the delta should
80            just be the difference between the nanoseconds part of b and the
81            nanoseconds part of a; don't adjust the seconds part of the delta,
82            as it's OK if the nanoseconds part is negative, and an overflow
83            can never result. */
84         delta->secs = 0;
85         delta->nsecs = b->nsecs - a->nsecs;
86     } else if (b->secs < a->secs) {
87         /* The seconds part of b is less than the seconds part of a, so b is
88            before a.
89
90            Both the "seconds" and "nanoseconds" value of the delta
91            should have the same sign, so if the difference between the
92            nanoseconds values would be *positive*, subtract 1,000,000,000
93            from it, and add one to the seconds value. */
94         delta->secs = b->secs - a->secs;
95         delta->nsecs = b->nsecs - a->nsecs;
96         if(delta->nsecs > 0) {
97             delta->nsecs -= NS_PER_S;
98             delta->secs ++;
99         }
100     } else {
101         delta->secs = b->secs - a->secs;
102         delta->nsecs = b->nsecs - a->nsecs;
103         if(delta->nsecs < 0) {
104             delta->nsecs += NS_PER_S;
105             delta->secs --;
106         }
107     }
108 }
109
110 /*
111  * function: nstime_sum
112  * sum = a + b
113  */
114
115 void nstime_sum(nstime_t *sum, const nstime_t *a, const nstime_t *b)
116 {
117     sum->secs = a->secs + b->secs;
118     sum->nsecs = a->nsecs + b->nsecs;
119     if(sum->nsecs>=NS_PER_S || (sum->nsecs>0 && sum->secs<0)){
120         sum->nsecs-=NS_PER_S;
121         sum->secs++;
122     } else if(sum->nsecs<=-NS_PER_S || (sum->nsecs<0 && sum->secs>0)) {
123         sum->nsecs+=NS_PER_S;
124         sum->secs--;
125     }
126 }
127
128 /*
129  * function: nstime_cmp
130  *
131  * a > b : > 0
132  * a = b : 0
133  * a < b : < 0
134  */
135
136 int nstime_cmp (const nstime_t *a, const nstime_t *b )
137 {
138     if (G_UNLIKELY(nstime_is_unset(a))) {
139         if (G_UNLIKELY(nstime_is_unset(b))) {
140             return 0;    /* "no time stamp" is "equal" to "no time stamp" */
141         } else {
142             return -1;   /* and is less than all time stamps */
143         }
144     } else {
145         if (G_UNLIKELY(nstime_is_unset(b))) {
146             return 1;
147         }
148     }
149     if (a->secs == b->secs) {
150         return a->nsecs - b->nsecs;
151     } else {
152         return (int) (a->secs - b->secs);
153     }
154 }
155
156 /*
157  * function: nstime_to_msec
158  * converts nstime to double, time base is milli seconds
159  */
160
161 double nstime_to_msec(const nstime_t *nstime)
162 {
163     return ((double)nstime->secs*1000 + (double)nstime->nsecs/1000000);
164 }
165
166 /*
167  * function: nstime_to_sec
168  * converts nstime to double, time base is seconds
169  */
170
171 double nstime_to_sec(const nstime_t *nstime)
172 {
173     return ((double)nstime->secs + (double)nstime->nsecs/NS_PER_S);
174 }
175
176 /*
177  * This code is based on the Samba code:
178  *
179  *  Unix SMB/Netbios implementation.
180  *  Version 1.9.
181  *  time handling functions
182  *  Copyright (C) Andrew Tridgell 1992-1998
183  */
184
185 /*
186  * Number of seconds between the UN*X epoch (January 1, 1970, 00:00:00 GMT)
187  * and the Windows NT epoch (January 1, 1601 in the proleptic Gregorian
188  * calendar, 00:00:00 "GMT")
189  *
190  * This is
191  *
192  *     369*365.25*24*60*60-(3*24*60*60+6*60*60)
193  *
194  * 1970-1601 is 369; 365.25 is the average length of a year in days,
195  * including leap years.
196  *
197  * 3 days are subtracted because 1700, 1800, and 1900 were not leap
198  * years, as, while they're all evenly divisible by 4, they're also
199  * evently divisible by 100, but not evently divisible by 400, so
200  * we need to compensate for using the average length of a year in
201  * days, which assumes a leap year every 4 years, *including* every
202  * 100 years.
203  *
204  * I'm not sure what the extra 6 hours are that are being subtracted.
205  */
206 #define TIME_FIXUP_CONSTANT G_GUINT64_CONSTANT(11644473600)
207
208 #ifndef TIME_T_MIN
209 #define TIME_T_MIN ((time_t) ((time_t)0 < (time_t) -1 ? (time_t) 0 \
210                     : (time_t) (~0ULL << (sizeof (time_t) * CHAR_BIT - 1))))
211 #endif
212 #ifndef TIME_T_MAX
213 #define TIME_T_MAX ((time_t) (~ (time_t) 0 - TIME_T_MIN))
214 #endif
215
216 static gboolean
217 common_filetime_to_nstime(nstime_t *nstime, guint64 ftsecs, int nsecs)
218 {
219     gint64 secs;
220
221     /*
222      * Shift the seconds from the Windows epoch to the UN*X epoch.
223      * ftsecs's value should fit in a 64-bit signed variable, as
224      * ftsecs is derived from a 64-bit fractions-of-a-second value,
225      * and is far from the maximum 64-bit signed value, and
226      * TIME_FIXUP_CONSTANT is also far from the maximum 64-bit
227      * signed value, so the difference between them should also
228      * fit in a 64-bit signed value.
229      */
230     secs = (gint64)ftsecs - TIME_FIXUP_CONSTANT;
231
232     if (!(TIME_T_MIN <= secs && secs <= TIME_T_MAX)) {
233         /* The result won't fit in a time_t */
234         return FALSE;
235     }
236
237     /*
238      * Get the time as seconds and nanoseconds.
239      */
240     nstime->secs = (time_t) secs;
241     nstime->nsecs = nsecs;
242     return TRUE;
243 }
244
245 /*
246  * function: filetime_to_nstime
247  * converts a Windows FILETIME value to an nstime_t
248  * returns TRUE if the conversion succeeds, FALSE if it doesn't
249  * (for example, with a 32-bit time_t, the time overflows or
250  * underflows time_t)
251  */
252 gboolean
253 filetime_to_nstime(nstime_t *nstime, guint64 filetime)
254 {
255     guint64 ftsecs;
256     int nsecs;
257
258     /*
259      * Split into seconds and tenths of microseconds, and
260      * then convert tenths of microseconds to nanoseconds.
261      */
262     ftsecs = filetime / 10000000;
263     nsecs = (int)((filetime % 10000000)*100);
264
265     return common_filetime_to_nstime(nstime, ftsecs, nsecs);
266 }
267
268 /*
269  * function: nsfiletime_to_nstime
270  * converts a Windows FILETIME-like value, but given in nanoseconds
271  * rather than 10ths of microseconds, to an nstime_t
272  * returns TRUE if the conversion succeeds, FALSE if it doesn't
273  * (for example, with a 32-bit time_t, the time overflows or
274  * underflows time_t)
275  */
276 gboolean
277 nsfiletime_to_nstime(nstime_t *nstime, guint64 nsfiletime)
278 {
279     guint64 ftsecs;
280     int nsecs;
281
282     /* Split into seconds and nanoseconds. */
283     ftsecs = nsfiletime / NS_PER_S;
284     nsecs = (int)(nsfiletime % NS_PER_S);
285
286     return common_filetime_to_nstime(nstime, ftsecs, nsecs);
287 }
288
289 /*
290  * Editor modelines
291  *
292  * Local Variables:
293  * c-basic-offset: 4
294  * tab-width: 8
295  * indent-tabs-mode: nil
296  * End:
297  *
298  * ex: set shiftwidth=4 tabstop=8 expandtab:
299  * :indentSize=4:tabSize=8:noTabs=true:
300  */