Cite the source of frequency allocation information.
[obnox/wireshark/wip.git] / epan / proto.c
index f3411740b59e893b41fbcc813d684decdc87b370..4197b5c1a948e16e95c5739d18d88d3cebd0e0b6 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
@@ -19,7 +19,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
 #include "ptvcursor.h"
 #include "strutil.h"
 #include "addr_resolv.h"
-#include "oid_resolv.h"
+#include "oids.h"
 #include "plugins.h"
 #include "proto.h"
 #include "epan_dissect.h"
 #include "slab.h"
 #include "tvbuff.h"
 #include "emem.h"
+#include "charsets.h"
+#include "asm_utils.h"
+#include "column-utils.h"
+
+#ifdef NEED_G_ASCII_STRCASECMP_H
+#include "g_ascii_strcasecmp.h"
+#endif
+
+#define SUBTREE_ONCE_ALLOCATION_NUMBER 8
+#define SUBTREE_MAX_LEVELS 256
+
+
+typedef struct __subtree_lvl {
+  gint cursor_offset;
+  proto_item * it;
+  proto_tree * tree;
+}subtree_lvl;
 
 struct ptvcursor {
+       subtree_lvl     *pushed_tree;
+       guint8          pushed_tree_index;
+       guint8          pushed_tree_max;
        proto_tree      *tree;
        tvbuff_t        *tvb;
        gint            offset;
 };
 
+/* Candidates for assembler */
+int
+wrs_count_bitshift(guint32 bitmask)
+{
+       int bitshift = 0;
+
+       while ((bitmask & (1 << bitshift)) == 0)
+               bitshift++;
+       return bitshift;
+}
+
+
+
+#if GLIB_MAJOR_VERSION < 2
+static void *discard_const(const void *const_ptr)
+{
+       union {
+               const void *const_ptr;
+               void *ptr;
+       } stupid_const;
+
+       stupid_const.const_ptr = const_ptr;
+
+       return stupid_const.ptr;
+}
+#endif
+
 #define cVALS(x) (const value_string*)(x)
 
 #if 1
@@ -61,7 +108,7 @@ struct ptvcursor {
           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     \
+          since dissectors that want to do proto_item_set_len() or     \
           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.      \
@@ -97,9 +144,11 @@ static void fill_label_enumerated_int(field_info *fi, gchar *label_str);
 int hfinfo_bitwidth(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_uint_value_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_int_value_format(header_field_info *hfinfo);
 static const char* hfinfo_int64_format(header_field_info *hfinfo);
 
 static proto_item*
@@ -135,10 +184,12 @@ proto_tree_set_bytes_tvb(field_info *fi, tvbuff_t *tvb, gint offset, gint length
 static void
 proto_tree_set_time(field_info *fi, nstime_t *value_ptr);
 static void
-proto_tree_set_string(field_info *fi, const char* value, gboolean);
+proto_tree_set_string(field_info *fi, const char* value);
 static void
 proto_tree_set_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
 static void
+proto_tree_set_ebcdic_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
+static void
 proto_tree_set_ether(field_info *fi, const guint8* value);
 static void
 proto_tree_set_ether_tvb(field_info *fi, tvbuff_t *tvb, gint start);
@@ -151,9 +202,9 @@ 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 guint8* value_ptr);
+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);
+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
@@ -171,13 +222,10 @@ proto_tree_set_int(field_info *fi, gint32 value);
 static void
 proto_tree_set_uint64(field_info *fi, guint64 value);
 static void
-proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian);
+proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, guint length, gboolean little_endian);
 
 static int proto_register_field_init(header_field_info *hfinfo, int parent);
 
-/* Comparision function for tree insertion. A wrapper around strcmp() */
-static int g_strcmp(gconstpointer a, gconstpointer b);
-
 /* special-case header field used within proto.c */
 int hf_text_only = -1;
 
@@ -240,7 +288,7 @@ static SLAB_FREE_LIST_DEFINE(item_label_t)
 
 #define PROTO_REGISTRAR_GET_NTH(hfindex, hfinfo) \
        DISSECTOR_ASSERT((guint)hfindex < gpa_hfinfo.len); \
-       hfinfo=gpa_hfinfo.hfi[hfindex];         
+       hfinfo=gpa_hfinfo.hfi[hfindex];
 
 
 /* List which stores protocols and fields that have been registered */
@@ -253,6 +301,14 @@ gpa_hfinfo_t gpa_hfinfo;
 
 /* Balanced tree of abbreviations and IDs */
 static GTree *gpa_name_tree = NULL;
+static header_field_info *same_name_hfinfo;
+
+#if GLIB_MAJOR_VERSION >= 2
+static void save_same_name_hfinfo(gpointer data)
+{
+  same_name_hfinfo = (header_field_info*)data;
+}
+#endif
 
 /* Points to the first element of an array of Booleans, indexed by
    a subtree item type; that array element is TRUE if subtrees of
@@ -273,48 +329,49 @@ 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);
+       return g_ascii_strcasecmp(p1->short_name, p2->short_name);
 }
 
 
 /* initialize data structures and register protocols and fields */
 void
