Wireshark-dev: [Wireshark-dev] [PATCH][UPDATE] ptvcursor and subtrees
From: Sebastien Tandel <sebastien@xxxxxxxxx>
Date: Thu, 15 Mar 2007 01:11:01 +0100
Hi,


   Series of three patches concerning the creation of subtrees via the
ptvcursor API :

1) ptvcursor-subtrees.diff : Update to get rid of potential memory leaks
with g_renew but also with g_new in ptvcursor_new().

New features supported by ptvcursor API :
  - 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

2) ptvcursor-subtrees-doc.diff : documentation of the new ptvcursor functions in README.developer

3) homeplug-ptvcursor-subtrees.diff : update of the homeplug dissector using the new ptvcursor functions.


Index: epan/dissectors/packet-homeplug.c
===================================================================
--- epan/dissectors/packet-homeplug.c	(révision 21032)
+++ epan/dissectors/packet-homeplug.c	(copie de travail)
@@ -39,7 +39,6 @@
 #include <epan/ptvcursor.h>
 
 
-
 /* METYPE Values */
 #define HOMEPLUG_MME_RCE      0x00
 #define HOMEPLUG_MME_CER      0x01
@@ -70,16 +69,15 @@
 #define HOMEPLUG_CER_NBDAS    0x7F
 
 
-/*  Length of Network Statistics Response defines whether it is the Basic or
- *  the Extended Response
- */
+/* Length of Network Statistics Response defines whether it is the Basic or the
+ * Extended Response */
 #define HOMEPLUG_NS_BASIC_LEN 187
 #define HOMEPLUG_NS_EXT_LEN   199
 
 /* forward reference */
 void proto_reg_handoff_homeplug();
 
-static int proto_homeplug = -1;
+static int proto_homeplug		= -1;
 
 static int hf_homeplug_mctrl		= -1;
   static int hf_homeplug_mctrl_reserved = -1;
@@ -122,29 +120,28 @@
     static int hf_homeplug_psr_rxbp40	= -1;
   /* Network Statistics */
       /* Basic */
-  static int hf_homeplug_ns			= -1;
-    static int hf_homeplug_ns_netw_ctrl_ac	= -1;
-    static int hf_homeplug_ns_netw_ctrl_icid	= -1;
-    static int hf_homeplug_ns_netw_ctrl_icid_rsvd= -1;
-    static int hf_homeplug_ns_bytes40_robo	= -1;
-    static int hf_homeplug_ns_fails_robo	  = -1;
-    static int hf_homeplug_ns_drops_robo	= -1;
-    static int hf_homeplug_ns_netw_da		= -1;
-    static int hf_homeplug_ns_bytes40		= -1;
-    static int hf_homeplug_ns_fails		= -1;
-    static int hf_homeplug_ns_drops		= -1;
+  static int hf_homeplug_ns		      = -1;
+    static int hf_homeplug_ns_netw_ctrl_ac    = -1;
+    static int hf_homeplug_ns_netw_ctrl_icid  = -1;
+    static int hf_homeplug_ns_netw_ctrl_icid_rsvd = -1;
+    static int hf_homeplug_ns_bytes40_robo    = -1;
+    static int hf_homeplug_ns_fails_robo      = -1;
+    static int hf_homeplug_ns_drops_robo      = -1;
+    static int hf_homeplug_ns_netw_da	      = -1;
+    static int hf_homeplug_ns_bytes40	      = -1;
+    static int hf_homeplug_ns_fails	      = -1;
+    static int hf_homeplug_ns_drops	      = -1;
     /* array of 15 elements */
-/*    static int hf_homeplug_ns_bytes40_1	= -1;
+/*    static int hf_homeplug_ns_bytes40_1	    = -1;
     static int hf_homeplug_ns_bytes40_1 */
       /* Extended */
     /* array of 6 elements */
-/*    static int hf_homeplug_ns_tx_bfr_0_state	= -1;*/
+/*    static int hf_homeplug_ns_tx_bfr_0_state = -1;*/
 
 static gint ett_homeplug		= -1;
 static gint ett_homeplug_mctrl		= -1;
 static gint ett_homeplug_mehdr		= -1;
-/* for a later use */
-/* static gint ett_homeplug_mme		= -1; */
+static gint ett_homeplug_mme		= -1;
 static gint ett_homeplug_rce		= -1;
 static gint ett_homeplug_cer		= -1;
 static gint ett_homeplug_rps		= -1;
@@ -172,15 +169,15 @@
 #define HOMEPLUG_NS_ICID_RSVD_MASK	0x78
 /* string values in function of IC_ID values */
 static const value_string homeplug_ns_icid_vals[] = {
-    { HOMEPLUG_NS_ICID5130A1,   "INT5130A1" },
-    { HOMEPLUG_NS_ICID51X1USB,  "INT51X1 (USB Option)" },
-    { HOMEPLUG_NS_ICID51X1PHY,  "INT51X1 (PHY Option)" },
+    { HOMEPLUG_NS_ICID5130A1,	"INT5130A1" },
+    { HOMEPLUG_NS_ICID51X1USB,	"INT51X1 (USB Option)" },
+    { HOMEPLUG_NS_ICID51X1PHY,	"INT51X1 (PHY Option)" },
     { HOMEPLUG_NS_ICID51X1HOST, "INT51X1 (Host/DTE Option)" },
-    { HOMEPLUG_NS_ICID5130A2,   "INT5130A2" },
-    { HOMEPLUG_NS_ICID_RSVD1,   "Reserved"},
-    { HOMEPLUG_NS_ICID_RSVD2,   "Reserved"},
-    { HOMEPLUG_NS_ICID_RSVD3,   "Reserved"},
-    { 0,			NULL }
+    { HOMEPLUG_NS_ICID5130A2,	"INT5130A2" },
+    { HOMEPLUG_NS_ICID_RSVD1,	"Reserved"},
+    { HOMEPLUG_NS_ICID_RSVD2,	"Reserved"},
+    { HOMEPLUG_NS_ICID_RSVD3,	"Reserved"},
+    { 0,      NULL }
 };
 
 /* Modulation Method Bit Mask */
