Generate randpkt_core/doxygen.cfg.
[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  * Originally written by Richard Sharpe.
5  * Improved by Guy Harris.
6  * Further improved by Richard Sharpe.
7  *
8  * Copyright 2013, Richard Sharpe <realrichardsharpe[AT]gmail.com>
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  */
28
29 #include <config.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35
36 /*
37  * Just make sure we include the prototype for strptime as well
38  * (needed for glibc 2.2) but make sure we do this only if not
39  * yet defined.
40  */
41
42 #ifndef __USE_XOPEN
43 #  define __USE_XOPEN
44 #endif
45
46 #include <time.h>
47 #include <glib.h>
48
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52
53 #ifdef HAVE_GETOPT_H
54 #include <getopt.h>
55 #endif
56
57 #ifdef HAVE_LIBZ
58 #include <zlib.h>     /* to get the libz version number */
59 #endif
60
61 #include <wiretap/wtap.h>
62
63 #include "epan/etypes.h"
64
65 #ifndef HAVE_GETOPT_LONG
66 #include "wsutil/wsgetopt.h"
67 #endif
68
69 #ifdef _WIN32
70 #include <wsutil/file_util.h>
71 #include <wsutil/unicode-utils.h>
72 #include <process.h>    /* getpid */
73 #ifdef HAVE_WINSOCK2_H
74 #include <winsock2.h>
75 #endif
76 #endif
77
78 #ifndef HAVE_STRPTIME
79 # include "wsutil/strptime.h"
80 #endif
81
82 #include <wsutil/crash_info.h>
83 #include <wsutil/filesystem.h>
84 #include <wsutil/md5.h>
85 #include <wsutil/plugins.h>
86 #include <wsutil/privileges.h>
87 #include <wsutil/report_err.h>
88 #include <wsutil/strnatcmp.h>
89 #include <wsutil/str_util.h>
90 #include <wsutil/ws_diag_control.h>
91 #include <wsutil/ws_version_info.h>
92
93 #include "ringbuffer.h" /* For RINGBUFFER_MAX_NUM_FILES */
94
95 /*
96  * Some globals so we can pass things to various routines
97  */
98
99 struct select_item {
100     gboolean inclusive;
101     guint first, second;
102 };
103
104 /*
105  * Duplicate frame detection
106  */
107 typedef struct _fd_hash_t {
108     md5_byte_t digest[16];
109     guint32    len;
110     nstime_t   frame_time;
111 } fd_hash_t;
112
113 #define DEFAULT_DUP_DEPTH       5   /* Used with -d */
114 #define MAX_DUP_DEPTH     1000000   /* the maximum window (and actual size of fd_hash[]) for de-duplication */
115
116 static fd_hash_t fd_hash[MAX_DUP_DEPTH];
117 static int       dup_window    = DEFAULT_DUP_DEPTH;
118 static int       cur_dup_entry = 0;
119
120 static int       ignored_bytes  = 0;  /* Used with -I */
121
122 #define ONE_BILLION 1000000000
123
124 /* Weights of different errors we can introduce */
125 /* We should probably make these command-line arguments */
126 /* XXX - Should we add a bit-level error? */
127 #define ERR_WT_BIT      5   /* Flip a random bit */
128 #define ERR_WT_BYTE     5   /* Substitute a random byte */
129 #define ERR_WT_ALNUM    5   /* Substitute a random character in [A-Za-z0-9] */
130 #define ERR_WT_FMT      2   /* Substitute "%s" */
131 #define ERR_WT_AA       1   /* Fill the remainder of the buffer with 0xAA */
132 #define ERR_WT_TOTAL    (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
133
134 #define ALNUM_CHARS     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
135 #define ALNUM_LEN       (sizeof(ALNUM_CHARS) - 1)
136
137 struct time_adjustment {
138     nstime_t tv;
139     int is_negative;
140 };
141
142 typedef struct _chop_t {
143     int len_begin;
144     int off_begin_pos;
145     int off_begin_neg;
146     int len_end;
147     int off_end_pos;
148     int off_end_neg;
149 } chop_t;
150
151
152 /* Table of user comments */
153 GTree *frames_user_comments = NULL;
154
155 #define MAX_SELECTIONS 512
156 static struct select_item     selectfrm[MAX_SELECTIONS];
157 static guint                  max_selected              = 0;
158 static int                    keep_em                   = 0;
159 #ifdef PCAP_NG_DEFAULT
160 static int                    out_file_type_subtype     = WTAP_FILE_TYPE_SUBTYPE_PCAPNG; /* default to pcapng   */
161 #else
162 static int                    out_file_type_subtype     = WTAP_FILE_TYPE_SUBTYPE_PCAP; /* default to pcap     */
163 #endif
164 static int                    out_frame_type            = -2; /* Leave frame type alone */
165 static int                    verbose                   = 0;  /* Not so verbose         */
166 static struct time_adjustment time_adj                  = {{0, 0}, 0}; /* no adjustment */
167 static nstime_t               relative_time_window      = {0, 0}; /* de-dup time window */
168 static double                 err_prob                  = 0.0;
169 static time_t                 starttime                 = 0;
170 static time_t                 stoptime                  = 0;
171 static gboolean               check_startstop           = FALSE;
172 static gboolean               rem_vlan                  = FALSE;
173 static gboolean               dup_detect                = FALSE;
174 static gboolean               dup_detect_by_time        = FALSE;
175
176 static int                    do_strict_time_adjustment = FALSE;
177 static struct time_adjustment strict_time_adj           = {{0, 0}, 0}; /* strict time adjustment */
178 static nstime_t               previous_time             = {0, 0}; /* previous time */
179
180 static int find_dct2000_real_data(guint8 *buf);
181 static void handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr,
182                             const struct wtap_pkthdr *in_phdr, guint8 **buf,
183                             gboolean adjlen);
184
185 static gchar *
186 abs_time_to_str_with_sec_resolution(const nstime_t *abs_time)
187 {
188     struct tm *tmp;
189     gchar     *buf = (gchar *)g_malloc(16);
190
191     tmp = localtime(&abs_time->secs);
192
193     if (tmp) {
194         g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
195             tmp->tm_year + 1900,
196             tmp->tm_mon+1,
197             tmp->tm_mday,
198             tmp->tm_hour,
199             tmp->tm_min,
200             tmp->tm_sec);
201     } else {
202         buf[0] = '\0';
203     }
204
205     return buf;
206 }
207
208 static gchar *
209 fileset_get_filename_by_pattern(guint idx, const struct wtap_pkthdr *phdr,
210                                 gchar *fprefix, gchar *fsuffix)
211 {
212     gchar  filenum[5+1];
213     gchar *timestr;
214     gchar *abs_str;
215
216     g_snprintf(filenum, sizeof(filenum), "%05u", idx % RINGBUFFER_MAX_NUM_FILES);
217     if (phdr->presence_flags & WTAP_HAS_TS) {
218         timestr = abs_time_to_str_with_sec_resolution(&phdr->ts);
219         abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
220         g_free(timestr);
221     } else
222         abs_str = g_strconcat(fprefix, "_", filenum, fsuffix, NULL);
223
224     return abs_str;
225 }
226
227 static gboolean
228 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
229 {
230     char  *pfx, *last_pathsep;
231     gchar *save_file;
232
233     save_file = g_strdup(fname);
234     if (save_file == NULL) {
235         fprintf(stderr, "editcap: Out of memory\n");
236         return FALSE;
237     }
238
239     last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
240     pfx = strrchr(save_file,'.');
241     if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
242         /* The pathname has a "." in it, and it's in the last component
243          * of the pathname (because there is either only one component,
244          * i.e. last_pathsep is null as there are no path separators,
245          * or the "." is after the path separator before the last
246          * component.
247
248          * Treat it as a separator between the rest of the file name and
249          * the file name suffix, and arrange that the names given to the
250          * ring buffer files have the specified suffix, i.e. put the
251          * changing part of the name *before* the suffix. */
252         pfx[0] = '\0';
253         *fprefix = g_strdup(save_file);
254         pfx[0] = '.'; /* restore capfile_name */
255         *fsuffix = g_strdup(pfx);
256     } else {
257         /* Either there's no "." in the pathname, or it's in a directory
258          * component, so the last component has no suffix. */
259         *fprefix = g_strdup(save_file);
260         *fsuffix = NULL;
261     }
262     g_free(save_file);
263     return TRUE;
264 }
265
266 /* Add a selection item, a simple parser for now */
267 static gboolean
268 add_selection(char *sel, guint* max_selection)
269 {
270     char *locn;
271     char *next;
272
273     if (max_selected >= MAX_SELECTIONS) {
274         /* Let the user know we stopped selecting */
275         fprintf(stderr, "Out of room for packet selections!\n");
276         return(FALSE);
277     }
278
279     if (verbose)
280         fprintf(stderr, "Add_Selected: %s\n", sel);
281
282     if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
283         if (verbose)
284             fprintf(stderr, "Not inclusive ...");
285
286         selectfrm[max_selected].inclusive = FALSE;
287         selectfrm[max_selected].first = (guint)strtoul(sel, NULL, 10);
288         if (selectfrm[max_selected].first < *max_selection)
289             *max_selection = selectfrm[max_selected].first;
290
291         if (verbose)
292             fprintf(stderr, " %i\n", selectfrm[max_selected].first);
293     } else {
294         if (verbose)
295             fprintf(stderr, "Inclusive ...");
296
297         next = locn + 1;
298         selectfrm[max_selected].inclusive = TRUE;
299         selectfrm[max_selected].first = (guint)strtoul(sel, NULL, 10);
300         selectfrm[max_selected].second = (guint)strtoul(next, NULL, 10);
301
302         if (selectfrm[max_selected].second == 0)
303         {
304             /* Not a valid number, presume all */
305             selectfrm[max_selected].second = *max_selection = G_MAXUINT;
306         }
307         else if (selectfrm[max_selected].second < *max_selection)
308             *max_selection = selectfrm[max_selected].second;
309
310         if (verbose)
311             fprintf(stderr, " %i, %i\n", selectfrm[max_selected].first,
312                    selectfrm[max_selected].second);
313     }
314
315     max_selected++;
316     return(TRUE);
317 }
318
319 /* Was the packet selected? */
320
321 static int
322 selected(guint recno)
323 {
324     guint i;
325
326     for (i = 0; i < max_selected; i++) {
327         if (selectfrm[i].inclusive) {
328             if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
329                 return 1;
330         } else {
331             if (recno == selectfrm[i].first)
332                 return 1;
333         }
334     }
335
336   return 0;
337 }
338
339 static void
340 set_time_adjustment(char *optarg_str_p)
341 {
342     char   *frac, *end;
343     long    val;
344     size_t  frac_digits;
345
346     if (!optarg_str_p)
347         return;
348
349     /* skip leading whitespace */
350     while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
351         optarg_str_p++;
352
353     /* check for a negative adjustment */
354     if (*optarg_str_p == '-') {
355         time_adj.is_negative = 1;
356         optarg_str_p++;
357     }
358
359     /* collect whole number of seconds, if any */
360     if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
361         val  = 0;
362         frac = optarg_str_p;
363     } else {
364         val = strtol(optarg_str_p, &frac, 10);
365         if (frac == NULL || frac == optarg_str_p
366             || val == LONG_MIN || val == LONG_MAX) {
367             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
368                     optarg_str_p);
369             exit(1);
370         }
371         if (val < 0) {            /* implies '--' since we caught '-' above  */
372             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
373                     optarg_str_p);
374             exit(1);
375         }
376     }
377     time_adj.tv.secs = val;
378
379     /* now collect the partial seconds, if any */
380     if (*frac != '\0') {             /* chars left, so get fractional part */
381         val = strtol(&(frac[1]), &end, 10);
382         /* if more than 9 fractional digits truncate to 9 */
383         if ((end - &(frac[1])) > 9) {
384             frac[10] = 't'; /* 't' for truncate */
385             val = strtol(&(frac[1]), &end, 10);
386         }
387         if (*frac != '.' || end == NULL || end == frac || val < 0
388             || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
389             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
390                     optarg_str_p);
391             exit(1);
392         }
393     } else {
394         return;                     /* no fractional digits */
395     }
396
397     /* adjust fractional portion from fractional to numerator
398      * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
399     if (frac && end) {            /* both are valid */
400         frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
401         while(frac_digits < 9) {    /* this is frac of 10^9 */
402             val *= 10;
403             frac_digits++;
404         }
405     }
406     time_adj.tv.nsecs = (int)val;
407 }
408
409 static void
410 set_strict_time_adj(char *optarg_str_p)
411 {
412     char   *frac, *end;
413     long    val;
414     size_t  frac_digits;
415
416     if (!optarg_str_p)
417         return;
418
419     /* skip leading whitespace */
420     while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
421         optarg_str_p++;
422
423     /*
424      * check for a negative adjustment
425      * A negative strict adjustment value is a flag
426      * to adjust all frames by the specifed delta time.
427      */
428     if (*optarg_str_p == '-') {
429         strict_time_adj.is_negative = 1;
430         optarg_str_p++;
431     }
432
433     /* collect whole number of seconds, if any */
434     if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
435         val  = 0;
436         frac = optarg_str_p;
437     } else {
438         val = strtol(optarg_str_p, &frac, 10);
439         if (frac == NULL || frac == optarg_str_p
440             || val == LONG_MIN || val == LONG_MAX) {
441             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
442                     optarg_str_p);
443             exit(1);
444         }
445         if (val < 0) {            /* implies '--' since we caught '-' above  */
446             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
447                     optarg_str_p);
448             exit(1);
449         }
450     }
451     strict_time_adj.tv.secs = val;
452
453     /* now collect the partial seconds, if any */
454     if (*frac != '\0') {             /* chars left, so get fractional part */
455         val = strtol(&(frac[1]), &end, 10);
456         /* if more than 9 fractional digits truncate to 9 */
457         if ((end - &(frac[1])) > 9) {
458             frac[10] = 't'; /* 't' for truncate */
459             val = strtol(&(frac[1]), &end, 10);
460         }
461         if (*frac != '.' || end == NULL || end == frac || val < 0
462             || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
463             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
464                     optarg_str_p);
465             exit(1);
466         }
467     } else {
468         return;                     /* no fractional digits */
469     }
470
471     /* adjust fractional portion from fractional to numerator
472      * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
473     if (frac && end) {            /* both are valid */
474         frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
475         while(frac_digits < 9) {    /* this is frac of 10^9 */
476             val *= 10;
477             frac_digits++;
478         }
479     }
480     strict_time_adj.tv.nsecs = (int)val;
481 }
482
483 static void
484 set_rel_time(char *optarg_str_p)
485 {
486     char   *frac, *end;
487     long    val;
488     size_t  frac_digits;
489
490     if (!optarg_str_p)
491         return;
492
493     /* skip leading whitespace */
494     while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
495         optarg_str_p++;
496
497     /* ignore negative adjustment  */
498     if (*optarg_str_p == '-')
499         optarg_str_p++;
500
501     /* collect whole number of seconds, if any */
502     if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
503         val  = 0;
504         frac = optarg_str_p;
505     } else {
506         val = strtol(optarg_str_p, &frac, 10);
507         if (frac == NULL || frac == optarg_str_p
508             || val == LONG_MIN || val == LONG_MAX) {
509             fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
510                     optarg_str_p);
511             exit(1);
512         }
513         if (val < 0) {            /* implies '--' since we caught '-' above  */
514             fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
515                     optarg_str_p);
516             exit(1);
517         }
518     }
519     relative_time_window.secs = val;
520
521     /* now collect the partial seconds, if any */
522     if (*frac != '\0') {             /* chars left, so get fractional part */
523         val = strtol(&(frac[1]), &end, 10);
524         /* if more than 9 fractional digits truncate to 9 */
525         if ((end - &(frac[1])) > 9) {
526             frac[10] = 't'; /* 't' for truncate */
527             val = strtol(&(frac[1]), &end, 10);
528         }
529         if (*frac != '.' || end == NULL || end == frac || val < 0
530             || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
531             fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
532                     optarg_str_p);
533             exit(1);
534         }
535     } else {
536         return;                     /* no fractional digits */
537     }
538
539     /* adjust fractional portion from fractional to numerator
540      * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
541     if (frac && end) {            /* both are valid */
542         frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
543         while(frac_digits < 9) {    /* this is frac of 10^9 */
544             val *= 10;
545             frac_digits++;
546         }
547     }
548     relative_time_window.nsecs = (int)val;
549 }
550
551 #define LINUX_SLL_OFFSETP 14
552 #define VLAN_SIZE 4
553 static void
554 sll_remove_vlan_info(guint8* fd, guint32* len) {
555     if (g_ntohs(*(fd + LINUX_SLL_OFFSETP)) == ETHERTYPE_VLAN) {
556         int rest_len;
557         /* point to start of vlan */
558         fd = fd + LINUX_SLL_OFFSETP;
559         /* bytes to read after vlan info */
560         rest_len = *len - (LINUX_SLL_OFFSETP + VLAN_SIZE);
561         /* remove vlan info from packet */
562         memmove(fd, fd + VLAN_SIZE, rest_len);
563         *len -= 4;
564     }
565 }
566
567 static void
568 remove_vlan_info(const struct wtap_pkthdr *phdr, guint8* fd, guint32* len) {
569     switch (phdr->pkt_encap) {
570         case WTAP_ENCAP_SLL:
571             sll_remove_vlan_info(fd, len);
572             break;
573         default:
574             /* no support for current pkt_encap */
575             break;
576     }
577 }
578
579 static gboolean
580 is_duplicate(guint8* fd, guint32 len) {
581     int i;
582     md5_state_t ms;
583
584     /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */
585     guint32 new_len;
586     guint8 *new_fd;
587
588     new_fd  = &fd[ignored_bytes];
589     new_len = len - (ignored_bytes);
590
591     cur_dup_entry++;
592     if (cur_dup_entry >= dup_window)
593         cur_dup_entry = 0;
594
595     /* Calculate our digest */
596     md5_init(&ms);
597     md5_append(&ms, new_fd, new_len);
598     md5_finish(&ms, fd_hash[cur_dup_entry].digest);
599
600     fd_hash[cur_dup_entry].len = len;
601
602     /* Look for duplicates */
603     for (i = 0; i < dup_window; i++) {
604         if (i == cur_dup_entry)
605             continue;
606
607         if (fd_hash[i].len == fd_hash[cur_dup_entry].len
608             && memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
609             return TRUE;
610         }
611     }
612
613     return FALSE;
614 }
615
616 static gboolean
617 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
618     int i;
619     md5_state_t ms;
620
621     /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */
622     guint32 new_len;
623     guint8 *new_fd;
624
625     new_fd  = &fd[ignored_bytes];
626     new_len = len - (ignored_bytes);
627
628     cur_dup_entry++;
629     if (cur_dup_entry >= dup_window)
630         cur_dup_entry = 0;
631
632     /* Calculate our digest */
633     md5_init(&ms);
634     md5_append(&ms, new_fd, new_len);
635     md5_finish(&ms, fd_hash[cur_dup_entry].digest);
636
637     fd_hash[cur_dup_entry].len = len;
638     fd_hash[cur_dup_entry].frame_time.secs = current->secs;
639     fd_hash[cur_dup_entry].frame_time.nsecs = current->nsecs;
640
641     /*
642      * Look for relative time related duplicates.
643      * This is hopefully a reasonably efficient mechanism for
644      * finding duplicates by rel time in the fd_hash[] cache.
645      * We check starting from the most recently added hash
646      * entries and work backwards towards older packets.
647      * This approach allows the dup test to be terminated
648      * when the relative time of a cached entry is found to
649      * be beyond the dup time window.
650      *
651      * Of course this assumes that the input trace file is
652      * "well-formed" in the sense that the packet timestamps are
653      * in strict chronologically increasing order (which is NOT
654      * always the case!!).
655      *
656      * The fd_hash[] table was deliberately created large (1,000,000).
657      * Looking for time related duplicates in large trace files with
658      * non-fractional dup time window values can potentially take
659      * a long time to complete.
660      */
661
662     for (i = cur_dup_entry - 1;; i--) {
663         nstime_t delta;
664         int cmp;
665
666         if (i < 0)
667             i = dup_window - 1;
668
669         if (i == cur_dup_entry) {
670             /*
671              * We've decremented back to where we started.
672              * Check no more!
673              */
674             break;
675         }
676
677         if (nstime_is_unset(&(fd_hash[i].frame_time))) {
678             /*
679              * We've decremented to an unused fd_hash[] entry.
680              * Check no more!
681              */
682             break;
683         }
684
685         nstime_delta(&delta, current, &fd_hash[i].frame_time);
686
687         if (delta.secs < 0 || delta.nsecs < 0) {
688             /*
689              * A negative delta implies that the current packet
690              * has an absolute timestamp less than the cached packet
691              * that it is being compared to.  This is NOT a normal
692              * situation since trace files usually have packets in
693              * chronological order (oldest to newest).
694              *
695              * There are several possible ways to deal with this:
696              * 1. 'continue' dup checking with the next cached frame.
697              * 2. 'break' from looking for a duplicate of the current frame.
698              * 3. Take the absolute value of the delta and see if that
699              * falls within the specifed dup time window.
700              *
701              * Currently this code does option 1.  But it would pretty
702              * easy to add yet-another-editcap-option to select one of
703              * the other behaviors for dealing with out-of-sequence
704              * packets.
705              */
706             continue;
707         }
708
709         cmp = nstime_cmp(&delta, &relative_time_window);
710
711         if (cmp > 0) {
712             /*
713              * The delta time indicates that we are now looking at
714              * cached packets beyond the specified dup time window.
715              * Check no more!
716              */
717             break;
718         } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len
719                    && memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
720             return TRUE;
721         }
722     }
723
724     return FALSE;
725 }
726
727 static void
728 print_usage(FILE *output)
729 {
730     fprintf(output, "\n");
731     fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
732     fprintf(output, "\n");
733     fprintf(output, "<infile> and <outfile> must both be present.\n");
734     fprintf(output, "A single packet or a range of packets can be selected.\n");
735     fprintf(output, "\n");
736     fprintf(output, "Packet selection:\n");
737     fprintf(output, "  -r                     keep the selected packets; default is to delete them.\n");
738     fprintf(output, "  -A <start time>        only output packets whose timestamp is after (or equal\n");
739     fprintf(output, "                         to) the given time (format as YYYY-MM-DD hh:mm:ss).\n");
740     fprintf(output, "  -B <stop time>         only output packets whose timestamp is before the\n");
741     fprintf(output, "                         given time (format as YYYY-MM-DD hh:mm:ss).\n");
742     fprintf(output, "\n");
743     fprintf(output, "Duplicate packet removal:\n");
744     fprintf(output, "  --novlan                remove vlan info from packets before checking for duplicates.\n");
745     fprintf(output, "  -d                     remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
746     fprintf(output, "  -D <dup window>        remove packet if duplicate; configurable <dup window>\n");
747     fprintf(output, "                         Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
748     fprintf(output, "                         NOTE: A <dup window> of 0 with -v (verbose option) is\n");
749     fprintf(output, "                         useful to print MD5 hashes.\n");
750     fprintf(output, "  -w <dup time window>   remove packet if duplicate packet is found EQUAL TO OR\n");
751     fprintf(output, "                         LESS THAN <dup time window> prior to current packet.\n");
752     fprintf(output, "                         A <dup time window> is specified in relative seconds\n");
753     fprintf(output, "                         (e.g. 0.000001).\n");
754     fprintf(output, "  -a <framenum>:<comment>  Add or replace comment for given frame number\n");
755     fprintf(output, "\n");
756     fprintf(output, "  -I <bytes to ignore>   ignore the specified bytes at the beginning of\n");
757     fprintf(output, "                         the frame during MD5 hash calculation\n");
758     fprintf(output, "                         Useful to remove duplicated packets taken on\n");
759     fprintf(output, "                         several routers(differents mac addresses for \n");
760     fprintf(output, "                         example)\n");
761     fprintf(output, "                         e.g. -I 26 in case of Ether/IP/ will ignore \n");
762     fprintf(output, "                         ether(14) and IP header(20 - 4(src ip) - 4(dst ip)).\n");
763     fprintf(output, "\n");
764     fprintf(output, "           NOTE: The use of the 'Duplicate packet removal' options with\n");
765     fprintf(output, "           other editcap options except -v may not always work as expected.\n");
766     fprintf(output, "           Specifically the -r, -t or -S options will very likely NOT have the\n");
767     fprintf(output, "           desired effect if combined with the -d, -D or -w.\n");
768     fprintf(output, "\n");
769     fprintf(output, "Packet manipulation:\n");
770     fprintf(output, "  -s <snaplen>           truncate each packet to max. <snaplen> bytes of data.\n");
771     fprintf(output, "  -C [offset:]<choplen>  chop each packet by <choplen> bytes. Positive values\n");
772     fprintf(output, "                         chop at the packet beginning, negative values at the\n");
773     fprintf(output, "                         packet end. If an optional offset precedes the length,\n");
774     fprintf(output, "                         then the bytes chopped will be offset from that value.\n");
775     fprintf(output, "                         Positive offsets are from the packet beginning,\n");
776     fprintf(output, "                         negative offsets are from the packet end. You can use\n");
777     fprintf(output, "                         this option more than once, allowing up to 2 chopping\n");
778     fprintf(output, "                         regions within a packet provided that at least 1\n");
779     fprintf(output, "                         choplen is positive and at least 1 is negative.\n");
780     fprintf(output, "  -L                     adjust the frame (i.e. reported) length when chopping\n");
781     fprintf(output, "                         and/or snapping\n");
782     fprintf(output, "  -t <time adjustment>   adjust the timestamp of each packet;\n");
783     fprintf(output, "                         <time adjustment> is in relative seconds (e.g. -0.5).\n");
784     fprintf(output, "  -S <strict adjustment> adjust timestamp of packets if necessary to insure\n");
785     fprintf(output, "                         strict chronological increasing order. The <strict\n");
786     fprintf(output, "                         adjustment> is specified in relative seconds with\n");
787     fprintf(output, "                         values of 0 or 0.000001 being the most reasonable.\n");
788     fprintf(output, "                         A negative adjustment value will modify timestamps so\n");
789     fprintf(output, "                         that each packet's delta time is the absolute value\n");
790     fprintf(output, "                         of the adjustment specified. A value of -0 will set\n");
791     fprintf(output, "                         all packets to the timestamp of the first packet.\n");
792     fprintf(output, "  -E <error probability> set the probability (between 0.0 and 1.0 incl.) that\n");
793     fprintf(output, "                         a particular packet byte will be randomly changed.\n");
794     fprintf(output, "  -o <change offset>     When used in conjunction with -E, skip some bytes from the\n");
795     fprintf(output, "                         beginning of the packet. This allows one to preserve some\n");
796     fprintf(output, "                         bytes, in order to have some headers untouched.\n");
797     fprintf(output, "\n");
798     fprintf(output, "Output File(s):\n");
799     fprintf(output, "  -c <packets per file>  split the packet output to different files based on\n");
800     fprintf(output, "                         uniform packet counts with a maximum of\n");
801     fprintf(output, "                         <packets per file> each.\n");
802     fprintf(output, "  -i <seconds per file>  split the packet output to different files based on\n");
803     fprintf(output, "                         uniform time intervals with a maximum of\n");
804     fprintf(output, "                         <seconds per file> each.\n");
805     fprintf(output, "  -F <capture type>      set the output file type; default is pcapng. An empty\n");
806     fprintf(output, "                         \"-F\" option will list the file types.\n");
807     fprintf(output, "  -T <encap type>        set the output file encapsulation type; default is the\n");
808     fprintf(output, "                         same as the input file. An empty \"-T\" option will\n");
809     fprintf(output, "                         list the encapsulation types.\n");
810     fprintf(output, "\n");
811     fprintf(output, "Miscellaneous:\n");
812     fprintf(output, "  -h                     display this help and exit.\n");
813     fprintf(output, "  -v                     verbose output.\n");
814     fprintf(output, "                         If -v is used with any of the 'Duplicate Packet\n");
815     fprintf(output, "                         Removal' options (-d, -D or -w) then Packet lengths\n");
816     fprintf(output, "                         and MD5 hashes are printed to standard-error.\n");
817     fprintf(output, "\n");
818 }
819
820 struct string_elem {
821     const char *sstr;   /* The short string */
822     const char *lstr;   /* The long string */
823 };
824
825 static gint
826 string_compare(gconstpointer a, gconstpointer b)
827 {
828     return strcmp(((const struct string_elem *)a)->sstr,
829         ((const struct string_elem *)b)->sstr);
830 }
831
832 static gint
833 string_nat_compare(gconstpointer a, gconstpointer b)
834 {
835     return ws_ascii_strnatcmp(((const struct string_elem *)a)->sstr,
836         ((const struct string_elem *)b)->sstr);
837 }
838
839 static void
840 string_elem_print(gpointer data, gpointer not_used _U_)
841 {
842     fprintf(stderr, "    %s - %s\n",
843         ((struct string_elem *)data)->sstr,
844         ((struct string_elem *)data)->lstr);
845 }
846
847 static void
848 list_capture_types(void) {
849     int i;
850     struct string_elem *captypes;
851     GSList *list = NULL;
852
853     captypes = g_new(struct string_elem,WTAP_NUM_FILE_TYPES_SUBTYPES);
854     fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
855     for (i = 0; i < WTAP_NUM_FILE_TYPES_SUBTYPES; i++) {
856         if (wtap_dump_can_open(i)) {
857             captypes[i].sstr = wtap_file_type_subtype_short_string(i);
858             captypes[i].lstr = wtap_file_type_subtype_string(i);
859             list = g_slist_insert_sorted(list, &captypes[i], string_compare);
860         }
861     }
862     g_slist_foreach(list, string_elem_print, NULL);
863     g_slist_free(list);
864     g_free(captypes);
865 }
866
867 static void
868 list_encap_types(void) {
869     int i;
870     struct string_elem *encaps;
871     GSList *list = NULL;
872
873     encaps = (struct string_elem *)g_malloc(sizeof(struct string_elem) * WTAP_NUM_ENCAP_TYPES);
874     fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
875     for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
876         encaps[i].sstr = wtap_encap_short_string(i);
877         if (encaps[i].sstr != NULL) {
878             encaps[i].lstr = wtap_encap_string(i);
879             list = g_slist_insert_sorted(list, &encaps[i], string_nat_compare);
880         }
881     }
882     g_slist_foreach(list, string_elem_print, NULL);
883     g_slist_free(list);
884     g_free(encaps);
885 }
886
887 static int
888 framenum_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_)
889 {
890     if (GPOINTER_TO_UINT(a) < GPOINTER_TO_UINT(b))
891         return -1;
892
893     if (GPOINTER_TO_UINT(a) > GPOINTER_TO_UINT(b))
894         return 1;
895
896     return 0;
897 }
898
899 #ifdef HAVE_PLUGINS
900 /*
901  *  Don't report failures to load plugins because most (non-wiretap) plugins
902  *  *should* fail to load (because we're not linked against libwireshark and
903  *  dissector plugins need libwireshark).
904  */
905 static void
906 failure_message(const char *msg_format _U_, va_list ap _U_)
907 {
908 }
909 #endif
910
911 static void
912 get_editcap_compiled_info(GString *str)
913 {
914   /* LIBZ */
915   g_string_append(str, ", ");
916 #ifdef HAVE_LIBZ
917   g_string_append(str, "with libz ");
918 #ifdef ZLIB_VERSION
919   g_string_append(str, ZLIB_VERSION);
920 #else /* ZLIB_VERSION */
921   g_string_append(str, "(version unknown)");
922 #endif /* ZLIB_VERSION */
923 #else /* HAVE_LIBZ */
924   g_string_append(str, "without libz");
925 #endif /* HAVE_LIBZ */
926 }
927
928 static void
929 get_editcap_runtime_info(GString *str)
930 {
931   /* zlib */
932 #if defined(HAVE_LIBZ) && !defined(_WIN32)
933   g_string_append_printf(str, ", with libz %s", zlibVersion());
934 #endif
935 }
936
937 static wtap_dumper *
938 editcap_dump_open(const char *filename, guint32 snaplen,
939                   wtapng_section_t *shb_hdr,
940                   wtapng_iface_descriptions_t *idb_inf,
941                   wtapng_name_res_t *nrb_hdr, int *write_err)
942 {
943   wtap_dumper *pdh;
944
945   if (strcmp(filename, "-") == 0) {
946     /* Write to the standard output. */
947     pdh = wtap_dump_open_stdout_ng(out_file_type_subtype, out_frame_type,
948                                    snaplen, FALSE /* compressed */,
949                                    shb_hdr, idb_inf, nrb_hdr,
950                                    write_err);
951   } else {
952     pdh = wtap_dump_open_ng(filename, out_file_type_subtype, out_frame_type,
953                             snaplen, FALSE /* compressed */,
954                             shb_hdr, idb_inf, nrb_hdr,
955                             write_err);
956   }
957   return pdh;
958 }
959
960 int
961 main(int argc, char *argv[])
962 {
963     GString      *comp_info_str;
964     GString      *runtime_info_str;
965     wtap         *wth;
966     int           i, j, read_err, write_err;
967     gchar        *read_err_info, *write_err_info;
968     int           opt;
969     static const struct option long_options[] = {
970         {"novlan", no_argument, NULL, 0x8100},
971         {"help", no_argument, NULL, 'h'},
972         {"version", no_argument, NULL, 'V'},
973         {0, 0, 0, 0 }
974     };
975
976     char         *p;
977     guint32       snaplen            = 0; /* No limit               */
978     chop_t        chop               = {0, 0, 0, 0, 0, 0}; /* No chop */
979     gboolean      adjlen             = FALSE;
980     wtap_dumper  *pdh                = NULL;
981     unsigned int  count              = 1;
982     unsigned int  duplicate_count    = 0;
983     gint64        data_offset;
984     int           err_type;
985     guint8       *buf;
986     guint32       read_count         = 0;
987     int           split_packet_count = 0;
988     int           written_count      = 0;
989     char         *filename           = NULL;
990     gboolean      ts_okay;
991     int           secs_per_block     = 0;
992     int           block_cnt          = 0;
993     nstime_t      block_start;
994     gchar        *fprefix            = NULL;
995     gchar        *fsuffix            = NULL;
996     guint32       change_offset      = 0;
997     guint         max_packet_number  = G_MAXUINT;
998     const struct wtap_pkthdr    *phdr;
999     struct wtap_pkthdr           temp_phdr;
1000     wtapng_iface_descriptions_t *idb_inf = NULL;
1001     wtapng_section_t            *shb_hdr = NULL;
1002     wtapng_name_res_t           *nrb_hdr = NULL;
1003
1004 #ifdef HAVE_PLUGINS
1005     char* init_progfile_dir_error;
1006 #endif
1007
1008 #ifdef _WIN32
1009     arg_list_utf_16to8(argc, argv);
1010     create_app_running_mutex();
1011 #endif /* _WIN32 */
1012
1013     /* Get the compile-time version information string */
1014     comp_info_str = get_compiled_version_info(NULL, get_editcap_compiled_info);
1015
1016     /* Get the run-time version information string */
1017     runtime_info_str = get_runtime_version_info(get_editcap_runtime_info);
1018
1019     /* Add it to the information to be reported on a crash. */
1020     ws_add_crash_info("Editcap (Wireshark) %s\n"
1021          "\n"
1022          "%s"
1023          "\n"
1024          "%s",
1025       get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
1026
1027     /*
1028      * Get credential information for later use.
1029      */
1030     init_process_policies();
1031     init_open_routines();
1032
1033 #ifdef HAVE_PLUGINS
1034     /* Register wiretap plugins */
1035     if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
1036         g_warning("editcap: init_progfile_dir(): %s", init_progfile_dir_error);
1037         g_free(init_progfile_dir_error);
1038     } else {
1039         /* Register all the plugin types we have. */
1040         wtap_register_plugin_types(); /* Types known to libwiretap */
1041
1042         init_report_err(failure_message,NULL,NULL,NULL);
1043
1044         /* Scan for plugins.  This does *not* call their registration routines;
1045            that's done later. */
1046         scan_plugins();
1047
1048         /* Register all libwiretap plugin modules. */
1049         register_all_wiretap_modules();
1050     }
1051 #endif
1052
1053     /* Process the options */
1054     while ((opt = getopt_long(argc, argv, "a:A:B:c:C:dD:E:F:hi:I:Lo:rs:S:t:T:vVw:", long_options, NULL)) != -1) {
1055         switch (opt) {
1056         case 0x8100:
1057         {
1058             rem_vlan = TRUE;
1059             break;
1060         }
1061
1062         case 'a':
1063         {
1064             guint frame_number;
1065             gint string_start_index = 0;
1066
1067             if ((sscanf(optarg, "%u:%n", &frame_number, &string_start_index) < 1) || (string_start_index == 0)) {
1068                 fprintf(stderr, "editcap: \"%s\" isn't a valid <frame>:<comment>\n\n",
1069                         optarg);
1070                 exit(1);
1071             }
1072
1073             /* Lazily create the table */
1074             if (!frames_user_comments) {
1075                 frames_user_comments = g_tree_new_full(framenum_compare, NULL, NULL, g_free);
1076             }
1077
1078             /* Insert this entry (framenum -> comment) */
1079             g_tree_replace(frames_user_comments, GUINT_TO_POINTER(frame_number), g_strdup(optarg+string_start_index));
1080             break;
1081         }
1082
1083         case 'A':
1084         {
1085             struct tm starttm;
1086
1087             memset(&starttm,0,sizeof(struct tm));
1088
1089             if (!strptime(optarg,"%Y-%m-%d %T", &starttm)) {
1090                 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n",
1091                         optarg);
1092                 exit(1);
1093             }
1094
1095             check_startstop = TRUE;
1096             starttm.tm_isdst = -1;
1097
1098             starttime = mktime(&starttm);
1099             break;
1100         }
1101
1102         case 'B':
1103         {
1104             struct tm stoptm;
1105
1106             memset(&stoptm,0,sizeof(struct tm));
1107
1108             if (!strptime(optarg,"%Y-%m-%d %T", &stoptm)) {
1109                 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n",
1110                         optarg);
1111                 exit(1);
1112             }
1113             check_startstop = TRUE;
1114             stoptm.tm_isdst = -1;
1115             stoptime = mktime(&stoptm);
1116             break;
1117         }
1118
1119         case 'c':
1120             split_packet_count = (int)strtol(optarg, &p, 10);
1121             if (p == optarg || *p != '\0') {
1122                 fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
1123                         optarg);
1124                 exit(1);
1125             }
1126             if (split_packet_count <= 0) {
1127                 fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
1128                         split_packet_count);
1129                 exit(1);
1130             }
1131             break;
1132
1133         case 'C':
1134         {
1135             int choplen = 0, chopoff = 0;
1136
1137             switch (sscanf(optarg, "%d:%d", &chopoff, &choplen)) {
1138             case 1: /* only the chop length was specififed */
1139                 choplen = chopoff;
1140                 chopoff = 0;
1141                 break;
1142
1143             case 2: /* both an offset and chop length was specified */
1144                 break;
1145
1146             default:
1147                 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length or offset:length\n",
1148                         optarg);
1149                 exit(1);
1150                 break;
1151             }
1152
1153             if (choplen > 0) {
1154                 chop.len_begin += choplen;
1155                 if (chopoff > 0)
1156                     chop.off_begin_pos += chopoff;
1157                 else
1158                     chop.off_begin_neg += chopoff;
1159             } else if (choplen < 0) {
1160                 chop.len_end += choplen;
1161                 if (chopoff > 0)
1162                     chop.off_end_pos += chopoff;
1163                 else
1164                     chop.off_end_neg += chopoff;
1165             }
1166             break;
1167         }
1168
1169         case 'd':
1170             dup_detect = TRUE;
1171             dup_detect_by_time = FALSE;
1172             dup_window = DEFAULT_DUP_DEPTH;
1173             break;
1174
1175         case 'D':
1176             dup_detect = TRUE;
1177             dup_detect_by_time = FALSE;
1178             dup_window = (int)strtol(optarg, &p, 10);
1179             if (p == optarg || *p != '\0') {
1180                 fprintf(stderr, "editcap: \"%s\" isn't a valid duplicate window value\n",
1181                         optarg);
1182                 exit(1);
1183             }
1184             if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
1185                 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
1186                         dup_window, MAX_DUP_DEPTH);
1187                 exit(1);
1188             }
1189             break;
1190
1191         case 'E':
1192             err_prob = g_ascii_strtod(optarg, &p);
1193             if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
1194                 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
1195                         optarg);
1196                 exit(1);
1197             }
1198             srand( (unsigned int) (time(NULL) + getpid()) );
1199             break;
1200
1201         case 'F':
1202             out_file_type_subtype = wtap_short_string_to_file_type_subtype(optarg);
1203             if (out_file_type_subtype < 0) {
1204                 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
1205                         optarg);
1206                 list_capture_types();
1207                 exit(1);
1208             }
1209             break;
1210
1211         case 'h':
1212             printf("Editcap (Wireshark) %s\n"
1213                    "Edit and/or translate the format of capture files.\n"
1214                    "See https://www.wireshark.org for more information.\n",
1215                get_ws_vcs_version_info());
1216             print_usage(stdout);
1217             exit(0);
1218             break;
1219
1220         case 'i': /* break capture file based on time interval */
1221             secs_per_block = atoi(optarg);
1222             if (secs_per_block <= 0) {
1223                 fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n",
1224                         optarg);
1225                 exit(1);
1226             }
1227             break;
1228
1229         case 'I': /* ignored_bytes at the beginning of the frame for duplications removal */
1230             ignored_bytes = atoi(optarg);
1231             if(ignored_bytes <= 0) {
1232                 fprintf(stderr, "editcap: \"%s\" isn't a valid number of bytes to ignore\n", optarg);
1233                 exit(1);
1234             }
1235             break;
1236
1237         case 'L':
1238             adjlen = TRUE;
1239             break;
1240
1241         case 'o':
1242             change_offset = (guint32)strtol(optarg, &p, 10);
1243             break;
1244
1245         case 'r':
1246             keep_em = !keep_em;  /* Just invert */
1247             break;
1248
1249         case 's':
1250             snaplen = (guint32)strtol(optarg, &p, 10);
1251             if (p == optarg || *p != '\0') {
1252                 fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
1253                         optarg);
1254                 exit(1);
1255             }
1256             break;
1257
1258         case 'S':
1259             set_strict_time_adj(optarg);
1260             do_strict_time_adjustment = TRUE;
1261             break;
1262
1263         case 't':
1264             set_time_adjustment(optarg);
1265             break;
1266
1267         case 'T':
1268             out_frame_type = wtap_short_string_to_encap(optarg);
1269             if (out_frame_type < 0) {
1270                 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
1271                         optarg);
1272                 list_encap_types();
1273                 exit(1);
1274             }
1275             break;
1276
1277         case 'v':
1278             verbose = !verbose;  /* Just invert */
1279             break;
1280
1281         case 'V':
1282             show_version("Editcap (Wireshark)", comp_info_str, runtime_info_str);
1283             g_string_free(comp_info_str, TRUE);
1284             g_string_free(runtime_info_str, TRUE);
1285             exit(0);
1286             break;
1287
1288         case 'w':
1289             dup_detect = FALSE;
1290             dup_detect_by_time = TRUE;
1291             dup_window = MAX_DUP_DEPTH;
1292             set_rel_time(optarg);
1293             break;
1294
1295         case '?':              /* Bad options if GNU getopt */
1296             switch(optopt) {
1297             case'F':
1298                 list_capture_types();
1299                 break;
1300             case'T':
1301                 list_encap_types();
1302                 break;
1303             default:
1304                 print_usage(stderr);
1305                 break;
1306             }
1307             exit(1);
1308             break;
1309         }
1310     } /* processing commmand-line options */
1311
1312 #ifdef DEBUG
1313     fprintf(stderr, "Optind = %i, argc = %i\n", optind, argc);
1314 #endif
1315
1316     if ((argc - optind) < 1) {
1317         print_usage(stderr);
1318         exit(1);
1319     }
1320
1321     if (check_startstop && !stoptime) {
1322         struct tm stoptm;
1323
1324         /* XXX: will work until 2035 */
1325         memset(&stoptm,0,sizeof(struct tm));
1326         stoptm.tm_year = 135;
1327         stoptm.tm_mday = 31;
1328         stoptm.tm_mon = 11;
1329
1330         stoptime = mktime(&stoptm);
1331     }
1332
1333     nstime_set_unset(&block_start);
1334
1335     if (starttime > stoptime) {
1336         fprintf(stderr, "editcap: start time is after the stop time\n");
1337         exit(1);
1338     }
1339
1340     if (split_packet_count > 0 && secs_per_block > 0) {
1341         fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1342         fprintf(stderr, "editcap: at the same time\n");
1343         exit(1);
1344     }
1345
1346     wth = wtap_open_offline(argv[optind], WTAP_TYPE_AUTO, &read_err, &read_err_info, FALSE);
1347
1348     if (!wth) {
1349         fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
1350                 wtap_strerror(read_err));
1351         if (read_err_info != NULL) {
1352             fprintf(stderr, "(%s)\n", read_err_info);
1353             g_free(read_err_info);
1354         }
1355         exit(2);
1356     }
1357
1358     if (verbose) {
1359         fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1360                 wtap_file_type_subtype_string(wtap_file_type_subtype(wth)));
1361     }
1362
1363     shb_hdr = wtap_file_get_shb_for_new_file(wth);
1364     idb_inf = wtap_file_get_idb_info(wth);
1365     nrb_hdr = wtap_file_get_nrb_for_new_file(wth);
1366
1367     /*
1368      * Now, process the rest, if any ... we only write if there is an extra
1369      * argument or so ...
1370      */
1371
1372     if ((argc - optind) >= 2) {
1373         if (out_frame_type == -2)
1374             out_frame_type = wtap_file_encap(wth);
1375
1376         for (i = optind + 2; i < argc; i++)
1377             if (add_selection(argv[i], &max_packet_number) == FALSE)
1378                 break;
1379
1380         if (keep_em == FALSE)
1381             max_packet_number = G_MAXUINT;
1382
1383         if (dup_detect || dup_detect_by_time) {
1384             for (i = 0; i < dup_window; i++) {
1385                 memset(&fd_hash[i].digest, 0, 16);
1386                 fd_hash[i].len = 0;
1387                 nstime_set_unset(&fd_hash[i].frame_time);
1388             }
1389         }
1390
1391         /* Read all of the packets in turn */
1392         while (wtap_read(wth, &read_err, &read_err_info, &data_offset)) {
1393             if (max_packet_number <= read_count)
1394                 break;
1395
1396             read_count++;
1397
1398             phdr = wtap_phdr(wth);
1399
1400             /* Extra actions for the first packet */
1401             if (read_count == 1) {
1402                 if (split_packet_count > 0 || secs_per_block > 0) {
1403                     if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
1404                         goto error_on_exit;
1405
1406                     filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1407                 } else {
1408                     filename = g_strdup(argv[optind+1]);
1409                 }
1410                 g_assert(filename);
1411
1412                 /* If we don't have an application name add Editcap */
1413                 if (shb_hdr->shb_user_appl == NULL) {
1414                     shb_hdr->shb_user_appl = g_strdup("Editcap " VERSION);
1415                 }
1416
1417                 pdh = editcap_dump_open(filename,
1418                                         snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1419                                         shb_hdr, idb_inf, nrb_hdr, &write_err);
1420
1421                 if (pdh == NULL) {
1422                     fprintf(stderr, "editcap: Can't open or create %s: %s\n",
1423                             filename, wtap_strerror(write_err));
1424                     goto error_on_exit;
1425                 }
1426             } /* first packet only handling */
1427
1428
1429             buf = wtap_buf_ptr(wth);
1430
1431             /*
1432              * Not all packets have time stamps. Only process the time
1433              * stamp if we have one.
1434              */
1435             if (phdr->presence_flags & WTAP_HAS_TS) {
1436                 if (nstime_is_unset(&block_start)) {
1437                     block_start = phdr->ts;
1438                 }
1439
1440                 if (secs_per_block > 0) {
1441                     while ((phdr->ts.secs - block_start.secs >  secs_per_block)
1442                            || (phdr->ts.secs - block_start.secs == secs_per_block
1443                                && phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1444
1445                         if (!wtap_dump_close(pdh, &write_err)) {
1446                             fprintf(stderr, "editcap: Error writing to %s: %s\n",
1447                                     filename, wtap_strerror(write_err));
1448                             goto error_on_exit;
1449                         }
1450                         block_start.secs = block_start.secs +  secs_per_block; /* reset for next interval */
1451                         g_free(filename);
1452                         filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1453                         g_assert(filename);
1454
1455                         if (verbose)
1456                             fprintf(stderr, "Continuing writing in file %s\n", filename);
1457
1458                         pdh = editcap_dump_open(filename,
1459                                                 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1460                                                 shb_hdr, idb_inf, nrb_hdr, &write_err);
1461
1462                         if (pdh == NULL) {
1463                             fprintf(stderr, "editcap: Can't open or create %s: %s\n",
1464                                     filename, wtap_strerror(write_err));
1465                             goto error_on_exit;
1466                         }
1467                     }
1468                 }
1469             }  /* time stamp handling */
1470
1471             if (split_packet_count > 0) {
1472                 /* time for the next file? */
1473                 if (written_count > 0 && written_count % split_packet_count == 0) {
1474                     if (!wtap_dump_close(pdh, &write_err)) {
1475                         fprintf(stderr, "editcap: Error writing to %s: %s\n",
1476                                 filename, wtap_strerror(write_err));
1477                         goto error_on_exit;
1478                     }
1479
1480                     g_free(filename);
1481                     filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1482                     g_assert(filename);
1483
1484                     if (verbose)
1485                         fprintf(stderr, "Continuing writing in file %s\n", filename);
1486
1487                     pdh = editcap_dump_open(filename,
1488                                             snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1489                                             shb_hdr, idb_inf, nrb_hdr, &write_err);
1490                     if (pdh == NULL) {
1491                         fprintf(stderr, "editcap: Can't open or create %s: %s\n",
1492                                 filename, wtap_strerror(write_err));
1493                         goto error_on_exit;
1494                     }
1495                 }
1496             } /* split packet handling */
1497
1498             if (check_startstop) {
1499                 /*
1500                  * Is the packet in the selected timeframe?
1501                  * If the packet has no time stamp, the answer is "no".
1502                  */
1503                 if (phdr->presence_flags & WTAP_HAS_TS)
1504                     ts_okay = (phdr->ts.secs >= starttime) && (phdr->ts.secs < stoptime);
1505                 else
1506                     ts_okay = FALSE;
1507             } else {
1508                 /*
1509                  * No selected timeframe, so all packets are "in the
1510                  * selected timeframe".
1511                  */
1512                 ts_okay = TRUE;
1513             }
1514
1515             if (ts_okay && ((!selected(count) && !keep_em)
1516                             || (selected(count) && keep_em))) {
1517
1518                 if (verbose && !dup_detect && !dup_detect_by_time)
1519                     fprintf(stderr, "Packet: %u\n", count);
1520
1521                 /* We simply write it, perhaps after truncating it; we could
1522                  * do other things, like modify it. */
1523
1524                 phdr = wtap_phdr(wth);
1525
1526                 if (snaplen != 0) {
1527                     /* Limit capture length to snaplen */
1528                     if (phdr->caplen > snaplen) {
1529                         /* Copy and change rather than modify returned phdr */
1530                         temp_phdr = *phdr;
1531                         temp_phdr.caplen = snaplen;
1532                         phdr = &temp_phdr;
1533                     }
1534                     /* If -L, also set reported length to snaplen */
1535                     if (adjlen && phdr->len > snaplen) {
1536                         /* Copy and change rather than modify returned phdr */
1537                         temp_phdr = *phdr;
1538                         temp_phdr.len = snaplen;
1539                         phdr = &temp_phdr;
1540                     }
1541                 }
1542
1543                 /* CHOP */
1544                 temp_phdr = *phdr;
1545                 handle_chopping(chop, &temp_phdr, phdr, &buf, adjlen);
1546                 phdr = &temp_phdr;
1547
1548                 if (phdr->presence_flags & WTAP_HAS_TS) {
1549                     /* Do we adjust timestamps to ensure strict chronological
1550                      * order? */
1551                     if (do_strict_time_adjustment) {
1552                         if (previous_time.secs || previous_time.nsecs) {
1553                             if (!strict_time_adj.is_negative) {
1554                                 nstime_t current;
1555                                 nstime_t delta;
1556
1557                                 current = phdr->ts;
1558
1559                                 nstime_delta(&delta, &current, &previous_time);
1560
1561                                 if (delta.secs < 0 || delta.nsecs < 0) {
1562                                     /*
1563                                      * A negative delta indicates that the current packet
1564                                      * has an absolute timestamp less than the previous packet
1565                                      * that it is being compared to.  This is NOT a normal
1566                                      * situation since trace files usually have packets in
1567                                      * chronological order (oldest to newest).
1568                                      */
1569                                     /* fprintf(stderr, "++out of order, need to adjust this packet!\n"); */
1570                                     temp_phdr = *phdr;
1571                                     temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
1572                                     temp_phdr.ts.nsecs = previous_time.nsecs;
1573                                     if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) {
1574                                         /* carry */
1575                                         temp_phdr.ts.secs++;
1576                                         temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
1577                                     } else {
1578                                         temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs;
1579                                     }
1580                                     phdr = &temp_phdr;
1581                                 }
1582                             } else {
1583                                 /*
1584                                  * A negative strict time adjustment is requested.
1585                                  * Unconditionally set each timestamp to previous
1586                                  * packet's timestamp plus delta.
1587                                  */
1588                                 temp_phdr = *phdr;
1589                                 temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
1590                                 temp_phdr.ts.nsecs = previous_time.nsecs;
1591                                 if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) {
1592                                     /* carry */
1593                                     temp_phdr.ts.secs++;
1594                                     temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
1595                                 } else {
1596                                     temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs;
1597                                 }
1598                                 phdr = &temp_phdr;
1599                             }
1600                         }
1601                         previous_time = phdr->ts;
1602                     }
1603
1604                     if (time_adj.tv.secs != 0) {
1605                         temp_phdr = *phdr;
1606                         if (time_adj.is_negative)
1607                             temp_phdr.ts.secs -= time_adj.tv.secs;
1608                         else
1609                             temp_phdr.ts.secs += time_adj.tv.secs;
1610                         phdr = &temp_phdr;
1611                     }
1612
1613                     if (time_adj.tv.nsecs != 0) {
1614                         temp_phdr = *phdr;
1615                         if (time_adj.is_negative) { /* subtract */
1616                             if (temp_phdr.ts.nsecs < time_adj.tv.nsecs) { /* borrow */
1617                                 temp_phdr.ts.secs--;
1618                                 temp_phdr.ts.nsecs += ONE_BILLION;
1619                             }
1620                             temp_phdr.ts.nsecs -= time_adj.tv.nsecs;
1621                         } else {                  /* add */
1622                             if (temp_phdr.ts.nsecs + time_adj.tv.nsecs > ONE_BILLION) {
1623                                 /* carry */
1624                                 temp_phdr.ts.secs++;
1625                                 temp_phdr.ts.nsecs += time_adj.tv.nsecs - ONE_BILLION;
1626                             } else {
1627                                 temp_phdr.ts.nsecs += time_adj.tv.nsecs;
1628                             }
1629                         }
1630                         phdr = &temp_phdr;
1631                     }
1632                 } /* time stamp adjustment */
1633
1634                 /* remove vlan info */
1635                 if (rem_vlan) {
1636                     /* TODO: keep casting const like this? change pointer instead of value? */
1637                     remove_vlan_info(phdr, buf, (guint32 *) &phdr->caplen);
1638                 }
1639
1640                 /* suppress duplicates by packet window */
1641                 if (dup_detect) {
1642                     if (is_duplicate(buf, phdr->caplen)) {
1643                         if (verbose) {
1644                             fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
1645                                     count, phdr->caplen);
1646                             for (i = 0; i < 16; i++)
1647                                 fprintf(stderr, "%02x",
1648                                         (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1649                             fprintf(stderr, "\n");
1650                         }
1651                         duplicate_count++;
1652                         count++;
1653                         continue;
1654                     } else {
1655                         if (verbose) {
1656                             fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
1657                                     count, phdr->caplen);
1658                             for (i = 0; i < 16; i++)
1659                                 fprintf(stderr, "%02x",
1660                                         (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1661                             fprintf(stderr, "\n");
1662                         }
1663                     }
1664                 } /* suppression of duplicates */
1665
1666                 if (phdr->presence_flags & WTAP_HAS_TS) {
1667                     /* suppress duplicates by time window */
1668                     if (dup_detect_by_time) {
1669                         nstime_t current;
1670
1671                         current.secs  = phdr->ts.secs;
1672                         current.nsecs = phdr->ts.nsecs;
1673
1674                         if (is_duplicate_rel_time(buf, phdr->caplen, &current)) {
1675                             if (verbose) {
1676                                 fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
1677                                         count, phdr->caplen);
1678                                 for (i = 0; i < 16; i++)
1679                                     fprintf(stderr, "%02x",
1680                                             (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1681                                 fprintf(stderr, "\n");
1682                             }
1683                             duplicate_count++;
1684                             count++;
1685                             continue;
1686                         } else {
1687                             if (verbose) {
1688                                 fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
1689                                         count, phdr->caplen);
1690                                 for (i = 0; i < 16; i++)
1691                                     fprintf(stderr, "%02x",
1692                                             (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1693                                 fprintf(stderr, "\n");
1694                             }
1695                         }
1696                     }
1697                 } /* suppress duplicates by time window */
1698
1699                 if (change_offset > phdr->caplen) {
1700                     fprintf(stderr, "change offset %u is longer than caplen %u in packet %u\n",
1701                         change_offset, phdr->caplen, count);
1702                 }
1703
1704                 /* Random error mutation */
1705                 if (err_prob > 0.0 && change_offset <= phdr->caplen) {
1706                     int real_data_start = 0;
1707
1708                     /* Protect non-protocol data */
1709                     if (wtap_file_type_subtype(wth) == WTAP_FILE_TYPE_SUBTYPE_CATAPULT_DCT2000)
1710                         real_data_start = find_dct2000_real_data(buf);
1711
1712                     real_data_start += change_offset;
1713
1714                     for (i = real_data_start; i < (int) phdr->caplen; i++) {
1715                         if (rand() <= err_prob * RAND_MAX) {
1716                             err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1717
1718                             if (err_type < ERR_WT_BIT) {
1719                                 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1720                                 err_type = ERR_WT_TOTAL;
1721                             } else {
1722                                 err_type -= ERR_WT_BYTE;
1723                             }
1724
1725                             if (err_type < ERR_WT_BYTE) {
1726                                 buf[i] = rand() / (RAND_MAX / 255 + 1);
1727                                 err_type = ERR_WT_TOTAL;
1728                             } else {
1729                                 err_type -= ERR_WT_BYTE;
1730                             }
1731
1732                             if (err_type < ERR_WT_ALNUM) {
1733                                 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1734                                 err_type = ERR_WT_TOTAL;
1735                             } else {
1736                                 err_type -= ERR_WT_ALNUM;
1737                             }
1738
1739                             if (err_type < ERR_WT_FMT) {
1740                                 if ((unsigned int)i < phdr->caplen - 2)
1741                                     g_strlcpy((char*) &buf[i], "%s", 2);
1742                                 err_type = ERR_WT_TOTAL;
1743                             } else {
1744                                 err_type -= ERR_WT_FMT;
1745                             }
1746
1747                             if (err_type < ERR_WT_AA) {
1748                                 for (j = i; j < (int) phdr->caplen; j++)
1749                                     buf[j] = 0xAA;
1750                                 i = phdr->caplen;
1751                             }
1752                         }
1753                     }
1754                 } /* random error mutation */
1755
1756                 /* Find a packet comment we may need to write */
1757                 if (frames_user_comments) {
1758                     const char *comment =
1759                         (const char*)g_tree_lookup(frames_user_comments, GUINT_TO_POINTER(read_count));
1760                     if (comment != NULL) {
1761                         /* Copy and change rather than modify returned phdr */
1762                         temp_phdr = *phdr;
1763                         temp_phdr.opt_comment = g_strdup(comment);
1764                         phdr = &temp_phdr;
1765                     }
1766                 }
1767
1768                 /* Attempt to dump out current frame to the output file */
1769                 if (!wtap_dump(pdh, phdr, buf, &write_err, &write_err_info)) {
1770                     switch (write_err) {
1771                     case WTAP_ERR_UNWRITABLE_ENCAP:
1772                         /*
1773                          * This is a problem with the particular frame we're
1774                          * writing and the file type and subtype we're
1775                          * writing; note that, and report the frame number
1776                          * and file type/subtype.
1777                          */
1778                         fprintf(stderr,
1779                                 "editcap: Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n",
1780                                 read_count, argv[optind],
1781                                 wtap_file_type_subtype_string(out_file_type_subtype));
1782                         break;
1783
1784                     case WTAP_ERR_PACKET_TOO_LARGE:
1785                         /*
1786                          * This is a problem with the particular frame we're
1787                          * writing and the file type and subtype we're
1788                          * writing; note that, and report the frame number
1789                          * and file type/subtype.
1790                          */
1791                         fprintf(stderr,
1792                                 "editcap: Frame %u of \"%s\" is too large for a \"%s\" file.\n",
1793                                 read_count, argv[optind],
1794                                 wtap_file_type_subtype_string(out_file_type_subtype));
1795                         break;
1796
1797                     case WTAP_ERR_UNWRITABLE_REC_TYPE:
1798                         /*
1799                          * This is a problem with the particular record we're
1800                          * writing and the file type and subtype we're
1801                          * writing; note that, and report the record number
1802                          * and file type/subtype.
1803                          */
1804                         fprintf(stderr,
1805                                 "editcap: Record %u of \"%s\" has a record type that can't be saved in a \"%s\" file.\n",
1806                                 read_count, argv[optind],
1807                                 wtap_file_type_subtype_string(out_file_type_subtype));
1808                         break;
1809
1810                     case WTAP_ERR_UNWRITABLE_REC_DATA:
1811                         /*
1812                          * This is a problem with the particular record we're
1813                          * writing and the file type and subtype we're
1814                          * writing; note that, and report the record number
1815                          * and file type/subtype.
1816                          */
1817                         fprintf(stderr,
1818                                 "editcap: Record %u of \"%s\" has data that can't be saved in a \"%s\" file.\n(%s)\n",
1819                                 read_count, argv[optind],
1820                                 wtap_file_type_subtype_string(out_file_type_subtype),
1821                                 write_err_info != NULL ? write_err_info : "no information supplied");
1822                         g_free(write_err_info);
1823                         break;
1824
1825                     default:
1826                         fprintf(stderr, "editcap: Error writing to %s: %s\n",
1827                                 filename, wtap_strerror(write_err));
1828                         break;
1829                     }
1830                     goto error_on_exit;
1831                 }
1832                 written_count++;
1833             }
1834             count++;
1835         }
1836
1837         g_free(fprefix);
1838         g_free(fsuffix);
1839
1840         if (read_err != 0) {
1841             /* Print a message noting that the read failed somewhere along the
1842              * line. */
1843             fprintf(stderr,
1844                     "editcap: An error occurred while reading \"%s\": %s.\n",
1845                     argv[optind], wtap_strerror(read_err));
1846             if (read_err_info != NULL) {
1847                 fprintf(stderr, "(%s)\n", read_err_info);
1848                 g_free(read_err_info);
1849             }
1850         }
1851
1852         if (!pdh) {
1853             /* No valid packages found, open the outfile so we can write an
1854              * empty header */
1855             g_free (filename);
1856             filename = g_strdup(argv[optind+1]);
1857
1858             pdh = editcap_dump_open(filename,
1859                                     snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
1860                                     shb_hdr, idb_inf, nrb_hdr, &write_err);
1861             if (pdh == NULL) {
1862                 fprintf(stderr, "editcap: Can't open or create %s: %s\n",
1863                         filename, wtap_strerror(write_err));
1864                 goto error_on_exit;
1865             }
1866         }
1867
1868         g_free(idb_inf);
1869         idb_inf = NULL;
1870
1871         if (!wtap_dump_close(pdh, &write_err)) {
1872             fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1873                     wtap_strerror(write_err));
1874             goto error_on_exit;
1875         }
1876         wtap_free_shb(shb_hdr);
1877         shb_hdr = NULL;
1878         wtap_free_nrb(nrb_hdr);
1879         nrb_hdr = NULL;
1880         g_free(filename);
1881
1882         if (frames_user_comments) {
1883             g_tree_destroy(frames_user_comments);
1884         }
1885     }
1886
1887     if (dup_detect) {
1888         fprintf(stderr, "%u packet%s seen, %u packet%s skipped with duplicate window of %i packets.\n",
1889                 count - 1, plurality(count - 1, "", "s"), duplicate_count,
1890                 plurality(duplicate_count, "", "s"), dup_window);
1891     } else if (dup_detect_by_time) {
1892         fprintf(stderr, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1893                 count - 1, plurality(count - 1, "", "s"), duplicate_count,
1894                 plurality(duplicate_count, "", "s"),
1895                 (long)relative_time_window.secs,
1896                 (long int)relative_time_window.nsecs);
1897     }
1898
1899     return 0;
1900
1901 error_on_exit:
1902     wtap_free_shb(shb_hdr);
1903     wtap_free_nrb(nrb_hdr);
1904     g_free(idb_inf);
1905     exit(2);
1906 }
1907
1908 /* Skip meta-information read from file to return offset of real
1909  * protocol data */
1910 static int
1911 find_dct2000_real_data(guint8 *buf)
1912 {
1913     int n = 0;
1914
1915     for (n = 0; buf[n] != '\0'; n++);   /* Context name */
1916     n++;
1917     n++;                                /* Context port number */
1918     for (; buf[n] != '\0'; n++);        /* Timestamp */
1919     n++;
1920     for (; buf[n] != '\0'; n++);        /* Protocol name */
1921     n++;
1922     for (; buf[n] != '\0'; n++);        /* Variant number (as string) */
1923     n++;
1924     for (; buf[n] != '\0'; n++);        /* Outhdr (as string) */
1925     n++;
1926     n += 2;                             /* Direction & encap */
1927
1928     return n;
1929 }
1930
1931 /*
1932  * We support up to 2 chopping regions in a single pass: one specified by the
1933  * positive chop length, and one by the negative chop length.
1934  */
1935 static void
1936 handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr,
1937                 const struct wtap_pkthdr *in_phdr, guint8 **buf,
1938                 gboolean adjlen)
1939 {
1940     /* Only packets can be chopped. */
1941     if (in_phdr->rec_type != REC_TYPE_PACKET)
1942         return;
1943
1944     /* If we're not chopping anything from one side, then the offset for that
1945      * side is meaningless. */
1946     if (chop.len_begin == 0)
1947         chop.off_begin_pos = chop.off_begin_neg = 0;
1948     if (chop.len_end == 0)
1949         chop.off_end_pos = chop.off_end_neg = 0;
1950
1951     if (chop.off_begin_neg < 0) {
1952         chop.off_begin_pos += in_phdr->caplen + chop.off_begin_neg;
1953         chop.off_begin_neg = 0;
1954     }
1955     if (chop.off_end_pos > 0) {
1956         chop.off_end_neg += chop.off_end_pos - in_phdr->caplen;
1957         chop.off_end_pos = 0;
1958     }
1959
1960     /* If we've crossed chopping regions, swap them */
1961     if (chop.len_begin && chop.len_end) {
1962         if (chop.off_begin_pos > ((int)in_phdr->caplen + chop.off_end_neg)) {
1963             int tmp_len, tmp_off;
1964
1965             tmp_off = in_phdr->caplen + chop.off_end_neg + chop.len_end;
1966             tmp_len = -chop.len_end;
1967
1968             chop.off_end_neg = chop.len_begin + chop.off_begin_pos - in_phdr->caplen;
1969             chop.len_end = -chop.len_begin;
1970
1971             chop.len_begin = tmp_len;
1972             chop.off_begin_pos = tmp_off;
1973         }
1974     }
1975
1976     /* Make sure we don't chop off more than we have available */
1977     if (in_phdr->caplen < (guint32)(chop.off_begin_pos - chop.off_end_neg)) {
1978         chop.len_begin = 0;
1979         chop.len_end = 0;
1980     }
1981     if ((guint32)(chop.len_begin - chop.len_end) >
1982         (in_phdr->caplen - (guint32)(chop.off_begin_pos - chop.off_end_neg))) {
1983         chop.len_begin = in_phdr->caplen - (chop.off_begin_pos - chop.off_end_neg);
1984         chop.len_end = 0;
1985     }
1986
1987     /* Handle chopping from the beginning.  Note that if a beginning offset
1988      * was specified, we need to keep that piece */
1989     if (chop.len_begin > 0) {
1990         *out_phdr = *in_phdr;
1991
1992         if (chop.off_begin_pos > 0) {
1993             memmove(*buf + chop.off_begin_pos,
1994                     *buf + chop.off_begin_pos + chop.len_begin,
1995                     out_phdr->caplen - chop.len_begin);
1996         } else {
1997             *buf += chop.len_begin;
1998         }
1999         out_phdr->caplen -= chop.len_begin;
2000
2001         if (adjlen) {
2002             if (in_phdr->len > (guint32)chop.len_begin)
2003                 out_phdr->len -= chop.len_begin;
2004             else
2005                 out_phdr->len = 0;
2006         }
2007         in_phdr = out_phdr;
2008     }
2009
2010     /* Handle chopping from the end.  Note that if an ending offset was
2011      * specified, we need to keep that piece */
2012     if (chop.len_end < 0) {
2013         *out_phdr = *in_phdr;
2014
2015         if (chop.off_end_neg < 0) {
2016             memmove(*buf + (gint)out_phdr->caplen + (chop.len_end + chop.off_end_neg),
2017                     *buf + (gint)out_phdr->caplen + chop.off_end_neg,
2018                     -chop.off_end_neg);
2019         }
2020         out_phdr->caplen += chop.len_end;
2021
2022         if (adjlen) {
2023             if (((signed int) in_phdr->len + chop.len_end) > 0)
2024                 out_phdr->len += chop.len_end;
2025             else
2026                 out_phdr->len = 0;
2027         }
2028         /*in_phdr = out_phdr;*/
2029     }
2030 }
2031
2032 /*
2033  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
2034  *
2035  * Local variables:
2036  * c-basic-offset: 4
2037  * tab-width: 8
2038  * indent-tabs-mode: nil
2039  * End:
2040  *
2041  * vi: set shiftwidth=4 tabstop=8 expandtab:
2042  * :indentSize=4:tabSize=8:noTabs=true:
2043  */
2044