-proto_init(const char *plugin_dir
-#ifndef HAVE_PLUGINS
-                                _U_
-#endif
-          ,
-          void (register_all_protocols)(void),
-          void (register_all_protocol_handoffs)(void))
+proto_init(void (register_all_protocols)(register_cb cb, gpointer client_data),
+          void (register_all_protocol_handoffs)(register_cb cb, gpointer client_data),
+          register_cb cb,
+          gpointer client_data)
 {
        static hf_register_info hf[] = {
                { &hf_text_only,
-               { "",   "", FT_NONE, BASE_NONE, NULL, 0x0,
+               { "Text item",  "", FT_NONE, BASE_NONE, NULL, 0x0,
                        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_names = g_hash_table_new(g_int_hash, g_int_equal);
+       proto_short_names = g_hash_table_new(wrs_str_hash, g_str_equal);
+       proto_filter_names = g_hash_table_new(wrs_str_hash, g_str_equal);
 
        proto_cleanup();
 
        gmc_hfinfo = g_mem_chunk_new("gmc_hfinfo",
                sizeof(header_field_info),
-        INITIAL_NUM_PROTOCOL_HFINFO * sizeof(header_field_info),
-        G_ALLOC_ONLY);
+               INITIAL_NUM_PROTOCOL_HFINFO * sizeof(header_field_info),
+               G_ALLOC_ONLY);
 
        gpa_hfinfo.len=0;
        gpa_hfinfo.allocated_len=0;
        gpa_hfinfo.hfi=NULL;
-       gpa_name_tree = g_tree_new(g_strcmp);
+#if GLIB_MAJOR_VERSION < 2
+       gpa_name_tree = g_tree_new(wrs_strcmp);
+#else
+       gpa_name_tree = g_tree_new_full(wrs_strcmp_with_data, NULL, NULL, save_same_name_hfinfo);
+#endif
 
        /* Initialize the ftype subsystem */
        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));
 
@@ -322,27 +379,32 @@ proto_init(const char *plugin_dir
           dissector tables, and dissectors to be called through a
           handle, and do whatever one-time initialization it needs to
           do. */
-       register_all_protocols();
+       register_all_protocols(cb, client_data);
 
 #ifdef HAVE_PLUGINS
        /* Now scan for plugins and load all the ones we find, calling
           their register routines to do the stuff described above. */
-       init_plugins(plugin_dir);
+       if(cb)
+         (*cb)(RA_PLUGIN_REGISTER, NULL, client_data);
+       init_plugins();
+       register_all_plugin_registrations();
 #endif
 
        /* Now call the "handoff registration" routines of all built-in
           dissectors; those routines register the dissector in other
           dissectors' handoff tables, and fetch any dissector handles
           they need. */
-       register_all_protocol_handoffs();
+       register_all_protocol_handoffs(cb, client_data);
 
 #ifdef HAVE_PLUGINS
        /* Now do the same with plugins. */
+       if(cb)
+         (*cb)(RA_PLUGIN_HANDOFF, NULL, client_data);
        register_all_plugin_handoffs();
 #endif
 
-    /* sort the protocols by protocol name */
-    protocols = g_list_sort(protocols, proto_compare_name);
+       /* 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. */
@@ -350,13 +412,6 @@ proto_init(const char *plugin_dir
        memset(tree_is_expanded, 0, num_tree_types*sizeof (gboolean));
 }
 
-/* String comparison func for dfilter_token GTree */
-static int
-g_strcmp(gconstpointer a, gconstpointer b)
-{
-       return strcmp((const char*)a, (const char*)b);
-}
-
 void
 proto_cleanup(void)
 {
@@ -380,8 +435,6 @@ proto_cleanup(void)
 
 }
 
-typedef gboolean (*proto_tree_traverse_func)(proto_node *, gpointer);
-
 static gboolean
 proto_tree_traverse_pre_order(proto_tree *tree, proto_tree_traverse_func func,
     gpointer data)
@@ -410,7 +463,7 @@ proto_tree_traverse_pre_order(proto_tree *tree, proto_tree_traverse_func func,
        return FALSE;
 }
 
-static gboolean
+gboolean
 proto_tree_traverse_in_order(proto_tree *tree, proto_tree_traverse_func func,
     gpointer data)
 {
@@ -478,16 +531,16 @@ proto_tree_free(proto_tree *tree)
 }
 
 static void
-free_GPtrArray_value(gpointer key _U_, gpointer value, gpointer user_data _U_)
+free_GPtrArray_value(gpointer key, gpointer value, gpointer user_data _U_)
 {
        GPtrArray   *ptrs = value;
-       gint hfid = (gint)key;
+       gint hfid = (gint)(long)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 
+               /* 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
                */
@@ -557,7 +610,7 @@ proto_tree_set_visible(proto_tree *tree, gboolean visible)
 
 /* Assume dissector set only its protocol fields.
    This function is called by dissectors and allowes to speed up filtering
-   in ethereal, if this function returns FALSE it is safe to reset tree to NULL
+   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.
@@ -598,7 +651,34 @@ header_field_info*
 proto_registrar_get_byname(const char *field_name)
 {
        DISSECTOR_ASSERT(field_name != NULL);
+#if GLIB_MAJOR_VERSION < 2
+       return g_tree_lookup(gpa_name_tree, discard_const(field_name));
+#else
        return g_tree_lookup(gpa_name_tree, field_name);
+#endif
+}
+
+
+void ptvcursor_new_subtree_levels(ptvcursor_t * ptvc)
+{
+  subtree_lvl * pushed_tree;
+
+  DISSECTOR_ASSERT(ptvc->pushed_tree_max <= SUBTREE_MAX_LEVELS-SUBTREE_ONCE_ALLOCATION_NUMBER);
+  ptvc->pushed_tree_max += SUBTREE_ONCE_ALLOCATION_NUMBER;
+
+  pushed_tree = ep_alloc(sizeof(subtree_lvl) * ptvc->pushed_tree_max);
+  DISSECTOR_ASSERT(pushed_tree != NULL);
+  if (ptvc->pushed_tree)
+    memcpy(pushed_tree, ptvc->pushed_tree, ptvc->pushed_tree_max - SUBTREE_ONCE_ALLOCATION_NUMBER);
+  ptvc->pushed_tree = pushed_tree;
+}
+
+void ptvcursor_free_subtree_levels(ptvcursor_t * ptvc)
+{
+  ptvc->pushed_tree = NULL;
+  ptvc->pushed_tree_max = 0;
+  DISSECTOR_ASSERT(ptvc->pushed_tree_index ==0);
+  ptvc->pushed_tree_index = 0;
 }
 
 /* Allocates an initializes a ptvcursor_t with 3 variables:
@@ -608,18 +688,23 @@ ptvcursor_new(proto_tree *tree, tvbuff_t *tvb, gint offset)
 {
        ptvcursor_t     *ptvc;
 
-       ptvc = g_new(ptvcursor_t, 1);
+       ptvc = ep_alloc(sizeof(ptvcursor_t));
        ptvc->tree      = tree;
        ptvc->tvb       = tvb;
        ptvc->offset    = offset;
+       ptvc->pushed_tree= NULL;
+       ptvc->pushed_tree_max= 0;
+       ptvc->pushed_tree_index= 0;
        return ptvc;
 }
 
+
 /* Frees memory for ptvcursor_t, but nothing deeper than that. */
 void
 ptvcursor_free(ptvcursor_t *ptvc)
 {
-       g_free(ptvc);
+       ptvcursor_free_subtree_levels(ptvc);
+       /*g_free(ptvc);*/
 }
 
 /* Returns tvbuff. */
@@ -639,7 +724,10 @@ ptvcursor_current_offset(ptvcursor_t* ptvc)
 proto_tree*
 ptvcursor_tree(ptvcursor_t* ptvc)
 {
-       return ptvc->tree;
+  if (!ptvc)
+    return NULL;
+
+  return ptvc->tree;
 }
 
 void
@@ -648,6 +736,102 @@ ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree)
        ptvc->tree = tree;
 }
 
+/* creates a subtree, sets it as the working tree and pushes the old working tree */
+proto_tree*
+ptvcursor_push_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree)
+{
+  subtree_lvl * subtree;
+  if (ptvc->pushed_tree_index >= ptvc->pushed_tree_max)
+    ptvcursor_new_subtree_levels(ptvc);
+
+  subtree = ptvc->pushed_tree+ptvc->pushed_tree_index;
+  subtree->tree = ptvc->tree;
+  subtree->it= NULL;
+  ptvc->pushed_tree_index++;
+  return ptvcursor_set_subtree(ptvc, it, ett_subtree);
+}
+
+/* pops a subtree */
+void
+ptvcursor_pop_subtree(ptvcursor_t *ptvc)
+{
+  subtree_lvl * subtree;
+  if (ptvc->pushed_tree_index <= 0)
+    return;
+
+  ptvc->pushed_tree_index--;
+  subtree = ptvc->pushed_tree+ptvc->pushed_tree_index;
+  if (subtree->it != NULL)
+    proto_item_set_len(subtree->it, ptvcursor_current_offset(ptvc) - subtree->cursor_offset);
+  ptvc->tree = subtree->tree;
+}
+
+/* saves the current tvb offset and the item in the current subtree level */
+void ptvcursor_subtree_set_item(ptvcursor_t * ptvc, proto_item * it)
+{
+  subtree_lvl * subtree;
+
+  DISSECTOR_ASSERT(ptvc->pushed_tree_index > 0);
+
+  subtree = ptvc->pushed_tree+ptvc->pushed_tree_index-1;
+  subtree->it = it;
+  subtree->cursor_offset = ptvcursor_current_offset(ptvc);
+}
+
+/* Creates a subtree and adds it to the cursor as the working tree but does not
+ * save the old working tree */
+proto_tree*
+ptvcursor_set_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree)
+{
+  ptvc->tree = proto_item_add_subtree(it, ett_subtree);
+  return ptvc->tree;
+}
+
+proto_tree* ptvcursor_add_subtree_item(ptvcursor_t * ptvc, proto_item * it, gint ett_subtree, gint length)
+{
+  ptvcursor_push_subtree(ptvc, it, ett_subtree);
+  if (length == SUBTREE_UNDEFINED_LENGTH)
+    ptvcursor_subtree_set_item(ptvc, it);
+  return ptvcursor_tree(ptvc);
+}
+
+/* Add an item to the tree and create a subtree
+ * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH.
+ * In this case, when the subtree will be closed, the parent item length will
+ * be equal to the advancement of the cursor since the creation of the subtree.
+ */
+proto_tree* ptvcursor_add_with_subtree(ptvcursor_t * ptvc, int hfindex, gint length,
+gboolean little_endian, gint ett_subtree)
+{
+  proto_item * it;
+  it = ptvcursor_add_no_advance(ptvc, hfindex, length, little_endian);
+  return ptvcursor_add_subtree_item(ptvc, it, ett_subtree, length);
+}
+
+static proto_item *
+proto_tree_add_text_node(proto_tree *tree, tvbuff_t *tvb, gint start, gint length);
+
+/* Add a text node to the tree and create a subtree
+ * If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH.
+ * In this case, when the subtree will be closed, the item length will be equal
+ * to the advancement of the cursor since the creation of the subtree.
+ */
+proto_tree * ptvcursor_add_text_with_subtree(ptvcursor_t * ptvc, gint length,
+    gint ett_subtree, const char *format, ...)
+{
+  proto_item * it;
+  va_list      ap;
+
+  it = proto_tree_add_text_node(ptvcursor_tree(ptvc), ptvcursor_tvbuff(ptvc),
+      ptvcursor_current_offset(ptvc), length);
+
+  va_start(ap, format);
+  proto_tree_set_representation(it, format, ap);
+  va_end(ap);
+
+  return ptvcursor_add_subtree_item(ptvc, it, ett_subtree, length);
+}
+
 /* 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)
@@ -706,11 +890,10 @@ proto_tree_add_debug_text(proto_tree *tree, const char *format, ...)
        va_list         ap;
 
        pi = proto_tree_add_text_node(tree, NULL, 0, 0);
-       if (pi == NULL)
-               return(NULL);
 
        va_start(ap, format);
-       proto_tree_set_representation(pi, format, ap);
+       if (pi)
+               proto_tree_set_representation(pi, format, ap);
        vprintf(format, ap);
        va_end(ap);
        printf("\n");
@@ -746,7 +929,7 @@ get_uint_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
                break;
 
        default:
-               THROW(ReportedBoundsError);
+               DISSECTOR_ASSERT_NOT_REACHED();
                value = 0;
                break;
        }
@@ -784,7 +967,7 @@ get_int_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
                break;
 
        default:
-               THROW(ReportedBoundsError);
+               DISSECTOR_ASSERT_NOT_REACHED();
                value = 0;
                break;
        }
@@ -865,8 +1048,8 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, int hfindex,
 
                case FT_INT64:
                case FT_UINT64:
-                       DISSECTOR_ASSERT(length == 8);
-                       proto_tree_set_uint64_tvb(new_fi, tvb, start, little_endian);
+                       DISSECTOR_ASSERT( length <= 8 && length >= 1);
+                       proto_tree_set_uint64_tvb(new_fi, tvb, start, length, little_endian);
                        break;
 
                /* XXX - make these just FT_INT? */
@@ -902,7 +1085,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, int hfindex,
 
                case FT_GUID:
                        DISSECTOR_ASSERT(length == 16);
-                       proto_tree_set_guid_tvb(new_fi, tvb, start);
+                       proto_tree_set_guid_tvb(new_fi, tvb, start, little_endian);
                        break;
 
                case FT_OID:
@@ -928,7 +1111,6 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, int hfindex,
                        break;
 
                case FT_STRING:
-                       /* This g_strdup'ed memory is freed in proto_tree_free_node() */
                        proto_tree_set_string_tvb(new_fi, tvb, start, length);
                        break;
 
@@ -947,13 +1129,11 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, int hfindex,
                                /* 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);
+                               string = ep_alloc(length);
 
                                tvb_memcpy(tvb, string, start, length);
                        } else if (length == 0) {
-                               string = g_strdup("[Empty]");
+                               string = "[Empty]";
                        } else {
                                /* In this case, length signifies
                                 * the length of the string.
@@ -986,18 +1166,19 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, int hfindex,
                                 * 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);
+                               string = tvb_get_ephemeral_string(tvb,
+                                                                         start,
+                                                                         length);
                        }
                        new_fi->length = length;
-                       proto_tree_set_string(new_fi, string, TRUE);
+                       proto_tree_set_string(new_fi, string);
+                       break;
+
+               case FT_EBCDIC:
+                       proto_tree_set_ebcdic_string_tvb(new_fi, tvb, start, length);
                        break;
 
                case FT_UINT_STRING:
-                       /* This g_strdup'ed memory is freed in proto_tree_free_node() */
                        n = get_uint_value(tvb, start, length, little_endian);
                        proto_tree_set_string_tvb(new_fi, tvb, start + length, n);
 
