Make FT_STRINGZ items work as apply/prepare as filter menu items
[obnox/wireshark/wip.git] / epan / proto.c
index 25c708eba9a2e1bb55bd7d09e2e64d4605e07e76..9be193a7a923bb73735785e6ce243528081dad37 100644 (file)
@@ -3,8 +3,8 @@
  *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
 #include <glib.h>
 #include <float.h>
 
-#ifdef NEED_SNPRINTF_H
-# include "snprintf.h"
-#endif
-
 #include "packet.h"
+#include "ptvcursor.h"
 #include "strutil.h"
 #include "addr_resolv.h"
+#include "oid_resolv.h"
 #include "plugins.h"
-#include "ipv6-utils.h"
 #include "proto.h"
 #include "epan_dissect.h"
 #include "slab.h"
 #include "tvbuff.h"
+#include "emem.h"
+
+struct ptvcursor {
+       proto_tree      *tree;
+       tvbuff_t        *tvb;
+       gint            offset;
+};
 
 #define cVALS(x) (const value_string*)(x)
 
+#if 1
+#define TRY_TO_FAKE_THIS_ITEM(tree, hfindex) \
+       /* If this item is not referenced we dont have to do much work  \
+          at all but we should still return a node so that             \
+          field items below this node ( think proto_item_add_subtree() )\
+          will still have somewhere to attach to                       \
+          or else filtering will not work (they would be ignored since tree\
+          would be NULL).                                              \
+          DONT try to fake a node where PITEM_FINFO(pi) is NULL        \
+          since dissectors that want to do proto_item_set_len() ot     \
+          other operations that dereference this would crash.          \
+          We dont fake FT_PROTOCOL either since these are cheap and    \
+          some stuff (proto hier stat) assumes they always exist.      \
+       */                                                              \
+       if(!(PTREE_DATA(tree)->visible)){                               \
+               if(PITEM_FINFO(tree)){                                  \
+                       register header_field_info *hfinfo;             \
+                       PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);       \
+                       if((hfinfo->ref_count == 0)                     \
+                       && (hfinfo->type!=FT_PROTOCOL)){                \
+                               /* just return tree back to the caller */\
+                               return tree;                            \
+                       }                                               \
+               }                                                       \
+       }
+#else
+#define TRY_TO_FAKE_THIS_ITEM(tree, hfindex) ;
+#endif
+
 static gboolean
 proto_tree_free_node(proto_node *node, gpointer data);
 
@@ -62,16 +95,24 @@ static void fill_label_int64(field_info *fi, gchar *label_str);
 static void fill_label_enumerated_int(field_info *fi, gchar *label_str);
 
 int hfinfo_bitwidth(header_field_info *hfinfo);
-static char* hfinfo_uint_vals_format(header_field_info *hfinfo);
-static char* hfinfo_uint_format(header_field_info *hfinfo);
-static char* hfinfo_uint64_format(header_field_info *hfinfo);
-static char* hfinfo_int_vals_format(header_field_info *hfinfo);
-static char* hfinfo_int_format(header_field_info *hfinfo);
-static char* hfinfo_int64_format(header_field_info *hfinfo);
+static const char* hfinfo_uint_vals_format(header_field_info *hfinfo);
+static const char* hfinfo_uint_format(header_field_info *hfinfo);
+static const char* hfinfo_uint64_format(header_field_info *hfinfo);
+static const char* hfinfo_int_vals_format(header_field_info *hfinfo);
+static const char* hfinfo_int_format(header_field_info *hfinfo);
+static const char* hfinfo_int64_format(header_field_info *hfinfo);
 
 static proto_item*
 proto_tree_add_node(proto_tree *tree, field_info *fi);
 
+static header_field_info *
+get_hfi_and_length(int hfindex, tvbuff_t *tvb, gint start, gint *length,
+    gint *item_length);
+
+static field_info *
+new_field_info(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb,
+    gint start, gint item_length);
+
 static field_info *
 alloc_field_info(proto_tree *tree, int hfindex, tvbuff_t *tvb,
         gint start, gint *length);
@@ -80,6 +121,8 @@ static proto_item *
 proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb,
         gint start, gint *length, field_info **pfi);
 
+static void
+proto_tree_set_representation_value(proto_item *pi, const char *format, va_list ap);
 static void
 proto_tree_set_representation(proto_item *pi, const char *format, va_list ap);
 
@@ -108,6 +151,14 @@ proto_tree_set_ipv6(field_info *fi, const guint8* value_ptr);
 static void
 proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start);
 static void
+proto_tree_set_guid(field_info *fi, const e_guid_t *value_ptr);
+static void
+proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian);
+static void
+proto_tree_set_oid(field_info *fi, const guint8* value_ptr, gint length);
+static void
+proto_tree_set_oid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
+static void
 proto_tree_set_boolean(field_info *fi, guint32 value);
 static void
 proto_tree_set_float(field_info *fi, float value);
@@ -132,18 +183,18 @@ int hf_text_only = -1;
 
 /* Structure for information about a protocol */
 struct _protocol {
-       char    *name;          /* long description */
-       char    *short_name;    /* short description */
-       char    *filter_name;   /* name of this protocol in filters */
-       int     proto_id;       /* field ID for this protocol */
-       GList   *fields;        /* fields for this protocol */
-       GList   *last_field;    /* pointer to end of list of fields */
-       gboolean is_enabled;    /* TRUE if protocol is enabled */
-       gboolean can_toggle;    /* TRUE if is_enabled can be changed */
+       const char *name;               /* long description */
+       const char *short_name;         /* short description */
+       const char *filter_name;        /* name of this protocol in filters */
+       int     proto_id;               /* field ID for this protocol */
+       GList   *fields;                /* fields for this protocol */
+       GList   *last_field;            /* pointer to end of list of fields */
+       gboolean is_enabled;            /* TRUE if protocol is enabled */
+       gboolean can_toggle;            /* TRUE if is_enabled can be changed */
 };
 
 /* List of all protocols */
-static GList *protocols;
+static GList *protocols = NULL;
 
 #define INITIAL_NUM_PROTOCOL_HFINFO     200
 
@@ -187,6 +238,10 @@ static SLAB_FREE_LIST_DEFINE(item_label_t)
        SLAB_FREE(il, item_label_t)
 
 
+#define PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo) \
+       DISSECTOR_ASSERT((guint)hfindex < gpa_hfinfo.len); \
+       hfinfo=gpa_hfinfo.hfi[hfindex];
+
 
 /* List which stores protocols and fields that have been registered */
 typedef struct _gpa_hfinfo_t {
@@ -207,6 +262,21 @@ gboolean   *tree_is_expanded;
 /* Number of elements in that array. */
 int            num_tree_types;
 
+/* Name hashtables for fast detection of duplicate names */
+static GHashTable* proto_names = NULL;
+static GHashTable* proto_short_names = NULL;
+static GHashTable* proto_filter_names = NULL;
+
+static gint
+proto_compare_name(gconstpointer p1_arg, gconstpointer p2_arg)
+{
+       const protocol_t *p1 = p1_arg;
+       const protocol_t *p2 = p2_arg;
+
+       return g_strcasecmp(p1->short_name, p2->short_name);
+}
+
+
 /* initialize data structures and register protocols and fields */
 void
 proto_init(const char *plugin_dir
@@ -223,6 +293,11 @@ proto_init(const char *plugin_dir
                        NULL, HFILL }},
        };
 
+
+    proto_names = g_hash_table_new(g_int_hash, g_int_equal);
+    proto_short_names = g_hash_table_new(g_int_hash, g_int_equal);
+    proto_filter_names = g_hash_table_new(g_int_hash, g_int_equal);
+
        proto_cleanup();
 
        gmc_hfinfo = g_mem_chunk_new("gmc_hfinfo",
@@ -239,7 +314,7 @@ proto_init(const char *plugin_dir
        ftypes_initialize();
 
        /* Register one special-case FT_TEXT_ONLY field for use when
-          converting ethereal to new-style proto_tree. These fields
+          converting wireshark to new-style proto_tree. These fields
           are merely strings on the GUI tree; they are not filterable */
        proto_register_field_array(-1, hf, array_length(hf));
 
@@ -266,10 +341,13 @@ proto_init(const char *plugin_dir
        register_all_plugin_handoffs();
 #endif
 
+    /* sort the protocols by protocol name */
+    protocols = g_list_sort(protocols, proto_compare_name);
+
        /* We've assigned all the subtree type values; allocate the array
           for them, and zero it out. */
-       tree_is_expanded = g_malloc(num_tree_types*sizeof (gint *));
-       memset(tree_is_expanded, 0, num_tree_types*sizeof (gint *));
+       tree_is_expanded = g_malloc(num_tree_types*sizeof (gboolean));
+       memset(tree_is_expanded, 0, num_tree_types*sizeof (gboolean));
 }
 
 /* String comparison func for dfilter_token GTree */
@@ -403,6 +481,23 @@ static void
 free_GPtrArray_value(gpointer key _U_, gpointer value, gpointer user_data _U_)
 {
        GPtrArray   *ptrs = value;
+       gint hfid = (gint)key;
+       header_field_info *hfinfo;
+
+
+       PROTO_REGISTRAR_GET_NTH(hfid, hfinfo);
+       if(hfinfo->ref_count){
+               /* when a field is referenced by a filter this also
+                  affects the refcount for the parent protocol so we need
+                  to adjust the refcount for the parent as well
+               */
+               if( (hfinfo->parent != -1) && (hfinfo->ref_count) ){
+                       header_field_info *parent_hfinfo;
+                       PROTO_REGISTRAR_GET_NTH(hfinfo->parent, parent_hfinfo);
+                       parent_hfinfo->ref_count -= hfinfo->ref_count;
+               }
+               hfinfo->ref_count = 0;
+       }
 
        g_ptr_array_free(ptrs, TRUE);
 }
@@ -452,7 +547,7 @@ proto_tree_free_node(proto_node *node, gpointer data _U_)
 
 /* Is the parsing being done for a visible proto_tree or an invisible one?
  * By setting this correctly, the proto_tree creation is sped up by not
- * having to call vsnprintf and copy strings around.
+ * having to call g_vsnprintf and copy strings around.
  */
 void
 proto_tree_set_visible(proto_tree *tree, gboolean visible)
@@ -460,9 +555,32 @@ proto_tree_set_visible(proto_tree *tree, gboolean visible)
        PTREE_DATA(tree)->visible = visible;
 }
 
-#define PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo) \
-       g_assert((guint)hfindex < gpa_hfinfo.len); \
-       hfinfo=gpa_hfinfo.hfi[hfindex];         
+/* Assume dissector set only its protocol fields.
+   This function is called by dissectors and allowes to speed up filtering
+   in wireshark, if this function returns FALSE it is safe to reset tree to NULL
+   and thus skip calling most of the expensive proto_tree_add_...()
+   functions.
+   If the tree is visible we implicitely assume the field is referenced.
+*/
+gboolean
+proto_field_is_referenced(proto_tree *tree, int proto_id)
+{
+       register header_field_info *hfinfo;
+
+
+       if (!tree)
+               return FALSE;
+
+       if (PTREE_DATA(tree)->visible)
+               return TRUE;
+
+       PROTO_REGISTRAR_GET_NTH(proto_id, hfinfo);
+       if (hfinfo->ref_count != 0)
+               return TRUE;
+
+       return FALSE;
+}
+
 
 /* Finds a record in the hf_info_records array by id. */
 header_field_info*
@@ -477,12 +595,59 @@ proto_registrar_get_nth(guint hfindex)
 /* Finds a record in the hf_info_records array by name.
  */
 header_field_info*
-proto_registrar_get_byname(char *field_name)
+proto_registrar_get_byname(const char *field_name)
 {
-       g_assert(field_name != NULL);
+       DISSECTOR_ASSERT(field_name != NULL);
        return g_tree_lookup(gpa_name_tree, field_name);
 }
 
+/* Allocates an initializes a ptvcursor_t with 3 variables:
+ *     proto_tree, tvbuff, and offset. */
+ptvcursor_t*
+ptvcursor_new(proto_tree *tree, tvbuff_t *tvb, gint offset)
+{
+       ptvcursor_t     *ptvc;
+
+       ptvc = g_new(ptvcursor_t, 1);
+       ptvc->tree      = tree;
+       ptvc->tvb       = tvb;
+       ptvc->offset    = offset;
+       return ptvc;
+}
+
+/* Frees memory for ptvcursor_t, but nothing deeper than that. */
+void
+ptvcursor_free(ptvcursor_t *ptvc)
+{
+       g_free(ptvc);
+}
+
+/* Returns tvbuff. */
+tvbuff_t*
+ptvcursor_tvbuff(ptvcursor_t* ptvc)
+{
+       return ptvc->tvb;
+}
+
+/* Returns current offset. */
+gint
+ptvcursor_current_offset(ptvcursor_t* ptvc)
+{
+       return ptvc->offset;
+}
+
+proto_tree*
+ptvcursor_tree(ptvcursor_t* ptvc)
+{
+       return ptvc->tree;
+}
+
+void
+ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree)
+{
+       ptvc->tree = tree;
+}
+
 /* Add a text-only node, leaving it to our caller to fill the text in */
 static proto_item *
 proto_tree_add_text_node(proto_tree *tree, tvbuff_t *tvb, gint start, gint length)
@@ -581,7 +746,7 @@ get_uint_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
                break;
 
        default:
-               g_assert_not_reached();
+               THROW(ReportedBoundsError);
                value = 0;
                break;
        }
@@ -619,7 +784,7 @@ get_int_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
                break;
 
        default:
-               g_assert_not_reached();
+               THROW(ReportedBoundsError);
                value = 0;
                break;
        }
@@ -628,11 +793,10 @@ get_int_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
 
 /* Add an item to a proto_tree, using the text label registered to that item;
    the item is extracted from the tvbuff handed to it. */