@@ -196,17 +193,17 @@
   { HOMEPLUG_CER_MOD_DBPSK, "DBPSK Modulation"},
   { HOMEPLUG_CER_MOD_DQPSK, "DQPSK Modulation"},
   { HOMEPLUG_CER_MOD_RSVD,  "Reserved"},
-  { 0,			    NULL}
+  { 0, NULL}
 };
 
 #define HOMEPLUG_MCTRL_LEN 1
 #define HOMEPLUG_MEHDR_LEN 1
 #define HOMEPLUG_MELEN_LEN 1
 
-
 void
 proto_register_homeplug(void)
 {
+
   static hf_register_info hf[] = {
     /* MAC Control Field */
     { &hf_homeplug_mctrl,
@@ -216,186 +213,186 @@
 
     { &hf_homeplug_mctrl_reserved,
       { "Reserved", "homeplug.mctrl.rsvd",
-	FT_NONE, BASE_DEC, NULL, HOMEPLUG_MCTRL_RSVD, "Reserved", HFILL }
+      FT_NONE, BASE_DEC, NULL, HOMEPLUG_MCTRL_RSVD, "Reserved", HFILL }
     },
 
     { &hf_homeplug_mctrl_ne,
       { "Number of MAC Data Entries", "homeplug.mctrl.ne",
-	FT_UINT8, BASE_DEC, NULL, HOMEPLUG_MCTRL_NE, "Number of MAC Data Entries", HFILL }
+      FT_UINT8, BASE_DEC, NULL, HOMEPLUG_MCTRL_NE, "Number of MAC Data Entries", HFILL }
     },
 
     /* MAC Entry Header */
     { &hf_homeplug_mehdr,
       { "MAC Management Entry Header", "homeplug.mehdr",
-	FT_NONE, BASE_DEC, NULL, 0x0, "MAC Management Entry Header", HFILL }
+      FT_NONE, BASE_DEC, NULL, 0x0, "MAC Management Entry Header", HFILL }
     },
 
     { &hf_homeplug_mehdr_mev,
       { "MAC Entry Version", "homeplug.mehdr.mev",
-	FT_UINT8, BASE_DEC, NULL, HOMEPLUG_MEHDR_MEV, "MAC Entry Version", HFILL }
+      FT_UINT8, BASE_DEC, NULL, HOMEPLUG_MEHDR_MEV, "MAC Entry Version", HFILL }
     },
 
     { &hf_homeplug_mehdr_metype,
       { "MAC Entry Type", "homeplug.mehdr.metype",
-	FT_UINT8, BASE_HEX, NULL, HOMEPLUG_MEHDR_METYPE, "MAC Entry Type", HFILL }
+      FT_UINT8, BASE_HEX, NULL, HOMEPLUG_MEHDR_METYPE, "MAC Entry Type", HFILL }
     },
 
     /* MAC Entry Len */
     { &hf_homeplug_melen,
       { "MAC Management Entry Length", "homeplug.melen",
-	FT_UINT8, BASE_DEC, NULL, 0x0, "MAC Management Entry Length", HFILL }
+      FT_UINT8, BASE_DEC, NULL, 0x0, "MAC Management Entry Length", HFILL }
     },
 
     /* MAC Management Entry */
     { &hf_homeplug_mme,
       { "MAC Management Entry Data", "homeplug.mmentry",
-	FT_UINT8, BASE_DEC, NULL, 0x0, "MAC Management Entry Data", HFILL }
+      FT_UINT8, BASE_DEC, NULL, 0x0, "MAC Management Entry Data", HFILL }
     },
 
     /* Request Channel Estimation */
     { &hf_homeplug_rce,
       { "Request Channel Estimation", "homeplug.rce",
-	FT_NONE, BASE_DEC, NULL, 0x0, "Request Channel Estimation", HFILL }
+      FT_NONE, BASE_DEC, NULL, 0x0, "Request Channel Estimation", HFILL }
     },
 
     { &hf_homeplug_rce_cev,
       { "Channel Estimation Version", "homeplug.rce.cev",
-	FT_UINT8, BASE_DEC, NULL, HOMEPLUG_RCE_CEV, "Channel Estimation Version", HFILL }
+      FT_UINT8, BASE_DEC, NULL, HOMEPLUG_RCE_CEV, "Channel Estimation Version", HFILL }
     },
 
     { &hf_homeplug_rce_rsvd,
       { "Reserved", "homeplug.rce.rsvd",
-	FT_NONE, BASE_DEC, NULL, HOMEPLUG_RCE_RSVD, "Reserved", HFILL }
+      FT_NONE, BASE_DEC, NULL, HOMEPLUG_RCE_RSVD, "Reserved", HFILL }
     },
 
     /* Channel Estimation Response */
     { &hf_homeplug_cer,
       { "Channel Estimation Response", "homeplug.cer",
-	FT_NONE, BASE_DEC, NULL, 0x0, "Channel Estimation Response", HFILL }
+      FT_NONE, BASE_DEC, NULL, 0x0, "Channel Estimation Response", HFILL }
     },
 
     { &hf_homeplug_cer_cerv,
       { "Channel Estimation Response Version", "homeplug.cer.cerv",
-	FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_CERV, "Channel Estimation Response Version", HFILL }
+      FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_CERV, "Channel Estimation Response Version", HFILL }
     },
 
     { &hf_homeplug_cer_rsvd1,
       { "Reserved", "homeplug.cer.rsvd1",
-	FT_NONE, BASE_DEC, NULL, HOMEPLUG_CER_RSVD, "Reserved", HFILL }
+      FT_NONE, BASE_DEC, NULL, HOMEPLUG_CER_RSVD, "Reserved", HFILL }
     },
 
     { &hf_homeplug_cer_rxtmi,
       { "Receive Tone Map Index", "homeplug.cer.rxtmi",
-	FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RXTMI, "Receive Tone Map Index", HFILL }
+      FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RXTMI, "Receive Tone Map Index", HFILL }
     },
 
     /* TODO must append vt[79-0] */
 
     { &hf_homeplug_cer_vt,
       {"Valid Tone Flags", "homeplug.cer.vt",
-	FT_UINT8, BASE_HEX, NULL, 0x0, "Valid Tone Flags", HFILL }
+      FT_UINT8, BASE_HEX, NULL, 0x0, "Valid Tone Flags", HFILL }
     },
 
     { &hf_homeplug_cer_rate,
       { "FEC Rate", "homeplug.cer.rate",
-	FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RATE, "FEC Rate", HFILL }
+      FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RATE, "FEC Rate", HFILL }
     },
 
     { &hf_homeplug_cer_bp,
       { "Bridge Proxy", "homeplug.cer.bp",
-	FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_BP, "Bridge Proxy", HFILL }
+      FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_BP, "Bridge Proxy", HFILL }
     },
 
     { &hf_homeplug_cer_mod,
       { "Modulation Method", "homeplug.cer.mod",
-	FT_UINT8, BASE_DEC, VALS(&homeplug_cer_mod_vals), HOMEPLUG_CER_MOD_MASK,
-	"Modulation Method", HFILL }
+      FT_UINT8, BASE_DEC, VALS(&homeplug_cer_mod_vals), HOMEPLUG_CER_MOD_MASK,
+      "Modulation Method", HFILL }
     },
 
     { &hf_homeplug_cer_vt11,
       { "Valid Tone Flags [83-80]", "homeplug.cer.vt11",
-	FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_VT11, "Valid Tone Flags [83-80]", HFILL }
+      FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_VT11, "Valid Tone Flags [83-80]", HFILL }
     },
 
     { &hf_homeplug_cer_rsvd2,
       { "Reserved", "homeplug.cer.rsvd2",
-	FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RSVD2, "Reserved", HFILL }
+      FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RSVD2, "Reserved", HFILL }
     },
 
     { &hf_homeplug_cer_nbdas,
       { "Number Bridged Destination Addresses", "homeplug.cer.nbdas",
-	FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_NBDAS, "Number Bridged Destination Addresses", HFILL }
+      FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_NBDAS, "Number Bridged Destination Addresses", HFILL }
     },
 
     { &hf_homeplug_cer_bda,
       { "Bridged Destination Address", "homeplug.cer.bda",
-	FT_ETHER, BASE_HEX, NULL, 0x0, "Bridged Destination Address", HFILL }
+      FT_ETHER, BASE_HEX, NULL, 0x0, "Bridged Destination Address", HFILL }
     },
 
     /* Request Parameters and Statistics */
     { &hf_homeplug_rps,
       { "Request Parameters and Statistics", "homeplug.rps",
-	FT_NONE, BASE_DEC, NULL, 0x0, "Request Parameters and Statistics", HFILL }
+      FT_NONE, BASE_DEC, NULL, 0x0, "Request Parameters and Statistics", HFILL }
     },
 
     /* Parameters and Statistics Response */
     { &hf_homeplug_psr,
       { "Parameters and Statistics Response", "homeplug.psr",
-	FT_NONE, BASE_DEC, NULL, 0x0, "Parameters and Statistics Response", HFILL }
+      FT_NONE, BASE_DEC, NULL, 0x0, "Parameters and Statistics Response", HFILL }
     },
 
     { &hf_homeplug_psr_txack,
       { "Transmit ACK Counter", "homeplug.psr.txack",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit ACK Counter", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit ACK Counter", HFILL }
     },
 
     { &hf_homeplug_psr_txnack,
       { "Transmit NACK Counter", "homeplug.psr.txnack",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit NACK Counter", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit NACK Counter", HFILL }
     },
 
     { &hf_homeplug_psr_txfail,
       { "Transmit FAIL Counter", "homeplug.psr.txfail",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit FAIL Counter", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit FAIL Counter", HFILL }
     },
 
     { &hf_homeplug_psr_txcloss,
       { "Transmit Contention Loss Counter", "homeplug.psr.txcloss",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit Contention Loss Counter", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit Contention Loss Counter", HFILL }
     },
 
     { &hf_homeplug_psr_txcoll,
       { "Transmit Collision Counter", "homeplug.psr.txcoll",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit Collision Counter", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit Collision Counter", HFILL }
     },
 
     { &hf_homeplug_psr_txca3lat,
       { "Transmit CA3 Latency Counter", "homeplug.psr.txca3lat",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA3 Latency Counter", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA3 Latency Counter", HFILL }
     },
 
     { &hf_homeplug_psr_txca2lat,
       { "Transmit CA2 Latency Counter", "homeplug.psr.txca2lat",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA2 Latency Counter", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA2 Latency Counter", HFILL }
     },
     { &hf_homeplug_psr_txca1lat,
       { "Transmit CA1 Latency Counter", "homeplug.psr.txca1lat",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA1 Latency Counter", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA1 Latency Counter", HFILL }
     },
     { &hf_homeplug_psr_txca0lat,
       { "Transmit CA0 Latency Counter", "homeplug.psr.txca0lat",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA0 Latency Counter", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA0 Latency Counter", HFILL }
     },
 
     { &hf_homeplug_psr_rxbp40,
       { "Receive Cumulative Bytes per 40-symbol", "homeplug.psr.rxbp40",
-	FT_UINT32, BASE_DEC, NULL, 0x0, "Receive Cumulative Bytes per 40-symbol", HFILL }
+      FT_UINT32, BASE_DEC, NULL, 0x0, "Receive Cumulative Bytes per 40-symbol", HFILL }
     },
 
     /* Network Statistics Basic */
     { &hf_homeplug_ns,
       { "Network Statistics Basic", "homeplug.ns",
-	FT_NONE, BASE_DEC, NULL, 0x0, "Network Statistics Basic", HFILL }
+      FT_NONE, BASE_DEC, NULL, 0x0, "Network Statistics Basic", HFILL }
     },
 
     { &hf_homeplug_ns_netw_ctrl_ac,
@@ -410,43 +407,43 @@
 
     { &hf_homeplug_ns_netw_ctrl_icid_rsvd,
       { "IC_ID Reserved", "homeplug.ns.icid",
-	FT_NONE, BASE_DEC, NULL, 0x0, "IC_ID Reserved", HFILL }
+      FT_NONE, BASE_DEC, NULL, 0x0, "IC_ID Reserved", HFILL }
     },
 
     { &hf_homeplug_ns_bytes40_robo,
       { "Bytes in 40 symbols in ROBO", "homeplug.ns.bytes40_robo",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Bytes in 40 symbols in ROBO", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Bytes in 40 symbols in ROBO", HFILL }
     },
 
     { &hf_homeplug_ns_fails_robo,
       { "Fails Received in ROBO", "homeplug.ns.fails_robo",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Fails Received in ROBO", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Fails Received in ROBO", HFILL }
     },
 
     { &hf_homeplug_ns_drops_robo,
       { "Frame Drops in ROBO", "homeplug.ns.drops_robo",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Frame Drops in ROBO", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Frame Drops in ROBO", HFILL }
     },
 
     /* TODO NETW_DA1 ... */
     { &hf_homeplug_ns_netw_da,
       { "Address of Network DA", "homeplug.ns.netw_da",
-	FT_ETHER, BASE_HEX, NULL, 0x0, "Address of Network DA", HFILL }
+      FT_ETHER, BASE_HEX, NULL, 0x0, "Address of Network DA", HFILL }
     },
 
     { &hf_homeplug_ns_bytes40,
       { "Bytes in 40 symbols", "homeplug.ns.bytes40",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Bytes in 40 symbols", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Bytes in 40 symbols", HFILL }
     },
 
     { &hf_homeplug_ns_fails,
       { "Fails Received", "homeplug.ns.fails",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Fails Received", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Fails Received", HFILL }
     },
 
     { &hf_homeplug_ns_drops,
       { "Frame Drops", "homeplug.ns.drops",
-	FT_UINT16, BASE_DEC, NULL, 0x0, "Frame Drops", HFILL }
+      FT_UINT16, BASE_DEC, NULL, 0x0, "Frame Drops", HFILL }
     }
 
     /* TODO Network Statistics Extended */
