diff -apurN a/mingw-w64-tools/widl/Makefile.am b/mingw-w64-tools/widl/Makefile.am --- a/mingw-w64-tools/widl/Makefile.am 2020-10-13 16:23:12.944066396 +0200 +++ b/mingw-w64-tools/widl/Makefile.am 2020-10-13 16:19:00.523221067 +0200 @@ -29,6 +29,7 @@ widl_SOURCES = src/widl.h \ src/utils.c \ src/widl.c \ src/write_msft.c \ + src/write_sltg.c \ src/wpp/wpp_private.h \ src/wpp/ppy.tab.h \ src/wpp/ppl.yy.c \ diff -apurN a/mingw-w64-tools/widl/Makefile.in b/mingw-w64-tools/widl/Makefile.in --- a/mingw-w64-tools/widl/Makefile.in 2020-10-13 16:23:12.944066396 +0200 +++ b/mingw-w64-tools/widl/Makefile.in 2020-10-13 16:21:19.069027341 +0200 @@ -117,7 +117,8 @@ am_widl_OBJECTS = src/widl-client.$(OBJE src/widl-utils.$(OBJEXT) src/widl-widl.$(OBJEXT) \ src/widl-write_msft.$(OBJEXT) src/wpp/widl-ppl.yy.$(OBJEXT) \ src/wpp/widl-ppy.tab.$(OBJEXT) src/wpp/widl-preproc.$(OBJEXT) \ - src/wpp/widl-wpp.$(OBJEXT) src/widl-pathtools.$(OBJEXT) + src/wpp/widl-wpp.$(OBJEXT) src/widl-pathtools.$(OBJEXT) \ + src/widl-write_sltg.$(OBJEXT) widl_OBJECTS = $(am_widl_OBJECTS) widl_LDADD = $(LDADD) widl_LINK = $(CCLD) $(widl_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ @@ -356,6 +357,7 @@ widl_SOURCES = src/widl.h \ src/utils.c \ src/widl.c \ src/write_msft.c \ + src/write_sltg.c \ src/wpp/wpp_private.h \ src/wpp/ppy.tab.h \ src/wpp/ppl.yy.c \ @@ -527,6 +529,8 @@ src/widl-widl.$(OBJEXT): src/$(am__dirst src/$(DEPDIR)/$(am__dirstamp) src/widl-write_msft.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) +src/widl-write_sltg.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) src/wpp/$(am__dirstamp): @$(MKDIR_P) src/wpp @: > src/wpp/$(am__dirstamp) @@ -840,6 +845,20 @@ src/widl-write_msft.obj: src/write_msft. @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(widl_CPPFLAGS) $(CPPFLAGS) $(widl_CFLAGS) $(CFLAGS) -c -o src/widl-write_msft.obj `if test -f 'src/write_msft.c'; then $(CYGPATH_W) 'src/write_msft.c'; else $(CYGPATH_W) '$(srcdir)/src/write_msft.c'; fi` +src/widl-write_sltg.o: src/write_sltg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(widl_CPPFLAGS) $(CPPFLAGS) $(widl_CFLAGS) $(CFLAGS) -MT src/widl-write_sltg.o -MD -MP -MF src/$(DEPDIR)/widl-write_sltg.Tpo -c -o src/widl-write_sltg.o `test -f 'src/write_sltg.c' || echo '$(srcdir)/'`src/write_sltg.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/widl-write_sltg.Tpo src/$(DEPDIR)/widl-write_sltg.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/write_sltg.c' object='src/widl-write_sltg.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(widl_CPPFLAGS) $(CPPFLAGS) $(widl_CFLAGS) $(CFLAGS) -c -o src/widl-write_sltg.o `test -f 'src/write_sltg.c' || echo '$(srcdir)/'`src/write_sltg.c + +src/widl-write_sltg.obj: src/write_sltg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(widl_CPPFLAGS) $(CPPFLAGS) $(widl_CFLAGS) $(CFLAGS) -MT src/widl-write_sltg.obj -MD -MP -MF src/$(DEPDIR)/widl-write_sltg.Tpo -c -o src/widl-write_sltg.obj `if test -f 'src/write_sltg.c'; then $(CYGPATH_W) 'src/write_sltg.c'; else $(CYGPATH_W) '$(srcdir)/src/write_sltg.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/widl-write_sltg.Tpo src/$(DEPDIR)/widl-write_sltg.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/write_sltg.c' object='src/widl-write_sltg.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(widl_CPPFLAGS) $(CPPFLAGS) $(widl_CFLAGS) $(CFLAGS) -c -o src/widl-write_sltg.obj `if test -f 'src/write_sltg.c'; then $(CYGPATH_W) 'src/write_sltg.c'; else $(CYGPATH_W) '$(srcdir)/src/write_sltg.c'; fi` + src/wpp/widl-ppl.yy.o: src/wpp/ppl.yy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(widl_CPPFLAGS) $(CPPFLAGS) $(widl_CFLAGS) $(CFLAGS) -MT src/wpp/widl-ppl.yy.o -MD -MP -MF src/wpp/$(DEPDIR)/widl-ppl.yy.Tpo -c -o src/wpp/widl-ppl.yy.o `test -f 'src/wpp/ppl.yy.c' || echo '$(srcdir)/'`src/wpp/ppl.yy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/wpp/$(DEPDIR)/widl-ppl.yy.Tpo src/wpp/$(DEPDIR)/widl-ppl.yy.Po diff -apurN a/mingw-w64-tools/widl/src/register.c b/mingw-w64-tools/widl/src/register.c --- a/mingw-w64-tools/widl/src/register.c 2020-10-13 16:23:12.950066345 +0200 +++ b/mingw-w64-tools/widl/src/register.c 2020-10-13 16:19:00.523221067 +0200 @@ -281,7 +281,12 @@ void write_typelib_regscript( const stat if (count && !strendswith( typelib_name, ".res" )) error( "Cannot store multiple typelibs into %s\n", typelib_name ); else - create_msft_typelib( stmt->u.lib ); + { + if (do_old_typelib) + create_sltg_typelib( stmt->u.lib ); + else + create_msft_typelib( stmt->u.lib ); + } count++; } if (count && strendswith( typelib_name, ".res" )) flush_output_resources( typelib_name ); diff -apurN a/mingw-w64-tools/widl/src/typelib.h b/mingw-w64-tools/widl/src/typelib.h --- a/mingw-w64-tools/widl/src/typelib.h 2020-10-13 16:23:12.950066345 +0200 +++ b/mingw-w64-tools/widl/src/typelib.h 2020-10-13 16:19:00.523221067 +0200 @@ -83,4 +83,5 @@ enum VARENUM { extern unsigned short get_type_vt(type_t *t); extern int create_msft_typelib(typelib_t *typelib); +extern int create_sltg_typelib(typelib_t *typelib); #endif diff -apurN a/mingw-w64-tools/widl/src/widl.c b/mingw-w64-tools/widl/src/widl.c --- a/mingw-w64-tools/widl/src/widl.c 2020-10-13 16:23:12.951066337 +0200 +++ b/mingw-w64-tools/widl/src/widl.c 2020-10-13 16:22:05.493635687 +0200 @@ -64,6 +64,7 @@ static const char usage[] = " --nostdinc Do not search the standard include path\n" " --ns_prefix Prefix namespaces with ABI namespace\n" " --oldnames Use old naming conventions\n" +" --oldtlb Use old typelib (SLTG) format\n" " -o, --output=NAME Set the output file name\n" " -Otype Type of stubs to generate (-Os, -Oi, -Oif)\n" " -p Generate proxy\n" @@ -116,6 +117,7 @@ int do_everything = 1; static int preprocess_only = 0; int do_header = 0; int do_typelib = 0; +int do_old_typelib = 0; int do_proxies = 0; int do_client = 0; int do_server = 0; @@ -168,6 +170,7 @@ enum { DLLDATA_OPTION, DLLDATA_ONLY_OPTION, LOCAL_STUBS_OPTION, + OLD_TYPELIB_OPTION, NOSTDINC_OPTION, PREFIX_ALL_OPTION, PREFIX_CLIENT_OPTION, @@ -195,6 +198,7 @@ static const struct option long_options[ { "nostdinc", 0, NULL, NOSTDINC_OPTION }, { "ns_prefix", 0, NULL, RT_NS_PREFIX }, { "oldnames", 0, NULL, OLDNAMES_OPTION }, + { "oldtlb", 0, NULL, OLD_TYPELIB_OPTION }, { "output", 0, NULL, 'o' }, { "prefix-all", 1, NULL, PREFIX_ALL_OPTION }, { "prefix-client", 1, NULL, PREFIX_CLIENT_OPTION }, @@ -333,6 +337,7 @@ static void set_everything(int x) { do_header = x; do_typelib = x; + do_old_typelib = x; do_proxies = x; do_client = x; do_server = x; @@ -749,6 +754,9 @@ int main(int argc,char *argv[]) do_everything = 0; do_typelib = 1; break; + case OLD_TYPELIB_OPTION: + do_old_typelib = 1; + break; case 'T': typelib_name = xstrdup(optarg); break; diff -apurN a/mingw-w64-tools/widl/src/widl.h b/mingw-w64-tools/widl/src/widl.h --- a/mingw-w64-tools/widl/src/widl.h 2020-10-13 16:23:12.951066337 +0200 +++ b/mingw-w64-tools/widl/src/widl.h 2020-10-13 16:19:00.524221058 +0200 @@ -38,6 +38,7 @@ extern int pedantic; extern int do_everything; extern int do_header; extern int do_typelib; +extern int do_old_typelib; extern int do_proxies; extern int do_client; extern int do_server; diff -apurN a/mingw-w64-tools/widl/src/write_sltg.c b/mingw-w64-tools/widl/src/write_sltg.c --- a/mingw-w64-tools/widl/src/write_sltg.c 1970-01-01 01:00:00.000000000 +0100 +++ b/mingw-w64-tools/widl/src/write_sltg.c 2020-10-13 16:19:00.524221058 +0200 @@ -0,0 +1,1857 @@ +/* + * Typelib (SLTG) generation + * + * Copyright 2015,2016 Dmitry Timoshkov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include +#include + +#define NONAMELESSUNION + +#include "windef.h" +#include "winbase.h" + +#include "widl.h" +#include "typelib.h" +#include "typelib_struct.h" +#include "utils.h" +#include "header.h" +#include "typetree.h" + +static const GUID sltg_library_guid = { 0x204ff,0,0,{ 0xc0,0,0,0,0,0,0,0x46 } }; + +struct sltg_data +{ + int size, allocated; + char *data; +}; + +struct sltg_library +{ + short name; + char *helpstring; + char *helpfile; + int helpcontext; + int syskind; + LCID lcid; + int libflags; + int version; + GUID uuid; +}; + +struct sltg_block +{ + int length; + int index_string; + void *data; + struct sltg_block *next; +}; + +struct sltg_typelib +{ + typelib_t *typelib; + struct sltg_data index; + struct sltg_data name_table; + struct sltg_library library; + struct sltg_block *blocks; + int n_file_blocks; + int first_block; + int typeinfo_count; + int typeinfo_size; + struct sltg_block *typeinfo; +}; + +struct sltg_hrefmap +{ + int href_count; + int *href; +}; + +#include "pshpack1.h" +struct sltg_typeinfo_header +{ + short magic; + int href_offset; + int res06; + int member_offset; + int res0e; + int version; + int res16; + struct + { + unsigned unknown1 : 3; + unsigned flags : 13; + unsigned unknown2 : 8; + unsigned typekind : 8; + } misc; + int res1e; +}; + +struct sltg_member_header +{ + short res00; + short res02; + char res04; + int extra; +}; + +struct sltg_variable +{ + char magic; /* 0x0a */ + char flags; + short next; + short name; + short byte_offs; /* pos in struct, or offset to const type or const data (if flags & 0x08) */ + short type; /* if flags & 0x02 this is the type, else offset to type */ + int memid; + short helpcontext; + short helpstring; + short varflags; /* only present if magic & 0x02 */ +}; + +struct sltg_tail +{ + short cFuncs; + short cVars; + short cImplTypes; + short res06; /* always 0000 */ + short funcs_off; /* offset to functions (starting from the member header) */ + short vars_off; /* offset to vars (starting from the member header) */ + short impls_off; /* offset to implemented types (starting from the member header) */ + short funcs_bytes; /* bytes used by function data */ + short vars_bytes; /* bytes used by var data */ + short impls_bytes; /* bytes used by implemented type data */ + short tdescalias_vt; /* for TKIND_ALIAS */ + short res16; /* always ffff */ + short res18; /* always 0000 */ + short res1a; /* always 0000 */ + short simple_alias; /* tdescalias_vt is a vt rather than an offset? */ + short res1e; /* always 0000 */ + short cbSizeInstance; + short cbAlignment; + short res24; + short res26; + short cbSizeVft; + short res2a; /* always ffff */ + short res2c; /* always ffff */ + short res2e; /* always ffff */ + short res30; /* always ffff */ + short res32; /* unknown */ + short type_bytes; /* bytes used by type descriptions */ +}; + +struct sltg_hrefinfo +{ + char magic; /* 0xdf */ + char res01; /* 0x00 */ + int res02; /* 0xffffffff */ + int res06; /* 0xffffffff */ + int res0a; /* 0xffffffff */ + int res0e; /* 0xffffffff */ + int res12; /* 0xffffffff */ + int res16; /* 0xffffffff */ + int res1a; /* 0xffffffff */ + int res1e; /* 0xffffffff */ + int res22; /* 0xffffffff */ + int res26; /* 0xffffffff */ + int res2a; /* 0xffffffff */ + int res2e; /* 0xffffffff */ + int res32; /* 0xffffffff */ + int res36; /* 0xffffffff */ + int res3a; /* 0xffffffff */ + int res3e; /* 0xffffffff */ + short res42;/* 0xffff */ + int number; /* this is 8 times the number of refs */ + /* Now we have number bytes (8 for each ref) of SLTG_UnknownRefInfo */ + + short res50;/* 0xffff */ + char res52; /* 0x01 */ + int res53; /* 0x00000000 */ + /* Now we have number/8 SLTG_Names (first WORD is no of bytes in the ascii + * string). Strings look like "*\Rxxxx*#n". If xxxx == ffff then the + * ref refers to the nth type listed in this library (0 based). Else + * the xxxx (which maybe fewer than 4 digits) is the offset into the name + * table to a string "*\G{}#1.0#0#C:\WINNT\System32\stdole32.tlb#" + * The guid is the typelib guid; the ref again refers to the nth type of + * the imported typelib. + */ + + char resxx; /* 0xdf */ +}; + +struct sltg_function +{ + char magic; /* 0x4c, 0xcb or 0x8b with optional SLTG_FUNCTION_FLAGS_PRESENT flag */ + char flags; /* high nibble is INVOKE_KIND, low nibble = 2 */ + short next; /* byte offset from beginning of group to next fn */ + short name; /* Offset within name table to name */ + int dispid; /* dispid */ + short helpcontext; /* helpcontext (again 1 is special) */ + short helpstring; /* helpstring offset to offset */ + short arg_off; /* offset to args from start of block */ + char nacc; /* lowest 3bits are CALLCONV, rest are no of args */ + char retnextopt; /* if 0x80 bit set ret type follows else next WORD + is offset to ret type. No of optional args is + middle 6 bits */ + short rettype; /* return type VT_?? or offset to ret type */ + short vtblpos; /* position in vtbl? */ + short funcflags; /* present if magic & 0x20 */ +/* Param list starts, repeat next two as required */ +#if 0 + WORD name; /* offset to 2nd letter of name */ + WORD+ type; /* VT_ of param */ +#endif +}; + +struct sltg_impl_info +{ + short res00; + short next; + short res04; + char impltypeflags; + char res07; + short res08; + short ref; + short res0c; + short res0e; + short res10; + short res12; + short pos; +}; + +#include "poppack.h" + +static void add_structure_typeinfo(struct sltg_typelib *typelib, type_t *type); +static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *type); +static void add_enum_typeinfo(struct sltg_typelib *typelib, type_t *type); +static void add_union_typeinfo(struct sltg_typelib *typelib, type_t *type); +static void add_coclass_typeinfo(struct sltg_typelib *typelib, type_t *type); + +static void init_sltg_data(struct sltg_data *data) +{ + data->size = 0; + data->allocated = 0x10; + data->data = xmalloc(0x10); +} + +static int add_index(struct sltg_data *index, const char *name) +{ + int name_offset = index->size; + int new_size = index->size + strlen(name) + 1; + + chat("add_index: name_offset %d, \"%s\"\n", name_offset, name); + + if (new_size > index->allocated) + { + index->allocated = max(index->allocated * 2, new_size); + index->data = xrealloc(index->data, index->allocated); + } + + strcpy(index->data + index->size, name); + index->size = new_size; + + return name_offset; +} + +static void init_index(struct sltg_data *index) +{ + static const char compobj[] = { 1,'C','o','m','p','O','b','j',0 }; + + init_sltg_data(index); + + add_index(index, compobj); +} + +static int add_name(struct sltg_typelib *sltg, const char *name) +{ + int name_offset = sltg->name_table.size; + int new_size = sltg->name_table.size + strlen(name) + 1 + 8; + int aligned_size; + + chat("add_name: %s\n", name); + + aligned_size = (new_size + 0x1f) & ~0x1f; + if (aligned_size - new_size < 4) + new_size = aligned_size; + else + new_size = (new_size + 1) & ~1; + + if (new_size > sltg->name_table.allocated) + { + sltg->name_table.allocated = max(sltg->name_table.allocated * 2, new_size); + sltg->name_table.data = xrealloc(sltg->name_table.data, sltg->name_table.allocated); + } + + memset(sltg->name_table.data + sltg->name_table.size, 0xff, 8); + strcpy(sltg->name_table.data + sltg->name_table.size + 8, name); + sltg->name_table.size = new_size; + sltg->name_table.data[sltg->name_table.size - 1] = 0; /* clear alignment */ + + return name_offset; +} + +static void init_name_table(struct sltg_typelib *sltg) +{ + init_sltg_data(&sltg->name_table); +} + +static void init_library(struct sltg_typelib *sltg) +{ + const attr_t *attr; + + sltg->library.name = add_name(sltg, sltg->typelib->name); + sltg->library.helpstring = NULL; + sltg->library.helpcontext = 0; + sltg->library.syskind = (pointer_size == 8) ? SYS_WIN64 : SYS_WIN32; + sltg->library.lcid = 0x0409; + sltg->library.libflags = 0; + sltg->library.version = 0; + sltg->library.helpfile = NULL; + memset(&sltg->library.uuid, 0, sizeof(sltg->library.uuid)); + + if (!sltg->typelib->attrs) return; + + LIST_FOR_EACH_ENTRY(attr, sltg->typelib->attrs, const attr_t, entry) + { + const expr_t *expr; + + switch (attr->type) + { + case ATTR_VERSION: + sltg->library.version = attr->u.ival; + break; + case ATTR_HELPSTRING: + sltg->library.helpstring = attr->u.pval; + break; + case ATTR_HELPFILE: + sltg->library.helpfile = attr->u.pval; + break; + case ATTR_UUID: + sltg->library.uuid = *(GUID *)attr->u.pval; + break; + case ATTR_HELPCONTEXT: + expr = attr->u.pval; + sltg->library.helpcontext = expr->cval; + break; + case ATTR_LIBLCID: + expr = attr->u.pval; + sltg->library.lcid = expr->cval; + break; + case ATTR_CONTROL: + sltg->library.libflags |= 0x02; /* LIBFLAG_FCONTROL */ + break; + case ATTR_HIDDEN: + sltg->library.libflags |= 0x04; /* LIBFLAG_FHIDDEN */ + break; + case ATTR_RESTRICTED: + sltg->library.libflags |= 0x01; /* LIBFLAG_FRESTRICTED */ + break; + default: + break; + } + } +} + +static void add_block_index(struct sltg_typelib *sltg, void *data, int size, int index) +{ + struct sltg_block *block = xmalloc(sizeof(*block)); + + block->length = size; + block->data = data; + block->index_string = index; + block->next = NULL; + + if (sltg->blocks) + { + struct sltg_block *blocks = sltg->blocks; + + while (blocks->next) + blocks = blocks->next; + + blocks->next = block; + } + else + sltg->blocks = block; + + sltg->n_file_blocks++; +} + +static void add_block(struct sltg_typelib *sltg, void *data, int size, const char *name) +{ + struct sltg_block *block = xmalloc(sizeof(*block)); + int index; + + chat("add_block: %p,%d,\"%s\"\n", data, size, name); + + index = add_index(&sltg->index, name); + + add_block_index(sltg, data, size, index); +} + +static void *create_library_block(struct sltg_typelib *typelib, int *size, int *index) +{ + void *block; + short *p; + + *size = sizeof(short) * 9 + sizeof(int) * 3 + sizeof(GUID); + if (typelib->library.helpstring) *size += strlen(typelib->library.helpstring); + if (typelib->library.helpfile) *size += strlen(typelib->library.helpfile); + + block = xmalloc(*size); + p = block; + *p++ = 0x51cc; /* magic */ + *p++ = 3; /* res02 */ + *p++ = typelib->library.name; + *p++ = 0xffff; /* res06 */ + if (typelib->library.helpstring) + { + *p++ = strlen(typelib->library.helpstring); + strcpy((char *)p, typelib->library.helpstring); + p = (short *)((char *)p + strlen(typelib->library.helpstring)); + } + else + *p++ = 0xffff; + if (typelib->library.helpfile) + { + *p++ = strlen(typelib->library.helpfile); + strcpy((char *)p, typelib->library.helpfile); + p = (short *)((char *)p + strlen(typelib->library.helpfile)); + } + else + *p++ = 0xffff; + *(int *)p = typelib->library.helpcontext; + p += 2; + *p++ = typelib->library.syskind; + *p++ = typelib->library.lcid; + *(int *)p = 0; /* res12 */ + p += 2; + *p++ = typelib->library.libflags; + *(int *)p = typelib->library.version; + p += 2; + *(GUID *)p = typelib->library.uuid; + + *index = add_index(&typelib->index, "dir"); + + return block; +} + +static const char *new_index_name(void) +{ + static char name[11] = "0000000000"; + static int pos = 0; + char *new_name; + + if (name[pos] == 'Z') + { + pos++; + if (pos > 9) + error("too many index names\n"); + } + + name[pos]++; + + new_name = xmalloc(sizeof(name)); + strcpy(new_name, name); + return new_name; +} + +static void sltg_add_typeinfo(struct sltg_typelib *sltg, void *data, int size, const char *name) +{ + struct sltg_block *block = xmalloc(sizeof(*block)); + + chat("sltg_add_typeinfo: %p,%d,%s\n", data, size, name); + + block->length = size; + block->data = data; + block->index_string = 0; + block->next = NULL; + + if (sltg->typeinfo) + { + struct sltg_block *typeinfo = sltg->typeinfo; + + while (typeinfo->next) + typeinfo = typeinfo->next; + + typeinfo->next = block; + } + else + sltg->typeinfo = block; + + sltg->typeinfo_count++; + sltg->typeinfo_size += size; +} + +static void append_data(struct sltg_data *block, const void *data, int size) +{ + int new_size = block->size + size; + + if (new_size > block->allocated) + { + block->allocated = max(block->allocated * 2, new_size); + block->data = xrealloc(block->data, block->allocated); + } + + memcpy(block->data + block->size, data, size); + block->size = new_size; +} + +static void add_module_typeinfo(struct sltg_typelib *typelib, type_t *type) +{ + error("add_module_typeinfo: %s not implemented\n", type->name); +} + +static const char *add_typeinfo_block(struct sltg_typelib *typelib, const type_t *type, int kind) +{ + const char *index_name, *other_name; + void *block; + short *p; + int size, helpcontext = 0; + GUID guid = { 0 }; + const expr_t *expr; + + index_name = new_index_name(); + other_name = new_index_name(); + + expr = get_attrp(type->attrs, ATTR_HELPCONTEXT); + if (expr) helpcontext = expr->cval; + + p = get_attrp(type->attrs, ATTR_UUID); + if (p) guid = *(GUID *)p; + + size = sizeof(short) * 8 + 10 /* index_name */ * 2 + sizeof(int) + sizeof(GUID); + + block = xmalloc(size); + p = block; + *p++ = strlen(index_name); + strcpy((char *)p, index_name); + p = (short *)((char *)p + strlen(index_name)); + *p++ = strlen(other_name); + strcpy((char *)p, other_name); + p = (short *)((char *)p + strlen(other_name)); + *p++ = -1; /* res1a */ + *p++ = add_name(typelib, type->name); /* name offset */ + *p++ = 0; /* FIXME: helpstring */ + *p++ = -1; /* res20 */ + *(int *)p = helpcontext; + p += 2; + *p++ = -1; /* res26 */ + *(GUID *)p = guid; + p += sizeof(GUID)/2; + *p = kind; + + sltg_add_typeinfo(typelib, block, size, index_name); + + return index_name; +} + +static void init_typeinfo(struct sltg_typeinfo_header *ti, const type_t *type, int kind, + const struct sltg_hrefmap *hrefmap) +{ + ti->magic = 0x0501; + ti->href_offset = -1; + ti->res06 = -1; + ti->res0e = -1; + ti->version = get_attrv(type->attrs, ATTR_VERSION); + ti->res16 = 0xfffe0000; + ti->misc.unknown1 = 0x02; + ti->misc.flags = 0; /* FIXME */ + ti->misc.unknown2 = 0x02; + ti->misc.typekind = kind; + ti->res1e = 0; + + ti->member_offset = sizeof(*ti); + + if (hrefmap->href_count) + { + char name[64]; + int i, hrefinfo_size; + + hrefinfo_size = sizeof(struct sltg_hrefinfo); + + for (i = 0; i < hrefmap->href_count; i++) + { + sprintf(name, "*\\Rffff*#%x", hrefmap->href[i]); + hrefinfo_size += 8 + 2 + strlen(name); + } + + ti->href_offset = ti->member_offset; + ti->member_offset += hrefinfo_size; + } +} + +static void init_sltg_tail(struct sltg_tail *tail) +{ + tail->cFuncs = 0; + tail->cVars = 0; + tail->cImplTypes = 0; + tail->res06 = 0; + tail->funcs_off = -1; + tail->vars_off = -1; + tail->impls_off = -1; + tail->funcs_bytes = -1; + tail->vars_bytes = -1; + tail->impls_bytes = -1; + tail->tdescalias_vt = -1; + tail->res16 = -1; + tail->res18 = 0; + tail->res1a = 0; + tail->simple_alias = 0; + tail->res1e = 0; + tail->cbSizeInstance = 0; + tail->cbAlignment = 4; + tail->res24 = -1; + tail->res26 = -1; + tail->cbSizeVft = 0; + tail->res2a = -1; + tail->res2c = -1; + tail->res2e = -1; + tail->res30 = -1; + tail->res32 = 0; + tail->type_bytes = 0; +} + +static void write_hrefmap(struct sltg_data *data, const struct sltg_hrefmap *hrefmap) +{ + struct sltg_hrefinfo hrefinfo; + char name[64]; + int i; + + if (!hrefmap->href_count) return; + + hrefinfo.magic = 0xdf; + hrefinfo.res01 = 0; + hrefinfo.res02 = -1; + hrefinfo.res06 = -1; + hrefinfo.res0a = -1; + hrefinfo.res0e = -1; + hrefinfo.res12 = -1; + hrefinfo.res16 = -1; + hrefinfo.res1a = -1; + hrefinfo.res1e = -1; + hrefinfo.res22 = -1; + hrefinfo.res26 = -1; + hrefinfo.res2a = -1; + hrefinfo.res2e = -1; + hrefinfo.res32 = -1; + hrefinfo.res36 = -1; + hrefinfo.res3a = -1; + hrefinfo.res3e = -1; + hrefinfo.res42 = -1; + hrefinfo.number = hrefmap->href_count * 8; + hrefinfo.res50 = -1; + hrefinfo.res52 = 1; + hrefinfo.res53 = 0; + hrefinfo.resxx = 0xdf; + + append_data(data, &hrefinfo, offsetof(struct sltg_hrefinfo, res50)); + + for (i = 0; i < hrefmap->href_count; i++) + append_data(data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8); + + append_data(data, &hrefinfo.res50, 7); + + for (i = 0; i < hrefmap->href_count; i++) + { + short len; + + sprintf(name, "*\\Rffff*#%x", hrefmap->href[i]); + len = strlen(name); + + append_data(data, &len, sizeof(len)); + append_data(data, name, len); + } + + append_data(data, &hrefinfo.resxx, sizeof(hrefinfo.resxx)); +} + +static void dump_var_desc(const char *data, int size) +{ + const unsigned char *p = (const unsigned char *)data; + int i; + + if (!(debuglevel & (DEBUGLEVEL_TRACE | DEBUGLEVEL_CHAT))) return; + + chat("dump_var_desc: size %d bytes\n", size); + + for (i = 0; i < size; i++) + fprintf(stderr, " %02x", *p++); + + fprintf(stderr, "\n"); +} + +static int get_element_size(type_t *type) +{ + int vt = get_type_vt(type); + + switch (vt) + { + case VT_I1: + case VT_UI1: + return 1; + + case VT_INT: + case VT_UINT: + return /* typelib_kind == SYS_WIN16 ? 2 : */ 4; + + case VT_UI2: + case VT_I2: + case VT_BOOL: + return 2; + + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_ERROR: + case VT_HRESULT: + return 4; + + case VT_R8: + case VT_I8: + case VT_UI8: + case VT_CY: + case VT_DATE: + return 8; + + case VT_DECIMAL: + return 16; + + case VT_PTR: + case VT_UNKNOWN: + case VT_DISPATCH: + case VT_BSTR: + case VT_LPSTR: + case VT_LPWSTR: + return pointer_size; + + case VT_VOID: + return 0; + + case VT_VARIANT: + return pointer_size == 8 ? 24 : 16; + + case VT_USERDEFINED: + return 0; + + default: + error("get_element_size: unrecognized vt %d\n", vt); + break; + } + + return 0; +} + +static int local_href(struct sltg_hrefmap *hrefmap, int typelib_href) +{ + int i, href = -1; + + for (i = 0; i < hrefmap->href_count; i++) + { + if (hrefmap->href[i] == typelib_href) + { + href = i; + break; + } + } + + if (href == -1) + { + href = hrefmap->href_count; + + if (hrefmap->href) + hrefmap->href = xrealloc(hrefmap->href, sizeof(*hrefmap->href) * (hrefmap->href_count + 1)); + else + hrefmap->href = xmalloc(sizeof(*hrefmap->href)); + + hrefmap->href[hrefmap->href_count] = typelib_href; + hrefmap->href_count++; + } + + chat("typelib href %d mapped to local href %d\n", typelib_href, href); + + return href << 2; +} + +static short write_var_desc(struct sltg_typelib *typelib, struct sltg_data *data, type_t *type, short param_flags, + short flags, short base_offset, int *size_instance, struct sltg_hrefmap *hrefmap) +{ + short vt, vt_flags, desc_offset; + + chat("write_var_desc: type %p, type->name %s\n", + type, type->name ? type->name : "NULL"); + + if (is_array(type) && !type_array_is_decl_as_ptr(type)) + { + int num_dims, elements, array_start, size, array_size; + type_t *atype; + struct + { + short cDims; + short fFeatures; + int cbElements; + int cLocks; + void *pvData; + int bound[2]; + } *array; + int *bound; + short vt_off[2]; + + elements = 1; + num_dims = 0; + + atype = type; + + while (is_array(atype) && !type_array_is_decl_as_ptr(atype)) + { + num_dims++; + elements *= type_array_get_dim(atype); + + atype = type_array_get_element_type(atype); + } + + chat("write_var_desc: VT_CARRAY: %d dimensions, %d elements\n", num_dims, elements); + + array_start = data->size; + + size = sizeof(*array) + (num_dims - 1) * 8 /* sizeof(SAFEARRAYBOUND) */; + array = xmalloc(size); + + array->cDims = num_dims; + array->fFeatures = 0x0004; /* FADF_EMBEDDED */ + array->cbElements = get_element_size(atype); + array->cLocks = 0; + array->pvData = NULL; + + bound = array->bound; + + array_size = array->cbElements; + atype = type; + + while (is_array(atype) && !type_array_is_decl_as_ptr(atype)) + { + bound[0] = type_array_get_dim(atype); + array_size *= bound[0]; + bound[1] = 0; + bound += 2; + + atype = type_array_get_element_type(atype); + } + + if (size_instance) + { + *size_instance += array_size; + size_instance = NULL; /* don't account for element size */ + } + + append_data(data, array, size); + + desc_offset = data->size; + + vt_off[0] = VT_CARRAY; + vt_off[1] = array_start + base_offset; + append_data(data, vt_off, sizeof(vt_off)); + + /* fall through to write array element description */ + type = atype; + } + else + desc_offset = data->size; + + vt = get_type_vt(type); + + if (vt == VT_PTR) + { + type_t *ref = is_ptr(type) ? type_pointer_get_ref_type(type) : type_array_get_element_type(type); + + if (is_ptr(ref)) + { + chat("write_var_desc: vt VT_PTR | 0x0400 | %04x\n", param_flags); + vt = VT_PTR | 0x0400 | param_flags; + append_data(data, &vt, sizeof(vt)); + write_var_desc(typelib, data, ref, 0, 0, base_offset, size_instance, hrefmap); + } + else + write_var_desc(typelib, data, ref, param_flags, 0x0e00, base_offset, size_instance, hrefmap); + return desc_offset; + } + + chat("write_var_desc: vt %d, flags %04x\n", vt, flags); + + vt_flags = vt | flags | param_flags; + append_data(data, &vt_flags, sizeof(vt_flags)); + + if (vt == VT_USERDEFINED) + { + short href; + + while (type->typelib_idx < 0 && type_is_alias(type)) + type = type_alias_get_aliasee_type(type); + + chat("write_var_desc: VT_USERDEFINED, type %p, name %s, real type %d, href %d\n", + type, type->name, type_get_type(type), type->typelib_idx); + + if (type->typelib_idx == -1) + { + chat("write_var_desc: trying to ref not added type\n"); + + switch (type_get_type(type)) + { + case TYPE_STRUCT: + add_structure_typeinfo(typelib, type); + break; + case TYPE_INTERFACE: + add_interface_typeinfo(typelib, type); + break; + case TYPE_ENUM: + add_enum_typeinfo(typelib, type); + break; + case TYPE_UNION: + add_union_typeinfo(typelib, type); + break; + case TYPE_COCLASS: + add_coclass_typeinfo(typelib, type); + break; + default: + error("write_var_desc: VT_USERDEFINED - unhandled type %d\n", + type_get_type(type)); + } + } + + if (type->typelib_idx == -1) + error("write_var_desc: trying to ref not added type\n"); + + href = local_href(hrefmap, type->typelib_idx); + chat("write_var_desc: VT_USERDEFINED, local href %d\n", href); + + append_data(data, &href, sizeof(href)); + } + + if (size_instance) + *size_instance += get_element_size(type); + + return desc_offset; +} + +static void add_structure_typeinfo(struct sltg_typelib *typelib, type_t *type) +{ + struct sltg_data data, *var_data = NULL; + struct sltg_hrefmap hrefmap; + const char *index_name; + struct sltg_typeinfo_header ti; + struct sltg_member_header member; + struct sltg_tail tail; + int member_offset, var_count = 0, var_data_size = 0, size_instance = 0; + short *type_desc_offset = NULL; + + if (type->typelib_idx != -1) return; + + chat("add_structure_typeinfo: type %p, type->name %s\n", type, type->name); + + type->typelib_idx = typelib->n_file_blocks; + + hrefmap.href_count = 0; + hrefmap.href = NULL; + + if (type_struct_get_fields(type)) + { + int i = 0; + var_t *var; + + var_count = list_count(type_struct_get_fields(type)); + + var_data = xmalloc(var_count * sizeof(*var_data)); + type_desc_offset = xmalloc(var_count * sizeof(*type_desc_offset)); + + LIST_FOR_EACH_ENTRY(var, type_struct_get_fields(type), var_t, entry) + { + short base_offset; + + chat("add_structure_typeinfo: var %p (%s), type %p (%s)\n", + var, var->name, var->declspec.type, var->declspec.type->name); + + init_sltg_data(&var_data[i]); + + base_offset = var_data_size + (i + 1) * sizeof(struct sltg_variable); + type_desc_offset[i] = write_var_desc(typelib, &var_data[i], var->declspec.type, 0, 0, + base_offset, &size_instance, &hrefmap); + dump_var_desc(var_data[i].data, var_data[i].size); + + if (var_data[i].size > sizeof(short)) + var_data_size += var_data[i].size; + i++; + } + } + + init_sltg_data(&data); + + index_name = add_typeinfo_block(typelib, type, TKIND_RECORD); + + init_typeinfo(&ti, type, TKIND_RECORD, &hrefmap); + append_data(&data, &ti, sizeof(ti)); + + write_hrefmap(&data, &hrefmap); + + member_offset = data.size; + + member.res00 = 0x0001; + member.res02 = 0xffff; + member.res04 = 0x01; + member.extra = var_data_size + var_count * sizeof(struct sltg_variable); + append_data(&data, &member, sizeof(member)); + + var_data_size = 0; + + if (type_struct_get_fields(type)) + { + int i = 0; + short next = member_offset; + var_t *var; + + LIST_FOR_EACH_ENTRY(var, type_struct_get_fields(type), var_t, entry) + { + struct sltg_variable variable; + + next += sizeof(variable); + + variable.magic = 0x2a; /* always write flags to simplify calculations */ + variable.name = add_name(typelib, var->name); + variable.byte_offs = 0; + if (var_data[i].size > sizeof(short)) + { + variable.flags = 0; + var_data_size = next - member_offset + type_desc_offset[i]; + variable.type = var_data_size; + next += var_data[i].size; + } + else + { + variable.flags = 0x02; + variable.type = *(short *)var_data[i].data; + } + variable.next = i < var_count - 1 ? next - member_offset : -1; + variable.memid = 0x40000000 + i; + variable.helpcontext = -2; /* 0xfffe */ + variable.helpstring = -1; + variable.varflags = 0; + + append_data(&data, &variable, sizeof(variable)); + if (var_data[i].size > sizeof(short)) + append_data(&data, var_data[i].data, var_data[i].size); + + i++; + } + } + + init_sltg_tail(&tail); + + tail.cVars = var_count; + tail.vars_off = 0; + tail.vars_bytes = var_data_size; + tail.cbSizeInstance = size_instance; + tail.type_bytes = data.size - member_offset - sizeof(member); + append_data(&data, &tail, sizeof(tail)); + + add_block(typelib, data.data, data.size, index_name); +} + +static importinfo_t *find_importinfo(typelib_t *typelib, const char *name) +{ + importlib_t *importlib; + + LIST_FOR_EACH_ENTRY(importlib, &typelib->importlibs, importlib_t, entry) + { + int i; + + for (i = 0; i < importlib->ntypeinfos; i++) + { + if (!strcmp(name, importlib->importinfos[i].name)) + { + chat("Found %s in importlib list\n", name); + return &importlib->importinfos[i]; + } + } + } + + return NULL; +} + +static int get_func_flags(const var_t *func, int *dispid, int *invokekind, int *helpcontext, const char **helpstring) +{ + const attr_t *attr; + int flags; + + *invokekind = 1 /* INVOKE_FUNC */; + *helpcontext = -2; + *helpstring = NULL; + + if (!func->attrs) return 0; + + flags = 0; + + LIST_FOR_EACH_ENTRY(attr, func->attrs, const attr_t, entry) + { + expr_t *expr = attr->u.pval; + switch(attr->type) + { + case ATTR_BINDABLE: + flags |= 0x4; /* FUNCFLAG_FBINDABLE */ + break; + case ATTR_DEFAULTBIND: + flags |= 0x20; /* FUNCFLAG_FDEFAULTBIND */ + break; + case ATTR_DEFAULTCOLLELEM: + flags |= 0x100; /* FUNCFLAG_FDEFAULTCOLLELEM */ + break; + case ATTR_DISPLAYBIND: + flags |= 0x10; /* FUNCFLAG_FDISPLAYBIND */ + break; + case ATTR_HELPCONTEXT: + *helpcontext = expr->u.lval; + break; + case ATTR_HELPSTRING: + *helpstring = attr->u.pval; + break; + case ATTR_HIDDEN: + flags |= 0x40; /* FUNCFLAG_FHIDDEN */ + break; + case ATTR_ID: + *dispid = expr->cval; + break; + case ATTR_IMMEDIATEBIND: + flags |= 0x1000; /* FUNCFLAG_FIMMEDIATEBIND */ + break; + case ATTR_NONBROWSABLE: + flags |= 0x400; /* FUNCFLAG_FNONBROWSABLE */ + break; + case ATTR_PROPGET: + *invokekind = 0x2; /* INVOKE_PROPERTYGET */ + break; + case ATTR_PROPPUT: + *invokekind = 0x4; /* INVOKE_PROPERTYPUT */ + break; + case ATTR_PROPPUTREF: + *invokekind = 0x8; /* INVOKE_PROPERTYPUTREF */ + break; + /* FIXME: FUNCFLAG_FREPLACEABLE */ + case ATTR_REQUESTEDIT: + flags |= 0x8; /* FUNCFLAG_FREQUESTEDIT */ + break; + case ATTR_RESTRICTED: + flags |= 0x1; /* FUNCFLAG_FRESTRICTED */ + break; + case ATTR_SOURCE: + flags |= 0x2; /* FUNCFLAG_FSOURCE */ + break; + case ATTR_UIDEFAULT: + flags |= 0x200; /* FUNCFLAG_FUIDEFAULT */ + break; + case ATTR_USESGETLASTERROR: + flags |= 0x80; /* FUNCFLAG_FUSESGETLASTERROR */ + break; + default: + break; + } + } + + return flags; +} + +static int get_param_flags(const var_t *param) +{ + const attr_t *attr; + int flags, in, out; + + if (!param->attrs) return 0; + + flags = 0; + in = out = 0; + + LIST_FOR_EACH_ENTRY(attr, param->attrs, const attr_t, entry) + { + switch(attr->type) + { + case ATTR_IN: + in++; + break; + case ATTR_OUT: + out++; + break; + case ATTR_PARAMLCID: + flags |= 0x2000; + break; + case ATTR_RETVAL: + flags |= 0x80; + break; + default: + chat("unhandled param attr %d\n", attr->type); + break; + } + } + + if (out) + { + if (in) + flags |= 0x8000; + else + flags |= 0x4000; + } + else if (!in) + flags |= 0xc000; + + return flags; +} + + +static int add_func_desc(struct sltg_typelib *typelib, struct sltg_data *data, var_t *func, + int idx, int dispid, short base_offset, struct sltg_hrefmap *hrefmap) +{ + struct sltg_data ret_data, *arg_data; + int arg_count = 0, arg_data_size, optional = 0, defaults = 0, old_size; + int funcflags = 0, invokekind = 1 /* INVOKE_FUNC */, helpcontext; + const char *helpstring; + const var_t *arg; + short ret_desc_offset, *arg_desc_offset, arg_offset; + struct sltg_function func_desc; + + chat("add_func_desc: %s, idx %#x, dispid %#x\n", func->name, idx, dispid); + + old_size = data->size; + + init_sltg_data(&ret_data); + ret_desc_offset = write_var_desc(typelib, &ret_data, type_function_get_rettype(func->declspec.type), + 0, 0, base_offset, NULL, hrefmap); + dump_var_desc(ret_data.data, ret_data.size); + + arg_data_size = 0; + arg_offset = base_offset + sizeof(struct sltg_function); + + if (ret_data.size > sizeof(short)) + { + arg_data_size += ret_data.size; + arg_offset += ret_data.size; + } + + if (type_function_get_args(func->declspec.type)) + { + int i = 0; + + arg_count = list_count(type_function_get_args(func->declspec.type)); + + arg_data = xmalloc(arg_count * sizeof(*arg_data)); + arg_desc_offset = xmalloc(arg_count * sizeof(*arg_desc_offset)); + + arg_offset += arg_count * 2 * sizeof(short); + + LIST_FOR_EACH_ENTRY(arg, type_function_get_args(func->declspec.type), const var_t, entry) + { + const attr_t *attr; + short param_flags = get_param_flags(arg); + + chat("add_func_desc: arg[%d] %p (%s), type %p (%s)\n", + i, arg, arg->name, arg->declspec.type, arg->declspec.type->name); + + init_sltg_data(&arg_data[i]); + + + arg_desc_offset[i] = write_var_desc(typelib, &arg_data[i], arg->declspec.type, param_flags, 0, + arg_offset, NULL, hrefmap); + dump_var_desc(arg_data[i].data, arg_data[i].size); + + if (arg_data[i].size > sizeof(short)) + { + arg_data_size += arg_data[i].size; + arg_offset += arg_data[i].size;; + } + + i++; + + if (!arg->attrs) continue; + + LIST_FOR_EACH_ENTRY(attr, arg->attrs, const attr_t, entry) + { + if (attr->type == ATTR_DEFAULTVALUE) + defaults++; + else if(attr->type == ATTR_OPTIONAL) + optional++; + } + } + } + + funcflags = get_func_flags(func, &dispid, &invokekind, &helpcontext, &helpstring); + + if (base_offset != -1) + chat("add_func_desc: flags %#x, dispid %#x, invokekind %d, helpcontext %#x, helpstring %s\n", + funcflags, dispid, invokekind, helpcontext, helpstring); + + func_desc.magic = 0x6c; /* always write flags to simplify calculations */ + func_desc.flags = (invokekind << 4) | 0x02; + if (idx & 0x80000000) + { + func_desc.next = -1; + idx &= ~0x80000000; + } + else + func_desc.next = base_offset + sizeof(func_desc) + arg_data_size + arg_count * 2 * sizeof(short); + func_desc.name = base_offset != -1 ? add_name(typelib, func->name) : -1; + func_desc.dispid = dispid; + func_desc.helpcontext = helpcontext; + func_desc.helpstring = (helpstring && base_offset != -1) ? add_name(typelib, helpstring) : -1; + func_desc.arg_off = arg_count ? base_offset + sizeof(func_desc) : -1; + func_desc.nacc = (arg_count << 3) | 4 /* CC_STDCALL */; + func_desc.retnextopt = (optional << 1); + if (ret_data.size > sizeof(short)) + { + func_desc.rettype = base_offset + sizeof(func_desc) + ret_desc_offset; + if (arg_count) + func_desc.arg_off += ret_data.size; + } + else + { + func_desc.retnextopt |= 0x80; + func_desc.rettype = *(short *)ret_data.data; + } + func_desc.vtblpos = idx * pointer_size; + func_desc.funcflags = funcflags; + + append_data(data, &func_desc, sizeof(func_desc)); + + arg_offset = base_offset + sizeof(struct sltg_function); + + if (ret_data.size > sizeof(short)) + { + append_data(data, ret_data.data, ret_data.size); + func_desc.arg_off += ret_data.size; + arg_offset += ret_data.size; + } + + if (arg_count) + { + int i = 0; + + arg_offset += arg_count * 2 * sizeof(short); + + LIST_FOR_EACH_ENTRY(arg, type_function_get_args(func->declspec.type), const var_t, entry) + { + short name, type_offset; + + name = base_offset != -1 ? add_name(typelib, arg->name) : -1; + + if (arg_data[i].size > sizeof(short)) + { + type_offset = (arg_offset + arg_desc_offset[i]); + arg_offset += arg_data[i].size; + } + else + { + name |= 1; + type_offset = *(short *)arg_data[i].data; + } + + append_data(data, &name, sizeof(name)); + append_data(data, &type_offset, sizeof(type_offset)); + + if (base_offset != -1) + chat("add_func_desc: arg[%d] - name %s (%#x), type_offset %#x\n", + i, arg->name, name, type_offset); + + i++; + } + + for (i = 0; i < arg_count; i++) + { + if (arg_data[i].size > sizeof(short)) + append_data(data, arg_data[i].data, arg_data[i].size); + } + } + + return data->size - old_size; +} + +static void write_impl_href(struct sltg_data *data, short href) +{ + struct sltg_impl_info impl_info; + + impl_info.res00 = 0x004a; + impl_info.next = -1; + impl_info.res04 = -1; + impl_info.impltypeflags = 0; + impl_info.res07 = 0x80; + impl_info.res08 = 0x0012; + impl_info.ref = href; + impl_info.res0c = 0x4001; + impl_info.res0e = -2; /* 0xfffe */ + impl_info.res10 = -1; + impl_info.res12 = 0x001d; + impl_info.pos = 0; + + append_data(data, &impl_info, sizeof(impl_info)); +} + +static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *iface) +{ + const statement_t *stmt_func; + importinfo_t *ref_importinfo = NULL; + short inherit_href = -1; + struct sltg_data data; + struct sltg_hrefmap hrefmap; + const char *index_name; + struct sltg_typeinfo_header ti; + struct sltg_member_header member; + struct sltg_tail tail; + int member_offset, base_offset, func_data_size, i; + int func_count, inherited_func_count = 0; + int dispid, inherit_level = 0; + + if (iface->typelib_idx != -1) return; + + chat("add_interface_typeinfo: type %p, type->name %s\n", iface, iface->name); + + if (!iface->details.iface) + { + error("interface %s is referenced but not defined\n", iface->name); + return; + } + + if (is_attr(iface->attrs, ATTR_DISPINTERFACE)) + { + error("support for dispinterface %s is not implemented\n", iface->name); + return; + } + + hrefmap.href_count = 0; + hrefmap.href = NULL; + + if (type_iface_get_inherit(iface)) + { + type_t *inherit; + + inherit = type_iface_get_inherit(iface); + + chat("add_interface_typeinfo: inheriting from base interface %s\n", inherit->name); + + ref_importinfo = find_importinfo(typelib->typelib, inherit->name); + + if (!ref_importinfo && type_iface_get_inherit(inherit)) + add_interface_typeinfo(typelib, inherit); + + if (ref_importinfo) + error("support for imported interfaces is not implemented\n"); + + inherit_href = local_href(&hrefmap, inherit->typelib_idx); + + while (inherit) + { + inherit_level++; + inherited_func_count += list_count(type_iface_get_stmts(inherit)); + inherit = type_iface_get_inherit(inherit); + } + } + + /* check typelib_idx again, it could have been added while resolving the parent interface */ + if (iface->typelib_idx != -1) return; + + iface->typelib_idx = typelib->n_file_blocks; + + /* pass 1: calculate function descriptions data size */ + init_sltg_data(&data); + + STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(iface)) + { + add_func_desc(typelib, &data, stmt_func->u.var, -1, -1, -1, &hrefmap); + } + + func_data_size = data.size; + + /* pass 2: write function descriptions */ + init_sltg_data(&data); + + func_count = list_count(type_iface_get_stmts(iface)); + + index_name = add_typeinfo_block(typelib, iface, TKIND_INTERFACE); + + init_typeinfo(&ti, iface, TKIND_INTERFACE, &hrefmap); + append_data(&data, &ti, sizeof(ti)); + + write_hrefmap(&data, &hrefmap); + + member_offset = data.size; + base_offset = 0; + + member.res00 = 0x0001; + member.res02 = 0xffff; + member.res04 = 0x01; + member.extra = func_data_size; + if (inherit_href != -1) + { + member.extra += sizeof(struct sltg_impl_info); + base_offset += sizeof(struct sltg_impl_info); + } + append_data(&data, &member, sizeof(member)); + + if (inherit_href != -1) + write_impl_href(&data, inherit_href); + + i = 0; + dispid = 0x60000000 | (inherit_level << 16); + + STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(iface)) + { + int idx = inherited_func_count + i; + + if (i == func_count - 1) idx |= 0x80000000; + + base_offset += add_func_desc(typelib, &data, stmt_func->u.var, + idx, dispid + i, base_offset, &hrefmap); + i++; + } + + init_sltg_tail(&tail); + + tail.cFuncs = func_count; + tail.funcs_off = 0; + tail.funcs_bytes = func_data_size; + tail.cbSizeInstance = pointer_size; + tail.cbAlignment = pointer_size; + tail.cbSizeVft = (inherited_func_count + func_count) * pointer_size; + tail.type_bytes = data.size - member_offset - sizeof(member); + tail.res24 = 0; + tail.res26 = 0; + if (inherit_href != -1) + { + tail.cImplTypes++; + tail.impls_off = 0; + tail.impls_bytes = 0; + + tail.funcs_off += sizeof(struct sltg_impl_info); + } + append_data(&data, &tail, sizeof(tail)); + + add_block(typelib, data.data, data.size, index_name); +} + +static void add_enum_typeinfo(struct sltg_typelib *typelib, type_t *type) +{ + error("add_enum_typeinfo: %s not implemented\n", type->name); +} + +static void add_union_typeinfo(struct sltg_typelib *typelib, type_t *type) +{ + error("add_union_typeinfo: %s not implemented\n", type->name); +} + +static void add_coclass_typeinfo(struct sltg_typelib *typelib, type_t *type) +{ + error("add_coclass_typeinfo: %s not implemented\n", type->name); +} + +static void add_type_typeinfo(struct sltg_typelib *typelib, type_t *type) +{ + chat("add_type_typeinfo: adding %s, type %d\n", type->name, type_get_type(type)); + + switch (type_get_type(type)) + { + case TYPE_INTERFACE: + add_interface_typeinfo(typelib, type); + break; + case TYPE_STRUCT: + add_structure_typeinfo(typelib, type); + break; + case TYPE_ENUM: + add_enum_typeinfo(typelib, type); + break; + case TYPE_UNION: + add_union_typeinfo(typelib, type); + break; + case TYPE_COCLASS: + add_coclass_typeinfo(typelib, type); + break; + case TYPE_BASIC: + case TYPE_POINTER: + break; + default: + error("add_type_typeinfo: unhandled type %d for %s\n", type_get_type(type), type->name); + break; + } +} + +static void add_statement(struct sltg_typelib *typelib, const statement_t *stmt) +{ + switch(stmt->type) + { + case STMT_LIBRARY: + case STMT_IMPORT: + case STMT_PRAGMA: + case STMT_CPPQUOTE: + case STMT_DECLARATION: + /* not included in typelib */ + break; + case STMT_IMPORTLIB: + /* not processed here */ + break; + + case STMT_TYPEDEF: + { + const type_list_t *type_entry = stmt->u.type_list; + for (; type_entry; type_entry = type_entry->next) + { + /* in old style typelibs all types are public */ + add_type_typeinfo(typelib, type_entry->type); + } + break; + } + + case STMT_MODULE: + add_module_typeinfo(typelib, stmt->u.type); + break; + + case STMT_TYPE: + case STMT_TYPEREF: + { + type_t *type = stmt->u.type; + add_type_typeinfo(typelib, type); + break; + } + + default: + error("add_statement: unhandled statement type %d\n", stmt->type); + break; + } +} + +static void sltg_write_header(struct sltg_typelib *sltg, int *library_block_start) +{ + char pad[0x40]; + struct sltg_header + { + int magic; + short n_file_blocks; + short res06; + short size_of_index; + short first_blk; + GUID uuid; + int res1c; + int res20; + } header; + struct sltg_block_entry + { + int length; + short index_string; + short next; + } entry; + struct sltg_block *block; + int i; + + header.magic = 0x47544c53; + header.n_file_blocks = sltg->n_file_blocks + 1; + header.res06 = 9; + header.size_of_index = sltg->index.size; + header.first_blk = 1; + header.uuid = sltg_library_guid; + header.res1c = 0x00000044; + header.res20 = 0xffff0000; + + put_data(&header, sizeof(header)); + + block = sltg->blocks; + for (i = 0; i < sltg->n_file_blocks - 1; i++) + { + assert(block->next != NULL); + + entry.length = block->length; + entry.index_string = block->index_string; + entry.next = header.first_blk + i + 1; + chat("sltg_write_header: writing block entry %d: length %#x, index_string %#x, next %#x\n", + i, entry.length, entry.index_string, entry.next); + put_data(&entry, sizeof(entry)); + + block = block->next; + } + + assert(block->next == NULL); + + /* library block length includes helpstrings and name table */ + entry.length = block->length + 0x40 + 2 + sltg->typeinfo_size + 4 + 6 + 12 + 0x200 + sltg->name_table.size + 12; + entry.index_string = block->index_string; + entry.next = 0; + chat("sltg_write_header: writing library block entry %d: length %#x, index_string %#x, next %#x\n", + i, entry.length, entry.index_string, entry.next); + put_data(&entry, sizeof(entry)); + + chat("sltg_write_header: writing index: %d bytes\n", sltg->index.size); + put_data(sltg->index.data, sltg->index.size); + memset(pad, 0, 9); + put_data(pad, 9); + + block = sltg->blocks; + for (i = 0; i < sltg->n_file_blocks - 1; i++) + { + chat("sltg_write_header: writing block %d: %d bytes\n", i, block->length); + + put_data(block->data, block->length); + block = block->next; + } + + assert(block->next == NULL); + + /* library block */ + chat("library_block_start = %#lx\n", (SIZE_T)output_buffer_pos); + *library_block_start = output_buffer_pos; + chat("sltg_write_header: writing library block %d: %d bytes\n", i, block->length); + put_data(block->data, block->length); + + chat("sltg_write_header: writing pad 0x40 bytes\n"); + memset(pad, 0xff, 0x40); + put_data(pad, 0x40); +} + +static void sltg_write_typeinfo(struct sltg_typelib *typelib) +{ + int i; + struct sltg_block *block; + short count = typelib->typeinfo_count; + + put_data(&count, sizeof(count)); + + block = typelib->typeinfo; + for (i = 0; i < typelib->typeinfo_count; i++) + { + chat("sltg_write_typeinfo: writing block %d: %d bytes\n", i, block->length); + + put_data(block->data, block->length); + block = block->next; + } + assert(block == NULL); +} + +static void sltg_write_helpstrings(struct sltg_typelib *typelib) +{ + static const char dummy[6]; + + chat("sltg_write_helpstrings: writing dummy 6 bytes\n"); + + put_data(dummy, sizeof(dummy)); +} + +static void sltg_write_nametable(struct sltg_typelib *typelib) +{ + static const short dummy[6] = { 0xffff,1,2,0xff00,0xffff,0xffff }; + char pad[0x200]; + + chat("sltg_write_nametable: writing 12+0x200+%d bytes\n", typelib->name_table.size); + + put_data(dummy, sizeof(dummy)); + memset(pad, 0xff, 0x200); + put_data(pad, 0x200); + put_data(&typelib->name_table.size, sizeof(typelib->name_table.size)); + put_data(typelib->name_table.data, typelib->name_table.size); +} + +static void sltg_write_remainder(void) +{ + static const short dummy1[] = { 1,0xfffe,0x0a03,0,0xffff,0xffff }; + static const short dummy2[] = { 0xffff,0xffff,0x0200,0,0,0 }; + static const char dummy3[] = { 0xf4,0x39,0xb2,0x71,0,0,0,0,0,0,0,0,0,0,0,0 }; + static const char TYPELIB[] = { 8,0,0,0,'T','Y','P','E','L','I','B',0 }; + int pad; + + pad = 0x01ffff01; + put_data(&pad, sizeof(pad)); + pad = 0; + put_data(&pad, sizeof(pad)); + + put_data(dummy1, sizeof(dummy1)); + + put_data(&sltg_library_guid, sizeof(sltg_library_guid)); + + put_data(TYPELIB, sizeof(TYPELIB)); + + put_data(dummy2, sizeof(dummy2)); + put_data(dummy3, sizeof(dummy3)); +} + +static void save_all_changes(struct sltg_typelib *typelib) +{ + int library_block_start; + int *name_table_offset; + + sltg_write_header(typelib, &library_block_start); + sltg_write_typeinfo(typelib); + + name_table_offset = (int *)(output_buffer + output_buffer_pos); + chat("name_table_offset = %#lx\n", (SIZE_T)output_buffer_pos); + put_data(&library_block_start, sizeof(library_block_start)); + + sltg_write_helpstrings(typelib); + + *name_table_offset = output_buffer_pos - library_block_start; + chat("*name_table_offset = %#x\n", *name_table_offset); + + sltg_write_nametable(typelib); + sltg_write_remainder(); + + if (strendswith(typelib_name, ".res")) /* create a binary resource file */ + { + char typelib_id[13] = "#1"; + + expr_t *expr = get_attrp(typelib->typelib->attrs, ATTR_ID); + if (expr) + sprintf(typelib_id, "#%d", expr->cval); + add_output_to_resources("TYPELIB", typelib_id); + output_typelib_regscript(typelib->typelib); + } + else flush_output_buffer(typelib_name); +} + +int create_sltg_typelib(typelib_t *typelib) +{ + struct sltg_typelib sltg; + const statement_t *stmt; + void *library_block; + int library_block_size, library_block_index; + + sltg.typelib = typelib; + sltg.typeinfo_count = 0; + sltg.typeinfo_size = 0; + sltg.typeinfo = NULL; + sltg.blocks = NULL; + sltg.n_file_blocks = 0; + sltg.first_block = 1; + + init_index(&sltg.index); + init_name_table(&sltg); + init_library(&sltg); + + library_block = create_library_block(&sltg, &library_block_size, &library_block_index); + + if (typelib->stmts) + LIST_FOR_EACH_ENTRY(stmt, typelib->stmts, const statement_t, entry) + add_statement(&sltg, stmt); + + add_block_index(&sltg, library_block, library_block_size, library_block_index); + + save_all_changes(&sltg); + + return 1; +}