-proto_item *
-proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
-    gint start, gint length, gboolean little_endian)
+static proto_item *
+proto_tree_new_item(field_info *new_fi, proto_tree *tree, int hfindex,
+    tvbuff_t *tvb, gint start, gint length, gboolean little_endian)
 {
-       field_info      *new_fi;
        proto_item      *pi;
        guint32         value, n;
        float           floatval;
@@ -641,14 +805,6 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
        GHashTable      *hash;
        GPtrArray       *ptrs;
 
-       if (!tree)
-               return(NULL);
-
-       new_fi = alloc_field_info(tree, hfindex, tvb, start, &length);
-
-       if (new_fi == NULL)
-               return(NULL);
-
        /* there is a possibility here that we might raise an exception
         * and thus would lose track of the field_info.
         * store it in a temp so that if we come here again we can reclaim
@@ -709,7 +865,7 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 
                case FT_INT64:
                case FT_UINT64:
-                       g_assert(length == 8);
+                       DISSECTOR_ASSERT(length == 8);
                        proto_tree_set_uint64_tvb(new_fi, tvb, start, little_endian);
                        break;
 
@@ -723,29 +879,38 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
                        break;
 
                case FT_IPv4:
-                       g_assert(length == 4);
-                       tvb_memcpy(tvb, (guint8 *)&value, start, 4);
+                       DISSECTOR_ASSERT(length == 4);
+                       value = tvb_get_ipv4(tvb, start);
                        proto_tree_set_ipv4(new_fi, little_endian ? GUINT32_SWAP_LE_BE(value) : value);
                        break;
 
                case FT_IPXNET:
-                       g_assert(length == 4);
+                       DISSECTOR_ASSERT(length == 4);
                        proto_tree_set_ipxnet(new_fi,
                            get_uint_value(tvb, start, 4, FALSE));
                        break;
 
                case FT_IPv6:
-                       g_assert(length == 16);
+                       DISSECTOR_ASSERT(length == 16);
                        proto_tree_set_ipv6_tvb(new_fi, tvb, start);
                        break;
 
                case FT_ETHER:
-                       g_assert(length == 6);
+                       DISSECTOR_ASSERT(length == 6);
                        proto_tree_set_ether_tvb(new_fi, tvb, start);
                        break;
 
+               case FT_GUID:
+                       DISSECTOR_ASSERT(length == 16);
+                       proto_tree_set_guid_tvb(new_fi, tvb, start, little_endian);
+                       break;
+
+               case FT_OID:
+                       proto_tree_set_oid_tvb(new_fi, tvb, start, length);
+                       break;
+
                case FT_FLOAT:
-                       g_assert(length == 4);
+                       DISSECTOR_ASSERT(length == 4);
                        if (little_endian)
                                floatval = tvb_get_letohieee_float(tvb, start);
                        else
@@ -754,7 +919,7 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
                        break;
 
                case FT_DOUBLE:
-                       g_assert(length == 8);
+                       DISSECTOR_ASSERT(length == 8);
                        if (little_endian)
                                doubleval = tvb_get_letohieee_double(tvb, start);
                        else
@@ -768,68 +933,67 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
                        break;
 
                case FT_STRINGZ:
-                       if (length != 0) {  /* XXX - Should we throw an exception instead? */
-                               /* Instead of calling proto_item_set_len(),
-                                * since we don't yet have a proto_item, we
-                                * set the field_info's length ourselves.
+                       DISSECTOR_ASSERT(length >= -1);
+                       /* Instead of calling proto_item_set_len(),
+                        * since we don't yet have a proto_item, we
+                        * set the field_info's length ourselves.
+                        *
+                        * XXX - our caller can't use that length to
+                        * advance an offset unless they arrange that
+                        * there always be a protocol tree into which
+                        * we're putting this item.
+                        */
+                       if (length == -1) {
+                               /* This can throw an exception */
+                               length = tvb_strsize(tvb, start);
+
+                               /* This g_malloc'ed memory is freed
+                                  in proto_tree_free_node() */
+                               string = g_malloc(length);
+
+                               tvb_memcpy(tvb, string, start, length);
+                       } else if (length == 0) {
+                               string = g_strdup("[Empty]");
+                       } else {
+                               /* In this case, length signifies
+                                * the length of the string.
+                                *
+                                * This could either be a null-padded
+                                * string, which doesn't necessarily
+                                * have a '\0' at the end, or a
+                                * null-terminated string, with a
+                                * trailing '\0'.  (Yes, there are
+                                * cases where you have a string
+                                * that's both counted and null-
+                                * terminated.)
+                                *
+                                * In the first case, we must
+                                * allocate a buffer of length
+                                * "length+1", to make room for
+                                * a trailing '\0'.
                                 *
-                                * XXX - our caller can't use that length to
-                                * advance an offset unless they arrange that
-                                * there always be a protocol tree into which
-                                * we're putting this item.
+                                * In the second case, we don't
+                                * assume that there is a trailing
+                                * '\0' there, as the packet might
+                                * be malformed.  (XXX - should we
+                                * throw an exception if there's no
+                                * trailing '\0'?)  Therefore, we
+                                * allocate a buffer of length
+                                * "length+1", and put in a trailing
+                                * '\0', just to be safe.
+                                *
+                                * (XXX - this would change if
+                                * we made string values counted
+                                * rather than null-terminated.)
                                 */
-                               if (length == -1) {
-                                       /* This can throw an exception */
-                                       length = tvb_strsize(tvb, start);
-
-                                       /* This g_malloc'ed memory is freed
-                                          in proto_tree_free_node() */
-                                       string = g_malloc(length);
 
-                                       tvb_memcpy(tvb, string, start, length);
-                                       new_fi->length = length;
-                               }
-                               else {
-                                       /* In this case, length signifies
-                                        * the length of the string.
-                                        *
-                                        * This could either be a null-padded
-                                        * string, which doesn't necessarily
-                                        * have a '\0' at the end, or a
-                                        * null-terminated string, with a
-                                        * trailing '\0'.  (Yes, there are
-                                        * cases where you have a string
-                                        * that's both counted and null-
-                                        * terminated.)
-                                        *
-                                        * In the first case, we must
-                                        * allocate a buffer of length
-                                        * "length+1", to make room for
-                                        * a trailing '\0'.
-                                        *
-                                        * In the second case, we don't
-                                        * assume that there is a trailing
-                                        * '\0' there, as the packet might
-                                        * be malformed.  (XXX - should we
-                                        * throw an exception if there's no
-                                        * trailing '\0'?)  Therefore, we
-                                        * allocate a buffer of length
-                                        * "length+1", and put in a trailing
-                                        * '\0', just to be safe.
-                                        *
-                                        * (XXX - this would change if
-                                        * we made string values counted
-                                        * rather than null-terminated.)
-                                        */
-
-                                       /* This g_malloc'ed memory is freed
-                                        * in proto_tree_free_node() */
-                                       string = tvb_get_string(tvb, start,
-                                           length);
-                                       new_fi->length = length;
-                               }
-                               proto_tree_set_string(new_fi, string, TRUE);
+                               /* This g_malloc'ed memory is freed
+                                * in proto_tree_free_node() */
+                               string = tvb_get_string(tvb, start,
+                                       length);
                        }
+                       new_fi->length = length;
+                       proto_tree_set_string(new_fi, string, TRUE);
                        break;
 
                case FT_UINT_STRING:
@@ -853,7 +1017,7 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
                        g_error("new_fi->hfinfo->type %d (%s) not handled\n",
                                        new_fi->hfinfo->type,
                                        ftype_name(new_fi->hfinfo->type));
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                        break;
        }
 
@@ -868,15 +1032,78 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 
        /* If the proto_tree wants to keep a record of this finfo
         * for quick lookup, then record it. */
-       hash = PTREE_DATA(tree)->interesting_hfids;
-       ptrs = g_hash_table_lookup(hash, GINT_TO_POINTER(hfindex));
-       if (ptrs) {
-               g_ptr_array_add(ptrs, new_fi);
+       if (new_fi->hfinfo->ref_count) {
+               /*HERE*/
+               hash = PTREE_DATA(tree)->interesting_hfids;
+               ptrs = g_hash_table_lookup(hash, GINT_TO_POINTER(hfindex));
+               if (ptrs) {
+                       g_ptr_array_add(ptrs, new_fi);
+               }
        }
 
        return pi;
 }
 
+/* Gets data from tvbuff, adds it to proto_tree, increments offset,
+   and returns proto_item* */
+proto_item*
+ptvcursor_add(ptvcursor_t *ptvc, int hfindex, gint length,
+    gboolean little_endian)
+{
+       field_info              *new_fi;
+       header_field_info       *hfinfo;
+       gint                    item_length;
+       guint32                 n;
+       int                     offset;
+
+       offset = ptvc->offset;
+       hfinfo = get_hfi_and_length(hfindex, ptvc->tvb, offset, &length,
+           &item_length);
+       ptvc->offset += length;
+       if (hfinfo->type == FT_UINT_BYTES || hfinfo->type == FT_UINT_STRING) {
+               /*
+                * The length of the rest of the item is in the first N
+                * bytes of the item.
+                */
+               n = get_uint_value(ptvc->tvb, offset, length, little_endian);
+               ptvc->offset += n;
+       }
+       if (ptvc->tree == NULL)
+               return NULL;
+
+       TRY_TO_FAKE_THIS_ITEM(ptvc->tree, hfindex);
+
+       new_fi = new_field_info(ptvc->tree, hfinfo, ptvc->tvb, offset,
+           item_length);
+       if (new_fi == NULL)
+               return NULL;
+
+       return proto_tree_new_item(new_fi, ptvc->tree, hfindex, ptvc->tvb,
+           offset, length, little_endian);
+}
+
+/* Add an item to a proto_tree, using the text label registered to that item;
+   the item is extracted from the tvbuff handed to it. */
+proto_item *
+proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+    gint start, gint length, gboolean little_endian)
+{
+       field_info      *new_fi;
+
+       if (!tree)
+               return(NULL);
+
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
+       new_fi = alloc_field_info(tree, hfindex, tvb, start, &length);
+
+       if (new_fi == NULL)
+               return(NULL);
+
+       return proto_tree_new_item(new_fi, tree, hfindex, tvb, start,
+           length, little_endian);
+}
+
 proto_item *
 proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb,
     gint start, gint length, gboolean little_endian)
@@ -906,7 +1133,7 @@ proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
                return (NULL);
 
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_NONE);
+       DISSECTOR_ASSERT(hfinfo->type == FT_NONE);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, NULL);
 
@@ -918,6 +1145,28 @@ proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
        return pi;
 }
 
+/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment
+ * offset, and returns proto_item* */
+proto_item*
+ptvcursor_add_no_advance(ptvcursor_t* ptvc, int hf, gint length,
+               gboolean endianness)
+{
+       proto_item      *item;
+
+       item = proto_tree_add_item(ptvc->tree, hf, ptvc->tvb, ptvc->offset,
+                       length, endianness);
+
+       return item;
+}
+
+/* Advance the ptvcursor's offset within its tvbuff without
+ * adding anything to the proto_tree. */
+void
+ptvcursor_advance(ptvcursor_t* ptvc, gint length)
+{
+       ptvc->offset += length;
+}
+
 
 static void
 proto_tree_set_protocol_tvb(field_info *fi, tvbuff_t *tvb)
@@ -939,7 +1188,7 @@ proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gin
                return (NULL);
 
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_PROTOCOL);
+       DISSECTOR_ASSERT(hfinfo->type == FT_PROTOCOL);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
 
@@ -969,8 +1218,10 @@ proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_BYTES);
+       DISSECTOR_ASSERT(hfinfo->type == FT_BYTES);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        proto_tree_set_bytes(new_fi, start_ptr, length);
@@ -993,6 +1244,25 @@ proto_tree_add_bytes_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s
        return pi;
 }
 
+proto_item *
+proto_tree_add_bytes_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, const guint8 *start_ptr,
+               const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_bytes(tree, hfindex, tvb, start, length, start_ptr);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_bytes_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
                gint length, const guint8 *start_ptr, const char *format, ...)
@@ -1042,8 +1312,10 @@ proto_tree_add_time(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_ABSOLUTE_TIME ||
+       DISSECTOR_ASSERT(hfinfo->type == FT_ABSOLUTE_TIME ||
                                hfinfo->type == FT_RELATIVE_TIME);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
@@ -1067,6 +1339,25 @@ proto_tree_add_time_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
        return pi;
 }
 
+proto_item *
+proto_tree_add_time_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, nstime_t *value_ptr,
+               const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_time(tree, hfindex, tvb, start, length, value_ptr);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_time_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                nstime_t *value_ptr, const char *format, ...)
@@ -1089,6 +1380,7 @@ proto_tree_add_time_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
 static void
 proto_tree_set_time(field_info *fi, nstime_t *value_ptr)
 {
+       DISSECTOR_ASSERT(value_ptr != NULL);
        fvalue_set(&fi->value, value_ptr, FALSE);
 }
 
@@ -1104,8 +1396,10 @@ proto_tree_add_ipxnet(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_IPXNET);
+       DISSECTOR_ASSERT(hfinfo->type == FT_IPXNET);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        proto_tree_set_ipxnet(new_fi, value);
@@ -1128,6 +1422,24 @@ proto_tree_add_ipxnet_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
        return pi;
 }
 
+proto_item *
+proto_tree_add_ipxnet_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, guint32 value, const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_ipxnet(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_ipxnet_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                guint32 value, const char *format, ...)
@@ -1165,8 +1477,10 @@ proto_tree_add_ipv4(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_IPv4);
+       DISSECTOR_ASSERT(hfinfo->type == FT_IPv4);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        proto_tree_set_ipv4(new_fi, value);
@@ -1189,6 +1503,24 @@ proto_tree_add_ipv4_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
        return pi;
 }
 
