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