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