+proto_item *
+proto_tree_add_ipv4_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, guint32 value, const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_ipv4(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_ipv4_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                guint32 value, const char *format, ...)
@@ -1226,8 +1558,10 @@ proto_tree_add_ipv6(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_IPv6);
+       DISSECTOR_ASSERT(hfinfo->type == FT_IPv6);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        proto_tree_set_ipv6(new_fi, value_ptr);
@@ -1250,6 +1584,25 @@ proto_tree_add_ipv6_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
        return pi;
 }
 
+proto_item *
+proto_tree_add_ipv6_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, const guint8* value_ptr,
+               const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_ipv6(tree, hfindex, tvb, start, length, value_ptr);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_ipv6_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                const guint8* value_ptr, const char *format, ...)
@@ -1272,6 +1625,7 @@ proto_tree_add_ipv6_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
 static void
 proto_tree_set_ipv6(field_info *fi, const guint8* value_ptr)
 {
+       DISSECTOR_ASSERT(value_ptr != NULL);
        fvalue_set(&fi->value, (gpointer) value_ptr, FALSE);
 }
 
@@ -1281,28 +1635,10 @@ proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start)
        proto_tree_set_ipv6(fi, tvb_get_ptr(tvb, start, 16));
 }
 
-static void
-proto_tree_set_uint64(field_info *fi, guint64 value)
-{
-       fvalue_set_integer64(&fi->value, value);
-}
-
-static void
-proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian)
-{
-       guint64 value;
-
-       value = little_endian ? tvb_get_letoh64(tvb, start)
-                             : tvb_get_ntoh64(tvb, start);
-
-       proto_tree_set_uint64(fi, value);
-}
-
-/* Add a FT_STRING or FT_STRINGZ to a proto_tree. Creates own copy of string,
- * and frees it when the proto_tree is destroyed. */
+/* Add a FT_GUID to a proto_tree */
 proto_item *
-proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
-               gint length, const char* value)
+proto_tree_add_guid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
+               const e_guid_t *value_ptr)
 {
        proto_item              *pi;
        field_info              *new_fi;
@@ -1311,11 +1647,219 @@ proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_STRING || hfinfo->type == FT_STRINGZ);
+       DISSECTOR_ASSERT(hfinfo->type == FT_GUID);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
-       g_assert(length >= 0);
+       proto_tree_set_guid(new_fi, value_ptr);
+
+       return pi;
+}
+
+proto_item *
+proto_tree_add_guid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
+               const e_guid_t *value_ptr)
+{
+       proto_item              *pi;
+
+       pi = proto_tree_add_guid(tree, hfindex, tvb, start, length, value_ptr);
+       if (pi == NULL)
+               return (NULL);
+
+       PROTO_ITEM_SET_HIDDEN(pi);
+
+       return pi;
+}
+
+proto_item *
+proto_tree_add_guid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, const e_guid_t *value_ptr,
+               const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_guid(tree, hfindex, tvb, start, length, value_ptr);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
+proto_item *
+proto_tree_add_guid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
+               const e_guid_t *value_ptr, const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_guid(tree, hfindex, tvb, start, length, value_ptr);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
+/* Set the FT_GUID value */
+static void
+proto_tree_set_guid(field_info *fi, const e_guid_t *value_ptr)
+{
+       DISSECTOR_ASSERT(value_ptr != NULL);
+       fvalue_set(&fi->value, (gpointer) value_ptr, FALSE);
+}
+
+static void
+proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian)
+{
+       e_guid_t guid;
+
+       tvb_get_guid(tvb, start, &guid, little_endian);
+       proto_tree_set_guid(fi, &guid);
+}
+
+/* Add a FT_OID to a proto_tree */
+proto_item *
+proto_tree_add_oid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
+               const guint8* value_ptr)
+{
+       proto_item              *pi;
+       field_info              *new_fi;
+       header_field_info       *hfinfo;
+
+       if (!tree)
+               return (NULL);
+
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
+       PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
+       DISSECTOR_ASSERT(hfinfo->type == FT_OID);
+
+       pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
+       proto_tree_set_oid(new_fi, value_ptr, length);
+
+       return pi;
+}
+
+proto_item *
+proto_tree_add_oid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
+               const guint8* value_ptr)
+{
+       proto_item              *pi;
+
+       pi = proto_tree_add_oid(tree, hfindex, tvb, start, length, value_ptr);
+       if (pi == NULL)
+               return (NULL);
+
+       PROTO_ITEM_SET_HIDDEN(pi);
+
+       return pi;
+}
+
+proto_item *
+proto_tree_add_oid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, const guint8* value_ptr,
+               const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_oid(tree, hfindex, tvb, start, length, value_ptr);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
+proto_item *
+proto_tree_add_oid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
+               const guint8* value_ptr, const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_oid(tree, hfindex, tvb, start, length, value_ptr);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
+/* Set the FT_OID value */
+static void
+proto_tree_set_oid(field_info *fi, const guint8* value_ptr, gint length)
+{
+       GByteArray              *bytes;
+
+       DISSECTOR_ASSERT(value_ptr != NULL);
+
+       bytes = g_byte_array_new();
+       if (length > 0) {
+               g_byte_array_append(bytes, value_ptr, length);
+       }
+       fvalue_set(&fi->value, bytes, TRUE);
+}
+
+static void
+proto_tree_set_oid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length)
+{
+       proto_tree_set_oid(fi, tvb_get_ptr(tvb, start, length), length);
+}
+
+static void
+proto_tree_set_uint64(field_info *fi, guint64 value)
+{
+       fvalue_set_integer64(&fi->value, value);
+}
+
+static void
+proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian)
+{
+       guint64 value;
+
+       value = little_endian ? tvb_get_letoh64(tvb, start)
+                             : tvb_get_ntoh64(tvb, start);
+
+       proto_tree_set_uint64(fi, value);
+}
+
+/* Add a FT_STRING or FT_STRINGZ to a proto_tree. Creates own copy of string,
+ * and frees it when the proto_tree is destroyed. */
+proto_item *
+proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
+               gint length, const char* value)
+{
+       proto_item              *pi;
+       field_info              *new_fi;
+       header_field_info       *hfinfo;
+
+       if (!tree)
+               return (NULL);
+
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
+       PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
+       DISSECTOR_ASSERT(hfinfo->type == FT_STRING || hfinfo->type == FT_STRINGZ);
+
+       pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
+       DISSECTOR_ASSERT(length >= 0);
        proto_tree_set_string(new_fi, value, FALSE);
 
        return pi;
@@ -1336,6 +1880,25 @@ proto_tree_add_string_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
        return pi;
 }
 
+proto_item *
+proto_tree_add_string_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, const char* value, const char *format,
+               ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_string(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_string_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
                gint length, const char* value, const char *format, ...)
@@ -1358,6 +1921,18 @@ proto_tree_add_string_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
  * field info update instead of only updating the representation as does
  * proto_item_append_text()
  */
+/* NOTE: this function will break with the TRY_TO_FAKE_THIS_ITEM()
+ * speed optimization.
+ * Currently only WSP use this function so it is not that bad but try to
+ * avoid using this one if possible.
+ * IF you must use this function you MUST also disable the
+ * TRY_TO_FAKE_THIS_ITEM() optimization for your dissector/function
+ * using proto_item_append_string().
+ * Do that by faking that the tree is visible by setting :
+ *   PTREE_DATA(tree)->visible=1;  (see packet-wsp.c)
+ * BEFORE you create the item you are later going to use
+ * proto_item_append_string() on.
+ */
 void
 proto_item_append_string(proto_item *pi, const char *str)
 {
@@ -1372,10 +1947,13 @@ proto_item_append_string(proto_item *pi, const char *str)
 
        fi = PITEM_FINFO(pi);
        hfinfo = fi->hfinfo;
-       g_assert(hfinfo->type == FT_STRING || hfinfo->type == FT_STRINGZ);
+       if (hfinfo->type == FT_PROTOCOL) {
+               /* TRY_TO_FAKE_THIS_ITEM() speed optimization: silently skip */
+               return;
+       }
+       DISSECTOR_ASSERT(hfinfo->type == FT_STRING || hfinfo->type == FT_STRINGZ);
        old_str = fvalue_get(&fi->value);
-       new_str = g_malloc(strlen(old_str) + strlen(str) + 1);
-       sprintf(new_str, "%s%s", old_str, str);
+       new_str = g_strdup_printf("%s%s", old_str, str);
        fvalue_set(&fi->value, new_str, TRUE);
 }
 
@@ -1384,7 +1962,10 @@ static void
 proto_tree_set_string(field_info *fi, const char* value,
                gboolean already_allocated)
 {
-       fvalue_set(&fi->value, (gpointer) value, already_allocated);
+       if (value)
+               fvalue_set(&fi->value, (gpointer) value, already_allocated);
+       else
+               fvalue_set(&fi->value, (gpointer) "[ Null ]", already_allocated);
 }
 
 static void
@@ -1413,8 +1994,10 @@ proto_tree_add_ether(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, g
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_ETHER);
+       DISSECTOR_ASSERT(hfinfo->type == FT_ETHER);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        proto_tree_set_ether(new_fi, value);
@@ -1437,6 +2020,25 @@ proto_tree_add_ether_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s
        return pi;
 }
 
+proto_item *
+proto_tree_add_ether_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, const guint8* value,
+               const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_ether(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_ether_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                const guint8* value, const char *format, ...)
@@ -1480,8 +2082,10 @@ proto_tree_add_boolean(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_BOOLEAN);
+       DISSECTOR_ASSERT(hfinfo->type == FT_BOOLEAN);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        proto_tree_set_boolean(new_fi, value);
@@ -1504,6 +2108,25 @@ proto_tree_add_boolean_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
        return pi;
 }
 
+proto_item *
+proto_tree_add_boolean_format_value(proto_tree *tree, int hfindex,
+               tvbuff_t *tvb, gint start, gint length, guint32 value,
+               const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_boolean(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_boolean_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                guint32 value, const char *format, ...)
@@ -1541,8 +2164,10 @@ proto_tree_add_float(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, g
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_FLOAT);
+       DISSECTOR_ASSERT(hfinfo->type == FT_FLOAT);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        proto_tree_set_float(new_fi, value);
@@ -1565,6 +2190,24 @@ proto_tree_add_float_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s
        return pi;
 }
 
+proto_item *
+proto_tree_add_float_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, float value, const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_float(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_float_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                float value, const char *format, ...)
@@ -1602,8 +2245,10 @@ proto_tree_add_double(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_DOUBLE);
+       DISSECTOR_ASSERT(hfinfo->type == FT_DOUBLE);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        proto_tree_set_double(new_fi, value);
@@ -1626,6 +2271,24 @@ proto_tree_add_double_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
        return pi;
 }
 
+proto_item *
+proto_tree_add_double_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, double value, const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_double(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_double_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                double value, const char *format, ...)
@@ -1663,6 +2326,8 @@ proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
        switch(hfinfo->type) {
                case FT_UINT8:
@@ -1676,7 +2341,7 @@ proto_tree_add_uint(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi
                        break;
 
                default:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
        }
 
        return pi;
@@ -1697,6 +2362,24 @@ proto_tree_add_uint_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
        return pi;
 }
 
+proto_item *
+proto_tree_add_uint_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, guint32 value, const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_uint(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_uint_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                guint32 value, const char *format, ...)
@@ -1749,8 +2432,10 @@ proto_tree_add_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_UINT64);
+       DISSECTOR_ASSERT(hfinfo->type == FT_UINT64);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        proto_tree_set_uint64(new_fi, value);
@@ -1758,6 +2443,24 @@ proto_tree_add_uint64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        return pi;
 }
 
+proto_item *
+proto_tree_add_uint64_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, guint64 value, const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_uint64(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_uint64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                guint64 value, const char *format, ...)
@@ -1788,6 +2491,8 @@ proto_tree_add_int(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gin
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
        switch(hfinfo->type) {
                case FT_INT8:
@@ -1800,7 +2505,7 @@ proto_tree_add_int(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gin
                        break;
 
                default:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
        }
 
        return pi;
@@ -1821,6 +2526,24 @@ proto_tree_add_int_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint sta
        return pi;
 }
 
+proto_item *
+proto_tree_add_int_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, gint32 value, const char *format, ...)
+{
+       proto_item              *pi = NULL;
+       va_list                 ap;
+
+       pi = proto_tree_add_int(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_int_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                gint32 value, const char *format, ...)
@@ -1873,8 +2596,10 @@ proto_tree_add_int64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, g
        if (!tree)
                return (NULL);
 
+       TRY_TO_FAKE_THIS_ITEM(tree, hfindex);
+
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
-       g_assert(hfinfo->type == FT_INT64);
+       DISSECTOR_ASSERT(hfinfo->type == FT_INT64);
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        proto_tree_set_uint64(new_fi, (guint64)value);
@@ -1882,6 +2607,24 @@ proto_tree_add_int64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, g
        return pi;
 }
 
+proto_item *
+proto_tree_add_int64_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+               gint start, gint length, gint64 value, const char *format, ...)
+{
+       proto_item              *pi;
+       va_list                 ap;
+
+       pi = proto_tree_add_int64(tree, hfindex, tvb, start, length, value);
+       if (pi == NULL)
+               return (NULL);
+
+       va_start(ap, format);
+       proto_tree_set_representation_value(pi, format, ap);
+       va_end(ap);
+
+       return pi;
+}
+
 proto_item *
 proto_tree_add_int64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
                gint64 value, const char *format, ...)
@@ -1900,7 +2643,9 @@ proto_tree_add_int64_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s
        return pi;
 }
 