@@ -1033,6 +1214,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree, int hfindex,
        /* If the proto_tree wants to keep a record of this finfo
         * for quick lookup, then record it. */
        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) {
@@ -1289,6 +1471,8 @@ proto_tree_set_bytes(field_info *fi, const guint8* start_ptr, gint length)
        if (length > 0) {
                g_byte_array_append(bytes, start_ptr, length);
        }
+       col_custom_set_fstr(fi->hfinfo, "%s", bytes_to_str(bytes->data,
+                                                                  length));
        fvalue_set(&fi->value, bytes, TRUE);
 }
 
@@ -1379,7 +1563,16 @@ 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)
 {
+       header_field_info       *hfinfo;
+
        DISSECTOR_ASSERT(value_ptr != NULL);
+       hfinfo = fi->hfinfo;
+
+       if (hfinfo->type == FT_ABSOLUTE_TIME) {
+               col_custom_set_fstr(fi->hfinfo, "%s", abs_time_to_str(value_ptr));
+       } else if (hfinfo->type == FT_RELATIVE_TIME) {
+               col_custom_set_fstr(fi->hfinfo, "%s", rel_time_to_secs_str(value_ptr));
+       }
        fvalue_set(&fi->value, value_ptr, FALSE);
 }
 
@@ -1461,7 +1654,7 @@ proto_tree_add_ipxnet_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
 static void
 proto_tree_set_ipxnet(field_info *fi, guint32 value)
 {
-       fvalue_set_integer(&fi->value, value);
+       fvalue_set_uinteger(&fi->value, value);
 }
 
 /* Add a FT_IPv4 to a proto_tree */
@@ -1542,7 +1735,9 @@ proto_tree_add_ipv4_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
 static void
 proto_tree_set_ipv4(field_info *fi, guint32 value)
 {
-       fvalue_set_integer(&fi->value, value);
+       col_custom_set_fstr(fi->hfinfo, "%s",
+                           ip_to_str((guint8 *)&value));
+       fvalue_set_uinteger(&fi->value, value);
 }
 
 /* Add a FT_IPv6 to a proto_tree */
@@ -1637,7 +1832,7 @@ proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start)
 /* Add a FT_GUID to a proto_tree */
 proto_item *
 proto_tree_add_guid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
-               const guint8* value_ptr)
+               const e_guid_t *value_ptr)
 {
        proto_item              *pi;
        field_info              *new_fi;
@@ -1659,7 +1854,7 @@ proto_tree_add_guid(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gi
 
 proto_item *
 proto_tree_add_guid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
-               const guint8* value_ptr)
+               const e_guid_t *value_ptr)
 {
        proto_item              *pi;
 
@@ -1674,7 +1869,7 @@ proto_tree_add_guid_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
 
 proto_item *
 proto_tree_add_guid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
-               gint start, gint length, const guint8* value_ptr,
+               gint start, gint length, const e_guid_t *value_ptr,
                const char *format, ...)
 {
        proto_item              *pi;
@@ -1693,7 +1888,7 @@ proto_tree_add_guid_format_value(proto_tree *tree, int hfindex, tvbuff_t *tvb,
 
 proto_item *
 proto_tree_add_guid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length,
-               const guint8* value_ptr, const char *format, ...)
+               const e_guid_t *value_ptr, const char *format, ...)
 {
        proto_item              *pi;
        va_list                 ap;
@@ -1711,16 +1906,21 @@ proto_tree_add_guid_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
 
 /* Set the FT_GUID value */
 static void
-proto_tree_set_guid(field_info *fi, const guint8* value_ptr)
+proto_tree_set_guid(field_info *fi, const e_guid_t *value_ptr)
 {
        DISSECTOR_ASSERT(value_ptr != NULL);
+       col_custom_set_fstr(fi->hfinfo, "%s",
+                           guid_to_str(value_ptr));
        fvalue_set(&fi->value, (gpointer) value_ptr, FALSE);
 }
 
 static void
-proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start)
+proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian)
 {
-       proto_tree_set_guid(fi, tvb_get_ptr(tvb, start, 16));
+       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 */
@@ -1810,6 +2010,8 @@ proto_tree_set_oid(field_info *fi, const guint8* value_ptr, gint length)
        if (length > 0) {
                g_byte_array_append(bytes, value_ptr, length);
        }
+       col_custom_set_fstr(fi->hfinfo, "%s",
+                           oid_resolved_from_encoded(value_ptr, length));
        fvalue_set(&fi->value, bytes, TRUE);
 }
 
@@ -1822,16 +2024,45 @@ proto_tree_set_oid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length)
 static void
 proto_tree_set_uint64(field_info *fi, guint64 value)
 {
+       col_custom_set_fstr(fi->hfinfo, "%" G_GINT64_MODIFIER "u",
+                           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_tvb(field_info *fi, tvbuff_t *tvb, gint start,  guint length, gboolean little_endian)
+{
+       guint64 value = 0;
+       guint8* b = ep_tvb_memdup(tvb,start,length);
+
+       if(little_endian) {
+               b += length;
+               switch(length) {
+                       default: DISSECTOR_ASSERT_NOT_REACHED();
+                       case 8: value <<= 8; value += *--b;
+                       case 7: value <<= 8; value += *--b;
+                       case 6: value <<= 8; value += *--b;
+                       case 5: value <<= 8; value += *--b;
+                       case 4: value <<= 8; value += *--b;
+                       case 3: value <<= 8; value += *--b;
+                       case 2: value <<= 8; value += *--b;
+                       case 1: value <<= 8; value += *--b;
+                               break;
+               }
+       } else {
+               switch(length) {
+                       default: DISSECTOR_ASSERT_NOT_REACHED();
+                       case 8: value <<= 8; value += *b++;
+                       case 7: value <<= 8; value += *b++;
+                       case 6: value <<= 8; value += *b++;
+                       case 5: value <<= 8; value += *b++;
+                       case 4: value <<= 8; value += *b++;
+                       case 3: value <<= 8; value += *b++;
+                       case 2: value <<= 8; value += *b++;
+                       case 1: value <<= 8; value += *b++;
+                               break;
+               }
+       }
 
        proto_tree_set_uint64(fi, value);
 }
@@ -1856,7 +2087,7 @@ proto_tree_add_string(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
 
        pi = proto_tree_add_pi(tree, hfindex, tvb, start, &length, &new_fi);
        DISSECTOR_ASSERT(length >= 0);
-       proto_tree_set_string(new_fi, value, FALSE);
+       proto_tree_set_string(new_fi, value);
 
        return pi;
 }
@@ -1917,15 +2148,15 @@ 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() 
+/* 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 
+ * 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 
+ * 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)
+ * Do that by faking that the tree is visible by calling
+ * proto_tree_set_visible(tree, TRUE) (see packet-wsp.c)
  * BEFORE you create the item you are later going to use
  * proto_item_append_string() on.
  */
@@ -1949,19 +2180,22 @@ proto_item_append_string(proto_item *pi, const char *str)
        }
        DISSECTOR_ASSERT(hfinfo->type == FT_STRING || hfinfo->type == FT_STRINGZ);
        old_str = fvalue_get(&fi->value);
-       new_str = g_strdup_printf("%s%s", old_str, str);
-       fvalue_set(&fi->value, new_str, TRUE);
+       new_str = ep_strdup_printf("%s%s", old_str, str);
+       fvalue_set(&fi->value, new_str, FALSE);
 }
 
 /* Set the FT_STRING value */
 static void
-proto_tree_set_string(field_info *fi, const char* value,
-               gboolean already_allocated)
+proto_tree_set_string(field_info *fi, const char* value)
 {
-       if (value)
-               fvalue_set(&fi->value, (gpointer) value, already_allocated);
-       else
-               fvalue_set(&fi->value, (gpointer) "[ Null ]", already_allocated);
+       if (value) {
+               col_custom_set_fstr(fi->hfinfo, "%s",
+                                   format_text(value, strlen(value)));
+               fvalue_set(&fi->value, (gpointer) value, FALSE);
+       } else {
+               col_custom_set_fstr(fi->hfinfo, "[ Null ]");
+               fvalue_set(&fi->value, (gpointer) "[ Null ]", FALSE);
+       }
 }
 
 static void
@@ -1973,9 +2207,22 @@ proto_tree_set_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length
                length = tvb_ensure_length_remaining(tvb, start);
        }
 
-       /* This memory is freed in proto_tree_free_node() */
-       string = tvb_get_string(tvb, start, length);
-       proto_tree_set_string(fi, string, TRUE);
+       string = tvb_get_ephemeral_string(tvb, start, length);
+       proto_tree_set_string(fi, string);
+}
+
+static void
+proto_tree_set_ebcdic_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length)
+{
+       gchar   *string;
+
+       if (length == -1) {
+               length = tvb_ensure_length_remaining(tvb, start);
+       }
+
+       string = tvb_get_ephemeral_string(tvb, start, length);
+       EBCDIC_to_ASCII(string, length);
+       proto_tree_set_string(fi, string);
 }
 
 /* Add a FT_ETHER to a proto_tree */
@@ -2057,6 +2304,7 @@ proto_tree_add_ether_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s
 static void
 proto_tree_set_ether(field_info *fi, const guint8* value)
 {
+       col_custom_set_fstr(fi->hfinfo, "%s", bytes_to_str_punct(value, 6, ':'));
        fvalue_set(&fi->value, (gpointer) value, FALSE);
 }
 
@@ -2226,6 +2474,8 @@ proto_tree_add_float_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s
 static void
 proto_tree_set_float(field_info *fi, float value)
 {
+       col_custom_set_fstr(fi->hfinfo, "%." STRINGIFY(FLT_DIG) "f",
+                           value);
        fvalue_set_floating(&fi->value, value);
 }
 
@@ -2307,6 +2557,8 @@ proto_tree_add_double_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
 static void
 proto_tree_set_double(field_info *fi, double value)
 {
+       col_custom_set_fstr(fi->hfinfo, "%." STRINGIFY(DBL_DIG) "g",
+                           value);
        fvalue_set_floating(&fi->value, value);
 }
 
@@ -2413,7 +2665,21 @@ proto_tree_set_uint(field_info *fi, guint32 value)
                        integer >>= hfinfo->bitshift;
                }
        }
