aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/README.developer39
-rw-r--r--epan/proto.c146
-rw-r--r--epan/ptvcursor.h30
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__ */