Rework "extended value strings":
[obnox/wireshark/wip.git] / epan / proto.c
index 0a5b6cc47bad2ddf79866531eb6596cf66db4790..d04ee42a159d7f89bf07353d6eeb67a04955c57d 100644 (file)
@@ -157,6 +157,7 @@ static const char* hfinfo_int_vals_format(const header_field_info *hfinfo);
 static const char* hfinfo_int_format(const header_field_info *hfinfo);
 static const char* hfinfo_int_value_format(const header_field_info *hfinfo);
 static const char* hfinfo_int64_format(const header_field_info *hfinfo);
+static const char* hfinfo_numeric_value_format(const header_field_info *hfinfo);
 
 static proto_item *
 proto_tree_add_node(proto_tree *tree, field_info *fi);
@@ -211,7 +212,7 @@ proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length);
 static void
 proto_tree_set_guid(field_info *fi, const e_guid_t *value_ptr);
 static void
-proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start, gboolean little_endian);
+proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start, const guint encoding);
 static void
 proto_tree_set_oid(field_info *fi, const guint8* value_ptr, gint length);
 static void
@@ -229,7 +230,7 @@ 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, guint length, gboolean little_endian);
+proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start, guint length, const guint encoding);
 static gboolean
 proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset,
                            const int len, const gint ett, const gint **fields,
@@ -972,11 +973,11 @@ ptvcursor_add_subtree_item(ptvcursor_t * ptvc, proto_item * it, gint ett_subtree
  */
 proto_tree *
 ptvcursor_add_with_subtree(ptvcursor_t * ptvc, int hfindex, gint length,
-                          gboolean little_endian, gint ett_subtree)
+                          const guint encoding, gint ett_subtree)
 {
        proto_item * it;
 
-       it = ptvcursor_add_no_advance(ptvc, hfindex, length, little_endian);
+       it = ptvcursor_add_no_advance(ptvc, hfindex, length, encoding);
        return ptvcursor_add_subtree_item(ptvc, it, ett_subtree, length);
 }
 
@@ -1080,9 +1081,12 @@ proto_tree_add_debug_text(proto_tree *tree, const char *format, ...)
 
        pi = proto_tree_add_text_node(tree, NULL, 0, 0);
 
-       va_start(ap, format);
-       if (pi)
+       if (pi) {
+               va_start(ap, format);
                proto_tree_set_representation(pi, format, ap);
+               va_end(ap);
+       }
+       va_start(ap, format);
        vprintf(format, ap);
        va_end(ap);
        printf("\n");
@@ -1090,9 +1094,14 @@ proto_tree_add_debug_text(proto_tree *tree, const char *format, ...)
        return pi;
 }
 
-
+/*
+ * NOTE: to support code written when proto_tree_add_item() took a
+ * gboolean as its last argument, with FALSE meaning "big-endian"
+ * and TRUE meaning "little-endian", we treat any non-zero value of
+ * "encoding" as meaning "little-endian".
+ */
 static guint32
-get_uint_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
+get_uint_value(tvbuff_t *tvb, gint offset, gint length, const guint encoding)
 {
        guint32 value;
 
@@ -1103,18 +1112,18 @@ get_uint_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
                break;
 
        case 2:
-               value = little_endian ? tvb_get_letohs(tvb, offset)
-                                     : tvb_get_ntohs(tvb, offset);
+               value = encoding ? tvb_get_letohs(tvb, offset)
+                                : tvb_get_ntohs(tvb, offset);
                break;
 
        case 3:
-               value = little_endian ? tvb_get_letoh24(tvb, offset)
-                                     : tvb_get_ntoh24(tvb, offset);
+               value = encoding ? tvb_get_letoh24(tvb, offset)
+                                : tvb_get_ntoh24(tvb, offset);
                break;
 
        case 4:
-               value = little_endian ? tvb_get_letohl(tvb, offset)
-                                     : tvb_get_ntohl(tvb, offset);
+               value = encoding ? tvb_get_letohl(tvb, offset)
+                                : tvb_get_ntohl(tvb, offset);
                break;
 
        default:
@@ -1125,8 +1134,14 @@ get_uint_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
        return value;
 }
 
+/*
+ * NOTE: to support code written when proto_tree_add_item() took a
+ * gboolean as its last argument, with FALSE meaning "big-endian"
+ * and TRUE meaning "little-endian", we treat any non-zero value of
+ * "encoding" as meaning "little-endian".
+ */
 static gint32