-       fvalue_set_integer(&fi->value, integer);
+
+       if (hfinfo->type == FT_BOOLEAN) {
+               const true_false_string  *tfstring = &tfs_true_false;
+               if (hfinfo->strings) {
+                       tfstring = (const struct true_false_string*) hfinfo->strings;
+               }
+               col_custom_set_fstr(fi->hfinfo, "%s", value ? tfstring->true_string : tfstring->false_string);
+       } else if (hfinfo->strings) {
+               col_custom_set_fstr(fi->hfinfo, "%s", val_to_str(integer, cVALS(hfinfo->strings), "%d"));
+       } else if (IS_BASE_DUAL(hfinfo->display)) {
+               col_custom_set_fstr(fi->hfinfo, hfinfo_uint_value_format(hfinfo), integer, integer);
+       } else {
+               col_custom_set_fstr(fi->hfinfo, hfinfo_uint_value_format(hfinfo), integer);
+       }
+       fvalue_set_uinteger(&fi->value, integer);
 }
 
 /* Add FT_UINT64 to a proto_tree */
@@ -2577,7 +2843,15 @@ proto_tree_set_int(field_info *fi, gint32 value)
                        integer >>= hfinfo->bitshift;
                }
        }
-       fvalue_set_integer(&fi->value, integer);
+
+       if (hfinfo->strings) {
+               col_custom_set_fstr(fi->hfinfo, "%s", val_to_str(integer, cVALS(hfinfo->strings), "%d"));
+       } else if (IS_BASE_DUAL(hfinfo->display)) {
+               col_custom_set_fstr(fi->hfinfo, hfinfo_int_value_format(hfinfo), integer, integer);
+       } else {
+               col_custom_set_fstr(fi->hfinfo, hfinfo_int_value_format(hfinfo), integer);
+       }
+       fvalue_set_sinteger(&fi->value, integer);
 }
 
 /* Add FT_INT64 to a proto_tree */
@@ -2639,7 +2913,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)
@@ -2667,6 +2943,14 @@ proto_tree_add_node(proto_tree *tree, field_info *fi)
        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;
@@ -2705,6 +2989,7 @@ 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. */
        if (fi->hfinfo->ref_count) {
+               /*HERE*/
                hash = PTREE_DATA(tree)->interesting_hfids;
                ptrs = g_hash_table_lookup(hash, GINT_TO_POINTER(hfindex));
                if (ptrs) {
@@ -2835,7 +3120,7 @@ get_hfi_and_length(int hfindex, tvbuff_t *tvb, gint start, gint *length,
                         * 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
-                        * Ethereal, we don't highlight stuff past
+                        * Wireshark, we don't highlight stuff past
                         * the end of the data.
                         */
                        /* XXX - what to do, if we don't have a tvb? */
@@ -2877,6 +3162,9 @@ new_field_info(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb,
        /* add the data source tvbuff */
        fi->ds_tvb=tvb?TVB_GET_DS_TVB(tvb):NULL;
 
+       fi->appendix_start = 0;
+       fi->appendix_length = 0;
+
        return fi;
 }
 
@@ -2973,6 +3261,9 @@ proto_item_append_text(proto_item *pi, const char *format, ...)
        }
 
        fi = PITEM_FINFO(pi);
+       if (fi==NULL) {
+               return;
+       }
 
        if (!PROTO_ITEM_IS_HIDDEN(pi)) {
                va_start(ap, format);
@@ -3007,6 +3298,9 @@ proto_item_set_len(proto_item *pi, gint length)
        fi = PITEM_FINFO(pi);
        DISSECTOR_ASSERT(length >= 0);
        fi->length = length;
+
+       if (fi->value.ftype->ftype == FT_BYTES)
+               fi->value.value.bytes->len = length;
 }
 
 /*
@@ -3043,8 +3337,8 @@ proto_item_get_len(proto_item *pi)
        (fi->flags = (fi)->flags | (flags_in)); \
 }
 
-gboolean 
-proto_item_set_expert_flags(proto_item *pi, int group, int severity)
+gboolean
+proto_item_set_expert_flags(proto_item *pi, int group, guint severity)
 {
        if(pi == NULL || pi->finfo == NULL)
                return FALSE;
@@ -3083,6 +3377,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;
 }
 
@@ -3141,16 +3438,14 @@ proto_item_get_subtree(proto_item *pi) {
 
 proto_item*
 proto_item_get_parent(proto_item *ti) {
-       /* dont bother if tree is not visible */
-       if( (!ti) || (!(PTREE_DATA(ti)->visible)) )
+       if (!ti)
                return (NULL);
        return ti->parent;
 }
 
 proto_item*
 proto_item_get_parent_nth(proto_item *ti, int gen) {
-       /* dont bother if tree is not visible */
-       if( (!ti) || (!(PTREE_DATA(ti)->visible)) )
+       if (!ti)
                return (NULL);
        while (gen--) {
                ti = ti->parent;
@@ -3161,14 +3456,22 @@ proto_item_get_parent_nth(proto_item *ti, int gen) {
 }
 
 
-proto_item* 
+proto_item*
 proto_tree_get_parent(proto_tree *tree) {
-       /* dont bother if tree is not visible */
-       if( (!tree) || (!(PTREE_DATA(tree)->visible)) )
+       if (!tree)
                return (NULL);
        return (proto_item*) tree;
 }
 
+proto_tree*
+proto_tree_get_root(proto_tree *tree) {
+       if (!tree)
+               return (NULL);
+       while (tree->parent) {
+               tree = tree->parent;
+       }
+       return tree;
+}
 
 void
 proto_tree_move_item(proto_tree *tree, proto_item *fixed_item, proto_item *item_to_move)
@@ -3197,7 +3500,7 @@ proto_tree_move_item(proto_tree *tree, proto_item *fixed_item, proto_item *item_
         /* fix last_child if required */
         if(tree->last_child == item_to_move) {
             tree->last_child = curr_item;
-        } 
+        }
     }
 
     /*** insert to_move after fixed ***/
@@ -3208,6 +3511,22 @@ proto_tree_move_item(proto_tree *tree, proto_item *fixed_item, proto_item *item_
     }
 }
 
+void
+proto_tree_set_appendix(proto_tree *tree, tvbuff_t *tvb, gint start, gint length)
+{
+       field_info *fi;
+
+       if (tree == NULL)
+               return;
+
+       fi = tree->finfo;
+       start += TVB_RAW_OFFSET(tvb);
+       DISSECTOR_ASSERT(start >= 0);
+       DISSECTOR_ASSERT(length >= 0);
+
+       fi->appendix_start = start;
+       fi->appendix_length = length;
+}
 
 int
 proto_register_protocol(const char *name, const char *short_name, const char *filter_name)
@@ -3231,14 +3550,14 @@ proto_register_protocol(const char *name, const char *short_name, const char *fi
      * 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, 
+     * 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);
+    *key = wrs_str_hash(name);
     existing_name = g_hash_table_lookup(proto_names, key);
     if (existing_name != NULL) {
         /* g_error will terminate the program */
@@ -3247,14 +3566,12 @@ proto_register_protocol(const char *name, const char *short_name, const char *fi
     }
     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);
+    existing_name = g_hash_table_lookup(proto_short_names, (gpointer)short_name);
     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);
+    g_hash_table_insert(proto_short_names, (gpointer)short_name, (gpointer)short_name);
 
     found_invalid = FALSE;
     for (i = 0; i < strlen(filter_name); i++) {
@@ -3268,14 +3585,12 @@ proto_register_protocol(const char *name, const char *short_name, const char *fi
             " 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);
+    existing_name = g_hash_table_lookup(proto_filter_names, (gpointer)filter_name);
     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);
+    g_hash_table_insert(proto_filter_names, (gpointer)filter_name, (gpointer)filter_name);
 
     /* Add this protocol to the list of known protocols; the list
        is sorted by protocol short name. */
@@ -3287,7 +3602,7 @@ proto_register_protocol(const char *name, const char *short_name, const char *fi
     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);
+    protocols = g_list_prepend(protocols, protocol);
 
     /* Here we do allocate a new header_field_info struct */
     hfinfo = g_mem_chunk_alloc(gmc_hfinfo);
@@ -3401,8 +3716,13 @@ int proto_get_id_by_filter_name(const gchar* filter_name)
        GList *list_entry;
        protocol_t *protocol;
 
+#if GLIB_MAJOR_VERSION < 2
+       list_entry = g_list_find_custom(protocols, discard_const(filter_name),
+           compare_filter_name);
+#else
        list_entry = g_list_find_custom(protocols, filter_name,
            compare_filter_name);
+#endif
        if (list_entry == NULL)
                return -1;
        protocol = list_entry->data;
@@ -3432,6 +3752,8 @@ proto_get_protocol_filter_name(int proto_id)
        protocol_t *protocol;
 
        protocol = find_protocol_by_id(proto_id);
+       if (protocol == NULL)
+               return "(none)";
        return protocol->filter_name;
 }
 
@@ -3460,6 +3782,23 @@ proto_set_decoding(int proto_id, gboolean enabled)
        protocol->is_enabled = enabled;
 }
 
+void
+proto_enable_all(void)
+{
+       protocol_t *protocol;
+       GList *list_item = protocols;
+
+       if (protocols == NULL)
+               return;
+
+       while (list_item) {
+               protocol = list_item->data;
+               if (protocol->can_toggle)
+                       protocol->is_enabled = TRUE;
+               list_item = g_list_next(list_item);
+       }
+}
+
 void
 proto_set_cant_toggle(int proto_id)
 {
@@ -3509,11 +3848,33 @@ proto_register_field_array(int parent, hf_register_info *hf, int num_records)
        }
 }
 
