Rename WTAP_ERR_UNSUPPORTED_ENCAP to WTAP_ERR_UNWRITABLE_ENCAP.
[metze/wireshark/wip.git] / wiretap / k12text.l
1 /*
2  * We don't use input, so don't generate code for it.
3  */
4 %option noinput
5
6 /*
7  * We don't use unput, so don't generate code for it.
8  */
9 %option nounput
10
11 /*
12  * We don't read from the terminal.
13  */
14 %option never-interactive
15
16 /*
17  * Prefix scanner routines with "K12Text_" rather than "yy", so this scanner
18  * can coexist with other scanners.
19  */
20 %option prefix="K12Text_"
21
22 %option outfile="k12text.c"
23
24 /* Options useful for debugging                         */
25 /* noline:  Prevent generation of #line directives      */
26 /*          Seems to be required when using the         */
27 /*          Windows VS debugger so as to be able        */
28 /*          to properly step through the code and       */
29 /*          set breakpoints & etc using the             */
30 /*          k12text.c file rather than the              */
31 /*          k12text.l file                              */
32 /*      XXX: %option noline gives an error message:     */
33 /*          "unrecognized %option: line"                */
34 /*          with flex 2.5.35; the --noline              */
35 /*          command-line option works OK.               */
36 /*                                                      */
37 /* debug:   Do output of "rule acceptance" info         */
38 /*          during parse                                */
39 /*                                                      */
40 /* %option noline  */
41 /* %option debug   */
42
43 %{
44 /* k12text.l
45  *
46  * Wiretap Library
47  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
48  *
49  * This program is free software; you can redistribute it and/or
50  * modify it under the terms of the GNU General Public License
51  * as published by the Free Software Foundation; either version 2
52  * of the License, or (at your option) any later version.
53  *
54  * This program is distributed in the hope that it will be useful,
55  * but WITHOUT ANY WARRANTY; without even the implied warranty of
56  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
57  * GNU General Public License for more details.
58  *
59  * You should have received a copy of the GNU General Public License
60  * along with this program; if not, write to the Free Software
61  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
62  */
63
64  /*
65   * TODO:
66   *   - fix timestamps after midnight
67   *   - verify encapsulations
68   */
69
70 #include "config.h"
71 #include <stdlib.h>
72 #include <string.h>
73 #include <errno.h>
74 #include <time.h>
75 #include "wtap-int.h"
76 #include "wtap.h"
77 #include "file_wrappers.h"
78 #include <wsutil/buffer.h>
79 #include "k12.h"
80 #include "k12text_lex.h"
81
82 #ifndef HAVE_UNISTD_H
83 #define YY_NO_UNISTD_H
84 #endif
85
86 static guint g_h;
87 static guint g_m;
88 static guint g_s;
89 static guint g_ms;
90 static guint g_ns;
91 static gint g_encap;
92 static guint8 bb[WTAP_MAX_PACKET_SIZE];
93 static guint ii;
94 static gboolean is_k12text;
95 static gboolean at_eof;
96 static guint junk_chars;
97 static void finalize_frame(void);
98 static gchar* error_str;
99 static guint64 file_bytes_read;
100 static gboolean ok_frame;
101 static FILE_T yy_fh;
102
103 #define KERROR(text) do { error_str = g_strdup(text); yyterminate(); } while(0)
104 #define SET_HOURS(text) g_h = (guint) strtoul(text,NULL,10)
105 #define SET_MINUTES(text) g_m = (guint) strtoul(text,NULL,10)
106 #define SET_SECONDS(text) g_s = (guint) strtoul(text,NULL,10)
107 #define SET_MS(text) g_ms = (guint) strtoul(text,NULL,10)
108 #define SET_NS(text) g_ns = (guint) strtoul(text,NULL,10)
109 #define ADD_BYTE(text) do {if (ii >= WTAP_MAX_PACKET_SIZE) {KERROR("frame too large");} bb[ii++] = (guint8)strtoul(text,NULL,16); } while(0)
110 #define FINALIZE_FRAME() finalize_frame()
111 /*~ #define ECHO*/
112 #define YY_USER_ACTION file_bytes_read += yyleng;
113 #define YY_INPUT(buf,result,max_size) { int c = file_getc(yy_fh);  result = (c==EOF) ? YY_NULL : (buf[0] = c, 1); }
114
115 #define MAX_JUNK 400000
116 #define ECHO
117
118 /*
119  * Private per-file data.
120  */
121 typedef struct {
122         /*
123          * The file position after the end of the previous frame processed by
124          * k12text_read.
125          *
126          * We need to keep this around, and seek to it at the beginning of
127          * each call to k12text_read(), since the lexer undoubtedly did some
128          * amount of look-ahead when processing the previous frame.
129          */
130         gint64  next_frame_offset;
131 } k12text_t;
132 %}
133 start_timestamp \053[\055]{9}\053[\055]{15,100}\053[\055]{10,100}\053
134 oneormoredigits [0-9]+:
135 twodigits [0-9][0-9]
136 colon :
137 comma ,
138 threedigits [0-9][0-9][0-9]
139 start_bytes \174\060\040\040\040\174
140 bytes_junk \174[A-F0-9][A-F0-9\040][A-F0-9\040][A-F0-9\040]\174
141 byte [a-f0-9][a-f0-9]\174
142 end_bytes \015?\012\015?\012
143 eth ETHER
144 mtp2 MTP-L2
145 sscop SSCOP
146 sscfnni SSCF
147 hdlc HDLC
148
149 %START MAGIC NEXT_FRAME HOURS MINUTES M2S SECONDS S2M MS M2N NS ENCAP STARTBYTES BYTE
150 %%
151 <MAGIC>{start_timestamp}  { is_k12text = TRUE; yyterminate(); }
152
153 <MAGIC>. { if (++ junk_chars > MAX_JUNK) { is_k12text = FALSE;  yyterminate(); } }
154
155 <NEXT_FRAME>{start_timestamp} {BEGIN(HOURS); }
156 <HOURS>{oneormoredigits} { SET_HOURS(yytext); BEGIN(MINUTES); }
157 <MINUTES>{twodigits} { SET_MINUTES(yytext); BEGIN(M2S);}
158 <M2S>{colon} { BEGIN(SECONDS);}
159 <SECONDS>{twodigits} { SET_SECONDS(yytext); BEGIN(S2M); }
160 <S2M>{comma}  { BEGIN(MS); }
161 <MS>{threedigits} { SET_MS(yytext); BEGIN(M2N);  }
162 <M2N>{comma}  { BEGIN(NS); }
163 <NS>{threedigits} { SET_NS(yytext); BEGIN(ENCAP);}
164 <ENCAP>{eth} {g_encap = WTAP_ENCAP_ETHERNET; BEGIN(STARTBYTES); }
165 <ENCAP>{mtp2} {g_encap = WTAP_ENCAP_MTP2; BEGIN(STARTBYTES); }
166 <ENCAP>{sscop} {g_encap = WTAP_ENCAP_ATM_PDUS; BEGIN(STARTBYTES); }
167 <ENCAP>{sscfnni} {g_encap = WTAP_ENCAP_MTP3; BEGIN(STARTBYTES); }
168 <ENCAP>{hdlc} {g_encap = WTAP_ENCAP_CHDLC; BEGIN(STARTBYTES); }
169 <ENCAP,STARTBYTES>{start_bytes} { fprintf(stderr, "OUCH: %s\b", yytext); BEGIN(BYTE); }
170 <BYTE>{byte} { ADD_BYTE(yytext); }
171 <BYTE>{bytes_junk} ;
172 <BYTE>{end_bytes} { FINALIZE_FRAME(); yyterminate(); }
173
174 . {  if (++junk_chars > MAX_JUNK) { KERROR("too much junk");  } }
175 <<EOF>> { at_eof = TRUE; yyterminate(); }
176
177 %%
178
179 static void finalize_frame(void) {
180         ok_frame = TRUE;
181 }
182
183 /* Fill in pkthdr */
184
185 static gboolean
186 k12text_set_headers(struct wtap_pkthdr *phdr, int *err, gchar **err_info)
187 {
188         phdr->rec_type = REC_TYPE_PACKET;
189         phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
190
191         phdr->ts.secs = 946681200 + (3600*g_h) + (60*g_m) + g_s;
192         phdr->ts.nsecs = 1000000*g_ms + 1000*g_ns;
193
194         phdr->caplen = phdr->len = ii;
195
196         phdr->pkt_encap = g_encap;
197
198         /* The file-encap is WTAP_ENCAP_PER_PACKET */
199         switch(g_encap) {
200             case WTAP_ENCAP_ETHERNET:
201                     phdr->pseudo_header.eth.fcs_len = 0;
202                     break;
203             case WTAP_ENCAP_MTP3:
204             case WTAP_ENCAP_CHDLC:
205                     /* no pseudo_header to fill in for these types */
206                     break;
207             case WTAP_ENCAP_MTP2:      /* not (yet) supported           */
208                     /* XXX: I don't know how to fill in the             */
209                     /* pseudo_header for these types.                   */
210                     *err = WTAP_ERR_UNSUPPORTED;
211                     *err_info = g_strdup("k12text: MTP2 packets not yet supported");
212                     return FALSE;
213             case WTAP_ENCAP_ATM_PDUS:  /* not (yet) supported           */
214                     /* XXX: I don't know how to fill in the             */
215                     /* pseudo_header for these types.                   */
216                     *err = WTAP_ERR_UNSUPPORTED;
217                     *err_info = g_strdup("k12text: SSCOP packets not yet supported");
218                     return FALSE;
219             default:
220                     *err = WTAP_ERR_UNSUPPORTED;
221                     *err_info = g_strdup("k12text: unknown encapsulation type");
222                     return FALSE;
223         }
224         return TRUE;
225 }
226
227 /* Note: k12text_reset is called each time data is to be processed from */
228 /*       a file. This ensures that no "state" from a previous read is   */
229 /*       used (such as the lexer look-ahead buffer, file_handle, file   */
230 /*       position and so on. This allows a single lexer buffer to be    */
231 /*       used even when multiple files are open simultaneously (as for  */
232 /*       a file merge).                                                 */
233
234 static void
235 k12text_reset(FILE_T fh)
236 {
237         yy_fh = fh;
238         yyrestart(0);
239         g_encap = WTAP_ENCAP_UNKNOWN;
240         ok_frame = FALSE;
241         is_k12text = FALSE;
242         at_eof = FALSE;
243         junk_chars = 0;
244         error_str = NULL;
245         file_bytes_read=0;
246         g_h=0;
247         g_m=0;
248         g_s=0;
249         g_ns=0;
250         g_ms=0;
251         ii=0;
252 }
253
254 static gboolean
255 k12text_read(wtap *wth, int *err, char ** err_info, gint64 *data_offset)
256 {
257         k12text_t *k12text = (k12text_t *)wth->priv;
258
259         /*
260          * We seek to the file position after the end of the previous frame
261          * processed by k12text_read(), since the lexer undoubtedly did some
262          * amount of look-ahead when processing the previous frame.
263          *
264          * We also clear out any lexer state (eg: look-ahead buffer) and
265          * init vars set by lexer.
266          */
267
268         if ( file_seek(wth->fh, k12text->next_frame_offset, SEEK_SET, err) == -1) {
269                 return FALSE;
270         }
271         k12text_reset(wth->fh);         /* init lexer buffer and vars set by lexer */
272
273         BEGIN(NEXT_FRAME);
274         yylex();
275
276         if (ok_frame == FALSE) {
277                 if (at_eof) {
278                         *err = 0;
279                         *err_info = NULL;
280                 } else {
281                         *err = WTAP_ERR_BAD_FILE;
282                         *err_info = error_str;
283                 }
284                 return FALSE;
285         }
286
287         *data_offset = k12text->next_frame_offset;       /* file position for beginning of this frame   */
288         k12text->next_frame_offset += file_bytes_read;   /* file position after end of this frame       */
289
290         if (!k12text_set_headers(&wth->phdr, err, err_info))
291                 return FALSE;
292
293         ws_buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
294         memcpy(ws_buffer_start_ptr(wth->frame_buffer), bb, wth->phdr.caplen);
295
296         return TRUE;
297 }
298
299 static gboolean
300 k12text_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr, Buffer *buf, int *err, char **err_info)
301 {
302         if ( file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
303                 return FALSE;
304         }
305         k12text_reset(wth->random_fh);          /* init lexer buffer and vars set by lexer */
306
307         BEGIN(NEXT_FRAME);
308         yylex();
309
310         if (ok_frame == FALSE) {
311                 *err = WTAP_ERR_BAD_FILE;
312                 if (at_eof) {
313                         /* What happened ? The desired frame was previously read without a problem */
314                         *err_info = g_strdup("Unexpected EOF (program error ?)");
315                 } else {
316                         *err_info = error_str;
317                 }
318                 return FALSE;
319         }
320
321         if (!k12text_set_headers(phdr, err, err_info))
322                 return FALSE;
323
324         ws_buffer_assure_space(buf, phdr->caplen);
325         memcpy(ws_buffer_start_ptr(buf), bb, phdr->caplen);
326
327         return TRUE;
328 }
329
330 wtap_open_return_val
331 k12text_open(wtap *wth, int *err, gchar **err_info _U_)
332 {
333         k12text_t *k12text;
334
335         k12text_reset(wth->fh);       /* init lexer buffer and vars set by lexer */
336
337         BEGIN(MAGIC);
338         yylex();
339
340         if (! is_k12text) return WTAP_OPEN_NOT_MINE;
341
342         if ( file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
343                 return WTAP_OPEN_ERROR;
344         }
345
346         k12text = (k12text_t *)g_malloc(sizeof(k12text_t));
347         wth->priv = (void *)k12text;
348         k12text->next_frame_offset = 0;
349         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_K12TEXT;
350         wth->file_encap = WTAP_ENCAP_PER_PACKET;
351         wth->snapshot_length = 0;
352         wth->subtype_read = k12text_read;
353         wth->subtype_seek_read = k12text_seek_read;
354         wth->file_tsprec = WTAP_TSPREC_NSEC;
355
356         return WTAP_OPEN_MINE;
357 }
358
359
360 static const struct { int e; const char* s; } encaps[] = {
361         { WTAP_ENCAP_ETHERNET, "ETHER" },
362         { WTAP_ENCAP_MTP2, "MTP-L2" },
363         { WTAP_ENCAP_ATM_PDUS, "SSCOP" },
364         { WTAP_ENCAP_MTP3, "SSCF" },
365         { WTAP_ENCAP_CHDLC, "HDLC" },
366         /* ... */
367         { 0, NULL }
368 };
369
370 static gboolean
371 k12text_dump(wtap_dumper *wdh _U_, const struct wtap_pkthdr *phdr,
372              const guint8 *pd, int *err) {
373 #define K12BUF_SIZE 196808
374         char *buf;
375         size_t left = K12BUF_SIZE;
376         size_t wl;
377         char *p;
378         const char* str_enc;
379         guint i;
380         guint ns;
381         guint ms;
382         gboolean ret;
383         struct tm *tmp;
384
385         /* Don't write anything bigger than we're willing to read. */
386         if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
387                 *err = WTAP_ERR_PACKET_TOO_LARGE;
388                 return FALSE;
389         }
390
391         str_enc = NULL;
392         for(i=0; encaps[i].s; i++) {
393                 if (phdr->pkt_encap == encaps[i].e) {
394                         str_enc = encaps[i].s;
395                         break;
396                 }
397         }
398         if (str_enc == NULL) {
399                 /*
400                  * That encapsulation type is not supported.  Fail.
401                  */
402                 *err = WTAP_ERR_UNWRITABLE_ENCAP;
403                 return FALSE;
404         }
405
406         buf = (char *)g_malloc(K12BUF_SIZE);
407         p = buf;
408
409         ms = phdr->ts.nsecs / 1000000;
410         ns = (phdr->ts.nsecs - (1000000*ms))/1000;
411
412         tmp = gmtime(&phdr->ts.secs);
413         if (tmp == NULL)
414                 g_snprintf(p, 90, "+---------+---------------+----------+\r\nXX:XX:XX,");
415         else
416                 strftime(p, 90, "+---------+---------------+----------+\r\n%H:%M:%S,", tmp);
417         wl = strlen(p);
418         p += wl;
419         left -= wl;
420
421         wl = g_snprintf(p, (gulong)left, "%.3d,%.3d   %s\r\n|0   |", ms, ns, str_enc);
422         p += wl;
423         left -= wl;
424
425         for(i = 0; i < phdr->caplen && left > 2; i++) {
426                 wl = g_snprintf(p, (gulong)left, "%.2x|", pd[i]);
427                 p += wl;
428                 left -= wl;
429         }
430
431         wl = g_snprintf(p, (gulong)left, "\r\n\r\n");
432         left -= wl;
433
434         ret = wtap_dump_file_write(wdh, buf, K12BUF_SIZE - left, err);
435
436         g_free(buf);
437         return ret;
438 }
439
440
441 gboolean
442 k12text_dump_open(wtap_dumper *wdh, int *err _U_)
443 {
444     wdh->subtype_write = k12text_dump;
445
446     return TRUE;
447 }
448
449 int
450 k12text_dump_can_write_encap(int encap)
451 {
452     switch (encap) {
453         case WTAP_ENCAP_PER_PACKET:
454         case WTAP_ENCAP_ETHERNET:
455         case WTAP_ENCAP_MTP3:
456         case WTAP_ENCAP_CHDLC:
457                 return 0;
458         case WTAP_ENCAP_MTP2:
459         case WTAP_ENCAP_ATM_PDUS:
460         default:
461                 return WTAP_ERR_UNWRITABLE_ENCAP;
462     }
463 }
464
465 /*
466  * We want to stop processing when we get to the end of the input.
467  * (%option noyywrap is not used because if used then
468  * some flex versions (eg: 2.5.35) generate code which causes
469  * warnings by the Windows VC compiler).
470  */
471
472 int yywrap(void) {
473     return 1;
474 }