Signed-off-by: Frediano Ziglio <[email protected]>
---
 codegen/dissector_test.c | 424 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 423 insertions(+), 1 deletion(-)

diff --git a/codegen/dissector_test.c b/codegen/dissector_test.c
index 25a33b5..5a49f40 100644
--- a/codegen/dissector_test.c
+++ b/codegen/dissector_test.c
@@ -21,6 +21,176 @@ static int last_ei_registered = first_ei_registered - 1;
 static int last_tree_registered = first_tree_registered - 1;
 static bool got_error = false;
 
+static GPtrArray *hfs;
+
+struct tvbuff {
+       guint8 *data;
+       size_t len;
+};
+
+static int check(const char *chk_str, int line, int chk, const char *fmt, ...)
+{
+       if (!chk) {
+               va_list ap;
+               va_start(ap, fmt);
+               fprintf(stderr, "Check failed at line %d\n", line);
+               fprintf(stderr, "Check: %s\n", chk_str);
+               vfprintf(stderr, fmt, ap);
+               fprintf(stderr, "\n");
+               va_end(ap);
+               abort();
+       }
+       return 1;
+}
+#define check(chk, ...) check(#chk, __LINE__, chk, __VA_ARGS__)
+
+static int check_tree(proto_node *node)
+{
+       assert(node->tree_data == (void*) node);
+       assert(node->next == NULL);
+       assert(node->finfo == NULL);
+       if (!node->first_child) {
+               assert(node->last_child == NULL);
+       } else {
+               assert(node->last_child->next == NULL);
+       }
+       return 1;
+}
+
+static int check_item(proto_node *node)
+{
+       assert(node->tree_data == NULL);
+       assert(node->finfo != NULL);
+       assert(node->finfo->rep != NULL);
+       assert(node->first_child == node->last_child);
+       assert(node->first_child == NULL || check_tree(node->first_child));
+       assert(node->parent);
+       assert(node->finfo->start >= 0);
+       assert(node->finfo->length >= 0);
+       return 1;
+}
+
+guint8 *tvb_bytes(tvbuff_t *tvb, const gint offset, unsigned len)
+{
+       if (!tvb)
+               return NULL;
+
+       assert(offset >= 0);
+       assert(offset + len <= tvb->len);
+       return tvb->data + offset;
+}
+
+static guint64 read_ule(const guint8 *p, unsigned len)
+{
+       guint64 low, high;
+
+       switch (len) {
+       case 1:
+               return p[0];
+       case 2:
+               return p[0] + 0x100u * p[1];
+       case 4:
+               return p[0] + 0x100u * p[1] + 0x10000u * p[2] + 0x1000000u * 
p[3];
+       case 8:
+               low  = p[0] + 0x100u * p[1] + 0x10000u * p[2] + 0x1000000u * 
p[3];
+               p += 4;
+               high = p[0] + 0x100u * p[1] + 0x10000u * p[2] + 0x1000000u * 
p[3];
+               return high << 32 | low;
+       }
+       assert(0);
+       return 0;
+}
+
+static gint64 read_sle(const guint8 *p, unsigned len)
+{
+       guint64 sign_bit = (((guint64) 0x80) << ((len-1) * 8));
+       guint64 val = read_ule(p, len);
+
+       if ((val & sign_bit) != 0)
+               return (gint64) ((val ^ sign_bit) - sign_bit);
+       return (gint64) val;
+}
+
+static guint64 tvb_get_ule(tvbuff_t *tvb, const gint offset, unsigned len)
+{
+       guint8 *p = tvb_bytes(tvb, offset, len);
+       if (!p)
+               return 0;
+       return read_ule(p, len);
+}
+
+static gint64 tvb_get_sle(tvbuff_t *tvb, const gint offset, unsigned len)
+{
+       guint8 *p = tvb_bytes(tvb, offset, len);
+       if (!p)
+               return 0;
+       return read_sle(p, len);
+}
+
+static const char *describe_fttype(enum ftenum type)
+{
+       switch (type) {
+#define FT(name) case FT_ ## name: return "FT_" #name;
+       FT(NONE)        /* used for text labels with no value */
+       FT(PROTOCOL)
+       FT(BOOLEAN)     /* TRUE and FALSE come from <glib.h> */
+       FT(UINT8)
+       FT(UINT16)
+       FT(UINT24)      /* really a UINT32, but displayed as 3 hex-digits if 
FD_HEX*/
+       FT(UINT32)
+       FT(UINT64)
+       FT(INT8)
+       FT(INT16)
+       FT(INT24)       /* same as for UINT24 */
+       FT(INT32)
+       FT(INT64)
+       FT(FLOAT)
+       FT(DOUBLE)
+       FT(ABSOLUTE_TIME)
+       FT(RELATIVE_TIME)
+       FT(STRING)
+       FT(STRINGZ)     /* for use with proto_tree_add_item() */
+       FT(UINT_STRING) /* for use with proto_tree_add_item() */
+       FT(ETHER)
+       FT(BYTES)
+       FT(UINT_BYTES)
+       FT(IPv4)
+       FT(IPv6)
+       FT(IPXNET)
+       FT(FRAMENUM)    /* a UINT32, but if selected lets you go to frame with 
that number */
+       FT(PCRE)        /* a compiled Perl-Compatible Regular Expression object 
*/
+       FT(GUID)        /* GUID, UUID */
+       FT(OID)         /* OBJECT IDENTIFIER */
+       FT(EUI64)
+       FT(AX25)
+       FT(VINES)
+       FT(REL_OID)     /* RELATIVE-OID */
+       FT(SYSTEM_ID)
+       FT(STRINGZPAD)  /* for use with proto_tree_add_item() */
+       default:
+               check(false, "Unknown fttype %d", type);
+               break;
+       }
+       return NULL;
+}
+
+static const char *describe_base(int base)
+{
+       switch (base) {
+#define BASE(base) case base: return #base;
+       BASE(BASE_NONE)
+       BASE(BASE_DEC)
+       BASE(BASE_HEX)
+       BASE(BASE_OCT)
+       BASE(BASE_DEC_HEX)
+       BASE(BASE_HEX_DEC)
+       BASE(BASE_CUSTOM)
+       BASE(STR_UNICODE)
+       }
+       check(false, "Unknown base %d", base);
+       return NULL;
+}
+
 WS_DLL_PUBLIC void
 proto_register_field_array(const int parent, hf_register_info *hf, const int 
num_records)
 {
@@ -31,6 +201,7 @@ proto_register_field_array(const int parent, 
hf_register_info *hf, const int num
                assert(hf[i].p_id);
                assert(*hf[i].p_id == -1);
                *hf[i].p_id = ++last_hf_registered;
+               g_ptr_array_add(hfs, &hf[i].hfinfo);
        }
 }
 
