2 * Routines for "Time Shift" window
3 * Submitted by Edwin Groothuis <wireshark@mavetju.org>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include "time_shift.h"
20 #include "ui/packet_list_utils.h"
24 #define SHIFT_SETTOZERO 1
25 #define SHIFT_KEEPOFFSET 0
27 #define CHECK_YEARS(Y) \
29 return "Years must be larger than 1970"; \
31 #define CHECK_MONTHS(M) \
32 if (*M < 1 || *M > 12) { \
33 return "Months must be between [1..12]"; \
35 #define CHECK_DAYS(D) \
36 if (*D < 1 || *D > 31) { \
37 return "Days must be between [1..31]"; \
39 #define CHECK_HOURS(h) \
40 if (*h < 0 || *h > 23) { \
41 return "Hours must be between [0..23]"; \
43 #define CHECK_HOUR(h) \
45 return "Negative hours. Have you specified more than " \
46 "one minus character?"; \
48 #define CHECK_MINUTE(m) \
49 if (*m < 0 || *m > 59) { \
50 return "Minutes must be between [0..59]"; \
52 #define CHECK_SECOND(s) \
53 if (*s < 0 || *s > 59) { \
54 return "Seconds must be between [0..59]"; \
58 modify_time_perform(frame_data
*fd
, int neg
, nstime_t
*offset
, int settozero
)
60 /* The actual shift */
61 if (settozero
== SHIFT_SETTOZERO
) {
62 nstime_subtract(&(fd
->abs_ts
), &(fd
->shift_offset
));
63 nstime_set_zero(&(fd
->shift_offset
));
66 if (neg
== SHIFT_POS
) {
67 nstime_add(&(fd
->abs_ts
), offset
);
68 nstime_add(&(fd
->shift_offset
), offset
);
69 } else if (neg
== SHIFT_NEG
) {
70 nstime_subtract(&(fd
->abs_ts
), offset
);
71 nstime_subtract(&(fd
->shift_offset
), offset
);
73 fprintf(stderr
, "Modify_time_perform: neg = %d?\n", neg
);
78 * If the line between (OT1, NT1) and (OT2, NT2) is a straight line
79 * and (OT3, NT3) is on that line,
80 * then (NT2 - NT1) / (OT2 - OT2) = (NT3 - NT1) / (OT3 - OT1) and
81 * then (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) = (NT3 - NT1) and
82 * then NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) = NT3 and
83 * then NT3 = NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) and
84 * thus NT3 = NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT1)
85 * or NT3 = NT1 + (OT3 - OT1) * ( deltaNT12 / deltaOT12)
87 * All the things you come up when waiting for the train to come...
90 calcNT3(nstime_t
*OT1
, nstime_t
*OT3
, nstime_t
*NT1
, nstime_t
*NT3
,
91 nstime_t
*deltaOT
, nstime_t
*deltaNT
)
93 long double fnt
, fot
, f
, secs
, nsecs
;
95 fnt
= (long double)deltaNT
->secs
+ (deltaNT
->nsecs
/ 1000000000.0L);
96 fot
= (long double)deltaOT
->secs
+ (deltaOT
->nsecs
/ 1000000000.0L);
99 nstime_copy(NT3
, OT3
);
100 nstime_subtract(NT3
, OT1
);
102 secs
= f
* (long double)NT3
->secs
;
103 nsecs
= f
* (long double)NT3
->nsecs
;
104 nsecs
+= (secs
- floorl(secs
)) * 1000000000.0L;
105 while (nsecs
> 1000000000L) {
107 nsecs
-= 1000000000L;
111 nsecs
+= 1000000000L;
113 NT3
->secs
= (time_t)secs
;
114 NT3
->nsecs
= (int)nsecs
;
115 nstime_add(NT3
, NT1
);
119 time_string_parse(const char *time_text
, int *year
, int *month
, int *day
, bool *negative
, int *hour
, int *minute
, long double *second
) {
120 const char *pts
= time_text
;
122 if (!time_text
|| !hour
|| !minute
|| !second
)
123 return "Unable to convert time.";
125 /* strip whitespace */
126 while (g_ascii_isspace(pts
[0]))
129 if (year
&& month
&& day
) {
131 * The following time format is allowed:
132 * [YYYY-MM-DD] hh:mm:ss(.decimals)?
134 * Since Wireshark doesn't support regular expressions (please prove me
135 * wrong :-) we will have to figure it out ourselves in the
138 * 1. YYYY-MM-DD hh:mm:ss.decimals
139 * 2. hh:mm:ss.decimals
143 /* check for empty string */
145 return "Time is empty.";
147 if (sscanf(pts
, "%d-%d-%d %d:%d:%Lf", year
, month
, day
, hour
, minute
, second
) == 6) {
148 /* printf("%%d-%%d-%%d %%d:%%d:%%f\n"); */
153 CHECK_MINUTE(minute
);
154 CHECK_SECOND(second
);
155 } else if (sscanf(pts
, "%d:%d:%Lf", hour
, minute
, second
) == 3) {
156 /* printf("%%d:%%d:%%f\n"); */
157 *year
= *month
= *day
= 0;
159 CHECK_MINUTE(minute
);
160 CHECK_SECOND(second
);
162 return "Could not parse the time. Expected [YYYY-MM-DD] "
167 return "Unable to convert time.";
170 * The following offset types are allowed:
171 * -?((hh:)mm:)ss(.decimals)?
173 * Since Wireshark doesn't support regular expressions (please prove me
174 * wrong :-) we will have to figure it out ourselves in the
177 * 1. hh:mm:ss.decimals
183 /* check for minus sign */
190 /* check for empty string */
192 return "Time is empty.";
194 if (sscanf(pts
, "%d:%d:%Lf", hour
, minute
, second
) == 3) {
195 /* printf("%%d:%%d:%%d.%%d\n"); */
197 CHECK_MINUTE(minute
);
198 CHECK_SECOND(second
);
199 } else if (sscanf(pts
, "%d:%Lf", minute
, second
) == 2) {
200 /* printf("%%d:%%d.%%d\n"); */
201 CHECK_MINUTE(minute
);
202 CHECK_SECOND(second
);
204 } else if (sscanf(pts
, "%Lf", second
) == 1) {
205 /* printf("%%d.%%d\n"); */
206 CHECK_SECOND(second
);
209 return "Could not parse the time: Expected [[hh:]mm:]ss.[dec].";
217 time_string_to_nstime(const char *time_text
, nstime_t
*packettime
, nstime_t
*nstime
)
221 struct tm tm
, *tmptm
;
225 if ((err_str
= time_string_parse(time_text
, &Y
, &M
, &D
, NULL
, &h
, &m
, &f
)) != NULL
)
228 /* Convert the time entered in an epoch offset */
229 tmptm
= localtime(&(packettime
->secs
));
233 memset (&tm
, 0, sizeof (tm
));
236 tm
.tm_year
= Y
- 1900;
242 tm
.tm_sec
= (int)floorl(f
);
246 return "Mktime went wrong. Is the time valid?";
251 nstime
->nsecs
= (int)(f
* 1000000000);
257 time_shift_all(capture_file
*cf
, const char *offset_text
)
260 long double offset_float
= 0;
268 if (!cf
|| !offset_text
)
269 return "Nothing to work with.";
271 if ((err_str
= time_string_parse(offset_text
, NULL
, NULL
, NULL
, &neg
, &h
, &m
, &f
)) != NULL
)
274 offset_float
= h
* 3600 + m
* 60 + f
;
276 if (offset_float
== 0)
277 return "Offset is zero.";
279 nstime_set_zero(&offset
);
280 offset
.secs
= (time_t)floorl(offset_float
);
281 offset_float
-= offset
.secs
;
282 offset
.nsecs
= (int)(offset_float
* 1000000000);
284 if (!frame_data_sequence_find(cf
->provider
.frames
, 1))
285 return "No frames found."; /* Shouldn't happen */
287 for (i
= 1; i
<= cf
->count
; i
++) {
288 if ((fd
= frame_data_sequence_find(cf
->provider
.frames
, i
)) == NULL
)
289 continue; /* Shouldn't happen */
290 modify_time_perform(fd
, neg
? SHIFT_NEG
: SHIFT_POS
, &offset
, SHIFT_KEEPOFFSET
);
292 cf
->unsaved_changes
= true;
293 packet_list_queue_draw();
299 time_shift_settime(capture_file
*cf
, unsigned packet_num
, const char *time_text
)
301 nstime_t set_time
, diff_time
, packet_time
;
302 frame_data
*fd
, *packetfd
;
306 if (!cf
|| !time_text
)
307 return "Nothing to work with.";
309 if (packet_num
< 1 || packet_num
> cf
->count
)
310 return "Packet out of range.";
313 * Get a copy of the real time (abs_ts - shift_offset) do we can find out the
314 * difference between the specified time and the original packet
316 if ((packetfd
= frame_data_sequence_find(cf
->provider
.frames
, packet_num
)) == NULL
)
317 return "No packets found.";
318 nstime_delta(&packet_time
, &(packetfd
->abs_ts
), &(packetfd
->shift_offset
));
320 if ((err_str
= time_string_to_nstime(time_text
, &packet_time
, &set_time
)) != NULL
)
323 /* Calculate difference between packet time and requested time */
324 nstime_delta(&diff_time
, &set_time
, &packet_time
);
326 /* Up to here nothing is changed */
328 if (!frame_data_sequence_find(cf
->provider
.frames
, 1))
329 return "No frames found."; /* Shouldn't happen */
331 /* Set everything back to the original time */
332 for (i
= 1; i
<= cf
->count
; i
++) {
333 if ((fd
= frame_data_sequence_find(cf
->provider
.frames
, i
)) == NULL
)
334 continue; /* Shouldn't happen */
335 modify_time_perform(fd
, SHIFT_POS
, &diff_time
, SHIFT_SETTOZERO
);
338 cf
->unsaved_changes
= true;
339 packet_list_queue_draw();
344 time_shift_adjtime(capture_file
*cf
, unsigned packet1_num
, const char *time1_text
, unsigned packet2_num
, const char *time2_text
)
346 nstime_t nt1
, nt2
, ot1
, ot2
, nt3
;
347 nstime_t dnt
, dot
, d3t
;
348 frame_data
*fd
, *packet1fd
, *packet2fd
;
352 if (!cf
|| !time1_text
|| !time2_text
)
353 return "Nothing to work with.";
355 if (packet1_num
< 1 || packet1_num
> cf
->count
|| packet2_num
< 1 || packet2_num
> cf
->count
)
356 return "Packet out of range.";
359 * The following time format is allowed:
360 * [YYYY-MM-DD] hh:mm:ss(.decimals)?
362 * Since Wireshark doesn't support regular expressions (please prove me
363 * wrong :-) we will have to figure it out ourselves in the
366 * 1. YYYY-MM-DD hh:mm:ss.decimals
367 * 2. hh:mm:ss.decimals
372 * Get a copy of the real time (abs_ts - shift_offset) do we can find out the
373 * difference between the specified time and the original packet
375 if ((packet1fd
= frame_data_sequence_find(cf
->provider
.frames
, packet1_num
)) == NULL
)
376 return "No frames found.";
377 nstime_copy(&ot1
, &(packet1fd
->abs_ts
));
378 nstime_subtract(&ot1
, &(packet1fd
->shift_offset
));
380 if ((err_str
= time_string_to_nstime(time1_text
, &ot1
, &nt1
)) != NULL
)
384 * Get a copy of the real time (abs_ts - shift_offset) do we can find out the
385 * difference between the specified time and the original packet
387 if ((packet2fd
= frame_data_sequence_find(cf
->provider
.frames
, packet2_num
)) == NULL
)
388 return "No frames found.";
389 nstime_copy(&ot2
, &(packet2fd
->abs_ts
));
390 nstime_subtract(&ot2
, &(packet2fd
->shift_offset
));
392 if ((err_str
= time_string_to_nstime(time2_text
, &ot2
, &nt2
)) != NULL
)
395 nstime_copy(&dot
, &ot2
);
396 nstime_subtract(&dot
, &ot1
);
398 nstime_copy(&dnt
, &nt2
);
399 nstime_subtract(&dnt
, &nt1
);
401 /* Up to here nothing is changed */
402 if (!frame_data_sequence_find(cf
->provider
.frames
, 1))
403 return "No frames found."; /* Shouldn't happen */
405 for (i
= 1; i
<= cf
->count
; i
++) {
406 if ((fd
= frame_data_sequence_find(cf
->provider
.frames
, i
)) == NULL
)
407 continue; /* Shouldn't happen */
409 /* Set everything back to the original time */
410 nstime_subtract(&(fd
->abs_ts
), &(fd
->shift_offset
));
411 nstime_set_zero(&(fd
->shift_offset
));
413 /* Add the difference to each packet */
414 calcNT3(&ot1
, &(fd
->abs_ts
), &nt1
, &nt3
, &dot
, &dnt
);
416 nstime_copy(&d3t
, &nt3
);
417 nstime_subtract(&d3t
, &(fd
->abs_ts
));
419 modify_time_perform(fd
, SHIFT_POS
, &d3t
, SHIFT_SETTOZERO
);
422 cf
->unsaved_changes
= true;
423 packet_list_queue_draw();
428 time_shift_undo(capture_file
*cf
)
435 return "Nothing to work with.";
437 nulltime
.secs
= nulltime
.nsecs
= 0;
439 if (!frame_data_sequence_find(cf
->provider
.frames
, 1))
440 return "No frames found."; /* Shouldn't happen */
442 for (i
= 1; i
<= cf
->count
; i
++) {
443 if ((fd
= frame_data_sequence_find(cf
->provider
.frames
, i
)) == NULL
)
444 continue; /* Shouldn't happen */
445 modify_time_perform(fd
, SHIFT_NEG
, &nulltime
, SHIFT_SETTOZERO
);
447 packet_list_queue_draw();