- 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:
Sebastien Tandel 2007-03-30 00:21:39 +00:00
parent c76ee5bc80
commit 0ca67aef30
3 changed files with 212 additions and 3 deletions

View File

@ -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*

View File

@ -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)

View File

@ -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__ */