| /* |
| * 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 <stdlib.h> |
| #include <string.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <ctype.h> |
| #include <time.h> |
| |
| #include "widl.h" |
| #include "windef.h" |
| #include "winbase.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_typelib |
| { |
| typelib_t *typelib; |
| struct sltg_data index; |
| struct sltg_data name_table; |
| struct sltg_library library; |
| struct sltg_block *blocks; |
| int block_count; |
| int first_block; |
| short typeinfo_count; |
| int typeinfo_size; |
| struct sltg_block *typeinfo; |
| }; |
| |
| struct sltg_hrefmap |
| { |
| int href_count; |
| int *href; |
| }; |
| |
| #pragma pack(push,1) |
| 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 & 0x20 */ |
| }; |
| |
| 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 */ |
| char res02[0x42]; /* 0xff... */ |
| 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{<guid>}#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; |
| }; |
| |
| #pragma pack(pop) |
| |
| 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 = 0; |
| data->data = NULL; |
| } |
| |
| 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 = index->allocated ? max(index->allocated * 2, new_size) : 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_data *name_table, const char *name) |
| { |
| int name_offset = name_table->size; |
| int new_size = 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 > name_table->allocated) |
| { |
| name_table->allocated = name_table->allocated ? max(name_table->allocated * 2, new_size) : new_size; |
| name_table->data = xrealloc(name_table->data, name_table->allocated); |
| } |
| |
| memset(name_table->data + name_table->size, 0xff, 8); |
| strcpy(name_table->data + name_table->size + 8, name); |
| name_table->size = new_size; |
| name_table->data[name_table->size - 1] = 0; /* clear alignment */ |
| |
| return name_offset; |
| } |
| |
| static void init_name_table(struct sltg_data *name_table) |
| { |
| init_sltg_data(name_table); |
| } |
| |
| static void init_library(struct sltg_typelib *sltg) |
| { |
| const attr_t *attr; |
| |
| sltg->library.name = add_name(&sltg->name_table, sltg->typelib->name); |
| sltg->library.helpstring = NULL; |
| sltg->library.helpcontext = 0; |
| sltg->library.syskind = 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: |
| { |
| const version_t *version = attr->u.pval; |
| unsigned short major = version ? version->major : 0, minor = version ? version->minor : 0; |
| |
| sltg->library.version = (minor << 16) | major; |
| 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 length, int index) |
| { |
| sltg->blocks = xrealloc(sltg->blocks, sizeof(sltg->blocks[0]) * (sltg->block_count + 1)); |
| sltg->blocks[sltg->block_count].length = length; |
| sltg->blocks[sltg->block_count].data = data; |
| sltg->blocks[sltg->block_count].index_string = index; |
| sltg->block_count++; |
| } |
| |
| 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] = "AAAAAAAAAA"; |
| 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 length, const char *name) |
| { |
| chat("sltg_add_typeinfo: %p,%d,%s\n", data, length, name); |
| |
| sltg->typeinfo = xrealloc(sltg->typeinfo, sizeof(sltg->typeinfo[0]) * (sltg->typeinfo_count + 1)); |
| sltg->typeinfo[sltg->typeinfo_count].length = length; |
| sltg->typeinfo[sltg->typeinfo_count].data = data; |
| sltg->typeinfo[sltg->typeinfo_count].index_string = 0; |
| sltg->typeinfo_count++; |
| sltg->typeinfo_size += length; |
| } |
| |
| 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, short kind) |
| { |
| struct sltg_data block; |
| const char *index_name, *other_name; |
| short val; |
| void *p; |
| int 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; |
| |
| init_sltg_data(&block); |
| |
| val = strlen(index_name); |
| append_data(&block, &val, sizeof(val)); |
| append_data(&block, index_name, val); |
| val = strlen(other_name); |
| append_data(&block, &val, sizeof(val)); |
| append_data(&block, other_name, val); |
| val = -1; /* res1a */ |
| append_data(&block, &val, sizeof(val)); |
| val = add_name(&typelib->name_table, type->name); /* name offset */ |
| append_data(&block, &val, sizeof(val)); |
| val = 0; /* FIXME: helpstring */ |
| append_data(&block, &val, sizeof(val)); |
| val = -1; /* res20 */ |
| append_data(&block, &val, sizeof(val)); |
| append_data(&block, &helpcontext, sizeof(helpcontext)); |
| val = -1; /* res26 */ |
| append_data(&block, &val, sizeof(val)); |
| append_data(&block, &guid, sizeof(guid)); |
| append_data(&block, &kind, sizeof(kind)); |
| |
| sltg_add_typeinfo(typelib, block.data, block.size, index_name); |
| |
| return index_name; |
| } |
| |
| static void init_typeinfo(struct sltg_typeinfo_header *ti, const type_t *type, short kind, |
| const struct sltg_hrefmap *hrefmap) |
| { |
| unsigned short major, minor; |
| |
| get_version( type->attrs, &major, &minor ); |
| |
| ti->magic = 0x0501; |
| ti->href_offset = -1; |
| ti->res06 = -1; |
| ti->member_offset = sizeof(*ti); |
| ti->res0e = -1; |
| ti->version = minor << 16 | major; |
| ti->res16 = 0xfffe0000; |
| ti->misc.unknown1 = 0x02; |
| ti->misc.flags = 0; /* FIXME */ |
| ti->misc.unknown2 = 0x02; |
| ti->misc.typekind = kind; |
| ti->res1e = 0; |
| |
| 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++) |
| { |
| snprintf(name, sizeof(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 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; |
| memset(hrefinfo.res02, 0xff, sizeof(hrefinfo.res02)); |
| 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; |
| |
| snprintf(name, sizeof(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_UI2: |
| case VT_I2: |
| case VT_BOOL: |
| return 2; |
| |
| case VT_INT: |
| case VT_UINT: |
| 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 4; |
| |
| case VT_VOID: |
| return 0; |
| |
| case VT_VARIANT: |
| return 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; |
| int 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 = 0; |
| |
| 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 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 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->block_count; |
| |
| 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->name_table, 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.integer.value; |
| 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) |
| flags |= in ? 0x8000 : 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, 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_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->name_table, func->name) : -1; |
| func_desc.dispid = dispid; |
| func_desc.helpcontext = helpcontext; |
| func_desc.helpstring = (helpstring && base_offset != -1) ? add_name(&typelib->name_table, 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->name_table, 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->block_count; |
| |
| /* 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: |
| { |
| typeref_t *ref; |
| |
| if (!stmt->u.type_list) |
| break; |
| |
| LIST_FOR_EACH_ENTRY(ref, stmt->u.type_list, typeref_t, entry) |
| { |
| /* in old style typelibs all types are public */ |
| add_type_typeinfo(typelib, ref->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 block_count; |
| 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; |
| int i; |
| |
| header.magic = 0x47544c53; |
| header.block_count = sltg->block_count + 1; /* 1-based */ |
| header.res06 = 9; |
| header.size_of_index = sltg->index.size; |
| header.first_blk = 1; /* 1-based */ |
| header.uuid = sltg_library_guid; |
| header.res1c = 0x00000044; |
| header.res20 = 0xffff0000; |
| |
| put_data(&header, sizeof(header)); |
| |
| /* library block is written separately */ |
| for (i = 0; i < sltg->block_count - 1; i++) |
| { |
| entry.length = sltg->blocks[i].length; |
| entry.index_string = sltg->blocks[i].index_string; |
| entry.next = header.first_blk + i + 1; /* point to next block */ |
| 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)); |
| } |
| |
| /* library block length includes helpstrings and name table */ |
| entry.length = sltg->blocks[sltg->block_count - 1].length + 0x40 /* pad after library block */ + |
| sizeof(sltg->typeinfo_count) + sltg->typeinfo_size + 4 /* library block size */ + 6 /* dummy help strings */ + |
| 12 /* name table header */ + 0x200 /* name table hash */ + |
| sizeof(sltg->name_table.size) + sltg->name_table.size + |
| 4 /* 0x01ffff01 */ + 4 /* 0 */; |
| entry.index_string = sltg->blocks[sltg->block_count - 1].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); |
| |
| /* library block is written separately */ |
| for (i = 0; i < sltg->block_count - 1; i++) |
| { |
| chat("sltg_write_header: writing block %d: %d bytes\n", i, sltg->blocks[i].length); |
| put_data(sltg->blocks[i].data, sltg->blocks[i].length); |
| } |
| |
| /* library block */ |
| chat("library_block_start = %#x\n", (int)output_buffer_pos); |
| *library_block_start = output_buffer_pos; |
| chat("sltg_write_header: writing library block %d: %d bytes\n", i, sltg->blocks[i].length); |
| put_data(sltg->blocks[sltg->block_count - 1].data, sltg->blocks[sltg->block_count - 1].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) |
| { |
| short i; |
| |
| put_data(&typelib->typeinfo_count, sizeof(typelib->typeinfo_count)); |
| |
| for (i = 0; i < typelib->typeinfo_count; i++) |
| { |
| chat("sltg_write_typeinfo: writing block %d: %d bytes\n", i, typelib->typeinfo[i].length); |
| put_data(typelib->typeinfo[i].data, typelib->typeinfo[i].length); |
| } |
| } |
| |
| 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 = %#x\n", (int)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) |
| snprintf(typelib_id, sizeof(typelib_id), "#%d", expr->cval); |
| add_output_to_resources("TYPELIB", typelib_id); |
| if (strendswith(typelib_name, "_t.res")) /* add typelib registration */ |
| 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; |
| |
| if (pointer_size != 4) |
| error("Only 32-bit platform is supported\n"); |
| |
| sltg.typelib = typelib; |
| sltg.typeinfo_count = 0; |
| sltg.typeinfo_size = 0; |
| sltg.typeinfo = NULL; |
| sltg.blocks = NULL; |
| sltg.block_count = 0; |
| sltg.first_block = 1; |
| |
| init_index(&sltg.index); |
| init_name_table(&sltg.name_table); |
| 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; |
| } |