[Spice-devel] [PATCH v3 41/51] Handle text formatting of different elements
Christophe Fergeau
cfergeau at redhat.com
Thu Jul 23 06:41:17 PDT 2015
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 at 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
> + at 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 at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/spice-devel/attachments/20150723/36f06ff2/attachment.sig>
More information about the Spice-devel
mailing list