If the user enables gtk3, (silently) disable gtk2 rather than forcing the user
[metze/wireshark/wip.git] / editcap.c
1 /* Edit capture files.  We can delete packets, adjust timestamps, or
2  * simply convert from one format to another format.
3  *
4  * Originally written by Richard Sharpe.
5  * Improved by Guy Harris.
6  * Further improved by Richard Sharpe.
7  *
8  * Copyright 2013, Richard Sharpe <realrichardsharpe[AT]gmail.com>
9  *
10  * $Id$
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, write to the Free Software Foundation, Inc.,
28  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29  */
30
31 #include "config.h"
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdarg.h>
37
38 /*
39  * Just make sure we include the prototype for strptime as well
40  * (needed for glibc 2.2) but make sure we do this only if not
41  * yet defined.
42  */
43
44 #ifndef __USE_XOPEN
45 #  define __USE_XOPEN
46 #endif
47
48 #include <time.h>
49 #include <glib.h>
50
51 #ifdef HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54
55 #ifdef HAVE_SYS_TIME_H
56 #include <sys/time.h>
57 #endif
58
59 #include "wtap.h"
60
61 #ifndef HAVE_GETOPT
62 #include "wsutil/wsgetopt.h"
63 #endif
64
65 #ifdef _WIN32
66 #include <wsutil/file_util.h>
67 #include <wsutil/unicode-utils.h>
68 #include <process.h>    /* getpid */
69 #ifdef HAVE_WINSOCK2_H
70 #include <winsock2.h>
71 #endif
72 #endif
73
74 #ifdef NEED_STRPTIME_H
75 # include "wsutil/strptime.h"
76 #endif
77
78 #include <wsutil/privileges.h>
79
80 /*
81  * The symbols declared in the below are exported from libwireshark,
82  * but we don't want to link whole libwireshark to editcap.
83  * We link the object directly instead and this needs a little trick
84  * with the WS_BUILD_DLL #define.
85  */
86 #define WS_BUILD_DLL
87 #define RESET_SYMBOL_EXPORT /* wsutil/wsgetopt.h set export behavior above. */
88 #include "epan/crypt/md5.h"
89 #include "epan/plugins.h"
90 #include "epan/report_err.h"
91 #include "epan/filesystem.h"
92 #include "wsutil/nstime.h"
93 #undef WS_BUILD_DLL
94 #define RESET_SYMBOL_EXPORT
95
96 #include "svnversion.h"
97
98 #include "ringbuffer.h" /* For RINGBUFFER_MAX_NUM_FILES */
99
100 /*
101  * Some globals so we can pass things to various routines
102  */
103
104 struct select_item {
105
106   int inclusive;
107   int first, second;
108
109 };
110
111
112 /*
113  * Duplicate frame detection
114  */
115 typedef struct _fd_hash_t {
116   md5_byte_t digest[16];
117   guint32 len;
118   nstime_t time;
119 } fd_hash_t;
120
121 #define DEFAULT_DUP_DEPTH 5     /* Used with -d */
122 #define MAX_DUP_DEPTH 1000000   /* the maximum window (and actual size of fd_hash[]) for de-duplication */
123
124 fd_hash_t fd_hash[MAX_DUP_DEPTH];
125 int dup_window = DEFAULT_DUP_DEPTH;
126 int cur_dup_entry = 0;
127
128 #define ONE_MILLION 1000000
129 #define ONE_BILLION 1000000000
130
131 /* Weights of different errors we can introduce */
132 /* We should probably make these command-line arguments */
133 /* XXX - Should we add a bit-level error? */
134 #define ERR_WT_BIT   5  /* Flip a random bit */
135 #define ERR_WT_BYTE  5  /* Substitute a random byte */
136 #define ERR_WT_ALNUM 5  /* Substitute a random character in [A-Za-z0-9] */
137 #define ERR_WT_FMT   2  /* Substitute "%s" */
138 #define ERR_WT_AA    1  /* Fill the remainder of the buffer with 0xAA */
139 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
140
141 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
142 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
143
144
145 struct time_adjustment {
146   struct timeval tv;
147   int is_negative;
148 };
149
150 #define MAX_SELECTIONS 512
151 static struct select_item selectfrm[MAX_SELECTIONS];
152 static int max_selected = -1;
153 static int keep_em = 0;
154 #ifdef PCAP_NG_DEFAULT
155 static int out_file_type = WTAP_FILE_PCAPNG; /* default to pcapng   */
156 #else
157 static int out_file_type = WTAP_FILE_PCAP;   /* default to pcap     */
158 #endif
159 static int out_frame_type = -2;              /* Leave frame type alone */
160 static int verbose = 0;                      /* Not so verbose         */
161 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
162 static nstime_t relative_time_window = {0, 0}; /* de-dup time window */
163 static double err_prob = 0.0;
164 static time_t starttime = 0;
165 static time_t stoptime = 0;
166 static gboolean check_startstop = FALSE;
167 static gboolean dup_detect = FALSE;
168 static gboolean dup_detect_by_time = FALSE;
169
170 static int do_strict_time_adjustment = FALSE;
171 static struct time_adjustment strict_time_adj = {{0, 0}, 0}; /* strict time adjustment */
172 static nstime_t previous_time = {0, 0}; /* previous time */
173
174 static int find_dct2000_real_data(guint8 *buf);
175
176 static gchar *
177 abs_time_to_str_with_sec_resolution(const struct wtap_nstime *abs_time)
178 {
179     struct tm *tmp;
180     gchar *buf = (gchar *)g_malloc(16);
181
182 #if (defined _WIN32) && (_MSC_VER < 1500)
183     /* calling localtime() on MSVC 2005 with huge values causes it to crash */
184     /* XXX - find the exact value that still does work */
185     /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
186     if(abs_time->secs > 2000000000) {
187         tmp = NULL;
188     } else
189 #endif
190     tmp = localtime(&abs_time->secs);
191     if (tmp) {
192         g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
193             tmp->tm_year + 1900,
194             tmp->tm_mon+1,
195             tmp->tm_mday,
196             tmp->tm_hour,
197             tmp->tm_min,
198             tmp->tm_sec);
199     } else
200         buf[0] = '\0';
201
202     return buf;
203 }
204
205 static gchar*
206 fileset_get_filename_by_pattern(guint idx,    const struct wtap_nstime *time_val,
207                                 gchar *fprefix, gchar *fsuffix)
208 {
209     gchar filenum[5+1];
210     gchar *timestr;
211     gchar *abs_str;
212
213     timestr = abs_time_to_str_with_sec_resolution(time_val);
214     g_snprintf(filenum, sizeof(filenum), "%05u", idx % RINGBUFFER_MAX_NUM_FILES);
215     abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
216     g_free(timestr);
217
218     return abs_str;
219 }
220
221 static gboolean
222 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
223 {
224     char  *pfx, *last_pathsep;
225     gchar *save_file;
226
227     save_file = g_strdup(fname);
228     if (save_file == NULL) {
229       fprintf(stderr, "editcap: Out of memory\n");
230       return FALSE;
231     }
232
233     last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
234     pfx = strrchr(save_file,'.');
235     if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
236       /* The pathname has a "." in it, and it's in the last component
237          of the pathname (because there is either only one component,
238          i.e. last_pathsep is null as there are no path separators,
239          or the "." is after the path separator before the last
240          component.
241
242          Treat it as a separator between the rest of the file name and
243          the file name suffix, and arrange that the names given to the
244          ring buffer files have the specified suffix, i.e. put the
245          changing part of the name *before* the suffix. */
246       pfx[0] = '\0';
247       *fprefix = g_strdup(save_file);
248       pfx[0] = '.'; /* restore capfile_name */
249       *fsuffix = g_strdup(pfx);
250     } else {
251       /* Either there's no "." in the pathname, or it's in a directory
252          component, so the last component has no suffix. */
253       *fprefix = g_strdup(save_file);
254       *fsuffix = NULL;
255     }
256     g_free(save_file);
257     return TRUE;
258 }
259
260 /* Add a selection item, a simple parser for now */
261 static gboolean
262 add_selection(char *sel)
263 {
264   char *locn;
265   char *next;
266
267   if (++max_selected >= MAX_SELECTIONS) {
268     /* Let the user know we stopped selecting */
269     printf("Out of room for packet selections!\n");
270     return(FALSE);
271   }
272
273   printf("Add_Selected: %s\n", sel);
274
275   if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
276
277     printf("Not inclusive ...");
278
279     selectfrm[max_selected].inclusive = 0;
280     selectfrm[max_selected].first = atoi(sel);
281
282     printf(" %i\n", selectfrm[max_selected].first);
283
284   }
285   else {
286
287     printf("Inclusive ...");
288
289     next = locn + 1;
290     selectfrm[max_selected].inclusive = 1;
291     selectfrm[max_selected].first = atoi(sel);
292     selectfrm[max_selected].second = atoi(next);
293
294     printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
295
296   }
297
298   return(TRUE);
299 }
300
301 /* Was the packet selected? */
302
303 static int
304 selected(int recno)
305 {
306   int i = 0;
307
308   for (i = 0; i<= max_selected; i++) {
309
310     if (selectfrm[i].inclusive) {
311       if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
312         return 1;
313     }
314     else {
315       if (recno == selectfrm[i].first)
316         return 1;
317     }
318   }
319
320   return 0;
321
322 }
323
324 /* is the packet in the selected timeframe */
325 static gboolean
326 check_timestamp(wtap *wth)
327 {
328   struct wtap_pkthdr* pkthdr = wtap_phdr(wth);
329
330   return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs < stoptime );
331 }
332
333 static void
334 set_time_adjustment(char *optarg_str_p)
335 {
336   char *frac, *end;
337   long val;
338   size_t frac_digits;
339
340   if (!optarg_str_p)
341     return;
342
343   /* skip leading whitespace */
344   while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
345       optarg_str_p++;
346   }
347
348   /* check for a negative adjustment */
349   if (*optarg_str_p == '-') {
350       time_adj.is_negative = 1;
351       optarg_str_p++;
352   }
353
354   /* collect whole number of seconds, if any */
355   if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
356       val  = 0;
357       frac = optarg_str_p;
358   } else {
359       val = strtol(optarg_str_p, &frac, 10);
360       if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
361           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
362                   optarg_str_p);
363           exit(1);
364       }
365       if (val < 0) {            /* implies '--' since we caught '-' above  */
366           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
367                   optarg_str_p);
368           exit(1);
369       }
370   }
371   time_adj.tv.tv_sec = val;
372
373   /* now collect the partial seconds, if any */
374   if (*frac != '\0') {             /* chars left, so get fractional part */
375     val = strtol(&(frac[1]), &end, 10);
376     /* if more than 6 fractional digits truncate to 6 */
377     if((end - &(frac[1])) > 6) {
378         frac[7] = 't'; /* 't' for truncate */
379         val = strtol(&(frac[1]), &end, 10);
380     }
381     if (*frac != '.' || end == NULL || end == frac
382         || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
383       fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
384               optarg_str_p);
385       exit(1);
386     }
387   }
388   else {
389     return;                     /* no fractional digits */
390   }
391
392   /* adjust fractional portion from fractional to numerator
393    * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
394   if (frac && end) {            /* both are valid */
395     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
396     while(frac_digits < 6) {    /* this is frac of 10^6 */
397       val *= 10;
398       frac_digits++;
399     }
400   }
401   time_adj.tv.tv_usec = (int)val;
402 }
403
404 static void
405 set_strict_time_adj(char *optarg_str_p)
406 {
407   char *frac, *end;
408   long val;
409   size_t frac_digits;
410
411   if (!optarg_str_p)
412     return;
413
414   /* skip leading whitespace */
415   while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
416       optarg_str_p++;
417   }
418
419   /*
420    * check for a negative adjustment
421    * A negative strict adjustment value is a flag
422    * to adjust all frames by the specifed delta time.
423    */
424   if (*optarg_str_p == '-') {
425       strict_time_adj.is_negative = 1;
426       optarg_str_p++;
427   }
428
429   /* collect whole number of seconds, if any */
430   if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
431       val  = 0;
432       frac = optarg_str_p;
433   } else {
434       val = strtol(optarg_str_p, &frac, 10);
435       if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
436           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
437                   optarg_str_p);
438           exit(1);
439       }
440       if (val < 0) {            /* implies '--' since we caught '-' above  */
441           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
442                   optarg_str_p);
443           exit(1);
444       }
445   }
446   strict_time_adj.tv.tv_sec = val;
447
448   /* now collect the partial seconds, if any */
449   if (*frac != '\0') {             /* chars left, so get fractional part */
450     val = strtol(&(frac[1]), &end, 10);
451     /* if more than 6 fractional digits truncate to 6 */
452     if((end - &(frac[1])) > 6) {
453         frac[7] = 't'; /* 't' for truncate */
454         val = strtol(&(frac[1]), &end, 10);
455     }
456     if (*frac != '.' || end == NULL || end == frac
457         || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
458       fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
459               optarg_str_p);
460       exit(1);
461     }
462   }
463   else {
464     return;                     /* no fractional digits */
465   }
466
467   /* adjust fractional portion from fractional to numerator
468    * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
469   if (frac && end) {            /* both are valid */
470     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
471     while(frac_digits < 6) {    /* this is frac of 10^6 */
472       val *= 10;
473       frac_digits++;
474     }
475   }
476   strict_time_adj.tv.tv_usec = (int)val;
477 }
478
479 static void
480 set_rel_time(char *optarg_str_p)
481 {
482   char *frac, *end;
483   long val;
484   size_t frac_digits;
485
486   if (!optarg_str_p)
487     return;
488
489   /* skip leading whitespace */
490   while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
491       optarg_str_p++;
492   }
493
494   /* ignore negative adjustment  */
495   if (*optarg_str_p == '-') {
496       optarg_str_p++;
497   }
498
499   /* collect whole number of seconds, if any */
500   if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
501       val  = 0;
502       frac = optarg_str_p;
503   } else {
504       val = strtol(optarg_str_p, &frac, 10);
505       if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
506           fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
507                   optarg_str_p);
508           exit(1);
509       }
510       if (val < 0) {            /* implies '--' since we caught '-' above  */
511           fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
512                   optarg_str_p);
513           exit(1);
514       }
515   }
516   relative_time_window.secs = val;
517
518   /* now collect the partial seconds, if any */
519   if (*frac != '\0') {             /* chars left, so get fractional part */
520     val = strtol(&(frac[1]), &end, 10);
521     /* if more than 9 fractional digits truncate to 9 */
522     if((end - &(frac[1])) > 9) {
523         frac[10] = 't'; /* 't' for truncate */
524         val = strtol(&(frac[1]), &end, 10);
525     }
526     if (*frac != '.' || end == NULL || end == frac
527         || val < 0 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
528       fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
529               optarg_str_p);
530       exit(1);
531     }
532   }
533   else {
534     return;                     /* no fractional digits */
535   }
536
537   /* adjust fractional portion from fractional to numerator
538    * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
539   if (frac && end) {            /* both are valid */
540     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
541     while(frac_digits < 9) {    /* this is frac of 10^9 */
542       val *= 10;
543       frac_digits++;
544     }
545   }
546   relative_time_window.nsecs = (int)val;
547 }
548
549 static gboolean
550 is_duplicate(guint8* fd, guint32 len) {
551   int i;
552   md5_state_t ms;
553
554   cur_dup_entry++;
555   if (cur_dup_entry >= dup_window)
556     cur_dup_entry = 0;
557
558   /* Calculate our digest */
559   md5_init(&ms);
560   md5_append(&ms, fd, len);
561   md5_finish(&ms, fd_hash[cur_dup_entry].digest);
562
563   fd_hash[cur_dup_entry].len = len;
564
565   /* Look for duplicates */
566   for (i = 0; i < dup_window; i++) {
567     if (i == cur_dup_entry)
568       continue;
569
570     if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
571         memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
572       return TRUE;
573     }
574   }
575
576   return FALSE;
577 }
578
579 static gboolean
580 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
581   int i;
582   md5_state_t ms;
583
584   cur_dup_entry++;
585   if (cur_dup_entry >= dup_window)
586     cur_dup_entry = 0;
587
588   /* Calculate our digest */
589   md5_init(&ms);
590   md5_append(&ms, fd, len);
591   md5_finish(&ms, fd_hash[cur_dup_entry].digest);
592
593   fd_hash[cur_dup_entry].len = len;
594   fd_hash[cur_dup_entry].time.secs = current->secs;
595   fd_hash[cur_dup_entry].time.nsecs = current->nsecs;
596
597   /*
598    * Look for relative time related duplicates.
599    * This is hopefully a reasonably efficient mechanism for
600    * finding duplicates by rel time in the fd_hash[] cache.
601    * We check starting from the most recently added hash
602    * entries and work backwards towards older packets.
603    * This approach allows the dup test to be terminated
604    * when the relative time of a cached entry is found to
605    * be beyond the dup time window.
606    *
607    * Of course this assumes that the input trace file is
608    * "well-formed" in the sense that the packet timestamps are
609    * in strict chronologically increasing order (which is NOT
610    * always the case!!).
611    *
612    * The fd_hash[] table was deliberatly created large (1,000,000).
613    * Looking for time related duplicates in large trace files with
614    * non-fractional dup time window values can potentially take
615    * a long time to complete.
616    */
617
618   for (i = cur_dup_entry - 1;; i--) {
619     nstime_t delta;
620     int cmp;
621
622     if (i < 0) {
623       i = dup_window - 1;
624     }
625
626     if (i == cur_dup_entry) {
627       /*
628        * We've decremented back to where we started.
629        * Check no more!
630        */
631       break;
632     }
633
634     if (nstime_is_unset(&(fd_hash[i].time))) {
635       /*
636        * We've decremented to an unused fd_hash[] entry.
637        * Check no more!
638        */
639       break;
640     }
641
642     nstime_delta(&delta, current, &fd_hash[i].time);
643
644     if(delta.secs < 0 || delta.nsecs < 0)
645     {
646       /*
647        * A negative delta implies that the current packet
648        * has an absolute timestamp less than the cached packet
649        * that it is being compared to.  This is NOT a normal
650        * situation since trace files usually have packets in
651        * chronological order (oldest to newest).
652        *
653        * There are several possible ways to deal with this:
654        * 1. 'continue' dup checking with the next cached frame.
655        * 2. 'break' from looking for a duplicate of the current frame.
656        * 3. Take the absolute value of the delta and see if that
657        * falls within the specifed dup time window.
658        *
659        * Currently this code does option 1.  But it would pretty
660        * easy to add yet-another-editcap-option to select one of
661        * the other behaviors for dealing with out-of-sequence
662        * packets.
663        */
664       continue;
665     }
666
667     cmp = nstime_cmp(&delta, &relative_time_window);
668
669     if(cmp > 0) {
670       /*
671        * The delta time indicates that we are now looking at
672        * cached packets beyond the specified dup time window.
673        * Check no more!
674        */
675       break;
676     } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
677           memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
678       return TRUE;
679     }
680   }
681
682   return FALSE;
683 }
684
685 static void
686 usage(gboolean is_error)
687 {
688   FILE *output;
689
690   if (!is_error)
691     output = stdout;
692   else
693     output = stderr;
694
695   fprintf(output, "Editcap %s"
696 #ifdef SVNVERSION
697     " (" SVNVERSION " from " SVNPATH ")"
698 #endif
699     "\n", VERSION);
700   fprintf(output, "Edit and/or translate the format of capture files.\n");
701   fprintf(output, "See http://www.wireshark.org for more information.\n");
702   fprintf(output, "\n");
703   fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
704   fprintf(output, "\n");
705   fprintf(output, "<infile> and <outfile> must both be present.\n");
706   fprintf(output, "A single packet or a range of packets can be selected.\n");
707   fprintf(output, "\n");
708   fprintf(output, "Packet selection:\n");
709   fprintf(output, "  -r                     keep the selected packets; default is to delete them.\n");
710   fprintf(output, "  -A <start time>        only output packets whose timestamp is after (or equal\n");
711   fprintf(output, "                         to) the given time (format as YYYY-MM-DD hh:mm:ss).\n");
712   fprintf(output, "  -B <stop time>         only output packets whose timestamp is before the\n");
713   fprintf(output, "                         given time (format as YYYY-MM-DD hh:mm:ss).\n");
714   fprintf(output, "\n");
715   fprintf(output, "Duplicate packet removal:\n");
716   fprintf(output, "  -d                     remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
717   fprintf(output, "  -D <dup window>        remove packet if duplicate; configurable <dup window>\n");
718   fprintf(output, "                         Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
719   fprintf(output, "                         NOTE: A <dup window> of 0 with -v (verbose option) is\n");
720   fprintf(output, "                         useful to print MD5 hashes.\n");
721   fprintf(output, "  -w <dup time window>   remove packet if duplicate packet is found EQUAL TO OR\n");
722   fprintf(output, "                         LESS THAN <dup time window> prior to current packet.\n");
723   fprintf(output, "                         A <dup time window> is specified in relative seconds\n");
724   fprintf(output, "                         (e.g. 0.000001).\n");
725   fprintf(output, "\n");
726   fprintf(output, "           NOTE: The use of the 'Duplicate packet removal' options with\n");
727   fprintf(output, "           other editcap options except -v may not always work as expected.\n");
728   fprintf(output, "           Specifically the -r, -t or -S options will very likely NOT have the\n");
729   fprintf(output, "           desired effect if combined with the -d, -D or -w.\n");
730   fprintf(output, "\n");
731   fprintf(output, "Packet manipulation:\n");
732   fprintf(output, "  -s <snaplen>           truncate each packet to max. <snaplen> bytes of data.\n");
733   fprintf(output, "  -C <choplen>           chop each packet by <choplen> bytes. Positive values\n");
734   fprintf(output, "                         chop at the packet beginning, negative values at the\n");
735   fprintf(output, "                         packet end.\n");
736   fprintf(output, "  -t <time adjustment>   adjust the timestamp of each packet;\n");
737   fprintf(output, "                         <time adjustment> is in relative seconds (e.g. -0.5).\n");
738   fprintf(output, "  -S <strict adjustment> adjust timestamp of packets if necessary to insure\n");
739   fprintf(output, "                         strict chronological increasing order. The <strict\n");
740   fprintf(output, "                         adjustment> is specified in relative seconds with\n");
741   fprintf(output, "                         values of 0 or 0.000001 being the most reasonable.\n");
742   fprintf(output, "                         A negative adjustment value will modify timestamps so\n");
743   fprintf(output, "                         that each packet's delta time is the absolute value\n");
744   fprintf(output, "                         of the adjustment specified. A value of -0 will set\n");
745   fprintf(output, "                         all packets to the timestamp of the first packet.\n");
746   fprintf(output, "  -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
747   fprintf(output, "                         that a particular packet byte will be randomly changed.\n");
748   fprintf(output, "\n");
749   fprintf(output, "Output File(s):\n");
750   fprintf(output, "  -c <packets per file>  split the packet output to different files\n");
751   fprintf(output, "                         based on uniform packet counts\n");
752   fprintf(output, "                         with a maximum of <packets per file> each.\n");
753   fprintf(output, "  -i <seconds per file>  split the packet output to different files\n");
754   fprintf(output, "                         based on uniform time intervals\n");
755   fprintf(output, "                         with a maximum of <seconds per file> each.\n");
756   fprintf(output, "  -F <capture type>      set the output file type; default is pcapng.\n");
757   fprintf(output, "                         an empty \"-F\" option will list the file types.\n");
758   fprintf(output, "  -T <encap type>        set the output file encapsulation type;\n");
759   fprintf(output, "                         default is the same as the input file.\n");
760   fprintf(output, "                         an empty \"-T\" option will list the encapsulation types.\n");
761   fprintf(output, "\n");
762   fprintf(output, "Miscellaneous:\n");
763   fprintf(output, "  -h                     display this help and exit.\n");
764   fprintf(output, "  -v                     verbose output.\n");
765   fprintf(output, "                         If -v is used with any of the 'Duplicate Packet\n");
766   fprintf(output, "                         Removal' options (-d, -D or -w) then Packet lengths\n");
767   fprintf(output, "                         and MD5 hashes are printed to standard-out.\n");
768   fprintf(output, "\n");
769 }
770
771 struct string_elem {
772     const char *sstr;   /* The short string */
773     const char *lstr;   /* The long string */
774 };
775
776 static gint
777 string_compare(gconstpointer a, gconstpointer b)
778 {
779     return strcmp(((const struct string_elem *)a)->sstr,
780         ((const struct string_elem *)b)->sstr);
781 }
782
783 static void
784 string_elem_print(gpointer data, gpointer not_used _U_)
785 {
786     fprintf(stderr, "    %s - %s\n",
787         ((struct string_elem *)data)->sstr,
788         ((struct string_elem *)data)->lstr);
789 }
790
791 static void
792 list_capture_types(void) {
793     int i;
794     struct string_elem *captypes;
795     GSList *list = NULL;
796
797     captypes = g_new(struct string_elem,WTAP_NUM_FILE_TYPES);
798     fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
799     for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
800       if (wtap_dump_can_open(i)) {
801         captypes[i].sstr = wtap_file_type_short_string(i);
802         captypes[i].lstr = wtap_file_type_string(i);
803         list = g_slist_insert_sorted(list, &captypes[i], string_compare);
804       }
805     }
806     g_slist_foreach(list, string_elem_print, NULL);
807     g_slist_free(list);
808     g_free(captypes);
809 }
810
811 static void
812 list_encap_types(void) {
813     int i;
814     struct string_elem *encaps;
815     GSList *list = NULL;
816
817     encaps = (struct string_elem *)g_malloc(sizeof(struct string_elem) * WTAP_NUM_ENCAP_TYPES);
818     fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
819     for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
820         encaps[i].sstr = wtap_encap_short_string(i);
821         if (encaps[i].sstr != NULL) {
822             encaps[i].lstr = wtap_encap_string(i);
823             list = g_slist_insert_sorted(list, &encaps[i], string_compare);
824         }
825     }
826     g_slist_foreach(list, string_elem_print, NULL);
827     g_slist_free(list);
828     g_free(encaps);
829 }
830
831 #ifdef HAVE_PLUGINS
832 /*
833  *  Don't report failures to load plugins because most (non-wiretap) plugins
834  *  *should* fail to load (because we're not linked against libwireshark and
835  *  dissector plugins need libwireshark).
836  */
837 static void
838 failure_message(const char *msg_format _U_, va_list ap _U_)
839 {
840     return;
841 }
842 #endif
843
844 int
845 main(int argc, char *argv[])
846 {
847   wtap *wth;
848   int i, j, err;
849   gchar *err_info;
850   int opt;
851
852   char *p;
853   guint32 snaplen = 0;                  /* No limit               */
854   int choplen = 0;                      /* No chop                */
855   wtap_dumper *pdh = NULL;
856   unsigned int count = 1;
857   unsigned int duplicate_count = 0;
858   gint64 data_offset;
859   struct wtap_pkthdr snap_phdr;
860   const struct wtap_pkthdr *phdr;
861   int err_type;
862   wtapng_section_t *shb_hdr;
863   wtapng_iface_descriptions_t *idb_inf;
864   guint8 *buf;
865   guint32 read_count = 0;
866   int split_packet_count = 0;
867   int written_count = 0;
868   char *filename = NULL;
869   gboolean ts_okay = TRUE;
870   int secs_per_block = 0;
871   int block_cnt = 0;
872   nstime_t block_start;
873   gchar *fprefix = NULL;
874   gchar *fsuffix = NULL;
875   char appname[100];
876
877 #ifdef HAVE_PLUGINS
878   char* init_progfile_dir_error;
879 #endif
880
881 #ifdef _WIN32
882   arg_list_utf_16to8(argc, argv);
883   create_app_running_mutex();
884 #endif /* _WIN32 */
885
886   /*
887    * Get credential information for later use.
888    */
889   init_process_policies();
890
891 #ifdef HAVE_PLUGINS
892   /* Register wiretap plugins */
893   if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
894     g_warning("editcap: init_progfile_dir(): %s", init_progfile_dir_error);
895     g_free(init_progfile_dir_error);
896   } else {
897     init_report_err(failure_message,NULL,NULL,NULL);
898     init_plugins();
899   }
900 #endif
901
902   /* Process the options */
903   while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:S:T:vw:")) !=-1) {
904
905     switch (opt) {
906
907     case 'E':
908       err_prob = strtod(optarg, &p);
909       if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
910         fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
911             optarg);
912         exit(1);
913       }
914       srand( (unsigned int) (time(NULL) + getpid()) );
915       break;
916
917     case 'F':
918       out_file_type = wtap_short_string_to_file_type(optarg);
919       if (out_file_type < 0) {
920         fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
921             optarg);
922         list_capture_types();
923         exit(1);
924       }
925       break;
926
927     case 'c':
928       split_packet_count = (int)strtol(optarg, &p, 10);
929       if (p == optarg || *p != '\0') {
930         fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
931             optarg);
932         exit(1);
933       }
934       if (split_packet_count <= 0) {
935         fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
936             split_packet_count);
937         exit(1);
938       }
939       break;
940
941     case 'C':
942       choplen = (int)strtol(optarg, &p, 10);
943       if (p == optarg || *p != '\0') {
944         fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
945             optarg);
946         exit(1);
947       }
948       break;
949
950     case 'd':
951       dup_detect = TRUE;
952       dup_detect_by_time = FALSE;
953       dup_window = DEFAULT_DUP_DEPTH;
954       break;
955
956     case 'D':
957       dup_detect = TRUE;
958       dup_detect_by_time = FALSE;
959       dup_window = (int)strtol(optarg, &p, 10);
960       if (p == optarg || *p != '\0') {
961         fprintf(stderr, "editcap: \"%s\" isn't a valid duplicate window value\n",
962             optarg);
963         exit(1);
964       }
965       if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
966         fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
967             dup_window, MAX_DUP_DEPTH);
968         exit(1);
969       }
970       break;
971
972     case 'w':
973       dup_detect = FALSE;
974       dup_detect_by_time = TRUE;
975       dup_window = MAX_DUP_DEPTH;
976       set_rel_time(optarg);
977       break;
978
979     case '?':              /* Bad options if GNU getopt */
980       switch(optopt) {
981       case'F':
982         list_capture_types();
983         break;
984       case'T':
985         list_encap_types();
986         break;
987       default:
988         usage(TRUE);
989       }
990       exit(1);
991       break;
992
993     case 'h':
994       usage(FALSE);
995       exit(1);
996       break;
997
998     case 'r':
999       keep_em = !keep_em;  /* Just invert */
1000       break;
1001
1002     case 's':
1003       snaplen = (guint32)strtol(optarg, &p, 10);
1004       if (p == optarg || *p != '\0') {
1005         fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
1006                 optarg);
1007         exit(1);
1008       }
1009       break;
1010
1011     case 't':
1012       set_time_adjustment(optarg);
1013       break;
1014
1015     case 'S':
1016       set_strict_time_adj(optarg);
1017       do_strict_time_adjustment = TRUE;
1018       break;
1019
1020     case 'T':
1021       out_frame_type = wtap_short_string_to_encap(optarg);
1022       if (out_frame_type < 0) {
1023         fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
1024           optarg);
1025         list_encap_types();
1026         exit(1);
1027       }
1028       break;
1029
1030     case 'v':
1031       verbose = !verbose;  /* Just invert */
1032       break;
1033
1034     case 'i': /* break capture file based on time interval */
1035       secs_per_block = atoi(optarg);
1036       if(secs_per_block <= 0) {
1037         fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
1038         exit(1);
1039         }
1040       break;
1041
1042     case 'A':
1043     {
1044       struct tm starttm;
1045
1046       memset(&starttm,0,sizeof(struct tm));
1047
1048       if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
1049         fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1050         exit(1);
1051       }
1052
1053       check_startstop = TRUE;
1054       starttm.tm_isdst = -1;
1055
1056       starttime = mktime(&starttm);
1057       break;
1058     }
1059
1060     case 'B':
1061     {
1062       struct tm stoptm;
1063
1064       memset(&stoptm,0,sizeof(struct tm));
1065
1066       if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
1067         fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1068         exit(1);
1069       }
1070       check_startstop = TRUE;
1071       stoptm.tm_isdst = -1;
1072       stoptime = mktime(&stoptm);
1073       break;
1074     }
1075     }
1076
1077   }
1078
1079 #ifdef DEBUG
1080   printf("Optind = %i, argc = %i\n", optind, argc);
1081 #endif
1082
1083   if ((argc - optind) < 1) {
1084
1085     usage(TRUE);
1086     exit(1);
1087
1088   }
1089
1090   if (check_startstop && !stoptime) {
1091     struct tm stoptm;
1092     /* XXX: will work until 2035 */
1093     memset(&stoptm,0,sizeof(struct tm));
1094     stoptm.tm_year = 135;
1095     stoptm.tm_mday = 31;
1096     stoptm.tm_mon = 11;
1097
1098     stoptime = mktime(&stoptm);
1099   }
1100
1101   nstime_set_unset(&block_start);
1102
1103   if (starttime > stoptime) {
1104     fprintf(stderr, "editcap: start time is after the stop time\n");
1105     exit(1);
1106   }
1107
1108   if (split_packet_count > 0 && secs_per_block > 0) {
1109     fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1110     fprintf(stderr, "editcap: at the same time\n");
1111     exit(1);
1112   }
1113
1114   wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
1115
1116   if (!wth) {
1117     fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
1118         wtap_strerror(err));
1119     switch (err) {
1120
1121     case WTAP_ERR_UNSUPPORTED:
1122     case WTAP_ERR_UNSUPPORTED_ENCAP:
1123     case WTAP_ERR_BAD_FILE:
1124       fprintf(stderr, "(%s)\n", err_info);
1125       g_free(err_info);
1126       break;
1127     }
1128     exit(2);
1129
1130   }
1131
1132   if (verbose) {
1133     fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1134             wtap_file_type_string(wtap_file_type(wth)));
1135   }
1136
1137   shb_hdr = wtap_file_get_shb_info(wth);
1138   idb_inf = wtap_file_get_idb_info(wth);
1139
1140   /*
1141    * Now, process the rest, if any ... we only write if there is an extra
1142    * argument or so ...
1143    */
1144
1145   if ((argc - optind) >= 2) {
1146
1147     if (out_frame_type == -2)
1148       out_frame_type = wtap_file_encap(wth);
1149
1150     for (i = optind + 2; i < argc; i++)
1151       if (add_selection(argv[i]) == FALSE)
1152         break;
1153
1154     if (dup_detect || dup_detect_by_time) {
1155       for (i = 0; i < dup_window; i++) {
1156         memset(&fd_hash[i].digest, 0, 16);
1157         fd_hash[i].len = 0;
1158         nstime_set_unset(&fd_hash[i].time);
1159       }
1160     }
1161
1162     while (wtap_read(wth, &err, &err_info, &data_offset)) {
1163       read_count++;
1164
1165       phdr = wtap_phdr(wth);
1166       buf = wtap_buf_ptr(wth);
1167
1168       if (nstime_is_unset(&block_start)) {  /* should only be the first packet */
1169         block_start.secs = phdr->ts.secs;
1170         block_start.nsecs = phdr->ts.nsecs;
1171
1172         if (split_packet_count > 0 || secs_per_block > 0) {
1173           if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
1174               exit(2);
1175
1176           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1177         } else
1178           filename = g_strdup(argv[optind+1]);
1179
1180         /* If we don't have an application name add Editcap */
1181         if(shb_hdr->shb_user_appl == NULL) {
1182           g_snprintf(appname, sizeof(appname), "Editcap " VERSION);
1183           shb_hdr->shb_user_appl = appname;
1184         }
1185
1186         pdh = wtap_dump_open_ng(filename, out_file_type, out_frame_type,
1187           snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1188           FALSE /* compressed */, shb_hdr, idb_inf, &err);
1189
1190         if (pdh == NULL) {
1191           fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1192                   wtap_strerror(err));
1193           exit(2);
1194         }
1195       }
1196
1197       g_assert(filename);
1198
1199       if (secs_per_block > 0) {
1200         while ((phdr->ts.secs - block_start.secs >  secs_per_block) ||
1201                (phdr->ts.secs - block_start.secs == secs_per_block &&
1202                 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1203
1204           if (!wtap_dump_close(pdh, &err)) {
1205             fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1206                 wtap_strerror(err));
1207             exit(2);
1208           }
1209           block_start.secs = block_start.secs +  secs_per_block; /* reset for next interval */
1210           g_free(filename);
1211           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1212           g_assert(filename);
1213
1214           if (verbose) {
1215             fprintf(stderr, "Continuing writing in file %s\n", filename);
1216           }
1217
1218           pdh = wtap_dump_open_ng(filename, out_file_type, out_frame_type,
1219             snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1220             FALSE /* compressed */, shb_hdr, idb_inf, &err);
1221
1222           if (pdh == NULL) {
1223             fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1224               wtap_strerror(err));
1225             exit(2);
1226           }
1227         }
1228       }
1229
1230       if (split_packet_count > 0) {
1231
1232         /* time for the next file? */
1233         if (written_count > 0 &&
1234             written_count % split_packet_count == 0) {
1235           if (!wtap_dump_close(pdh, &err)) {
1236             fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1237                 wtap_strerror(err));
1238             exit(2);
1239           }
1240
1241           g_free(filename);
1242           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1243           g_assert(filename);
1244
1245           if (verbose) {
1246             fprintf(stderr, "Continuing writing in file %s\n", filename);
1247           }
1248
1249           pdh = wtap_dump_open_ng(filename, out_file_type, out_frame_type,
1250             snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1251             FALSE /* compressed */, shb_hdr, idb_inf, &err);
1252           if (pdh == NULL) {
1253             fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1254                 wtap_strerror(err));
1255             exit(2);
1256           }
1257         }
1258       }
1259
1260       if (check_startstop)
1261         ts_okay = check_timestamp(wth);
1262
1263       if ( ts_okay && ((!selected(count) && !keep_em) || (selected(count) && keep_em)) ) {
1264
1265         if (verbose && !dup_detect && !dup_detect_by_time)
1266           printf("Packet: %u\n", count);
1267
1268         /* We simply write it, perhaps after truncating it; we could do other
1269            things, like modify it. */
1270
1271         phdr = wtap_phdr(wth);
1272
1273         if (snaplen != 0 && phdr->caplen > snaplen) {
1274           snap_phdr = *phdr;
1275           snap_phdr.caplen = snaplen;
1276           phdr = &snap_phdr;
1277         }
1278
1279         if (choplen < 0) {
1280           snap_phdr = *phdr;
1281           if (((signed int) phdr->caplen + choplen) > 0)
1282             snap_phdr.caplen += choplen;
1283           else
1284             snap_phdr.caplen = 0;
1285           phdr = &snap_phdr;
1286         } else if (choplen > 0) {
1287           snap_phdr = *phdr;
1288           if (phdr->caplen > (unsigned int) choplen) {
1289             snap_phdr.caplen -= choplen;
1290             buf += choplen;
1291           } else
1292             snap_phdr.caplen = 0;
1293           phdr = &snap_phdr;
1294         }
1295
1296         /*
1297          *  Do we adjust timestamps to insure strict chronologically order?
1298          */
1299
1300         if (do_strict_time_adjustment) {
1301           if (previous_time.secs || previous_time.nsecs) {
1302             if (!strict_time_adj.is_negative) {
1303               nstime_t current;
1304               nstime_t delta;
1305
1306               current.secs = phdr->ts.secs;
1307               current.nsecs = phdr->ts.nsecs;
1308
1309               nstime_delta(&delta, &current, &previous_time);
1310
1311               if (delta.secs < 0 || delta.nsecs < 0)
1312               {
1313                 /*
1314                  * A negative delta indicates that the current packet
1315                  * has an absolute timestamp less than the previous packet
1316                  * that it is being compared to.  This is NOT a normal
1317                  * situation since trace files usually have packets in
1318                  * chronological order (oldest to newest).
1319                  */
1320                 /* printf("++out of order, need to adjust this packet!\n"); */
1321                 snap_phdr = *phdr;
1322                 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1323                 snap_phdr.ts.nsecs = previous_time.nsecs;
1324                 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1325                   /* carry */
1326                   snap_phdr.ts.secs++;
1327                   snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1328                 } else {
1329                   snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1330                 }
1331                 phdr = &snap_phdr;
1332               }
1333             } else {
1334               /*
1335                * A negative strict time adjustment is requested.
1336                * Unconditionally set each timestamp to previous
1337                * packet's timestamp plus delta.
1338                */
1339               snap_phdr = *phdr;
1340               snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1341               snap_phdr.ts.nsecs = previous_time.nsecs;
1342               if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1343                 /* carry */
1344                 snap_phdr.ts.secs++;
1345                 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1346               } else {
1347                 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1348               }
1349               phdr = &snap_phdr;
1350             }
1351           }
1352           previous_time.secs = phdr->ts.secs;
1353           previous_time.nsecs = phdr->ts.nsecs;
1354         }
1355
1356         /* assume that if the frame's tv_sec is 0, then
1357          * the timestamp isn't supported */
1358         if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1359           snap_phdr = *phdr;
1360           if (time_adj.is_negative)
1361             snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1362           else
1363             snap_phdr.ts.secs += time_adj.tv.tv_sec;
1364           phdr = &snap_phdr;
1365         }
1366
1367         /* assume that if the frame's tv_sec is 0, then
1368          * the timestamp isn't supported */
1369         if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1370           snap_phdr = *phdr;
1371           if (time_adj.is_negative) { /* subtract */
1372             if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1373               snap_phdr.ts.secs--;
1374               snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1375             }
1376             snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1377           } else {                  /* add */
1378             if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1379               /* carry */
1380               snap_phdr.ts.secs++;
1381               snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1382             } else {
1383               snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1384             }
1385           }
1386           phdr = &snap_phdr;
1387         }
1388
1389         /* suppress duplicates by packet window */
1390         if (dup_detect) {
1391           if (is_duplicate(buf, phdr->caplen)) {
1392             if (verbose) {
1393               fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1394               for (i = 0; i < 16; i++) {
1395                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1396               }
1397               fprintf(stdout, "\n");
1398             }
1399             duplicate_count++;
1400             count++;
1401             continue;
1402           } else {
1403             if (verbose) {
1404               fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1405               for (i = 0; i < 16; i++) {
1406                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1407               }
1408               fprintf(stdout, "\n");
1409             }
1410           }
1411         }
1412
1413         /* suppress duplicates by time window */
1414         if (dup_detect_by_time) {
1415           nstime_t current;
1416
1417           current.secs = phdr->ts.secs;
1418           current.nsecs = phdr->ts.nsecs;
1419
1420           if (is_duplicate_rel_time(buf, phdr->caplen, &current)) {
1421             if (verbose) {
1422               fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1423               for (i = 0; i < 16; i++) {
1424                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1425               }
1426               fprintf(stdout, "\n");
1427             }
1428             duplicate_count++;
1429             count++;
1430             continue;
1431           } else {
1432             if (verbose) {
1433               fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1434               for (i = 0; i < 16; i++) {
1435                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1436               }
1437               fprintf(stdout, "\n");
1438             }
1439           }
1440         }
1441
1442         /* Random error mutation */
1443         if (err_prob > 0.0) {
1444           int real_data_start = 0;
1445           /* Protect non-protocol data */
1446           if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1447             real_data_start = find_dct2000_real_data(buf);
1448           }
1449           for (i = real_data_start; i < (int) phdr->caplen; i++) {
1450             if (rand() <= err_prob * RAND_MAX) {
1451               err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1452
1453               if (err_type < ERR_WT_BIT) {
1454                 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1455                 err_type = ERR_WT_TOTAL;
1456               } else {
1457                 err_type -= ERR_WT_BYTE;
1458               }
1459
1460               if (err_type < ERR_WT_BYTE) {
1461                 buf[i] = rand() / (RAND_MAX / 255 + 1);
1462                 err_type = ERR_WT_TOTAL;
1463               } else {
1464                 err_type -= ERR_WT_BYTE;
1465               }
1466
1467               if (err_type < ERR_WT_ALNUM) {
1468                 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1469                 err_type = ERR_WT_TOTAL;
1470               } else {
1471                 err_type -= ERR_WT_ALNUM;
1472               }
1473
1474               if (err_type < ERR_WT_FMT) {
1475                 if ((unsigned int)i < phdr->caplen - 2)
1476                   g_strlcpy((char*) &buf[i], "%s", 2);
1477                 err_type = ERR_WT_TOTAL;
1478               } else {
1479                 err_type -= ERR_WT_FMT;
1480               }
1481
1482               if (err_type < ERR_WT_AA) {
1483                 for (j = i; j < (int) phdr->caplen; j++) {
1484                   buf[j] = 0xAA;
1485                 }
1486                 i = phdr->caplen;
1487               }
1488             }
1489           }
1490         }
1491
1492         if (!wtap_dump(pdh, phdr, buf, &err)) {
1493           switch (err) {
1494
1495           case WTAP_ERR_UNSUPPORTED_ENCAP:
1496             /*
1497              * This is a problem with the particular frame we're writing;
1498              * note that, and give the frame number.
1499              */
1500             fprintf(stderr, "editcap: Frame %u of \"%s\" has a network type that can't be saved in a file with that format\n.",
1501                     read_count, argv[optind]);
1502             break;
1503
1504           default:
1505             fprintf(stderr, "editcap: Error writing to %s: %s\n",
1506                     filename, wtap_strerror(err));
1507             break;
1508           }
1509           exit(2);
1510         }
1511         written_count++;
1512       }
1513       count++;
1514     }
1515
1516
1517     g_free(fprefix);
1518     g_free(fsuffix);
1519
1520     if (err != 0) {
1521       /* Print a message noting that the read failed somewhere along the line. */
1522       fprintf(stderr,
1523               "editcap: An error occurred while reading \"%s\": %s.\n",
1524               argv[optind], wtap_strerror(err));
1525       switch (err) {
1526
1527       case WTAP_ERR_UNSUPPORTED:
1528       case WTAP_ERR_UNSUPPORTED_ENCAP:
1529       case WTAP_ERR_BAD_FILE:
1530         fprintf(stderr, "(%s)\n", err_info);
1531         g_free(err_info);
1532         break;
1533       }
1534     }
1535
1536     if (!pdh) {
1537       /* No valid packages found, open the outfile so we can write an empty header */
1538       g_free (filename);
1539       filename = g_strdup(argv[optind+1]);
1540
1541       pdh = wtap_dump_open_ng(filename, out_file_type, out_frame_type,
1542         snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
1543         FALSE /* compressed */, shb_hdr, idb_inf, &err);
1544       if (pdh == NULL) {
1545         fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1546         wtap_strerror(err));
1547         exit(2);
1548       }
1549     }
1550
1551     g_free(idb_inf);
1552     idb_inf = NULL;
1553
1554     if (!wtap_dump_close(pdh, &err)) {
1555
1556       fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1557           wtap_strerror(err));
1558       exit(2);
1559
1560     }
1561     g_free(shb_hdr);
1562     g_free(filename);
1563   }
1564
1565   if (dup_detect) {
1566     fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1567                 count - 1, plurality(count - 1, "", "s"),
1568                 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1569   } else if (dup_detect_by_time) {
1570     fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1571                 count - 1, plurality(count - 1, "", "s"),
1572                 duplicate_count, plurality(duplicate_count, "", "s"),
1573                 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1574   }
1575
1576   return 0;
1577 }
1578
1579 /* Skip meta-information read from file to return offset of real
1580    protocol data */
1581 static int find_dct2000_real_data(guint8 *buf)
1582 {
1583   int n=0;
1584
1585   for (n=0; buf[n] != '\0'; n++);   /* Context name */
1586   n++;
1587   n++;                              /* Context port number */
1588   for (; buf[n] != '\0'; n++);      /* Timestamp */
1589   n++;
1590   for (; buf[n] != '\0'; n++);      /* Protocol name */
1591   n++;
1592   for (; buf[n] != '\0'; n++);      /* Variant number (as string) */
1593   n++;
1594   for (; buf[n] != '\0'; n++);      /* Outhdr (as string) */
1595   n++;
1596   n += 2;                           /* Direction & encap */
1597
1598   return n;
1599 }