Miscellaneous code cleaning
[obnox/wireshark/wip.git] / proto.c
1 /* proto.c
2  * Routines for protocol tree
3  *
4  * $Id: proto.c,v 1.76 2000/08/11 13:35:33 deniel Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <glib.h>
37
38 #ifdef NEED_SNPRINTF_H
39 # include "snprintf.h"
40 #endif
41
42 #include "packet.h"
43 #include "resolv.h"
44 #include "register.h"
45 #include "packet-ipv6.h"
46 #include "proto.h"
47
48 #define cVALS(x) (const value_string*)(x)
49
50 static gboolean
51 proto_tree_free_node(GNode *node, gpointer data);
52
53 static void fill_label_boolean(field_info *fi, gchar *label_str);
54 static void fill_label_uint(field_info *fi, gchar *label_str);
55 static void fill_label_enumerated_uint(field_info *fi, gchar *label_str);
56 static void fill_label_enumerated_bitfield(field_info *fi, gchar *label_str);
57 static void fill_label_numeric_bitfield(field_info *fi, gchar *label_str);
58 static void fill_label_int(field_info *fi, gchar *label_str);
59 static void fill_label_enumerated_int(field_info *fi, gchar *label_str);
60
61 static int hfinfo_bitwidth(header_field_info *hfinfo);
62 static char* hfinfo_uint_vals_format(header_field_info *hfinfo);
63 static char* hfinfo_uint_format(header_field_info *hfinfo);
64 static char* hfinfo_int_vals_format(header_field_info *hfinfo);
65 static char* hfinfo_int_format(header_field_info *hfinfo);
66
67 static gboolean check_for_protocol_or_field_id(GNode *node, gpointer data);
68
69 static proto_item*
70 proto_tree_add_node(proto_tree *tree, field_info *fi);
71
72 static field_info *
73 alloc_field_info(int hfindex, tvbuff_t *tvb, gint start, gint length);
74
75 static proto_item *
76 proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
77                 field_info **pfi);
78 static void
79 proto_tree_set_representation(proto_item *pi, const char *format, va_list ap);
80
81 static void
82 proto_tree_set_bytes(field_info *fi, const guint8* start_ptr, gint length);
83 static void
84 proto_tree_set_bytes_tvb(field_info *fi, tvbuff_t *tvb, gint offset, gint length);
85 static void
86 proto_tree_set_time(field_info *fi, struct timeval *value_ptr);
87 static void
88 proto_tree_set_string(field_info *fi, const char* value);
89 static void
90 proto_tree_set_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
91 static void
92 proto_tree_set_ether(field_info *fi, const guint8* value);
93 static void
94 proto_tree_set_ether_tvb(field_info *fi, tvbuff_t *tvb, gint start);
95 static void
96 proto_tree_set_ipxnet(field_info *fi, guint32 value);
97 static void
98 proto_tree_set_ipv4(field_info *fi, guint32 value);
99 static void
100 proto_tree_set_ipv6(field_info *fi, const guint8* value_ptr);
101 static void
102 proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start);
103 static void
104 proto_tree_set_boolean(field_info *fi, guint32 value);
105 static void
106 proto_tree_set_double(field_info *fi, double value);
107 static void
108 proto_tree_set_uint(field_info *fi, guint32 value);
109 static void
110 proto_tree_set_int(field_info *fi, gint32 value);
111
112 static int proto_register_field_init(header_field_info *hfinfo, int parent);
113
114 /* special-case header field used within proto.c */
115 int hf_text_only = 1;
116
117 /* Contains information about protocols and header fields. Used when
118  * dissectors register their data */
119 GMemChunk *gmc_hfinfo = NULL;
120
121 /* Contains information about a field when a dissector calls
122  * proto_tree_add_item.  */
123 GMemChunk *gmc_field_info = NULL;
124
125 /* String space for protocol and field items for the GUI */
126 GMemChunk *gmc_item_labels = NULL;
127
128 /* List which stores protocols and fields that have been registered */
129 GPtrArray *gpa_hfinfo = NULL;
130
131 /* Points to the first element of an array of Booleans, indexed by
132    a subtree item type; that array element is TRUE if subtrees of
133    an item of that type are to be expanded. */
134 gboolean        *tree_is_expanded;
135
136 /* Number of elements in that array. */
137 int             num_tree_types;
138
139 /* Is the parsing being done for a visible proto_tree or an invisible one?
140  * By setting this correctly, the proto_tree creation is sped up by not
141  * having to call vsnprintf and copy strings around.
142  */
143 gboolean proto_tree_is_visible = FALSE;
144
145 /* initialize data structures and register protocols and fields */
146 void
147 proto_init(void)
148 {
149         static hf_register_info hf[] = {
150                 { &hf_text_only,
151                 { "Text",       "text", FT_TEXT_ONLY, BASE_NONE, NULL, 0x0,
152                         "" }},
153         };
154
155         if (gmc_hfinfo)
156                 g_mem_chunk_destroy(gmc_hfinfo);
157         if (gmc_field_info)
158                 g_mem_chunk_destroy(gmc_field_info);
159         if (gmc_item_labels)
160                 g_mem_chunk_destroy(gmc_item_labels);
161         if (gpa_hfinfo)
162                 g_ptr_array_free(gpa_hfinfo, FALSE);
163         if (tree_is_expanded != NULL)
164                 g_free(tree_is_expanded);
165
166         gmc_hfinfo = g_mem_chunk_new("gmc_hfinfo",
167                 sizeof(struct header_field_info), 50 * sizeof(struct 
168                 header_field_info), G_ALLOC_ONLY);
169         gmc_field_info = g_mem_chunk_new("gmc_field_info",
170                 sizeof(struct field_info), 200 * sizeof(struct field_info),
171                 G_ALLOC_AND_FREE);
172         gmc_item_labels = g_mem_chunk_new("gmc_item_labels",
173                 ITEM_LABEL_LENGTH, 20 * ITEM_LABEL_LENGTH,
174                 G_ALLOC_AND_FREE);
175         gpa_hfinfo = g_ptr_array_new();
176
177         /* Allocate "tree_is_expanded", with one element for ETT_NONE,
178            and initialize that element to FALSE. */
179         tree_is_expanded = g_malloc(sizeof (gint));
180         tree_is_expanded[0] = FALSE;
181         num_tree_types = 1;
182
183         /* Have each dissector register its protocols and fields, and
184            do whatever one-time initialization it needs to do. */
185         register_all_protocols();
186
187         /* Now have the ones that register a "handoff", i.e. that
188            specify that another dissector for a protocol under which
189            this dissector's protocol lives call it. */
190         register_all_protocol_handoffs();
191
192         /* Register one special-case FT_TEXT_ONLY field for use when
193                 converting ethereal to new-style proto_tree. These fields
194                 are merely strings on the GUI tree; they are not filterable */
195         proto_register_field_array(-1, hf, array_length(hf));
196
197         /* We've assigned all the subtree type values; allocate the array
198            for them, and zero it out. */
199         tree_is_expanded = g_malloc(num_tree_types*sizeof (gint *));
200         memset(tree_is_expanded, '\0', num_tree_types*sizeof (gint *));
201 }
202
203 void
204 proto_cleanup(void)
205 {
206         if (gmc_hfinfo)
207                 g_mem_chunk_destroy(gmc_hfinfo);
208         if (gmc_field_info)
209                 g_mem_chunk_destroy(gmc_field_info);
210         if (gmc_item_labels)
211                 g_mem_chunk_destroy(gmc_item_labels);
212         if (gpa_hfinfo)
213                 g_ptr_array_free(gpa_hfinfo, FALSE);
214 }
215
216 /* frees the resources that the dissection a proto_tree uses */
217 void
218 proto_tree_free(proto_tree *tree)
219 {
220         g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, -1,
221                 proto_tree_free_node, NULL);
222         g_node_destroy((GNode*)tree);
223 }
224
225 static gboolean
226 proto_tree_free_node(GNode *node, gpointer data)
227 {
228         field_info *fi = (field_info*) (node->data);
229
230         if (fi != NULL) {
231                 if (fi->representation)
232                         g_mem_chunk_free(gmc_item_labels, fi->representation);
233                 if (fi->hfinfo->type == FT_STRING)
234                         g_free(fi->value.string);
235                 else if (fi->hfinfo->type == FT_NSTRING_UINT8)
236                         g_free(fi->value.string);
237                 else if (fi->hfinfo->type == FT_BYTES) 
238                         g_free(fi->value.bytes);
239                 g_mem_chunk_free(gmc_field_info, fi);
240         }
241         return FALSE; /* FALSE = do not end traversal of GNode tree */
242 }       
243
244 /* Finds a record in the hf_info_records array by id. */
245 struct header_field_info*
246 proto_registrar_get_nth(int hfindex)
247 {
248         g_assert(hfindex >= 0 && hfindex < gpa_hfinfo->len);
249         return g_ptr_array_index(gpa_hfinfo, hfindex);
250 }
251
252
253 /* Add a node with no text */
254 proto_item *
255 proto_tree_add_notext(proto_tree *tree, tvbuff_t *tvb, gint start, gint length)
256 {
257         proto_item      *pi;
258
259         pi = proto_tree_add_pi(tree, hf_text_only, tvb, start, length, NULL);
260         if (pi == NULL)
261                 return(NULL);
262
263         return pi;
264 }
265
266 /* Add a text-only node to the proto_tree */
267 proto_item *
268 proto_tree_add_text(proto_tree *tree, tvbuff_t *tvb, gint start, gint length,
269         const char *format, ...)
270 {
271         proto_item      *pi;
272         va_list         ap;
273
274         pi = proto_tree_add_notext(tree, tvb, start, length);
275         if (pi == NULL)
276                 return(NULL);
277
278         va_start(ap, format);
279         proto_tree_set_representation(pi, format, ap);
280         va_end(ap);
281
282         return pi;
283 }
284
285 /* Add a text-only node to the proto_tree (va_list version) */
286 proto_item *
287 proto_tree_add_text_valist(proto_tree *tree, tvbuff_t *tvb, gint start, 
288         gint length, const char *format, va_list ap)
289 {
290         proto_item      *pi;
291
292         pi = proto_tree_add_notext(tree, tvb, start, length);
293         if (pi == NULL)
294                 return(NULL);
295
296         proto_tree_set_representation(pi, format, ap);
297
298         return pi;
299 }
300
301 /* Add a text-only node for debugging purposes. The caller doesn't need
302  * to worry about tvbuff, start, or length. Debug message gets sent to
303  * STDOUT, too */
304 proto_item *
305 proto_tree_add_debug_text(proto_tree *tree, const char *format, ...)
306 {
307         proto_item      *pi;
308         va_list         ap;
309
310         pi = proto_tree_add_notext(tree, NULL, 0, 0);
311         if (pi == NULL)
312                 return(NULL);
313
314         va_start(ap, format);
315         proto_tree_set_representation(pi, format, ap);
316         vprintf(format, ap);
317         va_end(ap);
318         printf("\n");
319
320         return pi;
321 }
322
323
324 static guint32
325 get_uint_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
326 {
327         guint32 value;
328
329         switch (length) {
330
331         case 1:
332                 value = tvb_get_guint8(tvb, offset);
333                 break;
334
335         case 2:
336                 value = little_endian ? tvb_get_letohs(tvb, offset)
337                                       : tvb_get_ntohs(tvb, offset);
338                 break;
339
340         case 3:
341                 value = little_endian ? tvb_get_letoh24(tvb, offset)
342                                       : tvb_get_ntoh24(tvb, offset);
343                 break;
344
345         case 4:
346                 value = little_endian ? tvb_get_letohl(tvb, offset)
347                                       : tvb_get_ntohl(tvb, offset);
348                 break;
349
350         default:
351                 g_assert_not_reached();
352                 value = 0;
353                 break;
354         }
355         return value;
356 }
357
358 static gint32
359 get_int_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
360 {
361         gint32 value;
362
363         switch (length) {
364
365         case 1:
366                 value = (gint8)tvb_get_guint8(tvb, offset);
367                 break;
368
369         case 2:
370                 value = (gint16) (little_endian ? tvb_get_letohs(tvb, offset)
371                                                 : tvb_get_ntohs(tvb, offset));
372                 break;
373
374         case 3:
375                 value = little_endian ? tvb_get_letoh24(tvb, offset)
376                                       : tvb_get_ntoh24(tvb, offset);
377                 if (value & 0x00800000) {
378                         /* Sign bit is set; sign-extend it. */
379                         value |= 0xFF000000;
380                 }
381                 break;
382
383         case 4:
384                 value = little_endian ? tvb_get_letohl(tvb, offset)
385                                       : tvb_get_ntohl(tvb, offset);
386                 break;
387
388         default:
389                 g_assert_not_reached();
390                 value = 0;
391                 break;
392         }
393         return value;
394 }
395
396 /* Add an item to a proto_tree, using the text label registered to that item;
397    the item is extracted from the tvbuff handed to it. */
398 proto_item *
399 proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
400     gint start, gint length, gboolean little_endian)
401 {
402         field_info      *new_fi;
403         proto_item      *pi;
404         guint32         value, n;
405
406         new_fi = alloc_field_info(hfindex, tvb, start, length);
407
408         if (new_fi == NULL)
409                 return(NULL);
410
411         switch(new_fi->hfinfo->type) {
412                 case FT_NONE:
413                         /* no value to set for FT_NONE */
414                         break;
415
416                 case FT_BYTES:
417                         proto_tree_set_bytes_tvb(new_fi, tvb, start, length);
418                         break;
419
420                 case FT_BOOLEAN:
421                         proto_tree_set_boolean(new_fi,
422                             get_uint_value(tvb, start, length, little_endian));
423                         break;
424
425                 /* XXX - make these just FT_UINT? */
426                 case FT_UINT8:
427                 case FT_UINT16:
428                 case FT_UINT24:
429                 case FT_UINT32:
430                         proto_tree_set_uint(new_fi,
431                             get_uint_value(tvb, start, length, little_endian));
432                         break;
433
434                 /* XXX - make these just FT_INT? */
435                 case FT_INT8:
436                 case FT_INT16:
437                 case FT_INT24:
438                 case FT_INT32:
439                         proto_tree_set_int(new_fi,
440                             get_int_value(tvb, start, length, little_endian));
441                         break;
442
443                 case FT_IPv4:
444                         g_assert(length == 4);
445                         tvb_memcpy(tvb, (guint8 *)&value, start, 4);
446                         proto_tree_set_ipv4(new_fi, value);
447                         break;
448
449                 case FT_IPXNET:
450                         g_assert(length == 4);
451                         proto_tree_set_ipxnet(new_fi,
452                             get_uint_value(tvb, start, 4, FALSE));
453                         break;
454
455                 case FT_IPv6:
456                         g_assert(length == 16);
457                         proto_tree_set_ipv6_tvb(new_fi, tvb, start);
458                         break;
459
460                 case FT_ETHER:
461                         g_assert(length == 6);
462                         proto_tree_set_ether_tvb(new_fi, tvb, start);
463                         break;
464
465                 case FT_STRING:
466                         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
467                         proto_tree_set_string_tvb(new_fi, tvb, start, length);
468                         break;
469
470                 case FT_NSTRING_UINT8:
471                         n = tvb_get_guint8(tvb, start);
472                         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
473                         proto_tree_set_string_tvb(new_fi, tvb, start + 1, n);
474                         /* Instead of calling proto_item_set_len(), since we don't yet
475                          * have a proto_item, we set the field_info's length ourselves. */
476                         new_fi->length = n + 1;
477                         break;
478
479                 default:
480                         g_error("new_fi->hfinfo->type %d not handled\n", new_fi->hfinfo->type);
481                         g_assert_not_reached();
482                         break;
483         }
484
485         /* Don't add to proto_item to proto_tree until now so that any exceptions
486          * raised by a tvbuff access method doesn't leave junk in the proto_tree. */
487         pi = proto_tree_add_node(tree, new_fi);
488
489         return pi;
490 }
491
492 proto_item *
493 proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb,
494     gint start, gint length, gboolean little_endian)
495 {
496         proto_item      *pi;
497         field_info      *fi;
498
499         pi = proto_tree_add_item(tree, hfindex, tvb, start, length, little_endian);
500         if (pi == NULL)
501                 return(NULL);
502
503         fi = (field_info*) (((GNode*)pi)->data);
504         fi->visible = FALSE;
505
506         return pi;
507 }
508
509
510 /* Add a FT_NONE to a proto_tree */
511 proto_item *
512 proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
513                 gint length, const char *format, ...)
514 {
515         proto_item              *pi;
516         va_list                 ap;
517         header_field_info       *hfinfo;
518
519         if (!tree)
520                 return (NULL);
521
522         hfinfo = proto_registrar_get_nth(hfindex);
523         g_assert(hfinfo->type == FT_NONE);
524
525         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, NULL);
526
527         va_start(ap, format);
528         proto_tree_set_representation(pi, format, ap);
529         va_end(ap);
530
531         /* no value to set for FT_NONE */
532
533         return pi;
534 }
535
536 /* Add a FT_BYTES to a proto_tree */
537 proto_item *
538 proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
539                 gint length, const guint8 *start_ptr)
540 {
541         proto_item              *pi;
542         field_info              *new_fi;
543         header_field_info       *hfinfo;
544
545         if (!tree)
546                 return (NULL);
547
548         hfinfo = proto_registrar_get_nth(hfindex);
549         g_assert(hfinfo->type == FT_BYTES);
550
551         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi);
552         proto_tree_set_bytes(new_fi, start_ptr, length);
553
554         return pi;
555 }
556
557 proto_item *
558 proto_tree_add_bytes_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
559                 gint length, const guint8 *start_ptr)
560 {
561         proto_item              *pi;
562         field_info              *fi;
563
564         pi = proto_tree_add_bytes(tree, hfindex, tvb, start, length, start_ptr);
565         if (pi == NULL)
566                 return (NULL);
567
568         fi = (field_info*) (((GNode*)pi)->data);
569         fi->visible = FALSE;
570
571         return pi;
572 }
573
574 proto_item *
575 proto_tree_add_bytes_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
576                 gint length, const guint8 *start_ptr, const char *format, ...)
577 {
578         proto_item              *pi;
579         va_list                 ap;
580
581         pi = proto_tree_add_bytes(tree, hfindex, tvb, start, length, start_ptr);
582         if (pi == NULL)
583                 return (NULL);
584
585         va_start(ap, format);
586         proto_tree_set_representation(pi, format, ap);
587         va_end(ap);
588
589         return pi;
590 }
591
592 /* Set the FT_BYTES value */
593 static void
594 proto_tree_set_bytes(field_info *fi, const guint8* start_ptr, gint length)
595 {
596         g_assert(start_ptr != NULL);
597
598         if (length > 0) {
599                 /* This g_malloc'ed memory is freed in
600                    proto_tree_free_node() */
601                 fi->value.bytes = g_malloc(length);
602                 memcpy(fi->value.bytes, start_ptr, length);
603         }
604         else {
605                 fi->value.bytes = NULL;
606         }
607 }
608
609 static void
610 proto_tree_set_bytes_tvb(field_info *fi, tvbuff_t *tvb, gint offset, gint length)
611 {
612         if (length > 0) {
613                 /* This g_malloc'ed memory is freed in
614                    proto_tree_free_node() */
615                 fi->value.bytes = tvb_memdup(tvb, offset, length);
616         }
617         else {
618                 fi->value.bytes = NULL;
619         }
620 }
621
622 /* Add a FT_*TIME to a proto_tree */
623 proto_item *
624 proto_tree_add_time(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
625                 struct timeval *value_ptr)
626 {
627         proto_item              *pi;
628         field_info              *new_fi;
629         header_field_info       *hfinfo;
630
631         if (!tree)
632                 return (NULL);
633
634         hfinfo = proto_registrar_get_nth(hfindex);
635         g_assert(hfinfo->type == FT_ABSOLUTE_TIME ||
636                                 hfinfo->type == FT_RELATIVE_TIME);
637
638         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi);
639         proto_tree_set_time(new_fi, value_ptr);
640
641         return pi;
642 }
643
644 proto_item *
645 proto_tree_add_time_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
646                 struct timeval *value_ptr)
647 {
648         proto_item              *pi;
649         field_info              *fi;
650
651         pi = proto_tree_add_time(tree, hfindex, tvb, start, length, value_ptr);
652         if (pi == NULL)
653                 return (NULL);
654
655         fi = (field_info*) (((GNode*)pi)->data);
656         fi->visible = FALSE;
657
658         return pi;
659 }
660
661 proto_item *
662 proto_tree_add_time_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
663                 struct timeval *value_ptr, const char *format, ...)
664 {
665         proto_item              *pi;
666         va_list                 ap;
667
668         pi = proto_tree_add_time(tree, hfindex, tvb, start, length, value_ptr);
669         if (pi == NULL)
670                 return (NULL);
671
672         va_start(ap, format);
673         proto_tree_set_representation(pi, format, ap);
674         va_end(ap);
675
676         return pi;
677 }
678
679 /* Set the FT_*TIME value */
680 static void
681 proto_tree_set_time(field_info *fi, struct timeval *value_ptr)
682 {
683         memcpy(&fi->value.time, value_ptr, sizeof(struct timeval));
684 }
685
686 /* Add a FT_IPXNET to a proto_tree */
687 proto_item *
688 proto_tree_add_ipxnet(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
689                 guint32 value)
690 {
691         proto_item              *pi;
692         field_info              *new_fi;
693         header_field_info       *hfinfo;
694
695         if (!tree)
696                 return (NULL);
697
698         hfinfo = proto_registrar_get_nth(hfindex);
699         g_assert(hfinfo->type == FT_IPXNET);
700
701         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi);
702         proto_tree_set_ipxnet(new_fi, value);
703
704         return pi;
705 }
706
707 proto_item *
708 proto_tree_add_ipxnet_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
709                 guint32 value)
710 {
711         proto_item              *pi;
712         field_info              *fi;
713
714         pi = proto_tree_add_ipxnet(tree, hfindex, tvb, start, length, value);
715         if (pi == NULL)
716                 return (NULL);
717
718         fi = (field_info*) (((GNode*)pi)->data);
719         fi->visible = FALSE;
720
721         return pi;
722 }
723
724 proto_item *
725 proto_tree_add_ipxnet_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
726                 guint32 value, const char *format, ...)
727 {
728         proto_item              *pi;
729         va_list                 ap;
730
731         pi = proto_tree_add_ipxnet(tree, hfindex, tvb, start, length, value);
732         if (pi == NULL)
733                 return (NULL);
734
735         va_start(ap, format);
736         proto_tree_set_representation(pi, format, ap);
737         va_end(ap);
738
739         return pi;
740 }
741
742 /* Set the FT_IPXNET value */
743 static void
744 proto_tree_set_ipxnet(field_info *fi, guint32 value)
745 {
746         fi->value.numeric = value;
747 }
748
749 /* Add a FT_IPv4 to a proto_tree */
750 proto_item *
751 proto_tree_add_ipv4(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
752                 guint32 value)
753 {
754         proto_item              *pi;
755         field_info              *new_fi;
756         header_field_info       *hfinfo;
757
758         if (!tree)
759                 return (NULL);
760
761         hfinfo = proto_registrar_get_nth(hfindex);
762         g_assert(hfinfo->type == FT_IPv4);
763
764         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi);
765         proto_tree_set_ipv4(new_fi, value);
766
767         return pi;
768 }
769
770 proto_item *
771 proto_tree_add_ipv4_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
772                 guint32 value)
773 {
774         proto_item              *pi;
775         field_info              *fi;
776
777         pi = proto_tree_add_ipv4(tree, hfindex, tvb, start, length, value);
778         if (pi == NULL)
779                 return (NULL);
780
781         fi = (field_info*) (((GNode*)pi)->data);
782         fi->visible = FALSE;
783
784         return pi;
785 }
786
787 proto_item *
788 proto_tree_add_ipv4_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
789                 guint32 value, const char *format, ...)
790 {
791         proto_item              *pi;
792         va_list                 ap;
793
794         pi = proto_tree_add_ipv4(tree, hfindex, tvb, start, length, value);
795         if (pi == NULL)
796                 return (NULL);
797
798         va_start(ap, format);
799         proto_tree_set_representation(pi, format, ap);
800         va_end(ap);
801
802         return pi;
803 }
804
805 /* Set the FT_IPv4 value */
806 static void
807 proto_tree_set_ipv4(field_info *fi, guint32 value)
808 {
809         ipv4_addr_set_net_order_addr(&(fi->value.ipv4), value);
810         ipv4_addr_set_netmask_bits(&(fi->value.ipv4), 32);
811 }
812
813 /* Add a FT_IPv6 to a proto_tree */
814 proto_item *
815 proto_tree_add_ipv6(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
816                 const guint8* value_ptr)
817 {
818         proto_item              *pi;
819         field_info              *new_fi;
820         header_field_info       *hfinfo;
821
822         if (!tree)
823                 return (NULL);
824
825         hfinfo = proto_registrar_get_nth(hfindex);
826         g_assert(hfinfo->type == FT_IPv6);
827
828         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi);
829         proto_tree_set_ipv6(new_fi, value_ptr);
830
831         return pi;
832 }
833
834 proto_item *
835 proto_tree_add_ipv6_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
836                 const guint8* value_ptr)
837 {
838         proto_item              *pi;
839         field_info              *fi;
840
841         pi = proto_tree_add_ipv6(tree, hfindex, tvb, start, length, value_ptr);
842         if (pi == NULL)
843                 return (NULL);
844
845         fi = (field_info*) (((GNode*)pi)->data);
846         fi->visible = FALSE;
847
848         return pi;
849 }
850
851 proto_item *
852 proto_tree_add_ipv6_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
853                 const guint8* value_ptr, const char *format, ...)
854 {
855         proto_item              *pi;
856         va_list                 ap;
857
858         pi = proto_tree_add_ipv6(tree, hfindex, tvb, start, length, value_ptr);
859         if (pi == NULL)
860                 return (NULL);
861
862         va_start(ap, format);
863         proto_tree_set_representation(pi, format, ap);
864         va_end(ap);
865
866         return pi;
867 }
868
869 /* Set the FT_IPv6 value */
870 static void
871 proto_tree_set_ipv6(field_info *fi, const guint8* value_ptr)
872 {
873         memcpy(fi->value.ipv6, value_ptr, 16);
874 }
875
876 static void
877 proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start)
878 {
879         tvb_memcpy(tvb, fi->value.ipv6, start, 16);
880 }
881
882 /* Add a FT_STRING to a proto_tree */
883 proto_item *
884 proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
885                 gint length, const char* value)
886 {
887         proto_item              *pi;
888         field_info              *new_fi;
889         header_field_info       *hfinfo;
890
891         if (!tree)
892                 return (NULL);
893
894         hfinfo = proto_registrar_get_nth(hfindex);
895         g_assert(hfinfo->type == FT_STRING);
896
897         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi);
898         proto_tree_set_string(new_fi, value);
899
900         return pi;
901 }
902
903 proto_item *
904 proto_tree_add_string_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
905                 gint length, const char* value)
906 {
907         proto_item              *pi;
908         field_info              *fi;
909
910         pi = proto_tree_add_string(tree, hfindex, tvb, start, length, value);
911         if (pi == NULL)
912                 return (NULL);
913
914         fi = (field_info*) (((GNode*)pi)->data);
915         fi->visible = FALSE;
916
917         return pi;
918 }
919
920 proto_item *
921 proto_tree_add_string_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
922                 gint length, const char* value, const char *format, ...)
923 {
924         proto_item              *pi;
925         va_list                 ap;
926
927         pi = proto_tree_add_string(tree, hfindex, tvb, start, length, value);
928         if (pi == NULL)
929                 return (NULL);
930
931         va_start(ap, format);
932         proto_tree_set_representation(pi, format, ap);
933         va_end(ap);
934
935         return pi;
936 }
937
938 /* Set the FT_STRING value */
939 static void
940 proto_tree_set_string(field_info *fi, const char* value)
941 {
942         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
943         fi->value.string = g_strdup(value);
944 }
945
946 static void
947 proto_tree_set_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length)
948 {
949         /* This memory is freed in proto_tree_free_node() */
950         fi->value.string = g_malloc(length + 1);
951         tvb_memcpy(tvb, fi->value.string, start, length);
952         fi->value.string[length] = '\0';
953 }
954
955 /* Add a FT_ETHER to a proto_tree */
956 proto_item *
957 proto_tree_add_ether(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
958                 const guint8* value)
959 {
960         proto_item              *pi;
961         field_info              *new_fi;
962         header_field_info       *hfinfo;
963
964         if (!tree)
965                 return (NULL);
966
967         hfinfo = proto_registrar_get_nth(hfindex);
968         g_assert(hfinfo->type == FT_ETHER);
969
970         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi);
971         proto_tree_set_ether(new_fi, value);
972
973         return pi;
974 }
975
976 proto_item *
977 proto_tree_add_ether_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
978                 const guint8* value)
979 {
980         proto_item              *pi;
981         field_info              *fi;
982
983         pi = proto_tree_add_ether(tree, hfindex, tvb, start, length, value);
984         if (pi == NULL)
985                 return (NULL);
986
987         fi = (field_info*) (((GNode*)pi)->data);
988         fi->visible = FALSE;
989
990         return pi;
991 }
992
993 proto_item *
994 proto_tree_add_ether_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
995                 const guint8* value, const char *format, ...)
996 {
997         proto_item              *pi;
998         va_list                 ap;
999
1000         pi = proto_tree_add_ether(tree, hfindex, tvb, start, length, value);
1001         if (pi == NULL)
1002                 return (NULL);
1003
1004         va_start(ap, format);
1005         proto_tree_set_representation(pi, format, ap);
1006         va_end(ap);
1007
1008         return pi;
1009 }
1010
1011 /* Set the FT_ETHER value */
1012 static void
1013 proto_tree_set_ether(field_info *fi, const guint8* value)
1014 {
1015         memcpy(fi->value.ether, value, 6);
1016 }
1017
1018 static void
1019 proto_tree_set_ether_tvb(field_info *fi, tvbuff_t *tvb, gint start)
1020 {
1021         tvb_memcpy(tvb, fi->value.ether, start, 6);
1022 }
1023
1024 /* Add a FT_BOOLEAN to a proto_tree */
1025 proto_item *
1026 proto_tree_add_boolean(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1027                 guint32 value)
1028 {
1029         proto_item              *pi;
1030         field_info              *new_fi;
1031         header_field_info       *hfinfo;
1032
1033         if (!tree)
1034                 return (NULL);
1035
1036         hfinfo = proto_registrar_get_nth(hfindex);
1037         g_assert(hfinfo->type == FT_BOOLEAN);
1038
1039         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi);
1040         proto_tree_set_boolean(new_fi, value);
1041
1042         return pi;
1043 }
1044
1045 proto_item *
1046 proto_tree_add_boolean_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1047                 guint32 value)
1048 {
1049         proto_item              *pi;
1050         field_info              *fi;
1051
1052         pi = proto_tree_add_boolean(tree, hfindex, tvb, start, length, value);
1053         if (pi == NULL)
1054                 return (NULL);
1055
1056         fi = (field_info*) (((GNode*)pi)->data);
1057         fi->visible = FALSE;
1058
1059         return pi;
1060 }
1061
1062 proto_item *
1063 proto_tree_add_boolean_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1064                 guint32 value, const char *format, ...)
1065 {
1066         proto_item              *pi;
1067         va_list                 ap;
1068
1069         pi = proto_tree_add_boolean(tree, hfindex, tvb, start, length, value);
1070         if (pi == NULL)
1071                 return (NULL);
1072
1073         va_start(ap, format);
1074         proto_tree_set_representation(pi, format, ap);
1075         va_end(ap);
1076
1077         return pi;
1078 }
1079
1080 /* Set the FT_BOOLEAN value */
1081 static void
1082 proto_tree_set_boolean(field_info *fi, guint32  value)
1083 {
1084         proto_tree_set_uint(fi, value);
1085 }
1086
1087 /* Add a FT_DOUBLE to a proto_tree */
1088 proto_item *
1089 proto_tree_add_double(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1090                 double value)
1091 {
1092         proto_item              *pi;
1093         field_info              *new_fi;
1094         header_field_info       *hfinfo;
1095
1096         if (!tree)
1097                 return (NULL);
1098
1099         hfinfo = proto_registrar_get_nth(hfindex);
1100         g_assert(hfinfo->type == FT_DOUBLE);
1101
1102         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi);
1103         proto_tree_set_double(new_fi, value);
1104
1105         return pi;
1106 }
1107
1108 proto_item *
1109 proto_tree_add_double_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1110                 double value)
1111 {
1112         proto_item              *pi;
1113         field_info              *fi;
1114
1115         pi = proto_tree_add_double(tree, hfindex, tvb, start, length, value);
1116         if (pi == NULL)
1117                 return (NULL);
1118
1119         fi = (field_info*) (((GNode*)pi)->data);
1120         fi->visible = FALSE;
1121
1122         return pi;
1123 }
1124
1125 proto_item *
1126 proto_tree_add_double_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1127                 double value, const char *format, ...)
1128 {
1129         proto_item              *pi;
1130         va_list                 ap;
1131
1132         pi = proto_tree_add_double(tree, hfindex, tvb, start, length, value);
1133         if (pi == NULL)
1134                 return (NULL);
1135
1136         va_start(ap, format);
1137         proto_tree_set_representation(pi, format, ap);
1138         va_end(ap);
1139
1140         return pi;
1141 }
1142
1143 /* Set the FT_DOUBLE value */
1144 static void
1145 proto_tree_set_double(field_info *fi, double value)
1146 {
1147         fi->value.floating = value;
1148 }
1149
1150 /* Add any FT_UINT* to a proto_tree */
1151 proto_item *
1152 proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1153                 guint32 value)
1154 {
1155         proto_item              *pi = NULL;
1156         field_info              *new_fi;
1157         header_field_info       *hfinfo;
1158
1159         if (!tree)
1160                 return (NULL);
1161
1162         hfinfo = proto_registrar_get_nth(hfindex);
1163         switch(hfinfo->type) {
1164                 case FT_UINT8:
1165                 case FT_UINT16:
1166                 case FT_UINT24:
1167                 case FT_UINT32:
1168                         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length,
1169                                         &new_fi);
1170                         proto_tree_set_uint(new_fi, value);
1171                         break;
1172
1173                 default:
1174                         g_assert_not_reached();
1175         }
1176
1177         return pi;
1178 }
1179
1180 proto_item *
1181 proto_tree_add_uint_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1182                 guint32 value)
1183 {
1184         proto_item              *pi;
1185         field_info              *fi;
1186
1187         pi = proto_tree_add_uint(tree, hfindex, tvb, start, length, value);
1188         if (pi == NULL)
1189                 return (NULL);
1190
1191         fi = (field_info*) (((GNode*)pi)->data);
1192         fi->visible = FALSE;
1193
1194         return pi;
1195 }
1196
1197 proto_item *
1198 proto_tree_add_uint_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1199                 guint32 value, const char *format, ...)
1200 {
1201         proto_item              *pi;
1202         va_list                 ap;
1203
1204         pi = proto_tree_add_uint(tree, hfindex, tvb, start, length, value);
1205         if (pi == NULL)
1206                 return (NULL);
1207
1208         va_start(ap, format);
1209         proto_tree_set_representation(pi, format, ap);
1210         va_end(ap);
1211
1212         return pi;
1213 }
1214
1215 /* Set the FT_UINT* value */
1216 static void
1217 proto_tree_set_uint(field_info *fi, guint32 value)
1218 {
1219         header_field_info *hfinfo;
1220
1221         hfinfo = fi->hfinfo;
1222         fi->value.numeric = value;
1223         if (hfinfo->bitmask) {
1224                 /* Mask out irrelevant portions */
1225                 fi->value.numeric &= hfinfo->bitmask;
1226
1227                 /* Shift bits */
1228                 if (hfinfo->bitshift > 0) {
1229                         fi->value.numeric >>= hfinfo->bitshift;
1230                 }
1231         }
1232 }
1233
1234 /* Add any FT_INT* to a proto_tree */
1235 proto_item *
1236 proto_tree_add_int(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1237                 gint32 value)
1238 {
1239         proto_item              *pi = NULL;
1240         field_info              *new_fi;
1241         header_field_info       *hfinfo;
1242
1243         if (!tree)
1244                 return (NULL);
1245
1246         hfinfo = proto_registrar_get_nth(hfindex);
1247         switch(hfinfo->type) {
1248                 case FT_INT8:
1249                 case FT_INT16:
1250                 case FT_INT24:
1251                 case FT_INT32:
1252                         pi = proto_tree_add_pi(tree, hfindex, tvb, start, length,
1253                                         &new_fi);
1254                         proto_tree_set_int(new_fi, value);
1255                         break;
1256
1257                 default:
1258                         g_assert_not_reached();
1259         }
1260
1261         return pi;
1262 }
1263
1264 proto_item *
1265 proto_tree_add_int_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1266                 gint32 value)
1267 {
1268         proto_item              *pi;
1269         field_info              *fi;
1270
1271         pi = proto_tree_add_int(tree, hfindex, tvb, start, length, value);
1272         if (pi == NULL)
1273                 return (NULL);
1274
1275         fi = (field_info*) (((GNode*)pi)->data);
1276         fi->visible = FALSE;
1277
1278         return pi;
1279 }
1280
1281 proto_item *
1282 proto_tree_add_int_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1283                 gint32 value, const char *format, ...)
1284 {
1285         proto_item              *pi = NULL;
1286         va_list                 ap;
1287
1288         pi = proto_tree_add_int(tree, hfindex, tvb, start, length, value);
1289         if (pi == NULL)
1290                 return (NULL);
1291
1292         va_start(ap, format);
1293         proto_tree_set_representation(pi, format, ap);
1294         va_end(ap);
1295
1296         return pi;
1297 }
1298
1299 /* Set the FT_INT* value */
1300 static void
1301 proto_tree_set_int(field_info *fi, gint32 value)
1302 {
1303         header_field_info *hfinfo;
1304
1305         hfinfo = fi->hfinfo;
1306         fi->value.numeric = (guint32) value;
1307         if (hfinfo->bitmask) {
1308                 /* Mask out irrelevant portions */
1309                 fi->value.numeric &= hfinfo->bitmask;
1310
1311                 /* Shift bits */
1312                 if (hfinfo->bitshift > 0) {
1313                         fi->value.numeric >>= hfinfo->bitshift;
1314                 }
1315         }
1316 }
1317
1318
1319 /* Add a field_info struct to the proto_tree, encapsulating it in a GNode (proto_item) */
1320 static proto_item *
1321 proto_tree_add_node(proto_tree *tree, field_info *fi)
1322 {
1323         proto_item *pi;
1324
1325         pi = (proto_item*) g_node_new(fi);
1326         g_node_append((GNode*)tree, (GNode*)pi);
1327
1328         return pi;
1329 }
1330
1331
1332 /* Generic way to allocate field_info and add to proto_tree.
1333  * Sets *pfi to address of newly-allocated field_info struct, if pfi is non-NULL. */
1334 static proto_item *
1335 proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
1336                 field_info **pfi)
1337 {
1338         proto_item      *pi;
1339         field_info      *fi;
1340
1341         if (!tree)
1342                 return(NULL);
1343
1344         fi = alloc_field_info(hfindex, tvb, start, length);
1345         pi = proto_tree_add_node(tree, fi);
1346
1347         if (pfi) {
1348                 *pfi = fi;
1349         }
1350
1351         return pi;
1352 }
1353
1354 static field_info *
1355 alloc_field_info(int hfindex, tvbuff_t *tvb, gint start, gint length)
1356 {
1357         field_info      *fi;
1358
1359         fi = g_mem_chunk_alloc(gmc_field_info);
1360
1361         g_assert(hfindex >= 0 && hfindex < gpa_hfinfo->len);
1362         fi->hfinfo = proto_registrar_get_nth(hfindex);
1363         g_assert(fi->hfinfo != NULL);
1364         fi->start = start;
1365         if (tvb) {
1366                 fi->start += tvb_raw_offset(tvb);
1367         }
1368         fi->length = length;
1369         fi->tree_type = ETT_NONE;
1370         fi->visible = proto_tree_is_visible;
1371         fi->representation = NULL;
1372
1373         return fi;
1374 }
1375
1376 /* Set representation of a proto_tree entry, if the protocol tree is to
1377    be visible. */
1378 static void
1379 proto_tree_set_representation(proto_item *pi, const char *format, va_list ap)
1380 {
1381         field_info *fi = (field_info*) (((GNode*)pi)->data);
1382
1383         if (fi->visible) {
1384                 fi->representation = g_mem_chunk_alloc(gmc_item_labels);
1385                 vsnprintf(fi->representation, ITEM_LABEL_LENGTH, format, ap);
1386         }
1387 }
1388
1389 void
1390 proto_item_set_text(proto_item *pi, const char *format, ...)
1391 {
1392         field_info *fi = (field_info*) (((GNode*)pi)->data);
1393         va_list ap;
1394
1395         if (fi->representation)
1396                 g_mem_chunk_free(gmc_item_labels, fi->representation);
1397
1398         va_start(ap, format);
1399         proto_tree_set_representation(pi, format, ap);
1400         va_end(ap);
1401 }
1402
1403 void
1404 proto_item_set_len(proto_item *pi, gint length)
1405 {
1406         field_info *fi = (field_info*) (((GNode*)pi)->data);
1407         fi->length = length;
1408 }
1409
1410 int
1411 proto_item_get_len(proto_item *pi)
1412 {
1413         field_info *fi = (field_info*) (((GNode*)pi)->data);
1414         return fi->length;
1415 }
1416
1417 proto_tree*
1418 proto_tree_create_root(void)
1419 {
1420         return (proto_tree*) g_node_new(NULL);
1421 }
1422
1423 proto_tree*
1424 proto_item_add_subtree(proto_item *pi,  gint idx) {
1425         field_info *fi = (field_info*) (((GNode*)pi)->data);
1426         g_assert(idx >= 0 && idx < num_tree_types);
1427         fi->tree_type = idx;
1428         return (proto_tree*) pi;
1429 }
1430
1431
1432 int
1433 proto_register_protocol(char *name, char *abbrev)
1434 {
1435         struct header_field_info *hfinfo;
1436
1437         /* Here we do allocate a new header_field_info struct */
1438         hfinfo = g_mem_chunk_alloc(gmc_hfinfo);
1439         hfinfo->name = name;
1440         hfinfo->abbrev = abbrev;
1441         hfinfo->type = FT_NONE;
1442         hfinfo->strings = NULL;
1443         hfinfo->bitmask = 0;
1444         hfinfo->bitshift = 0;
1445         hfinfo->blurb = "";
1446         hfinfo->parent = -1; /* this field differentiates protos and fields */
1447
1448         return proto_register_field_init(hfinfo, hfinfo->parent);
1449 }
1450
1451 /* for use with static arrays only, since we don't allocate our own copies
1452 of the header_field_info struct contained withing the hf_register_info struct */
1453 void
1454 proto_register_field_array(int parent, hf_register_info *hf, int num_records)
1455 {
1456         int                     field_id, i;
1457         hf_register_info        *ptr = hf;
1458
1459         for (i = 0; i < num_records; i++, ptr++) {
1460                 field_id = proto_register_field_init(&ptr->hfinfo, parent);
1461                 *ptr->p_id = field_id;
1462         }
1463 }
1464
1465 static int
1466 proto_register_field_init(header_field_info *hfinfo, int parent)
1467 {
1468         /* These types of fields are allowed to have value_strings or true_false_strings */
1469         g_assert((hfinfo->strings == NULL) || (
1470                         (hfinfo->type == FT_UINT8) ||
1471                         (hfinfo->type == FT_UINT16) ||
1472                         (hfinfo->type == FT_UINT24) ||
1473                         (hfinfo->type == FT_UINT32) ||
1474                         (hfinfo->type == FT_INT8) ||
1475                         (hfinfo->type == FT_INT16) ||
1476                         (hfinfo->type == FT_INT24) ||
1477                         (hfinfo->type == FT_INT32) ||
1478                         (hfinfo->type == FT_BOOLEAN) ));
1479
1480         /* if this is a bitfield, compure bitshift */
1481         if (hfinfo->bitmask) {
1482                 while ((hfinfo->bitmask & (1 << hfinfo->bitshift)) == 0)
1483                         hfinfo->bitshift++;
1484         }
1485
1486         hfinfo->parent = parent;
1487
1488         /* if we always add and never delete, then id == len - 1 is correct */
1489         g_ptr_array_add(gpa_hfinfo, hfinfo);
1490         hfinfo->id = gpa_hfinfo->len - 1;
1491         return hfinfo->id;
1492 }
1493
1494 void
1495 proto_register_subtree_array(gint **indices, int num_indices)
1496 {
1497         int     i;
1498         gint    **ptr = indices;
1499
1500         /*
1501          * Add "num_indices" elements to "tree_is_expanded".
1502          */
1503         tree_is_expanded = g_realloc(tree_is_expanded,
1504             (num_tree_types + num_indices)*sizeof (gint));
1505
1506         /*
1507          * Assign "num_indices" subtree numbers starting at "num_tree_types",
1508          * returning the indices through the pointers in the array whose
1509          * first element is pointed to by "indices", set to FALSE the
1510          * elements to which those subtree numbers refer, and update
1511          * "num_tree_types" appropriately.
1512          */
1513         for (i = 0; i < num_indices; i++, ptr++, num_tree_types++) {
1514                 tree_is_expanded[num_tree_types] = FALSE;
1515                 **ptr = num_tree_types;
1516         }
1517 }
1518
1519 void
1520 proto_item_fill_label(field_info *fi, gchar *label_str)
1521 {
1522         struct header_field_info        *hfinfo = fi->hfinfo;
1523         guint32                         n_addr; /* network-order IPv4 address */
1524
1525         switch(hfinfo->type) {
1526                 case FT_NONE:
1527                         snprintf(label_str, ITEM_LABEL_LENGTH,
1528                                 "%s", hfinfo->name);
1529                         break;
1530
1531                 case FT_BOOLEAN:
1532                         fill_label_boolean(fi, label_str);
1533                         break;
1534
1535                 case FT_BYTES:
1536                         if (fi->value.bytes) {
1537                                 snprintf(label_str, ITEM_LABEL_LENGTH,
1538                                         "%s: %s", hfinfo->name, 
1539                                          bytes_to_str(fi->value.bytes, fi->length));
1540                         }
1541                         else {
1542                                 snprintf(label_str, ITEM_LABEL_LENGTH,
1543                                         "%s: <MISSING>", hfinfo->name);
1544                         }
1545                         break;
1546
1547                 /* Four types of integers to take care of:
1548                  *      Bitfield, with val_string
1549                  *      Bitfield, w/o val_string
1550                  *      Non-bitfield, with val_string
1551                  *      Non-bitfield, w/o val_string
1552                  */
1553                 case FT_UINT8:
1554                 case FT_UINT16:
1555                 case FT_UINT24:
1556                 case FT_UINT32:
1557                         if (hfinfo->bitmask) {
1558                                 if (hfinfo->strings) {
1559                                         fill_label_enumerated_bitfield(fi, label_str);
1560                                 }
1561                                 else {
1562                                         fill_label_numeric_bitfield(fi, label_str);
1563                                 }
1564                         }
1565                         else {
1566                                 if (hfinfo->strings) {
1567                                         fill_label_enumerated_uint(fi, label_str);
1568                                 }
1569                                 else {
1570                                         fill_label_uint(fi, label_str);
1571                                 }
1572                         }
1573                         break;
1574
1575                 case FT_INT8:
1576                 case FT_INT16:
1577                 case FT_INT24:
1578                 case FT_INT32:
1579                         g_assert(!hfinfo->bitmask);
1580                         if (hfinfo->strings) {
1581                                 fill_label_enumerated_int(fi, label_str);
1582                         }
1583                         else {
1584                                 fill_label_int(fi, label_str);
1585                         }
1586                         break;
1587
1588                 case FT_DOUBLE:
1589                         snprintf(label_str, ITEM_LABEL_LENGTH,
1590                                 "%s: %g", fi->hfinfo->name,
1591                                 fi->value.floating);
1592                         break;
1593
1594                 case FT_ABSOLUTE_TIME:
1595                         snprintf(label_str, ITEM_LABEL_LENGTH,
1596                                 "%s: %s", fi->hfinfo->name,
1597                                 abs_time_to_str(&fi->value.time));
1598                         break;
1599
1600                 case FT_RELATIVE_TIME:
1601                         snprintf(label_str, ITEM_LABEL_LENGTH,
1602                                 "%s: %s seconds", fi->hfinfo->name,
1603                                 rel_time_to_str(&fi->value.time));
1604                         break;
1605
1606                 case FT_IPXNET:
1607                         snprintf(label_str, ITEM_LABEL_LENGTH,
1608                                 "%s: 0x%08X (%s)", fi->hfinfo->name,
1609                                 fi->value.numeric, get_ipxnet_name(fi->value.numeric));
1610                         break;
1611
1612                 case FT_ETHER:
1613                         snprintf(label_str, ITEM_LABEL_LENGTH,
1614                                 "%s: %s (%s)", fi->hfinfo->name,
1615                                 ether_to_str(fi->value.ether),
1616                                 get_ether_name(fi->value.ether));
1617                         break;
1618
1619                 case FT_IPv4:
1620                         n_addr = ipv4_get_net_order_addr(&fi->value.ipv4);
1621                         snprintf(label_str, ITEM_LABEL_LENGTH,
1622                                 "%s: %s (%s)", fi->hfinfo->name,
1623                                 get_hostname(n_addr),
1624                                 ip_to_str((guint8*)&n_addr));
1625                         break;
1626
1627                 case FT_IPv6:
1628                         snprintf(label_str, ITEM_LABEL_LENGTH,
1629                                 "%s: %s (%s)", fi->hfinfo->name,
1630                                 get_hostname6((struct e_in6_addr *)fi->value.ipv6),
1631                                 ip6_to_str((struct e_in6_addr*)fi->value.ipv6));
1632                         break;
1633         
1634                 case FT_STRING:
1635                 case FT_NSTRING_UINT8:
1636                         snprintf(label_str, ITEM_LABEL_LENGTH,
1637                                 "%s: %s", fi->hfinfo->name, fi->value.string);
1638                         break;
1639
1640                 default:
1641                         g_error("hfinfo->type %d not handled\n", fi->hfinfo->type);
1642                         break;
1643         }
1644 }
1645
1646 static void
1647 fill_label_boolean(field_info *fi, gchar *label_str)
1648 {
1649         char *p = label_str;
1650         int bitfield_byte_length = 0, bitwidth;
1651         guint32 unshifted_value;
1652
1653         struct header_field_info        *hfinfo = fi->hfinfo;
1654         struct true_false_string        default_tf = { "True", "False" };
1655         struct true_false_string        *tfstring = &default_tf;
1656
1657         if (hfinfo->strings) {
1658                 tfstring = (struct true_false_string*) hfinfo->strings;
1659         }
1660
1661         if (hfinfo->bitmask) {
1662                 /* Figure out the bit width */
1663                 bitwidth = hfinfo_bitwidth(hfinfo);
1664
1665                 /* Un-shift bits */
1666                 unshifted_value = fi->value.numeric;
1667                 if (hfinfo->bitshift > 0) {
1668                         unshifted_value <<= hfinfo->bitshift;
1669                 }
1670
1671                 /* Create the bitfield first */
1672                 p = decode_bitfield_value(label_str, unshifted_value, hfinfo->bitmask, bitwidth);
1673                 bitfield_byte_length = p - label_str;
1674         }
1675
1676         /* Fill in the textual info */
1677         snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
1678                 "%s: %s",  hfinfo->name,
1679                 fi->value.numeric ? tfstring->true_string : tfstring->false_string);
1680 }
1681
1682
1683 /* Fills data for bitfield ints with val_strings */
1684 static void
1685 fill_label_enumerated_bitfield(field_info *fi, gchar *label_str)
1686 {
1687         char *format = NULL, *p;
1688         int bitfield_byte_length, bitwidth;
1689         guint32 unshifted_value;
1690
1691         struct header_field_info        *hfinfo = fi->hfinfo;
1692
1693         /* Figure out the bit width */
1694         bitwidth = hfinfo_bitwidth(hfinfo);
1695
1696         /* Pick the proper format string */
1697         format = hfinfo_uint_vals_format(hfinfo);
1698
1699         /* Un-shift bits */
1700         unshifted_value = fi->value.numeric;
1701         if (hfinfo->bitshift > 0) {
1702                 unshifted_value <<= hfinfo->bitshift;
1703         }
1704
1705         /* Create the bitfield first */
1706         p = decode_bitfield_value(label_str, unshifted_value, hfinfo->bitmask, bitwidth);
1707         bitfield_byte_length = p - label_str;
1708
1709         /* Fill in the textual info using stored (shifted) value */
1710         snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
1711                         format,  hfinfo->name,
1712                         val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
1713                         fi->value.numeric);
1714 }
1715
1716 static void
1717 fill_label_numeric_bitfield(field_info *fi, gchar *label_str)
1718 {
1719         char *format = NULL, *p;
1720         int bitfield_byte_length, bitwidth;
1721         guint32 unshifted_value;
1722
1723         struct header_field_info        *hfinfo = fi->hfinfo;
1724
1725         /* Figure out the bit width */
1726         bitwidth = hfinfo_bitwidth(hfinfo);
1727
1728         /* Pick the proper format string */
1729         format = hfinfo_uint_format(hfinfo);
1730
1731         /* Un-shift bits */
1732         unshifted_value = fi->value.numeric;
1733         if (hfinfo->bitshift > 0) {
1734                 unshifted_value <<= hfinfo->bitshift;
1735         }
1736
1737         /* Create the bitfield using */
1738         p = decode_bitfield_value(label_str, unshifted_value, hfinfo->bitmask, bitwidth);
1739         bitfield_byte_length = p - label_str;
1740
1741         /* Fill in the textual info using stored (shifted) value */
1742         snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
1743                         format,  hfinfo->name, fi->value.numeric);
1744 }
1745
1746 static void
1747 fill_label_enumerated_uint(field_info *fi, gchar *label_str)
1748 {
1749         char *format = NULL;
1750         struct header_field_info        *hfinfo = fi->hfinfo;
1751
1752         /* Pick the proper format string */
1753         format = hfinfo_uint_vals_format(hfinfo);
1754
1755         /* Fill in the textual info */
1756         snprintf(label_str, ITEM_LABEL_LENGTH,
1757                         format,  hfinfo->name,
1758                         val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
1759                         fi->value.numeric);
1760 }
1761
1762 static void
1763 fill_label_uint(field_info *fi, gchar *label_str)
1764 {
1765         char *format = NULL;
1766         struct header_field_info        *hfinfo = fi->hfinfo;
1767
1768         /* Pick the proper format string */
1769         format = hfinfo_uint_format(hfinfo);
1770
1771         /* Fill in the textual info */
1772         snprintf(label_str, ITEM_LABEL_LENGTH,
1773                         format,  hfinfo->name, fi->value.numeric);
1774 }
1775
1776 static void
1777 fill_label_enumerated_int(field_info *fi, gchar *label_str)
1778 {
1779         char *format = NULL;
1780         struct header_field_info        *hfinfo = fi->hfinfo;
1781
1782         /* Pick the proper format string */
1783         format = hfinfo_int_vals_format(hfinfo);
1784
1785         /* Fill in the textual info */
1786         snprintf(label_str, ITEM_LABEL_LENGTH,
1787                         format,  hfinfo->name,
1788                         val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
1789                         fi->value.numeric);
1790 }
1791
1792 static void
1793 fill_label_int(field_info *fi, gchar *label_str)
1794 {
1795         char *format = NULL;
1796         struct header_field_info        *hfinfo = fi->hfinfo;
1797
1798         /* Pick the proper format string */
1799         format = hfinfo_int_format(hfinfo);
1800
1801         /* Fill in the textual info */
1802         snprintf(label_str, ITEM_LABEL_LENGTH,
1803                         format,  hfinfo->name, fi->value.numeric);
1804 }
1805
1806 static int
1807 hfinfo_bitwidth(header_field_info *hfinfo)
1808 {
1809         int bitwidth = 0;
1810
1811         if (!hfinfo->bitmask) {
1812                 return 0;
1813         }
1814
1815         switch(hfinfo->type) {
1816                 case FT_UINT8:
1817                 case FT_INT8:
1818                         bitwidth = 8;
1819                         break;
1820                 case FT_UINT16:
1821                 case FT_INT16:
1822                         bitwidth = 16;
1823                         break;
1824                 case FT_UINT24:
1825                 case FT_INT24:
1826                         bitwidth = 24;
1827                         break;
1828                 case FT_UINT32:
1829                 case FT_INT32:
1830                         bitwidth = 32;
1831                         break;
1832                 case FT_BOOLEAN:
1833                         bitwidth = hfinfo->display; /* hacky? :) */
1834                         break;
1835                 default:
1836                         g_assert_not_reached();
1837                         ;
1838         }
1839         return bitwidth;
1840 }
1841
1842 static char*
1843 hfinfo_uint_vals_format(header_field_info *hfinfo)
1844 {
1845         char *format = NULL;
1846
1847         switch(hfinfo->display) {
1848                 case BASE_DEC:
1849                 case BASE_NONE:
1850                 case BASE_OCT: /* I'm lazy */
1851                 case BASE_BIN: /* I'm lazy */
1852                         format = "%s: %s (%u)";
1853                         break;
1854                 case BASE_HEX:
1855                         switch(hfinfo->type) {
1856                                 case FT_UINT8:
1857                                         format = "%s: %s (0x%02x)";
1858                                         break;
1859                                 case FT_UINT16:
1860                                         format = "%s: %s (0x%04x)";
1861                                         break;
1862                                 case FT_UINT24:
1863                                         format = "%s: %s (0x%06x)";
1864                                         break;
1865                                 case FT_UINT32:
1866                                         format = "%s: %s (0x%08x)";
1867                                         break;
1868                                 default:
1869                                         g_assert_not_reached();
1870                                         ;
1871                         }
1872                         break;
1873                 default:
1874                         g_assert_not_reached();
1875                         ;
1876         }
1877         return format;
1878 }
1879
1880 static char*
1881 hfinfo_uint_format(header_field_info *hfinfo)
1882 {
1883         char *format = NULL;
1884
1885         /* Pick the proper format string */
1886         switch(hfinfo->display) {
1887                 case BASE_DEC:
1888                 case BASE_NONE:
1889                 case BASE_OCT: /* I'm lazy */
1890                 case BASE_BIN: /* I'm lazy */
1891                         format = "%s: %u";
1892                         break;
1893                 case BASE_HEX:
1894                         switch(hfinfo->type) {
1895                                 case FT_UINT8:
1896                                         format = "%s: 0x%02x";
1897                                         break;
1898                                 case FT_UINT16:
1899                                         format = "%s: 0x%04x";
1900                                         break;
1901                                 case FT_UINT24:
1902                                         format = "%s: 0x%06x";
1903                                         break;
1904                                 case FT_UINT32:
1905                                         format = "%s: 0x%08x";
1906                                         break;
1907                                 default:
1908                                         g_assert_not_reached();
1909                                         ;
1910                         }
1911                         break;
1912                 default:
1913                         g_assert_not_reached();
1914                         ;
1915         }
1916         return format;
1917 }
1918
1919 static char*
1920 hfinfo_int_vals_format(header_field_info *hfinfo)
1921 {
1922         char *format = NULL;
1923
1924         switch(hfinfo->display) {
1925                 case BASE_DEC:
1926                 case BASE_NONE:
1927                 case BASE_OCT: /* I'm lazy */
1928                 case BASE_BIN: /* I'm lazy */
1929                         format = "%s: %s (%d)";
1930                         break;
1931                 case BASE_HEX:
1932                         switch(hfinfo->type) {
1933                                 case FT_INT8:
1934                                         format = "%s: %s (0x%02x)";
1935                                         break;
1936                                 case FT_INT16:
1937                                         format = "%s: %s (0x%04x)";
1938                                         break;
1939                                 case FT_INT24:
1940                                         format = "%s: %s (0x%06x)";
1941                                         break;
1942                                 case FT_INT32:
1943                                         format = "%s: %s (0x%08x)";
1944                                         break;
1945                                 default:
1946                                         g_assert_not_reached();
1947                                         ;
1948                         }
1949                         break;
1950                 default:
1951                         g_assert_not_reached();
1952                         ;
1953         }
1954         return format;
1955 }
1956
1957 static char*
1958 hfinfo_int_format(header_field_info *hfinfo)
1959 {
1960         char *format = NULL;
1961
1962         /* Pick the proper format string */
1963         switch(hfinfo->display) {
1964                 case BASE_DEC:
1965                 case BASE_NONE:
1966                 case BASE_OCT: /* I'm lazy */
1967                 case BASE_BIN: /* I'm lazy */
1968                         format = "%s: %d";
1969                         break;
1970                 case BASE_HEX:
1971                         switch(hfinfo->type) {
1972                                 case FT_INT8:
1973                                         format = "%s: 0x%02x";
1974                                         break;
1975                                 case FT_INT16:
1976                                         format = "%s: 0x%04x";
1977                                         break;
1978                                 case FT_INT24:
1979                                         format = "%s: 0x%06x";
1980                                         break;
1981                                 case FT_INT32:
1982                                         format = "%s: 0x%08x";
1983                                         break;
1984                                 default:
1985                                         g_assert_not_reached();
1986                                         ;
1987                         }
1988                         break;
1989                 default:
1990                         g_assert_not_reached();
1991                         ;
1992         }
1993         return format;
1994 }
1995
1996
1997
1998 int
1999 proto_registrar_n(void)
2000 {
2001         return gpa_hfinfo->len;
2002 }
2003
2004 char*
2005 proto_registrar_get_name(int n)
2006 {
2007     struct header_field_info *hfinfo;
2008     hfinfo = proto_registrar_get_nth(n);
2009     if (hfinfo)
2010         return hfinfo->name;
2011     else        return NULL;
2012 }
2013
2014 char*
2015 proto_registrar_get_abbrev(int n)
2016 {
2017         struct header_field_info *hfinfo;
2018
2019         hfinfo = proto_registrar_get_nth(n);
2020         if (hfinfo)
2021                 return hfinfo->abbrev;
2022         else
2023                 return NULL;
2024 }
2025
2026 int
2027 proto_registrar_get_ftype(int n)
2028 {
2029         struct header_field_info *hfinfo;
2030
2031         hfinfo = proto_registrar_get_nth(n);
2032         if (hfinfo)
2033                 return hfinfo->type;
2034         else
2035                 return -1;
2036 }
2037
2038 int
2039 proto_registrar_get_parent(int n)
2040 {
2041         struct header_field_info *hfinfo;
2042
2043         hfinfo = proto_registrar_get_nth(n);
2044         if (hfinfo)
2045                 return hfinfo->parent;
2046         else
2047                 return -2;
2048 }
2049
2050 gboolean
2051 proto_registrar_is_protocol(int n)
2052 {
2053         struct header_field_info *hfinfo;
2054
2055         hfinfo = proto_registrar_get_nth(n);
2056         if (hfinfo)
2057                 return (hfinfo->parent == -1 ? TRUE : FALSE);
2058         else
2059                 return FALSE;
2060 }
2061
2062 /* Returns length of field in packet (not necessarily the length
2063  * in our internal representation, as in the case of IPv4).
2064  * 0 means undeterminable at time of registration
2065  * -1 means the field is not registered. */
2066 gint
2067 proto_registrar_get_length(int n)
2068 {
2069         struct header_field_info *hfinfo;
2070
2071         hfinfo = proto_registrar_get_nth(n);
2072         if (!hfinfo)
2073                 return -1;
2074
2075         switch (hfinfo->type) {
2076                 case FT_TEXT_ONLY: /* not filterable */
2077                 case NUM_FIELD_TYPES: /* satisfy picky compilers */
2078                         return -1;
2079
2080                 case FT_NONE:
2081                 case FT_BYTES:
2082                 case FT_BOOLEAN:
2083                 case FT_STRING:
2084                 case FT_NSTRING_UINT8:
2085                 case FT_DOUBLE:
2086                 case FT_ABSOLUTE_TIME:
2087                 case FT_RELATIVE_TIME:
2088                         return 0;
2089
2090                 case FT_UINT8:
2091                 case FT_INT8:
2092                         return 1;
2093
2094                 case FT_UINT16:
2095                 case FT_INT16:
2096                         return 2;
2097
2098                 case FT_UINT24:
2099                 case FT_INT24:
2100                         return 3;
2101
2102                 case FT_UINT32:
2103                 case FT_INT32:
2104                 case FT_IPXNET:
2105                 case FT_IPv4:
2106                         return 4;
2107
2108                 case FT_ETHER:
2109                         return 6;
2110
2111                 case FT_IPv6:
2112                         return 16;
2113         }
2114         g_assert_not_reached();
2115         return -1;
2116 }
2117
2118
2119 /* =================================================================== */
2120 /* used when calling proto search functions */
2121 typedef struct {
2122         int                     target;
2123         int                     parent;
2124         const guint8            *packet_data;
2125         guint                   packet_len;
2126         gboolean                halt_on_first_hit;
2127         GNodeTraverseFunc       traverse_func; /* for traverse_subtree_for_field() */
2128         union {
2129                 GPtrArray               *ptr_array;
2130                 GNode                   *node;
2131         }                       result;
2132 } proto_tree_search_info;
2133
2134 /* Looks for a protocol at the top layer of the tree. The protocol can occur
2135  * more than once, for those encapsulated protocols. For each protocol subtree
2136  * that is found, the callback function is called.
2137  */
2138 static void
2139 proto_find_protocol_multi(proto_tree* tree, int target, GNodeTraverseFunc callback,
2140                         proto_tree_search_info *sinfo)
2141 {
2142         g_assert(callback != NULL);
2143         g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2, callback, (gpointer*)sinfo);
2144 }
2145
2146 /* Calls a traversal function for all subtrees where:
2147  * 1. Subtree is immediate child of root node. That is, subtree is a "protocol"
2148  * 2. Subtree has finfo such that finfo->hfinfo->id == sinfo->parent
2149  */
2150 static gboolean
2151 traverse_subtree_for_field(GNode *node, gpointer data)
2152 {
2153         field_info              *fi = (field_info*) (node->data);
2154         proto_tree_search_info  *sinfo = (proto_tree_search_info*) data;
2155
2156         if (fi) { /* !fi == the top most container node which holds nothing */
2157                 if (fi->hfinfo->id == sinfo->parent) {
2158                         g_node_traverse(node, G_IN_ORDER, G_TRAVERSE_ALL, -1,
2159                                         sinfo->traverse_func, sinfo);
2160                         if (sinfo->result.node)
2161                                 return sinfo->halt_on_first_hit; /* halt? continue? */
2162                 }
2163         }
2164         return FALSE; /* keep traversing */
2165 }
2166
2167 static gboolean
2168 check_for_protocol_or_field_id(GNode *node, gpointer data)
2169 {
2170         field_info              *fi = (field_info*) (node->data);
2171         proto_tree_search_info  *sinfo = (proto_tree_search_info*) data;
2172
2173         if (fi) { /* !fi == the top most container node which holds nothing */
2174                 if (fi->hfinfo->id == sinfo->target) {
2175                         sinfo->result.node = node;
2176                         return TRUE; /* halt traversal */
2177                 }
2178         }
2179         return FALSE; /* keep traversing */
2180 }
2181
2182 /* Looks for a protocol or a field in a proto_tree. Returns TRUE if
2183  * it exists anywhere, or FALSE if it exists nowhere. */
2184 gboolean
2185 proto_check_for_protocol_or_field(proto_tree* tree, int id)
2186 {
2187         proto_tree_search_info  sinfo;
2188
2189         sinfo.target            = id;
2190         sinfo.result.node       = NULL;
2191         sinfo.parent            = -1;
2192         sinfo.traverse_func     = check_for_protocol_or_field_id;
2193         sinfo.halt_on_first_hit = TRUE;
2194
2195         /* do a quicker check if target is a protocol */
2196         if (proto_registrar_is_protocol(id) == TRUE) {
2197                 proto_find_protocol_multi(tree, id, check_for_protocol_or_field_id, &sinfo);
2198         }
2199         else {
2200                 /* find the field's parent protocol */
2201                 sinfo.parent = proto_registrar_get_parent(id);
2202
2203                 /* Go through each protocol subtree, checking if the protocols
2204                  * is the parent protocol of the field that we're looking for.
2205                  * We may have protocols that occur more than once (e.g., IP in IP),
2206                  * so we do indeed have to check all protocol subtrees, looking
2207                  * for the parent protocol. That's why proto_find_protocol()
2208                  * is not used --- it assumes a protocol occurs only once. */
2209                 g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2,
2210                                                 traverse_subtree_for_field, &sinfo);
2211         }
2212
2213         if (sinfo.result.node)
2214                 return TRUE;
2215         else
2216                 return FALSE;
2217 }
2218
2219
2220
2221 static gboolean
2222 get_finfo_ptr_array(GNode *node, gpointer data)
2223 {
2224         field_info              *fi = (field_info*) (node->data);
2225         proto_tree_search_info  *sinfo = (proto_tree_search_info*) data;
2226
2227         if (fi) { /* !fi == the top most container node which holds nothing */
2228                 if (fi->hfinfo->id == sinfo->target) {
2229                         if (!sinfo->result.ptr_array) {
2230                                 sinfo->result.ptr_array = g_ptr_array_new();
2231                         }
2232                         g_ptr_array_add(sinfo->result.ptr_array,
2233                                         (gpointer)fi);
2234                         return FALSE; /* keep traversing */
2235                 }
2236         }
2237         return FALSE; /* keep traversing */
2238 }
2239
2240 /* Return GPtrArray* of field_info pointers for all hfindex that appear in tree
2241  * (we assume that a field will only appear under its registered parent's subtree) */
2242 GPtrArray*
2243 proto_get_finfo_ptr_array(proto_tree *tree, int id)
2244 {
2245         proto_tree_search_info  sinfo;
2246
2247         sinfo.target            = id;
2248         sinfo.result.ptr_array  = NULL;
2249         sinfo.parent            = -1;
2250         sinfo.traverse_func     = get_finfo_ptr_array;
2251         sinfo.halt_on_first_hit = FALSE;
2252
2253         /* do a quicker check if target is a protocol */
2254         if (proto_registrar_is_protocol(id) == TRUE) {
2255                 proto_find_protocol_multi(tree, id, get_finfo_ptr_array, &sinfo);
2256         }
2257         else {
2258                 /* find the field's parent protocol */
2259                 sinfo.parent = proto_registrar_get_parent(id);
2260
2261                 /* Go through each protocol subtree, checking if the protocols
2262                  * is the parent protocol of the field that we're looking for.
2263                  * We may have protocols that occur more than once (e.g., IP in IP),
2264                  * so we do indeed have to check all protocol subtrees, looking
2265                  * for the parent protocol. That's why proto_find_protocol()
2266                  * is not used --- it assumes a protocol occurs only once. */
2267                 sinfo.traverse_func = get_finfo_ptr_array;
2268                 g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2,
2269                                                 traverse_subtree_for_field, &sinfo);
2270         }
2271
2272         return sinfo.result.ptr_array;
2273 }
2274         
2275
2276 /* Dumps the contents of the registration database to stdout. An indepedent program can take
2277  * this output and format it into nice tables or HTML or whatever.
2278  *
2279  * There is one record per line. Each record is either a protocol or a header
2280  * field, differentiated by the first field. The fields are tab-delimited.
2281  *
2282  * Protocols
2283  * ---------
2284  * Field 1 = 'P'
2285  * Field 2 = protocol name
2286  * Field 3 = protocol abbreviation
2287  *
2288  * Header Fields
2289  * -------------
2290  * Field 1 = 'F'
2291  * Field 2 = field name
2292  * Field 3 = field abbreviation
2293  * Field 4 = type ( textual representation of the the ftenum type )
2294  * Field 5 = parent protocol abbreviation
2295  */
2296 void
2297 proto_registrar_dump(void)
2298 {
2299         header_field_info       *hfinfo, *parent_hfinfo;
2300         int                     i, len;
2301         const char              *enum_name;
2302
2303         len = gpa_hfinfo->len;
2304         for (i = 0; i < len ; i++) {
2305                 hfinfo = proto_registrar_get_nth(i);
2306
2307                 /* format for protocols */
2308                 if (proto_registrar_is_protocol(i)) {
2309                         printf("P\t%s\t%s\n", hfinfo->name, hfinfo->abbrev);
2310                 }
2311                 /* format for header fields */
2312                 else {
2313                         parent_hfinfo = proto_registrar_get_nth(hfinfo->parent);
2314                         g_assert(parent_hfinfo);
2315
2316                         switch(hfinfo->type) {
2317                         case FT_NONE:
2318                                 enum_name = "FT_NONE";
2319                                 break;
2320                         case FT_BOOLEAN:
2321                                 enum_name = "FT_BOOLEAN";
2322                                 break;
2323                         case FT_UINT8:
2324                                 enum_name = "FT_UINT8";
2325                                 break;
2326                         case FT_UINT16:
2327                                 enum_name = "FT_UINT16";
2328                                 break;
2329                         case FT_UINT24:
2330                                 enum_name = "FT_UINT24";
2331                                 break;
2332                         case FT_UINT32:
2333                                 enum_name = "FT_UINT32";
2334                                 break;
2335                         case FT_INT8:
2336                                 enum_name = "FT_INT8";
2337                                 break;
2338                         case FT_INT16:
2339                                 enum_name = "FT_INT16";
2340                                 break;
2341                         case FT_INT24:
2342                                 enum_name = "FT_INT24";
2343                                 break;
2344                         case FT_INT32:
2345                                 enum_name = "FT_INT32";
2346                                 break;
2347                         case FT_DOUBLE:
2348                                 enum_name = "FT_DOUBLE";
2349                                 break;
2350                         case FT_ABSOLUTE_TIME:
2351                                 enum_name = "FT_ABSOLUTE_TIME";
2352                                 break;
2353                         case FT_RELATIVE_TIME:
2354                                 enum_name = "FT_RELATIVE_TIME";
2355                                 break;
2356                         case FT_NSTRING_UINT8:
2357                                 enum_name = "FT_NSTRING_UINT8";
2358                                 break;
2359                         case FT_STRING:
2360                                 enum_name = "FT_STRING";
2361                                 break;
2362                         case FT_ETHER:
2363                                 enum_name = "FT_ETHER";
2364                                 break;
2365                         case FT_BYTES:
2366                                 enum_name = "FT_BYTES";
2367                                 break;
2368                         case FT_IPv4:
2369                                 enum_name = "FT_IPv4";
2370                                 break;
2371                         case FT_IPv6:
2372                                 enum_name = "FT_IPv6";
2373                                 break;
2374                         case FT_IPXNET:
2375                                 enum_name = "FT_IPXNET";
2376                                 break;
2377                         case FT_TEXT_ONLY:
2378                                 enum_name = "FT_TEXT_ONLY";
2379                                 break;
2380                         default:
2381                                 g_assert_not_reached();
2382                                 enum_name = NULL;
2383                         }
2384                         printf("F\t%s\t%s\t%s\t%s\n", hfinfo->name, hfinfo->abbrev,
2385                                 enum_name,parent_hfinfo->abbrev);
2386                 }
2387         }
2388 }