-get_int_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
+get_int_value(tvbuff_t *tvb, gint offset, gint length, const guint encoding)
 {
        gint32 value;
 
@@ -1137,13 +1152,13 @@ get_int_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
                break;
 
        case 2:
-               value = (gint16) (little_endian ? tvb_get_letohs(tvb, offset)
-                                               : tvb_get_ntohs(tvb, offset));
+               value = (gint16) (encoding ? tvb_get_letohs(tvb, offset)
+                                          : tvb_get_ntohs(tvb, offset));
                break;
 
        case 3:
-               value = little_endian ? tvb_get_letoh24(tvb, offset)
-                                     : tvb_get_ntoh24(tvb, offset);
+               value = encoding ? tvb_get_letoh24(tvb, offset)
+                                : tvb_get_ntoh24(tvb, offset);
                if (value & 0x00800000) {
                        /* Sign bit is set; sign-extend it. */
                        value |= 0xFF000000;
@@ -1151,8 +1166,8 @@ get_int_value(tvbuff_t *tvb, gint offset, gint length, gboolean little_endian)
                break;
 
        case 4:
-               value = little_endian ? tvb_get_letohl(tvb, offset)
-                                     : tvb_get_ntohl(tvb, offset);
+               value = encoding ? tvb_get_letohl(tvb, offset)
+                                : tvb_get_ntohl(tvb, offset);
                break;
 
        default:
@@ -1197,13 +1212,14 @@ proto_lookup_or_create_interesting_hfids(proto_tree *tree,
 static proto_item *
 proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                    tvbuff_t *tvb, gint start, gint length,
-                   gboolean little_endian)
+                   const guint encoding)
 {
        proto_item      *pi;
        guint32         value, n;
        float           floatval;
        double          doubleval;
        char            *string;
+       nstime_t        time_stamp;
        GPtrArray       *ptrs;
 
        /* there is a possibility here that we might raise an exception
@@ -1242,7 +1258,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                        break;
 
                case FT_UINT_BYTES:
-                       n = get_uint_value(tvb, start, length, little_endian);
+                       n = get_uint_value(tvb, start, length, encoding);
                        proto_tree_set_bytes_tvb(new_fi, tvb, start + length, n);
 
                        /* Instead of calling proto_item_set_len(), since we don't yet
@@ -1252,7 +1268,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
 
                case FT_BOOLEAN:
                        proto_tree_set_boolean(new_fi,
-                               get_uint_value(tvb, start, length, little_endian));
+                               get_uint_value(tvb, start, length, encoding));
                        break;
 
                /* XXX - make these just FT_UINT? */
@@ -1261,13 +1277,13 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                case FT_UINT24:
                case FT_UINT32:
                        proto_tree_set_uint(new_fi,
-                               get_uint_value(tvb, start, length, little_endian));
+                               get_uint_value(tvb, start, length, encoding));
                        break;
 
                case FT_INT64:
                case FT_UINT64:
                        DISSECTOR_ASSERT( length <= 8 && length >= 1);
-                       proto_tree_set_uint64_tvb(new_fi, tvb, start, length, little_endian);
+                       proto_tree_set_uint64_tvb(new_fi, tvb, start, length, encoding);
                        break;
 
                /* XXX - make these just FT_INT? */
@@ -1276,13 +1292,21 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                case FT_INT24:
                case FT_INT32:
                        proto_tree_set_int(new_fi,
-                               get_int_value(tvb, start, length, little_endian));
+                               get_int_value(tvb, start, length, encoding));
                        break;
 
                case FT_IPv4:
                        DISSECTOR_ASSERT(length == FT_IPv4_LEN);
                        value = tvb_get_ipv4(tvb, start);
-                       proto_tree_set_ipv4(new_fi, little_endian ? GUINT32_SWAP_LE_BE(value) : value);
+                       /*
+                        * NOTE: to support code written when
+                        * proto_tree_add_item() took a gboolean as its
+                        * last argument, with FALSE meaning "big-endian"
+                        * and TRUE meaning "little-endian", we treat any
+                        * non-zero value of "encoding" as meaning
+                        * "little-endian".
+                        */
+                       proto_tree_set_ipv4(new_fi, encoding ? GUINT32_SWAP_LE_BE(value) : value);
                        break;
 
                case FT_IPXNET:
@@ -1303,7 +1327,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
 
                case FT_GUID:
                        DISSECTOR_ASSERT(length == FT_GUID_LEN);
-                       proto_tree_set_guid_tvb(new_fi, tvb, start, little_endian);
+                       proto_tree_set_guid_tvb(new_fi, tvb, start, encoding);
                        break;
 
                case FT_OID:
@@ -1312,7 +1336,20 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
 
                case FT_FLOAT:
                        DISSECTOR_ASSERT(length == 4);
-                       if (little_endian)
+                       /*
+                        * NOTE: to support code written when
+                        * proto_tree_add_item() took a gboolean as its
+                        * last argument, with FALSE meaning "big-endian"
+                        * and TRUE meaning "little-endian", we treat any
+                        * non-zero value of "encoding" as meaning
+                        * "little-endian".
+                        *
+                        * At some point in the future, we might
+                        * support non-IEEE-binary floating-point
+                        * formats in the encoding as well
+                        * (IEEE decimal, System/3x0, VAX).
+                        */
+                       if (encoding)
                                floatval = tvb_get_letohieee_float(tvb, start);
                        else
                                floatval = tvb_get_ntohieee_float(tvb, start);
@@ -1320,8 +1357,21 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                        break;
 
                case FT_DOUBLE:
+                       /*
+                        * NOTE: to support code written when
+                        * proto_tree_add_item() took a gboolean as its
+                        * last argument, with FALSE meaning "big-endian"
+                        * and TRUE meaning "little-endian", we treat any
+                        * non-zero value of "encoding" as meaning
+                        * "little-endian".
+                        *
+                        * At some point in the future, we might
+                        * support non-IEEE-binary floating-point
+                        * formats in the encoding as well
+                        * (IEEE decimal, System/3x0, VAX).
+                        */
                        DISSECTOR_ASSERT(length == 8);
-                       if (little_endian)
+                       if (encoding)
                                doubleval = tvb_get_letohieee_double(tvb, start);
                        else
                                doubleval = tvb_get_ntohieee_double(tvb, start);
@@ -1397,7 +1447,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                        break;
 
                case FT_UINT_STRING:
-                       n = get_uint_value(tvb, start, length, little_endian);
+                       n = get_uint_value(tvb, start, length, encoding);
                        proto_tree_set_string_tvb(new_fi, tvb, start + length, n);
 
                        /* Instead of calling proto_item_set_len(), since we
@@ -1412,6 +1462,38 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                        new_fi->length = n + length;
                        break;
 
+               case FT_ABSOLUTE_TIME:
+               case FT_RELATIVE_TIME:
+                       DISSECTOR_ASSERT(length == 8 || length == 4);
+                       /*
+                        * NOTE: to support code written when
+                        * proto_tree_add_item() took a gboolean as its
+                        * last argument, with FALSE meaning "big-endian"
+                        * and TRUE meaning "little-endian", we treat any
+                        * non-zero value of "encoding" as meaning
+                        * "little-endian".
+                        *
+                        * At some point in the future, we might
+                        * support non-struct timespec formats in
+                        * the encoding as well (struct timeval,
+                        * NTP time, Windows NT FILETIME, time_t, etc.).
+                        */
+                       if (encoding) {
+                               time_stamp.secs  = tvb_get_letohl(tvb, start);
+                               if (length == 8)
+                                       time_stamp.nsecs = tvb_get_letohl(tvb, start+4);
+                               else
+                                       time_stamp.nsecs = 0;
+                       } else {
+                               time_stamp.secs  = tvb_get_ntohl(tvb, start);
+                               if (length == 8)
+                                       time_stamp.nsecs = tvb_get_ntohl(tvb, start+4);
+                               else
+                                       time_stamp.nsecs = 0;
+                       }
+                       proto_tree_set_time(new_fi, &time_stamp);
+                       break;
+
                default:
                        g_error("new_fi->hfinfo->type %d (%s) not handled\n",
                                        new_fi->hfinfo->type,
@@ -1419,7 +1501,12 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
                        DISSECTOR_ASSERT_NOT_REACHED();
                        break;
        }
-       FI_SET_FLAG(new_fi, (little_endian) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN);
+       /*
+        * XXX - this should just check the ENC_*_ENDIAN bit, with
+        * those fields for which we treat any non-zero value of
+        * "encoding" checking the rest of the bits.
+        */
+       FI_SET_FLAG(new_fi, (encoding) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN);
 
        /* Don't add new node to proto_tree until now so that any exceptions
         * raised by a tvbuff access method doesn't leave junk in the proto_tree. */
@@ -1443,7 +1530,7 @@ proto_tree_new_item(field_info *new_fi, proto_tree *tree,
    and returns proto_item* */
 proto_item *
 ptvcursor_add(ptvcursor_t *ptvc, int hfindex, gint length,
-             gboolean little_endian)
+             const guint encoding)
 {
        field_info              *new_fi;
        header_field_info       *hfinfo;
@@ -1463,7 +1550,7 @@ ptvcursor_add(ptvcursor_t *ptvc, int hfindex, gint length,
                 * The length of the rest of the item is in the first N
                 * bytes of the item.
                 */
-               n = get_uint_value(ptvc->tvb, offset, length, little_endian);
+               n = get_uint_value(ptvc->tvb, offset, length, encoding);
                ptvc->offset += n;
        }
 
@@ -1475,14 +1562,14 @@ ptvcursor_add(ptvcursor_t *ptvc, int hfindex, gint length,
                return NULL;
 
        return proto_tree_new_item(new_fi, ptvc->tree, ptvc->tvb,
-               offset, length, little_endian);
+               offset, length, encoding);
 }
 
 /* Add an item to a proto_tree, using the text label registered to that item;
    the item is extracted from the tvbuff handed to it. */
 proto_item *
 proto_tree_add_item(proto_tree *tree, const int hfindex, tvbuff_t *tvb,
-                   const gint start, gint length, const gboolean little_endian)
+                   const gint start, gint length, const guint encoding)
 {
        field_info      *new_fi;
        header_field_info       *hfinfo;
@@ -1495,7 +1582,7 @@ proto_tree_add_item(proto_tree *tree, const int hfindex, tvbuff_t *tvb,
                return(NULL);
 
        return proto_tree_new_item(new_fi, tree, tvb, start,
-               length, little_endian);
+               length, encoding);
 }
 
 /* Add a FT_NONE to a proto_tree */
@@ -1528,12 +1615,12 @@ proto_tree_add_none_format(proto_tree *tree, const int hfindex, tvbuff_t *tvb,
  * offset, and returns proto_item* */
 proto_item *
 ptvcursor_add_no_advance(ptvcursor_t* ptvc, int hf, gint length,
-                        gboolean endianness)
+                        const guint encoding)
 {
        proto_item      *item;
 
        item = proto_tree_add_item(ptvc->tree, hf, ptvc->tvb, ptvc->offset,
-                                  length, endianness);
+                                  length, encoding);
 
        return item;
 }
@@ -2053,11 +2140,11 @@ proto_tree_set_guid(field_info *fi, const e_guid_t *value_ptr)
 
 static void
 proto_tree_set_guid_tvb(field_info *fi, tvbuff_t *tvb, gint start,
-                       gboolean little_endian)
+                       const guint encoding)
 {
        e_guid_t guid;
 
-       tvb_get_guid(tvb, start, &guid, little_endian);
+       tvb_get_guid(tvb, start, &guid, encoding);
        proto_tree_set_guid(fi, &guid);
 }
 
@@ -2156,14 +2243,20 @@ proto_tree_set_uint64(field_info *fi, guint64 value)
        fvalue_set_integer64(&fi->value, value);
 }
 