@@ -66,12 +237,245 @@ expert_add_info_format(packet_info *pinfo, proto_item 
*pi, expert_field *eiindex
                return;
 }
 
+struct all_ti
+{
+       proto_item ti;
+       field_info info;
+       item_label_t label;
+};
+
+WS_DLL_PUBLIC proto_item *
+proto_tree_add_text(proto_tree *tree, tvbuff_t *tvb, gint start, gint length, 
const char *format,
+       ...)
+{
+       struct all_ti *all;
+       proto_item *ti;
+       va_list ap;
+
+       assert(tvb);
+       assert(start >= 0);
+       assert(start <= tvb->len);
+       assert(length >= 0);
+       check(start + length <= tvb->len, "start %d len %d tvb_len %d", start, 
length, tvb->len);
+       if (!tree)
+               return NULL;
+
+       check_tree(tree);
+       all = calloc(1, sizeof(*all));
+       assert(all);
+       ti = &all->ti;
+       ti->finfo = &all->info;
+       ti->finfo->rep = &all->label;
+       ti->parent = tree;
+       if (tree->first_child) {
+               assert(tree->last_child->next == NULL);
+               tree->last_child->next = ti;
+               tree->last_child = ti;
+       } else {
+               tree->first_child = tree->last_child = ti;
+       }
+       va_start(ap, format);
+       vsnprintf(ti->finfo->rep->representation, 
sizeof(ti->finfo->rep->representation),
+               format, ap);
+       va_end(ap);
+       check_item(ti);
+       check_tree(tree);
+       return ti;
+}
+
+WS_DLL_PUBLIC proto_item *
+proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
+                   const gint start, gint length, const guint encoding)
+{
+       proto_item *ti;
+       header_field_info *hfinfo = NULL;
+       enum ftenum type = FT_NONE;
+       char *label;
+       guint64 uval;
+       gint64  sval;
+       unsigned size;
+       const struct true_false_string *tfs;
+
+       assert(hfindex >= first_hf_registered);
+       assert(hfindex <= last_hf_registered);
+
+       hfindex -= first_hf_registered;
+       assert(hfs && hfindex < hfs->len);
+       hfinfo = g_ptr_array_index(hfs, hfindex);
+
+       ti = proto_tree_add_text(tree, tvb, start, length, "");
+       if (!ti)
+               return NULL;
+
+       /* encoding is just used to read data and put in ti->finfo->rep */
+       if (hfinfo)
+               type = hfinfo->type;
+       label = ti->finfo->rep->representation;
+       switch (type) {
+       case FT_NONE:
+               break;
+       case FT_UINT8:
+               size = 1;
+               goto str_uint;
+       case FT_UINT16:
+               size = 2;
+               goto str_uint;
+       case FT_UINT32:
+               size = 4;
+               goto str_uint;
+       case FT_UINT64:
+               size = 8;
+       str_uint:
+               uval = tvb_get_ule(tvb, start, size);
+               sprintf(label, "%" G_GINT64_MODIFIER "u", uval);
+               break;
+       case FT_INT8:
+               size = 1;
+               goto str_int;
+       case FT_INT16:
+               size = 2;
+               goto str_int;
+       case FT_INT32:
+               size = 4;
+               goto str_int;
+       case FT_INT64:
+               size = 8;
+       str_int:
+               sval = tvb_get_sle(tvb, start, size);
+               sprintf(label, "%" G_GINT64_MODIFIER "d", sval);
+               break;
+       case FT_BOOLEAN:
+               uval = tvb_get_ule(tvb, start, length);
+               uval &= hfinfo->bitmask;
+               assert(hfinfo->strings);
+               tfs = (const struct true_false_string *) hfinfo->strings;
+               strcpy(label, uval ? tfs->true_string : tfs->false_string);
+               break;
+       case FT_STRING:
+               /* TODO read value */
+               assert(0);
+               break;
+       case FT_STRINGZ:
+               /* TODO read value */
+               assert(0);
+               break;
+       case FT_GUID:
+               /* TODO read value */
+               assert(0);
+               break;
+       case FT_BYTES:
+               /* TODO read value */
+               assert(0);
+               break;
+       default:
+               assert(0);
+       }
+       ti->finfo->hfinfo = hfinfo;
+       check_item(ti);
+       check_tree(tree);
+       return ti;
+}
+
+WS_DLL_PUBLIC guint8 tvb_get_guint8(tvbuff_t *tvb, const gint offset)
+{
+       return (guint8) tvb_get_ule(tvb, offset, 1);
+}
+
+WS_DLL_PUBLIC guint16 tvb_get_letohs(tvbuff_t *tvb, const gint offset)
+{
+       return (guint16) tvb_get_ule(tvb, offset, 2);
+}
+
+WS_DLL_PUBLIC guint32 tvb_get_letohl(tvbuff_t *tvb, const gint offset)
+{
+       return (guint32) tvb_get_ule(tvb, offset, 4);
+}
+
+WS_DLL_PUBLIC guint64 tvb_get_letoh64(tvbuff_t *tvb, const gint offset)
+{
+       return tvb_get_ule(tvb, offset, 8);
+}
+
+static int indentation = -1;
+static enum { PLAIN, XML } format = PLAIN;
+static FILE *output_file;
+#define oprintf(...) fprintf(output_file, __VA_ARGS__)
+#define INDENTED(s) "%*s" s, indentation*4, ""
+
+static void format_start(const char *name)
+{
+       ++indentation;
+       if (format == XML)
+               oprintf("<%s>\n", name);
+       else
+               oprintf(INDENTED("--- %s\n"), name);
+}
+
+static void format_end(const char *name)
+{
+       if (format == XML)
+               oprintf("</%s>\n", name);
+       --indentation;
+}
+
+static void format_item(const char *name, const char *value)
+{
+       if (format == XML)
+               /* TODO quote value for XML */
+               oprintf("<%s>%s</%s>\n", name, value, name);
+       else
+               oprintf(INDENTED("%s: %s\n"), name, value);
+}
+
+static void dump_tree(proto_tree *tree);
+
+static void dump_item(proto_item *ti)
+{
+       header_field_info *info = NULL;
+       check_item(ti);
+
+       format_start("item");
+       format_item("Text", ti->finfo->rep->representation);
+       info = ti->finfo->hfinfo;
+       if (info) {
+               format_item("Name", info->name);
+               format_item("Abbrev", info->abbrev);
+               if (info->type != FT_NONE)
+                       format_item("Type", describe_fttype(info->type));
+               if (info->type == FT_BOOLEAN) {
+                       char buf[32];
+                       sprintf(buf, "%d", info->display);
+                       format_item("Base", buf);
+               } else {
+                       if (info->display != BASE_NONE)
+                               format_item("Base", 
describe_base(info->display));
+               }
+       }
+       dump_tree(ti->first_child);
+       format_end("item");
+}
+
+static void dump_tree(proto_tree *tree)
+{
+       proto_item *ti;
+       if (!tree)
+               return;
+
+       check_tree(tree);
+       format_start("tree");
+       for (ti = tree->first_child; ti; ti = ti->next)
+               dump_item(ti);
+       format_end("tree");
+}
+
 static const struct option long_options[] = {
        { "help", 0, NULL, 'h' },
        { "server", 0, NULL, 's' },
        { "client", 0, NULL, 'c' },
+       { "output-file", required_argument, NULL, 'o' },
+       { "xml", 0, NULL, 'x' },
 };
