widl: Implement NDR for struct field alignment

Dan Hipschman dsh at linux.ucla.edu
Tue Sep 4 13:04:37 CDT 2007


This patch implements structure field alignment in widl, which is probably
needed for a lot of stuff (I seem to remember there was some stuff in
oaidl.idl that needed it).  The tests pass on wine and windows.

Since Alexandre is on vacation this week, I'm not going to save all my
patches up and send them all at once.  Just assume each of my patches
depends on the previous, even if they don't, and if one of them derails
the train, I'll just resend the rest next week.  Enjoy your break,
Alexandre.

---
 dlls/rpcrt4/tests/server.c   |    9 +++++++++
 dlls/rpcrt4/tests/server.idl |   10 ++++++++++
 tools/widl/typegen.c         |   40 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 58 insertions(+), 1 deletions(-)

diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c
index 32735a9..b6b2565 100644
--- a/dlls/rpcrt4/tests/server.c
+++ b/dlls/rpcrt4/tests/server.c
@@ -329,6 +329,12 @@ s_sum_toplev_conf_cond(int *x, int a, int b, int c)
   return sum;
 }
 
+double
+s_sum_aligns(aligns_t *a)
+{
+  return a->c + a->i + a->s + a->d;
+}
+
 void
 s_stop(void)
 {
@@ -374,6 +380,7 @@ basic_tests(void)
   static pvectors_t pvecs = {&vec1, &pvec2};
   static sp_inner_t spi = {42};
   static sp_t sp = {-13, &spi};
+  static aligns_t aligns = {3, 4, 5, 6.0};
   pints_t pints;
   ptypes_t ptypes;
   int i1, i2, i3, *pi2, *pi3, **ppi3;
@@ -447,6 +454,8 @@ basic_tests(void)
   ok(enum_ord(E2) == 2, "RPC enum_ord\n");
   ok(enum_ord(E3) == 3, "RPC enum_ord\n");
   ok(enum_ord(E4) == 4, "RPC enum_ord\n");
+
+  ok(sum_aligns(&aligns) == 18.0, "RPC sum_aligns\n");
 }
 
 static void
diff --git a/dlls/rpcrt4/tests/server.idl b/dlls/rpcrt4/tests/server.idl
index 59c9477..0a8c0d3 100644
--- a/dlls/rpcrt4/tests/server.idl
+++ b/dlls/rpcrt4/tests/server.idl
@@ -189,5 +189,15 @@ interface IServer
   int sum_toplev_conf_2n([size_is(n * 2)] int *x, int n);
   int sum_toplev_conf_cond([size_is(c ? a : b)] int *x, int a, int b, int c);
 
+  typedef struct
+  {
+    char c;
+    int i;
+    short s;
+    double d;
+  } aligns_t;
+
+  double sum_aligns(aligns_t *a);
+
   void stop(void);
 }
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index 2907706..0ec03d9 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -98,6 +98,8 @@ const char *string_of_type(unsigned char type)
     case RPC_FC_CARRAY: return "FC_CARRAY";
     case RPC_FC_CVARRAY: return "FC_CVARRAY";
     case RPC_FC_BOGUS_ARRAY: return "FC_BOGUS_ARRAY";
+    case RPC_FC_ALIGNM4: return "RPC_FC_ALIGNM4";
+    case RPC_FC_ALIGNM8: return "RPC_FC_ALIGNM8";
     default:
         error("string_of_type: unknown type 0x%02x\n", type);
         return NULL;
@@ -682,13 +684,25 @@ static size_t write_conf_or_var_desc(FILE *file, const func_t *func, const type_
 
 static size_t fields_memsize(const var_list_t *fields, unsigned int *align)
 {
+    int have_align = FALSE;
     size_t size = 0;
     const var_t *v;
 
     if (!fields) return 0;
     LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
-        size += type_memsize(v->type, align);
+    {
+        unsigned int falign = 0;
+        size_t fsize = type_memsize(v->type, &falign);
+        if (!have_align)
+        {
+            *align = falign;
+            have_align = TRUE;
+        }
+        size = (size + (falign - 1)) & ~(falign - 1);
+        size += fsize;
+    }
 
+    size = (size + (*align - 1)) & ~(*align - 1);
     return size;
 }
 
@@ -1508,12 +1522,36 @@ static void write_struct_members(FILE *file, const type_t *type,
                                  unsigned int *corroff, unsigned int *typestring_offset)
 {
     const var_t *field;
+    unsigned short offset = 0;
 
     if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
     {
         type_t *ft = field->type;
         if (!ft->declarray || !is_conformant_array(ft))
+        {
+            unsigned int align = 0;
+            size_t size = type_memsize(ft, &align);
+            if ((align - 1) & offset)
+            {
+                unsigned char fc = 0;
+                switch (align)
+                {
+                case 4:
+                    fc = RPC_FC_ALIGNM4;
+                    break;
+                case 8:
+                    fc = RPC_FC_ALIGNM8;
+                    break;
+                default:
+                    error("write_struct_members: cannot align type %d", ft->type);
+                }
+                print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
+                offset = (offset + (align - 1)) & ~(align - 1);
+                *typestring_offset += 1;
+            }
             write_member_type(file, ft, field, corroff, typestring_offset);
+            offset += size;
+        }
     }
 
     write_end(file, typestring_offset);



More information about the wine-patches mailing list