- new ptvcursor subtrees management functions :
authorSebastien Tandel <sebastien@tandel.be>
Fri, 30 Mar 2007 00:21:39 +0000 (00:21 -0000)
committerSebastien Tandel <sebastien@tandel.be>
Fri, 30 Mar 2007 00:21:39 +0000 (00:21 -0000)
  * 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

doc/README.developer
epan/proto.c
epan/ptvcursor.h

index b3b025ba4caa23dbab4f6c9ea91451d1e477dc29..bcd06b1b69edac4015e64601fdf01902cafe52e7 100644 (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*
index b8fe50d426caece951be89a04b22be14b9a45f72..8d436dcb3abc647a188c6a15ebea410a6ab7cb42 100644 (file)
 #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)
index 8c14e4c21cd6aff83fcf94971b7f64b086828a6d..9080a8b5be9a03374512ad2a0fdbd48db19b3cbc 100644 (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__ */