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