Use encap=WTAP_ENCAP_UNKNOWN if encap can't be determined from the file frame.
[metze/wireshark/wip.git] / wiretap / k12text.l
1 /*
2  * We don't use unput, so don't generate code for it.
3  */
4 %option nounput
5
6 /*
7  * We don't read from the terminal.
8  */
9 %option never-interactive
10
11 /*
12  * Prefix scanner routines with "K12Text_" rather than "yy", so this scanner
13  * can coexist with other scanners.
14  */
15 %option prefix="K12Text_"
16
17 %option outfile="k12text.c"
18
19 /* Options useful for debugging                    */
20 /* noline:  Prevent generation of #line directives */
21 /*          Seems to be required when using the    */
22 /*           Windows VS debugger so as to be able  */
23 /*           to properly step through the code and */
24 /*           set breakpoints & etc using the       */
25 /*           k12text.c file rather than the        */
26 /*           k12text.l file                        */
27 /*     XXX: %option noline gives an error message: */
28 /*          "unrecognized %option: line"           */
29 /*          with Cygwin flex 2.5.35; the --noline  */
30 /*          command-line option works OK.          */
31 /*                                                 */
32 /* debug:   Do output of "rule acceptance" info    */
33 /*           during parse                          */ 
34 /*                                                 */
35 /* %option line  */
36 /* %option debug */
37
38 %{
39 /* k12text.l
40  *
41  * $Id$
42  *
43  * Wiretap Library
44  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
45  *
46  * This program is free software; you can redistribute it and/or
47  * modify it under the terms of the GNU General Public License
48  * as published by the Free Software Foundation; either version 2
49  * of the License, or (at your option) any later version.
50  *
51  * This program is distributed in the hope that it will be useful,
52  * but WITHOUT ANY WARRANTY; without even the implied warranty of
53  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
54  * GNU General Public License for more details.
55  *
56  * You should have received a copy of the GNU General Public License
57  * along with this program; if not, write to the Free Software
58  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
59  */
60
61  /*
62   * TODO:
63   *   - fix timestamps after midnight
64   *   - verify encapsulations
65   */
66
67 #ifdef HAVE_CONFIG_H
68 #include "config.h"
69 #endif
70 #include <stdlib.h>
71 #include <string.h>
72 #include <errno.h>
73 #include <time.h>
74 #include "wtap-int.h"
75 #include "wtap.h"
76 #include "file_wrappers.h"
77 #include "buffer.h"
78 #include "k12.h"
79 #include "k12text_lex.h"
80
81 #ifndef HAVE_UNISTD_H
82 #define YY_NO_UNISTD_H
83 #endif
84
85 static guint h;
86 static guint m;
87 static guint s;
88 static guint ms;
89 static guint ns;
90 static gint encap;
91 static guint8 b[WTAP_MAX_PACKET_SIZE];
92 static guint i;
93 static gboolean is_k12text;
94 static gboolean at_eof;
95 static guint junk_chars;
96 static void finalize_frame(void);
97 static gchar* error_str;
98 static guint file_bytes_read;
99 static gboolean ok_frame;
100 static FILE_T yy_fh;
101
102 #define KERROR(text) do { error_str = g_strdup(text); yyterminate(); } while(0)
103 #define SET_HOURS(text) h = strtoul(text,NULL,10)
104 #define SET_MINUTES(text) m = strtoul(text,NULL,10)
105 #define SET_SECONDS(text) s = strtoul(text,NULL,10)
106 #define SET_MS(text) ms = strtoul(text,NULL,10)
107 #define SET_NS(text) ns = strtoul(text,NULL,10)
108 #define SET_ENCAP(text) set_encap(text)
109 #define ADD_BYTE(text) do {if (i >= WTAP_MAX_PACKET_SIZE) {KERROR("frame too large");} b[i++] = (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 start_timestamp \053[\055]{9}\053[\055]{15,100}\053[\055]{10,100}\053
119 oneormoredigits [0-9]+:
120 twodigits [0-9][0-9]
121 colon :
122 comma ,
123 threedigits [0-9][0-9][0-9]
124 start_bytes \174\060\040\040\040\174
125 bytes_junk \174[A-F0-9][A-F0-9\040][A-F0-9\040][A-F0-9\040]\174
126 byte [a-f0-9][a-f0-9]\174
127 end_bytes \015?\012\015?\012
128 eth ETHER
129 mtp2 MTP-L2
130 sscop SSCOP
131 sscfnni SSCF
132 hdlc HDLC
133
134 %START MAGIC NEXT_FRAME HOURS MINUTES M2S SECONDS S2M MS M2N NS ENCAP STARTBYTES BYTE
135 %%
136 <MAGIC>{start_timestamp}  { is_k12text = TRUE; yyterminate(); }
137
138 <MAGIC>. { if (++ junk_chars > MAX_JUNK) { is_k12text = FALSE;  yyterminate(); } }
139
140 <NEXT_FRAME>{start_timestamp} {BEGIN(HOURS); }
141 <HOURS>{oneormoredigits} { SET_HOURS(yytext); BEGIN(MINUTES); }
142 <MINUTES>{twodigits} { SET_MINUTES(yytext); BEGIN(M2S);}
143 <M2S>{colon} { BEGIN(SECONDS);}
144 <SECONDS>{twodigits} { SET_SECONDS(yytext); BEGIN(S2M); }
145 <S2M>{comma}  { BEGIN(MS); }
146 <MS>{threedigits} { SET_MS(yytext); BEGIN(M2N);  }
147 <M2N>{comma}  { BEGIN(NS); }
148 <NS>{threedigits} { SET_NS(yytext); BEGIN(ENCAP);}
149 <ENCAP>{eth} {encap = WTAP_ENCAP_ETHERNET; BEGIN(STARTBYTES); }
150 <ENCAP>{mtp2} {encap = WTAP_ENCAP_MTP2; BEGIN(STARTBYTES); }
151 <ENCAP>{sscop} {encap = WTAP_ENCAP_ATM_PDUS; BEGIN(STARTBYTES); }
152 <ENCAP>{sscfnni} {encap = WTAP_ENCAP_MTP3; BEGIN(STARTBYTES); }
153 <ENCAP>{hdlc} {encap = WTAP_ENCAP_CHDLC; BEGIN(STARTBYTES); }
154 <ENCAP,STARTBYTES>{start_bytes} { BEGIN(BYTE); }
155 <BYTE>{byte} { ADD_BYTE(yytext); }
156 <BYTE>{bytes_junk} ;
157 <BYTE>{end_bytes} { FINALIZE_FRAME(); yyterminate(); }
158
159 . {  if (++junk_chars > MAX_JUNK) { KERROR("too much junk");  } }
160 <<EOF>> { at_eof = TRUE; yyterminate(); }
161
162 %%
163
164 static void finalize_frame(void) {
165         ok_frame = TRUE;
166 }
167
168 /* Note: k12text_reset is called each time data is to be processed from  */
169 /*       a file. This ensures that no "state" from a previous read is    */
170 /*       used (such as the lexer look-ahead buffer, file_handle, file    */
171 /*       position and so on. This allows a single lexer buffer to be     */
172 /*       used even when multiple files are open simultaneously (as for   */
173 /*       a file merge).                                                  */
174
175 static void k12text_reset(FILE_T fh) {
176         yy_fh = fh;
177         yyrestart(0);
178         encap = WTAP_ENCAP_UNKNOWN;
179         ok_frame = FALSE;
180         is_k12text = FALSE;
181         at_eof = FALSE;
182         junk_chars = 0;
183         error_str = NULL;
184         file_bytes_read=0;
185         h=0;
186         m=0;
187         s=0;
188         ns=0;
189         ms=0;
190         i=0;
191 }
192
193 static gboolean k12text_read(wtap *wth, int *err, char ** err_info, gint64 *data_offset) {
194
195         /* We seek to the file position after the end of the previous frame processed by         */
196         /* k12text_read (kept in wth->data_offset). We do this each time since the lexer         */
197         /* undoubtedly did some amount of look-ahead when processing the previous frame.         */ 
198         /* We also clear out any lexer state (eg: look-ahead buffer) and init vars set by lexer. */
199
200         if ( file_seek(wth->fh, wth->data_offset, SEEK_SET, err) == -1) {
201                 return FALSE;
202         }
203         k12text_reset(wth->fh);          /* init lexer buffer and vars set by lexer */
204
205         BEGIN(NEXT_FRAME);
206         yylex();
207
208         if (ok_frame == FALSE) {
209                 if (at_eof) {
210                         *err_info = NULL;
211                         *err = 0;
212                 } else {
213                         *err_info = error_str;
214                         *err = WTAP_ERR_BAD_RECORD;
215                 }
216                 return FALSE;
217         }
218
219         *data_offset = wth->data_offset;       /* file position for beginning of this frame   */
220         wth->data_offset += file_bytes_read;   /* file position after end of this frame       */
221
222         wth->phdr.ts.secs = 946681200 + (3600*h) + (60*m) + s;
223         wth->phdr.ts.nsecs = 1000000*ms + 1000*ns;
224
225         wth->phdr.caplen = wth->phdr.len = i;
226
227         wth->phdr.pkt_encap = encap;
228
229         buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
230         memcpy(buffer_start_ptr(wth->frame_buffer), b, wth->phdr.caplen);
231
232         return TRUE;
233 }
234
235 static gboolean k12text_seek_read(wtap *wth, gint64 seek_off, union wtap_pseudo_header *pseudo_header _U_, guint8 *pd, int length, int *err, char **err_info) {
236
237         if ( file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
238                 return FALSE;
239         }
240         k12text_reset(wth->random_fh);            /* init lexer buffer and vars set by lexer */
241
242         BEGIN(NEXT_FRAME);
243         yylex();
244
245         if (ok_frame == FALSE) {
246                 if (at_eof) {
247                         /* What happened ? The desired frame was previously read without a problem */
248                         *err_info = g_strdup("Unexpected EOF (program error ?)");
249                 } else {
250                         *err_info = error_str;
251                 }
252                 *err = WTAP_ERR_BAD_RECORD;
253                 return FALSE;
254         }
255
256         /* verify frame length parsed this time against original frame length */
257         if (i != length) {
258                 /* What happened ? This now seems to have a different length than originally */
259                 *err_info = g_strdup("Incorrect frame length (program error ?)");
260                 *err = WTAP_ERR_BAD_RECORD;
261                 return FALSE;
262         }
263
264         memcpy(pd, b, length);
265
266         return TRUE;
267 }
268
269 static void k12text_close(wtap *wth _U_) {
270         (void)0;
271 }
272
273 int k12text_open(wtap *wth, int *err, gchar **err_info _U_) {
274
275         k12text_reset(wth->fh);       /* init lexer buffer and vars set by lexer */
276
277         BEGIN(MAGIC);
278         yylex();
279
280         if (! is_k12text) return 0;
281
282         if ( file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
283                 return -1;
284         }
285
286         wth->data_offset = 0;
287         wth->file_type = WTAP_FILE_K12TEXT;
288         wth->file_encap = WTAP_ENCAP_PER_PACKET;
289         wth->snapshot_length = 0;
290         wth->subtype_read = k12text_read;
291         wth->subtype_seek_read = k12text_seek_read;
292         wth->subtype_close = k12text_close;
293         wth->capture.generic  = NULL;
294         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
295
296         return 1;
297 }
298
299
300 static const struct { int e; const char* s; } encaps[] = {
301         { WTAP_ENCAP_ETHERNET, "ETHER" },
302         { WTAP_ENCAP_MTP2, "MTP-L2" },
303         { WTAP_ENCAP_ATM_PDUS, "SSCOP" },
304         { WTAP_ENCAP_MTP3, "SSCF" },
305         { WTAP_ENCAP_CHDLC, "HDLC" },
306         /* ... */
307         { WTAP_ENCAP_UNKNOWN, "UNKNOWN" },
308         { 0, NULL }
309 };
310
311 static gboolean k12text_dump(wtap_dumper *wdh _U_, const struct wtap_pkthdr *phdr,
312                          const union wtap_pseudo_header *pseudo_header _U_,
313                          const guchar *pd, int *err _U_) {
314         char buf[196808];
315         size_t left = 196808;
316         gint wl;
317         char* p=buf;
318         const char* str_enc = "";
319         guint i;
320         guint ns;
321         guint ms;
322
323         ms = phdr->ts.nsecs / 1000000;
324         ns = (phdr->ts.nsecs - (1000000*ms))/1000;
325
326         for(i=0; encaps[i].s; i++) {
327                 str_enc = encaps[i].s;
328                 if (phdr->pkt_encap == encaps[i].e) break;
329         }
330
331         strftime(p,90,"+---------+---------------+----------+\r\n%H:%M:%S,",gmtime(&phdr->ts.secs));
332        wl = strlen(p);
333        p += wl;
334        left -= wl;
335        
336        wl = g_snprintf(p,left,"%.3d,%.3d   %s\r\n|0   |",ms,ns,str_enc);
337        p+= wl;
338        left -= wl;
339
340        for(i=0;i < phdr->caplen && left > 2; i++) {
341                wl = g_snprintf(p,left,"%.2x|",pd[i]);
342                p += wl;
343                left -= wl;
344                 }
345
346        wl = g_snprintf(p,left,"\r\n\r\n");
347        p+= wl;
348        left -= wl;
349        
350         fwrite(buf, 1, strlen(buf), wdh->fh);
351
352         return TRUE;
353 }
354
355
356 static gboolean k12text_dump_close(wtap_dumper *wdh _U_ , int *err _U_) {
357         return TRUE;
358 }
359
360 gboolean k12text_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err) {
361
362     if (cant_seek) {
363         *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
364         return FALSE;
365     }
366
367     wdh->subtype_write = k12text_dump;
368     wdh->subtype_close = k12text_dump_close;
369
370     return TRUE;
371 }
372
373 int k12text_dump_can_write_encap(int encap) {
374     switch (encap) {
375         case WTAP_ENCAP_PER_PACKET:
376         case WTAP_ENCAP_ETHERNET:
377         case WTAP_ENCAP_MTP2:
378         case WTAP_ENCAP_ATM_PDUS:
379         case WTAP_ENCAP_MTP3:
380         case WTAP_ENCAP_CHDLC:
381         case WTAP_ENCAP_UNKNOWN:
382                 return 0;
383         default:
384                 return WTAP_ERR_UNSUPPORTED_ENCAP;
385     }
386 }
387
388 /*
389  * We want to stop processing when we get to the end of the input.
390  * (%option noyywrap is not used because if used then 
391  * some flex versions (eg: 2.5.35) generate code which causes
392  * warnings by the Windows VC compiler).
393  */
394
395 int yywrap(void) {
396     return 1;
397 }