@@ -462,7 +459,7 @@
     &ett_homeplug_rps,
     &ett_homeplug_psr,
     &ett_homeplug_ns,
-    &ett_homeplug_tone,
+    &ett_homeplug_tone
   };
 
   proto_homeplug = proto_register_protocol(
@@ -476,261 +473,219 @@
   proto_register_subtree_array(ett, array_length(ett));
 }
 
-
 /* Dissection of MCTRL */
 static void dissect_homeplug_mctrl(ptvcursor_t * cursor)
 {
-  proto_tree *initial_tree = NULL;
-  proto_tree *additional_tree = NULL;
-  proto_item *it = NULL;
+  proto_item * it = NULL;
 
-  if (!cursor || !ptvcursor_tree(cursor))
+  if (!ptvcursor_tree(cursor)) 
     return;
 
-  initial_tree = ptvcursor_tree(cursor);
-
   it = ptvcursor_add_no_advance(cursor, hf_homeplug_mctrl, 1, FALSE);
-  homeplug_ne = tvb_get_guint8(ptvcursor_tvbuff(cursor),
-			       ptvcursor_current_offset(cursor))
-		& HOMEPLUG_MCTRL_NE;
+  homeplug_ne = tvb_get_guint8(ptvcursor_tvbuff(cursor), 
+	    ptvcursor_current_offset(cursor)) & HOMEPLUG_MCTRL_NE;
 
-  additional_tree = proto_item_add_subtree(it, ett_homeplug_mctrl);
-  ptvcursor_set_tree(cursor, additional_tree);
-  ptvcursor_add_no_advance(cursor, hf_homeplug_mctrl_reserved, 1, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_mctrl_ne, 1, FALSE);
+  ptvcursor_push_subtree(cursor, it, ett_homeplug_mctrl);
+    ptvcursor_add_no_advance(cursor, hf_homeplug_mctrl_reserved, 1, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_mctrl_ne, 1, FALSE);
 
-  ptvcursor_set_tree(cursor, initial_tree);
+  ptvcursor_pop_subtree(cursor);
 }
 
 /* Dissection of MEHDR */
 static void dissect_homeplug_mehdr(ptvcursor_t * cursor)
 {
-  proto_tree *initial_tree = NULL;
-  proto_tree *additional_tree = NULL;
-  proto_item *it = NULL;
+  proto_item * it = NULL;
 
-  if (!cursor || !ptvcursor_tree(cursor))
+  if (!ptvcursor_tree(cursor)) 
     return;
 
-  initial_tree = ptvcursor_tree(cursor);
-
   it = ptvcursor_add_no_advance(cursor, hf_homeplug_mehdr, 0, FALSE);
-  homeplug_metype = tvb_get_guint8(ptvcursor_tvbuff(cursor),
-				   ptvcursor_current_offset(cursor))
-		    & HOMEPLUG_MEHDR_METYPE;
+  homeplug_metype = tvb_get_guint8(ptvcursor_tvbuff(cursor), 
+      ptvcursor_current_offset(cursor)) & HOMEPLUG_MEHDR_METYPE;
 
-  additional_tree = proto_item_add_subtree(it, ett_homeplug_mehdr);
-  ptvcursor_set_tree(cursor, additional_tree);
-  ptvcursor_add_no_advance(cursor, hf_homeplug_mehdr_mev, 1, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_mehdr_metype, 1, FALSE);
+  ptvcursor_push_subtree(cursor, it, ett_homeplug_mehdr);
+    ptvcursor_add_no_advance(cursor, hf_homeplug_mehdr_mev, 1, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_mehdr_metype, 1, FALSE);
 
-  ptvcursor_set_tree(cursor, initial_tree);
+  ptvcursor_pop_subtree(cursor);
 }
 
