From Alexey Neyman :

This patch implements a function for dissecting bitfields with better control
over the resulting representation than the existing proto_tree_add_bitmask()
routine. This function will be used by reworked IPMI/ATCA dissector (bug 2048).

The function is described in README.developer. In short, the differences are as
follows:

- The new function does not require a hf_XXX field for the whole bitmask. When
the bitmask includes several unrelated fields, such hf_XXX field does not make
sense.

- The new function allows better control over the way the sub-item descriptions
are added to the top-level item. For example, proto_tree_add_bitmask() function
does not add non-enumerated integers, does not use true_false_string to display
boolean.

- The new function allows to specify "fallback" text for the top-level item
which is used if no items were added to the top-level item.

svn path=/trunk/; revision=25920
This commit is contained in:
Anders Broman 2008-08-04 20:41:43 +00:00
parent 774f288597
commit da85c3dfab
3 changed files with 198 additions and 92 deletions

View File

@ -2018,6 +2018,11 @@ protocol or field labels to the proto_tree:
proto_tree_add_bitmask(tree, tvb, start, header, ett, **fields,
little_endian);
proto_item *
proto_tree_add_bitmask_text(proto_tree *tree, tvbuff_t *tvb,
guint offset, guint len, const char *name, const char *fallback,
gint ett, const int **fields, gboolean little_endian, int flags);
The 'tree' argument is the tree to which the item is to be added. The
'tvb' argument is the tvbuff from which the item's value is being
extracted; the 'start' argument is the offset from the beginning of that
@ -2318,8 +2323,8 @@ This is like proto_tree_add_text(), but takes, as the last argument, a
variable-length list of arguments to add a text item to the protocol
tree.
proto_tree_add_bitmask()
------------------------
proto_tree_add_bitmask() and proto_tree_add_bitmask_text()
----------------------------------------------------------
This function provides an easy to use and convenient helper function
to manage many types of common bitmasks that occur in protocols.
@ -2430,6 +2435,24 @@ filter is then possible:
tr.rif_ring eq 0x013
The proto_tree_add_bitmask_text() function is an extended version of
the proto_tree_add_bitmask() function. In addition, it allows to:
- Provide a leading text (e.g. "Flags: ") that will appear before
the comma-separated list of field values
- Provide a fallback text (e.g. "None") that will be appended if
no fields warranted a change to the top-level title.
- Using flags, specify which fields will affect the top-level title.
There are the following flags defined:
BMT_NO_APPEND - the title is taken "as-is" from the 'name' argument.
BMT_NO_INT - only boolean flags are added to the title.
BMT_NO_FALSE - boolean flags are only added to the title if they are set.
BMT_NO_TFS - only add flag name to the title, do not use true_false_string
The proto_tree_add_bitmask() behavior can be obtained by providing
both 'name' and 'fallback' arguments as NULL, and a flags of
(BMT_NO_FALSE|BMT_NO_TFS).
1.7 Utility routines.

View File

