diff options
-rw-r--r-- | doc/README.developer | 39 | ||||
-rw-r--r-- | epan/proto.c | 146 | ||||
-rw-r--r-- | epan/ptvcursor.h | 30 |
3 files changed, 212 insertions, 3 deletions
diff --git a/doc/README.developer b/doc/README.developer index b3b025ba4c..bcd06b1b69 100644 --- a/doc/README.developer +++ b/doc/README.developer @@ -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* diff --git a/epan/proto.c b/epan/proto.c index b8fe50d426..8d436dcb3a 100644 --- a/epan/proto.c +++ b/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) diff --git a/epan/ptvcursor.h b/epan/ptvcursor.h index 8c14e4c21c..9080a8b5be 100644 --- a/epan/ptvcursor.h +++ b/epan/ptvcursor.h @@ -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__ */ |