-
+/* Throw an exception if we exceed this many tree items. */
+/* XXX - This should probably be a preference */
+#define MAX_TREE_ITEMS (1 * 1000 * 1000)
 /* Add a field_info struct to the proto_tree, encapsulating it in a proto_node */
 static proto_item *
 proto_tree_add_node(proto_tree *tree, field_info *fi)
@@ -1919,9 +2664,23 @@ proto_tree_add_node(proto_tree *tree, field_info *fi)
         */
        tnode = tree;
        tfi = tnode->finfo;
-       g_assert(tfi == NULL ||
+       if (tfi != NULL && (tfi->tree_type < 0 || tfi->tree_type >= num_tree_types)) {
+               REPORT_DISSECTOR_BUG(ep_strdup_printf("\"%s\" - \"%s\" tfi->tree_type: %u invalid (%s:%u)",
+                       fi->hfinfo->name, fi->hfinfo->abbrev, tfi->tree_type, __FILE__, __LINE__));
+               /* XXX - is it safe to continue here? */
+       }
+
+       DISSECTOR_ASSERT(tfi == NULL ||
            (tfi->tree_type >= 0 && tfi->tree_type < num_tree_types));
 
+       PTREE_DATA(tree)->count++;
+       if (PTREE_DATA(tree)->count > MAX_TREE_ITEMS) {
+               /* Let the exception handler add items to the tree */
+               PTREE_DATA(tree)->count = 0;
+               THROW_MESSAGE(DissectorError,
+                       ep_strdup_printf("More than %d items in the tree -- possible infinite loop", MAX_TREE_ITEMS));
+       }
+
        PROTO_NODE_NEW(pnode);
        pnode->parent = tnode;
        pnode->finfo = fi;
@@ -1929,7 +2688,7 @@ proto_tree_add_node(proto_tree *tree, field_info *fi)
 
        if (tnode->last_child != NULL) {
                sibling = tnode->last_child;
-               g_assert(sibling->next == NULL);
+               DISSECTOR_ASSERT(sibling->next == NULL);
                sibling->next = pnode;
        } else
                tnode->first_child = pnode;
@@ -1959,10 +2718,13 @@ proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
 
        /* If the proto_tree wants to keep a record of this finfo
         * for quick lookup, then record it. */
-       hash = PTREE_DATA(tree)->interesting_hfids;
-       ptrs = g_hash_table_lookup(hash, GINT_TO_POINTER(hfindex));
-       if (ptrs) {
-               g_ptr_array_add(ptrs, fi);
+       if (fi->hfinfo->ref_count) {
+               /*HERE*/
+               hash = PTREE_DATA(tree)->interesting_hfids;
+               ptrs = g_hash_table_lookup(hash, GINT_TO_POINTER(hfindex));
+               if (ptrs) {
+                       g_ptr_array_add(ptrs, fi);
+               }
        }
 
        /* Does the caller want to know the fi pointer? */
@@ -1973,21 +2735,30 @@ proto_tree_add_pi(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        return pi;
 }
 
-static field_info *
-alloc_field_info(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
-    gint *length)
+
+static header_field_info *
+get_hfi_and_length(int hfindex, tvbuff_t *tvb, gint start, gint *length,
+    gint *item_length)
 {
        header_field_info       *hfinfo;
-       field_info              *fi;
+       gint                    length_remaining;
 
        /*
         * We only allow a null tvbuff if the item has a zero length,
         * i.e. if there's no data backing it.
         */
-       g_assert(tvb != NULL || *length == 0);
+       DISSECTOR_ASSERT(tvb != NULL || *length == 0);
 
        PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo);
 
+       /*
+        * XXX - in some protocols, there are 32-bit unsigned length
+        * fields, so lengths in protocol tree and tvbuff routines
+        * should really be unsigned.  We should have, for those
+        * field types for which "to the end of the tvbuff" makes sense,
+        * additional routines that take no length argument and
+        * add fields that run to the end of the tvbuff.
+        */
        if (*length == -1) {
                /*
                 * For FT_NONE, FT_PROTOCOL, FT_BYTES, and FT_STRING fields,
@@ -2048,14 +2819,14 @@ alloc_field_info(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
                                 */
                                tvb_ensure_bytes_exist(tvb, start, 0);
                        }
-                       g_assert(*length >= 0);
+                       DISSECTOR_ASSERT(*length >= 0);
                        break;
 
                case FT_NONE:
                case FT_BYTES:
                case FT_STRING:
                        *length = tvb_ensure_length_remaining(tvb, start);
-                       g_assert(*length >= 0);
+                       DISSECTOR_ASSERT(*length >= 0);
                        break;
 
                case FT_STRINGZ:
@@ -2066,17 +2837,51 @@ alloc_field_info(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
                        break;
 
                default:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                }
-       } else
-               g_assert(*length >= 0);
+               *item_length = *length;
+       } else {
+               *item_length = *length;
+               if (hfinfo->type == FT_PROTOCOL || hfinfo->type == FT_NONE) {
+                       /*
+                        * These types are for interior nodes of the
+                        * tree, and don't have data associated with
+                        * them; if the length is negative (XXX - see
+                        * above) or goes past the end of the tvbuff,
+                        * cut it short at the end of the tvbuff.
+                        * That way, if this field is selected in
+                        * Wireshark, we don't highlight stuff past
+                        * the end of the data.
+                        */
+                       /* XXX - what to do, if we don't have a tvb? */
+                       if (tvb) {
+                               length_remaining = tvb_length_remaining(tvb, start);
+                               if (*item_length < 0 ||
+                                   (*item_length > 0 &&
+                                     (length_remaining < *item_length)))
+                                       *item_length = length_remaining;
+                       }
+               }
+               if (*item_length < 0) {
+                       THROW(ReportedBoundsError);
+               }
+       }
+
+       return hfinfo;
+}
+
+static field_info *
+new_field_info(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb,
+    gint start, gint item_length)
+{
+       field_info              *fi;
 
        FIELD_INFO_NEW(fi);
 
        fi->hfinfo = hfinfo;
        fi->start = start;
        fi->start+=(tvb)?TVB_RAW_OFFSET(tvb):0;
-       fi->length = *length;
+       fi->length = item_length;
        fi->tree_type = -1;
        fi->flags = 0;
        if (!PTREE_DATA(tree)->visible)
@@ -2090,8 +2895,49 @@ alloc_field_info(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
        return fi;
 }
 
-/* Set representation of a proto_tree entry, if the protocol tree is to
-   be visible. */
+static field_info *
+alloc_field_info(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
+    gint *length)
+{
+       header_field_info       *hfinfo;
+       gint                    item_length;
+
+       hfinfo = get_hfi_and_length(hfindex, tvb, start, length, &item_length);
+       return new_field_info(tree, hfinfo, tvb, start, item_length);
+}
+
+/* If the protocol tree is to be visible, set the representation of a
+   proto_tree entry with the name of the field for the item and with
+   the value formatted with the supplied printf-style format and
+   argument list. */
+static void
+proto_tree_set_representation_value(proto_item *pi, const char *format, va_list ap)
+{
+       int     ret;    /*tmp return value */
+       int     replen;
+       field_info *fi = PITEM_FINFO(pi);
+
+       if (!PROTO_ITEM_IS_HIDDEN(pi)) {
+               ITEM_LABEL_NEW(fi->rep);
+               replen = 0;
+               ret = g_snprintf(fi->rep->representation, ITEM_LABEL_LENGTH,
+                   "%s: ", fi->hfinfo->name);
+               if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH)) {
+                       /* That's all we can put in the representation. */
+                       fi->rep->representation[ITEM_LABEL_LENGTH - 1] = '\0';
+                       return;
+               }
+               replen = ret;
+               ret = g_vsnprintf(fi->rep->representation + replen,
+                   ITEM_LABEL_LENGTH - replen, format, ap);
+               if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH - replen))
+                       fi->rep->representation[ITEM_LABEL_LENGTH - 1] = '\0';
+       }
+}
+
+/* If the protocol tree is to be visible, set the representation of a
+   proto_tree entry with the representation formatted with the supplied
+   printf-style format and argument list. */
 static void
 proto_tree_set_representation(proto_item *pi, const char *format, va_list ap)
 {
@@ -2100,7 +2946,7 @@ proto_tree_set_representation(proto_item *pi, const char *format, va_list ap)
 
        if (!PROTO_ITEM_IS_HIDDEN(pi)) {
                ITEM_LABEL_NEW(fi->rep);
-               ret = vsnprintf(fi->rep->representation, ITEM_LABEL_LENGTH, format, ap);
+               ret = g_vsnprintf(fi->rep->representation, ITEM_LABEL_LENGTH, format, ap);
                if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                        fi->rep->representation[ITEM_LABEL_LENGTH - 1] = '\0';
        }
@@ -2143,7 +2989,7 @@ proto_item_append_text(proto_item *pi, const char *format, ...)
 
        fi = PITEM_FINFO(pi);
 
-    if (!PROTO_ITEM_IS_HIDDEN(pi)) {
+       if (!PROTO_ITEM_IS_HIDDEN(pi)) {
                va_start(ap, format);
 
                /*
@@ -2157,7 +3003,7 @@ proto_item_append_text(proto_item *pi, const char *format, ...)
 
                curlen = strlen(fi->rep->representation);
                if (ITEM_LABEL_LENGTH > curlen) {
-                       ret = vsnprintf(fi->rep->representation + curlen,
+                       ret = g_vsnprintf(fi->rep->representation + curlen,
                            ITEM_LABEL_LENGTH - curlen, format, ap);
                        if ((ret == -1) || (ret >= (int)(ITEM_LABEL_LENGTH - curlen)))
                                fi->rep->representation[ITEM_LABEL_LENGTH - 1] = '\0';
@@ -2174,7 +3020,7 @@ proto_item_set_len(proto_item *pi, gint length)
        if (pi == NULL)
                return;
        fi = PITEM_FINFO(pi);
-       g_assert(length >= 0);
+       DISSECTOR_ASSERT(length >= 0);
        fi->length = length;
 }
 
@@ -2194,7 +3040,7 @@ proto_item_set_end(proto_item *pi, tvbuff_t *tvb, gint end)
                return;
        fi = PITEM_FINFO(pi);
        end += TVB_RAW_OFFSET(tvb);
-       g_assert(end >= fi->start);
+       DISSECTOR_ASSERT(end >= fi->start);
        fi->length = end - fi->start;
 }
 
@@ -2205,6 +3051,32 @@ proto_item_get_len(proto_item *pi)
        return fi->length;
 }
 
+
+/** clear flags according to the mask and set new flag values */
+#define FI_REPLACE_FLAGS(fi, mask, flags_in) { \
+       (fi->flags = (fi)->flags & ~(mask)); \
+       (fi->flags = (fi)->flags | (flags_in)); \
+}
+
+gboolean
+proto_item_set_expert_flags(proto_item *pi, int group, int severity)
+{
+       if(pi == NULL || pi->finfo == NULL)
+               return FALSE;
+
+       /* only change things if severity is worse or at least equal than before */
+       if(severity >= FI_GET_FLAG(pi->finfo, PI_SEVERITY_MASK)) {
+               FI_REPLACE_FLAGS(pi->finfo, PI_GROUP_MASK, group);
+               FI_REPLACE_FLAGS(pi->finfo, PI_SEVERITY_MASK, severity);
+
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+
+
 proto_tree*
 proto_tree_create_root(void)
 {
@@ -2226,6 +3098,9 @@ proto_tree_create_root(void)
         * changed, then we'll find out very quickly. */
        pnode->tree_data->visible = FALSE;
 
+       /* Keep track of the number of children */
+       pnode->tree_data->count = 0;
+
        return (proto_tree*) pnode;
 }
 
@@ -2235,10 +3110,26 @@ proto_tree_create_root(void)
 void
 proto_tree_prime_hfid(proto_tree *tree, gint hfid)
 {
+       header_field_info *hfinfo;
+
        g_hash_table_insert(PTREE_DATA(tree)->interesting_hfids,
                GINT_TO_POINTER(hfid), g_ptr_array_new());
-}
 
+       PROTO_REGISTRAR_GET_NTH(hfid, hfinfo);
+       /* this field is referenced by a filter so increase the refcount.
+          also increase the refcount for the parent, i.e the protocol.
+       */
+       hfinfo->ref_count++;
+       /* only increase the refcount if there is a parent.
+          if this is a protocol and not a field then parent will be -1
+          and there is no parent to add any refcounting for.
+       */
+       if (hfinfo->parent != -1) {
+               header_field_info *parent_hfinfo;
+               PROTO_REGISTRAR_GET_NTH(hfinfo->parent, parent_hfinfo);
+               parent_hfinfo->ref_count++;
+       }
+}
 
 proto_tree*
 proto_item_add_subtree(proto_item *pi,  gint idx) {
@@ -2248,8 +3139,9 @@ proto_item_add_subtree(proto_item *pi,  gint idx) {
                return(NULL);
 
        fi = PITEM_FINFO(pi);
-       g_assert(idx >= 0 && idx < num_tree_types);
+       DISSECTOR_ASSERT(idx >= 0 && idx < num_tree_types);
        fi->tree_type = idx;
+
        return (proto_tree*) pi;
 }
 
@@ -2260,21 +3152,23 @@ proto_item_get_subtree(proto_item *pi) {
        if (!pi)
                return(NULL);
        fi = PITEM_FINFO(pi);
-       if (fi->tree_type == -1)
+       if ( (!fi) || (fi->tree_type == -1) )
                return(NULL);
        return (proto_tree*) pi;
 }
 
 proto_item*
 proto_item_get_parent(proto_item *ti) {
-       if (!ti)
+       /* dont bother if tree is not visible */
+       if( (!ti) || (!(PTREE_DATA(ti)->visible)) )
                return (NULL);
        return ti->parent;
 }
 
 proto_item*
 proto_item_get_parent_nth(proto_item *ti, int gen) {
-       if (!ti)
+       /* dont bother if tree is not visible */
+       if( (!ti) || (!(PTREE_DATA(ti)->visible)) )
                return (NULL);
        while (gen--) {
                ti = ti->parent;
@@ -2285,92 +3179,159 @@ proto_item_get_parent_nth(proto_item *ti, int gen) {
 }
 
 
-proto_item* 
+proto_item*
 proto_tree_get_parent(proto_tree *tree) {
-       if (!tree)
+       /* dont bother if tree is not visible */
+       if( (!tree) || (!(PTREE_DATA(tree)->visible)) )
                return (NULL);
        return (proto_item*) tree;
 }
 
-static gint
-proto_match_short_name(gconstpointer p_arg, gconstpointer name_arg)
-{
-       const protocol_t *p = p_arg;
-       const char *name = name_arg;
-
-       return g_strcasecmp(p->short_name, name);
+proto_tree*
+proto_tree_get_root(proto_tree *tree) {
+       /* dont bother if tree is not visible */
+       if( (!tree) || (!(PTREE_DATA(tree)->visible)) )
+               return (NULL);
+       while (tree->parent) {
+               tree = tree->parent;
+       }
+       return tree;
 }
 
-static gint
-proto_match_name(gconstpointer p_arg, gconstpointer name_arg)
+void
+proto_tree_move_item(proto_tree *tree, proto_item *fixed_item, proto_item *item_to_move)
 {
-       const protocol_t *p = p_arg;
-       const char *name = name_arg;
+    proto_item *curr_item;
 
-       return g_strcasecmp(p->name, name);
-}
 
-static gint
-proto_match_filter_name(gconstpointer p_arg, gconstpointer name_arg)
-{
-       const protocol_t *p = p_arg;
-       const char *name = name_arg;
+    /*** cut item_to_move out ***/
 
-       return g_strcasecmp(p->filter_name, name);
-}
+    /* is item_to_move the first? */
+    if(tree->first_child == item_to_move) {
+        /* simply change first child to next */
+        tree->first_child = item_to_move->next;
+    } else {
+        /* find previous and change it's next */
+        for(curr_item = tree->first_child; curr_item != NULL; curr_item = curr_item->next) {
+            if(curr_item->next == item_to_move) {
+                break;
+            }
+        }
 
-static gint
-proto_compare_name(gconstpointer p1_arg, gconstpointer p2_arg)
-{
-       const protocol_t *p1 = p1_arg;
-       const protocol_t *p2 = p2_arg;
+        DISSECTOR_ASSERT(curr_item);
 
-       return g_strcasecmp(p1->short_name, p2->short_name);
+        curr_item->next = item_to_move->next;
+
+        /* fix last_child if required */
+        if(tree->last_child == item_to_move) {
+            tree->last_child = curr_item;
+        }
+    }
+
+    /*** insert to_move after fixed ***/
+    item_to_move->next = fixed_item->next;
+    fixed_item->next = item_to_move;
+    if(tree->last_child == fixed_item) {
+        tree->last_child = item_to_move;
+    }
 }
 
-int
-proto_register_protocol(char *name, char *short_name, char *filter_name)
-{
-       protocol_t *protocol;
-       header_field_info *hfinfo;
-       int proto_id;
 
-       /*
-        * Make sure there's not already a protocol with any of those
-        * names.  Crash if there is, as that's an error in the code,
-        * and the code has to be fixed not to register more than one
-        * protocol with the same name.
-        */
-       g_assert(g_list_find_custom(protocols, name, proto_match_name) == NULL);
-       g_assert(g_list_find_custom(protocols, short_name, proto_match_short_name) == NULL);
-       g_assert(g_list_find_custom(protocols, filter_name, proto_match_filter_name) == NULL);
-
-       /* Add this protocol to the list of known protocols; the list
-          is sorted by protocol short name. */
-       protocol = g_malloc(sizeof (protocol_t));
-       protocol->name = name;
-       protocol->short_name = short_name;
-       protocol->filter_name = filter_name;
-       protocol->fields = NULL;
-       protocol->is_enabled = TRUE; /* protocol is enabled by default */
-       protocol->can_toggle = TRUE;
-       protocols = g_list_insert_sorted(protocols, protocol,
-           proto_compare_name);
-
-       /* Here we do allocate a new header_field_info struct */
-       hfinfo = g_mem_chunk_alloc(gmc_hfinfo);
-       hfinfo->name = name;
-       hfinfo->abbrev = filter_name;
-       hfinfo->type = FT_PROTOCOL;
-       hfinfo->strings = NULL;
-       hfinfo->bitmask = 0;
-       hfinfo->bitshift = 0;
-       hfinfo->blurb = "";
-       hfinfo->parent = -1; /* this field differentiates protos and fields */
-
-       proto_id = proto_register_field_init(hfinfo, hfinfo->parent);
-       protocol->proto_id = proto_id;
-       return proto_id;
+int
+proto_register_protocol(const char *name, const char *short_name, const char *filter_name)
+{
+    protocol_t *protocol;
+    header_field_info *hfinfo;
+    int proto_id;
+    char *existing_name;
+    gint *key;
+    guint i;
+    guchar c;
+    gboolean found_invalid;
+
+    /*
+     * Make sure there's not already a protocol with any of those
+     * names.  Crash if there is, as that's an error in the code
+     * or an inappropriate plugin.
+     * This situation has to be fixed to not register more than one
+     * protocol with the same name.
+     *
+     * This is done by reducing the number of strcmp (and alike) calls as much as possible,
+     * as this significally slows down startup time.
+     *
+     * Drawback: As a hash value is used to reduce insert time,
+     * this might lead to a hash collision.
+     * However, as we have around 500+ protocols and we're using a 32 bit int this is very,
+     * very unlikely.
+     */
+
+    key = g_malloc (sizeof(gint));
+    *key = g_str_hash(name);
+    existing_name = g_hash_table_lookup(proto_names, key);
+    if (existing_name != NULL) {
+        /* g_error will terminate the program */
+        g_error("Duplicate protocol name \"%s\"!"
+            " This might be caused by an inappropriate plugin or a development error.", name);
+    }
+    g_hash_table_insert(proto_names, key, (gpointer)name);
+
+    key = g_malloc (sizeof(gint));
+    *key = g_str_hash(short_name);
+    existing_name = g_hash_table_lookup(proto_short_names, key);
+    if (existing_name != NULL) {
+        g_error("Duplicate protocol short_name \"%s\"!"
+            " This might be caused by an inappropriate plugin or a development error.", short_name);
+    }
+    g_hash_table_insert(proto_short_names, key, (gpointer)short_name);
+
+    found_invalid = FALSE;
+    for (i = 0; i < strlen(filter_name); i++) {
+        c = filter_name[i];
+        if (!(islower(c) || isdigit(c) || c == '-' || c == '_' || c == '.')) {
+            found_invalid = TRUE;
+        }
+    }
+    if (found_invalid) {
+        g_error("Protocol filter name \"%s\" has one or more invalid characters."
+            " Allowed are lower characters, digits, '-', '_' and '.'."
+            " This might be caused by an inappropriate plugin or a development error.", filter_name);
+    }
+    key = g_malloc (sizeof(gint));
+    *key = g_str_hash(filter_name);
+    existing_name = g_hash_table_lookup(proto_filter_names, key);
+    if (existing_name != NULL) {
+        g_error("Duplicate protocol filter_name \"%s\"!"
+            " This might be caused by an inappropriate plugin or a development error.", filter_name);
+    }
+    g_hash_table_insert(proto_filter_names, key, (gpointer)filter_name);
+
+    /* Add this protocol to the list of known protocols; the list
+       is sorted by protocol short name. */
+    protocol = g_malloc(sizeof (protocol_t));
+    protocol->name = name;
+    protocol->short_name = short_name;
+    protocol->filter_name = filter_name;
+    protocol->fields = NULL;
+    protocol->is_enabled = TRUE; /* protocol is enabled by default */
+    protocol->can_toggle = TRUE;
+    /* list will be sorted later by name, when all protocols completed registering */
+    protocols = g_list_append(protocols, protocol);
+
+    /* Here we do allocate a new header_field_info struct */
+    hfinfo = g_mem_chunk_alloc(gmc_hfinfo);
+    hfinfo->name = name;
+    hfinfo->abbrev = filter_name;
+    hfinfo->type = FT_PROTOCOL;
+    hfinfo->strings = protocol;
+    hfinfo->bitmask = 0;
+    hfinfo->bitshift = 0;
+    hfinfo->ref_count = 0;
+    hfinfo->blurb = NULL;
+    hfinfo->parent = -1; /* this field differentiates protos and fields */
+
+    proto_id = proto_register_field_init(hfinfo, hfinfo->parent);
+    protocol->proto_id = proto_id;
+    return proto_id;
 }
 
 /*
@@ -2435,27 +3396,17 @@ proto_get_next_protocol_field(void **cookie)
        return &ptr->hfinfo;
 }
 
-/*
- * Find the protocol list entry for a protocol given its field ID.
- */
-static gint
-compare_proto_id(gconstpointer proto_arg, gconstpointer id_arg)
-{
-       const protocol_t *protocol = proto_arg;
-       const int *id_ptr = id_arg;
-
-       return (protocol->proto_id == *id_ptr) ? 0 : 1;
-}
-
 protocol_t *
 find_protocol_by_id(int proto_id)
 {
-       GList *list_entry;
+       header_field_info *hfinfo;
 
-       list_entry = g_list_find_custom(protocols, &proto_id, compare_proto_id);
-       if (list_entry == NULL)
+       if(proto_id<0)
                return NULL;
-       return list_entry->data;
+
+       PROTO_REGISTRAR_GET_NTH(proto_id, hfinfo);
+       DISSECTOR_ASSERT(hfinfo->type==FT_PROTOCOL);
+       return (protocol_t *)hfinfo->strings;
 }
 
 static gint compare_filter_name(gconstpointer proto_arg,
@@ -2473,7 +3424,7 @@ proto_get_id(protocol_t *protocol)
        return protocol->proto_id;
 }
 
-int proto_get_id_by_filter_name(gchar* filter_name)
+int proto_get_id_by_filter_name(const gchar* filter_name)
 {
        GList *list_entry;
        protocol_t *protocol;
@@ -2486,7 +3437,7 @@ int proto_get_id_by_filter_name(gchar* filter_name)
        return protocol->proto_id;
 }
 
-char *
+const char *
 proto_get_protocol_name(int proto_id)
 {
        protocol_t *protocol;
@@ -2495,7 +3446,7 @@ proto_get_protocol_name(int proto_id)
        return protocol->name;
 }
 
-char *
+const char *
 proto_get_protocol_short_name(protocol_t *protocol)
 {
        if (protocol == NULL)
@@ -2503,7 +3454,7 @@ proto_get_protocol_short_name(protocol_t *protocol)
        return protocol->short_name;
 }
 
-char *
+const char *
 proto_get_protocol_filter_name(int proto_id)
 {
        protocol_t *protocol;
@@ -2533,7 +3484,7 @@ proto_set_decoding(int proto_id, gboolean enabled)
        protocol_t *protocol;
 
        protocol = find_protocol_by_id(proto_id);
-       g_assert(protocol->can_toggle);
+       DISSECTOR_ASSERT(protocol->can_toggle);
        protocol->is_enabled = enabled;
 }
 
@@ -2565,7 +3516,12 @@ proto_register_field_array(int parent, hf_register_info *hf, int num_records)
                 * 0 (which is unlikely to be the field ID we get back
                 * from "proto_register_field_init()").
                 */
-               g_assert(*ptr->p_id == -1 || *ptr->p_id == 0);
+               if (*ptr->p_id != -1 && *ptr->p_id != 0) {
+                       fprintf(stderr,
+                           "Duplicate field detected in call to proto_register_field_array: %s is already registered\n",
+                           ptr->hfinfo.abbrev);
+                       return;
+               }
 
                if (proto != NULL) {
                        if (proto->fields == NULL) {
@@ -2585,11 +3541,11 @@ static int
 proto_register_field_init(header_field_info *hfinfo, int parent)
 {
        /* The field must have names */
-       g_assert(hfinfo->name);
-       g_assert(hfinfo->abbrev);
+       DISSECTOR_ASSERT(hfinfo->name);
+       DISSECTOR_ASSERT(hfinfo->abbrev);
 
-       /* These types of fields are allowed to have value_strings or true_false_strings */
-       g_assert((hfinfo->strings == NULL) || (
+       /* These types of fields are allowed to have value_strings, true_false_strings or a protocol_t struct*/
+       DISSECTOR_ASSERT((hfinfo->strings == NULL) || (
                        (hfinfo->type == FT_UINT8) ||
                        (hfinfo->type == FT_UINT16) ||
                        (hfinfo->type == FT_UINT24) ||
@@ -2599,6 +3555,7 @@ proto_register_field_init(header_field_info *hfinfo, int parent)
                        (hfinfo->type == FT_INT24) ||
                        (hfinfo->type == FT_INT32) ||
                        (hfinfo->type == FT_BOOLEAN) ||
+                       (hfinfo->type == FT_PROTOCOL) ||
                        (hfinfo->type == FT_FRAMENUM) ));
 
        switch (hfinfo->type) {
@@ -2613,13 +3570,13 @@ proto_register_field_init(header_field_info *hfinfo, int parent)
        case FT_INT32:
                /* Require integral types (other than frame number, which is
                   always displayed in decimal) to have a number base */
-               g_assert(hfinfo->display != BASE_NONE);
+               DISSECTOR_ASSERT(hfinfo->display != BASE_NONE);
                break;
 
        case FT_FRAMENUM:
                /* Don't allow bitfields or value strings for frame numbers */
-               g_assert(hfinfo->bitmask == 0);
-               g_assert(hfinfo->strings == NULL);
+               DISSECTOR_ASSERT(hfinfo->bitmask == 0);
+               DISSECTOR_ASSERT(hfinfo->strings == NULL);
                break;
 
        default:
@@ -2653,15 +3610,18 @@ proto_register_field_init(header_field_info *hfinfo, int parent)
        if ((hfinfo->name[0] != 0) && (hfinfo->abbrev[0] != 0 )) {
 
                header_field_info *same_name_hfinfo, *same_name_next_hfinfo;
-               char *p;
+               const char *p;
                guchar c;
 
                /* Check that the filter name (abbreviation) is legal;
                 * it must contain only alphanumerics, '-', "_", and ".". */
-               for (p = hfinfo->abbrev; (c = *p) != '\0'; p++)
-                       g_assert(isalnum(c) || c == '-' || c == '_' ||
-                           c == '.');
-
+               for (p = hfinfo->abbrev; (c = *p) != '\0'; p++) {
+                       if (!(isalnum(c) || c == '-' || c == '_' || c == '.')) {
+                               fprintf(stderr, "OOPS: '%c' in '%s'\n", c, hfinfo->abbrev);
+                               DISSECTOR_ASSERT(isalnum(c) || c == '-' || c == '_' ||
+                                       c == '.');
+                       }
+               }
                /* We allow multiple hfinfo's to be registered under the same
                 * abbreviation. This was done for X.25, as, depending
                 * on whether it's modulo-8 or modulo-128 operation,
@@ -2688,27 +3648,36 @@ proto_register_field_init(header_field_info *hfinfo, int parent)
                        same_name_hfinfo->same_name_next = hfinfo;
                        hfinfo->same_name_prev = same_name_hfinfo;
                }
-               g_tree_insert(gpa_name_tree, hfinfo->abbrev, hfinfo);
+               g_tree_insert(gpa_name_tree, (gpointer) (hfinfo->abbrev), hfinfo);
        }
 
        return hfinfo->id;
 }
 
 void
-proto_register_subtree_array(gint **indices, int num_indices)
+proto_register_subtree_array(gint *const *indices, int num_indices)
 {
        int     i;
-       gint    **ptr = indices;
+       gint    *const *ptr = indices;
 
        /*
-        * Make sure we haven't already allocated the array of "tree is
-        * expanded" flags.
-        *
-        * XXX - if it's *really* important to allow more ett_ values to
-        * be given out after "proto_init()" is called, we could expand
-        * the array.
+        * If we've already allocated the array of tree types, expand
+        * it; this lets plugins such as mate add tree types after
+        * the initial startup.  (If we haven't already allocated it,
+        * we don't allocate it; on the first pass, we just assign
+        * ett values and keep track of how many we've assigned, and
+        * when we're finished registering all dissectors we allocate
+        * the array, so that we do only one allocation rather than
+        * wasting CPU time and memory by growing the array for each
+        * dissector that registers ett values.)
         */
-       g_assert(tree_is_expanded == NULL);
+       if (tree_is_expanded != NULL) {
+               tree_is_expanded =
+                   g_realloc(tree_is_expanded,
+                       (num_tree_types+num_indices)*sizeof (gboolean));
+               memset(tree_is_expanded + num_tree_types, 0,
+                   num_indices*sizeof (gboolean));
+       }
 
        /*
         * Assign "num_indices" subtree numbers starting at "num_tree_types",
@@ -2728,13 +3697,15 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
        guint8                          *bytes;
        guint32                         integer;
        ipv4_addr                       *ipv4;
+       e_guid_t                        *guid;
        guint32                         n_addr; /* network-order IPv4 address */
+       const gchar                     *name;
        int                                     ret;    /*tmp return value */
 
        switch(hfinfo->type) {
                case FT_NONE:
                case FT_PROTOCOL:
-                       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+                       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                "%s", hfinfo->name);
                        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
@@ -2748,14 +3719,14 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                case FT_UINT_BYTES:
                        bytes = fvalue_get(&fi->value);
                        if (bytes) {
-                               ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+                               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                        "%s: %s", hfinfo->name,
                                         bytes_to_str(bytes, fvalue_length(&fi->value)));
                                if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                                        label_str[ITEM_LABEL_LENGTH - 1] = '\0';
                        }
                        else {
-                               ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+                               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                        "%s: <MISSING>", hfinfo->name);
                                if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                                        label_str[ITEM_LABEL_LENGTH - 1] = '\0';
@@ -2799,7 +3770,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                case FT_INT16:
                case FT_INT24:
                case FT_INT32:
-                       g_assert(!hfinfo->bitmask);
+                       DISSECTOR_ASSERT(!hfinfo->bitmask);
                        if (hfinfo->strings) {
                                fill_label_enumerated_int(fi, label_str);
                        }
@@ -2813,7 +3784,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        break;
 
                case FT_FLOAT:
-                       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+                       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                "%s: %." STRINGIFY(FLT_DIG) "f",
                                hfinfo->name, fvalue_get_floating(&fi->value));
                        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
@@ -2821,7 +3792,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        break;
 
                case FT_DOUBLE:
-                       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+                       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                "%s: %." STRINGIFY(DBL_DIG) "g",
                                hfinfo->name, fvalue_get_floating(&fi->value));
                        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
@@ -2829,7 +3800,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        break;
 
                case FT_ABSOLUTE_TIME:
-                       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+                       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                "%s: %s", hfinfo->name,
                                abs_time_to_str(fvalue_get(&fi->value)));
                        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
@@ -2837,7 +3808,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        break;
 
                case FT_RELATIVE_TIME:
-                       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+                       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                "%s: %s seconds", hfinfo->name,
                                rel_time_to_secs_str(fvalue_get(&fi->value)));
                        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
@@ -2846,19 +3817,19 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
 
                case FT_IPXNET:
                        integer = fvalue_get_integer(&fi->value);
-                       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
-                               "%s: 0x%08X (%s)", hfinfo->name,
-                               integer, get_ipxnet_name(integer));
+                       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                               "%s: %s (0x%08X)", hfinfo->name,
+                               get_ipxnet_name(integer), integer);
                        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
                        break;
 
                case FT_ETHER:
                        bytes = fvalue_get(&fi->value);
-                       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+                       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                "%s: %s (%s)", hfinfo->name,
-                               ether_to_str(bytes),
-                               get_ether_name(bytes));
+                               get_ether_name(bytes),
+                               ether_to_str(bytes));
                        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
                        break;
@@ -2866,7 +3837,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                case FT_IPv4:
                        ipv4 = fvalue_get(&fi->value);
                        n_addr = ipv4_get_net_order_addr(ipv4);
-                       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+                       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                "%s: %s (%s)", hfinfo->name,
                                get_hostname(n_addr),
                                ip_to_str((guint8*)&n_addr));
@@ -2876,7 +3847,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
 
                case FT_IPv6:
                        bytes = fvalue_get(&fi->value);
-                       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+                       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                "%s: %s (%s)", hfinfo->name,
                                get_hostname6((struct e_in6_addr *)bytes),
                                ip6_to_str((struct e_in6_addr*)bytes));
@@ -2884,13 +3855,44 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
                        break;
 
+               case FT_GUID:
+                       guid = fvalue_get(&fi->value);
+                       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                               "%s: %s", hfinfo->name,
+                                guid_to_str(guid));
+                       if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
+                               label_str[ITEM_LABEL_LENGTH - 1] = '\0';
+                       break;
+
+               case FT_OID:
+                       bytes = fvalue_get(&fi->value);
+                       name = (oid_resolv_enabled()) ? get_oid_name(bytes, fvalue_length(&fi->value)) : NULL;
+                       if (name) {
+                               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                                       "%s: %s (%s)", hfinfo->name,
+                                        oid_to_str(bytes, fvalue_length(&fi->value)), name);
+                       } else {
+                               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                                       "%s: %s", hfinfo->name,
+                                        oid_to_str(bytes, fvalue_length(&fi->value)));
+                       }
+                       if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
+                               label_str[ITEM_LABEL_LENGTH - 1] = '\0';
+                       break;
+
                case FT_STRING:
                case FT_STRINGZ:
                case FT_UINT_STRING:
                        bytes = fvalue_get(&fi->value);
-                       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
-                               "%s: %s", hfinfo->name,
-                               format_text(bytes, strlen(bytes)));
+            if(strlen(bytes) > ITEM_LABEL_LENGTH) {
+                           ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                                   "%s [truncated]: %s", hfinfo->name,
+                                   format_text(bytes, strlen(bytes)));
+            } else {
+                           ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                                   "%s: %s", hfinfo->name,
+                                   format_text(bytes, strlen(bytes)));
+            }
                        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
                        break;
