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