-
 /* dissection of MELEN */
-static void dissect_homeplug_melen(ptvcursor_t *cursor)
+static void dissect_homeplug_melen(ptvcursor_t * cursor)
 {
-  if (!cursor || !ptvcursor_tree(cursor))
+  if (!ptvcursor_tree(cursor)) 
     return;
 
-  homeplug_melen = tvb_get_guint8(ptvcursor_tvbuff(cursor),
-				  ptvcursor_current_offset(cursor));
+  homeplug_melen = tvb_get_guint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)); 
   ptvcursor_add(cursor, hf_homeplug_melen, 1, FALSE);
+
 }
 
 /* Dissection of Request Channel Estimation MME */
-static void dissect_homeplug_rce(ptvcursor_t *cursor)
+static void dissect_homeplug_rce(ptvcursor_t * cursor)
 {
-  proto_tree *initial_tree = NULL;
-  proto_tree *additional_tree = NULL;
-  proto_item *it = NULL;
+  proto_item * it = NULL;
 
-  if (!cursor || !ptvcursor_tree(cursor))
+  if (!ptvcursor_tree(cursor)) 
     return;
 
-  initial_tree = ptvcursor_tree(cursor);
-
   it = ptvcursor_add_no_advance(cursor, hf_homeplug_rce, homeplug_melen, FALSE);
 
-  additional_tree = proto_item_add_subtree(it , ett_homeplug_rce);
-  ptvcursor_set_tree(cursor, additional_tree);
-  ptvcursor_add_no_advance(cursor, hf_homeplug_rce_cev, 1, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_rce_rsvd, 1, FALSE);
+  ptvcursor_push_subtree(cursor, it, ett_homeplug_rce);
+    ptvcursor_add_no_advance(cursor, hf_homeplug_rce_cev, 1, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_rce_rsvd, 1, FALSE);
 
-  ptvcursor_set_tree(cursor, initial_tree);
+  ptvcursor_pop_subtree(cursor);
 }
 
 /* Dissection of Channel Estimation Response MME */