@@ -2899,7 +3901,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        g_error("hfinfo->type %d (%s) not handled\n",
                                        hfinfo->type,
                                        ftype_name(hfinfo->type));
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                        break;
        }
 }
@@ -2938,7 +3940,7 @@ fill_label_boolean(field_info *fi, gchar *label_str)
        }
 
        /* Fill in the textual info */
-       ret = snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
+       ret = g_snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
                "%s: %s",  hfinfo->name,
                value ? tfstring->true_string : tfstring->false_string);
        if ((ret == -1) || (ret >= (ITEM_LABEL_LENGTH - bitfield_byte_length)))
@@ -2950,7 +3952,8 @@ fill_label_boolean(field_info *fi, gchar *label_str)
 static void
 fill_label_enumerated_bitfield(field_info *fi, gchar *label_str)
 {
-       char *format = NULL, *p;
+       const char *format = NULL;
+       char *p;
        int bitfield_byte_length, bitwidth;
        guint32 unshifted_value;
        guint32 value;
@@ -2976,7 +3979,7 @@ fill_label_enumerated_bitfield(field_info *fi, gchar *label_str)
        bitfield_byte_length = p - label_str;
 
        /* Fill in the textual info using stored (shifted) value */
-       ret = snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
+       ret = g_snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
                        format,  hfinfo->name,
                        val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value);
        if ((ret == -1) || (ret >= (ITEM_LABEL_LENGTH - bitfield_byte_length)))
