Because there's more than just text in XML...

DTDs are imported to create fields


svn path=/trunk/; revision=15851
This commit is contained in:
Luis Ontanon 2005-09-17 17:05:46 +00:00
parent 8ace2749f3
commit 4c14b12c25
5 changed files with 646 additions and 190 deletions

View File

@ -31,10 +31,15 @@
#include "config.h"
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
@ -44,58 +49,109 @@
#include <epan/strutil.h>
#include <epan/tvbparse.h>
#include <epan/dtd.h>
#include <epan/report_err.h>
#include <epan/filesystem.h>
typedef struct _xml_names_t {
typedef struct _xml_ns_t {
/* the name of this namespace */
gchar* name;
gchar* longname;
gchar* blurb;
/* its fully qualified name */
gchar* fqn;
/* the contents of the whole element from <> to </> */
int hf_tag;
/* chunks of cdata from <> to </> excluding sub tags */
int hf_cdata;
/* the subtree for its sub items */
gint ett;
gboolean is_root;
GHashTable* attributes;
GHashTable* elements;
} xml_names_t;
/* key: the attribute name
value: hf_id of what's between quotes */
/* the namespace's namespaces */
GHashTable* elements;
/* key: the element name
value: the child namespace */
GPtrArray* element_names;
/* imported directly from the parser and used while building the namespace */
} xml_ns_t;
typedef struct {
proto_tree* tree;
proto_item* item;
proto_item* last_item;
xml_names_t* ns;
xml_ns_t* ns;
int start_offset;
} xml_frame_t;
struct _attr_reg_data {
GArray* hf;
gchar* basename;
};
static gint ett_dtd = -1;
static gint ett_xmpli = -1;
static int hf_junk = -1;
static int hf_unknowwn_attrib = -1;
static int hf_comment = -1;
static int hf_xmlpi = -1;
static int hf_dtd_tag = -1;
static int hf_doctype = -1;
/* Dissector handles */
/* dissector handles */
static dissector_handle_t xml_handle;
/* tokenizer defs */
/* parser definitions */
static tvbparse_wanted_t* want;
static tvbparse_wanted_t* want_ignore;
static GHashTable* xmpli_names;
static GHashTable* media_types;
static xml_names_t xml_ns = {"xml","eXtesible Markup Language","XML",-1,-1,-1,TRUE,NULL,NULL};
static xml_names_t unknown_ns = {"","","",-1,-1,-1,TRUE,NULL,NULL};
static xml_names_t* root_ns;
static xml_ns_t xml_ns = {"xml","/",-1,-1,-1,NULL,NULL,NULL};
static xml_ns_t unknown_ns = {"unknown","?",-1,-1,-1,NULL,NULL,NULL};
static xml_ns_t* root_ns;
#define XML_CDATA -1000
#define XML_SCOPED_NAME -1001
GArray* hf;
GArray* hf_arr;
GArray* ett_arr;
static const gchar* default_media_types[] = {
"text/xml",
"application/xml",
"application/soap+xml",
"application/xml-dtd",
"text/vnd.wap.wml",
"text/vnd.wap.si",
"text/vnd.wap.sl",
"text/vnd.wap.co",
"text/vnd.wap.emn",
"application/vnd.wv.csp+xml",
"application/xcap-el+xml",
"application/xcap-att+xml",
"application/xcap-error+xml",
"application/xcap-caps+xml",
"application/auth-policy+xml",
"application/smil",
"application/cpim-pidf+xml",
"application/rdf+xml",
"application/xslt+xml",
"application/mathml+xml",
"image/svg+xml",
"application/vnd.wv.csp.xml",
};
static void
dissect_xml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
@ -119,13 +175,13 @@ dissect_xml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
root_ns = g_hash_table_lookup(media_types,pinfo->match_string);
if (! root_ns ) {
root_ns = &unknown_ns;
root_ns = &xml_ns;
}
current_frame->ns = root_ns;
current_frame->item = proto_tree_add_item(tree,xml_ns.hf_tag,tvb,0,-1,FALSE);
current_frame->tree = proto_item_add_subtree(current_frame->item,xml_ns.ett);
current_frame->item = proto_tree_add_item(tree,current_frame->ns->hf_tag,tvb,0,-1,FALSE);
current_frame->tree = proto_item_add_subtree(current_frame->item,current_frame->ns->ett);
current_frame->last_item = current_frame->item;
while(( tok = tvbparse_get(tt, want) )) ;
@ -143,7 +199,7 @@ static void after_token(void* tvbparse_data, const void* wanted_data _U_, tvbpar
} else if ( tok->id > 0) {
hfid = tok->id;
} else {
hfid = hf_junk;
hfid = xml_ns.hf_cdata;
}
pi = proto_tree_add_item(current_frame->tree, hfid, tok->tvb, tok->offset, tok->len, FALSE);
@ -159,7 +215,8 @@ static void before_xmpli(void* tvbparse_data, const void* wanted_data _U_, tvbpa
proto_tree* pt;
tvbparse_elem_t* name_tok = tok->sub->next;
gchar* name = tvb_get_ephemeral_string(name_tok->tvb,name_tok->offset,name_tok->len);
xml_names_t* ns = g_hash_table_lookup(xmpli_names,name);
xml_ns_t* ns = g_hash_table_lookup(xmpli_names,name);
int hf_tag;
gint ett;
@ -208,20 +265,46 @@ static void before_tag(void* tvbparse_data, const void* wanted_data _U_, tvbpars
GPtrArray* stack = tvbparse_data;
xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
tvbparse_elem_t* name_tok = tok->sub->next;
gchar* name =tvb_get_ephemeral_string(name_tok->tvb,name_tok->offset,name_tok->len);
xml_names_t* ns = g_hash_table_lookup(current_frame->ns->elements,name);
gchar* root_name;
gchar* name;
xml_ns_t* ns;
xml_frame_t* new_frame;
proto_item* pi;
proto_tree* pt;
g_strdown(name);
if (!ns) {
if (! ( ns = g_hash_table_lookup(root_ns->elements,name) ) ) {
ns = &unknown_ns;
}
}
pi = proto_tree_add_item(current_frame->tree,ns->hf_tag,tok->tvb,tok->offset,tok->len,FALSE);
if (name_tok->sub->id == XML_SCOPED_NAME) {
tvbparse_elem_t* root_tok = name_tok->sub->sub;
tvbparse_elem_t* leaf_tok = name_tok->sub->sub->next->next;
xml_ns_t* nameroot_ns;
root_name = tvb_get_ephemeral_string(root_tok->tvb,root_tok->offset,root_tok->len);
name = tvb_get_ephemeral_string(leaf_tok->tvb,leaf_tok->offset,leaf_tok->len);
nameroot_ns = g_hash_table_lookup(xml_ns.elements,root_name);
if(nameroot_ns) {
ns = g_hash_table_lookup(nameroot_ns->elements,name);
if (!ns) {
ns = &unknown_ns;
}
} else {
ns = &unknown_ns;
}
} else {
name = tvb_get_ephemeral_string(name_tok->tvb,name_tok->offset,name_tok->len);
g_strdown(name);
ns = g_hash_table_lookup(current_frame->ns->elements,name);
if (!ns) {
if (! ( ns = g_hash_table_lookup(root_ns->elements,name) ) ) {
ns = &unknown_ns;
}
}
}
pi = proto_tree_add_item(current_frame->tree,ns->hf_tag,tok->tvb,tok->offset,tok->len,FALSE);
proto_item_set_text(pi,tvb_format_text(tok->tvb,tok->offset,(name_tok->offset - tok->offset) + name_tok->len));
pt = proto_item_add_subtree(pi,ns->ett);
@ -354,11 +437,20 @@ static void unrecognized_token(void* tvbparse_data, const void* wanted_data _U_,
void init_xml_parser(void) {
tvbparse_wanted_t* want_name = tvbparse_chars(-1,0,0,"abcdefghijklmnopqrstuvwxyz-_:ABCDEFGHIJKLMNOPQRSTUVWXYZ",NULL,NULL,NULL);
tvbparse_wanted_t* want_name = tvbparse_chars(-1,0,0,"abcdefghijklmnopqrstuvwxyz-_ABCDEFGHIJKLMNOPQRSTUVWXYZ",NULL,NULL,NULL);
tvbparse_wanted_t* want_tag_name = tvbparse_set_oneof(0, NULL, NULL, NULL,
tvbparse_set_seq(XML_SCOPED_NAME, NULL, NULL, NULL,
want_name,
tvbparse_char(-1,":",NULL,NULL,NULL),
want_name,
NULL),
want_name,
NULL);
tvbparse_wanted_t* want_attributes = tvbparse_one_or_more(-1, NULL, NULL, NULL,
tvbparse_set_seq(-1, NULL, NULL, after_attrib,
want_name,
tvbparse_chars(-1,0,0,"abcdefghijklmnopqrstuvwxyz-_ABCDEFGHIJKLMNOPQRSTUVWXYZ:",NULL,NULL,NULL),
tvbparse_char(-1,"=",NULL,NULL,NULL),
tvbparse_set_oneof(0, NULL, NULL, get_attrib_value,
tvbparse_quoted(-1, NULL, NULL, tvbparse_shrink_token_cb,'\"','\\'),
@ -398,7 +490,7 @@ void init_xml_parser(void) {
tvbparse_set_seq(0,NULL,NULL,after_untag,
tvbparse_char(-1, "<", NULL, NULL, NULL),
tvbparse_char(-1, "/", NULL, NULL, NULL),
want_name,
want_tag_name,
tvbparse_char(-1, ">", NULL, NULL, NULL),
NULL),
tvbparse_set_seq(-1,NULL,before_dtd_doctype,NULL,
@ -435,7 +527,7 @@ void init_xml_parser(void) {
NULL),
tvbparse_set_seq(-1, NULL, before_tag, NULL,
tvbparse_char(-1,"<",NULL,NULL,NULL),
want_name,
want_tag_name,
tvbparse_set_oneof(-1,NULL,NULL,NULL,
tvbparse_set_seq(-1,NULL,NULL,NULL,
want_attributes,
@ -452,21 +544,19 @@ void init_xml_parser(void) {
}
xml_names_t* xml_new_namespace(GHashTable* hash, gchar* name, gchar* longname, gchar* blurb, ...) {
xml_names_t* ns = g_malloc(sizeof(xml_names_t));
xml_ns_t* xml_new_namespace(GHashTable* hash, gchar* name, ...) {
xml_ns_t* ns = g_malloc(sizeof(xml_ns_t));
va_list ap;
gchar* attr_name;
ns->name = g_strdup(name);
ns->longname = g_strdup(longname);
ns->blurb = g_strdup(blurb);
ns->hf_tag = -1;
ns->hf_cdata = -1;
ns->ett = -1;
ns->attributes = g_hash_table_new(g_str_hash,g_str_equal);
ns->elements = g_hash_table_new(g_str_hash,g_str_equal);
va_start(ap,blurb);
va_start(ap,name);
while(( attr_name = va_arg(ap,gchar*) )) {
int* hfp = g_malloc(sizeof(int));
@ -481,18 +571,18 @@ xml_names_t* xml_new_namespace(GHashTable* hash, gchar* name, gchar* longname, g
return ns;
}
void add_xml_attribute_names(gpointer k, gpointer v, gpointer p) {
gchar* basename = g_strdup_printf("%s.%s",(gchar*)p,(gchar*)k);
void add_xml_field(GArray* hfs, int* p_id, gchar* name, gchar* fqn) {
hf_register_info hfri;
hfri.p_id = (int*)v;
hfri.hfinfo.name = basename;
hfri.hfinfo.abbrev = basename;
hfri.p_id = p_id;
hfri.hfinfo.name = name;
hfri.hfinfo.abbrev = fqn;
hfri.hfinfo.type = FT_STRING;
hfri.hfinfo.display = BASE_NONE;
hfri.hfinfo.strings = NULL;
hfri.hfinfo.bitmask = 0x0;
hfri.hfinfo.blurb = basename;
hfri.hfinfo.blurb = "";
hfri.hfinfo.id = 0;
hfri.hfinfo.parent = 0;
hfri.hfinfo.ref_count = 0;
@ -500,55 +590,469 @@ void add_xml_attribute_names(gpointer k, gpointer v, gpointer p) {
hfri.hfinfo.same_name_next = NULL;
hfri.hfinfo.same_name_prev = NULL;
g_array_append_val(hf,hfri);
g_array_append_val(hfs,hfri);
}
void add_xml_attribute_names(gpointer k, gpointer v, gpointer p) {
struct _attr_reg_data* d = p;
gchar* basename = g_strdup_printf("%s.%s",d->basename,(gchar*)k);
add_xml_field(d->hf, (int*) v, (gchar*)k, basename);
}
void add_xmlpi_namespace(gpointer k _U_, gpointer v, gpointer p) {
xml_names_t* ns = v;
hf_register_info hfri;
xml_ns_t* ns = v;
gchar* basename = g_strdup_printf("%s.%s",(gchar*)p,ns->name);
gint* ett_p = &(ns->ett);
hfri.p_id = &(ns->hf_tag);
hfri.hfinfo.name = basename;
hfri.hfinfo.abbrev = basename;
hfri.hfinfo.type = FT_STRING;
hfri.hfinfo.display = BASE_NONE;
hfri.hfinfo.strings = NULL;
hfri.hfinfo.bitmask = 0x0;
hfri.hfinfo.blurb = basename;
hfri.hfinfo.id = 0;
hfri.hfinfo.parent = 0;
hfri.hfinfo.ref_count = 0;
hfri.hfinfo.bitshift = 0;
hfri.hfinfo.same_name_next = NULL;
hfri.hfinfo.same_name_prev = NULL;
struct _attr_reg_data d;
add_xml_field(hf_arr, &(ns->hf_tag), basename, basename);
g_array_append_val(hf,hfri);
g_array_append_val(ett_arr,ett_p);
g_hash_table_foreach(ns->attributes,add_xml_attribute_names,basename);
d.basename = basename;
d.hf = hf_arr;
g_hash_table_foreach(ns->attributes,add_xml_attribute_names,&d);
}
void init_xml_names(void) {
xml_names_t* xmlpi_xml_ns;
static void destroy_dtd_data(dtd_build_data_t* dtd_data) {
if(dtd_data->proto_name) g_free(dtd_data->proto_name);
if(dtd_data->media_type) g_free(dtd_data->media_type);
if(dtd_data->description) g_free(dtd_data->description);
if(dtd_data->proto_root) g_free(dtd_data->proto_root);
if(dtd_data->location) g_free(dtd_data->location);
g_string_free(dtd_data->error,TRUE);
while(dtd_data->elements->len) {
dtd_named_list_t* nl = g_ptr_array_remove_index_fast(dtd_data->elements,0);
g_ptr_array_free(nl->list,TRUE);
g_free(nl);
}
g_ptr_array_free(dtd_data->elements,FALSE);
while(dtd_data->attributes->len) {
dtd_named_list_t* nl = g_ptr_array_remove_index_fast(dtd_data->elements,0);
g_ptr_array_free(nl->list,TRUE);
g_free(nl);
}
g_ptr_array_free(dtd_data->attributes,FALSE);
g_free(dtd_data);
}
static void copy_attrib_item(gpointer k, gpointer v _U_, gpointer p) {
gchar* key = g_strdup(k);
int* value = g_malloc(sizeof(int));
GHashTable* dst = p;
*value = -1;
g_hash_table_insert(dst,key,value);
}
static GHashTable* copy_attributes_hash(GHashTable* src) {
GHashTable* dst = g_hash_table_new(g_str_hash,g_str_equal);
g_hash_table_foreach(src,copy_attrib_item,dst);
return dst;
}
static xml_ns_t* duplicate_element(xml_ns_t* orig) {
xml_ns_t* new_item = g_malloc(sizeof(xml_ns_t));
guint i;
new_item->name = g_strdup(orig->name);
new_item->hf_tag = -1;
new_item->hf_cdata = -1;
new_item->ett = -1;
new_item->attributes = copy_attributes_hash(orig->attributes);
new_item->elements = g_hash_table_new(g_str_hash,g_str_equal);
new_item->element_names = g_ptr_array_new();
for(i=0; i < orig->element_names->len; i++) {
g_ptr_array_add(new_item->element_names,
g_ptr_array_index(orig->element_names,i));
}
return new_item;
}
static gchar* fully_qualified_name(GPtrArray* hier, gchar* name) {
guint i;
GString* s = g_string_new("");
gchar* str;
for (i = 0; i < hier->len; i++) {
g_string_sprintfa(s, "%s.",(gchar*)g_ptr_array_index(hier,i));
}
g_string_append(s,name);
str = s->str;
g_string_free(s,FALSE);
return str;
}
static xml_ns_t* make_xml_hier(gchar* elem_name,
xml_ns_t* root,
GHashTable* elements,
GPtrArray* hier,
GString* error,
GArray* hfs,
GArray* etts) {
xml_ns_t* new;
xml_ns_t* orig = g_hash_table_lookup(elements,elem_name);
gchar* fqn;
gint* ett_p;
struct _attr_reg_data d;
gboolean recurred = FALSE;
if ( g_str_equal(elem_name,root->name) ) {
return NULL;
}
if (! orig) {
g_string_sprintfa(error,"element '%s' is not defined\n", elem_name);
return NULL;
}
fqn = fully_qualified_name(hier,elem_name);
new = duplicate_element(orig);
new->fqn = fqn;
add_xml_field(hfs, &(new->hf_tag), elem_name, fqn);
add_xml_field(hfs, &(new->hf_cdata), elem_name, fqn);
ett_p = &new->ett;
g_array_append_val(etts,ett_p);
d.basename = fqn;
d.hf = hfs;
g_hash_table_foreach(new->attributes,add_xml_attribute_names,&d);
while(new->element_names->len) {
gchar* child_name = g_ptr_array_remove_index(new->element_names,0);
xml_ns_t* child_element = NULL;
guint i;
for (i = 0; i < hier->len; i++) {
if( strcmp(child_name,(gchar*) g_ptr_array_index(hier,i) ) == 0 ) {
recurred = TRUE;
}
}
if( ! recurred ) {
g_ptr_array_add(hier,elem_name);
child_element = make_xml_hier(child_name, root, elements, hier,error,hfs,etts);
g_ptr_array_remove_index_fast(hier,hier->len - 1);
}
if (child_element) {
g_hash_table_insert(new->elements,child_element->name,child_element);
}
}
g_ptr_array_free(new->element_names,FALSE);
new->element_names = NULL;
return new;
}
static void register_dtd(dtd_build_data_t* dtd_data, GString* errors) {
GHashTable* elements = g_hash_table_new(g_str_hash,g_str_equal);
gchar* root_name = NULL;
xml_ns_t* root_element = NULL;
GArray* hfs;
GArray* etts;
GPtrArray* hier;
gchar* curr_name;
GPtrArray* element_names = g_ptr_array_new();
/* we first populate elements with the those coming from the parser */
while(dtd_data->elements->len) {
dtd_named_list_t* nl = g_ptr_array_remove_index(dtd_data->elements,0);
xml_ns_t* element = g_malloc(sizeof(xml_ns_t));
/* we will use the first element found as root in case no other one was given. */
if (root_name == NULL) root_name = g_strdup(nl->name);
element->name = nl->name;
element->element_names = nl->list;
element->hf_tag = -1;
element->hf_cdata = -1;
element->ett = -1;
element->attributes = g_hash_table_new(g_str_hash,g_str_equal);
element->elements = g_hash_table_new(g_str_hash,g_str_equal);
g_hash_table_insert(elements,element->name,element);
g_ptr_array_add(element_names,element->name);
g_free(nl);
}
/* then we add the attributes to its relative elements */
while(dtd_data->attributes->len) {
dtd_named_list_t* nl = g_ptr_array_remove_index(dtd_data->attributes,0);
xml_ns_t* element = g_hash_table_lookup(elements,nl->name);
if (!element) {
g_string_sprintfa(errors,"no element %s is been defined\n", nl->name);
goto next_attribute;
}
while(nl->list->len) {
gchar* name = g_ptr_array_remove_index(nl->list,0);
int* id_p = g_malloc(sizeof(int));
*id_p = -1;
g_hash_table_insert(element->attributes,name,id_p);
}
next_attribute:
g_free(nl->name);
g_ptr_array_free(nl->list,FALSE);
g_free(nl);
}
if( dtd_data->proto_root ) {
if(root_name) g_free(root_name);
root_name = g_strdup(dtd_data->proto_root);
}
hier = g_ptr_array_new();
if( ! dtd_data->proto_name ) {
hfs = hf_arr;
etts = ett_arr;
g_ptr_array_add(hier,g_strdup("xml"));
root_element = &xml_ns;
} else {
hfs = g_array_new(FALSE,FALSE,sizeof(hf_register_info));
etts = g_array_new(FALSE,FALSE,sizeof(gint*));
}
root_element = g_malloc(sizeof(xml_ns_t));
root_element->name = g_strdup(root_name);
root_element->fqn = root_element->name;
root_element->hf_tag = -1;
root_element->hf_cdata = -1;
root_element->ett = -1;
root_element->elements = g_hash_table_new(g_str_hash,g_str_equal);
root_element->element_names = element_names;
if (dtd_data->recursion) {
xml_ns_t* orig_root;
make_xml_hier(root_name, root_element, elements,hier,errors,hfs,etts);
g_hash_table_insert(root_element->elements,root_element->name,root_element);
orig_root = g_hash_table_lookup(elements,root_name);
if(orig_root) {
struct _attr_reg_data d;
d.basename = root_name;
d.hf = hfs;
root_element->attributes = copy_attributes_hash(orig_root->attributes);
g_hash_table_foreach(root_element->attributes,add_xml_attribute_names,&d);
} else {
root_element->attributes = g_hash_table_new(g_str_hash,g_str_equal);
}
g_ptr_array_add(hier,root_name);
while(root_element->element_names->len) {
curr_name = g_ptr_array_remove_index(root_element->element_names,0);
if( ! g_hash_table_lookup(root_element->elements,curr_name) ) {
xml_ns_t* new = make_xml_hier(curr_name, root_element, elements,hier,errors,hfs,etts);
g_hash_table_insert(root_element->elements,new->name,new);
}
}
} else {
g_ptr_array_add(hier,root_name);
root_element->attributes = g_hash_table_new(g_str_hash,g_str_equal);
while(root_element->element_names->len) {
xml_ns_t* new;
gint* ett_p;
struct _attr_reg_data d;
curr_name = g_ptr_array_remove_index(root_element->element_names,0);
new = duplicate_element(g_hash_table_lookup(elements,curr_name));
new->fqn = fully_qualified_name(hier, curr_name);
add_xml_field(hfs, &(new->hf_tag), curr_name, new->fqn);
add_xml_field(hfs, &(new->hf_cdata), curr_name, new->fqn);
d.basename = new->fqn;
d.hf = hfs;
g_hash_table_foreach(new->attributes,add_xml_attribute_names,&d);
ett_p = &new->ett;
g_array_append_val(etts,ett_p);
g_hash_table_insert(root_element->elements,new->name,new);
}
}
g_ptr_array_free(element_names,FALSE);
g_ptr_array_free(hier,FALSE);
if( dtd_data->proto_name ) {
gint* ett_p;
if ( ! dtd_data->description) {
dtd_data->description = g_strdup(root_name);
}
ett_p = &root_element->ett;
g_array_append_val(etts,ett_p);
add_xml_field(hfs, &root_element->hf_cdata, root_element->name, root_element->fqn);
root_element->hf_tag = proto_register_protocol(dtd_data->description, dtd_data->proto_name, root_element->name);
proto_register_field_array(root_element->hf_tag, (hf_register_info*)hfs->data, hfs->len);
proto_register_subtree_array((gint**)etts->data, etts->len);
if (dtd_data->media_type) {
g_hash_table_insert(media_types,dtd_data->media_type,root_element);
dtd_data->media_type = NULL;
}
dtd_data->description = NULL;
dtd_data->proto_name = NULL;
g_array_free(hfs,FALSE);
g_array_free(etts,FALSE);
}
g_hash_table_insert(xml_ns.elements,root_element->name,root_element);
destroy_dtd_data(dtd_data);
}
#if GLIB_MAJOR_VERSION < 2
# define DIRECTORY_T DIR
# define FILE_T struct dirent
# define OPENDIR_OP(name) opendir(name)
# define DIRGETNEXT_OP(dir) readdir(dir)
# define GETFNAME_OP(file) (gchar *)file->d_name
# define CLOSEDIR_OP(dir) closedir(dir)
#else /* GLIB 2 */
# define DIRECTORY_T GDir
# define FILE_T gchar
# define OPENDIR_OP(name) g_dir_open(name, 0, dummy)
# define DIRGETNEXT_OP(dir) g_dir_read_name(dir)
# define GETFNAME_OP(file) (file);
# define CLOSEDIR_OP(dir) g_dir_close(dir)
#endif
void init_xml_names(void) {
xml_ns_t* xmlpi_xml_ns;
guint i;
DIRECTORY_T* dir;
const FILE_T* file;
const gchar* filename;
gchar* dirname;
#if GLIB_MAJOR_VERSION >= 2
GError** dummy = g_malloc(sizeof(GError *));
*dummy = NULL;
#endif
xmpli_names = g_hash_table_new(g_str_hash,g_str_equal);
media_types = g_hash_table_new(g_str_hash,g_str_equal);
unknown_ns.elements = g_hash_table_new(g_str_hash,g_str_equal);
unknown_ns.attributes = g_hash_table_new(g_str_hash,g_str_equal);
unknown_ns.elements = xml_ns.elements = g_hash_table_new(g_str_hash,g_str_equal);
unknown_ns.attributes = xml_ns.attributes = g_hash_table_new(g_str_hash,g_str_equal);
xmlpi_xml_ns = xml_new_namespace(xmpli_names,"xml","XML XMLPI","XML XMLPI",
"version","encoding","standalone",NULL);
xmlpi_xml_ns = xml_new_namespace(xmpli_names,"xml","version","encoding","standalone",NULL);
g_hash_table_destroy(xmlpi_xml_ns->elements);
xmlpi_xml_ns->elements = NULL;
dirname = get_persconffile_path("dtds", FALSE);
if (test_for_directory(dirname) != EISDIR) {
dirname = get_datafile_path("dtds");
}
if (test_for_directory(dirname) == EISDIR) {
if ((dir = OPENDIR_OP(dirname)) != NULL) {
while ((file = DIRGETNEXT_OP(dir)) != NULL) {
guint namelen;
filename = GETFNAME_OP(file);
namelen = strlen(filename);
if ( namelen > 4 && ( g_strcasecmp(filename+(namelen-4),".dtd") == 0 ) ) {
GString* errors = g_string_new("");
GString* preparsed = dtd_preparse(dirname, filename, errors);
dtd_build_data_t* dtd_data;
if (errors->len) {
report_failure("Dtd Preparser in file %s%c%s: %s",dirname,G_DIR_SEPARATOR,filename,errors->str);
continue;
}
dtd_data = dtd_parse(preparsed);
g_string_free(preparsed,TRUE);
if (dtd_data->error->len) {
report_failure("Dtd Parser in file %s%c%s: %s",dirname,G_DIR_SEPARATOR,filename,dtd_data->error->str);
destroy_dtd_data(dtd_data);
continue;
}
register_dtd(dtd_data,errors);
if (errors->len) {
report_failure("Dtd Registration in file: %s%c%s: %s",dirname,G_DIR_SEPARATOR,filename,errors->str);
g_string_free(errors,TRUE);
continue;
}
}
}
CLOSEDIR_OP(dir);
}
}
for(i=0;i<array_length(default_media_types);i++) {
if( ! g_hash_table_lookup(media_types,default_media_types[i]) ) {
g_hash_table_insert(media_types,(gpointer)default_media_types[i],&xml_ns);
}
}
g_hash_table_foreach(xmpli_names,add_xmlpi_namespace,"xml.xmlpi");
}
#if GLIB_MAJOR_VERSION >= 2
g_free(dummy);
#endif
}
void
proto_register_xml(void) {
@ -568,25 +1072,30 @@ proto_register_xml(void) {
{ &hf_dtd_tag, {"DTD Tag", "xml.dtdtag", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }},
{ &unknown_ns.hf_cdata, {"CDATA", "xml.cdata", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }},
{ &unknown_ns.hf_tag, {"Tag", "xml.tag", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }},
{ &hf_junk, {"Unknown", "xml.unknown", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}
{ &xml_ns.hf_cdata, {"Unknown", "xml.unknown", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}
};
hf = g_array_new(FALSE,FALSE,sizeof(hf_register_info));
hf_arr = g_array_new(FALSE,FALSE,sizeof(hf_register_info));
ett_arr = g_array_new(FALSE,FALSE,sizeof(gint*));
g_array_append_vals(hf,hf_base,array_length(hf_base));
g_array_append_vals(hf_arr,hf_base,array_length(hf_base));
g_array_append_vals(ett_arr,ett_base,array_length(ett_base));
init_xml_names();
xml_ns.hf_tag = proto_register_protocol(xml_ns.blurb, xml_ns.longname, xml_ns.name);
xml_ns.hf_tag = proto_register_protocol("eXtensible Markup Language", "XML", xml_ns.name);
proto_register_field_array(xml_ns.hf_tag, (hf_register_info*)hf->data, hf->len);
proto_register_field_array(xml_ns.hf_tag, (hf_register_info*)hf_arr->data, hf_arr->len);
proto_register_subtree_array((gint**)ett_arr->data, ett_arr->len);
register_dissector("xml", dissect_xml, xml_ns.hf_tag);
init_xml_parser();
}
void add_dissector_media(gpointer k, gpointer v _U_, gpointer p _U_) {
dissector_add_string("media_type", (gchar*)k, xml_handle);
}
void
@ -595,33 +1104,6 @@ proto_reg_handoff_xml(void)
xml_handle = find_dissector("xml");
dissector_add_string("media_type", "text/xml", xml_handle);
dissector_add_string("media_type", "application/xml", xml_handle);
dissector_add_string("media_type", "application/soap+xml", xml_handle);
dissector_add_string("media_type", "application/xml-dtd", xml_handle);
/* WAP and OMA XML media */
dissector_add_string("media_type", "text/vnd.wap.wml", xml_handle);
dissector_add_string("media_type", "text/vnd.wap.si", xml_handle);
dissector_add_string("media_type", "text/vnd.wap.sl", xml_handle);
dissector_add_string("media_type", "text/vnd.wap.co", xml_handle);
dissector_add_string("media_type", "text/vnd.wap.emn", xml_handle);
dissector_add_string("media_type", "application/vnd.wv.csp+xml", xml_handle);
/* The Extensible Markup Language (XML) Configuration Access Protocol (XCAP)
* draft-ietf-simple-xcap-06
*/
dissector_add_string("media_type", "application/xcap-el+xml", xml_handle);
dissector_add_string("media_type", "application/xcap-att+xml", xml_handle);
dissector_add_string("media_type", "application/xcap-error+xml", xml_handle);
dissector_add_string("media_type", "application/xcap-caps+xml", xml_handle);
/* draft-ietf-simple-presence-rules-02 */
dissector_add_string("media_type", "application/auth-policy+xml", xml_handle);
/* Other */
dissector_add_string("media_type", "application/smil", xml_handle);
dissector_add_string("media_type", "application/cpim-pidf+xml", xml_handle);
dissector_add_string("media_type", "application/rdf+xml", xml_handle);
dissector_add_string("media_type", "application/xslt+xml", xml_handle);
dissector_add_string("media_type", "application/mathml+xml", xml_handle);
dissector_add_string("media_type", "image/svg+xml", xml_handle);
dissector_add_string("media_type", "application/vnd.wv.csp.xml", xml_handle);
g_hash_table_foreach(media_types,add_dissector_media,NULL);
}

View File

@ -37,6 +37,7 @@ typedef struct _dtd_build_data_t {
gchar* media_type;
gchar* description;
gchar* proto_root;
gboolean recursion;
GPtrArray* elements;
GPtrArray* attributes;
@ -55,7 +56,7 @@ typedef struct _dtd_named_list_t {
GPtrArray* list;
} dtd_named_list_t;
extern GString* dtd_preparse(gchar* dname, gchar* fname, GString* err);
extern GString* dtd_preparse(const gchar* dname, const gchar* fname, GString* err);
extern dtd_build_data_t* dtd_parse(GString* s);
#endif

View File

@ -85,8 +85,31 @@ dtd ::= doctype.
dtd ::= dtd_parts.
doctype ::= TAG_START DOCTYPE_KW NAME(Name) OPEN_BRACKET dtd_parts CLOSE_BRACKET TAG_STOP. {
bd->proto_name = g_strdup(Name->text);
dtd_named_list_t* root;
GPtrArray* root_elems = g_ptr_array_new();
guint i;
if(! bd->proto_name) {
bd->proto_name = g_strdup(Name->text);
}
if(bd->proto_root)
g_free(bd->proto_root);
bd->proto_root = g_strdup(Name->text);
g_strdown(bd->proto_name);
for( i = 0; i< bd->elements->len; i++) {
dtd_named_list_t* el = g_ptr_array_index(bd->elements,i);
g_ptr_array_add(root_elems,g_strdup(el->name));
}
root = dtd_named_list_new(g_strdup(Name->text),root_elems);
g_ptr_array_add(bd->elements,root);
}
dtd_parts ::= dtd_parts element(Element). { g_ptr_array_add(bd->elements,Element); }
@ -95,10 +118,10 @@ dtd_parts ::= element(Element). { g_ptr_array_add(bd->elements,Element); }
dtd_parts ::= attlist(Attlist). { g_ptr_array_add(bd->attributes,Attlist); }
%type attlist { dtd_named_list_t* }
attlist(A) ::= TAG_START ATTLIST_KW NAME(B) attrib_list(TheList) TAG_STOP. { A = dtd_named_list_new(B->text,TheList); }
attlist(A) ::= TAG_START ATTLIST_KW NAME(B) attrib_list(TheList) TAG_STOP. { g_strdown(B->text); A = dtd_named_list_new(B->text,TheList); }
%type element { dtd_named_list_t* }
element(A) ::= TAG_START ELEMENT_KW NAME(B) sub_elements(C) TAG_STOP. { A = dtd_named_list_new(B->text,C); }
element(A) ::= TAG_START ELEMENT_KW NAME(B) sub_elements(C) TAG_STOP. { g_strdown(B->text); A = dtd_named_list_new(B->text,C); }
%type attrib_list { GPtrArray* }
attrib_list(A) ::= attrib_list(B) attrib(C). { g_ptr_array_add(B,C); A = B; }

View File

@ -62,13 +62,15 @@
static void set_media_type (gchar* val) { if(build_data->media_type) g_free(build_data->media_type); build_data->media_type = g_strdup(val); }
static void set_proto_root (gchar* val) { if(build_data->proto_root) g_free(build_data->proto_root); build_data->proto_root = g_strdup(val); }
static void set_description (gchar* val) { if(build_data->description) g_free(build_data->description); build_data->description = g_strdup(val); }
static void set_recursive (gchar* val) { build_data->recursion = ( g_strcasecmp(val,"yes") == 0 ) ? TRUE : FALSE; }
struct _proto_xmlpi_attr proto_attrs[] =
{
{ "name", set_proto_name },
{ "proto_name", set_proto_name },
{ "media", set_media_type },
{ "root", set_proto_root },
{ "description", set_description },
{ "hierarchy", set_recursive },
{NULL,NULL}
};
@ -82,6 +84,9 @@
%}
comment_start "<!--"
comment_stop "-->"
start_xmlpi "<?"
location_xmlpi "ethereal:location"
@ -133,15 +138,21 @@ comma ","
pipe "|"
dquote ["]
name [a-z][-a-z0-9_]*
name [a-z][-a-zA-Z0-9_]*
dquoted ["][^\"]*["]
squoted ['][^\']*[']
%START DTD XMLPI LOCATION DONE PROTOCOL GET_ATTR_QUOTE GET_ATTR_VAL GET_ATTR_CLOSE_QUOTE
%START DTD XMLPI LOCATION DONE PROTOCOL GET_ATTR_QUOTE GET_ATTR_VAL GET_ATTR_CLOSE_QUOTE IN_COMMENT
%%
{whitespace} ;
<DTD>{comment_start} { BEGIN IN_COMMENT; }
<IN_COMMENT>[^-]? |
<IN_COMMENT>[-] ;
<IN_COMMENT>{comment_stop} { BEGIN DTD; }
<DTD>{start_xmlpi} {
BEGIN XMLPI;
}
@ -167,6 +178,7 @@ squoted ['][^\']*[']
<PROTOCOL>{name} {
attr_name = g_strdup(yytext);
g_strdown(attr_name);
BEGIN GET_ATTR_QUOTE;
}
@ -292,13 +304,16 @@ extern dtd_build_data_t* dtd_parse(GString* s) {
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->location = NULL;
build_data->error = g_string_new("");
location = NULL;
BEGIN DTD;
yylex();

View File

@ -56,16 +56,14 @@ GHashTable* entities;
gchar* entity_name;
GString* error;
gchar* dirname;
gchar* filename;
const gchar* dirname;
const gchar* filename;
guint linenum;
gchar* textstr;
GString* textstr;
static gchar* replace_entity(gchar* s);
static const gchar* location(void);
static gchar* load_entity_file(gchar* filename);
/* [:blank:]+file[:blank:]*=[:blank:]*["] */
%}
xmlpi_start "<?"
@ -95,7 +93,7 @@ entity [%&][A-Za-z][-A-Za-z0-9_]*;
whitespace [[blank:]]+
newline \n
%START OUTSIDE IN_COMMENT IN_ENTITY NAMED_ENTITY IN_QUOTE ENTITY_DONE GET_FNAME_OPEN_QUOTE GET_FNAME GET_FNAME_CLOSE_QUOTE XMLPI
%START OUTSIDE IN_COMMENT IN_ENTITY NAMED_ENTITY IN_QUOTE ENTITY_DONE XMLPI
%%
@ -126,77 +124,14 @@ newline \n
<IN_QUOTE>{percent} |
<IN_QUOTE>{non_quote} |
<IN_QUOTE>{escaped_quote} g_string_append(current,yytext);
<NAMED_ENTITY>{system} { BEGIN GET_FNAME_OPEN_QUOTE; }
<GET_FNAME_OPEN_QUOTE>{quote} { BEGIN GET_FNAME; }
<GET_FNAME>{filename} {
if ((textstr = load_entity_file(yytext))) {
g_hash_table_insert(entities,entity_name,textstr);
} else {
yyterminate();
}
BEGIN GET_FNAME_CLOSE_QUOTE;
<NAMED_ENTITY>{system} {
g_string_sprintfa(error,"at %s:%u: file inclusion is not supported!", filename, linenum);
yyterminate();
}
<GET_FNAME_CLOSE_QUOTE>{quote} { BEGIN ENTITY_DONE; }
<ENTITY_DONE>{special_stop} { current = output; g_string_append(current,"\n"); BEGIN OUTSIDE; }
%%
static gchar* load_entity_file(gchar* fname) {
gchar* fullname = g_strdup_printf("%s%s",dirname,fname);
gchar* save_filename = filename;
guint save_linenum = linenum;
FILE* fp = fopen(fullname,"r");
GString* filetext;
gchar* retstr;
gchar c;
g_free(fullname);
if (!fp) {
g_string_sprintfa(error,"at %s:%u: could not load file %s: %s", filename, linenum, fname, strerror(errno));
return NULL;
}
filename = fname;
linenum = 1;
filetext = g_string_new(location());
while( ! feof(fp)) {
c = fgetc(fp);
if ( ferror(fp) ) {
g_string_sprintfa(error,"at %s:%u: problem reading file %s: %s", filename, linenum, fname, strerror(errno));
g_string_free(filetext,TRUE);
filename = save_filename;
save_linenum = linenum;
return NULL;
}
g_string_append_c(filetext,c);
if(c == '\n') {
g_string_append(filetext,location());
linenum++;
}
}
retstr = filetext->str;
g_string_free(filetext,FALSE);
filename = save_filename;
save_linenum = linenum;
return retstr;
}
static gchar* replace_entity(gchar* entity) {
GString* replacement;
@ -207,7 +142,7 @@ static gchar* replace_entity(gchar* entity) {
if (replacement) {
return replacement->str;
} else {
g_string_sprintfa(error,"dtd_preparse: in file '%s': %s does not exists\n", filename, entity);
g_string_sprintfa(error,"dtd_preparse: in file '%s': entity %s does not exists\n", filename, entity);
return "";
}
@ -244,8 +179,8 @@ static gboolean free_gstring_hash_items(gpointer k,gpointer v,gpointer p _U_) {
return TRUE;
}
extern GString* dtd_preparse(gchar* dname, gchar* fname, GString* err) {
gchar* fullname = g_strdup_printf("%s%s",dname,fname);
extern GString* dtd_preparse(const gchar* dname,const gchar* fname, GString* err) {
gchar* fullname = g_strdup_printf("%s%c%s",dname,G_DIR_SEPARATOR,fname);
dirname = dname;
filename = fname;