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