@@ -2986,7 +3989,8 @@ fill_label_enumerated_bitfield(field_info *fi, gchar *label_str)
 static void
 fill_label_numeric_bitfield(field_info *fi, gchar *label_str)
 {
-       char *format = NULL, *p;
+       const char *format = NULL;
+       char *p;
        int bitfield_byte_length, bitwidth;
        guint32 unshifted_value;
        guint32 value;
@@ -3012,8 +4016,13 @@ fill_label_numeric_bitfield(field_info *fi, gchar *label_str)
        bitfield_byte_length = p - label_str;
 
        /* Fill in the textual info using stored (shifted) value */
-       ret = snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
-                       format,  hfinfo->name, value);
+       if (IS_BASE_DUAL(hfinfo->display)) {
+               ret = g_snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
+                               format,  hfinfo->name, value, value);
+       } else {
+               ret = g_snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
+                               format,  hfinfo->name, value);
+       }
        if ((ret == -1) || (ret >= (ITEM_LABEL_LENGTH - bitfield_byte_length)))
                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
 
@@ -3022,7 +4031,7 @@ fill_label_numeric_bitfield(field_info *fi, gchar *label_str)
 static void
 fill_label_enumerated_uint(field_info *fi, gchar *label_str)
 {
-       char *format = NULL;
+       const char *format = NULL;
        header_field_info       *hfinfo = fi->hfinfo;
        guint32 value;
        int                                     ret;    /*tmp return value */
@@ -3033,7 +4042,7 @@ fill_label_enumerated_uint(field_info *fi, gchar *label_str)
        value = fvalue_get_integer(&fi->value);
 
        /* Fill in the textual info */
-       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                        format,  hfinfo->name,
                        val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value);
        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
@@ -3043,7 +4052,7 @@ fill_label_enumerated_uint(field_info *fi, gchar *label_str)
 static void
 fill_label_uint(field_info *fi, gchar *label_str)
 {
-       char *format = NULL;
+       const char *format = NULL;
        header_field_info       *hfinfo = fi->hfinfo;
        guint32 value;
        int                                     ret;    /*tmp return value */
@@ -3053,8 +4062,13 @@ fill_label_uint(field_info *fi, gchar *label_str)
        value = fvalue_get_integer(&fi->value);
 
        /* Fill in the textual info */
-       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
-                       format,  hfinfo->name, value);
+       if (IS_BASE_DUAL(hfinfo->display)) {
+               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                               format,  hfinfo->name, value, value);
+       } else {
+               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                               format,  hfinfo->name, value);
+       }
        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
 }
@@ -3062,7 +4076,7 @@ fill_label_uint(field_info *fi, gchar *label_str)
 static void
 fill_label_uint64(field_info *fi, gchar *label_str)
 {
-       char *format = NULL;
+       const char *format = NULL;
        header_field_info       *hfinfo = fi->hfinfo;
        guint64 value;
        int                                     ret;    /*tmp return value */
@@ -3072,8 +4086,13 @@ fill_label_uint64(field_info *fi, gchar *label_str)
        value = fvalue_get_integer64(&fi->value);
 
        /* Fill in the textual info */
-       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
-                       format,  hfinfo->name, value);
+       if (IS_BASE_DUAL(hfinfo->display)) {
+               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                               format,  hfinfo->name, value, value);
+       } else {
+               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                               format,  hfinfo->name, value);
+       }
        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
 }
@@ -3081,7 +4100,7 @@ fill_label_uint64(field_info *fi, gchar *label_str)
 static void
 fill_label_enumerated_int(field_info *fi, gchar *label_str)
 {
-       char *format = NULL;
+       const char *format = NULL;
        header_field_info       *hfinfo = fi->hfinfo;
        guint32 value;
        int                                     ret;    /*tmp return value */
@@ -3091,7 +4110,7 @@ fill_label_enumerated_int(field_info *fi, gchar *label_str)
        value = fvalue_get_integer(&fi->value);
 
        /* Fill in the textual info */
-       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
+       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                        format,  hfinfo->name,
                        val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value);
        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
