[4/4] widl: Implement conformant structure handling

Dan Hipschman dsh at linux.ucla.edu
Tue Jun 5 20:52:24 CDT 2007


This patch corrects and simplifies structure handling.  It adds a test
for a conformant structure that passes on wine and XP.

A lot of the code for structure handling was duplicated, with minor
inconsistencies, and some of it was wrong to begin with.  This factors
it, and gets most of it working.

---
 dlls/rpcrt4/tests/server.c   |   17 +++
 dlls/rpcrt4/tests/server.idl |    9 ++
 tools/widl/typegen.c         |  247 +++++++++++++-----------------------------
 3 files changed, 100 insertions(+), 173 deletions(-)

diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c
index 52a8ad3..76d6f01 100644
--- a/dlls/rpcrt4/tests/server.c
+++ b/dlls/rpcrt4/tests/server.c
@@ -23,6 +23,7 @@
 #include "server.h"
 #include "server_defines.h"
 
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -203,6 +204,12 @@ s_dot_two_vectors(vector_t vs[2])
   return vs[0].x * vs[1].x + vs[0].y * vs[1].y + vs[0].z * vs[1].z;
 }
 
+int
+s_sum_cs(cs_t *cs)
+{
+  return s_sum_conf_array(cs->ca, cs->n);
+}
+
 void
 s_stop(void)
 {
@@ -386,6 +393,7 @@ array_tests(void)
   };
   static int c[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
   static vector_t vs[2] = {{1, -2, 3}, {4, -5, -6}};
+  cs_t *cs;
 
   ok(sum_fixed_int_3d(m) == 4116, "RPC sum_fixed_int_3d\n");
 
@@ -400,6 +408,15 @@ array_tests(void)
   ok(sum_var_array(&c[2], 0) == 0, "RPC sum_conf_array\n");
 
   ok(dot_two_vectors(vs) == -4, "RPC dot_two_vectors\n");
+  cs = HeapAlloc(GetProcessHeap(), 0, offsetof(cs_t, ca) + 5 * sizeof cs->ca[0]);
+  cs->n = 5;
+  cs->ca[0] = 3;
+  cs->ca[1] = 5;
+  cs->ca[2] = -2;
+  cs->ca[3] = -1;
+  cs->ca[4] = -4;
+  ok(sum_cs(cs) == 1, "RPC sum_cs\n");
+  HeapFree(GetProcessHeap(), 0, cs);
 }
 
 static void
diff --git a/dlls/rpcrt4/tests/server.idl b/dlls/rpcrt4/tests/server.idl
index 65fb71f..213a883 100644
--- a/dlls/rpcrt4/tests/server.idl
+++ b/dlls/rpcrt4/tests/server.idl
@@ -112,5 +112,14 @@ interface IServer
   int sum_conf_array([size_is(n)] int x[], int n);
   int sum_var_array([length_is(n)] int x[20], int n);
   int dot_two_vectors(vector_t vs[2]);
