put original tag name (not lowercase) into dissected xml structure too
[obnox/wireshark/wip.git] / epan / dissectors / packet-xml.c
1 /* packet-xml.c
2  * wireshark's xml dissector .
3  *
4  * (C) 2005, Luis E. Garcia Ontanon.
5  *
6  * $Id$
7  *
8  * Refer to the AUTHORS file or the AUTHORS section in the man page
9  * for contacting the author(s) of this file.
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #ifdef HAVE_DIRENT_H
35 #include <dirent.h>
36 #endif
37
38 #include <ctype.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdarg.h>
42 #include <errno.h>
43
44 #include <stdio.h>
45
46 #include <glib.h>
47
48 #include <wsutil/str_util.h>
49
50 #include <epan/emem.h>
51 #include <epan/packet.h>
52 #include <epan/tvbparse.h>
53 #include <epan/dtd.h>
54 #include <epan/report_err.h>
55 #include <epan/filesystem.h>
56 #include <epan/prefs.h>
57 #include <epan/garrayfix.h>
58
59 #include "packet-xml.h"
60
61 struct _attr_reg_data {
62         GArray* hf;
63         gchar* basename;
64 };
65
66
67 static gint ett_dtd = -1;
68 static gint ett_xmpli = -1;
69
70 static int hf_unknowwn_attrib = -1;
71 static int hf_comment = -1;
72 static int hf_xmlpi = -1;
73 static int hf_dtd_tag = -1;
74 static int hf_doctype = -1;
75
76 /* dissector handles */
77 static dissector_handle_t xml_handle;
78
79 /* parser definitions */
80 static tvbparse_wanted_t* want;
81 static tvbparse_wanted_t* want_ignore;
82 static tvbparse_wanted_t* want_heur;
83
84 static GHashTable* xmpli_names;
85 static GHashTable* media_types;
86
87 static xml_ns_t xml_ns = {"xml","/",-1,-1,-1,NULL,NULL,NULL};
88 static xml_ns_t unknown_ns = {"unknown","?",-1,-1,-1,NULL,NULL,NULL};
89 static xml_ns_t* root_ns;
90
91 static gboolean pref_heuristic_media = FALSE;
92 static gboolean pref_heuristic_tcp = FALSE;
93 static gboolean pref_heuristic_udp = FALSE;
94 static gboolean pref_heuristic_media_save = FALSE;
95 static gboolean pref_heuristic_tcp_save = FALSE;
96 static gboolean pref_heuristic_udp_save = FALSE;
97 static range_t *global_xml_tcp_range = NULL;
98 static range_t *xml_tcp_range = NULL;
99
100 #define XML_CDATA -1000
101 #define XML_SCOPED_NAME -1001
102
103
104 GArray* hf_arr;
105 GArray* ett_arr;
106
107 static const gchar* default_media_types[] = {
108         "text/xml",
109         "text/vnd.wap.wml",
110         "text/vnd.wap.si",
111         "text/vnd.wap.sl",
112         "text/vnd.wap.co",
113         "text/vnd.wap.emn",
114         "application/auth-policy+xml",
115         "application/cpim-pidf+xml",
116         "application/cpl+xml",
117         "application/mathml+xml",
118         "application/media_control+xml",
119         "application/note+xml",
120         "application/pidf+xml",
121         "application/poc-settings+xml",
122         "application/rdf+xml",
123         "application/reginfo+xml",
124         "application/resource-lists+xml",
125         "application/rlmi+xml",
126         "application/rls-services+xml",
127         "application/smil",
128         "application/simple-filter+xml",
129         "application/soap+xml",
130         "application/vnd.wv.csp+xml",
131         "application/vnd.wv.csp.xml",
132         "application/watcherinfo+xml",
133         "application/xcap-att+xml",
134         "application/xcap-caps+xml",
135         "application/xcap-diff+xml",
136         "application/xcap-el+xml",
137         "application/xcap-error+xml",
138         "application/xcap-ns+xml",
139         "application/xml",
140         "application/xml-dtd",
141         "application/xpidf+xml",
142         "application/xslt+xml",
143         "application/x-wms-logconnectstats",
144         "application/x-wms-logplaystats",
145         "application/x-wms-sendevent",
146         "application/rss+xml",   
147         "image/svg+xml",
148 };
149
150 static void insert_xml_frame(xml_frame_t *parent, xml_frame_t *new_child) {
151         new_child->firts_child = NULL;
152         new_child->last_child = NULL;
153
154         new_child->parent = parent;
155         new_child->next_sibling = NULL;
156         new_child->prev_sibling = NULL;
157         if (parent == NULL) return;  /* root */
158
159         if (parent->firts_child == NULL) {  /* the 1st child */
160                 parent->firts_child = new_child;
161         } else {  /* following children */
162                 parent->last_child->next_sibling = new_child;
163                 new_child->prev_sibling = parent->last_child;
164         }
165         parent->last_child = new_child;
166 }
167
168 static void
169 dissect_xml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
170 {
171         tvbparse_t* tt;
172         tvbparse_elem_t* tok = NULL;
173         static GPtrArray* stack = NULL;
174         xml_frame_t* current_frame;
175         char* colinfo_str;
176         
177         if (stack != NULL)
178                 g_ptr_array_free(stack,TRUE);
179
180         stack = g_ptr_array_new();
181         current_frame = ep_alloc(sizeof(xml_frame_t));
182         current_frame->type = XML_FRAME_ROOT;
183         current_frame->name = NULL;
184         insert_xml_frame(NULL, current_frame);
185         g_ptr_array_add(stack,current_frame);
186
187         tt = tvbparse_init(tvb,0,-1,stack,want_ignore);
188         current_frame->start_offset = 0;
189
190         root_ns = NULL;
191
192         if (pinfo->match_string)
193                 root_ns = g_hash_table_lookup(media_types,pinfo->match_string);
194
195         if (! root_ns ) {
196                 root_ns = &xml_ns;
197                 colinfo_str = "/XML";
198         } else {
199                 colinfo_str = ep_strdup_printf("/%s",root_ns->name);
200                 ascii_strup_inplace(colinfo_str);
201         }
202
203         if (check_col(pinfo->cinfo, COL_PROTOCOL))
204                 col_append_str(pinfo->cinfo, COL_PROTOCOL, colinfo_str);
205
206         current_frame->ns = root_ns;
207
208         current_frame->item = proto_tree_add_item(tree,current_frame->ns->hf_tag,tvb,0,-1,FALSE);
209         current_frame->tree = proto_item_add_subtree(current_frame->item,current_frame->ns->ett);
210         current_frame->last_item = current_frame->item;
211
212         while(( tok = tvbparse_get(tt, want) )) ;
213
214         pinfo->private_data = current_frame;  /* pass XML structure to the dissector calling XML */
215 }
216
217 static gboolean dissect_xml_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
218         if ( (pref_heuristic_media || pref_heuristic_tcp || pref_heuristic_udp)
219              && tvbparse_peek(tvbparse_init(tvb,0,-1,NULL,want_ignore), want_heur)) {
220                 dissect_xml(tvb, pinfo, tree);
221                 return TRUE;
222         } else {
223                 return FALSE;
224         }
225 }
226
227 static void after_token(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok) {
228         GPtrArray* stack = tvbparse_data;
229         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
230         int hfid;
231         proto_item* pi;
232
233         if (tok->id == XML_CDATA) {
234                 hfid = current_frame->ns ? current_frame->ns->hf_cdata : xml_ns.hf_cdata;
235         } else if ( tok->id > 0) {
236                 hfid = tok->id;
237         } else {
238                 hfid = xml_ns.hf_cdata;
239         }
240
241         pi = proto_tree_add_item(current_frame->tree, hfid, tok->tvb, tok->offset, tok->len, FALSE);
242
243         proto_item_set_text(pi, "%s",
244                                                 tvb_format_text(tok->tvb,tok->offset,tok->len));
245 }
246
247 static void before_xmpli(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok) {
248         GPtrArray* stack = tvbparse_data;
249         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
250         proto_item* pi;
251         proto_tree* pt;
252         tvbparse_elem_t* name_tok = tok->sub->next;
253         gchar* name = tvb_get_ephemeral_string(name_tok->tvb,name_tok->offset,name_tok->len);
254         xml_ns_t* ns = g_hash_table_lookup(xmpli_names,name);
255         xml_frame_t* new_frame;
256
257         int hf_tag;
258         gint ett;
259
260         ascii_strdown_inplace(name);
261         if (!ns) {
262                 hf_tag = hf_xmlpi;
263                 ett = ett_xmpli;
264         } else {
265                 hf_tag = ns->hf_tag;
266                 ett = ns->ett;
267         }
268
269         pi = proto_tree_add_item(current_frame->tree,hf_tag,tok->tvb,tok->offset,tok->len,FALSE);
270
271         proto_item_set_text(pi, "%s", tvb_format_text(tok->tvb,tok->offset,(name_tok->offset - tok->offset) + name_tok->len));
272
273         pt = proto_item_add_subtree(pi,ett);
274
275         new_frame = ep_alloc(sizeof(xml_frame_t));
276         new_frame->type = XML_FRAME_XMPLI;
277         new_frame->name = name;
278         new_frame->name_orig_case = name;
279         insert_xml_frame(current_frame, new_frame);
280         new_frame->item = pi;
281         new_frame->last_item = pi;
282         new_frame->tree = pt;
283         new_frame->start_offset = tok->offset;
284         new_frame->ns = ns;
285
286         g_ptr_array_add(stack,new_frame);
287
288 }
289
290 static void after_xmlpi(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok) {
291         GPtrArray* stack = tvbparse_data;
292         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
293
294         proto_tree_add_text(current_frame->tree,
295                                                    tok->tvb, tok->offset, tok->len,
296                                                    tvb_format_text(tok->tvb,tok->offset,tok->len));
297
298         if (stack->len > 1) {
299                 g_ptr_array_remove_index_fast(stack,stack->len - 1);
300         } else {
301                 proto_tree_add_text(current_frame->tree,tok->tvb,tok->offset,tok->len,"[ ERROR: Closing an unopened xmpli tag ]");
302         }
303 }
304
305 static void before_tag(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok) {
306         GPtrArray* stack = tvbparse_data;
307         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
308         tvbparse_elem_t* name_tok = tok->sub->next;
309         gchar* root_name;
310         gchar *name = NULL, *name_orig_case = NULL;
311         xml_ns_t* ns;
312         xml_frame_t* new_frame;
313         proto_item* pi;
314         proto_tree* pt;
315
316         if (name_tok->sub->id == XML_SCOPED_NAME) {
317                 tvbparse_elem_t* root_tok = name_tok->sub->sub;
318                 tvbparse_elem_t* leaf_tok = name_tok->sub->sub->next->next;
319                 xml_ns_t* nameroot_ns;
320
321                 root_name = (gchar*)tvb_get_ephemeral_string(root_tok->tvb,root_tok->offset,root_tok->len);
322                 name = (gchar*)tvb_get_ephemeral_string(leaf_tok->tvb,leaf_tok->offset,leaf_tok->len);
323                 name_orig_case = name;
324
325                 nameroot_ns = g_hash_table_lookup(xml_ns.elements,root_name);
326
327                 if(nameroot_ns) {
328                         ns = g_hash_table_lookup(nameroot_ns->elements,name);
329                         if (!ns) {
330                                 ns = &unknown_ns;
331                         }
332                 } else {
333                         ns = &unknown_ns;
334                 }
335
336         } else {
337                 name = tvb_get_ephemeral_string(name_tok->tvb,name_tok->offset,name_tok->len);
338                 name_orig_case = ep_strdup(name);
339                 ascii_strdown_inplace(name);
340
341                 if(current_frame->ns) {
342                         ns = g_hash_table_lookup(current_frame->ns->elements,name);
343
344                         if (!ns) {
345                                 if (! ( ns = g_hash_table_lookup(root_ns->elements,name) ) ) {
346                                         ns = &unknown_ns;
347                                 }
348                         }
349                 } else {
350                         ns = &unknown_ns;
351                 }
352         }
353
354         pi = proto_tree_add_item(current_frame->tree,ns->hf_tag,tok->tvb,tok->offset,tok->len,FALSE);
355         proto_item_set_text(pi, "%s", tvb_format_text(tok->tvb,tok->offset,(name_tok->offset - tok->offset) + name_tok->len));
356
357         pt = proto_item_add_subtree(pi,ns->ett);
358
359         new_frame = ep_alloc(sizeof(xml_frame_t));
360         new_frame->type = XML_FRAME_TAG;
361         new_frame->name = name;
362         new_frame->name_orig_case = name_orig_case;
363         insert_xml_frame(current_frame, new_frame);
364         new_frame->item = pi;
365         new_frame->last_item = pi;
366         new_frame->tree = pt;
367         new_frame->start_offset = tok->offset;
368         new_frame->ns = ns;
369
370         g_ptr_array_add(stack,new_frame);
371
372 }
373
374 static void after_open_tag(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok _U_) {
375         GPtrArray* stack = tvbparse_data;
376         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
377
378         proto_item_append_text(current_frame->last_item,">");
379 }
380
381 static void after_closed_tag(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok) {
382         GPtrArray* stack = tvbparse_data;
383         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
384
385         proto_item_append_text(current_frame->last_item,"/>");
386
387         if (stack->len > 1) {
388                 g_ptr_array_remove_index_fast(stack,stack->len - 1);
389         } else {
390                 proto_tree_add_text(current_frame->tree,tok->tvb,tok->offset,tok->len,"[ ERROR: Closing an unopened tag ]");
391         }
392 }
393
394 static void after_untag(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok){
395         GPtrArray* stack = tvbparse_data;
396         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
397
398         proto_item_set_len(current_frame->item, (tok->offset - current_frame->start_offset) + tok->len);
399
400         proto_tree_add_text(current_frame->tree,tok->tvb,tok->offset,tok->len,"%s",
401                                                 tvb_format_text(tok->tvb,tok->offset,tok->len));
402
403         if (stack->len > 1) {
404                 g_ptr_array_remove_index_fast(stack,stack->len - 1);
405         } else {
406                 proto_tree_add_text(current_frame->tree,tok->tvb,tok->offset,tok->len,
407                                                         "[ ERROR: Closing an unopened tag ]");
408         }
409 }
410
411 static void before_dtd_doctype(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok){
412         GPtrArray* stack = tvbparse_data;
413         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
414         xml_frame_t* new_frame;
415         tvbparse_elem_t* name_tok = tok->sub->next->next->next->sub->sub;
416         proto_tree* dtd_item = proto_tree_add_item(current_frame->tree, hf_doctype,
417                                                                                            name_tok->tvb, name_tok->offset, name_tok->len, FALSE);
418
419         proto_item_set_text(dtd_item,"%s",tvb_format_text(tok->tvb,tok->offset,tok->len));
420
421         new_frame = ep_alloc(sizeof(xml_frame_t));
422         new_frame->type = XML_FRAME_DTD_DOCTYPE;
423         new_frame->name = (gchar*)tvb_get_ephemeral_string(name_tok->tvb,name_tok->offset,name_tok->len);
424         new_frame->name_orig_case = new_frame->name;
425         insert_xml_frame(current_frame, new_frame);
426         new_frame->item = dtd_item;
427         new_frame->last_item = dtd_item;
428         new_frame->tree = proto_item_add_subtree(dtd_item,ett_dtd);
429         new_frame->start_offset = tok->offset;
430         new_frame->ns = NULL;
431
432         g_ptr_array_add(stack,new_frame);
433 }
434
435 static void pop_stack(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok _U_) {
436         GPtrArray* stack = tvbparse_data;
437         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
438
439         if (stack->len > 1) {
440                 g_ptr_array_remove_index_fast(stack,stack->len - 1);
441         } else {
442                 proto_tree_add_text(current_frame->tree,tok->tvb,tok->offset,tok->len,
443                                                         "[ ERROR: Closing an unopened tag ]");
444         }
445 }
446
447 static void after_dtd_close(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok){
448         GPtrArray* stack = tvbparse_data;
449         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
450
451         proto_tree_add_text(current_frame->tree,tok->tvb,tok->offset,tok->len,"%s",
452                                                 tvb_format_text(tok->tvb,tok->offset,tok->len));
453         if (stack->len > 1) {
454                 g_ptr_array_remove_index_fast(stack,stack->len - 1);
455         } else {
456                 proto_tree_add_text(current_frame->tree,tok->tvb,tok->offset,tok->len,"[ ERROR: Closing an unopened tag ]");
457         }
458 }
459
460 static void get_attrib_value(void* tvbparse_data _U_, const void* wanted_data _U_, tvbparse_elem_t* tok) {
461         tok->data = tok->sub;
462 }
463
464 static void after_attrib(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok) {
465         GPtrArray* stack = tvbparse_data;
466         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
467         gchar* name = (gchar*)tvb_get_ephemeral_string(tok->sub->tvb,tok->sub->offset,tok->sub->len);
468         tvbparse_elem_t* value = tok->sub->next->next->data;
469         int* hfidp;
470         int hfid;
471
472         ascii_strdown_inplace(name);
473         if(current_frame->ns && (hfidp = g_hash_table_lookup(current_frame->ns->attributes,name) )) {
474                 hfid = *hfidp;
475         } else {
476                 hfid = hf_unknowwn_attrib;
477                 value = tok;
478         }
479
480         current_frame->last_item = proto_tree_add_item(current_frame->tree,hfid,value->tvb,value->offset,value->len,FALSE);
481         proto_item_set_text(current_frame->last_item, "%s", tvb_format_text(tok->tvb,tok->offset,tok->len));
482
483 }
484
485 static void unrecognized_token(void* tvbparse_data, const void* wanted_data _U_, tvbparse_elem_t* tok _U_){
486         GPtrArray* stack = tvbparse_data;
487         xml_frame_t* current_frame = g_ptr_array_index(stack,stack->len - 1);
488
489         proto_tree_add_text(current_frame->tree,tok->tvb,tok->offset,tok->len,"[ ERROR: Unrecognized text ]");
490
491 }
492
493
494
495 static void init_xml_parser(void) {
496         tvbparse_wanted_t* want_name = tvbparse_chars(-1,1,0,"abcdefghijklmnopqrstuvwxyz-_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",NULL,NULL,NULL);
497         tvbparse_wanted_t* want_attr_name = tvbparse_chars(-1,1,0,"abcdefghijklmnopqrstuvwxyz-_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:",NULL,NULL,NULL);
498
499         tvbparse_wanted_t* want_scoped_name = tvbparse_set_seq(XML_SCOPED_NAME, NULL, NULL, NULL,
500                                                                want_name,
501                                                                tvbparse_char(-1,":",NULL,NULL,NULL),
502                                                                want_name,
503                                                                NULL);
504
505         tvbparse_wanted_t* want_tag_name = tvbparse_set_oneof(0, NULL, NULL, NULL,
506                                                               want_scoped_name,
507                                                               want_name,
508                                                               NULL);
509
510         tvbparse_wanted_t* want_attrib_value = tvbparse_set_oneof(0, NULL, NULL, get_attrib_value,
511                                                                   tvbparse_quoted(-1, NULL, NULL, tvbparse_shrink_token_cb,'\"','\\'),
512                                                                   tvbparse_quoted(-1, NULL, NULL, tvbparse_shrink_token_cb,'\'','\\'),
513                                                                   tvbparse_chars(-1,1,0,"0123456789",NULL,NULL,NULL),
514                                                                   want_name,
515                                                                   NULL);
516
517         tvbparse_wanted_t* want_attributes = tvbparse_one_or_more(-1, NULL, NULL, NULL,
518                                                                   tvbparse_set_seq(-1, NULL, NULL, after_attrib,
519                                                                                    want_attr_name,
520                                                                                    tvbparse_char(-1,"=",NULL,NULL,NULL),
521                                                                                    want_attrib_value,
522                                                                                    NULL));
523
524         tvbparse_wanted_t* want_stoptag = tvbparse_set_oneof(-1,NULL,NULL,NULL,
525                                                              tvbparse_char(-1, ">", NULL, NULL, after_open_tag),
526                                                              tvbparse_string(-1, "/>", NULL, NULL, after_closed_tag),
527                                                              NULL);
528
529         tvbparse_wanted_t* want_stopxmlpi = tvbparse_string(-1,"?>",NULL,NULL,after_xmlpi);
530
531         tvbparse_wanted_t* want_comment = tvbparse_set_seq(hf_comment,NULL,NULL,after_token,
532                                                            tvbparse_string(-1,"<!--",NULL,NULL,NULL),
533                                                            tvbparse_until(-1,NULL,NULL,NULL,
534                                                                           tvbparse_string(-1,"-->",NULL,NULL,NULL),
535                                                                           TP_UNTIL_INCLUDE),
536                                                            NULL);
537
538         tvbparse_wanted_t* want_xmlpi = tvbparse_set_seq(hf_xmlpi,NULL,before_xmpli,NULL,
539                                                          tvbparse_string(-1,"<?",NULL,NULL,NULL),
540                                                          want_name,
541                                                          tvbparse_set_oneof(-1,NULL,NULL,NULL,
542                                                                             want_stopxmlpi,
543                                                                             tvbparse_set_seq(-1,NULL,NULL,NULL,
544                                                                                              want_attributes,
545                                                                                              want_stopxmlpi,
546                                                                                              NULL),
547                                                                             NULL),
548                                                          NULL);
549
550         tvbparse_wanted_t* want_closing_tag = tvbparse_set_seq(0,NULL,NULL,after_untag,
551                                                                tvbparse_char(-1, "<", NULL, NULL, NULL),
552                                                                tvbparse_char(-1, "/", NULL, NULL, NULL),
553                                                                want_tag_name,
554                                                                tvbparse_char(-1, ">", NULL, NULL, NULL),
555                                                                NULL);
556
557         tvbparse_wanted_t* want_doctype_start = tvbparse_set_seq(-1,NULL,before_dtd_doctype,NULL,
558                                                                  tvbparse_char(-1,"<",NULL,NULL,NULL),
559                                                                  tvbparse_char(-1,"!",NULL,NULL,NULL),
560                                                                  tvbparse_casestring(-1,"DOCTYPE",NULL,NULL,NULL),
561                                                                  tvbparse_set_oneof(-1,NULL,NULL,NULL,
562                                                                                     tvbparse_set_seq(-1,NULL,NULL,NULL,
563                                                                                                      want_name,
564                                                                                                      tvbparse_char(-1,"[",NULL,NULL,NULL),
565                                                                                                      NULL),
566                                                                                     tvbparse_set_seq(-1,NULL,NULL,pop_stack,
567                                                                                                      want_name,
568                                                                                                      tvbparse_set_oneof(-1,NULL,NULL,NULL,
569                                                                                                                         tvbparse_casestring(-1,"PUBLIC",NULL,NULL,NULL),
570                                                                                                                         tvbparse_casestring(-1,"SYSTEM",NULL,NULL,NULL),
571                                                                                                                         NULL),
572                                                                                                      tvbparse_until(-1,NULL,NULL,NULL,
573                                                                                                                     tvbparse_char(-1,">",NULL,NULL,NULL),
574                                                                                                                     TP_UNTIL_INCLUDE),
575                                                                                                      NULL),
576                                                                                     NULL),
577                                                                  NULL);
578
579         tvbparse_wanted_t* want_dtd_tag = tvbparse_set_seq(hf_dtd_tag,NULL,NULL,after_token,
580                                                            tvbparse_char(-1,"<",NULL,NULL,NULL),
581                                                            tvbparse_char(-1,"!",NULL,NULL,NULL),
582                                                            tvbparse_until(-1,NULL,NULL,NULL,
583                                                                           tvbparse_char(-1, ">", NULL, NULL, NULL),
584                                                                           TP_UNTIL_INCLUDE),
585                                                            NULL);
586
587         tvbparse_wanted_t* want_tag = tvbparse_set_seq(-1, NULL, before_tag, NULL,
588                                                        tvbparse_char(-1,"<",NULL,NULL,NULL),
589                                                        want_tag_name,
590                                                        tvbparse_set_oneof(-1,NULL,NULL,NULL,
591                                                                           tvbparse_set_seq(-1,NULL,NULL,NULL,
592                                                                                            want_attributes,
593                                                                                            want_stoptag,
594                                                                                            NULL),
595                                                                           want_stoptag,
596                                                                           NULL),
597                                                        NULL);
598
599         tvbparse_wanted_t* want_dtd_close = tvbparse_set_seq(-1,NULL,NULL,after_dtd_close,
600                                                              tvbparse_char(-1,"]",NULL,NULL,NULL),
601                                                              tvbparse_char(-1,">",NULL,NULL,NULL),
602                                                              NULL);
603
604         want_ignore = tvbparse_chars(-1,1,0," \t\r\n",NULL,NULL,NULL);
605
606
607         want = tvbparse_set_oneof(-1, NULL, NULL, NULL,
608                                   want_comment,
609                                   want_xmlpi,
610                                   want_closing_tag,
611                                   want_doctype_start,
612                                   want_dtd_close,
613                                   want_dtd_tag,
614                                   want_tag,
615                                   tvbparse_not_chars(XML_CDATA,1,0,"<",NULL,NULL,after_token),
616                                   tvbparse_not_chars(-1,1,0," \t\r\n",NULL,NULL,unrecognized_token),
617                                   NULL);
618
619         want_heur = tvbparse_set_oneof(-1, NULL, NULL, NULL,
620                                        want_comment,
621                                        want_xmlpi,
622                                        want_doctype_start,
623                                        want_dtd_tag,
624                                        want_tag,
625                                        NULL);
626
627 }
628
629
630 static xml_ns_t* xml_new_namespace(GHashTable* hash, gchar* name, ...) {
631         xml_ns_t* ns = g_malloc(sizeof(xml_ns_t));
632         va_list ap;
633         gchar* attr_name;
634
635         ns->name = g_strdup(name);
636         ns->hf_tag = -1;
637         ns->hf_cdata = -1;
638         ns->ett = -1;
639         ns->attributes = g_hash_table_new(g_str_hash,g_str_equal);
640         ns->elements = g_hash_table_new(g_str_hash,g_str_equal);
641
642         va_start(ap,name);
643
644         while(( attr_name = va_arg(ap,gchar*) )) {
645                 int* hfp = g_malloc(sizeof(int));
646                 *hfp = -1;
647                 g_hash_table_insert(ns->attributes,g_strdup(attr_name),hfp);
648         };
649
650         va_end(ap);
651
652         g_hash_table_insert(hash,ns->name,ns);
653
654         return ns;
655 }
656
657
658 static void add_xml_field(GArray* hfs, int* p_id, gchar* name, gchar* fqn) {
659         hf_register_info hfri;
660
661         hfri.p_id = p_id;
662         hfri.hfinfo.name = name;
663         hfri.hfinfo.abbrev = fqn;
664         hfri.hfinfo.type = FT_STRING;
665         hfri.hfinfo.display = BASE_NONE;
666         hfri.hfinfo.strings = NULL;
667         hfri.hfinfo.bitmask = 0x0;
668         hfri.hfinfo.blurb = "";
669         hfri.hfinfo.id = 0;
670         hfri.hfinfo.parent = 0;
671         hfri.hfinfo.ref_count = 0;
672         hfri.hfinfo.bitshift = 0;
673         hfri.hfinfo.same_name_next = NULL;
674         hfri.hfinfo.same_name_prev = NULL;
675
676         g_array_append_val(hfs,hfri);
677 }
678
679 static void add_xml_attribute_names(gpointer k, gpointer v, gpointer p) {
680         struct _attr_reg_data* d = p;
681         gchar* basename = g_strdup_printf("%s.%s",d->basename,(gchar*)k);
682         add_xml_field(d->hf, (int*) v, (gchar*)k, basename);
683 }
684
685
686 static void add_xmlpi_namespace(gpointer k _U_, gpointer v, gpointer p) {
687         xml_ns_t* ns = v;
688         gchar* basename = g_strdup_printf("%s.%s",(gchar*)p,ns->name);
689         gint* ett_p = &(ns->ett);
690         struct _attr_reg_data d;
691
692         add_xml_field(hf_arr, &(ns->hf_tag), basename, basename);
693
694         g_array_append_val(ett_arr,ett_p);
695
696         d.basename = basename;
697         d.hf = hf_arr;
698
699         g_hash_table_foreach(ns->attributes,add_xml_attribute_names,&d);
700
701 }
702
703 static void destroy_dtd_data(dtd_build_data_t* dtd_data) {
704
705         if(dtd_data->proto_name) g_free(dtd_data->proto_name);
706         if(dtd_data->media_type) g_free(dtd_data->media_type);
707         if(dtd_data->description) g_free(dtd_data->description);
708         if(dtd_data->proto_root) g_free(dtd_data->proto_root);
709
710         g_string_free(dtd_data->error,TRUE);
711
712
713         while(dtd_data->elements->len) {
714                 dtd_named_list_t* nl = g_ptr_array_remove_index_fast(dtd_data->elements,0);
715                 g_ptr_array_free(nl->list,TRUE);
716                 g_free(nl);
717         }
718
719         g_ptr_array_free(dtd_data->elements,TRUE);
720
721         while(dtd_data->attributes->len) {
722                 dtd_named_list_t* nl = g_ptr_array_remove_index_fast(dtd_data->attributes,0);
723                 g_ptr_array_free(nl->list,TRUE);
724                 g_free(nl);
725         }
726
727         g_ptr_array_free(dtd_data->attributes,TRUE);
728
729         g_free(dtd_data);
730
731 }
732
733
734 static void copy_attrib_item(gpointer k, gpointer v _U_, gpointer p) {
735         gchar* key = g_strdup(k);
736         int* value = g_malloc(sizeof(int));
737         GHashTable* dst = p;
738
739         *value = -1;
740         g_hash_table_insert(dst,key,value);
741
742 }
743
744 static GHashTable* copy_attributes_hash(GHashTable* src) {
745         GHashTable* dst = g_hash_table_new(g_str_hash,g_str_equal);
746
747         g_hash_table_foreach(src,copy_attrib_item,dst);
748
749         return dst;
750 }
751
752 static xml_ns_t* duplicate_element(xml_ns_t* orig) {
753         xml_ns_t* new_item  = g_malloc(sizeof(xml_ns_t));
754         guint i;
755
756         new_item->name = g_strdup(orig->name);
757         new_item->hf_tag = -1;
758         new_item->hf_cdata = -1;
759         new_item->ett = -1;
760         new_item->attributes = copy_attributes_hash(orig->attributes);
761         new_item->elements =  g_hash_table_new(g_str_hash,g_str_equal);
762         new_item->element_names = g_ptr_array_new();
763
764         for(i=0; i < orig->element_names->len; i++) {
765                 g_ptr_array_add(new_item->element_names,
766                                                    g_ptr_array_index(orig->element_names,i));
767         }
768
769         return new_item;
770 }
771
772 static gchar* fully_qualified_name(GPtrArray* hier, gchar* name, gchar* proto_name) {
773         guint i;
774         GString* s = g_string_new(proto_name);
775         gchar* str;
776         g_string_append(s,".");
777         
778         for (i = 1; i < hier->len; i++) {
779                 g_string_append_printf(s, "%s.",(gchar*)g_ptr_array_index(hier,i));
780         }
781
782         g_string_append(s,name);
783         str = s->str;
784         g_string_free(s,FALSE);
785
786         return str;
787 }
788
789
790 static xml_ns_t* make_xml_hier(gchar* elem_name,
791                                xml_ns_t* root,
792                                GHashTable* elements,
793                                GPtrArray* hier,
794                                GString* error,
795                                GArray* hfs,
796                                GArray* etts,
797                                char* proto_name) {
798         xml_ns_t* new;
799         xml_ns_t* orig;
800         gchar* fqn;
801         gint* ett_p;
802         struct _attr_reg_data d;
803         gboolean recurred = FALSE;
804         guint i;
805
806         if ( g_str_equal(elem_name,root->name) ) {
807                 return NULL;
808         }
809
810         if (! ( orig = g_hash_table_lookup(elements,elem_name) )) {
811                 g_string_append_printf(error,"element '%s' is not defined\n", elem_name);
812                 return NULL;
813         }
814
815         for (i = 0; i < hier->len; i++) {
816                 if( strcmp(elem_name,(gchar*) g_ptr_array_index(hier,i) ) == 0 ) {
817                         recurred = TRUE;
818                 }
819         }
820
821         if (recurred) {
822                 return NULL;
823         }
824
825         fqn = fully_qualified_name(hier,elem_name,proto_name);
826
827         new = duplicate_element(orig);
828         new->fqn = fqn;
829
830         add_xml_field(hfs, &(new->hf_tag), g_strdup(elem_name), fqn);
831         add_xml_field(hfs, &(new->hf_cdata), g_strdup(elem_name), fqn);
832
833         ett_p = &new->ett;
834         g_array_append_val(etts,ett_p);
835
836         d.basename = fqn;
837         d.hf = hfs;
838
839         g_hash_table_foreach(new->attributes,add_xml_attribute_names,&d);
840
841         while(new->element_names->len) {
842                 gchar* child_name = g_ptr_array_remove_index(new->element_names,0);
843                 xml_ns_t* child_element = NULL;
844
845                 g_ptr_array_add(hier,elem_name);
846                 child_element = make_xml_hier(child_name, root, elements, hier,error,hfs,etts,proto_name);
847                 g_ptr_array_remove_index_fast(hier,hier->len - 1);
848
849                 if (child_element) {
850                         g_hash_table_insert(new->elements,child_element->name,child_element);
851                 }
852         }
853
854         g_ptr_array_free(new->element_names,TRUE);
855         new->element_names = NULL;
856         return new;
857 }
858
859 static gboolean free_both(gpointer k, gpointer v, gpointer p _U_) {
860         g_free(k);
861         g_free(v);
862         return TRUE;
863 }
864
865 static gboolean free_elements(gpointer k _U_, gpointer v, gpointer p _U_) {
866         xml_ns_t* e = v;
867         g_free(e->name);
868         g_hash_table_foreach_remove(e->attributes,free_both,NULL);
869         g_hash_table_destroy(e->attributes);
870         g_hash_table_destroy(e->elements);
871
872         while (e->element_names->len) {
873                 g_free(g_ptr_array_remove_index(e->element_names,0));
874         }
875
876         g_ptr_array_free(e->element_names,TRUE);
877         g_free(e);
878
879         return TRUE;
880 }
881
882 static void register_dtd(dtd_build_data_t* dtd_data, GString* errors) {
883         GHashTable* elements = g_hash_table_new(g_str_hash,g_str_equal);
884         gchar* root_name = NULL;
885         xml_ns_t* root_element = NULL;
886         GArray* hfs;
887         GArray* etts;
888         GPtrArray* hier;
889         gchar* curr_name;
890         GPtrArray* element_names = g_ptr_array_new();
891
892         /* we first populate elements with the those coming from the parser */
893         while(dtd_data->elements->len) {
894                 dtd_named_list_t* nl = g_ptr_array_remove_index(dtd_data->elements,0);
895                 xml_ns_t* element = g_malloc(sizeof(xml_ns_t));
896
897                 /* we will use the first element found as root in case no other one was given. */
898                 if (root_name == NULL)
899                         root_name = g_strdup(nl->name);
900
901                 element->name = nl->name;
902                 element->element_names = nl->list;
903                 element->hf_tag = -1;
904                 element->hf_cdata = -1;
905                 element->ett = -1;
906                 element->attributes = g_hash_table_new(g_str_hash,g_str_equal);
907                 element->elements = g_hash_table_new(g_str_hash,g_str_equal);
908
909                 if( g_hash_table_lookup(elements,element->name) ) {
910                         g_string_append_printf(errors,"element %s defined more than once\n", element->name);
911                         free_elements(NULL,element,NULL);
912                 } else {
913                         g_hash_table_insert(elements,element->name,element);
914                         g_ptr_array_add(element_names,g_strdup(element->name));
915                 }
916
917                 g_free(nl);
918         }
919
920         /* then we add the attributes to its relative elements */
921         while(dtd_data->attributes->len) {
922                 dtd_named_list_t* nl = g_ptr_array_remove_index(dtd_data->attributes,0);
923                 xml_ns_t* element = g_hash_table_lookup(elements,nl->name);
924
925                 if (!element) {
926                         g_string_append_printf(errors,"element %s is not defined\n", nl->name);
927
928                         goto next_attribute;
929                 }
930
931                 while(nl->list->len) {
932                         gchar* name = g_ptr_array_remove_index(nl->list,0);
933                         int* id_p = g_malloc(sizeof(int));
934
935                         *id_p = -1;
936                         g_hash_table_insert(element->attributes,name,id_p);
937                 }
938
939 next_attribute:
940                 g_free(nl->name);
941                 g_ptr_array_free(nl->list,TRUE);
942                 g_free(nl);
943         }
944
945         /* if a proto_root is defined in the dtd we'll use that as root */
946         if( dtd_data->proto_root ) {
947                 if(root_name)
948                         g_free(root_name);
949                 root_name = g_strdup(dtd_data->proto_root);
950         }
951
952         /* we use a stack with the names to avoid recurring infinitelly */
953         hier = g_ptr_array_new();
954
955         /*
956          * if a proto name was given in the dtd the dtd will be used as a protocol
957          * or else the dtd will be loaded as a branch of the xml namespace
958          */
959         if( ! dtd_data->proto_name ) {
960                 hfs = hf_arr;
961                 etts = ett_arr;
962                 g_ptr_array_add(hier,g_strdup("xml"));
963                 root_element = &xml_ns;
964         } else {
965                 /*
966                  * if we were given a proto_name the namespace will be registered
967                  * as an indipendent protocol with its own hf and ett arrays.
968                  */
969                 hfs = g_array_new(FALSE,FALSE,sizeof(hf_register_info));
970                 etts = g_array_new(FALSE,FALSE,sizeof(gint*));
971         }
972
973         /* the root element of the dtd's namespace */
974         root_element = g_malloc(sizeof(xml_ns_t));
975         root_element->name = g_strdup(root_name);
976         root_element->fqn = dtd_data->proto_name ? g_strdup(dtd_data->proto_name) : root_element->name;
977         root_element->hf_tag = -1;
978         root_element->hf_cdata = -1;
979         root_element->ett = -1;
980         root_element->elements = g_hash_table_new(g_str_hash,g_str_equal);
981         root_element->element_names = element_names;
982
983         /*
984          * we can either create a namespace as a flat namespace
985          * in which all the elements are at the root level
986          * or we can create a recursive namespace
987          */
988         if (dtd_data->recursion) {
989                 xml_ns_t* orig_root;
990
991                 make_xml_hier(root_name, root_element, elements,hier,errors,hfs,etts,dtd_data->proto_name);
992
993                 g_hash_table_insert(root_element->elements,root_element->name,root_element);
994
995                 orig_root = g_hash_table_lookup(elements,root_name);
996
997                 /* if the root element was defined copy its attrlist to the child */
998                 if(orig_root) {
999                         struct _attr_reg_data d;
1000
1001                         d.basename = dtd_data->proto_name;
1002                         d.hf = hfs;
1003
1004                         root_element->attributes = copy_attributes_hash(orig_root->attributes);
1005                         g_hash_table_foreach(root_element->attributes,add_xml_attribute_names,&d);
1006                 } else {
1007                         root_element->attributes = g_hash_table_new(g_str_hash,g_str_equal);
1008                 }
1009
1010                 /* we then create all the sub hierachies to catch the recurred cases */
1011                 g_ptr_array_add(hier,root_name);
1012
1013                 while(root_element->element_names->len) {
1014                         curr_name = g_ptr_array_remove_index(root_element->element_names,0);
1015
1016                         if( ! g_hash_table_lookup(root_element->elements,curr_name) ) {
1017                                 xml_ns_t* new = make_xml_hier(curr_name, root_element, elements,hier,errors,hfs,etts,dtd_data->proto_name);
1018                                 g_hash_table_insert(root_element->elements,new->name,new);
1019                         }
1020
1021                         g_free(curr_name);
1022                 }
1023
1024         } else {
1025                 /* a flat namespace */
1026                 g_ptr_array_add(hier,root_name);
1027
1028                 root_element->attributes = g_hash_table_new(g_str_hash,g_str_equal);
1029
1030                 while(root_element->element_names->len) {
1031                         xml_ns_t* new;
1032                         gint* ett_p;
1033                         struct _attr_reg_data d;
1034
1035                         curr_name = g_ptr_array_remove_index(root_element->element_names,0);
1036                         new = duplicate_element(g_hash_table_lookup(elements,curr_name));
1037                         new->fqn = fully_qualified_name(hier, curr_name, root_name);
1038
1039                         add_xml_field(hfs, &(new->hf_tag), curr_name, new->fqn);
1040                         add_xml_field(hfs, &(new->hf_cdata), curr_name, new->fqn);
1041
1042                         d.basename = new->fqn;
1043                         d.hf = hfs;
1044
1045                         g_hash_table_foreach(new->attributes,add_xml_attribute_names,&d);
1046
1047                         ett_p = &new->ett;
1048                         g_array_append_val(etts,ett_p);
1049
1050                         g_ptr_array_free(new->element_names,TRUE);
1051
1052                         g_hash_table_insert(root_element->elements,new->name,new);
1053                 }
1054         }
1055
1056         g_ptr_array_free(element_names,TRUE);
1057
1058         g_ptr_array_free(hier,TRUE);
1059
1060         /*
1061          * if we were given a proto_name the namespace will be registered
1062          * as an indipendent protocol.
1063          */
1064         if( dtd_data->proto_name ) {
1065                 gint* ett_p;
1066
1067                 if ( ! dtd_data->description) {
1068                         dtd_data->description = g_strdup(root_name);
1069                 }
1070
1071                 ett_p = &root_element->ett;
1072                 g_array_append_val(etts,ett_p);
1073
1074                 add_xml_field(hfs, &root_element->hf_cdata, root_element->name, root_element->fqn);
1075
1076                 root_element->hf_tag = proto_register_protocol(dtd_data->description, dtd_data->proto_name, dtd_data->proto_name);
1077                 proto_register_field_array(root_element->hf_tag, (hf_register_info*)g_array_data(hfs), hfs->len);
1078                 proto_register_subtree_array((gint**)g_array_data(etts), etts->len);
1079
1080                 if (dtd_data->media_type) {
1081                         g_hash_table_insert(media_types,dtd_data->media_type,root_element);
1082                         dtd_data->media_type = NULL;
1083                 }
1084
1085                 dtd_data->description = NULL;
1086                 dtd_data->proto_name = NULL;
1087                 g_array_free(hfs,FALSE);
1088                 g_array_free(etts,TRUE);
1089         }
1090
1091         g_hash_table_insert(xml_ns.elements,root_element->name,root_element);
1092
1093         g_hash_table_foreach_remove(elements,free_elements,NULL);
1094         g_hash_table_destroy(elements);
1095
1096         destroy_dtd_data(dtd_data);
1097
1098         if (root_name)
1099                 g_free(root_name);
1100 }
1101
1102 #  define DIRECTORY_T GDir
1103 #  define FILE_T gchar
1104 #  define OPENDIR_OP(name) g_dir_open(name, 0, dummy)
1105 #  define DIRGETNEXT_OP(dir) g_dir_read_name(dir)
1106 #  define GETFNAME_OP(file) (file);
1107 #  define CLOSEDIR_OP(dir) g_dir_close(dir)
1108
1109 static void init_xml_names(void) {
1110         xml_ns_t* xmlpi_xml_ns;
1111         guint i;
1112         DIRECTORY_T* dir;
1113         const FILE_T* file;
1114         const gchar* filename;
1115         gchar* dirname;
1116
1117         GError** dummy = g_malloc(sizeof(GError *));
1118         *dummy = NULL;
1119
1120         xmpli_names = g_hash_table_new(g_str_hash,g_str_equal);
1121         media_types = g_hash_table_new(g_str_hash,g_str_equal);
1122
1123         unknown_ns.elements = xml_ns.elements = g_hash_table_new(g_str_hash,g_str_equal);
1124         unknown_ns.attributes = xml_ns.attributes = g_hash_table_new(g_str_hash,g_str_equal);
1125
1126         xmlpi_xml_ns = xml_new_namespace(xmpli_names,"xml","version","encoding","standalone",NULL);
1127
1128         g_hash_table_destroy(xmlpi_xml_ns->elements);
1129         xmlpi_xml_ns->elements = NULL;
1130
1131
1132         dirname = get_persconffile_path("dtds", FALSE, FALSE);
1133
1134         if (test_for_directory(dirname) != EISDIR) {
1135                 /* Although dir isn't a directory it may still use memory */
1136                 g_free(dirname);
1137                 dirname = get_datafile_path("dtds");
1138         }
1139
1140         if (test_for_directory(dirname) == EISDIR) {
1141
1142                 if ((dir = OPENDIR_OP(dirname)) != NULL) {
1143                         while ((file = DIRGETNEXT_OP(dir)) != NULL) {
1144                                 guint namelen;
1145                                 filename = GETFNAME_OP(file);
1146
1147                                 namelen = strlen(filename);
1148                                 if ( namelen > 4 && ( g_ascii_strcasecmp(filename+(namelen-4),".dtd")  == 0 ) ) {
1149                                         GString* errors = g_string_new("");
1150                                         GString* preparsed = dtd_preparse(dirname, filename, errors);
1151                                         dtd_build_data_t* dtd_data;
1152
1153                                         if (errors->len) {
1154                                                 report_failure("Dtd Preparser in file %s%c%s: %s",dirname,G_DIR_SEPARATOR,filename,errors->str);
1155                                                 continue;
1156                                         }
1157
1158                                         dtd_data = dtd_parse(preparsed);
1159
1160                                         g_string_free(preparsed,TRUE);
1161
1162                                         if (dtd_data->error->len) {
1163                                                 report_failure("Dtd Parser in file %s%c%s: %s",dirname,G_DIR_SEPARATOR,filename,dtd_data->error->str);
1164                                                 destroy_dtd_data(dtd_data);
1165                                                 continue;
1166                                         }
1167
1168                                         register_dtd(dtd_data,errors);
1169
1170                                         if (errors->len) {
1171                                                 report_failure("Dtd Registration in file: %s%c%s: %s",dirname,G_DIR_SEPARATOR,filename,errors->str);
1172                                                 g_string_free(errors,TRUE);
1173                                                 continue;
1174                                         }
1175                                 }
1176                         }
1177
1178                         CLOSEDIR_OP(dir);
1179                 }
1180         }
1181
1182         g_free(dirname);
1183
1184         for(i=0;i<array_length(default_media_types);i++) {
1185                 if( ! g_hash_table_lookup(media_types,default_media_types[i]) ) {
1186                         g_hash_table_insert(media_types,(gpointer)default_media_types[i],&xml_ns);
1187                 }
1188         }
1189
1190         g_hash_table_foreach(xmpli_names,add_xmlpi_namespace,"xml.xmlpi");
1191
1192         g_free(dummy);
1193 }
1194
1195 static void range_delete_xml_tcp_callback(guint32 port) {
1196         dissector_delete("tcp.port", port, xml_handle);
1197 }
1198
1199 static void range_add_xml_tcp_callback(guint32 port) {
1200         dissector_add("tcp.port", port, xml_handle);
1201 }
1202
1203 static void apply_prefs(void) {
1204         if (pref_heuristic_media_save != pref_heuristic_media) {
1205                 if (pref_heuristic_media) {
1206                         heur_dissector_add("http", dissect_xml_heur, xml_ns.hf_tag);
1207                         heur_dissector_add("sip", dissect_xml_heur, xml_ns.hf_tag);
1208                         heur_dissector_add("media", dissect_xml_heur, xml_ns.hf_tag);
1209                         pref_heuristic_media_save = TRUE;
1210                 } else {
1211                         heur_dissector_delete("http", dissect_xml_heur, xml_ns.hf_tag);
1212                         heur_dissector_delete("sip", dissect_xml_heur, xml_ns.hf_tag);
1213                         heur_dissector_delete("media", dissect_xml_heur, xml_ns.hf_tag);
1214                         pref_heuristic_media_save = FALSE;
1215                 }
1216         }
1217         
1218         if (pref_heuristic_tcp_save != pref_heuristic_tcp ) {
1219                 if (pref_heuristic_tcp) {
1220                         heur_dissector_add("tcp", dissect_xml_heur, xml_ns.hf_tag);
1221                         pref_heuristic_tcp_save = TRUE;
1222                 } else {
1223                         heur_dissector_delete("tcp", dissect_xml_heur, xml_ns.hf_tag);
1224                         pref_heuristic_tcp_save = FALSE;
1225                 }
1226         }
1227         
1228         if (pref_heuristic_udp_save != pref_heuristic_udp ) {
1229                 if (pref_heuristic_udp) {
1230                         heur_dissector_add("udp", dissect_xml_heur, xml_ns.hf_tag);
1231                         pref_heuristic_udp_save = TRUE;
1232                 } else {
1233                         heur_dissector_delete("udp", dissect_xml_heur, xml_ns.hf_tag);
1234                         pref_heuristic_udp_save = FALSE;
1235                 }
1236         }
1237
1238         range_foreach(xml_tcp_range, range_delete_xml_tcp_callback);
1239         g_free(xml_tcp_range);
1240         xml_tcp_range = range_copy(global_xml_tcp_range);
1241         range_foreach(xml_tcp_range, range_add_xml_tcp_callback);       
1242 }
1243
1244 void
1245 proto_register_xml(void) {
1246         static gint *ett_base[] = {
1247                 &unknown_ns.ett,
1248                 &xml_ns.ett,
1249                 &ett_dtd,
1250                 &ett_xmpli
1251         };
1252
1253         static hf_register_info hf_base[] = {
1254                 { &hf_xmlpi, {"XMLPI", "xml.xmlpi", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }},
1255                 { &hf_comment, {"Comment", "xml.comment", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }},
1256                 { &hf_unknowwn_attrib, {"Attribute", "xml.attribute", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }},
1257                 { &hf_doctype, {"Doctype", "xml.doctype", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }},
1258                 { &hf_dtd_tag, {"DTD Tag", "xml.dtdtag", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }},
1259                 { &unknown_ns.hf_cdata, {"CDATA", "xml.cdata", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }},
1260                 { &unknown_ns.hf_tag, {"Tag", "xml.tag", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }},
1261                 { &xml_ns.hf_cdata, {"Unknown", "xml.unknown", FT_STRING, BASE_NONE, NULL, 0, "", HFILL }}
1262     };
1263         module_t* xml_module;
1264
1265         hf_arr = g_array_new(FALSE,FALSE,sizeof(hf_register_info));
1266         ett_arr = g_array_new(FALSE,FALSE,sizeof(gint*));
1267
1268         g_array_append_vals(hf_arr,hf_base,array_length(hf_base));
1269         g_array_append_vals(ett_arr,ett_base,array_length(ett_base));
1270
1271         init_xml_names();
1272
1273         xml_ns.hf_tag = proto_register_protocol("eXtensible Markup Language", "XML", xml_ns.name);
1274
1275         proto_register_field_array(xml_ns.hf_tag, (hf_register_info*)g_array_data(hf_arr), hf_arr->len);
1276         proto_register_subtree_array((gint**)g_array_data(ett_arr), ett_arr->len);
1277
1278         xml_module = prefs_register_protocol(xml_ns.hf_tag,apply_prefs);
1279         prefs_register_bool_preference(xml_module, "heuristic", "Use Heuristics for media types",
1280                                    "Try to recognize XML for unknown media types",
1281                                    &pref_heuristic_media);
1282         prefs_register_bool_preference(xml_module, "heuristic_tcp", "Use Heuristics for tcp",
1283                                    "Try to recognize XML for unknown TCP ports",
1284                                    &pref_heuristic_tcp);
1285         prefs_register_range_preference(xml_module, "tcp.port", "TCP Ports",
1286                                                                         "TCP Ports range",
1287                                                                         &global_xml_tcp_range, 65535);
1288         prefs_register_bool_preference(xml_module, "heuristic_udp", "Use Heuristics for UDP",
1289                                    "Try to recognize XML for unknown UDP ports",
1290                                    &pref_heuristic_udp);
1291         
1292         g_array_free(hf_arr,FALSE);
1293         g_array_free(ett_arr,TRUE);
1294
1295         register_dissector("xml", dissect_xml, xml_ns.hf_tag);
1296
1297         init_xml_parser();
1298
1299         xml_tcp_range = range_empty();
1300
1301
1302 }
1303
1304 static void add_dissector_media(gpointer k, gpointer v _U_, gpointer p _U_) {
1305         dissector_add_string("media_type", (gchar*)k, xml_handle);
1306 }
1307
1308 void
1309 proto_reg_handoff_xml(void)
1310 {
1311
1312         xml_handle = find_dissector("xml");
1313
1314         g_hash_table_foreach(media_types,add_dissector_media,NULL);
1315
1316 }