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