+
+  typedef struct
+  {
+    int n;
+    [size_is(n)] int ca[];
+  } cs_t;
+
+  int sum_cs(cs_t *cs);
+
   void stop(void);
 }
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index 9583743..2327e21 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -709,7 +709,12 @@ size_t type_memsize(const type_t *t, unsigned int *align)
 {
     size_t size = 0;
 
-    if (is_ptr(t))
+    if (t->declarray && is_conformant_array(t))
+    {
+        type_memsize(t->ref, align);
+        size = 0;
+    }
+    else if (is_ptr(t) || is_conformant_array(t))
     {
         size = sizeof(void *);
         if (size > *align) *align = size;
@@ -759,12 +764,8 @@ size_t type_memsize(const type_t *t, unsigned int *align)
     case RPC_FC_LGFARRAY:
     case RPC_FC_SMVARRAY:
     case RPC_FC_LGVARRAY:
-        size = t->dim * type_memsize(t->ref, align);
-        break;
-    case RPC_FC_CARRAY:
-    case RPC_FC_CVARRAY:
     case RPC_FC_BOGUS_ARRAY:
-        size = type_memsize(t->ref, align);
+        size = t->dim * type_memsize(t->ref, align);
         break;
     default:
         error("type_memsize: Unknown type %d\n", t->type);
@@ -1000,6 +1001,8 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
         has_pointer = TRUE;
 
     size = type_memsize(type, &align);
+    if (size == 0)              /* conformant array */
+        size = type_memsize(type->ref, &align);
 
     start_offset = *typestring_offset;
     update_tfsoff(type, start_offset, file);
@@ -1075,15 +1078,15 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
 static const var_t *find_array_or_string_in_struct(const type_t *type)
 {
     const var_t *last_field = LIST_ENTRY( list_tail(type->fields), const var_t, entry );
+    const type_t *ft = last_field->type;
 
-    if (last_field->type->declarray)
+    if (ft->declarray && is_conformant_array(ft))
         return last_field;
 
-    assert((last_field->type->type == RPC_FC_CSTRUCT) ||
-           (last_field->type->type == RPC_FC_CPSTRUCT) ||
-           (last_field->type->type == RPC_FC_CVSTRUCT));
-
-    return find_array_or_string_in_struct(last_field->type);
+    if (ft->type == RPC_FC_CSTRUCT || ft->type == RPC_FC_CPSTRUCT || ft->type == RPC_FC_CVSTRUCT)
+        return find_array_or_string_in_struct(last_field->type);
+    else
+        return NULL;
 }
 
 static void write_struct_members(FILE *file, const type_t *type, unsigned int *typestring_offset)
@@ -1091,13 +1094,17 @@ static void write_struct_members(FILE *file, const type_t *type, unsigned int *t
     const var_t *field;
 
     if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
-        write_member_type(file, field->type, field, typestring_offset);
+    {
+        type_t *ft = field->type;
+        if (!ft->declarray || !is_conformant_array(ft))
+            write_member_type(file, ft, field, typestring_offset);
+    }
 
     write_end(file, typestring_offset);
 }
 
 static size_t write_struct_tfs(FILE *file, type_t *type,
-                               const char *name, unsigned int *typestring_offset)
+                               const char *name, unsigned int *tfsoff)
 {
     unsigned int total_size;
     const var_t *array;
@@ -1108,175 +1115,67 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
 
     guard_rec(type);
 
-    switch (type->type)
-    {
-    case RPC_FC_STRUCT:
-    case RPC_FC_PSTRUCT:
-        total_size = type_memsize(type, &align);
-
-        if (total_size > USHRT_MAX)
-            error("structure size for %s exceeds %d bytes by %d bytes\n",
-                  name, USHRT_MAX, total_size - USHRT_MAX);
-
-        if (type->type == RPC_FC_PSTRUCT)
-            write_embedded_types(file, NULL, type, name, 0, typestring_offset);
-
-        start_offset = *typestring_offset;
-        update_tfsoff(type, start_offset, file);
-        if (type->type == RPC_FC_STRUCT)
-            WRITE_FCTYPE(file, FC_STRUCT, *typestring_offset);
-        else
-            WRITE_FCTYPE(file, FC_PSTRUCT, *typestring_offset);
-        /* alignment */
-        print_file(file, 2, "0x%02x,\n", align - 1);
-        /* total size */
-        print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
-        *typestring_offset += 4;
-
-        if (type->type == RPC_FC_PSTRUCT)
-        {
-            print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
-            print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
-            *typestring_offset += 2;
-            write_pointer_description(file, type, 0, 0, typestring_offset);
-            print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
-            *typestring_offset += 1;
-        }
-
-        /* member layout */
-        current_structure = type;
-        write_struct_members(file, type, typestring_offset);
-        current_structure = NULL;
-        return start_offset;
-    case RPC_FC_CSTRUCT:
-    case RPC_FC_CPSTRUCT:
-        total_size = type_memsize(type, &align);
-
-        if (total_size > USHRT_MAX)
-            error("structure size for %s exceeds %d bytes by %d bytes\n",
-                  name, USHRT_MAX, total_size - USHRT_MAX);
-
-        array = find_array_or_string_in_struct(type);
-        current_structure = type;
-        array_offset = write_array_tfs(file, array->attrs, array->type,
-                                       array->name, typestring_offset);
-        current_structure = NULL;
-
-        if (type->type == RPC_FC_CPSTRUCT)
-            write_embedded_types(file, NULL, type, name, 0, typestring_offset);
-
-        start_offset = *typestring_offset;
-        update_tfsoff(type, start_offset, file);
-        if (type->type == RPC_FC_CSTRUCT)
-            WRITE_FCTYPE(file, FC_CSTRUCT, *typestring_offset);
-        else
-            WRITE_FCTYPE(file, FC_CPSTRUCT, *typestring_offset);
-        /* alignment */
-        print_file(file, 2, "0x%02x,\n", align - 1);
-        /* total size */
-        print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
-        *typestring_offset += 4;
-        print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d (%u) */\n",
-                   array_offset - *typestring_offset,
-                   array_offset - *typestring_offset,
-                   array_offset);
-        *typestring_offset += 2;
-
-        if (type->type == RPC_FC_CPSTRUCT)
-        {
-            print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
-            print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
-            *typestring_offset += 2;
-            write_pointer_description(file, type, 0, 0, typestring_offset);
-            print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
-            *typestring_offset += 1;
-        }
-
-        print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
-        *typestring_offset += 1;
-
-        return start_offset;
-    case RPC_FC_CVSTRUCT:
-        total_size = type_memsize(type, &align);
+    total_size = type_memsize(type, &align);
+    if (total_size > USHRT_MAX)
+        error("structure size for %s exceeds %d bytes by %d bytes\n",
+              name, USHRT_MAX, total_size - USHRT_MAX);
 
-        if (total_size > USHRT_MAX)
-            error("structure size for %s exceeds %d bytes by %d bytes\n",
-                  name, USHRT_MAX, total_size - USHRT_MAX);
+    has_pointers = write_embedded_types(file, NULL, type, name, 0, tfsoff);
 
-        array = find_array_or_string_in_struct(type);
+    array = find_array_or_string_in_struct(type);
+    if (array && !processed(array->type))
+    {
         current_structure = type;
-        if (is_attr(array->attrs, ATTR_STRING))
-            array_offset = write_string_tfs(file, array->attrs, array->type,
-                                            array->name, typestring_offset);
-        else
-            array_offset = write_array_tfs(file, array->attrs, array->type,
-                                           array->name, typestring_offset);
+        array_offset
+            = is_attr(array->attrs, ATTR_STRING)
+            ? write_string_tfs(file, array->attrs, array->type, array->name, tfsoff)
+            : write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
         current_structure = NULL;
+    }
 
-        has_pointers = write_embedded_types(file, NULL, type, name, 0,
-                                            typestring_offset);
-
-        start_offset = *typestring_offset;
-        update_tfsoff(type, start_offset, file);
-        WRITE_FCTYPE(file, FC_CVSTRUCT, *typestring_offset);
-        /* alignment */
-        print_file(file, 2, "0x%02x,\n", align - 1);
-        /* total size */
-        print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
-        *typestring_offset += 4;
-        print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d (%u) */\n",
-                   array_offset - *typestring_offset,
-                   array_offset - *typestring_offset,
-                   array_offset);
-        *typestring_offset += 2;
-
-        if (has_pointers)
-        {
-            print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
-            print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
-            *typestring_offset += 2;
-            write_pointer_description(file, type, 0, 0, typestring_offset);
-            print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
-            *typestring_offset += 1;
-        }
-
-        print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
-        *typestring_offset += 1;
-
-        return start_offset;
-
-    case RPC_FC_BOGUS_STRUCT:
-        total_size = type_memsize(type, &align);
-        if (total_size > USHRT_MAX)
-            error("structure size for %s exceeds %d bytes by %d bytes\n",
-                  name, USHRT_MAX, total_size - USHRT_MAX);
-
-        write_embedded_types(file, NULL, type, name, 0, typestring_offset);
+    start_offset = *tfsoff;
+    update_tfsoff(type, start_offset, file);
+    print_file(file, 0, "/* %d */\n", start_offset);
+    print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
+    print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
+    print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size);
+    *tfsoff += 4;
 