-static int
-proto_register_field_init(header_field_info *hfinfo, int parent)
-{
-       /* The field must have names */
-       DISSECTOR_ASSERT(hfinfo->name);
+/* chars allowed in field abbrev */
+static
+const guchar fld_abbrev_chars[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x0F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x1F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, /* 0x20-0x2F '-', '.'     */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30-0x3F '0'-'9'      */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40-0x4F 'A'-'O'      */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50-0x5F 'P'-'Z', '_' */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60-0x6F 'a'-'o'      */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x70-0x7F 'p'-'z'      */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0-0xAF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0-0xBF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0-0xCF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0-0xDF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0-0xEF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0-0xFF */
+};
+
+/* temporary function containing assert part for easier profiling */
+static void tmp_fld_check_assert(header_field_info *hfinfo) {
+       /* The field must have a name (with length > 0) */
+       DISSECTOR_ASSERT(hfinfo->name && hfinfo->name[0]);
+
+       /* fields with an empty string for an abbreviation aren't filterable */
        DISSECTOR_ASSERT(hfinfo->abbrev);
 
        /* These types of fields are allowed to have value_strings, true_false_strings or a protocol_t struct*/
@@ -3554,10 +3915,17 @@ proto_register_field_init(header_field_info *hfinfo, int parent)
        default:
                break;
        }
+}
+
+static int
+proto_register_field_init(header_field_info *hfinfo, int parent)
+{
+
+       tmp_fld_check_assert(hfinfo);
+
        /* if this is a bitfield, compute bitshift */
        if (hfinfo->bitmask) {
-               while ((hfinfo->bitmask & (1 << hfinfo->bitshift)) == 0)
-                       hfinfo->bitshift++;
+               hfinfo->bitshift = wrs_count_bitshift(hfinfo->bitmask);
        }
 
        hfinfo->parent = parent;
@@ -3581,19 +3949,17 @@ proto_register_field_init(header_field_info *hfinfo, int parent)
        /* if we have real names, enter this field in the name tree */
        if ((hfinfo->name[0] != 0) && (hfinfo->abbrev[0] != 0 )) {
 
-               header_field_info *same_name_hfinfo, *same_name_next_hfinfo;
-               const char *p;
+               header_field_info *same_name_next_hfinfo;
                guchar c;
 
                /* Check that the filter name (abbreviation) is legal;
                 * it must contain only alphanumerics, '-', "_", and ".". */
-               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 == '.');
-                       }
+               c = wrs_check_charset(fld_abbrev_chars, hfinfo->abbrev);
+               if (c) {
+                       fprintf(stderr, "OOPS: '%c' in '%s'\n", c, hfinfo->abbrev);
+                       DISSECTOR_ASSERT(!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,
@@ -3601,7 +3967,15 @@ proto_register_field_init(header_field_info *hfinfo, int parent)
                 * a byte, and we want to be able to refer to that field
                 * with one name regardless of whether the packets
                 * are modulo-8 or modulo-128 packets. */
-               same_name_hfinfo = g_tree_lookup(gpa_name_tree, hfinfo->abbrev);
+#if GLIB_MAJOR_VERSION < 2
+               same_name_hfinfo = g_tree_lookup(gpa_name_tree, discard_const(hfinfo->abbrev));
+#else
+               same_name_hfinfo = NULL;
+#endif
+               g_tree_insert(gpa_name_tree, (gpointer) (hfinfo->abbrev), hfinfo);
+               /* GLIB 2.x - if it is already present
+         * the previous hfinfo with the same name is saved
+         * to same_name_hfinfo by value destroy callback */
                if (same_name_hfinfo) {
                        /* There's already a field with this name.
                         * Put it after that field in the list of
@@ -3620,7 +3994,6 @@ 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, (gpointer) (hfinfo->abbrev), hfinfo);
        }
 
        return hfinfo->id;
@@ -3669,6 +4042,7 @@ 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 */
@@ -3787,7 +4161,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        break;
 
                case FT_IPXNET:
-                       integer = fvalue_get_integer(&fi->value);
+                       integer = fvalue_get_uinteger(&fi->value);
                        ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                "%s: %s (0x%08X)", hfinfo->name,
                                get_ipxnet_name(integer), integer);
@@ -3827,25 +4201,25 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                        break;
 
                case FT_GUID:
-                       bytes = fvalue_get(&fi->value);
+                       guid = fvalue_get(&fi->value);
                        ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                "%s: %s", hfinfo->name,
-                                guid_to_str(bytes));
+                                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;
+                       name = oid_resolved_from_encoded(bytes, fvalue_length(&fi->value));
                        if (name) {
                                ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                        "%s: %s (%s)", hfinfo->name,
-                                        oid_to_str(bytes, fvalue_length(&fi->value)), name);
+                                        oid_encoded2string(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)));
+                                        oid_encoded2string(bytes, fvalue_length(&fi->value)));
                        }
                        if ((ret == -1) || (ret >= ITEM_LABEL_LENGTH))
                                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
@@ -3853,9 +4227,10 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
 
                case FT_STRING:
                case FT_STRINGZ:
+               case FT_EBCDIC:
                case FT_UINT_STRING:
                        bytes = fvalue_get(&fi->value);
-            if(strlen(bytes) > ITEM_LABEL_LENGTH) {
+           if(strlen(bytes) > ITEM_LABEL_LENGTH) {
                            ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                    "%s [truncated]: %s", hfinfo->name,
                                    format_text(bytes, strlen(bytes)));
@@ -3887,14 +4262,13 @@ fill_label_boolean(field_info *fi, gchar *label_str)
        int                                     ret;    /*tmp return value */
 
        header_field_info               *hfinfo = fi->hfinfo;
-       static const true_false_string  default_tf = { "True", "False" };
-       const true_false_string         *tfstring = &default_tf;
+       const true_false_string         *tfstring = &tfs_true_false;
 
        if (hfinfo->strings) {
                tfstring = (const struct true_false_string*) hfinfo->strings;
        }
 
-       value = fvalue_get_integer(&fi->value);
+       value = fvalue_get_uinteger(&fi->value);
        if (hfinfo->bitmask) {
                /* Figure out the bit width */
                bitwidth = hfinfo_bitwidth(hfinfo);
@@ -3939,7 +4313,7 @@ fill_label_enumerated_bitfield(field_info *fi, gchar *label_str)
        format = hfinfo_uint_vals_format(hfinfo);
 
        /* Un-shift bits */
-       unshifted_value = fvalue_get_integer(&fi->value);
+       unshifted_value = fvalue_get_uinteger(&fi->value);
        value = unshifted_value;
        if (hfinfo->bitshift > 0) {
                unshifted_value <<= hfinfo->bitshift;
@@ -3976,7 +4350,7 @@ fill_label_numeric_bitfield(field_info *fi, gchar *label_str)
        format = hfinfo_uint_format(hfinfo);
 
        /* Un-shift bits */
-       unshifted_value = fvalue_get_integer(&fi->value);
+       unshifted_value = fvalue_get_uinteger(&fi->value);
        value = unshifted_value;
        if (hfinfo->bitshift > 0) {
                unshifted_value <<= hfinfo->bitshift;
@@ -4010,12 +4384,18 @@ fill_label_enumerated_uint(field_info *fi, gchar *label_str)
        /* Pick the proper format string */
        format = hfinfo_uint_vals_format(hfinfo);
 
-       value = fvalue_get_integer(&fi->value);
+       value = fvalue_get_uinteger(&fi->value);
 
        /* Fill in the textual info */
-       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+       if (hfinfo->display & BASE_RANGE_STRING) {
+         ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                       format,  hfinfo->name,
+                       rval_to_str(value, hfinfo->strings, "Unknown"), value);
+       } else {
+         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))
                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
 }
@@ -4030,7 +4410,7 @@ fill_label_uint(field_info *fi, gchar *label_str)
 
        /* Pick the proper format string */
        format = hfinfo_uint_format(hfinfo);
-       value = fvalue_get_integer(&fi->value);
+       value = fvalue_get_uinteger(&fi->value);
 
        /* Fill in the textual info */
        if (IS_BASE_DUAL(hfinfo->display)) {
@@ -4078,12 +4458,18 @@ fill_label_enumerated_int(field_info *fi, gchar *label_str)
 
        /* Pick the proper format string */
        format = hfinfo_int_vals_format(hfinfo);
-       value = fvalue_get_integer(&fi->value);
+       value = fvalue_get_sinteger(&fi->value);
 
        /* Fill in the textual info */
-       ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+       if (hfinfo->display & BASE_RANGE_STRING) {
+         ret = g_snprintf(label_str, ITEM_LABEL_LENGTH,
+                       format,  hfinfo->name,
+                       rval_to_str(value, hfinfo->strings, "Unknown"), value);
+       } else {
+         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))
                label_str[ITEM_LABEL_LENGTH - 1] = '\0';
 }
@@ -4098,7 +4484,7 @@ fill_label_int(field_info *fi, gchar *label_str)
 
        /* Pick the proper format string */
        format = hfinfo_int_format(hfinfo);