@@ -3101,7 +4120,7 @@ fill_label_enumerated_int(field_info *fi, gchar *label_str)
 static void
 fill_label_int(field_info *fi, gchar *label_str)
 {
-       char *format = NULL;
+       const char *format = NULL;
        header_field_info       *hfinfo = fi->hfinfo;
        guint32 value;
        int                                     ret;    /*tmp return value */
@@ -3111,8 +4130,13 @@ fill_label_int(field_info *fi, gchar *label_str)
        value = fvalue_get_integer(&fi->value);
 
        /* Fill in the textual info */
-       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
-                       format,  hfinfo->name, value);
+       if (IS_BASE_DUAL(hfinfo->display)) {
+               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                               format,  hfinfo->name, value, value);
+       } else {
+               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                               format,  hfinfo->name, value);
+       }
        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
 }
@@ -3120,7 +4144,7 @@ fill_label_int(field_info *fi, gchar *label_str)
 static void
 fill_label_int64(field_info *fi, gchar *label_str)
 {
-       char *format = NULL;
+       const char *format = NULL;
        header_field_info       *hfinfo = fi->hfinfo;
        guint64 value;
        int                                     ret;    /*tmp return value */
@@ -3130,8 +4154,13 @@ fill_label_int64(field_info *fi, gchar *label_str)
        value = fvalue_get_integer64(&fi->value);
 
        /* Fill in the textual info */
-       ret = snprintf(label_str, ITEM_LABEL_LENGTH,
-                       format,  hfinfo->name, value);
+       if (IS_BASE_DUAL(hfinfo->display)) {
+               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                               format,  hfinfo->name, value, value);
+       } else {
+               ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                               format,  hfinfo->name, value);
+       }
        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
 }
@@ -3166,25 +4195,27 @@ hfinfo_bitwidth(header_field_info *hfinfo)
                        bitwidth = hfinfo->display; /* hacky? :) */
                        break;
                default:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                        ;
        }
        return bitwidth;
 }
 
-static char*
+static const char*
 hfinfo_uint_vals_format(header_field_info *hfinfo)
 {
-       char *format = NULL;
+       const char *format = NULL;
 
        switch(hfinfo->display) {
                case BASE_DEC:
+               case BASE_DEC_HEX:
                        format = "%s: %s (%u)";
                        break;
                case BASE_OCT: /* I'm lazy */
                        format = "%s: %s (%o)";
                        break;
                case BASE_HEX:
+               case BASE_HEX_DEC:
                        switch(hfinfo->type) {
                                case FT_UINT8:
                                        format = "%s: %s (0x%02x)";
@@ -3199,21 +4230,21 @@ hfinfo_uint_vals_format(header_field_info *hfinfo)
                                        format = "%s: %s (0x%08x)";
                                        break;
                                default:
-                                       g_assert_not_reached();
+                                       DISSECTOR_ASSERT_NOT_REACHED();
                                        ;
                        }
                        break;
                default:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                        ;
        }
        return format;
 }
 
-static char*
+static const char*
 hfinfo_uint_format(header_field_info *hfinfo)
 {
-       char *format = NULL;
+       const char *format = NULL;
 
        /* Pick the proper format string */
        if (hfinfo->type == FT_FRAMENUM) {
@@ -3226,6 +4257,25 @@ hfinfo_uint_format(header_field_info *hfinfo)
                        case BASE_DEC:
                                format = "%s: %u";
                                break;
+                       case BASE_DEC_HEX:
+                               switch(hfinfo->type) {
+                                       case FT_UINT8:
+                                               format = "%s: %u (0x%02x)";
+                                               break;
+                                       case FT_UINT16:
+                                               format = "%s: %u (0x%04x)";
+                                               break;
+                                       case FT_UINT24:
+                                               format = "%s: %u (0x%06x)";
+                                               break;
+                                       case FT_UINT32:
+                                               format = "%s: %u (0x%08x)";
+                                               break;
+                                       default:
+                                               DISSECTOR_ASSERT_NOT_REACHED();
+                                               ;
+                               }
+                               break;
                        case BASE_OCT: /* I'm lazy */
                                format = "%s: %o";
                                break;
@@ -3244,31 +4294,52 @@ hfinfo_uint_format(header_field_info *hfinfo)
                                                format = "%s: 0x%08x";
                                                break;
                                        default:
-                                               g_assert_not_reached();
+                                               DISSECTOR_ASSERT_NOT_REACHED();
+                                               ;
+                               }
+                               break;
+                       case BASE_HEX_DEC:
+                               switch(hfinfo->type) {
+                                       case FT_UINT8:
+                                               format = "%s: 0x%02x (%u)";
+                                               break;
+                                       case FT_UINT16:
+                                               format = "%s: 0x%04x (%u)";
+                                               break;
+                                       case FT_UINT24:
+                                               format = "%s: 0x%06x (%u)";
+                                               break;
+                                       case FT_UINT32:
+                                               format = "%s: 0x%08x (%u)";
+                                               break;
+                                       default:
+                                               DISSECTOR_ASSERT_NOT_REACHED();
                                                ;
                                }
                                break;
                        default:
-                               g_assert_not_reached();
+                               DISSECTOR_ASSERT_NOT_REACHED();
                                ;
                }
        }
        return format;
 }
 
-static char*
+static const char*
 hfinfo_int_vals_format(header_field_info *hfinfo)
 {
-       char *format = NULL;
+       const char *format = NULL;
 
        switch(hfinfo->display) {
                case BASE_DEC:
+               case BASE_DEC_HEX:
                        format = "%s: %s (%d)";
                        break;
                case BASE_OCT: /* I'm lazy */
                        format = "%s: %s (%o)";
                        break;
                case BASE_HEX:
+               case BASE_HEX_DEC:
                        switch(hfinfo->type) {
                                case FT_INT8:
                                        format = "%s: %s (0x%02x)";
@@ -3283,50 +4354,74 @@ hfinfo_int_vals_format(header_field_info *hfinfo)
                                        format = "%s: %s (0x%08x)";
                                        break;
                                default:
-                                       g_assert_not_reached();
+                                       DISSECTOR_ASSERT_NOT_REACHED();
                                        ;
                        }
                        break;
                default:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                        ;
        }
        return format;
 }
 
-static char*
+static const char*
 hfinfo_uint64_format(header_field_info *hfinfo)
 {
-       char *format = NULL;
+       const char *format = NULL;
 
        /* Pick the proper format string */
        switch(hfinfo->display) {
                case BASE_DEC:
                        format = "%s: %" PRIu64;
                        break;
+               case BASE_DEC_HEX:
+                       format = "%s: %" PRIu64 " (%" PRIx64 ")";
+                       break;
                case BASE_OCT: /* I'm lazy */
                        format = "%s: %" PRIo64;
                        break;
                case BASE_HEX:
                        format = "%s: 0x%016" PRIx64;
                        break;
+               case BASE_HEX_DEC:
+                       format = "%s: 0x%016" PRIx64 " (%" PRIu64 ")";
+                       break;
                default:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                        ;
        }
        return format;
 }
 
-static char*
+static const char*
 hfinfo_int_format(header_field_info *hfinfo)
 {
-       char *format = NULL;
+       const char *format = NULL;
 
        /* Pick the proper format string */
        switch(hfinfo->display) {
                case BASE_DEC:
                        format = "%s: %d";
                        break;
+               case BASE_DEC_HEX:
+                       switch(hfinfo->type) {
+                               case FT_INT8:
+                                       format = "%s: %d (0x%02x)";
+                                       break;
+                               case FT_INT16:
+                                       format = "%s: %d (0x%04x)";
+                                       break;
+                               case FT_INT24:
+                                       format = "%s: %d (0x%06x)";
+                                       break;
+                               case FT_INT32:
+                                       format = "%s: %d (0x%08x)";
+                                       break;
+                               default:
+                                       DISSECTOR_ASSERT_NOT_REACHED();
+                                       ;
+                       }
                case BASE_OCT: /* I'm lazy */
                        format = "%s: %o";
                        break;
@@ -3345,35 +4440,60 @@ hfinfo_int_format(header_field_info *hfinfo)
                                        format = "%s: 0x%08x";
                                        break;
                                default:
-                                       g_assert_not_reached();
+                                       DISSECTOR_ASSERT_NOT_REACHED();
+                                       ;
+                       }
+                       break;
+               case BASE_HEX_DEC:
+                       switch(hfinfo->type) {
+                               case FT_INT8:
+                                       format = "%s: 0x%02x (%d)";
+                                       break;
+                               case FT_INT16:
+                                       format = "%s: 0x%04x (%d)";
+                                       break;
+                               case FT_INT24:
+                                       format = "%s: 0x%06x (%d)";
+                                       break;
+                               case FT_INT32:
+                                       format = "%s: 0x%08x (%d)";
+                                       break;
+                               default:
+                                       DISSECTOR_ASSERT_NOT_REACHED();
                                        ;
                        }
                        break;
                default:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                        ;
        }
        return format;
 }
 
-static char*
+static const char*
 hfinfo_int64_format(header_field_info *hfinfo)
 {
-       char *format = NULL;
+       const char *format = NULL;
 
        /* Pick the proper format string */
        switch(hfinfo->display) {
                case BASE_DEC:
                        format = "%s: %" PRId64;
                        break;
+               case BASE_DEC_HEX:
+                       format = "%s: %" PRId64 " (%" PRIx64 ")";
+                       break;
                case BASE_OCT: /* I'm lazy */
                        format = "%s: %" PRIo64;
                        break;
                case BASE_HEX:
                        format = "%s: 0x%016" PRIx64;
                        break;
+               case BASE_HEX_DEC:
+                       format = "%s: 0x%016" PRIx64 " (%" PRId64 ")";
+                       break;
                default:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                        ;
        }
        return format;
@@ -3387,7 +4507,7 @@ proto_registrar_n(void)
        return gpa_hfinfo.len;
 }
 
-char*
+const char*
 proto_registrar_get_name(int n)
 {
        header_field_info *hfinfo;
@@ -3396,7 +4516,7 @@ proto_registrar_get_name(int n)
        return hfinfo->name;
 }
 
-char*
+const char*
 proto_registrar_get_abbrev(int n)
 {
        header_field_info *hfinfo;
@@ -3478,12 +4598,13 @@ proto_get_finfo_ptr_array(proto_tree *tree, int id)
 }
 
 
-/* Helper struct and function for proto_find_info() */
+/* Helper struct for proto_find_info() and  proto_all_finfos() */
 typedef struct {
        GPtrArray       *array;
        int             id;
 } ffdata_t;
 
