%top { /* Include this before everything else, for various large-file definitions */ #include "config.h" #include } /* * 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="Dtd_Parse_scanner_state_t *" /* * Prefix scanner routines with "Dtd_Parse_" rather than "yy", so this scanner * can coexist with other scanners. */ %option prefix="Dtd_Parse_" %option outfile="dtd_parse.c" /* * 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 %{ /* dtd_parse.l * an XML dissector for Wireshark * lexical analyzer for DTDs * * Copyright 2004, Luis E. Garcia Ontanon * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "dtd.h" #include "dtd_grammar.h" #include "dtd_parse.h" /* * Disable diagnostics in the code generated by Flex. */ DIAG_OFF_FLEX() struct _proto_xmlpi_attr { const char* name; void (*act)(char*); }; typedef struct { GString* input_string; size_t offsetx; size_t len; void* pParser; char* location; char* attr_name; } Dtd_Parse_scanner_state_t; static size_t my_yyinput(Dtd_Parse_scanner_state_t *state,char* buff,size_t size); static dtd_token_data_t* new_token(char*,char*); static dtd_build_data_t* build_data; static void set_proto_name (char* val) { g_free(build_data->proto_name); build_data->proto_name = g_strdup(val); } static void set_media_type (char* val) { g_free(build_data->media_type); build_data->media_type = g_strdup(val); } static void set_proto_root (char* val) { g_free(build_data->proto_root); build_data->proto_root = g_strdup(val); } static void set_description (char* val) { g_free(build_data->description); build_data->description = g_strdup(val); } static void set_recursive (char* val) { build_data->recursion = ( g_ascii_strcasecmp(val,"yes") == 0 ) ? true : false; } #ifdef DEBUG_DTD_PARSER #define DEBUG_DTD_TOKEN fprintf(stderr,"->%s (%i)%s\n",location,token_type,yytext) #else #define DEBUG_DTD_TOKEN #endif #define DTD_PARSE(token_type) \ { DEBUG_DTD_TOKEN; \ DtdParse(yyextra->pParser, (token_type), new_token(yytext, yyextra->location), build_data); \ if(build_data->error->len > 0) yyterminate(); \ } #define YY_INPUT(buff,result,max_size) ( (result) = my_yyinput(yyextra,(buff),(max_size)) ) #define YY_USER_INIT BEGIN DTD; /* * Flex (v 2.5.35) uses this symbol to "exclude" unistd.h */ #ifdef _WIN32 #define YY_NO_UNISTD_H #endif /* * 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 Dtd_Parse_alloc(size, yyscanner) (void *)malloc(size) #define Dtd_Parse_realloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size)) #define Dtd_Parse_free(ptr, yyscanner) free((char *)ptr) %} comment_start "" start_xmlpi "" notation_tag "" whitespace [[:blank:]\r\n]+ newline \n attlist_kw ATTLIST doctype_kw DOCTYPE element_kw ELEMENT pcdata #PCDATA any ANY cdata #CDATA iD ID idref IDREF idrefs IDREFS nmtoken NMTOKEN nmtokens NMTOKENS entity ENTITY entities ENTITIES notation NOTATION cdata_t CDATA empty EMPTY defaulT #DEFAULT fixed #FIXED required #REQUIRED implied #IMPLIED star "*" question "?" plus "+" open_parens "(" close_parens ")" open_bracket "[" close_bracket "]" comma "," pipe "|" dquote ["] name [A-Za-z0-9][-a-zA-Z0-9_]* dquoted ["][^\"]*["] squoted ['][^\']*['] %START DTD XMLPI LOCATION DONE PROTOCOL GET_ATTR_QUOTE GET_ATTR_VAL GET_ATTR_CLOSE_QUOTE IN_COMMENT IN_NOTATION %% {whitespace} ; {comment_start} { BEGIN IN_COMMENT; } [^-]? | [-] ; {comment_stop} { BEGIN DTD; } {notation_tag} { BEGIN IN_NOTATION; } [^>] ; {special_stop} { BEGIN DTD; } {start_xmlpi} { BEGIN XMLPI; } {location_xmlpi} { BEGIN LOCATION; } {protocol_xmlpi} { BEGIN PROTOCOL; } <.> ; {stop_xmlpi} BEGIN DTD; {get_location_xmlpi} { g_free(yyextra->location); yyextra->location = g_strdup(yytext); BEGIN DONE; } {stop_xmlpi} BEGIN DTD; {name} { yyextra->attr_name = g_ascii_strdown(yytext, -1); BEGIN GET_ATTR_QUOTE; } {get_attr_quote} { BEGIN GET_ATTR_VAL; } . { g_string_append_printf(build_data->error, "error in wireshark:protocol xmpli at %s : could not find attribute value!", yyextra->location); yyterminate(); } [^"]+ { /*"*/ struct _proto_xmlpi_attr* pa; bool got_it = false; static struct _proto_xmlpi_attr proto_attrs[] = { { "proto_name", set_proto_name }, { "media", set_media_type }, { "root", set_proto_root }, { "description", set_description }, { "hierarchy", set_recursive }, {NULL,NULL} }; for(pa = proto_attrs; pa->name; pa++) { if (g_ascii_strcasecmp(yyextra->attr_name,pa->name) == 0) { pa->act(yytext); got_it = true; break; } } if (! got_it) { g_string_append_printf(build_data->error, "error in wireshark:protocol xmpli at %s : no such parameter %s!", yyextra->location, yyextra->attr_name); g_free(yyextra->attr_name); yyterminate(); } g_free(yyextra->attr_name); BEGIN GET_ATTR_CLOSE_QUOTE; } {dquote} { BEGIN PROTOCOL;} {stop_xmlpi} BEGIN DTD; {special_start} { DTD_PARSE(TOKEN_TAG_START); } {special_stop} { DTD_PARSE(TOKEN_TAG_STOP); } {attlist_kw} { DTD_PARSE(TOKEN_ATTLIST_KW); } {element_kw} { DTD_PARSE(TOKEN_ELEMENT_KW); } {doctype_kw} { DTD_PARSE(TOKEN_DOCTYPE_KW); } {pcdata} { DTD_PARSE(TOKEN_ELEM_DATA); } {any} { DTD_PARSE(TOKEN_ELEM_DATA); } {cdata} { DTD_PARSE(TOKEN_ELEM_DATA); } {empty} { DTD_PARSE(TOKEN_EMPTY_KW); } {iD} { DTD_PARSE(TOKEN_ATT_TYPE); } {idref} { DTD_PARSE(TOKEN_ATT_TYPE); } {idrefs} { DTD_PARSE(TOKEN_ATT_TYPE); } {nmtoken} { DTD_PARSE(TOKEN_ATT_TYPE); } {nmtokens} { DTD_PARSE(TOKEN_ATT_TYPE); } {entity} { DTD_PARSE(TOKEN_ATT_TYPE); } {entities} { DTD_PARSE(TOKEN_ATT_TYPE); } {notation} { DTD_PARSE(TOKEN_ATT_TYPE); } {cdata_t} { DTD_PARSE(TOKEN_ATT_TYPE); } {defaulT} { DTD_PARSE(TOKEN_ATT_DEF_WITH_VALUE); } {fixed} { DTD_PARSE(TOKEN_ATT_DEF_WITH_VALUE); } {required} { DTD_PARSE(TOKEN_ATT_DEF); } {implied} { DTD_PARSE(TOKEN_ATT_DEF); } {star} { DTD_PARSE(TOKEN_STAR); } {question} { DTD_PARSE(TOKEN_QUESTION); } {plus} { DTD_PARSE(TOKEN_PLUS); } {comma} { DTD_PARSE(TOKEN_COMMA); } {open_parens} { DTD_PARSE(TOKEN_OPEN_PARENS); } {close_parens} { DTD_PARSE(TOKEN_CLOSE_PARENS); } {open_bracket} { DTD_PARSE(TOKEN_OPEN_BRACKET); } {close_bracket} { DTD_PARSE(TOKEN_CLOSE_BRACKET); } {pipe} { DTD_PARSE(TOKEN_PIPE); } {dquoted} | {squoted} { DTD_PARSE(TOKEN_QUOTED); } {name} { DTD_PARSE(TOKEN_NAME); } %% /* * Turn diagnostics back on, so we check the code that we've written. */ DIAG_ON_FLEX() static dtd_token_data_t* new_token(char* text, char* location) { dtd_token_data_t* t = g_new(dtd_token_data_t,1); t->text = g_strdup(text); t->location = g_strdup(location); return t; } static size_t my_yyinput(Dtd_Parse_scanner_state_t *state, char* buff, size_t size) { if (state->offsetx >= state->len) { return YY_NULL; } else if (state->offsetx + size <= state->len) { memcpy(buff, state->input_string->str + state->offsetx, size); state->offsetx += size; return size; } else { size = state->len - state->offsetx; memcpy(buff, state->input_string->str + state->offsetx, size); state->offsetx = state->len; return size; } } extern dtd_build_data_t* dtd_parse(GString* s) { yyscan_t scanner; Dtd_Parse_scanner_state_t state; if (Dtd_Parse_lex_init(&scanner) != 0) { #ifdef DEBUG_DTD_PARSER fprintf(stderr, "Can't initialize scanner: %s\n", strerror(errno)); #endif return NULL; } state.input_string = s; state.offsetx = 0; state.len = state.input_string->len; state.pParser = DtdParseAlloc(g_malloc); #ifdef DEBUG_DTD_PARSER DtdParseTrace(stderr, ">>"); #endif build_data = g_new(dtd_build_data_t,1); build_data->proto_name = NULL; build_data->media_type = NULL; build_data->description = NULL; build_data->proto_root = NULL; build_data->recursion = false; build_data->elements = g_ptr_array_new(); build_data->attributes = g_ptr_array_new(); build_data->error = g_string_new(""); state.location = NULL; state.attr_name = NULL; /* Associate the state with the scanner */ Dtd_Parse_set_extra(&state, scanner); Dtd_Parse_lex(scanner); DtdParse(state.pParser, 0, NULL, build_data); Dtd_Parse_lex_destroy(scanner); g_free(state.location); DtdParseFree(state.pParser, g_free); return build_data; }