@ -202,6 +202,9 @@ 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);
static gboolean
proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, int offset, int len, gint ett,
const gint **fields, gboolean little_endian, int flags, gboolean first);
static int proto_register_field_init(header_field_info *hfinfo, int parent);
@ -5695,6 +5698,124 @@ proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt)
}
/* This function is common code for both proto_tree_add_bitmask() and
* proto_tree_add_bitmask_text() functions.
*/
static gboolean
proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, int offset, int len, gint ett,
const int **fields, gboolean little_endian, int flags, gboolean first)
{
guint32 value = 0, tmpval;
proto_tree *tree = NULL;
header_field_info *hf;
const char *fmt;
switch (len) {
case 1:
value = tvb_get_guint8(tvb, offset);
break;
case 2:
value = little_endian ? 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);
break;
case 4:
value = little_endian ? tvb_get_letohl(tvb, offset) :
tvb_get_ntohl(tvb, offset);
break;
default:
g_assert_not_reached();
}
tree = proto_item_add_subtree(item, ett);
while (*fields) {
proto_tree_add_item(tree, **fields, tvb, offset, len, little_endian);
if (flags & BMT_NO_APPEND) {
fields++;
continue;
}
hf = proto_registrar_get_nth(**fields);
DISSECTOR_ASSERT(hf->bitmask != 0);
tmpval = (value & hf->bitmask) >> hf->bitshift;
switch (hf->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:
DISSECTOR_ASSERT(len == ftype_length(hf->type));
if (hf->display == BASE_CUSTOM) {
gchar lbl[ITEM_LABEL_LENGTH];
custom_fmt_func_t fmtfunc = (custom_fmt_func_t)hf->strings;
DISSECTOR_ASSERT(fmtfunc);
fmtfunc(lbl, tmpval);
proto_item_append_text(item, "%s%s: %s", first ? "" : ", ",
hf->name, lbl);
first = FALSE;
}
else if (hf->strings) {
proto_item_append_text(item, "%s%s: %s", first ? "" : ", ",
hf->name, val_to_str(tmpval, hf->strings, "Unknown"));
first = FALSE;
}
else if (!(flags & BMT_NO_INT)) {
if (!first) {
proto_item_append_text(item, ", ");
}
fmt = IS_FT_INT(hf->type) ? hfinfo_int_format(hf) : hfinfo_uint_format(hf);
if (IS_BASE_DUAL(hf->display)) {
proto_item_append_text(item, fmt, hf->name, tmpval, tmpval);
} else {
proto_item_append_text(item, fmt, hf->name, tmpval);
}
first = FALSE;
}
break;
case FT_BOOLEAN:
DISSECTOR_ASSERT(len * 8 == hf->display);
if (hf->strings && !(flags & BMT_NO_TFS)) {
/* If we have true/false strings, emit full - otherwise messages
might look weird */
const struct true_false_string *tfs =
(const struct true_false_string *)hf->strings;
if (tmpval) {
proto_item_append_text(item, "%s%s: %s", first ? "" : ", ",
hf->name, tfs->true_string);
first = FALSE;
} else if (!(flags & BMT_NO_FALSE)) {
proto_item_append_text(item, "%s%s: %s", first ? "" : ", ",
hf->name, tfs->false_string);
first = FALSE;
}
} else if (hf->bitmask & value) {
/* If the flag is set, show the name */
proto_item_append_text(item, "%s%s", first ? "" : ", ", hf->name);
first = FALSE;
}
break;
default:
g_assert_not_reached();
}
fields++;
}
return first;
}
/* 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.
@ -5708,105 +5829,45 @@ proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt)
* 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
* 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_add_bitmask(proto_tree *parent_tree, tvbuff_t *tvb, guint 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;
proto_item *item = NULL;
header_field_info *hf;
int len;
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();
hf = proto_registrar_get_nth(hf_hdr);
DISSECTOR_ASSERT(IS_FT_INT(hf->type) || IS_FT_UINT(hf->type));
len = ftype_length(hf->type);
if (parent_tree) {
item = proto_tree_add_item(parent_tree, hf_hdr, tvb, offset, len, little_endian);
proto_item_add_bitmask_tree(item, tvb, offset, len, ett, fields, little_endian,
BMT_NO_INT|BMT_NO_TFS, FALSE);
}
if(parent_tree){
item=proto_tree_add_item(parent_tree, hf_hdr, tvb, offset, len, little_endian);
tree=proto_item_add_subtree(item, ett);
}
return item;
}
while(*fields){
header_field_info *hf_field;
guint32 tmpval, tmpmask;
/* The same as proto_tree_add_bitmask(), but using an arbitrary text as a top-level item */
proto_item *
proto_tree_add_bitmask_text(proto_tree *parent_tree, tvbuff_t *tvb, guint offset, guint len,
const char *name, const char *fallback,
gint ett, const int **fields, gboolean little_endian, int flags)
{
proto_item *item = NULL;
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 && hf_field->display != BASE_CUSTOM){
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();
if (parent_tree) {
item = proto_tree_add_text(parent_tree, tvb, offset, len, "%s", name ? name : "");
if (proto_item_add_bitmask_tree(item, tvb, offset, len, ett, fields, little_endian,
flags, TRUE) && fallback) {
/* Still at first item - append 'fallback' text if any */
proto_item_append_text(item, "%s", fallback);
}
fields++;
}
return item;

View File

@ -1539,6 +1539,7 @@ proto_find_field_from_offset(proto_tree *tree, guint offset, tvbuff_t *tvb);
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}.
@param ett subtree index
@param fields 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.
@ -1549,7 +1550,28 @@ proto_find_field_from_offset(proto_tree *tree, guint offset, tvbuff_t *tvb);
@param little_endian big or little endian byte representation
@return the newly created item */
extern proto_item *
proto_tree_add_bitmask(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian);
proto_tree_add_bitmask(proto_tree *tree, tvbuff_t *tvb, guint offset,
int hf_hdr, gint ett, const int **fields, gboolean little_endian);
/** Add a text with a subtree of bitfields.
@param tree the tree to append this item to
@param tvb the tv buffer of the current data
@param offset start of data in tvb
@param name field name (NULL if bitfield contents should be used)
@param fallback field name if none of bitfields were usable
@param ett subtree index
@param fields NULL-terminated array of bitfield indexes
@param little_endian big or little endian byte representation
@return the newly created item */
extern proto_item *
proto_tree_add_bitmask_text(proto_tree *tree, tvbuff_t *tvb, guint offset, guint len,
const char *name, const char *fallback,
gint ett, const int **fields, gboolean little_endian, int flags);
#define BMT_NO_APPEND 0x01 /**< Don't change the title at all */
#define BMT_NO_INT 0x02 /**< Don't add integral (non-boolean) fields to title */
#define BMT_NO_FALSE 0x04 /**< Don't add booleans unless they're TRUE */
#define BMT_NO_TFS 0x08 /**< Don't use true_false_string while formatting booleans */
/** Add bits to a proto_tree, using the text label registered to that item.
The item is extracted from the tvbuff handed to it.