+/* Helper function for proto_find_info() */
 static gboolean
 find_finfo(proto_node *node, gpointer data)
 {
@@ -3499,11 +4620,11 @@ find_finfo(proto_node *node, gpointer data)
 }
 
 /* Return GPtrArray* of field_info pointers for all hfindex that appear in a tree.
- * This works on any proto_tree, primed or unprimed, but actually searches
- * the tree, so it is slower than using proto_get_finfo_ptr_array on a primed tree.
- * The caller does need to free the returned GPtrArray with
- * g_ptr_array_free(<array>, FALSE).
- */
+* This works on any proto_tree, primed or unprimed, but actually searches
+* the tree, so it is slower than using proto_get_finfo_ptr_array on a primed tree.
+* The caller does need to free the returned GPtrArray with
+* g_ptr_array_free(<array>, FALSE).
+*/
 GPtrArray*
 proto_find_finfo(proto_tree *tree, int id)
 {
@@ -3515,7 +4636,34 @@ proto_find_finfo(proto_tree *tree, int id)
        proto_tree_traverse_pre_order(tree, find_finfo, &ffdata);
 
        return ffdata.array;
-}      
+}
+
+/* Helper function for proto_all_finfos() */
+static gboolean
+every_finfo(proto_node *node, gpointer data)
+{
+       field_info *fi = PITEM_FINFO(node);
+       if (fi && fi->hfinfo) {
+               g_ptr_array_add(((ffdata_t*)data)->array, fi);
+       }
+
+       /* Don't stop traversing. */
+       return FALSE;
+}
+
+/* Return GPtrArray* of field_info pointers containing all hfindexes that appear in a tree. */
+GPtrArray*
+proto_all_finfos(proto_tree *tree)
+{
+       ffdata_t        ffdata;
+
+       ffdata.array = g_ptr_array_new();
+       ffdata.id = 0;
+
+       proto_tree_traverse_pre_order(tree, every_finfo, &ffdata);
+
+       return ffdata.array;
+}
 
 
 typedef struct {
@@ -3579,7 +4727,7 @@ proto_registrar_dump_protocols(void)
 {
        protocol_t              *protocol;
        int                     i;
-       void                    *cookie;
+       void                    *cookie = NULL;
 
        for (i = proto_get_first_protocol(&cookie); i != -1;
            i = proto_get_next_protocol(&cookie)) {
@@ -3719,10 +4867,27 @@ proto_registrar_dump_values(void)
  * Field 3 = field abbreviation
  * Field 4 = type ( textual representation of the the ftenum type )
  * Field 5 = parent protocol abbreviation
+ * Field 6 = blurb describing field
+ *
+ * (format 2)
+ * Field 1 = 'F'
+ * Field 2 = descriptive field name
+ * Field 3 = field abbreviation
+ * Field 4 = type ( textual representation of the the ftenum type )
+ * Field 5 = parent protocol abbreviation
+ * Field 6 = blurb describing field
+ * Field 7 = base for display (for integer types)
+ * Field 8 = blurb describing field (yes, apparently we repeated this accidentally)
  *
- * (format 2 adds these fields:)
- * Field 6 = base for display (for integer types)
- * Field 7 = blurb describing field
+ * (format 3)
+ * Field 1 = 'F'
+ * Field 2 = descriptive field name
+ * Field 3 = field abbreviation
+ * Field 4 = type ( textual representation of the the ftenum type )
+ * Field 5 = parent protocol abbreviation
+ * Field 6 = blurb describing field
+ * Field 7 = base for display (for integer types)
+ * Field 8 = bitmask
  */
 void
 proto_registrar_dump_fields(int format)
@@ -3731,32 +4896,17 @@ proto_registrar_dump_fields(int format)
        int                     i, len;
        const char              *enum_name;
        const char              *base_name;
+       const char              *blurb;
 
        len = gpa_hfinfo.len;
        for (i = 0; i < len ; i++) {
                PROTO_REGISTRAR_GET_NTH(i, hfinfo);
 
                /*
-                * Skip fields with zero-length names or abbreviations;
-                * the pseudo-field for "proto_tree_add_text()" is such
-                * a field, and we don't want it in the list of filterable
-                * fields.
-                *
-                *
-                * XXX - perhaps the name and abbrev field should be null
-                * pointers rather than null strings for that pseudo-field,
-                * but we'd have to add checks for null pointers in some
-                * places if we did that.
-                *
-                * Or perhaps protocol tree items added with
-                * "proto_tree_add_text()" should have -1 as the field index,
-                * with no pseudo-field being used, but that might also
-                * require special checks for -1 to be added.
-                */
-               /* XXX - we could just skip the special text
-                * pseudo-field by testing: if (hfinfo->id == hf_text_only)
-                * */
-               if (hfinfo->name[0] == 0 || hfinfo->abbrev[0] == 0)
+                * Skip the pseudo-field for "proto_tree_add_text()" since
+                * we don't want it in the list of filterable fields.
+         */
+        if (hfinfo->id == hf_text_only)
                        continue;
 
                /* format for protocols */
@@ -3797,7 +4947,7 @@ proto_registrar_dump_fields(int format)
                                        hfinfo->type == FT_INT32 ||
                                        hfinfo->type == FT_INT64) {
 
-                                       
+
                                        switch(hfinfo->display) {
                                                case BASE_NONE:
                                                        base_name = "BASE_NONE";
@@ -3811,28 +4961,47 @@ proto_registrar_dump_fields(int format)
                                                case BASE_OCT:
                                                        base_name = "BASE_OCT";
                                                        break;
+                                               case BASE_DEC_HEX:
+                                                       base_name = "BASE_DEC_HEX";
+                                                       break;
+                                               case BASE_HEX_DEC:
+                                                       base_name = "BASE_HEX_DEC";
+                                                       break;
                                        }
                                }
                        }
 
+                       blurb = hfinfo->blurb;
+                       if (blurb == NULL)
+                               blurb = "";
                        if (format == 1) {
-                               printf("F\t%s\t%s\t%s\t%s\t%s\n", hfinfo->name, hfinfo->abbrev,
-                                       enum_name,parent_hfinfo->abbrev, hfinfo->blurb);
+                               printf("F\t%s\t%s\t%s\t%s\t%s\n",
+                                       hfinfo->name, hfinfo->abbrev, enum_name,
+                                       parent_hfinfo->abbrev, blurb);
                        }
                        else if (format == 2) {
                                printf("F\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
-                                       hfinfo->name, hfinfo->abbrev,
-                                       enum_name,parent_hfinfo->abbrev, hfinfo->blurb,
-                                       base_name, hfinfo->blurb);
+                                       hfinfo->name, hfinfo->abbrev, enum_name,
+                                       parent_hfinfo->abbrev, blurb,
+                                       base_name, blurb);
+                       }
+                       else if (format == 3) {
+                               printf("F\t%s\t%s\t%s\t%s\t%s\t%s\t%u\n",
+                                       hfinfo->name, hfinfo->abbrev, enum_name,
+                                       parent_hfinfo->abbrev, blurb,
+                                       base_name, hfinfo->bitmask);
+                       }
+                       else {
+                               g_assert_not_reached();
                        }
                }
        }
 }
 
-static char*
+static const char*
 hfinfo_numeric_format(header_field_info *hfinfo)
 {
-       char *format = NULL;
+       const char *format = NULL;
 
        /* Pick the proper format string */
        if (hfinfo->type == FT_FRAMENUM) {
@@ -3844,6 +5013,7 @@ hfinfo_numeric_format(header_field_info *hfinfo)
                /* Pick the proper format string */
                switch(hfinfo->display) {
                        case BASE_DEC:
+                       case BASE_DEC_HEX:
                        case BASE_OCT: /* I'm lazy */
                                switch(hfinfo->type) {
                                        case FT_UINT8:
@@ -3865,11 +5035,12 @@ hfinfo_numeric_format(header_field_info *hfinfo)
                                                format = "%s == %" PRId64;
                                                break;
                                        default:
-                                               g_assert_not_reached();
+                                               DISSECTOR_ASSERT_NOT_REACHED();
                                                ;
                                }
                                break;
                        case BASE_HEX:
+                       case BASE_HEX_DEC:
                                switch(hfinfo->type) {
                                        case FT_UINT8:
                                                format = "%s == 0x%02x";
@@ -3887,12 +5058,12 @@ hfinfo_numeric_format(header_field_info *hfinfo)
                                                format = "%s == 0x%016" PRIx64;
                                                break;
                                        default:
-                                               g_assert_not_reached();
+                                               DISSECTOR_ASSERT_NOT_REACHED();
                                                ;
                                }
                                break;
                        default:
-                               g_assert_not_reached();
+                               DISSECTOR_ASSERT_NOT_REACHED();
                                ;
                }
        }
@@ -3910,7 +5081,7 @@ proto_can_match_selected(field_info *finfo, epan_dissect_t *edt)
        gint                    length;
 
        hfinfo = finfo->hfinfo;
-       g_assert(hfinfo);
+       DISSECTOR_ASSERT(hfinfo);
 
        switch(hfinfo->type) {
 
@@ -3940,11 +5111,18 @@ proto_can_match_selected(field_info *finfo, epan_dissect_t *edt)
                case FT_BYTES:
                case FT_UINT_BYTES:
                case FT_PROTOCOL:
+               case FT_GUID:
+               case FT_OID:
                        /*
                         * These all have values, so we can match.
                         */
                        return TRUE;
-
+               case FT_NONE:
+                       /*
+                        * Doesn't have a value, but may still want to test
+                        * for its presence in a trace
+                        */
+                       return TRUE;
                default:
                        /*
                         * This doesn't have a value, so we'd match
@@ -3991,32 +5169,35 @@ proto_can_match_selected(field_info *finfo, epan_dissect_t *edt)
        }
 }
 
+/* This function returns a string allocated with packet lifetime scope.
+ * You do not need to [g_]free() this string since it will be automatically
+ * freed once the next packet is dissected.
+ */
 char*
 proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
 {
        header_field_info       *hfinfo;
        int                     abbrev_len;
-       char                    *buf, *stringified, *format, *ptr;
+       char                    *buf, *ptr;
+       int                     buf_len;
+       const char              *format;
        int                     dfilter_len, i;
        gint                    start, length, length_remaining;
        guint8                  c;
 
        hfinfo = finfo->hfinfo;
-       g_assert(hfinfo);
+       DISSECTOR_ASSERT(hfinfo);
        abbrev_len = strlen(hfinfo->abbrev);
 
        /*
-        * XXX - we should add "val_to_string_repr" and "string_repr_len"
-        * functions for more types, and use them whenever possible.
-        *
-        * The FT_UINT and FT_INT types are the only tricky ones, as
-        * we choose the base in the string expression based on the
-        * display base of the field.
+        * XXX - we can't use the "val_to_string_repr" and "string_repr_len"
+        * functions for FT_UINT and FT_INT types, as we choose the base in
+        * the string expression based on the display base of the field.
         *
         * Note that the base does matter, as this is also used for
         * the protocolinfo tap.
         *
-        * It might be nice to use that in "proto_item_fill_label()"
+        * It might be nice to use them in "proto_item_fill_label()"
         * as well, although, there, you'd have to deal with the base
         * *and* with resolved values for addresses.
         *
@@ -4056,9 +5237,9 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                         * 1 byte for the trailing '\0'.
                         */
                        dfilter_len = abbrev_len + 4 + 11 + 1;
-                       buf = g_malloc0(dfilter_len);
+                       buf = ep_alloc0(dfilter_len);
                        format = hfinfo_numeric_format(hfinfo);
-                       snprintf(buf, dfilter_len, format, hfinfo->abbrev, fvalue_get_integer(&finfo->value));
+                       g_snprintf(buf, dfilter_len, format, hfinfo->abbrev, fvalue_get_integer(&finfo->value));
                        break;
 
                case FT_INT64:
@@ -4080,48 +5261,28 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                         * 1 byte for the trailing '\0'.
                         */
                        dfilter_len = abbrev_len + 4 + 22 + 1;
-                       buf = g_malloc0(dfilter_len);
+                       buf = ep_alloc0(dfilter_len);
                        format = hfinfo_numeric_format(hfinfo);
-                       snprintf(buf, dfilter_len, format, hfinfo->abbrev, fvalue_get_integer64(&finfo->value));
-                       break;
-
-               case FT_IPXNET:
-                       /*
-                        * 4 bytes for " == ".
-                        * 2 bytes for "0x".
-                        * 8 bytes for 8 digits of 32-bit hex number.
-                        * 1 byte for the trailing '\0'.
-                        */
-                       dfilter_len = abbrev_len + 4 + 2 + 8 + 1;
-                       buf = g_malloc0(dfilter_len);
-                       snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
-                                       fvalue_get_integer(&finfo->value));
-                       break;
-
-               case FT_IPv6:
-                       /*
-                        * 4 bytes for " == ".
-                        * N bytes for the string for the address.
-                        * 1 byte for the trailing '\0'.
-                        */
-                       stringified = ip6_to_str((struct e_in6_addr*) fvalue_get(&finfo->value));
-                       dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
-                       buf = g_malloc0(dfilter_len);
-                       snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
-                                       stringified);
+                       g_snprintf(buf, dfilter_len, format, hfinfo->abbrev, fvalue_get_integer64(&finfo->value));
                        break;
 
                /* These use the fvalue's "to_string_repr" method. */
+               case FT_IPXNET:
                case FT_BOOLEAN:
                case FT_STRING:
+               case FT_STRINGZ:
                case FT_ETHER:
                case FT_BYTES:
                case FT_UINT_BYTES:
+               case FT_UINT_STRING:
                case FT_FLOAT:
                case FT_DOUBLE:
                case FT_ABSOLUTE_TIME:
                case FT_RELATIVE_TIME:
                case FT_IPv4:
+               case FT_IPv6:
+               case FT_GUID:
+               case FT_OID:
                        /* Figure out the string length needed.
                         *      The ft_repr length.
                         *      4 bytes for " == ".
@@ -4130,17 +5291,17 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                        dfilter_len = fvalue_string_repr_len(&finfo->value,
                                        FTREPR_DFILTER);
                        dfilter_len += abbrev_len + 4 + 1;
-                       buf = g_malloc0(dfilter_len);
+                       buf = ep_alloc0(dfilter_len);
 
                        /* Create the string */
-                       snprintf(buf, dfilter_len, "%s == ", hfinfo->abbrev);
+                       g_snprintf(buf, dfilter_len, "%s == ", hfinfo->abbrev);
                        fvalue_to_string_repr(&finfo->value,
                                        FTREPR_DFILTER,
                                        &buf[abbrev_len + 4]);
                        break;
 
                case FT_PROTOCOL:
-                       buf = g_strdup(finfo->hfinfo->abbrev);
+                       buf = ep_strdup(finfo->hfinfo->abbrev);
                        break;
 
                default:
@@ -4152,7 +5313,7 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                         * If "edt" is NULL, the answer is "no".
                         */
                        if (edt == NULL)
-                               return FALSE;
+                               return NULL;
 
                        /*
                         * Is this field part of the raw frame tvbuff?
@@ -4169,13 +5330,18 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                                return NULL;    /* you lose */
 
                        /*
-                        * If the length is 0, there's nothing to match, so
-                        * we can't match.  (Also check for negative values,
+                        * If the length is 0, just match the name of the field
+                        * (Also check for negative values,
                         * just in case, as we'll cast it to an unsigned
                         * value later.)
                         */
                        length = finfo->length;
-                       if (length <= 0)
+                       if (length == 0)
+                       {
+                               buf = ep_strdup(finfo->hfinfo->abbrev);
+                               break;
+                       }
+                       if (length < 0)
                                return NULL;
 
                        /*
@@ -4186,24 +5352,22 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                                length = length_remaining;
                        if (length <= 0)
                                return NULL;
-                       
+
                        start = finfo->start;
-                       buf = g_malloc0(32 + length * 3);
+                       buf_len = 32 + length * 3;
+                       buf = ep_alloc0(buf_len);
                        ptr = buf;
 
-                       sprintf(ptr, "frame[%d:%d] == ", finfo->start, length);
-                       ptr = buf+strlen(buf);
-
+                       ptr += g_snprintf(ptr, buf_len-(ptr-buf), "frame[%d:%d] == ", finfo->start, length);
                        for (i=0;i<length; i++) {
                                c = tvb_get_guint8(finfo->ds_tvb, start);
                                start++;
                                if (i == 0 ) {
-                                       sprintf(ptr, "%02x", c);
+                                       ptr += g_snprintf(ptr, buf_len-(ptr-buf), "%02x", c);
                                }
                                else {
-                                       sprintf(ptr, ":%02x", c);
+                                       ptr += g_snprintf(ptr, buf_len-(ptr-buf), ":%02x", c);
                                }
-                               ptr = buf+strlen(buf);
                        }
                        break;
        }