+/*
+ * NOTE: to support code written when proto_tree_add_item() took a
+ * gboolean as its last argument, with FALSE meaning "big-endian"
+ * and TRUE meaning "little-endian", we treat any non-zero value of
+ * "encoding" as meaning "little-endian".
+ */
 static void
 proto_tree_set_uint64_tvb(field_info *fi, tvbuff_t *tvb, gint start,
-                         guint length, gboolean little_endian)
+                         guint length, const guint encoding)
 {
        guint64 value = 0;
        guint8* b = ep_tvb_memdup(tvb,start,length);
 
-       if(little_endian) {
+       if(encoding) {
                b += length;
                switch(length) {
                        default: DISSECTOR_ASSERT_NOT_REACHED();
@@ -3325,8 +3418,8 @@ proto_tree_set_representation(proto_item *pi, const char *format, va_list ap)
 
 /* -------------------------- */
 const gchar *
-proto_custom_set(proto_tree* tree, const int field_id, gchar *result,
-                gchar *expr, const int size)
+proto_custom_set(proto_tree* tree, const int field_id, gint occurrence,
+                 gchar *result, gchar *expr, const int size)
 {
        guint32         u_integer;
        gint32          integer;
@@ -3337,10 +3430,11 @@ proto_custom_set(proto_tree* tree, const int field_id, gchar *result,
        guint32         n_addr; /* network-order IPv4 address */
 
        const true_false_string  *tfstring;
-       int             len;
+       int             len, prev_len=0, last, i, offset_r=0, offset_e=0;
        GPtrArray       *finfos;
-       field_info      *finfo;
+       field_info      *finfo = NULL;
        header_field_info* hfinfo;
+       const gchar     *abbrev = NULL;
 
        g_assert(field_id >= 0);
 
@@ -3350,162 +3444,253 @@ proto_custom_set(proto_tree* tree, const int field_id, gchar *result,
        if (!hfinfo)
                return "";
 
+       if (occurrence < 0) {
+               /* Search other direction */
+               while (hfinfo->same_name_prev) {
+                       hfinfo = hfinfo->same_name_prev;
+               }
+       }
+
        while (hfinfo) {
                finfos = proto_get_finfo_ptr_array(tree, hfinfo->id);
 
                if (!finfos || !(len = g_ptr_array_len(finfos))) {
-                       hfinfo = hfinfo->same_name_next;
-                       continue;
-               }
-               /* get the last one  */
-               finfo = g_ptr_array_index(finfos, len -1);
-
-               switch(hfinfo->type) {
-
-               case FT_NONE: /* Nothing to add */
-                       result[0] = '\0';
-                       break;
-
-               case FT_PROTOCOL:
-                       g_strlcpy(result, "Yes", size);
-                       break;
-
-               case FT_UINT_BYTES:
-               case FT_BYTES:
-                       bytes = fvalue_get(&finfo->value);
-                       g_strlcpy(result, bytes_to_str(bytes, fvalue_length(&finfo->value)), size);
-                       break;
-
-               case FT_ABSOLUTE_TIME:
-                       g_strlcpy(result,
-                               abs_time_to_str(fvalue_get(&finfo->value), hfinfo->display),
-                               size);
-                       break;
-
-               case FT_RELATIVE_TIME:
-                       g_strlcpy(result, rel_time_to_secs_str(fvalue_get(&finfo->value)), size);
-                       break;
-
-               case FT_BOOLEAN:
-                       u_integer = fvalue_get_uinteger(&finfo->value);
-                       tfstring = (const true_false_string *)&tfs_true_false;
-                       if (hfinfo->strings) {
-                               tfstring = (const struct true_false_string*) hfinfo->strings;
-                       }
-                       g_strlcpy(result, u_integer ? tfstring->true_string : tfstring->false_string, size);
-                       break;
-
-               case FT_UINT8:
-               case FT_UINT16:
-               case FT_UINT24:
-               case FT_UINT32:
-               case FT_FRAMENUM:
-                       u_integer = fvalue_get_uinteger(&finfo->value);
-                       if (hfinfo->strings) {
-                               if (hfinfo->display & BASE_RANGE_STRING) {
-                                       g_strlcpy(result, rval_to_str(u_integer, hfinfo->strings, "%u"), size);
-                               } else if (hfinfo->display & BASE_EXT_STRING) {
-                                       g_strlcpy(result, val_to_str_ext(u_integer, (value_string_ext *) (hfinfo->strings), "%u"), size);
-                               } else {
-                                       g_strlcpy(result, val_to_str(u_integer, cVALS(hfinfo->strings), "%u"), size);
-                               }
-                       } else if (IS_BASE_DUAL(hfinfo->display)) {
-                               g_snprintf(result, size, hfinfo_uint_value_format(hfinfo), u_integer, u_integer);
+                       if (occurrence < 0) {
+                               hfinfo = hfinfo->same_name_next;
                        } else {
-                               g_snprintf(result, size, hfinfo_uint_value_format(hfinfo), u_integer);
+                               hfinfo = hfinfo->same_name_prev;
                        }
-                       break;
-
-               case FT_INT64:
-               case FT_UINT64:
-                       g_snprintf(result, size, "%" G_GINT64_MODIFIER "u", fvalue_get_integer64(&finfo->value));
-                       break;
-
-               /* XXX - make these just FT_INT? */
-               case FT_INT8:
-               case FT_INT16:
-               case FT_INT24:
-               case FT_INT32:
-                       integer = fvalue_get_sinteger(&finfo->value);
-                       if (hfinfo->strings) {
-                               if (hfinfo->display & BASE_RANGE_STRING) {
-                                       g_strlcpy(result, rval_to_str(integer, hfinfo->strings, "%d"), size);
-                               } else if (hfinfo->display & BASE_EXT_STRING) {
-                                       g_strlcpy(result, val_to_str_ext(integer, (value_string_ext *) (hfinfo->strings), "%d"), size);
-                               } else {
-                                       g_strlcpy(result, val_to_str(integer, cVALS(hfinfo->strings), "%d"), size);
-                       }
-                       } else if (IS_BASE_DUAL(hfinfo->display)) {
-                               g_snprintf(result, size, hfinfo_int_value_format(hfinfo), integer, integer);
-                       } else {
-                               g_snprintf(result, size, hfinfo_int_value_format(hfinfo), integer);
-                       }
-                       break;
-
-               case FT_IPv4:
-                       ipv4 = fvalue_get(&finfo->value);
-                       n_addr = ipv4_get_net_order_addr(ipv4);
-                       g_strlcpy(result, ip_to_str((guint8 *)&n_addr), size);
-                       break;
-
-               case FT_IPv6:
-                       ipv6 = fvalue_get(&finfo->value);
-                       SET_ADDRESS (&addr, AT_IPv6, sizeof(struct e_in6_addr), ipv6);
-                       address_to_str_buf(&addr, result, size);
-                       break;
-
-               case FT_ETHER:
-                       g_strlcpy(result, bytes_to_str_punct(fvalue_get(&finfo->value), 6, ':'), size);
-                       break;
-
-               case FT_GUID:
-                       g_strlcpy(result, guid_to_str((e_guid_t *)fvalue_get(&finfo->value)), size);
-                       break;
-
-               case FT_OID:
-                       bytes = fvalue_get(&finfo->value);
-                       g_strlcpy(result, oid_resolved_from_encoded(bytes, fvalue_length(&finfo->value)), size);
-                       break;
-
-               case FT_FLOAT:
-                       g_snprintf(result, size, "%." STRINGIFY(FLT_DIG) "f", fvalue_get_floating(&finfo->value));
-                       break;
-
-               case FT_DOUBLE:
-                       g_snprintf(result, size, "%." STRINGIFY(DBL_DIG) "g", fvalue_get_floating(&finfo->value));
-                       break;
-
-               case FT_EBCDIC:
-               case FT_STRING:
-               case FT_STRINGZ:
-               case FT_UINT_STRING:
-                       bytes = fvalue_get(&finfo->value);
-                       g_strlcpy(result, format_text(bytes, strlen(bytes)), size);
-                       break;
-
-               case FT_IPXNET: /*XXX really No column custom ?*/
-               case FT_PCRE:
-               default:
-                       g_error("hfinfo->type %d (%s) not handled\n",
-                                       hfinfo->type,
-                                       ftype_name(hfinfo->type));
-                       DISSECTOR_ASSERT_NOT_REACHED();
-                       break;
+                       continue;
                }
 
-               switch(hfinfo->type) {
-               case FT_EBCDIC:
-               case FT_STRING:
-               case FT_STRINGZ:
-               case FT_UINT_STRING:
-                       g_snprintf(expr, size, "\"%s\"",result);
-               default:
-                       g_strlcpy(expr, result, size);
-                       break;
-               }
-               return hfinfo->abbrev;
-       }
-       return "";
+                /* Are there enough occurrences of the field? */
+                if ((occurrence-prev_len > len) || (occurrence+prev_len < -len)) {
+                        if (occurrence < 0) {
+                                hfinfo = hfinfo->same_name_next;
+                        } else {
+                                hfinfo = hfinfo->same_name_prev;
+                        }
+                        prev_len += len;
+                        continue;
+                }
+
+                /* Calculate single index or set outer bounderies */
+                if (occurrence < 0) {
+                        i = occurrence + len + prev_len;
+                        last = i;
+                } else if (occurrence > 0) {
+                        i = occurrence - 1 - prev_len;
+                        last = i;
+                } else {
+                        i = 0;
+                        last = len - 1;
+                }
+
+                prev_len += len; /* Count handled occurrences */
+
+                while (i <= last) {
+                        finfo = g_ptr_array_index(finfos, i);
+
+                        if (offset_r && (offset_r < size-2))
+                                result[offset_r++]=',';
+
+                        if (offset_e && (offset_e < size-2))
+                                expr[offset_e++]=',';
+
+                        switch(hfinfo->type) {
+
+                        case FT_NONE: /* Nothing to add */
+                                if (offset_r == 0) {
+                                        result[0] = '\0';
+                                } else if (result[offset_r-1] == ',') {
+                                        result[offset_r-1] = '\0';
+                                }
+                                break;
+
+                        case FT_PROTOCOL:
+                                /* prevent multiple "yes" entries by setting result directly */
+                                g_strlcpy(result, "Yes", size);
+                                break;
+
+                        case FT_UINT_BYTES:
+                        case FT_BYTES:
+                                bytes = fvalue_get(&finfo->value);
+                                offset_r += (int)g_strlcpy(result+offset_r, bytes_to_str(bytes, fvalue_length(&finfo->value)), size-offset_r);
+                                break;
+
+                        case FT_ABSOLUTE_TIME:
+                                offset_r += (int)g_strlcpy(result+offset_r,
+                                        abs_time_to_str(fvalue_get(&finfo->value), hfinfo->display, TRUE),
+                                        size-offset_r);
+                                break;
+
+                        case FT_RELATIVE_TIME:
+                                offset_r += (int)g_strlcpy(result+offset_r, rel_time_to_secs_str(fvalue_get(&finfo->value)), size-offset_r);
+                                break;
+
+                        case FT_BOOLEAN:
+                                u_integer = fvalue_get_uinteger(&finfo->value);
+                                tfstring = (const true_false_string *)&tfs_true_false;
+                                if (hfinfo->strings) {
+                                        tfstring = (const struct true_false_string*) hfinfo->strings;
+                                }
+                                offset_r += (int)g_strlcpy(result+offset_r, u_integer ? tfstring->true_string : tfstring->false_string, size-offset_r);
+
+                                g_snprintf(expr+offset_e, size-offset_e, "%u", fvalue_get_uinteger(&finfo->value) ? 1 : 0);
+                                offset_e = (int)strlen(expr);
+                                break;
+
+                        case FT_UINT8:
+                        case FT_UINT16:
+                        case FT_UINT24:
+                        case FT_UINT32:
+                        case FT_FRAMENUM:
+                                u_integer = fvalue_get_uinteger(&finfo->value);
+                                if (hfinfo->strings) {
+                                        if (hfinfo->display & BASE_RANGE_STRING) {
+                                                offset_r += (int)g_strlcpy(result+offset_r, rval_to_str(u_integer, hfinfo->strings, "%u"), size-offset_r);
+                                        } else if (hfinfo->display & BASE_EXT_STRING) {
+                                                offset_r += (int)g_strlcpy(result+offset_r, val_to_str_ext(u_integer, (value_string_ext *) (hfinfo->strings), "%u"), size-offset_r);
+                                        } else {
+                                                offset_r += (int)g_strlcpy(result+offset_r, val_to_str(u_integer, cVALS(hfinfo->strings), "%u"), size-offset_r);
+                                        }
+                                } else if (IS_BASE_DUAL(hfinfo->display)) {
+                                        g_snprintf(result+offset_r, size-offset_r, hfinfo_uint_value_format(hfinfo), u_integer, u_integer);
+                                        offset_r = (int)strlen(result);
+                                } else {
+                                        g_snprintf(result+offset_r, size-offset_r, hfinfo_uint_value_format(hfinfo), u_integer);
+                                        offset_r = (int)strlen(result);
+                                }
+
+                                g_snprintf(expr+offset_e, size-offset_e, hfinfo_numeric_value_format(hfinfo), fvalue_get_uinteger(&finfo->value));
+                                offset_e = (int)strlen(expr);
+                                break;
+
+                        case FT_INT64:
+                        case FT_UINT64:
+                                g_snprintf(result+offset_r, size-offset_r, "%" G_GINT64_MODIFIER "u", fvalue_get_integer64(&finfo->value));
+                                offset_r = (int)strlen(result);
+                                break;
+
+                        /* XXX - make these just FT_INT? */
+                        case FT_INT8:
+                        case FT_INT16:
+                        case FT_INT24:
+                        case FT_INT32:
+                                integer = fvalue_get_sinteger(&finfo->value);
+                                if (hfinfo->strings) {
+                                        if (hfinfo->display & BASE_RANGE_STRING) {
+                                                offset_r += (int)g_strlcpy(result+offset_r, rval_to_str(integer, hfinfo->strings, "%d"), size-offset_r);
+                                        } else if (hfinfo->display & BASE_EXT_STRING) {
+                                                offset_r += (int)g_strlcpy(result+offset_r, val_to_str_ext(integer, (value_string_ext *) (hfinfo->strings), "%d"), size-offset_r);
+                                        } else {
+                                                offset_r += (int)g_strlcpy(result+offset_r, val_to_str(integer, cVALS(hfinfo->strings), "%d"), size-offset_r);
+                                        }
+                                } else if (IS_BASE_DUAL(hfinfo->display)) {
+                                        g_snprintf(result+offset_r, size-offset_r, hfinfo_int_value_format(hfinfo), integer, integer);
+                                        offset_r = (int)strlen(result);
+                                } else {
+                                        g_snprintf(result+offset_r, size-offset_r, hfinfo_int_value_format(hfinfo), integer);
+                                        offset_r = (int)strlen(result);
+                                }
+
+                                g_snprintf(expr+offset_e, size-offset_e, hfinfo_numeric_value_format(hfinfo), fvalue_get_sinteger(&finfo->value));
+                                offset_e = (int)strlen(expr);
+                                break;
+
+                        case FT_IPv4:
+                                ipv4 = fvalue_get(&finfo->value);
+                                n_addr = ipv4_get_net_order_addr(ipv4);
+                                offset_r += (int)g_strlcpy(result+offset_r, ip_to_str((guint8 *)&n_addr), size-offset_r);
+                                break;
+
+                        case FT_IPv6:
+                                ipv6 = fvalue_get(&finfo->value);
+                                SET_ADDRESS (&addr, AT_IPv6, sizeof(struct e_in6_addr), ipv6);
+                                address_to_str_buf(&addr, result+offset_r, size-offset_r);
+                                offset_r = (int)strlen(result);
+                                break;
+
+                        case FT_ETHER:
+                                offset_r += (int)g_strlcpy(result+offset_r, bytes_to_str_punct(fvalue_get(&finfo->value), 6, ':'), size-offset_r);
+                                break;
+
+                        case FT_GUID:
+                                offset_r += (int)g_strlcpy(result+offset_r, guid_to_str((e_guid_t *)fvalue_get(&finfo->value)), size-offset_r);
+                                break;
+
+                        case FT_OID:
+                                bytes = fvalue_get(&finfo->value);
+                                offset_r += (int)g_strlcpy(result+offset_r, oid_resolved_from_encoded(bytes, fvalue_length(&finfo->value)), size-offset_r);
+                                offset_e += (int)g_strlcpy(expr+offset_e, oid_encoded2string(bytes, fvalue_length(&finfo->value)), size-offset_e);
+                                break;
+
+                        case FT_FLOAT:
+                                g_snprintf(result+offset_r, size-offset_r, "%." STRINGIFY(FLT_DIG) "f", fvalue_get_floating(&finfo->value));
+                                offset_r = (int)strlen(result);
+                                break;
+
+                        case FT_DOUBLE:
+                                g_snprintf(result+offset_r, size-offset_r, "%." STRINGIFY(DBL_DIG) "g", fvalue_get_floating(&finfo->value));
+                                offset_r = (int)strlen(result);
+                                break;
+
+                        case FT_EBCDIC:
+                        case FT_STRING:
+                        case FT_STRINGZ:
+                        case FT_UINT_STRING:
+                                bytes = fvalue_get(&finfo->value);
+                                offset_r += (int)g_strlcpy(result+offset_r, format_text(bytes, strlen(bytes)), size-offset_r);
+                                break;
+
+                        case FT_IPXNET: /*XXX really No column custom ?*/
+                        case FT_PCRE:
+                        default:
+                                g_error("hfinfo->type %d (%s) not handled\n",
+                                                hfinfo->type,
+                                                ftype_name(hfinfo->type));
+                                DISSECTOR_ASSERT_NOT_REACHED();
+                                break;
+                        }
+                        i++;
+                }
+
+                switch(hfinfo->type) {
+
+                case FT_BOOLEAN:
+                case FT_UINT8:
+                case FT_UINT16:
+                case FT_UINT24:
+                case FT_UINT32:
+                case FT_FRAMENUM:
+                case FT_INT8:
+                case FT_INT16:
+                case FT_INT24:
+                case FT_INT32:
+                case FT_OID:
+                        /* for these types, "expr" is filled in the loop above */
+                        break;
+
+                default:
+                        /* for all others, just copy "result" to "expr" */
+                        g_strlcpy(expr, result, size);
+                        break;
+                }
+
+                if (!abbrev) {
+                        /* Store abbrev for return value */
+                        abbrev = hfinfo->abbrev;
+                }
+
+                if (occurrence == 0) {
+                        /* Fetch next hfinfo with same name (abbrev) */
+                        hfinfo = hfinfo->same_name_prev;
+                } else {
+                        hfinfo = NULL;
+                }
+        }
+
+        return abbrev ? abbrev : "";
 }
 
 
@@ -3551,8 +3736,6 @@ proto_item_append_text(proto_item *pi, const char *format, ...)
        }
 
        if (!PROTO_ITEM_IS_HIDDEN(pi)) {
-               va_start(ap, format);
-
                /*
                 * If we don't already have a representation,
                 * generate the default representation.
@@ -3564,10 +3747,52 @@ proto_item_append_text(proto_item *pi, const char *format, ...)
 
                curlen = strlen(fi->rep->representation);
                if (ITEM_LABEL_LENGTH > curlen) {
+                       va_start(ap, format);
                        g_vsnprintf(fi->rep->representation + curlen,
                                ITEM_LABEL_LENGTH - (gulong) curlen, format, ap);
+                       va_end(ap);
                }
+       }
+}
+
+/* Prepend to text of proto_item after having already been created. */
+void
+proto_item_prepend_text(proto_item *pi, const char *format, ...)
+{
+       field_info *fi = NULL;
+       char representation[ITEM_LABEL_LENGTH];
+       size_t curlen;
+       va_list ap;
+
+       if (pi==NULL) {
+               return;
+       }
+
+       fi = PITEM_FINFO(pi);
+       if (fi==NULL) {
+               return;
+       }
+
+       if (!PROTO_ITEM_IS_HIDDEN(pi)) {
+               /*
+                * If we don't already have a representation,
+                * generate the default representation.
+                */
+               if (fi->rep == NULL) {
+                       ITEM_LABEL_NEW(fi->rep);
+                       proto_item_fill_label(fi, fi->rep->representation);
+               }
+
+               strcpy(representation, fi->rep->representation);
+               va_start(ap, format);
+               g_vsnprintf(fi->rep->representation,
+                       ITEM_LABEL_LENGTH, format, ap);
                va_end(ap);
+               curlen = strlen(fi->rep->representation);
+               if (ITEM_LABEL_LENGTH > curlen) {
+                       strncpy(fi->rep->representation + curlen, representation,
+                               ITEM_LABEL_LENGTH - (gulong) curlen);
+               }
        }
 }
 
@@ -4411,8 +4636,8 @@ proto_register_field_init(header_field_info *hfinfo, const int parent)
        /* if we always add and never delete, then id == len - 1 is correct */
        if(gpa_hfinfo.len>=gpa_hfinfo.allocated_len){
                if(!gpa_hfinfo.hfi){
-                       gpa_hfinfo.allocated_len=1000;
-                       gpa_hfinfo.hfi=g_malloc(sizeof(header_field_info *)*1000);
+                       gpa_hfinfo.allocated_len=100000;
+                       gpa_hfinfo.hfi=g_malloc(sizeof(header_field_info *)*100000);
                } else {
                        gpa_hfinfo.allocated_len+=1000;
                        gpa_hfinfo.hfi=g_realloc(gpa_hfinfo.hfi, sizeof(header_field_info *)*gpa_hfinfo.allocated_len);
@@ -4622,7 +4847,7 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
                case FT_ABSOLUTE_TIME:
                        g_snprintf(label_str, ITEM_LABEL_LENGTH,
                                   "%s: %s", hfinfo->name,
-                                  abs_time_to_str(fvalue_get(&fi->value), hfinfo->display));
+                                  abs_time_to_str(fvalue_get(&fi->value), hfinfo->display, TRUE));
                        break;
 
                case FT_RELATIVE_TIME:
@@ -5782,8 +6007,8 @@ proto_registrar_dump_values(void)
                                hfinfo->type == FT_INT64)) {
 
                                if ((hfinfo->display & BASE_EXT_STRING)) {
-                                       vals = ((value_string_ext *) hfinfo->strings)->vals;
-                               } if ((hfinfo->display & BASE_RANGE_STRING) == 0) {
+                                       vals = VALUE_STRING_EXT_VS_P((value_string_ext *) hfinfo->strings);
+                               } else if ((hfinfo->display & BASE_RANGE_STRING) == 0) {
                                        vals = hfinfo->strings;
                                } else {
                                        range = hfinfo->strings;
@@ -5985,6 +6210,8 @@ proto_registrar_dump_fields(const int format)
                        blurb = hfinfo->blurb;
                        if (blurb == NULL)
                                blurb = "";
+                       else if (strlen(blurb) == 0)
+                               blurb = "\"\"";
                        if (format == 1) {
                                printf("F\t%s\t%s\t%s\t%s\t%s\n",
                                        hfinfo->name, hfinfo->abbrev, enum_name,
@@ -6082,6 +6309,79 @@ hfinfo_numeric_format(const header_field_info *hfinfo)
        return format;
 }
 
+static const char *
+hfinfo_numeric_value_format(const header_field_info *hfinfo)
+{
+       const char *format = NULL;
+
+       /* Pick the proper format string */
+       if (hfinfo->type == FT_FRAMENUM) {
+               /*
+                * Frame numbers are always displayed in decimal.
+                */
+               format = "%u";
+       } else {
+               /* Get the underlying BASE_ value */
+               switch(hfinfo->display & BASE_DISPLAY_E_MASK) {
+                       case BASE_DEC:
+                       case BASE_DEC_HEX:
+                       case BASE_OCT: /* I'm lazy */
+                       case BASE_CUSTOM:
+                               switch(hfinfo->type) {
+                                       case FT_UINT8:
+                                       case FT_UINT16:
+                                       case FT_UINT24:
+                                       case FT_UINT32:
+                                               format = "%u";
+                                               break;
+                                       case FT_UINT64:
+                                               format = "%" G_GINT64_MODIFIER "u";
+                                               break;
+                                       case FT_INT8:
+                                       case FT_INT16:
+                                       case FT_INT24:
+                                       case FT_INT32:
+                                               format = "%d";
+                                               break;
+                                       case FT_INT64:
+                                               format = "%" G_GINT64_MODIFIER "d";
+                                               break;
+                                       default:
+                                               DISSECTOR_ASSERT_NOT_REACHED();
+                                               ;
+                               }
+                               break;
+                       case BASE_HEX:
+                       case BASE_HEX_DEC:
+                               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;
+                                       case FT_UINT64:
+                                               format = "0x%016" G_GINT64_MODIFIER "x";
+                                               break;
+                                       default:
+                                               DISSECTOR_ASSERT_NOT_REACHED();
+                                               ;
+                               }
+                               break;
+                       default:
+                               DISSECTOR_ASSERT_NOT_REACHED();
+                               ;
+               }
+       }
+       return format;
+}
+
 /* 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
@@ -6095,11 +6395,11 @@ construct_match_selected_string(field_info *finfo, epan_dissect_t *edt,
                                char **filter)
 {
        header_field_info       *hfinfo;
-       int                     abbrev_len;
+       int                             abbrev_len;
        char                    *ptr;
-       int                     buf_len;
+       int                             buf_len;
        const char              *format;
-       int                     dfilter_len, i;
+       int                             dfilter_len, i;
        gint                    start, length, length_remaining;
        guint8                  c;
        gchar                   is_signed_num = FALSE;
@@ -6854,7 +7154,7 @@ proto_tree_add_float_bits_format_value(proto_tree *tree, const int hf_index,
        TRY_TO_FAKE_THIS_ITEM(tree, hf_index, hf_field);
 
        DISSECTOR_ASSERT(hf_field->type == FT_FLOAT);
-       
+
        CREATE_VALUE_STRING(dst,format,ap);
 
        return proto_tree_add_bits_format_value(tree, hf_index, tvb, bit_offset, no_of_bits, &value, dst);
@@ -6903,7 +7203,7 @@ proto_tree_add_boolean_bits_format_value(proto_tree *tree, const int hf_index,
        TRY_TO_FAKE_THIS_ITEM(tree, hf_index, hf_field);
 
        DISSECTOR_ASSERT(hf_field->type == FT_BOOLEAN);
-       
+
        CREATE_VALUE_STRING(dst,format,ap);
 
        return proto_tree_add_bits_format_value(tree, hf_index, tvb, bit_offset, no_of_bits, &value, dst);