-        start_offset = *typestring_offset;
-        update_tfsoff(type, start_offset, file);
-        print_file(file, 0, "/* %d */\n", start_offset);
-        print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
-        print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
-        print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size);
+    if (array)
+    {
+        unsigned int absoff = array->type->typestring_offset;
+        short reloff = absoff - *tfsoff;
+        print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
+                   reloff, reloff, absoff);
+        *tfsoff += 2;
+    }
+    else if (type->type == RPC_FC_BOGUS_STRUCT)
+    {
+        print_file(file, 2, "NdrFcShort(0x0),\n");
+        *tfsoff += 2;
+    }
 
-        /* do conformant array stuff */
-        print_file(file, 2, "NdrFcShort(0x0),\t/* FIXME: conformant array stuff */\n");
+    if (type->type == RPC_FC_BOGUS_STRUCT)
+    {
 
-        /* do pointer stuff here */
         print_file(file, 2, "NdrFcShort(0x0),\t/* FIXME: pointer stuff */\n");
+        *tfsoff += 2;
+    }
+    else if (has_pointers)
+    {
+        print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
+        print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
+        *tfsoff += 2;
+        write_pointer_description(file, type, 0, 0, tfsoff);
+        print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
+        *tfsoff += 1;
+    }
 
-        *typestring_offset += 8;
-        current_structure = type;
-        write_struct_members(file, type, typestring_offset);
-        current_structure = NULL;
-
-        return start_offset;
+    current_structure = type;
+    write_struct_members(file, type, tfsoff);
+    current_structure = NULL;
 
-    default:
-        error("write_struct_tfs: Unimplemented for type 0x%x\n", type->type);
-        return *typestring_offset;
-    }
+    return start_offset;
 }
 
 static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
@@ -1665,9 +1564,11 @@ static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *ty
 
         retmask |= 1;
     }
+    else if (type->declarray && is_conformant_array(type))
+        ;    /* conformant arrays and strings are handled specially */
     else if (is_array(type))
     {
-        retmask |= write_array_tfs(file, attrs, type, name, tfsoff);
+        write_array_tfs(file, attrs, type, name, tfsoff);
     }
     else if (!is_base_type(type->type))
         error("write_embedded_types: unknown embedded type for %s (0x%x)\n",



More information about the wine-patches mailing list