summaryrefslogtreecommitdiffstats
path: root/wiretap/k12text.l
diff options
context:
space:
mode:
Diffstat (limited to 'wiretap/k12text.l')
-rw-r--r--wiretap/k12text.l604
1 files changed, 604 insertions, 0 deletions
diff --git a/wiretap/k12text.l b/wiretap/k12text.l
new file mode 100644
index 00000000..7ba4587c
--- /dev/null
+++ b/wiretap/k12text.l
@@ -0,0 +1,604 @@
+%top {
+/* Include this before everything else, for various large-file definitions */
+#include "config.h"
+#include <wireshark.h>
+}
+
+/*
+ * We want a reentrant scanner.
+ */
+%option reentrant
+
+/*
+ * We don't use input, so don't generate code for it.
+ */
+%option noinput
+
+/*
+ * We don't use unput, so don't generate code for it.
+ */
+%option nounput
+
+/*
+ * We don't read interactively from the terminal.
+ */
+%option never-interactive
+
+/*
+ * We want to stop processing when we get to the end of the input.
+ */
+%option noyywrap
+
+/*
+ * The type for the state we keep for a scanner.
+ */
+%option extra-type="k12text_state_t *"
+
+/*
+ * Prefix scanner routines with "k12text_" rather than "yy", so this scanner
+ * can coexist with other scanners.
+ */
+%option prefix="k12text_"
+
+%option outfile="k12text.c"
+
+/* Options useful for debugging */
+/* noline: Prevent generation of #line directives */
+/* Seems to be required when using the */
+/* Windows VS debugger so as to be able */
+/* to properly step through the code and */
+/* set breakpoints & etc using the */
+/* k12text.c file rather than the */
+/* k12text.l file */
+/* XXX: %option noline gives an error message: */
+/* "unrecognized %option: line" */
+/* with flex 2.5.35; the --noline */
+/* command-line option works OK. */
+/* */
+/* debug: Do output of "rule acceptance" info */
+/* during parse */
+/* */
+/* %option noline */
+/* %option debug */
+
+/*
+ * We have to override the memory allocators so that we don't get
+ * "unused argument" warnings from the yyscanner argument (which
+ * we don't use, as we have a global memory allocator).
+ *
+ * We provide, as macros, our own versions of the routines generated by Flex,
+ * which just call malloc()/realloc()/free() (as the Flex versions do),
+ * discarding the extra argument.
+ */
+%option noyyalloc
+%option noyyrealloc
+%option noyyfree
+
+%{
+/* k12text.l
+ *
+ * Wiretap Library
+ * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+ /*
+ * TODO:
+ * - fix timestamps after midnight
+ * - verify encapsulations
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include "wtap-int.h"
+#include "wtap.h"
+#include "file_wrappers.h"
+#include <wsutil/buffer.h>
+#include "k12.h"
+
+#ifndef HAVE_UNISTD_H
+#define YY_NO_UNISTD_H
+#endif
+
+/*
+ * Disable diagnostics in the code generated by Flex.
+ */
+DIAG_OFF_FLEX()
+
+/*
+ * State kept by the scanner.
+ */
+typedef struct {
+ FILE_T fh;
+ int err;
+ gchar *err_info;
+ int start_state;
+
+ guint g_h;
+ guint g_m;
+ guint g_s;
+ guint g_ms;
+ guint g_ns;
+ gint g_encap;
+ guint8 *bb;
+ guint ii;
+ gboolean is_k12text;
+ gboolean at_eof;
+ guint junk_chars;
+ gchar* error_str;
+ guint64 file_bytes_read;
+ gboolean ok_frame;
+} k12text_state_t;
+
+#define KERROR(text) do { yyextra->error_str = g_strdup(text); yyterminate(); } while(0)
+#define SET_HOURS(text) yyextra->g_h = (guint) strtoul(text,NULL,10)
+#define SET_MINUTES(text) yyextra->g_m = (guint) strtoul(text,NULL,10)
+#define SET_SECONDS(text) yyextra->g_s = (guint) strtoul(text,NULL,10)
+#define SET_MS(text) yyextra->g_ms = (guint) strtoul(text,NULL,10)
+#define SET_NS(text) yyextra->g_ns = (guint) strtoul(text,NULL,10)
+#define ADD_BYTE(text) do {if (yyextra->ii >= WTAP_MAX_PACKET_SIZE_STANDARD) {KERROR("frame too large");} yyextra->bb[yyextra->ii++] = (guint8)strtoul(text,NULL,16); } while(0)
+#define FINALIZE_FRAME() do { yyextra->ok_frame = TRUE; } while (0)
+/*~ #define ECHO*/
+#define YY_USER_ACTION yyextra->file_bytes_read += yyleng;
+#define YY_USER_INIT { \
+ k12text_state_t *scanner_state = k12text_get_extra(yyscanner); \
+ BEGIN(scanner_state->start_state); \
+}
+#define YY_INPUT(buf,result,max_size) { \
+ k12text_state_t *scanner_state = k12text_get_extra(yyscanner); \
+ int c = file_getc(scanner_state->fh); \
+ if (c == EOF) { \
+ scanner_state->err = file_error(scanner_state->fh, \
+ &scanner_state->err_info); \
+ if (scanner_state->err == 0) \
+ scanner_state->err = WTAP_ERR_SHORT_READ; \
+ result = YY_NULL; \
+ } else { \
+ buf[0] = c; \
+ result = 1; \
+ } \
+}
+#define MAX_JUNK 400000
+#define ECHO
+
+/*
+ * Private per-file data.
+ */
+typedef struct {
+ /*
+ * The file position after the end of the previous frame processed by
+ * k12text_read.
+ *
+ * We need to keep this around, and seek to it at the beginning of
+ * each call to k12text_read(), since the lexer undoubtedly did some
+ * amount of look-ahead when processing the previous frame.
+ */
+ gint64 next_frame_offset;
+} k12text_t;
+
+/*
+ * Sleazy hack to suppress compiler warnings in yy_fatal_error().
+ */
+#define YY_EXIT_FAILURE ((void)yyscanner, 2)
+
+/*
+ * Macros for the allocators, to discard the extra argument.
+ */
+#define k12text_alloc(size, yyscanner) (void *)malloc(size)
+#define k12text_realloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size))
+#define k12text_free(ptr, yyscanner) free((char *)ptr)
+
+static int k12text_file_type_subtype = -1;
+
+void register_k12text(void);
+
+%}
+start_timestamp \053[\055]{9}\053[\055]{15,100}\053[\055]{10,100}\053
+oneormoredigits [0-9]+:
+twodigits [0-9][0-9]
+colon :
+comma ,
+threedigits [0-9][0-9][0-9]
+start_bytes \174\060\040\040\040\174
+bytes_junk \174[A-F0-9][A-F0-9\040][A-F0-9\040][A-F0-9\040]\174
+byte [a-f0-9][a-f0-9]\174
+end_bytes \015?\012\015?\012
+eth ETHER
+mtp2 MTP-L2
+sscop SSCOP
+sscfnni SSCF
+hdlc HDLC
+
+%START MAGIC NEXT_FRAME HOURS MINUTES M2S SECONDS S2M MS M2N NS ENCAP STARTBYTES BYTE
+%%
+<MAGIC>{start_timestamp} { yyextra->is_k12text = TRUE; yyterminate(); }
+
+<MAGIC>. { if (++ yyextra->junk_chars > MAX_JUNK) { yyextra->is_k12text = FALSE; yyterminate(); } }
+
+<NEXT_FRAME>{start_timestamp} {BEGIN(HOURS); }
+<HOURS>{oneormoredigits} { SET_HOURS(yytext); BEGIN(MINUTES); }
+<MINUTES>{twodigits} { SET_MINUTES(yytext); BEGIN(M2S);}
+<M2S>{colon} { BEGIN(SECONDS);}
+<SECONDS>{twodigits} { SET_SECONDS(yytext); BEGIN(S2M); }
+<S2M>{comma} { BEGIN(MS); }
+<MS>{threedigits} { SET_MS(yytext); BEGIN(M2N); }
+<M2N>{comma} { BEGIN(NS); }
+<NS>{threedigits} { SET_NS(yytext); BEGIN(ENCAP);}
+<ENCAP>{eth} {yyextra->g_encap = WTAP_ENCAP_ETHERNET; BEGIN(STARTBYTES); }
+<ENCAP>{mtp2} {yyextra->g_encap = WTAP_ENCAP_MTP2; BEGIN(STARTBYTES); }
+<ENCAP>{sscop} {yyextra->g_encap = WTAP_ENCAP_ATM_PDUS; BEGIN(STARTBYTES); }
+<ENCAP>{sscfnni} {yyextra->g_encap = WTAP_ENCAP_MTP3; BEGIN(STARTBYTES); }
+<ENCAP>{hdlc} {yyextra->g_encap = WTAP_ENCAP_CHDLC; BEGIN(STARTBYTES); }
+<ENCAP,STARTBYTES>{start_bytes} { BEGIN(BYTE); }
+<BYTE>{byte} { ADD_BYTE(yytext); }
+<BYTE>{bytes_junk} ;
+<BYTE>{end_bytes} { FINALIZE_FRAME(); yyterminate(); }
+
+. { if (++yyextra->junk_chars > MAX_JUNK) { KERROR("too much junk"); } }
+<<EOF>> { yyextra->at_eof = TRUE; yyterminate(); }
+
+%%
+
+/*
+ * Turn diagnostics back on, so we check the code that we've written.
+ */
+DIAG_ON_FLEX()
+
+/* Fill in pkthdr */
+
+static gboolean
+k12text_set_headers(wtap_rec *rec, k12text_state_t *state,
+ int *err, gchar **err_info)
+{
+ rec->rec_type = REC_TYPE_PACKET;
+ rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
+ rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
+
+ rec->ts.secs = 946681200 + (3600*state->g_h) + (60*state->g_m) + state->g_s;
+ rec->ts.nsecs = 1000000*state->g_ms + 1000*state->g_ns;
+
+ rec->rec_header.packet_header.caplen = rec->rec_header.packet_header.len = state->ii;
+
+ rec->rec_header.packet_header.pkt_encap = state->g_encap;
+
+ /* The file-encap is WTAP_ENCAP_PER_PACKET */
+ switch(state->g_encap) {
+ case WTAP_ENCAP_ETHERNET:
+ rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
+ break;
+ case WTAP_ENCAP_MTP3:
+ case WTAP_ENCAP_CHDLC:
+ /* no pseudo_header to fill in for these types */
+ break;
+ case WTAP_ENCAP_MTP2: /* not (yet) supported */
+ /* XXX: I don't know how to fill in the */
+ /* pseudo_header for these types. */
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = g_strdup("k12text: MTP2 packets not yet supported");
+ return FALSE;
+ case WTAP_ENCAP_ATM_PDUS: /* not (yet) supported */
+ /* XXX: I don't know how to fill in the */
+ /* pseudo_header for these types. */
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = g_strdup("k12text: SSCOP packets not yet supported");
+ return FALSE;
+ default:
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = g_strdup("k12text: unknown encapsulation type");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Note: k12text_reset is called each time data is to be processed from */
+/* a file. This ensures that no "state" from a previous read is */
+/* used (such as the lexer look-ahead buffer, file_handle, file */
+/* position and so on. This allows a single lexer buffer to be */
+/* used even when multiple files are open simultaneously (as for */
+/* a file merge). */
+
+static gboolean
+k12text_run_scanner(k12text_state_t *state, FILE_T fh, int start_state,
+ int *err, gchar **err_info)
+{
+ yyscan_t scanner = NULL;
+
+ if (yylex_init(&scanner) != 0) {
+ /* errno is set if this fails */
+ *err = errno;
+ *err_info = NULL;
+ return FALSE;
+ }
+ state->fh = fh;
+ state->err = 0;
+ state->err_info = NULL;
+ state->start_state = start_state;
+
+ state->g_encap = WTAP_ENCAP_UNKNOWN;
+ state->ok_frame = FALSE;
+ state->is_k12text = FALSE;
+ state->at_eof = FALSE;
+ state->junk_chars = 0;
+ state->error_str = NULL;
+ state->file_bytes_read=0;
+ state->g_h=0;
+ state->g_m=0;
+ state->g_s=0;
+ state->g_ns=0;
+ state->g_ms=0;
+ state->ii=0;
+
+ /* Associate the state with the scanner */
+ k12text_set_extra(state, scanner);
+
+ yylex(scanner);
+ yylex_destroy(scanner);
+ if (state->err != 0 && state->err != WTAP_ERR_SHORT_READ) {
+ /* I/O error. */
+ *err = state->err;
+ *err_info = state->err_info;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+k12text_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, char ** err_info, gint64 *data_offset)
+{
+ k12text_t *k12text = (k12text_t *)wth->priv;
+ k12text_state_t state;
+
+ /*
+ * We seek to the file position after the end of the previous frame
+ * processed by k12text_read(), since the lexer undoubtedly did some
+ * amount of look-ahead when processing the previous frame.
+ *
+ * We also clear out any lexer state (eg: look-ahead buffer) and
+ * init vars set by lexer.
+ */
+
+ if ( file_seek(wth->fh, k12text->next_frame_offset, SEEK_SET, err) == -1) {
+ return FALSE;
+ }
+ state.bb = (guint8*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
+
+ if (!k12text_run_scanner(&state, wth->fh, NEXT_FRAME, err, err_info)) {
+ g_free(state.bb);
+ return FALSE;
+ }
+
+ if (state.ok_frame == FALSE) {
+ if (state.at_eof) {
+ *err = 0;
+ *err_info = NULL;
+ } else {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = state.error_str;
+ }
+ g_free(state.bb);
+ return FALSE;
+ }
+
+ *data_offset = k12text->next_frame_offset; /* file position for beginning of this frame */
+ k12text->next_frame_offset += state.file_bytes_read; /* file position after end of this frame */
+
+ if (!k12text_set_headers(rec, &state, err, err_info)) {
+ g_free(state.bb);
+ return FALSE;
+ }
+ ws_buffer_assure_space(buf, rec->rec_header.packet_header.caplen);
+ memcpy(ws_buffer_start_ptr(buf), state.bb, rec->rec_header.packet_header.caplen);
+
+ g_free(state.bb);
+ return TRUE;
+}
+
+static gboolean
+k12text_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf, int *err, char **err_info)
+{
+ k12text_state_t state;
+
+ if ( file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
+ return FALSE;
+ }
+ state.bb = (guint8*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
+
+ if (!k12text_run_scanner(&state, wth->random_fh, NEXT_FRAME, err, err_info)) {
+ g_free(state.bb);
+ return FALSE;
+ }
+
+ if (state.ok_frame == FALSE) {
+ *err = WTAP_ERR_BAD_FILE;
+ if (state.at_eof) {
+ /* What happened ? The desired frame was previously read without a problem */
+ *err_info = g_strdup("Unexpected EOF (program error ?)");
+ } else {
+ *err_info = state.error_str;
+ }
+ g_free(state.bb);
+ return FALSE;
+ }
+
+ if (!k12text_set_headers(rec, &state, err, err_info)) {
+ g_free(state.bb);
+ return FALSE;
+ }
+ ws_buffer_assure_space(buf, rec->rec_header.packet_header.caplen);
+ memcpy(ws_buffer_start_ptr(buf), state.bb, rec->rec_header.packet_header.caplen);
+
+ g_free(state.bb);
+ return TRUE;
+}
+
+wtap_open_return_val
+k12text_open(wtap *wth, int *err, gchar **err_info)
+{
+ k12text_t *k12text;
+ k12text_state_t state;
+
+ state.bb = (guint8*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
+ if (!k12text_run_scanner(&state, wth->fh, MAGIC, err, err_info)) {
+ g_free(state.bb);
+ return WTAP_OPEN_ERROR;
+ }
+
+ if (!state.is_k12text) {
+ /* *err might have been set to WTAP_ERR_SHORT_READ */
+ *err = 0;
+ g_free(state.bb);
+ return WTAP_OPEN_NOT_MINE;
+ }
+
+ if ( file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
+ g_free(state.bb);
+ return WTAP_OPEN_ERROR;
+ }
+
+ k12text = g_new(k12text_t, 1);
+ wth->priv = (void *)k12text;
+ k12text->next_frame_offset = 0;
+ wth->file_type_subtype = k12text_file_type_subtype;
+ wth->file_encap = WTAP_ENCAP_PER_PACKET;
+ wth->snapshot_length = 0;
+ wth->subtype_read = k12text_read;
+ wth->subtype_seek_read = k12text_seek_read;
+ wth->file_tsprec = WTAP_TSPREC_NSEC;
+
+ g_free(state.bb);
+ return WTAP_OPEN_MINE;
+}
+
+
+static const struct { int e; const char* s; } encaps[] = {
+ { WTAP_ENCAP_ETHERNET, "ETHER" },
+ { WTAP_ENCAP_MTP2, "MTP-L2" },
+ { WTAP_ENCAP_ATM_PDUS, "SSCOP" },
+ { WTAP_ENCAP_MTP3, "SSCF" },
+ { WTAP_ENCAP_CHDLC, "HDLC" },
+ /* ... */
+ { 0, NULL }
+};
+
+static gboolean
+k12text_dump(wtap_dumper *wdh, const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info _U_) {
+#define K12BUF_SIZE 196808
+ char *buf;
+ size_t left = K12BUF_SIZE;
+ size_t wl;
+ char *p;
+ const char* str_enc;
+ guint i;
+ guint ns;
+ guint ms;
+ gboolean ret;
+ struct tm *tmp;
+
+ /* Don't write anything bigger than we're willing to read. */
+ if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) {
+ *err = WTAP_ERR_PACKET_TOO_LARGE;
+ return FALSE;
+ }
+
+ str_enc = NULL;
+ for(i=0; encaps[i].s; i++) {
+ if (rec->rec_header.packet_header.pkt_encap == encaps[i].e) {
+ str_enc = encaps[i].s;
+ break;
+ }
+ }
+ if (str_enc == NULL) {
+ /*
+ * That encapsulation type is not supported. Fail.
+ */
+ *err = WTAP_ERR_UNWRITABLE_ENCAP;
+ return FALSE;
+ }
+
+ buf = (char *)g_malloc(K12BUF_SIZE);
+ p = buf;
+
+ ms = rec->ts.nsecs / 1000000;
+ ns = (rec->ts.nsecs - (1000000*ms))/1000;
+
+ tmp = gmtime(&rec->ts.secs);
+ if (tmp == NULL)
+ snprintf(p, 90, "+---------+---------------+----------+\r\nXX:XX:XX,");
+ else
+ strftime(p, 90, "+---------+---------------+----------+\r\n%H:%M:%S,", tmp);
+ wl = strlen(p);
+ p += wl;
+ left -= wl;
+
+ wl = snprintf(p, left, "%.3d,%.3d %s\r\n|0 |", ms, ns, str_enc);
+ p += wl;
+ left -= wl;
+
+ for(i = 0; i < rec->rec_header.packet_header.caplen && left > 2; i++) {
+ wl = snprintf(p, left, "%.2x|", pd[i]);
+ p += wl;
+ left -= wl;
+ }
+
+ wl = snprintf(p, left, "\r\n\r\n");
+ left -= wl;
+
+ ret = wtap_dump_file_write(wdh, buf, K12BUF_SIZE - left, err);
+
+ g_free(buf);
+ return ret;
+}
+
+
+static gboolean
+k12text_dump_open(wtap_dumper *wdh, int *err _U_, gchar **err_info _U_)
+{
+ wdh->subtype_write = k12text_dump;
+
+ return TRUE;
+}
+
+static int
+k12text_dump_can_write_encap(int encap)
+{
+ switch (encap) {
+ case WTAP_ENCAP_PER_PACKET:
+ case WTAP_ENCAP_ETHERNET:
+ case WTAP_ENCAP_MTP3:
+ case WTAP_ENCAP_CHDLC:
+ return 0;
+ case WTAP_ENCAP_MTP2:
+ case WTAP_ENCAP_ATM_PDUS:
+ default:
+ return WTAP_ERR_UNWRITABLE_ENCAP;
+ }
+}
+
+static const struct supported_block_type k12text_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info k12text_info = {
+ "K12 text file", "k12text", "txt", NULL,
+ FALSE, BLOCKS_SUPPORTED(k12text_blocks_supported),
+ k12text_dump_can_write_encap, k12text_dump_open, NULL
+};
+
+void register_k12text(void)
+{
+ k12text_file_type_subtype = wtap_register_file_type_subtype(&k12text_info);
+
+ /*
+ * Register name for backwards compatibility with the
+ * wtap_filetypes table in Lua.
+ */
+ wtap_register_backwards_compatibility_lua_name("K12TEXT",
+ k12text_file_type_subtype);
+}