-static void dissect_homeplug_cer(ptvcursor_t *cursor)
+static void dissect_homeplug_cer(ptvcursor_t * cursor)
 {
-  proto_tree *initial_tree = NULL;
-  proto_tree *additional_tree = NULL;
-  proto_item *it = NULL;
-  guint8 iTone;
+  proto_item * it = NULL;
+  guint8 iTone = 0;
   guint8 BP = 0;
   guint8 iNBDA = 0;
 
-  if (!cursor || !ptvcursor_tree(cursor))
+  if (!ptvcursor_tree(cursor)) 
     return;
 
-  initial_tree = ptvcursor_tree(cursor);
-
   it = ptvcursor_add_no_advance(cursor, hf_homeplug_cer_cerv, homeplug_melen, FALSE);
 
-  additional_tree = proto_item_add_subtree(it, ett_homeplug_cer);
-  ptvcursor_set_tree(cursor, additional_tree);
-  ptvcursor_add_no_advance(cursor, hf_homeplug_cer_cerv, 1, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_cer_rsvd1, 2, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_cer_rxtmi, 1, FALSE);
+  ptvcursor_push_subtree(cursor, it, ett_homeplug_cer);
+    ptvcursor_add_no_advance(cursor, hf_homeplug_cer_cerv, 1, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_cer_rsvd1, 2, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_cer_rxtmi, 1, FALSE);
 
-  for (iTone = 0; iTone < 10; iTone++) {
-    ptvcursor_add(cursor, hf_homeplug_cer_vt, 1, FALSE);
-  }
+    for (;iTone < 10; iTone++) {
+      ptvcursor_add(cursor, hf_homeplug_cer_vt, 1, FALSE);
+    }
 
-  ptvcursor_add_no_advance(cursor, hf_homeplug_cer_rate, 1, FALSE);
-  ptvcursor_add_no_advance(cursor, hf_homeplug_cer_bp, 1, FALSE);
-  BP = tvb_get_guint8(ptvcursor_tvbuff(cursor),
-		      ptvcursor_current_offset(cursor)) & HOMEPLUG_CER_BP;
-  ptvcursor_add_no_advance(cursor, hf_homeplug_cer_mod, 1, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_cer_vt11, 1, FALSE);
-  ptvcursor_add_no_advance(cursor, hf_homeplug_cer_rsvd2, 1, FALSE);
+    ptvcursor_add_no_advance(cursor, hf_homeplug_cer_rate, 1, FALSE);
+    ptvcursor_add_no_advance(cursor, hf_homeplug_cer_bp, 1, FALSE);
+    BP = tvb_get_guint8(ptvcursor_tvbuff(cursor), 
+	      ptvcursor_current_offset(cursor)) & HOMEPLUG_CER_BP;
+    ptvcursor_add_no_advance(cursor, hf_homeplug_cer_mod, 1, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_cer_vt11, 1, FALSE);
+    ptvcursor_add_no_advance(cursor, hf_homeplug_cer_rsvd2, 1, FALSE);
 
-  if (BP) {
-    iNBDA = tvb_get_guint8(ptvcursor_tvbuff(cursor),
-			   ptvcursor_current_offset(cursor))
-	    & HOMEPLUG_CER_NBDAS;
-    ptvcursor_add(cursor, hf_homeplug_cer_nbdas, 1, FALSE);
-    /* TODO : Check on iNBDA! INT51X1 up to 16 dba. But up to 32 for INT51X1 (Host/DTE) */
-    for (;iNBDA > 0; iNBDA--) {
-      ptvcursor_add(cursor, hf_homeplug_cer_bda, 6, FALSE);
+    if (BP) {
+      iNBDA = tvb_get_guint8(ptvcursor_tvbuff(cursor), 
+		ptvcursor_current_offset(cursor)) & HOMEPLUG_CER_NBDAS;
+      ptvcursor_add(cursor, hf_homeplug_cer_nbdas, 1, FALSE);
+      /* TODO : Check on iNBDA! INT51X1 up to 16 dba. But up to 32 for INT51X1 (Host/DTE) */
+      for (;iNBDA > 0; iNBDA--) {
+	ptvcursor_add(cursor, hf_homeplug_cer_bda, 6, FALSE);
+      }
     }
-  }
-
-  ptvcursor_set_tree(cursor, initial_tree);
+  ptvcursor_pop_subtree(cursor);
 }
 
 
 /* Dissection of Request Parameters and Statistics MME */
-static void dissect_homeplug_rps(ptvcursor_t *cursor)
+static void dissect_homeplug_rps(ptvcursor_t * cursor) 
 {
-  if (!cursor || !ptvcursor_tree(cursor))
+  if (!ptvcursor_tree(cursor)) 
     return;
 
   ptvcursor_add(cursor, hf_homeplug_rps, 4, FALSE);
 }
 
 /* Dissection of Parameters and Statistics Response MME */
-static void dissect_homeplug_psr(ptvcursor_t *cursor)
+static void dissect_homeplug_psr(ptvcursor_t * cursor)
 {
-  proto_tree *initial_tree = NULL;
-  proto_tree *additional_tree = NULL;
-  proto_item *it = NULL;
+  proto_item * it = NULL;
 
-  if (!cursor || !ptvcursor_tree(cursor))
+  if (!ptvcursor_tree(cursor)) 
     return;
 
-  initial_tree = ptvcursor_tree(cursor);
-
   it = ptvcursor_add_no_advance(cursor, hf_homeplug_psr, homeplug_melen, FALSE);
 
-  additional_tree = proto_item_add_subtree(it, ett_homeplug_psr);
-  ptvcursor_set_tree(cursor, additional_tree);
-  ptvcursor_add(cursor, hf_homeplug_psr_txack, 2, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_psr_txnack, 2, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_psr_txfail, 2, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_psr_txcloss, 2, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_psr_txcoll, 2, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_psr_txca3lat, 2, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_psr_txca2lat, 2, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_psr_txca1lat, 2, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_psr_txca0lat, 2, FALSE);
-  ptvcursor_add(cursor, hf_homeplug_psr_rxbp40, 4, FALSE);
+  ptvcursor_push_subtree(cursor, it, ett_homeplug_psr);
+    ptvcursor_add(cursor, hf_homeplug_psr_txack, 2, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_psr_txnack, 2, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_psr_txfail, 2, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_psr_txcloss, 2, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_psr_txcoll, 2, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_psr_txca3lat, 2, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_psr_txca2lat, 2, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_psr_txca1lat, 2, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_psr_txca0lat, 2, FALSE);
+    ptvcursor_add(cursor, hf_homeplug_psr_rxbp40, 4, FALSE);
 
-  ptvcursor_set_tree(cursor, initial_tree);
+  ptvcursor_pop_subtree(cursor);
 }
 
 /* Dissection of the Network Statistic MME */
-static void dissect_homeplug_ns(ptvcursor_t *cursor)
+static void dissect_homeplug_ns(ptvcursor_t * cursor)
 {
-  proto_item *it = NULL;
-  proto_tree *additional_tree = NULL, *tree_tone = NULL;
-  proto_tree *initial_tree = NULL;
   guint8 homeplug_ns_icid_rsvd = 0;
   guint8 iTone = 0;
-  guint16 ns_bytes40 = 0;
-  guint64 newt_da = 0;
+
+  guint16 ns_bytes40= 0;
+  guint64 newt_da= 0;
 #define NEWT_DA_INEXISTANT G_GINT64_CONSTANT(010000000000U)
 
-  if (!cursor || !ptvcursor_tree(cursor))
+  if (!ptvcursor_tree(cursor)) 
     return;
 
-  initial_tree = ptvcursor_tree(cursor);
-
   /* TODO : test length of the MME : differentiation of NS Basic and Extended */
-  it = ptvcursor_add_no_advance(cursor, hf_homeplug_ns, homeplug_melen, FALSE);
+  ptvcursor_add_with_subtree(cursor, hf_homeplug_ns, SUBTREE_UNDEFINED_LENGTH, FALSE, ett_homeplug_ns);
 
-  additional_tree = proto_item_add_subtree(it, ett_homeplug_ns);
-  ptvcursor_set_tree(cursor, additional_tree);
-  ptvcursor_add_no_advance(cursor, hf_homeplug_ns_netw_ctrl_ac, 1, FALSE);
-  homeplug_ns_icid_rsvd = tvb_get_guint8(ptvcursor_tvbuff(cursor),
-					 ptvcursor_current_offset(cursor))
-			  & HOMEPLUG_NS_ICID_RSVD_MASK;
+  /*it = ptvcursor_add_no_advance(cursor, hf_homeplug_ns, homeplug_melen, FALSE);
 
-  if (homeplug_ns_icid_rsvd)
-    ptvcursor_add(cursor, hf_homeplug_ns_netw_ctrl_icid_rsvd, 1, FALSE);
-  else
-    ptvcursor_add(cursor, hf_homeplug_ns_netw_ctrl_icid, 1, FALSE);
+  ptvcursor_push_subtree(cursor, it, ett_homeplug_ns);*/
+    ptvcursor_add_no_advance(cursor, hf_homeplug_ns_netw_ctrl_ac, 1, FALSE);
+    homeplug_ns_icid_rsvd = tvb_get_guint8(ptvcursor_tvbuff(cursor), 
+	    ptvcursor_current_offset(cursor)) & HOMEPLUG_NS_ICID_RSVD_MASK; 
+    if (homeplug_ns_icid_rsvd)
+      ptvcursor_add(cursor, hf_homeplug_ns_netw_ctrl_icid_rsvd, 1, FALSE);
+    else
+      ptvcursor_add(cursor, hf_homeplug_ns_netw_ctrl_icid, 1, FALSE);
 
-  ptvcursor_add_no_advance(cursor, hf_homeplug_ns_bytes40_robo, 2, TRUE);
-  ns_bytes40 = tvb_get_letohs(ptvcursor_tvbuff(cursor),
-			      ptvcursor_current_offset(cursor));
-  it = proto_tree_add_text(additional_tree, ptvcursor_tvbuff(cursor),
-			   ptvcursor_current_offset(cursor), 2, "MHz :  %.3f",
-			   (float)(ns_bytes40)/42);
-  ptvcursor_advance(cursor, 2);
+    ptvcursor_add_no_advance(cursor, hf_homeplug_ns_bytes40_robo, 2, TRUE);
+    ns_bytes40 = tvb_get_letohs(ptvcursor_tvbuff(cursor),
+	  ptvcursor_current_offset(cursor));
+    proto_tree_add_text(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor), 
+	    ptvcursor_current_offset(cursor), 2, "MHz :  %.3f", (float)(ns_bytes40)/42);
+    ptvcursor_advance(cursor, 2);
 
-  ptvcursor_add(cursor, hf_homeplug_ns_fails_robo, 2, TRUE);
-  ptvcursor_add(cursor, hf_homeplug_ns_drops_robo, 2, TRUE);
+    ptvcursor_add(cursor, hf_homeplug_ns_fails_robo, 2, TRUE);
+    ptvcursor_add(cursor, hf_homeplug_ns_drops_robo, 2, TRUE);
 
-  while (iTone < 15) {
-    newt_da = ((gint64)tvb_get_ntoh24(ptvcursor_tvbuff(cursor),
-				      ptvcursor_current_offset(cursor))) << 24;
-    newt_da |= tvb_get_ntoh24(ptvcursor_tvbuff(cursor),
-			      ptvcursor_current_offset(cursor)+3);
+    while (iTone < 15) { 
+      newt_da = ((gint64)tvb_get_ntoh24(ptvcursor_tvbuff(cursor),
+	ptvcursor_current_offset(cursor))) << 24;
+      newt_da |= tvb_get_ntoh24(ptvcursor_tvbuff(cursor),
+	ptvcursor_current_offset(cursor)+3);
 
-    if (newt_da != NEWT_DA_INEXISTANT) {
-      it = proto_tree_add_text(additional_tree, ptvcursor_tvbuff(cursor),
-			       ptvcursor_current_offset(cursor), 12,
-			       "Tone Map #%d", iTone+1);
+      if (newt_da != NEWT_DA_INEXISTANT) {
+	ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH,
+	    ett_homeplug_tone, "Tone Map #%d", iTone+1);
 
-      tree_tone = proto_item_add_subtree(it, ett_homeplug_tone);
-      ptvcursor_set_tree(cursor, tree_tone);
+	ptvcursor_add(cursor, hf_homeplug_ns_netw_da, 6, FALSE);
 
-      ptvcursor_add(cursor, hf_homeplug_ns_netw_da, 6, FALSE);
+	ptvcursor_add_no_advance(cursor, hf_homeplug_ns_bytes40, 2, TRUE);
+	ns_bytes40 = tvb_get_letohs(ptvcursor_tvbuff(cursor),
+	  ptvcursor_current_offset(cursor));
+	proto_tree_add_text(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor), 
+	    ptvcursor_current_offset(cursor), 2, "MHz :  %.3f", (float)(ns_bytes40)/42);
+	ptvcursor_advance(cursor, 2);
 
-      ptvcursor_add_no_advance(cursor, hf_homeplug_ns_bytes40, 2, TRUE);
-      ns_bytes40 = tvb_get_letohs(ptvcursor_tvbuff(cursor),
-				  ptvcursor_current_offset(cursor));
-      it = proto_tree_add_text(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor),
-			       ptvcursor_current_offset(cursor), 2,
-			       "MHz :  %.3f", (float)(ns_bytes40)/42);
-      ptvcursor_advance(cursor, 2);
+	ptvcursor_add(cursor, hf_homeplug_ns_fails, 2, TRUE);
+	ptvcursor_add(cursor, hf_homeplug_ns_drops, 2, TRUE);
 
-      ptvcursor_add(cursor, hf_homeplug_ns_fails, 2, TRUE);
-      ptvcursor_add(cursor, hf_homeplug_ns_drops, 2, TRUE);
-    } else
-      it = proto_tree_add_text(additional_tree, ptvcursor_tvbuff(cursor),
-			       ptvcursor_current_offset(cursor), 12,
-			       "Tone Map #%d does not exist", iTone+1);
+	ptvcursor_pop_subtree(cursor);
+      } else
+	proto_tree_add_text(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor), 
+		  ptvcursor_current_offset(cursor), 12, "Tone Map #%d does not exist", iTone+1);
 
       iTone++;
