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