widl: Add support for recursive type references to SLTG typelib generator.
[wine.git] / tools / widl / write_sltg.c
blob220fd933704415dc0180e8a608801cc482ffe9bb
1 /*
2 * Typelib (SLTG) generation
4 * Copyright 2015,2016 Dmitry Timoshkov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <time.h>
30 #include "widl.h"
31 #include "windef.h"
32 #include "winbase.h"
34 #include "typelib.h"
35 #include "typelib_struct.h"
36 #include "utils.h"
37 #include "header.h"
38 #include "typetree.h"
40 static const GUID sltg_library_guid = { 0x204ff,0,0,{ 0xc0,0,0,0,0,0,0,0x46 } };
42 struct sltg_data
44 int size, allocated;
45 char *data;
48 struct sltg_library
50 short name;
51 char *helpstring;
52 char *helpfile;
53 int helpcontext;
54 int syskind;
55 LCID lcid;
56 int libflags;
57 int version;
58 GUID uuid;
61 struct sltg_block
63 int length;
64 int index_string;
65 void *data;
68 struct sltg_typelib
70 typelib_t *typelib;
71 struct sltg_data index;
72 struct sltg_data name_table;
73 struct sltg_library library;
74 struct sltg_block *blocks;
75 int block_count;
76 int first_block;
77 short typeinfo_count;
78 int typeinfo_size;
79 struct sltg_block *typeinfo;
82 struct sltg_hrefmap
84 int href_count;
85 int *href;
88 #include "pshpack1.h"
89 struct sltg_typeinfo_header
91 short magic;
92 int href_offset;
93 int res06;
94 int member_offset;
95 int res0e;
96 int version;
97 int res16;
98 struct
100 unsigned unknown1 : 3;
101 unsigned flags : 13;
102 unsigned unknown2 : 8;
103 unsigned typekind : 8;
104 } misc;
105 int res1e;
108 struct sltg_member_header
110 short res00;
111 short res02;
112 char res04;
113 int extra;
116 struct sltg_variable
118 char magic; /* 0x0a */
119 char flags;
120 short next;
121 short name;
122 short byte_offs; /* pos in struct, or offset to const type or const data (if flags & 0x08) */
123 short type; /* if flags & 0x02 this is the type, else offset to type */
124 int memid;
125 short helpcontext;
126 short helpstring;
127 short varflags; /* only present if magic & 0x20 */
130 struct sltg_tail
132 short cFuncs;
133 short cVars;
134 short cImplTypes;
135 short res06; /* always 0000 */
136 short funcs_off; /* offset to functions (starting from the member header) */
137 short vars_off; /* offset to vars (starting from the member header) */
138 short impls_off; /* offset to implemented types (starting from the member header) */
139 short funcs_bytes; /* bytes used by function data */
140 short vars_bytes; /* bytes used by var data */
141 short impls_bytes; /* bytes used by implemented type data */
142 short tdescalias_vt; /* for TKIND_ALIAS */
143 short res16; /* always ffff */
144 short res18; /* always 0000 */
145 short res1a; /* always 0000 */
146 short simple_alias; /* tdescalias_vt is a vt rather than an offset? */
147 short res1e; /* always 0000 */
148 short cbSizeInstance;
149 short cbAlignment;
150 short res24; /* always ffff */
151 short res26; /* always ffff */
152 short cbSizeVft;
153 short res2a; /* always ffff */
154 short res2c; /* always ffff */
155 short res2e; /* always ffff */
156 short res30; /* always ffff */
157 short res32; /* unknown */
158 short type_bytes; /* bytes used by type descriptions */
161 struct sltg_hrefinfo
163 char magic; /* 0xdf */
164 char res01; /* 0x00 */
165 char res02[0x42]; /* 0xff... */
166 int number; /* this is 8 times the number of refs */
167 /* Now we have number bytes (8 for each ref) of SLTG_UnknownRefInfo */
169 short res50;/* 0xffff */
170 char res52; /* 0x01 */
171 int res53; /* 0x00000000 */
172 /* Now we have number/8 SLTG_Names (first WORD is no of bytes in the ascii
173 * string). Strings look like "*\Rxxxx*#n". If xxxx == ffff then the
174 * ref refers to the nth type listed in this library (0 based). Else
175 * the xxxx (which maybe fewer than 4 digits) is the offset into the name
176 * table to a string "*\G{<guid>}#1.0#0#C:\WINNT\System32\stdole32.tlb#"
177 * The guid is the typelib guid; the ref again refers to the nth type of
178 * the imported typelib.
181 char resxx; /* 0xdf */
184 #include "poppack.h"
186 static void add_structure_typeinfo(struct sltg_typelib *typelib, type_t *type);
187 static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *type);
188 static void add_enum_typeinfo(struct sltg_typelib *typelib, type_t *type);
189 static void add_union_typeinfo(struct sltg_typelib *typelib, type_t *type);
190 static void add_coclass_typeinfo(struct sltg_typelib *typelib, type_t *type);
192 static void init_sltg_data(struct sltg_data *data)
194 data->size = 0;
195 data->allocated = 0;
196 data->data = NULL;
199 static int add_index(struct sltg_data *index, const char *name)
201 int name_offset = index->size;
202 int new_size = index->size + strlen(name) + 1;
204 chat("add_index: name_offset %d, \"%s\"\n", name_offset, name);
206 if (new_size > index->allocated)
208 index->allocated = index->allocated ? max(index->allocated * 2, new_size) : new_size;
209 index->data = xrealloc(index->data, index->allocated);
212 strcpy(index->data + index->size, name);
213 index->size = new_size;
215 return name_offset;
218 static void init_index(struct sltg_data *index)
220 static const char compobj[] = { 1,'C','o','m','p','O','b','j',0 };
222 init_sltg_data(index);
224 add_index(index, compobj);
227 static int add_name(struct sltg_data *name_table, const char *name)
229 int name_offset = name_table->size;
230 int new_size = name_table->size + strlen(name) + 1 + 8;
231 int aligned_size;
233 chat("add_name: %s\n", name);
235 aligned_size = (new_size + 0x1f) & ~0x1f;
236 if (aligned_size - new_size < 4)
237 new_size = aligned_size;
238 else
239 new_size = (new_size + 1) & ~1;
241 if (new_size > name_table->allocated)
243 name_table->allocated = name_table->allocated ? max(name_table->allocated * 2, new_size) : new_size;
244 name_table->data = xrealloc(name_table->data, name_table->allocated);
247 memset(name_table->data + name_table->size, 0xff, 8);
248 strcpy(name_table->data + name_table->size + 8, name);
249 name_table->size = new_size;
250 name_table->data[name_table->size - 1] = 0; /* clear alignment */
252 return name_offset;
255 static void init_name_table(struct sltg_data *name_table)
257 init_sltg_data(name_table);
260 static void init_library(struct sltg_typelib *sltg)
262 const attr_t *attr;
264 sltg->library.name = add_name(&sltg->name_table, sltg->typelib->name);
265 sltg->library.helpstring = NULL;
266 sltg->library.helpcontext = 0;
267 sltg->library.syskind = SYS_WIN32;
268 sltg->library.lcid = 0x0409;
269 sltg->library.libflags = 0;
270 sltg->library.version = 0;
271 sltg->library.helpfile = NULL;
272 memset(&sltg->library.uuid, 0, sizeof(sltg->library.uuid));
274 if (!sltg->typelib->attrs) return;
276 LIST_FOR_EACH_ENTRY(attr, sltg->typelib->attrs, const attr_t, entry)
278 const expr_t *expr;
280 switch (attr->type)
282 case ATTR_VERSION:
283 sltg->library.version = attr->u.ival;
284 break;
285 case ATTR_HELPSTRING:
286 sltg->library.helpstring = attr->u.pval;
287 break;
288 case ATTR_HELPFILE:
289 sltg->library.helpfile = attr->u.pval;
290 break;
291 case ATTR_UUID:
292 sltg->library.uuid = *(GUID *)attr->u.pval;
293 break;
294 case ATTR_HELPCONTEXT:
295 expr = attr->u.pval;
296 sltg->library.helpcontext = expr->cval;
297 break;
298 case ATTR_LIBLCID:
299 expr = attr->u.pval;
300 sltg->library.lcid = expr->cval;
301 break;
302 case ATTR_CONTROL:
303 sltg->library.libflags |= 0x02; /* LIBFLAG_FCONTROL */
304 break;
305 case ATTR_HIDDEN:
306 sltg->library.libflags |= 0x04; /* LIBFLAG_FHIDDEN */
307 break;
308 case ATTR_RESTRICTED:
309 sltg->library.libflags |= 0x01; /* LIBFLAG_FRESTRICTED */
310 break;
311 default:
312 break;
317 static void add_block(struct sltg_typelib *sltg, void *data, int length, const char *name)
319 chat("add_block: %p,%d,\"%s\"\n", data, length, name);
321 sltg->blocks = xrealloc(sltg->blocks, sizeof(sltg->blocks[0]) * (sltg->block_count + 1));
322 sltg->blocks[sltg->block_count].length = length;
323 sltg->blocks[sltg->block_count].data = data;
324 sltg->blocks[sltg->block_count].index_string = add_index(&sltg->index, name);
325 sltg->block_count++;
328 static void add_library_block(struct sltg_typelib *typelib)
330 void *block;
331 short *p;
332 int size;
334 size = sizeof(short) * 9 + sizeof(int) * 3 + sizeof(GUID);
335 if (typelib->library.helpstring) size += strlen(typelib->library.helpstring);
336 if (typelib->library.helpfile) size += strlen(typelib->library.helpfile);
338 block = xmalloc(size);
339 p = block;
340 *p++ = 0x51cc; /* magic */
341 *p++ = 3; /* res02 */
342 *p++ = typelib->library.name;
343 *p++ = 0xffff; /* res06 */
344 if (typelib->library.helpstring)
346 *p++ = strlen(typelib->library.helpstring);
347 strcpy((char *)p, typelib->library.helpstring);
348 p = (short *)((char *)p + strlen(typelib->library.helpstring));
350 else
351 *p++ = 0xffff;
352 if (typelib->library.helpfile)
354 *p++ = strlen(typelib->library.helpfile);
355 strcpy((char *)p, typelib->library.helpfile);
356 p = (short *)((char *)p + strlen(typelib->library.helpfile));
358 else
359 *p++ = 0xffff;
360 *(int *)p = typelib->library.helpcontext;
361 p += 2;
362 *p++ = typelib->library.syskind;
363 *p++ = typelib->library.lcid;
364 *(int *)p = 0; /* res12 */
365 p += 2;
366 *p++ = typelib->library.libflags;
367 *(int *)p = typelib->library.version;
368 p += 2;
369 *(GUID *)p = typelib->library.uuid;
371 add_block(typelib, block, size, "dir");
374 static const char *new_index_name(void)
376 static char name[11] = "AAAAAAAAAA";
377 static int pos = 0;
378 char *new_name;
380 if (name[pos] == 'Z')
382 pos++;
383 if (pos > 9)
384 error("too many index names\n");
387 name[pos]++;
389 new_name = xmalloc(sizeof(name));
390 strcpy(new_name, name);
391 return new_name;
394 static void sltg_add_typeinfo(struct sltg_typelib *sltg, void *data, int length, const char *name)
396 chat("sltg_add_typeinfo: %p,%d,%s\n", data, length, name);
398 sltg->typeinfo = xrealloc(sltg->typeinfo, sizeof(sltg->typeinfo[0]) * (sltg->typeinfo_count + 1));
399 sltg->typeinfo[sltg->typeinfo_count].length = length;
400 sltg->typeinfo[sltg->typeinfo_count].data = data;
401 sltg->typeinfo[sltg->typeinfo_count].index_string = 0;
402 sltg->typeinfo_count++;
403 sltg->typeinfo_size += length;
406 static void append_data(struct sltg_data *block, const void *data, int size)
408 int new_size = block->size + size;
410 if (new_size > block->allocated)
412 block->allocated = max(block->allocated * 2, new_size);
413 block->data = xrealloc(block->data, block->allocated);
416 memcpy(block->data + block->size, data, size);
417 block->size = new_size;
420 static void add_module_typeinfo(struct sltg_typelib *typelib, type_t *type)
422 error("add_module_typeinfo: %s not implemented\n", type->name);
425 static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *type)
427 error("add_interface_typeinfo: %s not implemented\n", type->name);
430 static const char *add_typeinfo_block(struct sltg_typelib *typelib, const type_t *type, short kind)
432 struct sltg_data block;
433 const char *index_name, *other_name;
434 short val;
435 void *p;
436 int helpcontext = 0;
437 GUID guid = { 0 };
438 const expr_t *expr;
440 index_name = new_index_name();
441 other_name = new_index_name();
443 expr = get_attrp(type->attrs, ATTR_HELPCONTEXT);
444 if (expr) helpcontext = expr->cval;
446 p = get_attrp(type->attrs, ATTR_UUID);
447 if (p) guid = *(GUID *)p;
449 init_sltg_data(&block);
451 val = strlen(index_name);
452 append_data(&block, &val, sizeof(val));
453 append_data(&block, index_name, val);
454 val = strlen(other_name);
455 append_data(&block, &val, sizeof(val));
456 append_data(&block, other_name, val);
457 val = -1; /* res1a */
458 append_data(&block, &val, sizeof(val));
459 val = add_name(&typelib->name_table, type->name); /* name offset */
460 append_data(&block, &val, sizeof(val));
461 val = 0; /* FIXME: helpstring */
462 append_data(&block, &val, sizeof(val));
463 val = -1; /* res20 */
464 append_data(&block, &val, sizeof(val));
465 append_data(&block, &helpcontext, sizeof(helpcontext));
466 val = -1; /* res26 */
467 append_data(&block, &val, sizeof(val));
468 append_data(&block, &guid, sizeof(guid));
469 append_data(&block, &kind, sizeof(kind));
471 sltg_add_typeinfo(typelib, block.data, block.size, index_name);
473 return index_name;
476 static void init_typeinfo(struct sltg_typeinfo_header *ti, const type_t *type, short kind,
477 const struct sltg_hrefmap *hrefmap)
479 ti->magic = 0x0501;
480 ti->href_offset = -1;
481 ti->res06 = -1;
482 ti->member_offset = sizeof(*ti);
483 ti->res0e = -1;
484 ti->version = get_attrv(type->attrs, ATTR_VERSION);
485 ti->res16 = 0xfffe0000;
486 ti->misc.unknown1 = 0x02;
487 ti->misc.flags = 0; /* FIXME */
488 ti->misc.unknown2 = 0x02;
489 ti->misc.typekind = kind;
490 ti->res1e = -1;
492 if (hrefmap->href_count)
494 char name[64];
495 int i, hrefinfo_size;
497 hrefinfo_size = sizeof(struct sltg_hrefinfo);
499 for (i = 0; i < hrefmap->href_count; i++)
501 sprintf(name, "*\\Rffff*#%x", hrefmap->href[i]);
502 hrefinfo_size += 8 + 2 + strlen(name);
505 ti->href_offset = ti->member_offset;
506 ti->member_offset += hrefinfo_size;
510 static void write_hrefmap(struct sltg_data *data, const struct sltg_hrefmap *hrefmap)
512 struct sltg_hrefinfo hrefinfo;
513 char name[64];
514 int i;
516 if (!hrefmap->href_count) return;
518 hrefinfo.magic = 0xdf;
519 hrefinfo.res01 = 0;
520 memset(hrefinfo.res02, 0xff, sizeof(hrefinfo.res02));
521 hrefinfo.number = hrefmap->href_count * 8;
522 hrefinfo.res50 = -1;
523 hrefinfo.res52 = 1;
524 hrefinfo.res53 = 0;
525 hrefinfo.resxx = 0xdf;
527 append_data(data, &hrefinfo, offsetof(struct sltg_hrefinfo, res50));
529 for (i = 0; i < hrefmap->href_count; i++)
530 append_data(data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8);
532 append_data(data, &hrefinfo.res50, 7);
534 for (i = 0; i < hrefmap->href_count; i++)
536 short len;
538 sprintf(name, "*\\Rffff*#%x", hrefmap->href[i]);
539 len = strlen(name);
541 append_data(data, &len, sizeof(len));
542 append_data(data, name, len);
545 append_data(data, &hrefinfo.resxx, sizeof(hrefinfo.resxx));
548 static void dump_var_desc(const char *data, int size)
550 const unsigned char *p = (const unsigned char *)data;
551 int i;
553 if (!(debuglevel & (DEBUGLEVEL_TRACE | DEBUGLEVEL_CHAT))) return;
555 chat("dump_var_desc: size %d bytes\n", size);
557 for (i = 0; i < size; i++)
558 fprintf(stderr, " %02x", *p++);
560 fprintf(stderr, "\n");
563 static int get_element_size(type_t *type)
565 int vt = get_type_vt(type);
567 switch (vt)
569 case VT_I1:
570 case VT_UI1:
571 return 1;
573 case VT_UI2:
574 case VT_I2:
575 case VT_BOOL:
576 return 2;
578 case VT_INT:
579 case VT_UINT:
580 case VT_I4:
581 case VT_UI4:
582 case VT_R4:
583 case VT_ERROR:
584 case VT_HRESULT:
585 return 4;
587 case VT_R8:
588 case VT_I8:
589 case VT_UI8:
590 case VT_CY:
591 case VT_DATE:
592 return 8;
594 case VT_DECIMAL:
595 return 16;
597 case VT_PTR:
598 case VT_UNKNOWN:
599 case VT_DISPATCH:
600 case VT_BSTR:
601 case VT_LPSTR:
602 case VT_LPWSTR:
603 return 4;
605 case VT_VOID:
606 return 0;
608 case VT_VARIANT:
609 return 16;
611 case VT_USERDEFINED:
612 return 0;
614 default:
615 error("get_element_size: unrecognized vt %d\n", vt);
616 break;
619 return 0;
622 static int local_href(struct sltg_hrefmap *hrefmap, int typelib_href)
624 int i, href = -1;
626 for (i = 0; i < hrefmap->href_count; i++)
628 if (hrefmap->href[i] == typelib_href)
630 href = i;
631 break;
635 if (href == -1)
637 href = hrefmap->href_count;
639 if (hrefmap->href)
640 hrefmap->href = xrealloc(hrefmap->href, sizeof(*hrefmap->href) * (hrefmap->href_count + 1));
641 else
642 hrefmap->href = xmalloc(sizeof(*hrefmap->href));
644 hrefmap->href[hrefmap->href_count] = typelib_href;
645 hrefmap->href_count++;
648 chat("typelib href %d mapped to local href %d\n", typelib_href, href);
650 return href << 2;
653 static short write_var_desc(struct sltg_typelib *typelib, struct sltg_data *data, type_t *type, short flags,
654 short base_offset, int *size_instance, struct sltg_hrefmap *hrefmap)
656 short vt, vt_flags, desc_offset;
658 chat("write_var_desc: type %p, type->name %s\n",
659 type, type->name ? type->name : "NULL");
661 if (is_array(type) && !type_array_is_decl_as_ptr(type))
663 int num_dims, elements, array_start, size, array_size;
664 type_t *atype;
665 struct
667 short cDims;
668 short fFeatures;
669 int cbElements;
670 int cLocks;
671 int pvData;
672 int bound[2];
673 } *array;
674 int *bound;
675 short vt_off[2];
677 elements = 1;
678 num_dims = 0;
680 atype = type;
682 while (is_array(atype) && !type_array_is_decl_as_ptr(atype))
684 num_dims++;
685 elements *= type_array_get_dim(atype);
687 atype = type_array_get_element_type(atype);
690 chat("write_var_desc: VT_CARRAY: %d dimensions, %d elements\n", num_dims, elements);
692 array_start = data->size;
694 size = sizeof(*array) + (num_dims - 1) * 8 /* sizeof(SAFEARRAYBOUND) */;
695 array = xmalloc(size);
697 array->cDims = num_dims;
698 array->fFeatures = 0x0004; /* FADF_EMBEDDED */
699 array->cbElements = get_element_size(atype);
700 array->cLocks = 0;
701 array->pvData = 0;
703 bound = array->bound;
705 array_size = array->cbElements;
706 atype = type;
708 while (is_array(atype) && !type_array_is_decl_as_ptr(atype))
710 bound[0] = type_array_get_dim(atype);
711 array_size *= bound[0];
712 bound[1] = 0;
713 bound += 2;
715 atype = type_array_get_element_type(atype);
718 *size_instance += array_size;
719 size_instance = NULL; /* don't account for element size */
721 append_data(data, array, size);
723 desc_offset = data->size;
725 vt_off[0] = VT_CARRAY;
726 vt_off[1] = array_start + base_offset;
727 append_data(data, vt_off, sizeof(vt_off));
729 /* fall through to write array element description */
730 type = atype;
732 else
733 desc_offset = data->size;
735 vt = get_type_vt(type);
737 if (vt == VT_PTR)
739 type_t *ref = is_ptr(type) ? type_pointer_get_ref_type(type) : type_array_get_element_type(type);
741 if (is_ptr(ref))
743 chat("write_var_desc: vt VT_PTR | 0x0400\n");
744 vt = VT_PTR | 0x0400;
745 append_data(data, &vt, sizeof(vt));
746 write_var_desc(typelib, data, ref, 0, base_offset, size_instance, hrefmap);
748 else
749 write_var_desc(typelib, data, ref, 0x0e00, base_offset, size_instance, hrefmap);
750 return desc_offset;
753 chat("write_var_desc: vt %d, flags %04x\n", vt, flags);
755 vt_flags = vt | flags;
756 append_data(data, &vt_flags, sizeof(vt_flags));
758 if (vt == VT_USERDEFINED)
760 short href;
762 while (type->typelib_idx < 0 && type_is_alias(type))
763 type = type_alias_get_aliasee_type(type);
765 chat("write_var_desc: VT_USERDEFINED, type %p, name %s, real type %d, href %d\n",
766 type, type->name, type_get_type(type), type->typelib_idx);
768 if (type->typelib_idx == -1)
770 chat("write_var_desc: trying to ref not added type\n");
772 switch (type_get_type(type))
774 case TYPE_STRUCT:
775 add_structure_typeinfo(typelib, type);
776 break;
777 case TYPE_INTERFACE:
778 add_interface_typeinfo(typelib, type);
779 break;
780 case TYPE_ENUM:
781 add_enum_typeinfo(typelib, type);
782 break;
783 case TYPE_UNION:
784 add_union_typeinfo(typelib, type);
785 break;
786 case TYPE_COCLASS:
787 add_coclass_typeinfo(typelib, type);
788 break;
789 default:
790 error("write_var_desc: VT_USERDEFINED - unhandled type %d\n",
791 type_get_type(type));
795 if (type->typelib_idx == -1)
796 error("write_var_desc: trying to ref not added type\n");
798 href = local_href(hrefmap, type->typelib_idx);
799 chat("write_var_desc: VT_USERDEFINED, local href %d\n", href);
801 append_data(data, &href, sizeof(href));
804 if (size_instance)
805 *size_instance += get_element_size(type);
807 return desc_offset;
810 static void init_sltg_tail(struct sltg_tail *tail)
812 tail->cFuncs = 0;
813 tail->cVars = 0;
814 tail->cImplTypes = 0;
815 tail->res06 = 0;
816 tail->funcs_off = -1;
817 tail->vars_off = 0;
818 tail->impls_off = -1;
819 tail->funcs_bytes = -1;
820 tail->vars_bytes = 0;
821 tail->impls_bytes = -1;
822 tail->tdescalias_vt = -1;
823 tail->res16 = -1;
824 tail->res18 = 0;
825 tail->res1a = 0;
826 tail->simple_alias = 0;
827 tail->res1e = 0;
828 tail->cbSizeInstance = 0;
829 tail->cbAlignment = 4;
830 tail->res24 = -1;
831 tail->res26 = -1;
832 tail->cbSizeVft = 0;
833 tail->res2a = -1;
834 tail->res2c = -1;
835 tail->res2e = -1;
836 tail->res30 = -1;
837 tail->res32 = 0;
838 tail->type_bytes = 0;
841 static void add_structure_typeinfo(struct sltg_typelib *typelib, type_t *type)
843 struct sltg_data data, *var_data = NULL;
844 struct sltg_hrefmap hrefmap;
845 const char *index_name;
846 struct sltg_typeinfo_header ti;
847 struct sltg_member_header member;
848 struct sltg_tail tail;
849 int member_offset, var_count = 0, var_data_size = 0, size_instance = 0;
850 short *type_desc_offset = NULL;
852 if (type->typelib_idx != -1) return;
854 chat("add_structure_typeinfo: type %p, type->name %s\n", type, type->name);
856 type->typelib_idx = typelib->block_count;
858 hrefmap.href_count = 0;
859 hrefmap.href = NULL;
861 init_sltg_data(&data);
863 if (type_struct_get_fields(type))
865 int i = 0;
866 var_t *var;
868 var_count = list_count(type_struct_get_fields(type));
870 var_data = xmalloc(var_count * sizeof(*var_data));
871 type_desc_offset = xmalloc(var_count * sizeof(*type_desc_offset));
873 LIST_FOR_EACH_ENTRY(var, type_struct_get_fields(type), var_t, entry)
875 short base_offset;
877 chat("add_structure_typeinfo: var %p (%s), type %p (%s)\n",
878 var, var->name, var->declspec.type, var->declspec.type->name);
880 init_sltg_data(&var_data[i]);
882 base_offset = var_data_size + (i + 1) * sizeof(struct sltg_variable);
883 type_desc_offset[i] = write_var_desc(typelib, &var_data[i], var->declspec.type, 0, base_offset, &size_instance, &hrefmap);
884 dump_var_desc(var_data[i].data, var_data[i].size);
886 if (var_data[i].size > sizeof(short))
887 var_data_size += var_data[i].size;
888 i++;
892 index_name = add_typeinfo_block(typelib, type, TKIND_RECORD);
894 init_typeinfo(&ti, type, TKIND_RECORD, &hrefmap);
895 append_data(&data, &ti, sizeof(ti));
897 write_hrefmap(&data, &hrefmap);
899 member_offset = data.size;
901 member.res00 = 0x0001;
902 member.res02 = 0xffff;
903 member.res04 = 0x01;
904 member.extra = var_data_size + var_count * sizeof(struct sltg_variable);
905 append_data(&data, &member, sizeof(member));
907 var_data_size = 0;
909 if (type_struct_get_fields(type))
911 int i = 0;
912 short next = member_offset;
913 var_t *var;
915 LIST_FOR_EACH_ENTRY(var, type_struct_get_fields(type), var_t, entry)
917 struct sltg_variable variable;
919 next += sizeof(variable);
921 variable.magic = 0x2a; /* always write flags to simplify calculations */
922 variable.name = add_name(&typelib->name_table, var->name);
923 variable.byte_offs = 0;
924 if (var_data[i].size > sizeof(short))
926 variable.flags = 0;
927 var_data_size = next - member_offset + type_desc_offset[i];
928 variable.type = var_data_size;
929 next += var_data[i].size;
931 else
933 variable.flags = 0x02;
934 variable.type = *(short *)var_data[i].data;
936 variable.next = i < var_count - 1 ? next - member_offset : -1;
937 variable.memid = 0x40000000 + i;
938 variable.helpcontext = -2; /* 0xfffe */
939 variable.helpstring = -1;
940 variable.varflags = 0;
942 append_data(&data, &variable, sizeof(variable));
943 if (var_data[i].size > sizeof(short))
944 append_data(&data, var_data[i].data, var_data[i].size);
946 i++;
950 init_sltg_tail(&tail);
951 tail.cVars = var_count;
952 tail.vars_bytes = var_data_size;
953 tail.cbSizeInstance = size_instance;
954 tail.type_bytes = data.size - member_offset - sizeof(member);
955 append_data(&data, &tail, sizeof(tail));
957 add_block(typelib, data.data, data.size, index_name);
960 static void add_enum_typeinfo(struct sltg_typelib *typelib, type_t *type)
962 error("add_enum_typeinfo: %s not implemented\n", type->name);
965 static void add_union_typeinfo(struct sltg_typelib *typelib, type_t *type)
967 error("add_union_typeinfo: %s not implemented\n", type->name);
970 static void add_coclass_typeinfo(struct sltg_typelib *typelib, type_t *type)
972 error("add_coclass_typeinfo: %s not implemented\n", type->name);
975 static void add_type_typeinfo(struct sltg_typelib *typelib, type_t *type)
977 chat("add_type_typeinfo: adding %s, type %d\n", type->name, type_get_type(type));
979 switch (type_get_type(type))
981 case TYPE_INTERFACE:
982 add_interface_typeinfo(typelib, type);
983 break;
984 case TYPE_STRUCT:
985 add_structure_typeinfo(typelib, type);
986 break;
987 case TYPE_ENUM:
988 add_enum_typeinfo(typelib, type);
989 break;
990 case TYPE_UNION:
991 add_union_typeinfo(typelib, type);
992 break;
993 case TYPE_COCLASS:
994 add_coclass_typeinfo(typelib, type);
995 break;
996 case TYPE_BASIC:
997 case TYPE_POINTER:
998 break;
999 default:
1000 error("add_type_typeinfo: unhandled type %d for %s\n", type_get_type(type), type->name);
1001 break;
1005 static void add_statement(struct sltg_typelib *typelib, const statement_t *stmt)
1007 switch(stmt->type)
1009 case STMT_LIBRARY:
1010 case STMT_IMPORT:
1011 case STMT_PRAGMA:
1012 case STMT_CPPQUOTE:
1013 case STMT_DECLARATION:
1014 /* not included in typelib */
1015 break;
1016 case STMT_IMPORTLIB:
1017 /* not processed here */
1018 break;
1020 case STMT_TYPEDEF:
1022 typeref_t *ref;
1024 if (!stmt->u.type_list)
1025 break;
1027 LIST_FOR_EACH_ENTRY(ref, stmt->u.type_list, typeref_t, entry)
1029 /* in old style typelibs all types are public */
1030 add_type_typeinfo(typelib, ref->type);
1032 break;
1035 case STMT_MODULE:
1036 add_module_typeinfo(typelib, stmt->u.type);
1037 break;
1039 case STMT_TYPE:
1040 case STMT_TYPEREF:
1042 type_t *type = stmt->u.type;
1043 add_type_typeinfo(typelib, type);
1044 break;
1047 default:
1048 error("add_statement: unhandled statement type %d\n", stmt->type);
1049 break;
1053 static void sltg_write_header(struct sltg_typelib *sltg, int *library_block_start)
1055 char pad[0x40];
1056 struct sltg_header
1058 int magic;
1059 short block_count;
1060 short res06;
1061 short size_of_index;
1062 short first_blk;
1063 GUID uuid;
1064 int res1c;
1065 int res20;
1066 } header;
1067 struct sltg_block_entry
1069 int length;
1070 short index_string;
1071 short next;
1072 } entry;
1073 int i;
1075 header.magic = 0x47544c53;
1076 header.block_count = sltg->block_count + 1; /* 1-based */
1077 header.res06 = 9;
1078 header.size_of_index = sltg->index.size;
1079 header.first_blk = 1; /* 1-based */
1080 header.uuid = sltg_library_guid;
1081 header.res1c = 0x00000044;
1082 header.res20 = 0xffff0000;
1084 put_data(&header, sizeof(header));
1086 /* library block is written separately */
1087 for (i = 0; i < sltg->block_count - 1; i++)
1089 entry.length = sltg->blocks[i].length;
1090 entry.index_string = sltg->blocks[i].index_string;
1091 entry.next = header.first_blk + i + 1; /* point to next block */
1092 chat("sltg_write_header: writing block entry %d: length %#x, index_string %#x, next %#x\n",
1093 i, entry.length, entry.index_string, entry.next);
1094 put_data(&entry, sizeof(entry));
1097 /* library block length includes helpstrings and name table */
1098 entry.length = sltg->blocks[sltg->block_count - 1].length + 0x40 /* pad after library block */ +
1099 sizeof(sltg->typeinfo_count) + sltg->typeinfo_size + 4 /* library block offset */ + 6 /* dummy help strings */ +
1100 12 /* name table header */ + 0x200 /* name table hash */ + sltg->name_table.size;
1101 entry.index_string = sltg->blocks[sltg->block_count - 1].index_string;
1102 entry.next = 0;
1103 chat("sltg_write_header: writing library block entry %d: length %#x, index_string %#x, next %#x\n",
1104 i, entry.length, entry.index_string, entry.next);
1105 put_data(&entry, sizeof(entry));
1107 chat("sltg_write_header: writing index: %d bytes\n", sltg->index.size);
1108 put_data(sltg->index.data, sltg->index.size);
1109 memset(pad, 0, 9);
1110 put_data(pad, 9);
1112 /* library block is written separately */
1113 for (i = 0; i < sltg->block_count - 1; i++)
1115 chat("sltg_write_header: writing block %d: %d bytes\n", i, sltg->blocks[i].length);
1116 put_data(sltg->blocks[i].data, sltg->blocks[i].length);
1119 /* library block */
1120 chat("library_block_start = %#x\n", (int)output_buffer_pos);
1121 *library_block_start = output_buffer_pos;
1122 chat("sltg_write_header: writing library block %d: %d bytes\n", i, sltg->blocks[i].length);
1123 put_data(sltg->blocks[sltg->block_count - 1].data, sltg->blocks[sltg->block_count - 1].length);
1125 chat("sltg_write_header: writing pad 0x40 bytes\n");
1126 memset(pad, 0xff, 0x40);
1127 put_data(pad, 0x40);
1130 static void sltg_write_typeinfo(struct sltg_typelib *typelib)
1132 short i;
1134 put_data(&typelib->typeinfo_count, sizeof(typelib->typeinfo_count));
1136 for (i = 0; i < typelib->typeinfo_count; i++)
1138 chat("sltg_write_typeinfo: writing block %d: %d bytes\n", i, typelib->typeinfo[i].length);
1139 put_data(typelib->typeinfo[i].data, typelib->typeinfo[i].length);
1143 static void sltg_write_helpstrings(struct sltg_typelib *typelib)
1145 static const char dummy[6];
1147 chat("sltg_write_helpstrings: writing dummy 6 bytes\n");
1149 put_data(dummy, sizeof(dummy));
1152 static void sltg_write_nametable(struct sltg_typelib *typelib)
1154 static const short dummy[6] = { 0xffff,1,2,0xff00,0xffff,0xffff };
1155 char pad[0x200];
1157 chat("sltg_write_nametable: writing 12+0x200+%d bytes\n", typelib->name_table.size);
1159 put_data(dummy, sizeof(dummy));
1160 memset(pad, 0xff, 0x200);
1161 put_data(pad, 0x200);
1162 put_data(&typelib->name_table.size, sizeof(typelib->name_table.size));
1163 put_data(typelib->name_table.data, typelib->name_table.size);
1166 static void sltg_write_remainder(void)
1168 static const short dummy1[] = { 1,0xfffe,0x0a03,0,0xffff,0xffff };
1169 static const short dummy2[] = { 0xffff,0xffff,0x0200,0,0,0 };
1170 static const char dummy3[] = { 0xf4,0x39,0xb2,0x71,0,0,0,0,0,0,0,0,0,0,0,0 };
1171 static const char TYPELIB[] = { 8,0,0,0,'T','Y','P','E','L','I','B',0 };
1172 int pad;
1174 pad = 0x01ffff01;
1175 put_data(&pad, sizeof(pad));
1176 pad = 0;
1177 put_data(&pad, sizeof(pad));
1179 put_data(dummy1, sizeof(dummy1));
1181 put_data(&sltg_library_guid, sizeof(sltg_library_guid));
1183 put_data(TYPELIB, sizeof(TYPELIB));
1185 put_data(dummy2, sizeof(dummy2));
1186 put_data(dummy3, sizeof(dummy3));
1189 static void save_all_changes(struct sltg_typelib *typelib)
1191 int library_block_start;
1192 int *name_table_offset;
1194 sltg_write_header(typelib, &library_block_start);
1195 sltg_write_typeinfo(typelib);
1197 name_table_offset = (int *)(output_buffer + output_buffer_pos);
1198 chat("name_table_offset = %#x\n", (int)output_buffer_pos);
1199 put_data(&library_block_start, sizeof(library_block_start));
1201 sltg_write_helpstrings(typelib);
1203 *name_table_offset = output_buffer_pos - library_block_start;
1204 chat("*name_table_offset = %#x\n", *name_table_offset);
1206 sltg_write_nametable(typelib);
1207 sltg_write_remainder();
1209 if (strendswith(typelib_name, ".res")) /* create a binary resource file */
1211 char typelib_id[13] = "#1";
1213 expr_t *expr = get_attrp(typelib->typelib->attrs, ATTR_ID);
1214 if (expr)
1215 sprintf(typelib_id, "#%d", expr->cval);
1216 add_output_to_resources("TYPELIB", typelib_id);
1217 if (strendswith(typelib_name, "_t.res")) /* add typelib registration */
1218 output_typelib_regscript(typelib->typelib);
1220 else flush_output_buffer(typelib_name);
1223 int create_sltg_typelib(typelib_t *typelib)
1225 struct sltg_typelib sltg;
1226 const statement_t *stmt;
1228 if (pointer_size != 4)
1229 error("Only 32-bit platform is supported\n");
1231 sltg.typelib = typelib;
1232 sltg.typeinfo_count = 0;
1233 sltg.typeinfo_size = 0;
1234 sltg.typeinfo = NULL;
1235 sltg.blocks = NULL;
1236 sltg.block_count = 0;
1237 sltg.first_block = 1;
1239 init_index(&sltg.index);
1240 init_name_table(&sltg.name_table);
1241 init_library(&sltg);
1243 add_library_block(&sltg);
1245 if (typelib->stmts)
1246 LIST_FOR_EACH_ENTRY(stmt, typelib->stmts, const statement_t, entry)
1247 add_statement(&sltg, stmt);
1249 save_all_changes(&sltg);
1251 return 1;