-  }
-
-  ptvcursor_set_tree(cursor, initial_tree);
+    }
+  ptvcursor_pop_subtree(cursor);
 }
 
-static void dissect_homeplug_mme(ptvcursor_t *cursor, packet_info *pinfo)
+static void dissect_homeplug_mme(ptvcursor_t * cursor, packet_info * pinfo)
 {
   switch(homeplug_metype) {
     case HOMEPLUG_MME_RCE:
@@ -740,7 +695,6 @@
       }
       dissect_homeplug_rce(cursor);
       break;
-
     case HOMEPLUG_MME_CER:
       if (check_col(pinfo->cinfo, COL_INFO)) {
 	col_clear(pinfo->cinfo, COL_INFO);
@@ -748,15 +702,13 @@
       }
       dissect_homeplug_cer(cursor);
       break;
-
     case HOMEPLUG_MME_RPS:
       if (check_col(pinfo->cinfo, COL_INFO)) {
 	col_clear(pinfo->cinfo, COL_INFO);
 	col_set_str(pinfo->cinfo, COL_INFO, "Request Parameters and Statistics");
-      }
+      } 
       dissect_homeplug_rps(cursor);
       break;
-
     case HOMEPLUG_MME_PSR:
       if (check_col(pinfo->cinfo, COL_INFO)) {
 	col_clear(pinfo->cinfo, COL_INFO);
@@ -764,7 +716,6 @@
       }
       dissect_homeplug_psr(cursor);
       break;