-static const char options[] = "hsc";
+static const char options[] = "hscxo:";
 
 static void syntax(FILE *f, int exit_value)
 {
@@ -82,6 +486,8 @@ static void syntax(FILE *f, int exit_value)
                "  -h, --help               Show this help\n"
                "  -s, --server             Process server messages (default)\n"
                "  -c, --client             Process client messages\n"
+               "  -x, --xml                Output in XML format\n"
+               "  -o, --output-file=FILE   Output to specified file\n"
        );
        exit(exit_value);
 }
@@ -94,6 +500,7 @@ int main(int argc, char **argv)
        spice_dissect_func_t (*msg_func)(guint8 channel);
        spice_dissect_func_t channel_func = NULL;
 
+       output_file = stdout;
        msg_func = spice_server_channel_get_dissect;
 
        while (1) {
@@ -112,6 +519,13 @@ int main(int argc, char **argv)
                case 'c':
                        msg_func = spice_client_channel_get_dissect;
                        break;
+               case 'x':
+                       format = XML;
+                       break;
+               case 'o':
+                       output_file = fopen(optarg, "w");
+                       check(output_file != NULL, "Error opening output file");
+                       break;
                default:
                        syntax(stderr, EXIT_FAILURE);
                        break;
@@ -123,6 +537,7 @@ int main(int argc, char **argv)
        channel      = strtol(argv[optind++], NULL, 0);
        message_type = strtol(argv[optind++], NULL, 0);
 
+       hfs = g_ptr_array_new_with_free_func(free);
        spice_register_fields(1, NULL);
 
        memset(&glb, 0, sizeof(glb));
@@ -134,9 +549,16 @@ int main(int argc, char **argv)
        assert(channel_func);
 
        memset(&tree, 0, sizeof(tree));
+       tree.tree_data = (void *) &tree;
+       check_tree(&tree);
 
        /* TODO check offset ?? */
        channel_func(message_type, &glb, &tree, 0);
 
+       dump_tree(&tree);
+
+       if (output_file != stdout)
+               fclose(output_file);
+
        return got_error ? EXIT_FAILURE : EXIT_SUCCESS;
 }
-- 
2.1.0

_______________________________________________
Spice-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/spice-devel

Reply via email to