-       value = fvalue_get_integer(&fi->value);
+       value = fvalue_get_sinteger(&fi->value);
 
        /* Fill in the textual info */
        if (IS_BASE_DUAL(hfinfo->display)) {
@@ -4177,7 +4563,9 @@ hfinfo_uint_vals_format(header_field_info *hfinfo)
 {
        const char *format = NULL;
 
-       switch(hfinfo->display) {
+       /* bit operation to reset the potential BASE_RANGE_STRING (or others in
+        * the future?) */
+       switch(hfinfo->display & BASE_STRUCTURE_RESET) {
                case BASE_DEC:
                case BASE_DEC_HEX:
                        format = "%s: %s (%u)";
@@ -4297,72 +4685,158 @@ hfinfo_uint_format(header_field_info *hfinfo)
 }
 
 static const char*
-hfinfo_int_vals_format(header_field_info *hfinfo)
-{
-       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)";
-                                       break;
-                               case FT_INT16:
-                                       format = "%s: %s (0x%04x)";
-                                       break;
-                               case FT_INT24:
-                                       format = "%s: %s (0x%06x)";
-                                       break;
-                               case FT_INT32:
-                                       format = "%s: %s (0x%08x)";
-                                       break;
-                               default:
-                                       DISSECTOR_ASSERT_NOT_REACHED();
-                                       ;
-                       }
-                       break;
-               default:
-                       DISSECTOR_ASSERT_NOT_REACHED();
-                       ;
-       }
-       return format;
-}
-
-static const char*
-hfinfo_uint64_format(header_field_info *hfinfo)
+hfinfo_uint_value_format(header_field_info *hfinfo)
 {
        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:
-                       DISSECTOR_ASSERT_NOT_REACHED();
-                       ;
-       }
-       return format;
+       if (hfinfo->type == FT_FRAMENUM) {
+               /*
+                * Frame numbers are always displayed in decimal.
+                */
+               format = "%u";
+       } else {
+               switch(hfinfo->display) {
+                       case BASE_DEC:
+                               format = "%u";
+                               break;
+                       case BASE_DEC_HEX:
+                               switch(hfinfo->type) {
+                                       case FT_UINT8:
+                                               format = "%u (0x%02x)";
+                                               break;
+                                       case FT_UINT16:
+                                               format = "%u (0x%04x)";
+                                               break;
+                                       case FT_UINT24:
+                                               format = "%u (0x%06x)";
+                                               break;
+                                       case FT_UINT32:
+                                               format = "%u (0x%08x)";
+                                               break;
+                                       default:
+                                               DISSECTOR_ASSERT_NOT_REACHED();
+                                               ;
+                               }
+                               break;
+                       case BASE_OCT:
+                               format = "%o";
+                               break;
+                       case BASE_HEX:
+                               switch(hfinfo->type) {
+                                       case FT_UINT8:
+                                               format = "0x%02x";
+                                               break;
+                                       case FT_UINT16:
+                                               format = "0x%04x";
+                                               break;
+                                       case FT_UINT24:
+                                               format = "0x%06x";
+                                               break;
+                                       case FT_UINT32:
+                                               format = "0x%08x";
+                                               break;
+                                       default:
+                                               DISSECTOR_ASSERT_NOT_REACHED();
+                                               ;
+                               }
+                               break;
+                       case BASE_HEX_DEC:
+                               switch(hfinfo->type) {
+                                       case FT_UINT8:
+                                               format = "0x%02x (%u)";
+                                               break;
+                                       case FT_UINT16:
+                                               format = "0x%04x (%u)";
+                                               break;
+                                       case FT_UINT24:
+                                               format = "0x%06x (%u)";
+                                               break;
+                                       case FT_UINT32:
+                                               format = "0x%08x (%u)";
+                                               break;
+                                       default:
+                                               DISSECTOR_ASSERT_NOT_REACHED();
+                                               ;
+                               }
+                               break;
+                       default:
+                               DISSECTOR_ASSERT_NOT_REACHED();
+                               ;
+               }
+       }
+       return format;
+}
+
+static const char*
+hfinfo_int_vals_format(header_field_info *hfinfo)
+{
+       const char *format = NULL;
+
+       /* bit operation to reset the potential BASE_RANGE_STRING (or others in
+        * the future?)*/
+       switch(hfinfo->display & BASE_STRUCTURE_RESET) {
+               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)";
+                                       break;
+                               case FT_INT16:
+                                       format = "%s: %s (0x%04x)";
+                                       break;
+                               case FT_INT24:
+                                       format = "%s: %s (0x%06x)";
+                                       break;
+                               case FT_INT32:
+                                       format = "%s: %s (0x%08x)";
+                                       break;
+                               default:
+                                       DISSECTOR_ASSERT_NOT_REACHED();
+                                       ;
+                       }
+                       break;
+               default:
+                       DISSECTOR_ASSERT_NOT_REACHED();
+                       ;
+       }
+       return format;
+}
+
+static const char*
+hfinfo_uint64_format(header_field_info *hfinfo)
+{
+       const char *format = NULL;
+
+       /* Pick the proper format string */
+       switch(hfinfo->display) {
+               case BASE_DEC:
+                       format = "%s: %" G_GINT64_MODIFIER "u";
+                       break;
+               case BASE_DEC_HEX:
+                       format = "%s: %" G_GINT64_MODIFIER "u (%" G_GINT64_MODIFIER "x)";
+                       break;
+               case BASE_OCT: /* I'm lazy */
+                       format = "%s: %" G_GINT64_MODIFIER "o";
+                       break;
+               case BASE_HEX:
+                       format = "%s: 0x%016" G_GINT64_MODIFIER "x";
+                       break;
+               case BASE_HEX_DEC:
+                       format = "%s: 0x%016" G_GINT64_MODIFIER "x (%" G_GINT64_MODIFIER "u)";
+                       break;
+               default:
+                       DISSECTOR_ASSERT_NOT_REACHED();
+                       ;
+       }
+       return format;
 }
 
 static const char*
@@ -4393,6 +4867,7 @@ hfinfo_int_format(header_field_info *hfinfo)
                                        DISSECTOR_ASSERT_NOT_REACHED();
                                        ;
                        }
+                       break;
                case BASE_OCT: /* I'm lazy */
                        format = "%s: %o";
                        break;
@@ -4414,6 +4889,7 @@ hfinfo_int_format(header_field_info *hfinfo)
                                        DISSECTOR_ASSERT_NOT_REACHED();
                                        ;
                        }
+                       break;
                case BASE_HEX_DEC:
                        switch(hfinfo->type) {
                                case FT_INT8:
@@ -4440,6 +4916,83 @@ hfinfo_int_format(header_field_info *hfinfo)
        return format;
 }
 