-
     case HOMEPLUG_MME_NS:
       if (check_col(pinfo->cinfo, COL_INFO)) {
 	col_clear(pinfo->cinfo, COL_INFO);
@@ -776,7 +727,7 @@
 }
 
 #define TVB_LEN_GREATEST  1
-#define TVB_LEN_UNDEF	  0
+#define TVB_LEN_UNDEF     0
 #define TVB_LEN_SHORTEST -1
 static int check_tvb_length(ptvcursor_t *cursor, const gint length)
 {
@@ -784,22 +735,21 @@
     return TVB_LEN_UNDEF;
 
   if (tvb_reported_length_remaining(ptvcursor_tvbuff(cursor),
-				    ptvcursor_current_offset(cursor)) < length)
+                                    ptvcursor_current_offset(cursor)) < length)
     return TVB_LEN_SHORTEST;
 
   return TVB_LEN_GREATEST;
 }
 
 static void
-dissect_homeplug(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_homeplug(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 {
-  proto_item *it = NULL;
-  proto_tree *homeplug_tree = NULL;
-  ptvcursor_t *cursor = NULL;
+  proto_item * it= NULL;
+  proto_tree * homeplug_tree= NULL;
+  ptvcursor_t * cursor= NULL;
 
   if (check_col(pinfo->cinfo, COL_PROTOCOL))
     col_set_str(pinfo->cinfo, COL_PROTOCOL, "HomePlug");
-
   /* Clear out stuff in the info column */
   if (check_col(pinfo->cinfo, COL_INFO)) {
     col_clear(pinfo->cinfo, COL_INFO);
@@ -819,26 +769,26 @@
 
     dissect_homeplug_mctrl(cursor);
 
-    /*  homeplug_ne indicates the number of MME entries. This field is fetched
-     *  from MCTRL.
+    /** homeplug_ne indicates the number of MME entries. This field is fetched
+     *  from MCTRL. 
      */
     for (; homeplug_ne > 0; homeplug_ne--) {
 
       /* Check we have enough data in tvb to read MEHDR */
       if (check_tvb_length(cursor, HOMEPLUG_MEHDR_LEN) == TVB_LEN_SHORTEST)
-	break;
+        break;
       dissect_homeplug_mehdr(cursor);
 
       /* Check we have enough data in tvb to read MELEN */
       if (check_tvb_length(cursor, HOMEPLUG_MELEN_LEN) == TVB_LEN_SHORTEST)
-	break;
+        break;
       dissect_homeplug_melen(cursor);
 
       dissect_homeplug_mme(cursor, pinfo);
     }
   }
 
-  if (cursor)
+  if (cursor) 
     ptvcursor_free(cursor);
 }
 
Index: epan/proto.c
===================================================================
--- epan/proto.c	(révision 21032)
+++ epan/proto.c	(copie de travail)
@@ -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,30 @@
 	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)
+{
+  /*g_free(ptvc->pushed_tree);*/
+  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 +640,23 @@
 {
 	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 +676,10 @@
 proto_tree*
 ptvcursor_tree(ptvcursor_t* ptvc)
 {
-	return ptvc->tree;
+  if (!ptvc)
+    return NULL;
+
+  return ptvc->tree;
 }
 
 void
@@ -643,6 +688,102 @@
 	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: epan/ptvcursor.h
===================================================================
--- epan/ptvcursor.h	(révision 21032)
+++ epan/ptvcursor.h	(copie de travail)
@@ -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 @@
 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__ */
Index: doc/README.developer
===================================================================
--- doc/README.developer	(révision 21032)
+++ doc/README.developer	(copie de travail)
@@ -3395,6 +3395,17 @@
     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 @@
     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*