[Spice-devel,v3,41/51] Handle text formatting of different elements

Submitted by Frediano Ziglio on July 23, 2015, 12:07 p.m.

Details

Message ID 1873420052.2662532.1437653252756.JavaMail.zimbra@redhat.com
State New
Headers show

Not browsing as part of any series.

Commit Message

Frediano Ziglio July 23, 2015, 12:07 p.m.
Support ws_txt and ws_txt_n attributes.
These attributes are there to allow to set specific text to different
elements.
The can be used to output in a single line the features of a structure.
Or they can be used to format small array items.
They can applied to almost everything from primitives, arrays,
structure or even pointers.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
---
 codegen/dissector_test.c     |  28 ++++++
 codegen/out_array_raw.txt    |   4 +-
 codegen/out_array_struct.txt |  52 ++++++-----
 codegen/out_struct1.txt      |  13 +--
 python_modules/dissector.py  | 205 +++++++++++++++++++++++++++++++++++++++----
 5 files changed, 256 insertions(+), 46 deletions(-)

Changed:
- compatibility with Python 3

Patch hide | download patch | download mbox

diff --git a/codegen/dissector_test.c b/codegen/dissector_test.c
index 96b3107..84abacf 100644
--- a/codegen/dissector_test.c
+++ b/codegen/dissector_test.c
@@ -276,6 +276,34 @@  WS_DLL_PUBLIC proto_tree* proto_item_add_subtree(proto_item *ti, const gint idx)
 	return res;
 }
 