+static const char*
+hfinfo_int_value_format(header_field_info *hfinfo)
+{
+       const char *format = NULL;
+
+       /* Pick the proper format string */
+       switch(hfinfo->display) {
+               case BASE_DEC:
+                       format = "%d";
+                       break;
+               case BASE_DEC_HEX:
+                       switch(hfinfo->type) {
+                               case FT_INT8:
+                                       format = "%d (0x%02x)";
+                                       break;
+                               case FT_INT16:
+                                       format = "%d (0x%04x)";
+                                       break;
+                               case FT_INT24:
+                                       format = "%d (0x%06x)";
+                                       break;
+                               case FT_INT32:
+                                       format = "%d (0x%08x)";
+                                       break;
+                               default:
+                                       DISSECTOR_ASSERT_NOT_REACHED();
+                                       ;
+                       }
+                       break;
+               case BASE_OCT:
+                       format = "%o";
+                       break;
+               case BASE_HEX:
+                       switch(hfinfo->type) {
+                               case FT_INT8:
+                                       format = "0x%02x";
+                                       break;
+                               case FT_INT16:
+                                       format = "0x%04x";
+                                       break;
+                               case FT_INT24:
+                                       format = "0x%06x";
+                                       break;
+                               case FT_INT32:
+                                       format = "0x%08x";
+                                       break;
+                               default:
+                                       DISSECTOR_ASSERT_NOT_REACHED();
+                                       ;
+                       }
+                       break;
+               case BASE_HEX_DEC:
+                       switch(hfinfo->type) {
+                               case FT_INT8:
+                                       format = "0x%02x (%d)";
+                                       break;
+                               case FT_INT16:
+                                       format = "0x%04x (%d)";
+                                       break;
+                               case FT_INT24:
+                                       format = "0x%06x (%d)";
+                                       break;
+                               case FT_INT32:
+                                       format = "0x%08x (%d)";
+                                       break;
+                               default:
+                                       DISSECTOR_ASSERT_NOT_REACHED();
+                                       ;
+                       }
+                       break;
+               default:
+                       DISSECTOR_ASSERT_NOT_REACHED();
+                       ;
+       }
+       return format;
+}
+
 static const char*
 hfinfo_int64_format(header_field_info *hfinfo)
 {
@@ -4448,19 +5001,19 @@ hfinfo_int64_format(header_field_info *hfinfo)
        /* Pick the proper format string */
        switch(hfinfo->display) {
                case BASE_DEC:
-                       format = "%s: %" PRId64;
+                       format = "%s: %" G_GINT64_MODIFIER "d";
                        break;
                case BASE_DEC_HEX:
-                       format = "%s: %" PRId64 " (%" PRIx64 ")";
+                       format = "%s: %" G_GINT64_MODIFIER "d (%" G_GINT64_MODIFIER "x)";
                        break;
                case BASE_OCT: /* I'm lazy */
-                       format = "%s: %" PRIo64;
+                       format = "%s: %" G_GINT64_MODIFIER "o";
                        break;
                case BASE_HEX:
-                       format = "%s: 0x%016" PRIx64;
+                       format = "%s: 0x%016" G_GINT64_MODIFIER "x";
                        break;
                case BASE_HEX_DEC:
-                       format = "%s: 0x%016" PRIx64 " (%" PRId64 ")";
+                       format = "%s: 0x%016" G_GINT64_MODIFIER "x (%" G_GINT64_MODIFIER "d)";
                        break;
                default:
                        DISSECTOR_ASSERT_NOT_REACHED();
@@ -4568,12 +5121,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)
 {
@@ -4589,11 +5143,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)
 {
@@ -4605,7 +5159,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 {
@@ -4669,7 +5250,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)) {
@@ -4845,25 +5426,10 @@ proto_registrar_dump_fields(int format)
                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 */
@@ -4904,7 +5470,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";
@@ -4980,7 +5546,7 @@ hfinfo_numeric_format(header_field_info *hfinfo)
                                                format = "%s == %u";
                                                break;
                                        case FT_UINT64:
-                                               format = "%s == %" PRIu64;
+                                               format = "%s == %" G_GINT64_MODIFIER "u";
                                                break;
                                        case FT_INT8:
                                        case FT_INT16:
@@ -4989,7 +5555,7 @@ hfinfo_numeric_format(header_field_info *hfinfo)
                                                format = "%s == %d";
                                                break;
                                        case FT_INT64:
-                                               format = "%s == %" PRId64;
+                                               format = "%s == %" G_GINT64_MODIFIER "d";
                                                break;
                                        default:
                                                DISSECTOR_ASSERT_NOT_REACHED();
@@ -5012,7 +5578,7 @@ hfinfo_numeric_format(header_field_info *hfinfo)
                                                format = "%s == 0x%08x";
                                                break;
                                        case FT_UINT64:
-                                               format = "%s == 0x%016" PRIx64;
+                                               format = "%s == 0x%016" G_GINT64_MODIFIER "x";
                                                break;
                                        default:
                                                DISSECTOR_ASSERT_NOT_REACHED();
@@ -5027,115 +5593,27 @@ hfinfo_numeric_format(header_field_info *hfinfo)
        return format;
 }
 
-/*
- * Returns TRUE if we can do a "match selected" on the field, FALSE
- * otherwise.
- */
-gboolean
-proto_can_match_selected(field_info *finfo, epan_dissect_t *edt)
-{
-       header_field_info       *hfinfo;
-       gint                    length;
-
-       hfinfo = finfo->hfinfo;
-       DISSECTOR_ASSERT(hfinfo);
-
-       switch(hfinfo->type) {
-
-               case FT_BOOLEAN:
-               case FT_UINT8:
-               case FT_UINT16:
-               case FT_UINT24:
-               case FT_UINT32:
-               case FT_INT8:
-               case FT_INT16:
-               case FT_INT24:
-               case FT_INT32:
-               case FT_FRAMENUM:
-               case FT_UINT64:
-               case FT_INT64:
-               case FT_IPv4:
-               case FT_IPXNET:
-               case FT_IPv6:
-               case FT_FLOAT:
-               case FT_DOUBLE:
-               case FT_ABSOLUTE_TIME:
-               case FT_RELATIVE_TIME:
-               case FT_STRING:
-               case FT_STRINGZ:
-               case FT_UINT_STRING:
-               case FT_ETHER:
-               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;
-
-               default:
-                       /*
-                        * This doesn't have a value, so we'd match
-                        * on the raw bytes at this address.
-                        *
-                        * Should we be allowed to access to the raw bytes?
-                        * If "edt" is NULL, the answer is "no".
-                        */
-                       if (edt == NULL)
-                               return FALSE;
-
-                       /*
-                        * Is this field part of the raw frame tvbuff?
-                        * If not, we can't use "frame[N:M]" to match
-                        * it.
-                        *
-                        * XXX - should this be frame-relative, or
-                        * protocol-relative?
-                        *
-                        * XXX - does this fallback for non-registered
-                        * fields even make sense?
-                        */
-                       if (finfo->ds_tvb != edt->tvb)
-                               return FALSE;
-
-                       /*
-                        * If the length is 0, there's nothing to match, so
-                        * we can't match.  (Also check for negative values,
-                        * just in case, as we'll cast it to an unsigned
-                        * value later.)
-                        */
-                       length = finfo->length;
-                       if (length <= 0)
-                               return FALSE;
-
-                       /*
-                        * Don't go past the end of that tvbuff.
-                        */
-                       if ((guint)length > tvb_length(finfo->ds_tvb))
-                               length = tvb_length(finfo->ds_tvb);
-                       if (length <= 0)
-                               return FALSE;
-                       return TRUE;
-       }
-}
-
-/* This function returns a string allocated with packet lifetime scope.
- * You do not need to [g_]free() this string since it will be automatically 
+/* This function indicates whether it's possible to construct a
+ * "match selected" display filter string for the specified field,
+ * returns an indication of whether it's possible, and, if it's
+ * possible and "filter" is non-null, constructs the filter and
+ * sets "*filter" to point to it.
+ * 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)
+static gboolean
+construct_match_selected_string(field_info *finfo, epan_dissect_t *edt,
+    char **filter)
 {
        header_field_info       *hfinfo;
        int                     abbrev_len;
-       char                    *buf, *ptr;
+       char                    *ptr;
        int                     buf_len;
        const char              *format;
        int                     dfilter_len, i;
        gint                    start, length, length_remaining;
        guint8                  c;
+       gchar                   is_signed_num = FALSE;
 
        hfinfo = finfo->hfinfo;
        DISSECTOR_ASSERT(hfinfo);
@@ -5163,14 +5641,15 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
         */
        switch(hfinfo->type) {
 
-               case FT_UINT8:
-               case FT_UINT16:
-               case FT_UINT24:
-               case FT_UINT32:
                case FT_INT8:
                case FT_INT16:
                case FT_INT24:
                case FT_INT32:
+                       is_signed_num = TRUE;
+               case FT_UINT8:
+               case FT_UINT16:
+               case FT_UINT24:
+               case FT_UINT32:
                case FT_FRAMENUM:
                        /*
                         * 4 bytes for " == ".
@@ -5188,10 +5667,20 @@ 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 = ep_alloc0(dfilter_len);
-                       format = hfinfo_numeric_format(hfinfo);
-                       g_snprintf(buf, dfilter_len, format, hfinfo->abbrev, fvalue_get_integer(&finfo->value));
+                       if (filter != NULL) {
+                               dfilter_len = abbrev_len + 4 + 11 + 1;
+                               *filter = ep_alloc0(dfilter_len);
+                               format = hfinfo_numeric_format(hfinfo);
+                               if(is_signed_num) {
+                                       g_snprintf(*filter, dfilter_len, format,
+                                                  hfinfo->abbrev,
+                                                  fvalue_get_sinteger(&finfo->value));
+                               } else {
+                                       g_snprintf(*filter, dfilter_len, format,
+                                                  hfinfo->abbrev,
+                                                  fvalue_get_uinteger(&finfo->value));
+                               }
+                       }
                        break;
 
                case FT_INT64:
@@ -5212,49 +5701,39 @@ 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 = ep_alloc0(dfilter_len);
-                       format = hfinfo_numeric_format(hfinfo);
-                       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_ETHER:
-               case FT_BYTES:
-               case FT_UINT_BYTES:
-               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 " == ".
-                        *      1 byte for trailing NUL.
-                        */
-                       dfilter_len = fvalue_string_repr_len(&finfo->value,
-                                       FTREPR_DFILTER);
-                       dfilter_len += abbrev_len + 4 + 1;
-                       buf = ep_alloc0(dfilter_len);
-
-                       /* Create the string */
-                       g_snprintf(buf, dfilter_len, "%s == ", hfinfo->abbrev);
-                       fvalue_to_string_repr(&finfo->value,
-                                       FTREPR_DFILTER,
-                                       &buf[abbrev_len + 4]);
+                       if (filter != NULL) {
+                               dfilter_len = abbrev_len + 4 + 22 + 1;
+                               *filter = ep_alloc0(dfilter_len);
+                               format = hfinfo_numeric_format(hfinfo);
+                               g_snprintf(*filter, dfilter_len, format,
+                                   hfinfo->abbrev,
+                                   fvalue_get_integer64(&finfo->value));
+                       }
                        break;
 
                case FT_PROTOCOL:
-                       buf = ep_strdup(finfo->hfinfo->abbrev);
+                       if (filter != NULL)
+                               *filter = ep_strdup(finfo->hfinfo->abbrev);
                        break;
 
-               default:
+               case FT_NONE:
+               case FT_PCRE:
+                       /*
+                        * 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 (filter != NULL)
+                                       *filter = ep_strdup(finfo->hfinfo->abbrev);
+                               break;
+                       }
+                       if (length < 0)
+                               return FALSE;
+
                        /*
                         * This doesn't have a value, so we'd match
                         * on the raw bytes at this address.
@@ -5263,7 +5742,7 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                         * If "edt" is NULL, the answer is "no".
                         */
                        if (edt == NULL)
-                               return NULL;
+                               return FALSE;
 
                        /*
                         * Is this field part of the raw frame tvbuff?
@@ -5277,17 +5756,7 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                         * fields even make sense?
                         */
                        if (finfo->ds_tvb != edt->tvb)
-                               return NULL;    /* you lose */
-
-                       /*
-                        * If the length is 0, there's nothing to match, so
-                        * we can't match.  (Also check for negative values,
-                        * just in case, as we'll cast it to an unsigned
-                        * value later.)
-                        */
-                       length = finfo->length;
-                       if (length <= 0)
-                               return NULL;
+                               return FALSE;   /* you lose */
 
                        /*
                         * Don't go past the end of that tvbuff.
@@ -5296,26 +5765,373 @@ proto_construct_dfilter_string(field_info *finfo, epan_dissect_t *edt)
                        if (length > length_remaining)
                                length = length_remaining;
                        if (length <= 0)
-                               return NULL;
-                       
-                       start = finfo->start;
-                       buf_len = 32 + length * 3;
-                       buf = ep_alloc0(buf_len);
-                       ptr = 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 ) {
-                                       ptr += g_snprintf(ptr, buf_len-(ptr-buf), "%02x", c);
+                               return FALSE;
+
+                       if (filter != NULL) {
+                               start = finfo->start;
+                               buf_len = 32 + length * 3;
+                               *filter = ep_alloc0(buf_len);
+                               ptr = *filter;
+
+                               ptr += g_snprintf(ptr, buf_len-(ptr-*filter),
+                                   "frame[%d:%d] == ", finfo->start, length);
+                               for (i=0;i<length; i++) {
+                                       c = tvb_get_guint8(finfo->ds_tvb, start);
+                                       start++;
+                                       if (i == 0 ) {
+                                               ptr += g_snprintf(ptr, buf_len-(ptr-*filter), "%02x", c);
+                                       }
+                                       else {
+                                               ptr += g_snprintf(ptr, buf_len-(ptr-*filter), ":%02x", c);
+                                       }
                                }
-                               else {
-                                       ptr += snprintf(ptr, buf_len-(ptr-buf), ":%02x", c);
+                       }
+                       break;
+
+               /* By default, use the fvalue's "to_string_repr" method. */
+               default:
+                       /* Figure out the string length needed.
+                        *      The ft_repr length.
+                        *      4 bytes for " == ".
+                        *      1 byte for trailing NUL.
+                        */
+                       if (filter != NULL) {
+                               dfilter_len = fvalue_string_repr_len(&finfo->value,
+                                               FTREPR_DFILTER);
+                               dfilter_len += abbrev_len + 4 + 1;
+                               *filter = ep_alloc0(dfilter_len);
+
+                               /* Create the string */
+                               g_snprintf(*filter, dfilter_len, "%s == ",
+                                   hfinfo->abbrev);
+                               fvalue_to_string_repr(&finfo->value,
+                                   FTREPR_DFILTER,
+                                   &(*filter)[abbrev_len + 4]);
+                       }
+                       break;
+       }
+
+       return TRUE;
+}
+
+/*
+ * Returns TRUE if we can do a "match selected" on the field, FALSE
+ * otherwise.
+ */
+gboolean
+proto_can_match_selected(field_info *finfo, epan_dissect_t *edt)
+{
+       return construct_match_selected_string(finfo, edt, NULL);
+}
+
+/* This function attempts to construct a "match selected" display filter
+ * string for the specified field; if it can do so, it returns a pointer
+ * to the string, otherwise it returns NULL.
+ *
+ * The string is 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_match_selected_string(field_info *finfo, epan_dissect_t *edt)
+{
+       char *filter;
+
+       if (!construct_match_selected_string(finfo, edt, &filter))
+               return NULL;
+       return filter;
+}
+
+
+/* This function will dissect a sequence of bytes that describe a
+ * bitmask.
+ * hf_hdr is a 8/16/24/32 bit integer that describes the bitmask to be dissected.
+ * This field will form an expansion under which the individual fields of the
+ * bitmask is dissected and displayed.
+ * This field must be of the type FT_[U]INT{8|16|24|32}.
+ *
+ * fields is an array of pointers to int that lists all the fields of the
+ * bitmask. These fields can be either of the type FT_BOOLEAN for flags
+ * or another integer of the same type/size as hf_hdr with a mask specified.
+ * This array is terminated by a NULL entry.
+ *
+ * FT_BOOLEAN bits that are set to 1 will have the name added to the expansion.
+ * FT_integer fields that have a value_string attached will have the
+ * matched string displayed on the expansion line.
+ */
+proto_item *
+proto_tree_add_bitmask(proto_tree *parent_tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian)
+{
+       proto_tree *tree=NULL;
+       proto_item *item=NULL;
+       header_field_info *hf_info;
+       int len=0;
+       guint32 value=0;
+
+       hf_info=proto_registrar_get_nth(hf_hdr);
+       switch(hf_info->type){
+       case FT_INT8:
+       case FT_UINT8:
+               len=1;
+               value=tvb_get_guint8(tvb, offset);
+               break;
+       case FT_INT16:
+       case FT_UINT16:
+               len=2;
+               if(little_endian){
+                       value=tvb_get_letohs(tvb, offset);
+               } else {
+                       value=tvb_get_ntohs(tvb, offset);
+               }
+               break;
+       case FT_INT24:
+       case FT_UINT24:
+               len=3;
+               if(little_endian){
+                       value=tvb_get_letoh24(tvb, offset);
+               } else {
+                       value=tvb_get_ntoh24(tvb, offset);
+               }
+               break;
+       case FT_INT32:
+       case FT_UINT32:
+               len=4;
+               if(little_endian){
+                       value=tvb_get_letohl(tvb, offset);
+               } else {
+                       value=tvb_get_ntohl(tvb, offset);
+               }
+               break;
+       default:
+               g_assert_not_reached();
+       }
+
+       if(parent_tree){
+               item=proto_tree_add_item(parent_tree, hf_hdr, tvb, offset, len, little_endian);
+               tree=proto_item_add_subtree(item, ett);
+       }
+
+       while(*fields){
+               header_field_info *hf_field;
+               guint32 tmpval, tmpmask;
+
+               hf_field=proto_registrar_get_nth(**fields);
+               switch(hf_field->type){
+               case FT_INT8:
+               case FT_UINT8:
+               case FT_INT16:
+               case FT_UINT16:
+               case FT_INT24:
+               case FT_UINT24:
+               case FT_INT32:
+               case FT_UINT32:
+                       proto_tree_add_item(tree, **fields, tvb, offset, len, little_endian);
+
+                       /* Mask and shift out the value */
+                       tmpmask=hf_field->bitmask;
+                       tmpval=value;
+                       if(tmpmask){
+                               tmpval&=tmpmask;
+                               while(!(tmpmask&0x00000001)){
+                                       tmpval>>=1;
+                                       tmpmask>>=1;
                                }
                        }
+                       /* Show the value_string content (if there is one) */
+                       if(hf_field->strings){
+                               proto_item_append_text(item, ",  %s", val_to_str(tmpval, hf_field->strings, "Unknown"));
+                       }
+
+                       break;
+               case FT_BOOLEAN:
+                       proto_tree_add_item(tree, **fields, tvb, offset, len, little_endian);
+                       /* if the flag is set, show the name */
+                       if(hf_field->bitmask&value){
+                               proto_item_append_text(item, ",  %s", hf_field->name);
+                       }
+                       break;
+               default:
+                       g_assert_not_reached();
+               }
+
+               fields++;
+       }
+
+       return item;
+}
+
+proto_item *
+proto_tree_add_bits_item(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian)
+{
+       return proto_tree_add_bits_ret_val(tree, hf_index, tvb, bit_offset, no_of_bits, NULL, little_endian);
+
+}
+/*
+ * This function will dissect a sequence of bits that does not need to be byte aligned the bits
+ * set vill be shown in the tree as ..10 10.. and the integer value returned if return_value is set.
+ * Offset should be given in bits from the start of the tvb.
+ */
+
+proto_item *
+proto_tree_add_bits_ret_val(proto_tree *tree, int hf_index, tvbuff_t *tvb, gint bit_offset, gint no_of_bits, guint64 *return_value, gboolean little_endian)
+{
+       gint    offset;
+       guint   length;
+       guint8  tot_no_bits;
+       guint8  remaining_bits;
+       guint64 mask = 0,tmp;
+       char *str;
+       header_field_info *hf_field;
+       guint64 value = 0;
+       int bit;
+       int i;
+
+       hf_field = proto_registrar_get_nth(hf_index);
+
+       /* Byte align offset */
+       offset = bit_offset>>3;
+
+
+       /*
+        * Calculate the number of octets used to hold the bits
+        */
+       tot_no_bits = ((bit_offset&0x7)+no_of_bits);
+       length = tot_no_bits>>3;
+       remaining_bits = tot_no_bits % 8;
+       if ((remaining_bits)!=0)
+               length++;
+
+       if (no_of_bits < 9){
+               value = tvb_get_bits8(tvb, bit_offset, no_of_bits);
+       }else if(no_of_bits < 17){
+               value = tvb_get_bits16(tvb, bit_offset, no_of_bits, little_endian);
+       }else if(no_of_bits < 33){
+               value = tvb_get_bits32(tvb, bit_offset, no_of_bits, little_endian);
+       }else if(no_of_bits < 65){
+               value = tvb_get_bits64(tvb, bit_offset, no_of_bits, little_endian);
+       }else if(no_of_bits>64){
+               DISSECTOR_ASSERT_NOT_REACHED();
+               return NULL;
+       }
+
+
+       mask = 1;
+       mask = mask << (no_of_bits-1);
+
+       /* prepare the string */
+       str=ep_alloc(256);
+       str[0]='\0';
+       for(bit=0;bit<((int)(bit_offset&0x07));bit++){
+               if(bit&&(!(bit%4))){
+                       strcat(str, " ");
+               }
+               strcat(str,".");
+       }
+       /* read the bits for the int */
+       for(i=0;i<no_of_bits;i++){
+               if(bit&&(!(bit%4))){
+                       strcat(str, " ");
+               }
+               if(bit&&(!(bit%8))){
+                       strcat(str, " ");
+               }
+               bit++;
+               tmp = value & mask;
+               if(tmp != 0){
+                       strcat(str, "1");
+               } else {
+                       strcat(str, "0");
+               }
+               mask = mask>>1;
+       }
+       for(;bit%8;bit++){
+               if(bit&&(!(bit%4))){
+                       strcat(str, " ");
+               }
+               strcat(str,".");
+       }
+
+       if(return_value){
+               *return_value=value;
+       }
+       if(hf_index == -1)
+               return NULL;
+
+       strcat(str," = ");
+       strcat(str,hf_field->name);
+
+       switch(hf_field->type){
+       case FT_BOOLEAN:
+               /* Boolean field */
+               if (hf_field->strings) {
+                       const true_false_string         *tfstring = &tfs_true_false;
+                       tfstring = (const struct true_false_string*) hf_field->strings;
+
+                       return proto_tree_add_boolean_format(tree, hf_index, tvb, offset, length, (guint32)value,
+                               "%s: %s",
+                               str,
+                               (guint32)value ? tfstring->true_string : tfstring->false_string);
+               }else{
+                       return proto_tree_add_boolean_format(tree, hf_index, tvb, offset, length, (guint32)value,
+                               "%s: %u",
+                               str,
+                               (guint32)value);
+               }
+               break;
+       case FT_UINT8:
+       case FT_UINT16:
+       case FT_UINT24:
+       case FT_UINT32:
+               /* 1 - 32 bits field */
+               if (hf_field->strings) {
+                       return proto_tree_add_uint_format(tree, hf_index, tvb, offset, length, (guint32)value,
+                                                 "%s: %s (%u)",
+                                                 str,
+                                                 val_to_str((guint32)value, cVALS(hf_field->strings), "Unknown "),
+                                                 (guint32)value);
                        break;
+               }
+               switch(hf_field->display){
+                       case BASE_DEC:
+                               return proto_tree_add_uint_format(tree, hf_index, tvb, offset, length, (guint32)value,
+                                        "%s: %u",
+                                                 str,
+                                                 (guint32)value);
+                               break;
+                       case BASE_HEX:
+                               return proto_tree_add_uint_format(tree, hf_index, tvb, offset, length, (guint32)value,
+                                    "%s: 0x%x",
+                                                 str,
+                                                 (guint32)value);
+                               break;
+                       default:
+                               DISSECTOR_ASSERT_NOT_REACHED();
+                               return NULL;
+                               break;
+               }
+               break;
+       case FT_UINT64:
+               switch(hf_field->display){
+                       case BASE_DEC:
+                               return proto_tree_add_uint64_format(tree, hf_index, tvb, offset, length, value,
+                                        "%s: %" G_GINT64_MODIFIER "u",
+                                                 str, value);
+                               break;
+                       case BASE_HEX:
+                               return proto_tree_add_uint64_format(tree, hf_index, tvb, offset, length, value,
+                                    "%s: 0x%" G_GINT64_MODIFIER "x",
+                                                 str, value);
+                               break;
+                       default:
+                               DISSECTOR_ASSERT_NOT_REACHED();
+                               return NULL;
+                               break;
+               }
+               break;
+       default:
+               DISSECTOR_ASSERT_NOT_REACHED();
+               return NULL;
+               break;
        }
 
-       return buf;
 }