forked from osmocom/wireshark
- new ptvcursor subtrees management functions :
* ptvcursor_push_subtree(), ptvcursor_pop_subtree() for pushing/popping subtrees. Multiple levels of subtrees (256 max.), allocation per 8 levels. * Two new functions creating an item in the tree and pushing a subtree at the same time. These two functions accept an undefined length (SUBTREE_UNDEFINED_LENGTH). The length of the item is set at the next pop. 1) ptvcursor_add_with_subtree 2) ptvcursor_add_text_with_subtree - get rid of potential memory leaks with g_new in ptvcursor_new(). - Documentation of the new ptvcursor functions in README.developer svn path=/trunk/; revision=21276
This commit is contained in:
parent
c76ee5bc80
commit
0ca67aef30
|
@ -3395,6 +3395,17 @@ The three steps for a simple protocol are:
|
|||
2. Add fields with multiple calls of ptvcursor_add()
|
||||
3. Delete the ptvcursor with ptvcursor_free()
|
||||
|
||||
ptvcursor offers the possibility to add subtrees in the tree as well. It can be
|
||||
done in very simple steps :
|
||||
1. Create a new subtree with ptvcursor_push_subtree(). The old subtree is
|
||||
pushed in a stack and the new subtree will be used by ptvcursor.
|
||||
2. Add fields with multiple calls of ptvcursor_add(). The fields will be
|
||||
added in the new subtree created at the previous step.
|
||||
3. Pop the previous subtree with ptvcursor_pop_subtree(). The previous
|
||||
subtree is again used by ptvcursor.
|
||||
Note that at the end of the parsing of a packet you must have popped each
|
||||
subtree you pushed. If it's not the case, the dissector will generate an error.
|
||||
|
||||
To use the ptvcursor API, include the "ptvcursor.h" file. The PGM dissector
|
||||
is an example of how to use it. You don't need to look at it as a guide;
|
||||
instead, the API description here should be good enough.
|
||||
|
@ -3429,6 +3440,34 @@ ptvcursor_free(ptvcursor_t*)
|
|||
Frees the memory associated with the ptvcursor. You must call this
|
||||
after your dissection with the ptvcursor API is completed.
|
||||
|
||||
|
||||
proto_tree*
|
||||
ptvcursor_push_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree)
|
||||
Pushes the current subtree in the tree stack of the cursor, creates a new
|
||||
one and sets this one as the working tree.
|
||||
|
||||
void
|
||||
ptvcursor_pop_subtree(ptvcursor_t *ptvc);
|
||||
Pops a subtree in the tree stack of the cursor
|
||||
|
||||
proto_tree*
|
||||
ptvcursor_add_with_subtree(ptvcursor_t * ptvc, int hfindex, gint length,
|
||||
gboolean little_endian, gint ett_subtree);
|
||||
Adds an item to the tree and creates a subtree.
|
||||
If the length is unknown, length may be defined as
|
||||
SUBTREE_UNDEFINED_LENGTH. In this case, at the next pop, 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, ...);
|
||||
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, at the next pop, the item length
|
||||
will be equal to the advancement of the cursor since the creation of the
|
||||
subtree.
|
||||
|
||||
2.8.2 Miscellaneous functions.
|
||||
|
||||
tvbuff_t*
|
||||
|
|
146
epan/proto.c
146
epan/proto.c
|
@ -44,7 +44,20 @@
|
|||
#include "tvbuff.h"
|
||||
#include "emem.h"
|
||||
|
||||
#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;
|
||||
|
@ -596,6 +609,29 @@ proto_registrar_get_byname(const char *field_name)
|
|||
return g_tree_lookup(gpa_name_tree, field_name);
|
||||
}
|
||||
|
||||
|
||||
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:
|
||||
* proto_tree, tvbuff, and offset. */
|
||||
ptvcursor_t*
|
||||
|
@ -603,18 +639,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. */
|
||||
|
@ -634,7 +675,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
|
||||
|
@ -643,6 +687,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)
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <glib.h>
|
||||
#include <epan/packet.h>
|
||||
|
||||
#define SUBTREE_UNDEFINED_LENGTH -1
|
||||
|
||||
typedef struct ptvcursor ptvcursor_t;
|
||||
|
||||
/* Allocates an initializes a ptvcursor_t with 3 variables:
|
||||
|
@ -77,4 +79,32 @@ ptvcursor_tree(ptvcursor_t* ptvc);
|
|||
void
|
||||
ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree);
|
||||
|
||||
/* push a subtree in the tree stack of the cursor */
|
||||
proto_tree*
|
||||
ptvcursor_push_subtree(ptvcursor_t *ptvc, proto_item *it, gint ett_subtree);
|
||||
|
||||
/* pop a subtree in the tree stack of the cursor */
|
||||
void ptvcursor_pop_subtree(ptvcursor_t *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);
|
||||
|
||||
/* 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, ...);
|
||||
|
||||
/* 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);
|
||||
|
||||
#endif /* __PTVCURSOR_H__ */
|
||||
|
|
Loading…
Reference in New Issue