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