Use "tvb_get_ntohieee_float()" to fetch floating-point numbers.
[obnox/wireshark/wip.git] / editcap.c
1 /* Edit capture files.  We can delete records, adjust timestamps, or
2  * simply convert from one format to another format.
3  *
4  * $Id: editcap.c,v 1.22 2002/03/31 20:39:08 guy Exp $
5  *
6  * Originally written by Richard Sharpe.
7  * Improved by Guy Harris.
8  * Further improved by Richard Sharpe.
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <glib.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26
27 #ifdef HAVE_WINSOCK_H
28 #include <winsock.h>
29 #endif
30
31 #include <string.h>
32 #include "wtap.h"
33
34 #ifdef NEED_GETOPT_H
35 #include "getopt.h"
36 #endif
37
38 /*
39  * Some globals so we can pass things to various routines
40  */
41
42 struct select_item {
43
44   int inclusive;
45   int first, second;
46
47 };
48
49 #define ONE_MILLION 1000000
50
51 struct time_adjustment {
52   struct timeval tv;
53   int is_negative;
54 };
55
56 struct select_item selectfrm[100];
57 int max_selected = -1;
58 static int count = 1;
59 static int keep_em = 0;
60 static int out_file_type = WTAP_FILE_PCAP;   /* default to "libpcap"   */
61 static int out_frame_type = -2;              /* Leave frame type alone */
62 static int verbose = 0;                      /* Not so verbose         */
63 static unsigned int snaplen = 0;             /* No limit               */
64 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
65
66 /* Add a selection item, a simple parser for now */
67
68 void add_selection(char *sel) 
69 {
70   char *locn;
71   char *next;
72
73   if (max_selected == (sizeof(selectfrm)/sizeof(struct select_item)) - 1)
74     return;
75
76   printf("Add_Selected: %s\n", sel);
77
78   if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
79
80     printf("Not inclusive ...");
81
82     max_selected++;
83     selectfrm[max_selected].inclusive = 0;
84     selectfrm[max_selected].first = atoi(sel);
85
86     printf(" %i\n", selectfrm[max_selected].first);
87
88   }
89   else {
90
91     printf("Inclusive ...");
92
93     next = locn + 1;
94     max_selected++;
95     selectfrm[max_selected].inclusive = 1;
96     selectfrm[max_selected].first = atoi(sel);
97     selectfrm[max_selected].second = atoi(next);
98
99     printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
100
101   }
102
103
104 }
105
106 /* Was the record selected? */
107
108 int selected(int recno)
109 {
110   int i = 0;
111
112   for (i = 0; i<= max_selected; i++) {
113
114     if (selectfrm[i].inclusive) {
115       if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
116         return 1;
117     }
118     else {
119       if (recno == selectfrm[i].first)
120         return 1;
121     }
122   }
123
124   return 0;
125
126 }
127
128 /* An argument to the callback routine */
129
130 typedef struct {
131         char    *filename;
132         wtap_dumper *pdh;
133 } callback_arg;
134
135 /*
136  *The callback routine that is called for each frame in the input file
137  */
138
139 static void
140 edit_callback(u_char *user, const struct wtap_pkthdr *phdr, long offset _U_,
141     union wtap_pseudo_header *pseudo_header, const u_char *buf) 
142 {
143   callback_arg *argp = (callback_arg *)user;
144   int err;
145   struct wtap_pkthdr snap_phdr;
146
147   if ((!selected(count) && !keep_em) ||
148       (selected(count) && keep_em)) {
149
150     if (verbose)
151       printf("Record: %u\n", count);
152
153     /* We simply write it, perhaps after truncating it; we could do other
154        things, like modify it. */
155
156     if (snaplen != 0 && phdr->caplen > snaplen) {
157       snap_phdr = *phdr;
158       snap_phdr.caplen = snaplen;
159       phdr = &snap_phdr;
160     }
161
162     /* assume that if the frame's tv_sec is 0, then
163      * the timestamp isn't supported */
164     if (phdr->ts.tv_sec > 0 && time_adj.tv.tv_sec != 0) {
165       snap_phdr = *phdr;
166       if (time_adj.is_negative)
167         snap_phdr.ts.tv_sec -= time_adj.tv.tv_sec;
168       else
169         snap_phdr.ts.tv_sec += time_adj.tv.tv_sec;
170       phdr = &snap_phdr;
171     }
172
173     /* assume that if the frame's tv_sec is 0, then
174      * the timestamp isn't supported */
175     if (phdr->ts.tv_sec > 0 && time_adj.tv.tv_usec != 0) {
176       snap_phdr = *phdr;
177       if (time_adj.is_negative) { /* subtract */
178         if (snap_phdr.ts.tv_usec < time_adj.tv.tv_usec) { /* borrow */
179           snap_phdr.ts.tv_sec--;
180           snap_phdr.ts.tv_usec += ONE_MILLION;
181         }
182         snap_phdr.ts.tv_usec -= time_adj.tv.tv_usec;
183       } else {                  /* add */
184         if (snap_phdr.ts.tv_usec + time_adj.tv.tv_usec > ONE_MILLION) {
185           /* carry */
186           snap_phdr.ts.tv_sec++;
187           snap_phdr.ts.tv_usec += time_adj.tv.tv_usec - ONE_MILLION;
188         } else {
189           snap_phdr.ts.tv_usec += time_adj.tv.tv_usec;
190         }
191       }
192       phdr = &snap_phdr;
193     }
194       
195     if (!wtap_dump(argp->pdh, phdr, pseudo_header, buf, &err)) {
196
197       fprintf(stderr, "editcap: Error writing to %s: %s\n", argp->filename,
198         wtap_strerror(err));
199       exit(1);
200
201     }
202
203   }
204
205   count++;
206
207 }
208
209 static void
210 set_time_adjustment(char *optarg)
211 {
212   char *frac, *end;
213   long val;
214   int frac_digits;
215
216   if (!optarg)
217     return;
218
219   /* skip leading whitespace */
220   while (*optarg == ' ' || *optarg == '\t') {
221       optarg++;
222   }
223
224   /* check for a negative adjustment */
225   if (*optarg == '-') {
226       time_adj.is_negative = 1;
227       optarg++;
228   }
229
230   /* collect whole number of seconds, if any */
231   if (*optarg == '.') {         /* only fractional (i.e., .5 is ok) */
232       val  = 0;
233       frac = optarg;
234   } else {
235       val = strtol(optarg, &frac, 10);
236       if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) {
237           fprintf(stderr, "editcap: \"%s\" is not a valid time adjustment\n",
238                   optarg);
239           exit(1);
240       }
241       if (val < 0) {            /* implies '--' since we caught '-' above  */
242           fprintf(stderr, "editcap: \"%s\" is not a valid time adjustment\n",
243                   optarg);
244           exit(1);
245       }
246   }
247   time_adj.tv.tv_sec = val;
248
249   /* now collect the partial seconds, if any */
250   if (*frac != '\0') {             /* chars left, so get fractional part */
251     val = strtol(&(frac[1]), &end, 10);
252     if (*frac != '.' || end == NULL || end == frac
253         || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
254       fprintf(stderr, "editcap: \"%s\" is not a valid time adjustment\n",
255               optarg);
256       exit(1);
257     }
258   }
259   else {
260     return;                     /* no fractional digits */
261   }
262
263   /* adjust fractional portion from fractional to numerator
264    * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
265   if (frac && end) {            /* both are valid */
266     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
267     while(frac_digits < 6) {    /* this is frac of 10^6 */
268       val *= 10;
269       frac_digits++;
270     }
271   }
272   time_adj.tv.tv_usec = val;
273 }
274
275 void usage()
276 {
277   int i;
278   const char *string;
279
280   fprintf(stderr, "Usage: editcap [-r] [-h] [-v] [-T <encap type>] [-F <capture type>]\n");
281   fprintf(stderr, "               [-s <snaplen>] [-t <time adjustment\n");
282   fprintf(stderr, "               <infile> <outfile> [ <record#>[-<record#>] ... ]\n");
283   fprintf(stderr, "  where\t-r specifies that the records specified should be kept, not deleted, \n");
284   fprintf(stderr, "                           default is to delete\n");
285   fprintf(stderr, "       \t-v specifies verbose operation, default is silent\n");
286   fprintf(stderr, "       \t-h produces this help listing.\n");
287   fprintf(stderr, "       \t-T <encap type> specifies the encapsulation type to use:\n");
288   for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
289       string = wtap_encap_short_string(i);
290       if (string != NULL)
291         fprintf(stderr, "       \t    %s - %s\n",
292           string, wtap_encap_string(i));
293   }
294   fprintf(stderr, "       \t    default is the same as the input file\n");
295   fprintf(stderr, "       \t-F <capture type> specifies the capture file type to write:\n");
296   for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
297     if (wtap_dump_can_open(i))
298       fprintf(stderr, "       \t    %s - %s\n",
299         wtap_file_type_short_string(i), wtap_file_type_string(i));
300   }
301   fprintf(stderr, "       \t    default is libpcap\n");
302   fprintf(stderr, "       \t-s <snaplen> specifies that packets should be truncated to\n");
303   fprintf(stderr, "       \t   <snaplen> bytes of data\n");
304   fprintf(stderr, "       \t-t <time adjustment> specifies the time adjustment\n");
305   fprintf(stderr, "       \t   to be applied to selected packets\n");
306   fprintf(stderr, "\n      \t    A range of records can be specified as well\n");
307 }
308
309 int main(int argc, char *argv[])
310
311 {
312   wtap *wth;
313   int i, err;
314   callback_arg args;
315   extern char *optarg;
316   extern int optind;
317   int opt;
318   char *p;
319   int snapshot_length;
320
321   /* Process the options first */
322
323   while ((opt = getopt(argc, argv, "T:F:rvs:t:h")) !=-1) {
324
325     switch (opt) {
326
327     case 'T':
328       out_frame_type = wtap_short_string_to_encap(optarg);
329       if (out_frame_type < 0) {
330         fprintf(stderr, "editcap: \"%s\" is not a valid encapsulation type\n",
331             optarg);
332         exit(1);
333       }
334       break;
335       
336     case 'F':
337       out_file_type = wtap_short_string_to_file_type(optarg);
338       if (out_file_type < 0) {
339         fprintf(stderr, "editcap: \"%s\" is not a valid capture file type\n",
340             optarg);
341         exit(1);
342       }
343       break;
344
345     case 'v':
346       verbose = !verbose;  /* Just invert */
347       break;
348
349     case 'r':
350       keep_em = !keep_em;  /* Just invert */
351       break;
352
353     case 's':
354       snaplen = strtol(optarg, &p, 10);
355       if (p == optarg || *p != '\0') {
356         fprintf(stderr, "editcap: \"%s\" is not a valid snapshot length\n",
357             optarg);
358         exit(1);
359       }
360       break;
361
362     case 't':
363       set_time_adjustment(optarg);
364       break;
365
366     case 'h':
367       usage();
368       exit(1);
369       break;
370
371     case '?':              /* Bad options if GNU getopt */
372       usage();
373       exit(1);
374       break;
375
376     }
377
378   }
379
380 #ifdef DEBUG
381   printf("Optind = %i, argc = %i\n", optind, argc);
382 #endif
383
384   if ((argc - optind) < 1) {
385
386     usage();
387     exit(1);
388
389   }
390
391   wth = wtap_open_offline(argv[optind], &err, FALSE);
392
393   if (!wth) {
394
395     fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
396         wtap_strerror(err));
397     exit(1);
398
399   }
400
401   if (verbose) {
402
403     fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
404             wtap_file_type_string(wtap_file_type(wth)));
405
406   }
407
408   /*
409    * Now, process the rest, if any ... we only write if there is an extra
410    * argument or so ...
411    */
412
413   if ((argc - optind) >= 2) {
414
415     args.filename = argv[optind + 1];
416     if (out_frame_type == -2)
417       out_frame_type = wtap_file_encap(wth);
418
419     snapshot_length = wtap_snapshot_length(wth);
420     if (snapshot_length == 0) {
421       /* Snapshot length of input file not known. */
422       snapshot_length = WTAP_MAX_PACKET_SIZE;
423     }
424     args.pdh = wtap_dump_open(argv[optind + 1], out_file_type,
425                               out_frame_type, wtap_snapshot_length(wth), &err);
426     if (args.pdh == NULL) {
427
428       fprintf(stderr, "editcap: Can't open or create %s: %s\n", argv[optind+1],
429               wtap_strerror(err));
430       exit(1);
431
432     }
433
434     for (i = optind + 2; i < argc; i++)
435       add_selection(argv[i]);
436
437     wtap_loop(wth, 0, edit_callback, (char *)&args, &err);
438
439     if (!wtap_dump_close(args.pdh, &err)) {
440
441       fprintf(stderr, "editcap: Error writing to %s: %s\n", argv[2],
442               wtap_strerror(err));
443       exit(1);
444
445     }
446   }
447
448   return 0;
449 }
450