[PATCH 7/8] rpcrt4: Write type format strings for complex structs.
Zebediah Figura
z.figura12 at gmail.com
Sun Mar 31 23:31:19 CDT 2019
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46378
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/rpcrt4/ndr_typelib.c | 231 ++++++++++++++++++++++++++++++++++++--
1 file changed, 221 insertions(+), 10 deletions(-)
diff --git a/dlls/rpcrt4/ndr_typelib.c b/dlls/rpcrt4/ndr_typelib.c
index 3d3d42b97a..5a4de51dd1 100644
--- a/dlls/rpcrt4/ndr_typelib.c
+++ b/dlls/rpcrt4/ndr_typelib.c
@@ -355,24 +355,42 @@ static unsigned char get_array_fc(ITypeInfo *typeinfo, TYPEDESC *desc)
return FC_BOGUS_ARRAY;
}
-static size_t write_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
+static BOOL type_is_non_iface_pointer(ITypeInfo *typeinfo, TYPEDESC *desc)
+{
+ if (desc->vt == VT_PTR)
+ return !type_pointer_is_iface(typeinfo, desc->lptdesc);
+ else if (desc->vt == VT_USERDEFINED)
+ {
+ ITypeInfo *refinfo;
+ TYPEATTR *attr;
+ BOOL ret;
+
+ ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
+ ITypeInfo_GetTypeAttr(refinfo, &attr);
+
+ if (attr->typekind == TKIND_ALIAS)
+ ret = type_is_non_iface_pointer(refinfo, &attr->tdescAlias);
+ else
+ ret = FALSE;
+
+ ITypeInfo_ReleaseTypeAttr(refinfo, attr);
+ ITypeInfo_Release(refinfo);
+
+ return ret;
+ }
+ else
+ return FALSE;
+}
+
+static void write_struct_members(ITypeInfo *typeinfo, unsigned char *str,
size_t *len, TYPEATTR *attr)
{
- unsigned char fc = get_struct_fc(typeinfo, attr);
unsigned int struct_offset = 0;
unsigned char basetype;
- size_t off = *len;
TYPEDESC *tdesc;
VARDESC *desc;
WORD i;
- if (fc != FC_STRUCT)
- FIXME("fc %02x not implemented\n", fc);
-
- WRITE_CHAR (str, *len, FC_STRUCT);
- WRITE_CHAR (str, *len, attr->cbAlignment - 1);
- WRITE_SHORT(str, *len, attr->cbSizeInstance);
-
for (i = 0; i < attr->cVars; i++)
{
ITypeInfo_GetVarDesc(typeinfo, i, &desc);
@@ -391,12 +409,205 @@ static size_t write_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
if ((basetype = get_basetype(typeinfo, tdesc)))
WRITE_CHAR(str, *len, basetype);
+ else if (type_is_non_iface_pointer(typeinfo, tdesc))
+ WRITE_CHAR(str, *len, FC_POINTER);
+ else
+ {
+ WRITE_CHAR(str, *len, FC_EMBEDDED_COMPLEX);
+ WRITE_CHAR(str, *len, 0);
+ WRITE_SHORT(str, *len, 0);
+ }
ITypeInfo_ReleaseVarDesc(typeinfo, desc);
}
if (!(*len & 1))
WRITE_CHAR (str, *len, FC_PAD);
WRITE_CHAR (str, *len, FC_END);
+}
+
+static void write_simple_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
+ size_t *len, TYPEATTR *attr)
+{
+ write_struct_members(typeinfo, str, len, attr);
+}
+
+static BOOL type_needs_pointer_deref(ITypeInfo *typeinfo, TYPEDESC *desc)
+{
+ if (desc->vt == VT_PTR || desc->vt == VT_UNKNOWN || desc->vt == VT_DISPATCH)
+ return TRUE;
+ else if (desc->vt == VT_USERDEFINED)
+ {
+ ITypeInfo *refinfo;
+ BOOL ret = FALSE;
+ TYPEATTR *attr;
+
+ ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
+ ITypeInfo_GetTypeAttr(refinfo, &attr);
+
+ if (attr->typekind == TKIND_ALIAS)
+ ret = type_needs_pointer_deref(refinfo, &attr->tdescAlias);
+
+ ITypeInfo_ReleaseTypeAttr(refinfo, attr);
+ ITypeInfo_Release(refinfo);
+
+ return ret;
+ }
+ else
+ return FALSE;
+}
+
+static void write_complex_struct_pointer_layout(ITypeInfo *typeinfo,
+ TYPEDESC *desc, unsigned char *str, size_t *len)
+{
+ unsigned char basetype;
+
+ if (desc->vt == VT_PTR && !type_pointer_is_iface(typeinfo, desc->lptdesc))
+ {
+ WRITE_CHAR(str, *len, FC_UP);
+ if ((basetype = get_basetype(typeinfo, desc->lptdesc)))
+ {
+ WRITE_CHAR(str, *len, FC_SIMPLE_POINTER);
+ WRITE_CHAR(str, *len, basetype);
+ WRITE_CHAR(str, *len, FC_PAD);
+ }
+ else
+ {
+ if (type_needs_pointer_deref(typeinfo, desc->lptdesc))
+ WRITE_CHAR(str, *len, FC_POINTER_DEREF);
+ else
+ WRITE_CHAR(str, *len, 0);
+ WRITE_SHORT(str, *len, 0);
+ }
+ }
+ else if (desc->vt == VT_USERDEFINED)
+ {
+ ITypeInfo *refinfo;
+ TYPEATTR *attr;
+
+ ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
+ ITypeInfo_GetTypeAttr(refinfo, &attr);
+
+ if (attr->typekind == TKIND_ALIAS)
+ write_complex_struct_pointer_layout(refinfo, &attr->tdescAlias, str, len);
+
+ ITypeInfo_ReleaseTypeAttr(refinfo, attr);
+ ITypeInfo_Release(refinfo);
+ }
+}
+
+static size_t write_complex_struct_pointer_ref(ITypeInfo *typeinfo,
+ TYPEDESC *desc, unsigned char *str, size_t *len)
+{
+ if (desc->vt == VT_PTR && !type_pointer_is_iface(typeinfo, desc->lptdesc)
+ && !get_basetype(typeinfo, desc->lptdesc))
+ {
+ return write_type_tfs(typeinfo, str, len, desc->lptdesc, FALSE, FALSE);
+ }
+ else if (desc->vt == VT_USERDEFINED)
+ {
+ ITypeInfo *refinfo;
+ TYPEATTR *attr;
+ size_t ret = 0;
+
+ ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
+ ITypeInfo_GetTypeAttr(refinfo, &attr);
+
+ if (attr->typekind == TKIND_ALIAS)
+ ret = write_complex_struct_pointer_ref(refinfo, &attr->tdescAlias, str, len);
+
+ ITypeInfo_ReleaseTypeAttr(refinfo, attr);
+ ITypeInfo_Release(refinfo);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static void write_complex_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
+ size_t *len, TYPEATTR *attr)
+{
+ size_t pointer_layout_offset, pointer_layout, member_layout, ref;
+ unsigned int struct_offset = 0;
+ TYPEDESC *tdesc;
+ VARDESC *desc;
+ WORD i;
+
+ WRITE_SHORT(str, *len, 0); /* conformant array description */
+ pointer_layout_offset = *len;
+ WRITE_SHORT(str, *len, 0); /* pointer layout; will be filled in later */
+ member_layout = *len;
+
+ /* First pass: write the struct members and pointer layout, but do not yet
+ * write the offsets for embedded complexes and pointer refs. These must be
+ * handled after we write the whole struct description, since it must be
+ * contiguous. */
+
+ write_struct_members(typeinfo, str, len, attr);
+
+ pointer_layout = *len;
+ if (str) *((short *)(str + pointer_layout_offset)) = pointer_layout - pointer_layout_offset;
+
+ for (i = 0; i < attr->cVars; i++)
+ {
+ ITypeInfo_GetVarDesc(typeinfo, i, &desc);
+ write_complex_struct_pointer_layout(typeinfo, &desc->elemdescVar.tdesc, str, len);
+ ITypeInfo_ReleaseVarDesc(typeinfo, desc);
+ }
+
+ /* Second pass: write types for embedded complexes and non-simple pointers. */
+
+ struct_offset = 0;
+
+ for (i = 0; i < attr->cVars; i++)
+ {
+ ITypeInfo_GetVarDesc(typeinfo, i, &desc);
+ tdesc = &desc->elemdescVar.tdesc;
+
+ if (struct_offset != desc->oInst)
+ member_layout++; /* alignment directive */
+ struct_offset = desc->oInst + type_memsize(typeinfo, tdesc);
+
+ if (get_basetype(typeinfo, tdesc))
+ member_layout++;
+ else if (type_is_non_iface_pointer(typeinfo, tdesc))
+ {
+ member_layout++;
+ if ((ref = write_complex_struct_pointer_ref(typeinfo, tdesc, str, len)))
+ {
+ if (str) *((short *)(str + pointer_layout + 2)) = ref - (pointer_layout + 2);
+ }
+ pointer_layout += 4;
+ }
+ else
+ {
+ ref = write_type_tfs(typeinfo, str, len, tdesc, FALSE, FALSE);
+ if (str) *((short *)(str + member_layout + 2)) = ref - (member_layout + 2);
+ member_layout += 4;
+ }
+
+ ITypeInfo_ReleaseVarDesc(typeinfo, desc);
+ }
+}
+
+static size_t write_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
+ size_t *len, TYPEATTR *attr)
+{
+ unsigned char fc = get_struct_fc(typeinfo, attr);
+ size_t off = *len;
+
+ /* For the sake of simplicity, write pointer structs as complex structs. */
+ if (fc == FC_PSTRUCT)
+ fc = FC_BOGUS_STRUCT;
+
+ WRITE_CHAR (str, *len, fc);
+ WRITE_CHAR (str, *len, attr->cbAlignment - 1);
+ WRITE_SHORT(str, *len, attr->cbSizeInstance);
+
+ if (fc == FC_STRUCT)
+ write_simple_struct_tfs(typeinfo, str, len, attr);
+ else if (fc == FC_BOGUS_STRUCT)
+ write_complex_struct_tfs(typeinfo, str, len, attr);
return off;
}
--
2.20.1
More information about the wine-devel
mailing list