+WS_DLL_PUBLIC void proto_item_set_end(proto_item *ti, tvbuff_t *tvb, gint end)
+{
+	assert(tvb);
+	assert(end >= 0);
+	if (!ti)
+		return;
+	check_item(ti);
+	tvb_bytes(tvb, 0, end);
+	assert(ti->finfo->start <= end);
+	ti->finfo->length = end - ti->finfo->start;
+	check_item(ti);
+}
+
+WS_DLL_PUBLIC void proto_item_set_text(proto_item *ti, const char *format, ...)
+{
+	va_list ap;
+	assert(format);
+	if (!ti)
+		return;
+
+	check_item(ti);
+	va_start(ap, format);
+	vsnprintf(ti->finfo->rep->representation, sizeof(ti->finfo->rep->representation),
+		format, ap);
+	va_end(ap);
+	check_item(ti);
+}
+
 struct all_ti
 {
 	proto_item ti;
diff --git a/codegen/out_array_raw.txt b/codegen/out_array_raw.txt
index f276871..31b510c 100644
--- a/codegen/out_array_raw.txt
+++ b/codegen/out_array_raw.txt
@@ -1,5 +1,3 @@ 
 --- tree
     --- item
-    Text: 
-    Name: array
-    Abbrev: spice2.auto.ArrayRaw_array_array
+    Text: array
diff --git a/codegen/out_array_struct.txt b/codegen/out_array_struct.txt
index eb03cd8..53d28ef 100644
--- a/codegen/out_array_struct.txt
+++ b/codegen/out_array_struct.txt
@@ -1,25 +1,37 @@ 
 --- tree
     --- item
-    Text: 0 (0)
-    Name: dummy
-    Abbrev: spice2.auto.Dummy_dummy
-    Type: FT_UINT16
-    Base: BASE_DEC
+    Text: Dummy
+        --- tree
+            --- item
+            Text: 0 (0)
+            Name: dummy
+            Abbrev: spice2.auto.Dummy_dummy
+            Type: FT_UINT16
+            Base: BASE_DEC
     --- item
-    Text: 1 (0x1)
-    Name: dummy
-    Abbrev: spice2.auto.Dummy_dummy
-    Type: FT_UINT16
-    Base: BASE_DEC
+    Text: Dummy
+        --- tree
+            --- item
+            Text: 1 (0x1)
+            Name: dummy
+            Abbrev: spice2.auto.Dummy_dummy
+            Type: FT_UINT16
+            Base: BASE_DEC
     --- item
-    Text: 2 (0x2)
-    Name: dummy
-    Abbrev: spice2.auto.Dummy_dummy
-    Type: FT_UINT16
-    Base: BASE_DEC
+    Text: Dummy
+        --- tree
+            --- item
+            Text: 2 (0x2)
+            Name: dummy
+            Abbrev: spice2.auto.Dummy_dummy
+            Type: FT_UINT16
+            Base: BASE_DEC
     --- item
-    Text: 3 (0x3)
-    Name: dummy
-    Abbrev: spice2.auto.Dummy_dummy
-    Type: FT_UINT16
-    Base: BASE_DEC
+    Text: Dummy
+        --- tree
+            --- item
+            Text: 3 (0x3)
+            Name: dummy
+            Abbrev: spice2.auto.Dummy_dummy
+            Type: FT_UINT16
+            Base: BASE_DEC
diff --git a/codegen/out_struct1.txt b/codegen/out_struct1.txt
index a1d429c..993e77c 100644
--- a/codegen/out_struct1.txt
+++ b/codegen/out_struct1.txt
@@ -1,7 +1,10 @@ 
 --- tree
     --- item
-    Text: 33154 (0x8182)
-    Name: dummy
-    Abbrev: spice2.auto.Dummy_dummy
-    Type: FT_UINT16
-    Base: BASE_DEC
+    Text: Dummy
+        --- tree
+            --- item
+            Text: 33154 (0x8182)
+            Name: dummy
+            Abbrev: spice2.auto.Dummy_dummy
+            Type: FT_UINT16
+            Base: BASE_DEC
diff --git a/python_modules/dissector.py b/python_modules/dissector.py
index f08cf0f..c4b0749 100644
--- a/python_modules/dissector.py
+++ b/python_modules/dissector.py
@@ -3,6 +3,7 @@  from . import ptypes
 from . import codegen
 import re
 
+from contextlib import contextmanager
 import sys
 import types
 
@@ -196,6 +197,7 @@  class Destination:
         self.reuse_scope = scope
         self.parent_dest = None
         self.level = Level()
+        self.index = None
 
     def child_sub(self, member, scope):
         return SubDestination(self, member, scope)
@@ -293,7 +295,6 @@  def get_primitive_ft_type(t):
 # write a field
 def write_wireshark_field(writer, container, member, t, ws, tree, dest, size, encoding='ENC_LITTLE_ENDIAN', prefix=''):
 
-    assert(member and container)
 
     size_name = ''
 
@@ -344,7 +345,17 @@  def write_wireshark_field(writer, container, member, t, ws, tree, dest, size, en
 
     # read name
     ws_name = ws.name
+
+    # TODO change entirely to catch flags with same name in different places
+    # read all forces, check not changed at end dump
+
     if not ws_name:
+        # write a text only item
+        if (f_type, base, vals) == ('FT_NONE', 'BASE_NONE', 'NULL'):
+            stmt = "%sproto_tree_add_text(%s, glb->tvb, offset, %s, \"%s\")" % (prefix, tree, size, desc)
+            writer.statement(stmt)
+            return
+
         hf_name = member_hf_name(container, member)
         ws_name = 'auto.' + hf_name[3:]
     else:
@@ -447,24 +458,46 @@  def write_switch(writer, container, switch, dest, scope):
     if switch.has_attr("fixedsize"):
         writer.assign("output", "save_output + %s" % switch.get_fixed_nw_size())
 
+
+def write_array_core(writer, container, member, nelements, array, dest, scope):
+    element_type = array.element_type
+
+    with writer.index() as index, writer.for_loop(index, nelements) as array_scope:
+        dest.index = index
+        if element_type.is_primitive():
+            write_member_primitive(writer, container, member, element_type, WSAttributes(element_type, array.item_attrs), dest, scope)
+        else:
+            assert(element_type.is_struct())
+            write_struct(writer, member, element_type, index, dest, scope)
+        dest.index = None
+
 def write_array(writer, container, member, nelements, array, dest, scope):
     assert(container and member)
 
     ws = WSAttributes(array, member.attributes)
 
+    tree = dest.level.tree
     element_type = array.element_type
 
+    # easy case, binary data
     if element_type == ptypes.uint8 or element_type == ptypes.int8:
-        write_wireshark_field(writer, container, member, array, ws, dest.level.tree, dest, nelements, 'ENC_NA')
+        if not ws.has_txts():
+            write_wireshark_field(writer, container, member, array, ws, tree, dest, nelements, 'ENC_NA')
+        else:
+            with dest.level:
+                if not scope.variable_defined(dest.level.ti):
+                    scope.variable_def('proto_item *', dest.level.ti)
+                write_wireshark_field(writer, container, member, array, ws, tree, dest, nelements, 'ENC_NA', prefix=dest.level.ti + ' = ')
+                write_ws_formats(writer, ws, dest)
         writer.increment("offset", nelements)
         return
 
-    with writer.index() as index, writer.for_loop(index, nelements) as array_scope:
-        if element_type.is_primitive():
-            write_member_primitive(writer, container, member, element_type, WSAttributes(element_type, array.item_attrs), dest, scope)
-        else:
-            assert(element_type.is_struct())
-            write_struct(writer, member, element_type, index, dest, scope)
+    # just the core
+    if not ws.desc and not ws.name and not ws.has_txts():
+        write_array_core(writer, container, member, nelements, array, dest, scope)
+    else:
+        with tree_item(writer, scope, ws, array, dest):
+            write_array_core(writer, container, member, nelements, array, dest, scope)
 
 
 def write_ptr_function(writer, target_type, container, member, dest, scope):
@@ -505,8 +538,15 @@  def write_pointer(writer, container, member, t, dest, scope):
     assert(t.is_pointer())
 
     if not scope.variable_defined('ptr'):
+        # TODO correct pointer
         scope.variable_def('guint32', 'ptr')
+
+    ws = WSAttributes(ptypes.uint32, t.attributes)
+    if ws.name:
+        with tree_item(writer, scope, ws, ptypes.uint32, dest, has_subtree=False):
+            pass
     read_ptr(writer, t)
+
     with writer.if_block('ptr'):
         writer.variable_def('guint32', 'save_offset = offset')
         writer.assign('offset', 'ptr + glb->message_offset')
@@ -519,6 +559,117 @@  def write_pointer(writer, container, member, t, dest, scope):
         writer.assign('offset', 'save_offset')
 
 
+def get_ws_txt_formats(txt, dest):
+    if txt is None:
+        return None
+
+    fmt = txt[0].replace('%%',chr(1)*2).split('%')
+    if len(fmt) != len(txt):
+        raise Exception('Wrong number of formatting argument in %s' % fmt)
+    fmts = [fmt[0]]
+    s = ''
+    # parse all fields
+    for f, fld in list(zip(fmt, txt))[1:]:
+        s += ', '
+        if fld == 'INDEX':
+            assert dest.index, 'INDEX variable not found'
+            s += dest.index
+        else:
+            s += dest.read_ref(fld)
+            size = dest.ref_size(fld)
+            if size > 32:
+                f = '" G_GINT%d_MODIFIER "' % size + f
+        fmts.append(f)
+    fmt = '%'.join(fmts).replace(chr(1), '%')
+    s = '"%s"' % fmt + s
+    return s
+
+
+# TODO ugly the fmt part
+def write_ws_formats(writer, ws, dest, fmt=None, formats=None):
+    formats = get_ws_txt_formats(ws.txt, dest) if formats is None else formats
+    formats_n = get_ws_txt_formats(ws.txt_n, dest)
+    if not fmt:
+        fmt = 'proto_item_set_text(%s, %%s)' % dest.level.ti
+    if formats_n:
+        assert dest.index, "ws_txt_n specified without an active index"
+        with writer.if_block('%s != -1' % dest.index, newline=False):
+            writer.statement(fmt % formats_n)
+        if formats:
+            with writer.block(' else ', newline=False):
+                writer.statement(fmt % formats)
+        writer.newline()
+    elif formats:
+        writer.statement(fmt % formats)
+
+
+# write a new tree
+@contextmanager
+def tree_item(writer, scope, ws, t, dest, has_subtree=True):
+    # at enter generate the subtree
+    size_written = t.is_fixed_nw_size()
+    size = t.get_fixed_nw_size() if size_written else 1
+    need_treeitem = has_subtree or not size_written
+    def declare_ti():
+        if need_treeitem and not scope.variable_defined(dest.level.ti):
+            scope.variable_def('proto_item *', dest.level.ti)
+    txt_done = False
+    if not ws.name:
+        can_format = False
+        # TODO ugly
+        fmt = "proto_tree_add_text(%s, glb->tvb, offset, %s, %%s)" % (dest.level.tree, size)
+        try:
+            txt   = get_ws_txt_formats(ws.txt, dest)
+            txt_n = get_ws_txt_formats(ws.txt_n, dest)
+            can_format = True
+        except:
+            pass
+        if can_format and ws.has_txts() and (txt is not None or ws.desc):
+            if ws.txt is None and ws.desc:
+                txt = '"%s"' % ws.desc.replace('%','%%')
+            if need_treeitem:
+                declare_ti()
+                fmt = dest.level.ti + ' = ' + fmt
+            write_ws_formats(writer, ws, dest, fmt=fmt, formats=txt)
+            txt_done = True
+        else:
+            if not txt_done and ws.has_txts():
+                need_treeitem = True
+            can_format = False
+            desc = ws.desc
+            if desc is None and t.is_struct():
+                desc = t.name
+            txt = '"%s"' % desc.replace('%','%%')
+            if need_treeitem:
+                declare_ti()
+                fmt = dest.level.ti + ' = ' + fmt
+            writer.statement(fmt % txt)
+    else:
+        if not txt_done and ws.has_txts():
+            need_treeitem = True
+        prefix = ''
+        if need_treeitem:
+            declare_ti()
+            prefix = dest.level.ti + ' = '
+        write_wireshark_field(writer, None, None, t, ws, dest.level.tree, dest, size, 'ENC_LITTLE_ENDIAN', prefix=prefix)
+
+    ti = dest.level.ti
+    with dest.level:
+        if has_subtree:
+            if not scope.variable_defined(dest.level.tree):
+                scope.variable_def('proto_tree *', dest.level.tree)
+            ett_name = new_ett(writer)
+            writer.assign(dest.level.tree, 'proto_item_add_subtree(%s, %s)' % (ti, ett_name))
+
+        yield scope
+
+    # at exit fix length and write possible text
+    if not size_written:
+        writer.statement('proto_item_set_end(%s, glb->tvb, offset)' % dest.level.ti)
+    if not txt_done and ws.has_txts():
+        write_ws_formats(writer, ws, dest)
+
+
 def write_struct_func(writer, t, func_name, index):
     func_name = 'dissect_spice_struct_' + t.name
 
@@ -529,7 +680,11 @@  def write_struct_func(writer, t, func_name, index):
     writer = writer.function_helper()
     scope = writer.function(func_name, "guint32", "GlobalInfo *glb _U_, proto_tree *tree _U_, guint32 offset, gint32 index _U_", True)
     dest = RootDestination(scope)
-    write_container_parser(writer, t, dest)
+    dest.index = 'index'
+    if not t.is_fixed_nw_size() or t.get_fixed_nw_size() != 0:
+        ws = WSAttributes(t)
+        with tree_item(writer, scope, ws, t, dest):
+            write_container_parser(writer, t, dest)
     writer.statement('return offset')
     writer.end_block()
 
@@ -538,7 +693,9 @@  def write_struct(writer, member, t, index, dest, scope):
 
     if member.has_attr('ws_inline'):
         dest = dest.child_sub(member.name, scope)
-        with writer.block() as scope:
+        dest.index = 'index'
+        ws = WSAttributes(t, member.attributes)
+        with writer.block() as scope, tree_item(writer, scope, ws, t, dest):
             write_container_parser(writer, t, dest)
     else:
         func_name = 'dissect_spice_struct_' + t.name
@@ -603,19 +760,24 @@  def write_flags(writer, container, member, t, ws, tree, dest):
     ws_func = WSAttributes(t)
 
     own_ti = ws.name != ws_func.name or ws.desc != ws_func.desc or ws.base != ws_func.base
-    if not own_ti:
+    if not own_ti and not ws.has_txts():
         stmt = write_flags_func(writer, t, ws_func, tree, 'NULL')
         writer.statement(stmt)
         return
 
-    tree = dest.level.tree
+    # write reference to allows txt to read it
+    dest.write_ref(writer, t.get_fixed_nw_size() * 8, member.name, '%s(glb->tvb, offset)' % primitive_read_func(t))
+
+    # write flags and override texts
     with writer.block() as scope, dest.level:
         scope.variable_def('proto_item *', dest.level.ti)
-        size = t.get_fixed_nw_size()
-        int_type = ptypes.IntegerType(size*8, False)
-        write_wireshark_field(writer, container, member, int_type, ws, tree, dest, size, prefix=dest.level.ti + ' = ')
+        if own_ti:
+            size = t.get_fixed_nw_size()
+            int_type = ptypes.IntegerType(size*8, False)
+            write_wireshark_field(writer, container, member, int_type, ws, tree, dest, size, prefix=dest.level.ti + ' = ')
         stmt = write_flags_func(writer, t, ws_func, tree, dest.level.ti)
-        writer.statement(stmt)
+        writer.assign(dest.level.ti, stmt)
+        write_ws_formats(writer, ws, dest)
 
 
 def write_member_primitive(writer, container, member, t, ws, dest, scope):
@@ -623,13 +785,20 @@  def write_member_primitive(writer, container, member, t, ws, dest, scope):
 
     if member.has_attr("bytes_count"):
         raise NotImplementedError("bytes_count not implemented")
-
-    write_wireshark_field(writer, container, member, t, ws, dest.level.tree, dest, t.get_fixed_nw_size())
     if member.has_attr("bytes_count"):
         dest_var = member.attributes["bytes_count"][0]
     else:
         dest_var = member.name
     dest.write_ref(writer, t.get_fixed_nw_size() * 8, dest_var, '%s(glb->tvb, offset)' % primitive_read_func(t))
+
+    if not ws.has_txts():
+        write_wireshark_field(writer, container, member, t, ws, dest.level.tree, dest, t.get_fixed_nw_size())
+    else:
+        if not scope.variable_defined(dest.level.ti):
+            scope.variable_def('proto_item *', dest.level.ti)
+        write_wireshark_field(writer, container, member, t, ws, dest.level.tree, dest, t.get_fixed_nw_size(), prefix=dest.level.ti + ' = ')
+        write_ws_formats(writer, ws, dest)
+
     writer.increment("offset", t.get_fixed_nw_size())
 
 def write_member(writer, container, member, dest, scope):

Comments

On Thu, Jul 23, 2015 at 08:07:32AM -0400, Frediano Ziglio wrote:
> Support ws_txt and ws_txt_n attributes.
> These attributes are there to allow to set specific text to different
> elements.

'on different elements' ?

> The can be used to output in a single line the features of a structure.

'They can be used'

> Or they can be used to format small array items.
> They can applied to almost everything from primitives, arrays,
> structure or even pointers.
> 
> Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
> ---
>  codegen/dissector_test.c     |  28 ++++++
>  codegen/out_array_raw.txt    |   4 +-
>  codegen/out_array_struct.txt |  52 ++++++-----
>  codegen/out_struct1.txt      |  13 +--
>  python_modules/dissector.py  | 205 +++++++++++++++++++++++++++++++++++++++----
>  5 files changed, 256 insertions(+), 46 deletions(-)
> 
> Changed:
> - compatibility with Python 3
> 
> diff --git a/codegen/dissector_test.c b/codegen/dissector_test.c
> index 96b3107..84abacf 100644
> --- a/codegen/dissector_test.c
> +++ b/codegen/dissector_test.c
> @@ -276,6 +276,34 @@ WS_DLL_PUBLIC proto_tree* proto_item_add_subtree(proto_item *ti, const gint idx)
>  	return res;
>  }
>  
> +WS_DLL_PUBLIC void proto_item_set_end(proto_item *ti, tvbuff_t *tvb, gint end)
> +{
> +	assert(tvb);
> +	assert(end >= 0);
> +	if (!ti)
> +		return;
> +	check_item(ti);
> +	tvb_bytes(tvb, 0, end);
> +	assert(ti->finfo->start <= end);
> +	ti->finfo->length = end - ti->finfo->start;
> +	check_item(ti);
> +}
> +
> +WS_DLL_PUBLIC void proto_item_set_text(proto_item *ti, const char *format, ...)
> +{
> +	va_list ap;
> +	assert(format);
> +	if (!ti)
> +		return;
> +
> +	check_item(ti);
> +	va_start(ap, format);
> +	vsnprintf(ti->finfo->rep->representation, sizeof(ti->finfo->rep->representation),
> +		format, ap);
> +	va_end(ap);
> +	check_item(ti);
> +}
> +
>  struct all_ti
>  {
>  	proto_item ti;
> diff --git a/codegen/out_array_raw.txt b/codegen/out_array_raw.txt
> index f276871..31b510c 100644
> --- a/codegen/out_array_raw.txt
> +++ b/codegen/out_array_raw.txt
> @@ -1,5 +1,3 @@
>  --- tree
>      --- item
> -    Text: 
> -    Name: array
> -    Abbrev: spice2.auto.ArrayRaw_array_array
> +    Text: array
> diff --git a/codegen/out_array_struct.txt b/codegen/out_array_struct.txt
> index eb03cd8..53d28ef 100644
> --- a/codegen/out_array_struct.txt
> +++ b/codegen/out_array_struct.txt
> @@ -1,25 +1,37 @@
>  --- tree
>      --- item
> -    Text: 0 (0)
> -    Name: dummy
> -    Abbrev: spice2.auto.Dummy_dummy
> -    Type: FT_UINT16
> -    Base: BASE_DEC
> +    Text: Dummy
> +        --- tree
> +            --- item
> +            Text: 0 (0)
> +            Name: dummy
> +            Abbrev: spice2.auto.Dummy_dummy
> +            Type: FT_UINT16
> +            Base: BASE_DEC
>      --- item
> -    Text: 1 (0x1)
> -    Name: dummy
> -    Abbrev: spice2.auto.Dummy_dummy
> -    Type: FT_UINT16
> -    Base: BASE_DEC
> +    Text: Dummy
> +        --- tree
> +            --- item
> +            Text: 1 (0x1)
> +            Name: dummy
> +            Abbrev: spice2.auto.Dummy_dummy
> +            Type: FT_UINT16
> +            Base: BASE_DEC
>      --- item
> -    Text: 2 (0x2)
> -    Name: dummy
> -    Abbrev: spice2.auto.Dummy_dummy
> -    Type: FT_UINT16
> -    Base: BASE_DEC
> +    Text: Dummy
> +        --- tree
> +            --- item
> +            Text: 2 (0x2)
> +            Name: dummy
> +            Abbrev: spice2.auto.Dummy_dummy
> +            Type: FT_UINT16
> +            Base: BASE_DEC
>      --- item
> -    Text: 3 (0x3)
> -    Name: dummy
> -    Abbrev: spice2.auto.Dummy_dummy
> -    Type: FT_UINT16
> -    Base: BASE_DEC
> +    Text: Dummy
> +        --- tree
> +            --- item
> +            Text: 3 (0x3)
> +            Name: dummy
> +            Abbrev: spice2.auto.Dummy_dummy
> +            Type: FT_UINT16
> +            Base: BASE_DEC
> diff --git a/codegen/out_struct1.txt b/codegen/out_struct1.txt
> index a1d429c..993e77c 100644
> --- a/codegen/out_struct1.txt
> +++ b/codegen/out_struct1.txt
> @@ -1,7 +1,10 @@
>  --- tree
>      --- item
> -    Text: 33154 (0x8182)
> -    Name: dummy
> -    Abbrev: spice2.auto.Dummy_dummy
> -    Type: FT_UINT16
> -    Base: BASE_DEC
> +    Text: Dummy
> +        --- tree
> +            --- item
> +            Text: 33154 (0x8182)
> +            Name: dummy
> +            Abbrev: spice2.auto.Dummy_dummy
> +            Type: FT_UINT16
> +            Base: BASE_DEC
> diff --git a/python_modules/dissector.py b/python_modules/dissector.py
> index f08cf0f..c4b0749 100644
> --- a/python_modules/dissector.py
> +++ b/python_modules/dissector.py
> @@ -3,6 +3,7 @@ from . import ptypes
>  from . import codegen
>  import re
>  
> +from contextlib import contextmanager
>  import sys
>  import types
>  
> @@ -196,6 +197,7 @@ class Destination:
>          self.reuse_scope = scope
>          self.parent_dest = None
>          self.level = Level()
> +        self.index = None
>  
>      def child_sub(self, member, scope):
>          return SubDestination(self, member, scope)
> @@ -293,7 +295,6 @@ def get_primitive_ft_type(t):
>  # write a field
>  def write_wireshark_field(writer, container, member, t, ws, tree, dest, size, encoding='ENC_LITTLE_ENDIAN', prefix=''):
>  
> -    assert(member and container)
>  
>      size_name = ''
>  
> @@ -344,7 +345,17 @@ def write_wireshark_field(writer, container, member, t, ws, tree, dest, size, en
>  
>      # read name
>      ws_name = ws.name
> +
> +    # TODO change entirely to catch flags with same name in different places
> +    # read all forces, check not changed at end dump
> +
>      if not ws_name:
> +        # write a text only item
> +        if (f_type, base, vals) == ('FT_NONE', 'BASE_NONE', 'NULL'):
> +            stmt = "%sproto_tree_add_text(%s, glb->tvb, offset, %s, \"%s\")" % (prefix, tree, size, desc)
> +            writer.statement(stmt)
> +            return
> +
>          hf_name = member_hf_name(container, member)
>          ws_name = 'auto.' + hf_name[3:]
>      else:
> @@ -447,24 +458,46 @@ def write_switch(writer, container, switch, dest, scope):
>      if switch.has_attr("fixedsize"):
>          writer.assign("output", "save_output + %s" % switch.get_fixed_nw_size())
>  
> +
> +def write_array_core(writer, container, member, nelements, array, dest, scope):
> +    element_type = array.element_type
> +
> +    with writer.index() as index, writer.for_loop(index, nelements) as array_scope:
> +        dest.index = index
> +        if element_type.is_primitive():
> +            write_member_primitive(writer, container, member, element_type, WSAttributes(element_type, array.item_attrs), dest, scope)
> +        else:
> +            assert(element_type.is_struct())
> +            write_struct(writer, member, element_type, index, dest, scope)
> +        dest.index = None
> +
>  def write_array(writer, container, member, nelements, array, dest, scope):
>      assert(container and member)
>  
>      ws = WSAttributes(array, member.attributes)
>  
> +    tree = dest.level.tree
>      element_type = array.element_type
>  
> +    # easy case, binary data
>      if element_type == ptypes.uint8 or element_type == ptypes.int8:
> -        write_wireshark_field(writer, container, member, array, ws, dest.level.tree, dest, nelements, 'ENC_NA')
> +        if not ws.has_txts():
> +            write_wireshark_field(writer, container, member, array, ws, tree, dest, nelements, 'ENC_NA')
> +        else:
> +            with dest.level:
> +                if not scope.variable_defined(dest.level.ti):
> +                    scope.variable_def('proto_item *', dest.level.ti)
> +                write_wireshark_field(writer, container, member, array, ws, tree, dest, nelements, 'ENC_NA', prefix=dest.level.ti + ' = ')
> +                write_ws_formats(writer, ws, dest)
>          writer.increment("offset", nelements)
>          return
>  
> -    with writer.index() as index, writer.for_loop(index, nelements) as array_scope:
> -        if element_type.is_primitive():
> -            write_member_primitive(writer, container, member, element_type, WSAttributes(element_type, array.item_attrs), dest, scope)
> -        else:
> -            assert(element_type.is_struct())
> -            write_struct(writer, member, element_type, index, dest, scope)
> +    # just the core
> +    if not ws.desc and not ws.name and not ws.has_txts():
> +        write_array_core(writer, container, member, nelements, array, dest, scope)
> +    else:
> +        with tree_item(writer, scope, ws, array, dest):
> +            write_array_core(writer, container, member, nelements, array, dest, scope)
>  
>  
>  def write_ptr_function(writer, target_type, container, member, dest, scope):
> @@ -505,8 +538,15 @@ def write_pointer(writer, container, member, t, dest, scope):
>      assert(t.is_pointer())
>  
>      if not scope.variable_defined('ptr'):
> +        # TODO correct pointer
>          scope.variable_def('guint32', 'ptr')
> +
> +    ws = WSAttributes(ptypes.uint32, t.attributes)
> +    if ws.name:
> +        with tree_item(writer, scope, ws, ptypes.uint32, dest, has_subtree=False):
> +            pass
>      read_ptr(writer, t)
> +
>      with writer.if_block('ptr'):
>          writer.variable_def('guint32', 'save_offset = offset')
>          writer.assign('offset', 'ptr + glb->message_offset')
> @@ -519,6 +559,117 @@ def write_pointer(writer, container, member, t, dest, scope):
>          writer.assign('offset', 'save_offset')
>  
>  
> +def get_ws_txt_formats(txt, dest):
> +    if txt is None:
> +        return None
> +
> +    fmt = txt[0].replace('%%',chr(1)*2).split('%')
> +    if len(fmt) != len(txt):
> +        raise Exception('Wrong number of formatting argument in %s' % fmt)
> +    fmts = [fmt[0]]
> +    s = ''
> +    # parse all fields
> +    for f, fld in list(zip(fmt, txt))[1:]:
> +        s += ', '
> +        if fld == 'INDEX':
> +            assert dest.index, 'INDEX variable not found'
> +            s += dest.index
> +        else:
> +            s += dest.read_ref(fld)
> +            size = dest.ref_size(fld)
> +            if size > 32:
> +                f = '" G_GINT%d_MODIFIER "' % size + f
> +        fmts.append(f)
> +    fmt = '%'.join(fmts).replace(chr(1), '%')
> +    s = '"%s"' % fmt + s
> +    return s
> +
> +
> +# TODO ugly the fmt part
> +def write_ws_formats(writer, ws, dest, fmt=None, formats=None):
> +    formats = get_ws_txt_formats(ws.txt, dest) if formats is None else formats
> +    formats_n = get_ws_txt_formats(ws.txt_n, dest)
> +    if not fmt:
> +        fmt = 'proto_item_set_text(%s, %%s)' % dest.level.ti
> +    if formats_n:
> +        assert dest.index, "ws_txt_n specified without an active index"
> +        with writer.if_block('%s != -1' % dest.index, newline=False):
> +            writer.statement(fmt % formats_n)
> +        if formats:
> +            with writer.block(' else ', newline=False):
> +                writer.statement(fmt % formats)
> +        writer.newline()
> +    elif formats:
> +        writer.statement(fmt % formats)
> +
> +
> +# write a new tree
> +@contextmanager
> +def tree_item(writer, scope, ws, t, dest, has_subtree=True):
> +    # at enter generate the subtree
> +    size_written = t.is_fixed_nw_size()
> +    size = t.get_fixed_nw_size() if size_written else 1
> +    need_treeitem = has_subtree or not size_written
> +    def declare_ti():
> +        if need_treeitem and not scope.variable_defined(dest.level.ti):
> +            scope.variable_def('proto_item *', dest.level.ti)
> +    txt_done = False
> +    if not ws.name:
> +        can_format = False
> +        # TODO ugly
> +        fmt = "proto_tree_add_text(%s, glb->tvb, offset, %s, %%s)" % (dest.level.tree, size)
> +        try:
> +            txt   = get_ws_txt_formats(ws.txt, dest)
> +            txt_n = get_ws_txt_formats(ws.txt_n, dest)
> +            can_format = True
> +        except:
> +            pass
> +        if can_format and ws.has_txts() and (txt is not None or ws.desc):
> +            if ws.txt is None and ws.desc:
> +                txt = '"%s"' % ws.desc.replace('%','%%')
> +            if need_treeitem:
> +                declare_ti()
> +                fmt = dest.level.ti + ' = ' + fmt
> +            write_ws_formats(writer, ws, dest, fmt=fmt, formats=txt)
> +            txt_done = True
> +        else:
> +            if not txt_done and ws.has_txts():
> +                need_treeitem = True
> +            can_format = False
> +            desc = ws.desc
> +            if desc is None and t.is_struct():
> +                desc = t.name
> +            txt = '"%s"' % desc.replace('%','%%')
> +            if need_treeitem:
> +                declare_ti()
> +                fmt = dest.level.ti + ' = ' + fmt
> +            writer.statement(fmt % txt)
> +    else:
> +        if not txt_done and ws.has_txts():
> +            need_treeitem = True
> +        prefix = ''
> +        if need_treeitem:
> +            declare_ti()
> +            prefix = dest.level.ti + ' = '
> +        write_wireshark_field(writer, None, None, t, ws, dest.level.tree, dest, size, 'ENC_LITTLE_ENDIAN', prefix=prefix)
> +
> +    ti = dest.level.ti
> +    with dest.level:
> +        if has_subtree:
> +            if not scope.variable_defined(dest.level.tree):
> +                scope.variable_def('proto_tree *', dest.level.tree)
> +            ett_name = new_ett(writer)
> +            writer.assign(dest.level.tree, 'proto_item_add_subtree(%s, %s)' % (ti, ett_name))
> +
> +        yield scope
> +
> +    # at exit fix length and write possible text
> +    if not size_written:
> +        writer.statement('proto_item_set_end(%s, glb->tvb, offset)' % dest.level.ti)
> +    if not txt_done and ws.has_txts():
> +        write_ws_formats(writer, ws, dest)
> +
> +
>  def write_struct_func(writer, t, func_name, index):
>      func_name = 'dissect_spice_struct_' + t.name
>  
> @@ -529,7 +680,11 @@ def write_struct_func(writer, t, func_name, index):
>      writer = writer.function_helper()
>      scope = writer.function(func_name, "guint32", "GlobalInfo *glb _U_, proto_tree *tree _U_, guint32 offset, gint32 index _U_", True)
>      dest = RootDestination(scope)
> -    write_container_parser(writer, t, dest)
> +    dest.index = 'index'
> +    if not t.is_fixed_nw_size() or t.get_fixed_nw_size() != 0:
> +        ws = WSAttributes(t)
> +        with tree_item(writer, scope, ws, t, dest):
> +            write_container_parser(writer, t, dest)
>      writer.statement('return offset')
>      writer.end_block()
>  
> @@ -538,7 +693,9 @@ def write_struct(writer, member, t, index, dest, scope):
>  
>      if member.has_attr('ws_inline'):
>          dest = dest.child_sub(member.name, scope)
> -        with writer.block() as scope:
> +        dest.index = 'index'
> +        ws = WSAttributes(t, member.attributes)
> +        with writer.block() as scope, tree_item(writer, scope, ws, t, dest):
>              write_container_parser(writer, t, dest)
>      else:
>          func_name = 'dissect_spice_struct_' + t.name
> @@ -603,19 +760,24 @@ def write_flags(writer, container, member, t, ws, tree, dest):
>      ws_func = WSAttributes(t)
>  
>      own_ti = ws.name != ws_func.name or ws.desc != ws_func.desc or ws.base != ws_func.base
> -    if not own_ti:
> +    if not own_ti and not ws.has_txts():
>          stmt = write_flags_func(writer, t, ws_func, tree, 'NULL')
>          writer.statement(stmt)
>          return
>  
> -    tree = dest.level.tree
> +    # write reference to allows txt to read it
> +    dest.write_ref(writer, t.get_fixed_nw_size() * 8, member.name, '%s(glb->tvb, offset)' % primitive_read_func(t))
> +
> +    # write flags and override texts
>      with writer.block() as scope, dest.level:
>          scope.variable_def('proto_item *', dest.level.ti)
> -        size = t.get_fixed_nw_size()
> -        int_type = ptypes.IntegerType(size*8, False)
> -        write_wireshark_field(writer, container, member, int_type, ws, tree, dest, size, prefix=dest.level.ti + ' = ')
> +        if own_ti:
> +            size = t.get_fixed_nw_size()
> +            int_type = ptypes.IntegerType(size*8, False)
> +            write_wireshark_field(writer, container, member, int_type, ws, tree, dest, size, prefix=dest.level.ti + ' = ')
>          stmt = write_flags_func(writer, t, ws_func, tree, dest.level.ti)
> -        writer.statement(stmt)
> +        writer.assign(dest.level.ti, stmt)
> +        write_ws_formats(writer, ws, dest)
>  
>  
>  def write_member_primitive(writer, container, member, t, ws, dest, scope):
> @@ -623,13 +785,20 @@ def write_member_primitive(writer, container, member, t, ws, dest, scope):
>  
>      if member.has_attr("bytes_count"):
>          raise NotImplementedError("bytes_count not implemented")
> -
> -    write_wireshark_field(writer, container, member, t, ws, dest.level.tree, dest, t.get_fixed_nw_size())
>      if member.has_attr("bytes_count"):
>          dest_var = member.attributes["bytes_count"][0]
>      else:
>          dest_var = member.name
>      dest.write_ref(writer, t.get_fixed_nw_size() * 8, dest_var, '%s(glb->tvb, offset)' % primitive_read_func(t))
> +
> +    if not ws.has_txts():
> +        write_wireshark_field(writer, container, member, t, ws, dest.level.tree, dest, t.get_fixed_nw_size())
> +    else:
> +        if not scope.variable_defined(dest.level.ti):
> +            scope.variable_def('proto_item *', dest.level.ti)
> +        write_wireshark_field(writer, container, member, t, ws, dest.level.tree, dest, t.get_fixed_nw_size(), prefix=dest.level.ti + ' = ')
> +        write_ws_formats(writer, ws, dest)
> +
>      writer.increment("offset", t.get_fixed_nw_size())
>  
>  def write_member(writer, container, member, dest, scope):
> -- 
> 2.1.0
> _______________________________________________
> Spice-devel mailing list
> Spice-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel