Dan Hipschman : widl: Fix problems with variable-size user types.

Alexandre Julliard julliard at winehq.org
Mon Oct 22 09:55:26 CDT 2007


Module: wine
Branch: master
Commit: ff8930f2bfdfd5a16924422fcd9e2730593952fa
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=ff8930f2bfdfd5a16924422fcd9e2730593952fa

Author: Dan Hipschman <dsh at linux.ucla.edu>
Date:   Fri Oct 19 15:30:12 2007 -0700

widl: Fix problems with variable-size user types.

---

 dlls/rpcrt4/tests/server.c   |   48 ++++++++++++++++++++++++++++++++++++++++++
 dlls/rpcrt4/tests/server.idl |    9 +++++++
 tools/widl/typegen.c         |   22 +++++++++++++++++-
 3 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c
index 97f2e23..d0f4eef 100644
--- a/dlls/rpcrt4/tests/server.c
+++ b/dlls/rpcrt4/tests/server.c
@@ -459,6 +459,18 @@ s_make_pyramid_doub_carr(unsigned char n, doub_carr_t **dc)
   *dc = t;
 }
 
+unsigned
+s_hash_bstr(bstr_t b)
+{
+  short n = b[-1];
+  short *s = b;
+  unsigned hash = 0;
+  short i;
+  for (i = 0; i < n; ++i)
+    hash = 5 * hash + (unsigned) s[i];
+  return hash;
+}
+
 void
 s_stop(void)
 {
@@ -744,6 +756,38 @@ us_t_UserFree(ULONG *flags, us_t *pus)
   HeapFree(GetProcessHeap(), 0, pus->x);
 }
 
+ULONG __RPC_USER
+bstr_t_UserSize(ULONG *flags, ULONG start, bstr_t *b)
+{
+  return start + FIELD_OFFSET(wire_bstr_t, data[(*b)[-1]]);
+}
+
+unsigned char * __RPC_USER
+bstr_t_UserMarshal(ULONG *flags, unsigned char *buffer, bstr_t *b)
+{
+  wire_bstr_t *wb = (wire_bstr_t *) buffer;
+  wb->n = (*b)[-1];
+  memcpy(&wb->data, *b, wb->n * sizeof wb->data[0]);
+  return buffer + FIELD_OFFSET(wire_bstr_t, data[wb->n]);
+}
+
+unsigned char * __RPC_USER
+bstr_t_UserUnmarshal(ULONG *flags, unsigned char *buffer, bstr_t *b)
+{
+  wire_bstr_t *wb = (wire_bstr_t *) buffer;
+  short *data = HeapAlloc(GetProcessHeap(), 0, (wb->n + 1) * sizeof *data);
+  data[0] = wb->n;
+  memcpy(&data[1], wb->data, wb->n * sizeof data[1]);
+  *b = &data[1];
+  return buffer + FIELD_OFFSET(wire_bstr_t, data[wb->n]);
+}
+
+void __RPC_USER
+bstr_t_UserFree(ULONG *flags, bstr_t *b)
+{
+  HeapFree(GetProcessHeap(), 0, &((*b)[-1]));
+}
+
 static void
 pointer_tests(void)
 {
@@ -754,6 +798,8 @@ pointer_tests(void)
   int *pa[4];
   puints_t pus;
   cpuints_t cpus;
+  short bstr_data[] = { 5, 'H', 'e', 'l', 'l', 'o' };
+  bstr_t bstr = &bstr_data[1];
 
   ok(test_list_length(list) == 3, "RPC test_list_length\n");
   ok(square_puint(p1) == 121, "RPC square_puint\n");
@@ -794,6 +840,8 @@ pointer_tests(void)
   pa[3] = &a[3];
   ok(sum_pcarr(pa, 4) == 10, "RPC sum_pcarr\n");
 
+  ok(hash_bstr(bstr) == s_hash_bstr(bstr), "RPC hash_bstr_data\n");
+
   free_list(list);
 }
 
diff --git a/dlls/rpcrt4/tests/server.idl b/dlls/rpcrt4/tests/server.idl
index 807bf44..fa1ea15 100644
--- a/dlls/rpcrt4/tests/server.idl
+++ b/dlls/rpcrt4/tests/server.idl
@@ -281,5 +281,14 @@ cpp_quote("#endif")
   int sum_doub_carr(doub_carr_t *dc);
   void make_pyramid_doub_carr(unsigned char n, [out] doub_carr_t **dc);
 
+  typedef struct
+  {
+    short n;
+    [size_is(n)] short data[];
+  } wire_bstr_t;
+
+  typedef [wire_marshal(wire_bstr_t)] short *bstr_t;
+  unsigned hash_bstr(bstr_t s);
+
   void stop(void);
 }
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index 6f194b7..dd21fe4 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -907,13 +907,31 @@ static int processed(const type_t *type)
     return type->typestring_offset && !type->tfswrite;
 }
 
+static int user_type_has_variable_size(const type_t *t)
+{
+    if (is_ptr(t))
+        return TRUE;
+    else
+        switch (t->type)
+        {
+        case RPC_FC_PSTRUCT:
+        case RPC_FC_CSTRUCT:
+        case RPC_FC_CPSTRUCT:
+        case RPC_FC_CVSTRUCT:
+            return TRUE;
+        }
+    /* Note: Since this only applies to user types, we can't have a conformant
+       array here, and strings should get filed under pointer in this case.  */
+    return FALSE;
+}
+
 static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
 {
     unsigned int start, absoff, flags;
     unsigned int align = 0, ualign = 0;
     const char *name;
     type_t *utype = get_user_type(type, &name);
-    size_t usize = type_memsize(utype, &ualign);
+    size_t usize = user_type_has_variable_size(utype) ? 0 : type_memsize(utype, &ualign);
     size_t size = type_memsize(type, &align);
     unsigned short funoff = user_type_offset(name);
     short reloff;
@@ -949,8 +967,8 @@ static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
     print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
                flags | (align - 1), align - 1, flags);
     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
-    print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize);
     print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", size, size);
+    print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize);
     *tfsoff += 8;
     reloff = absoff - *tfsoff;
     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", reloff, reloff, absoff);




More information about the wine-cvs mailing list