xref: /reactos/sdk/tools/widl/write_sltg.c (revision 22c8b4bf)
1 /*
2  * Typelib (SLTG) generation
3  *
4  * Copyright 2015,2016 Dmitry Timoshkov
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include "config.h"
22 #include "wine/port.h"
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <time.h>
30 
31 #define NONAMELESSUNION
32 
33 #ifdef __REACTOS__
34 #include <typedefs.h>
35 #include <nls.h>
36 #else
37 #include "windef.h"
38 #include "winbase.h"
39 #endif
40 
41 #include "widl.h"
42 #include "typelib.h"
43 #include "typelib_struct.h"
44 #include "utils.h"
45 #include "header.h"
46 #include "typetree.h"
47 
48 static const GUID sltg_library_guid = { 0x204ff,0,0,{ 0xc0,0,0,0,0,0,0,0x46 } };
49 
50 struct sltg_data
51 {
52     int size, allocated;
53     char *data;
54 };
55 
56 struct sltg_library
57 {
58     short name;
59     char *helpstring;
60     char *helpfile;
61     int helpcontext;
62     int syskind;
63     LCID lcid;
64     int libflags;
65     int version;
66     GUID uuid;
67 };
68 
69 struct sltg_block
70 {
71     int length;
72     int index_string;
73     void *data;
74     struct sltg_block *next;
75 };
76 
77 struct sltg_typelib
78 {
79     typelib_t *typelib;
80     struct sltg_data index;
81     struct sltg_data name_table;
82     struct sltg_library library;
83     struct sltg_block *blocks;
84     int n_file_blocks;
85     int first_block;
86     int typeinfo_count;
87     int typeinfo_size;
88     struct sltg_block *typeinfo;
89 };
90 
91 struct sltg_hrefmap
92 {
93     int href_count;
94     int *href;
95 };
96 
97 #include "pshpack1.h"
98 struct sltg_typeinfo_header
99 {
100     short magic;
101     int href_offset;
102     int res06;
103     int member_offset;
104     int res0e;
105     int version;
106     int res16;
107     struct
108     {
109         unsigned unknown1  : 3;
110         unsigned flags     : 13;
111         unsigned unknown2  : 8;
112         unsigned typekind  : 8;
113     } misc;
114     int res1e;
115 };
116 
117 struct sltg_member_header
118 {
119     short res00;
120     short res02;
121     char res04;
122     int extra;
123 };
124 
125 struct sltg_variable
126 {
127     char magic; /* 0x0a */
128     char flags;
129     short next;
130     short name;
131     short byte_offs; /* pos in struct, or offset to const type or const data (if flags & 0x08) */
132     short type; /* if flags & 0x02 this is the type, else offset to type */
133     int memid;
134     short helpcontext;
135     short helpstring;
136     short varflags; /* only present if magic & 0x02 */
137 };
138 
139 struct sltg_tail
140 {
141     short cFuncs;
142     short cVars;
143     short cImplTypes;
144     short res06; /* always 0000 */
145     short funcs_off; /* offset to functions (starting from the member header) */
146     short vars_off; /* offset to vars (starting from the member header) */
147     short impls_off; /* offset to implemented types (starting from the member header) */
148     short funcs_bytes; /* bytes used by function data */
149     short vars_bytes; /* bytes used by var data */
150     short impls_bytes; /* bytes used by implemented type data */
151     short tdescalias_vt; /* for TKIND_ALIAS */
152     short res16; /* always ffff */
153     short res18; /* always 0000 */
154     short res1a; /* always 0000 */
155     short simple_alias; /* tdescalias_vt is a vt rather than an offset? */
156     short res1e; /* always 0000 */
157     short cbSizeInstance;
158     short cbAlignment;
159     short res24;
160     short res26;
161     short cbSizeVft;
162     short res2a; /* always ffff */
163     short res2c; /* always ffff */
164     short res2e; /* always ffff */
165     short res30; /* always ffff */
166     short res32; /* unknown */
167     short type_bytes; /* bytes used by type descriptions */
168 };
169 
170 struct sltg_hrefinfo
171 {
172     char magic; /* 0xdf */
173     char res01; /* 0x00 */
174     int res02;  /* 0xffffffff */
175     int res06;  /* 0xffffffff */
176     int res0a;  /* 0xffffffff */
177     int res0e;  /* 0xffffffff */
178     int res12;  /* 0xffffffff */
179     int res16;  /* 0xffffffff */
180     int res1a;  /* 0xffffffff */
181     int res1e;  /* 0xffffffff */
182     int res22;  /* 0xffffffff */
183     int res26;  /* 0xffffffff */
184     int res2a;  /* 0xffffffff */
185     int res2e;  /* 0xffffffff */
186     int res32;  /* 0xffffffff */
187     int res36;  /* 0xffffffff */
188     int res3a;  /* 0xffffffff */
189     int res3e;  /* 0xffffffff */
190     short res42;/* 0xffff */
191     int number; /* this is 8 times the number of refs */
192     /* Now we have number bytes (8 for each ref) of SLTG_UnknownRefInfo */
193 
194     short res50;/* 0xffff */
195     char res52; /* 0x01 */
196     int res53;  /* 0x00000000 */
197     /*    Now we have number/8 SLTG_Names (first WORD is no of bytes in the ascii
198      *    string).  Strings look like "*\Rxxxx*#n".  If xxxx == ffff then the
199      *    ref refers to the nth type listed in this library (0 based).  Else
200      *    the xxxx (which maybe fewer than 4 digits) is the offset into the name
201      *    table to a string "*\G{<guid>}#1.0#0#C:\WINNT\System32\stdole32.tlb#"
202      *    The guid is the typelib guid; the ref again refers to the nth type of
203      *    the imported typelib.
204      */
205 
206     char resxx; /* 0xdf */
207 };
208 
209 struct sltg_function
210 {
211     char magic; /* 0x4c, 0xcb or 0x8b with optional SLTG_FUNCTION_FLAGS_PRESENT flag */
212     char flags; /* high nibble is INVOKE_KIND, low nibble = 2 */
213     short next; /* byte offset from beginning of group to next fn */
214     short name; /* Offset within name table to name */
215     int dispid; /* dispid */
216     short helpcontext; /* helpcontext (again 1 is special) */
217     short helpstring; /* helpstring offset to offset */
218     short arg_off; /* offset to args from start of block */
219     char nacc; /* lowest 3bits are CALLCONV, rest are no of args */
220     char retnextopt; /* if 0x80 bit set ret type follows else next WORD
221                         is offset to ret type. No of optional args is
222                         middle 6 bits */
223     short rettype; /* return type VT_?? or offset to ret type */
224     short vtblpos; /* position in vtbl? */
225     short funcflags; /* present if magic & 0x20 */
226 /* Param list starts, repeat next two as required */
227 #if 0
228     WORD name; /* offset to 2nd letter of name */
229     WORD+ type; /* VT_ of param */
230 #endif
231 };
232 
233 struct sltg_impl_info
234 {
235     short res00;
236     short next;
237     short res04;
238     char impltypeflags;
239     char res07;
240     short res08;
241     short ref;
242     short res0c;
243     short res0e;
244     short res10;
245     short res12;
246     short pos;
247 };
248 
249 #include "poppack.h"
250 
251 static void add_structure_typeinfo(struct sltg_typelib *typelib, type_t *type);
252 static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *type);
253 static void add_enum_typeinfo(struct sltg_typelib *typelib, type_t *type);
254 static void add_union_typeinfo(struct sltg_typelib *typelib, type_t *type);
255 static void add_coclass_typeinfo(struct sltg_typelib *typelib, type_t *type);
256 
init_sltg_data(struct sltg_data * data)257 static void init_sltg_data(struct sltg_data *data)
258 {
259     data->size = 0;
260     data->allocated = 0x10;
261     data->data = xmalloc(0x10);
262 }
263 
add_index(struct sltg_data * index,const char * name)264 static int add_index(struct sltg_data *index, const char *name)
265 {
266     int name_offset = index->size;
267     int new_size = index->size + strlen(name) + 1;
268 
269     chat("add_index: name_offset %d, \"%s\"\n", name_offset, name);
270 
271     if (new_size > index->allocated)
272     {
273         index->allocated = max(index->allocated * 2, new_size);
274         index->data = xrealloc(index->data, index->allocated);
275     }
276 
277     strcpy(index->data + index->size, name);
278     index->size = new_size;
279 
280     return name_offset;
281 }
282 
init_index(struct sltg_data * index)283 static void init_index(struct sltg_data *index)
284 {
285     static const char compobj[] = { 1,'C','o','m','p','O','b','j',0 };
286 
287     init_sltg_data(index);
288 
289     add_index(index, compobj);
290 }
291 
add_name(struct sltg_typelib * sltg,const char * name)292 static int add_name(struct sltg_typelib *sltg, const char *name)
293 {
294     int name_offset = sltg->name_table.size;
295     int new_size = sltg->name_table.size + strlen(name) + 1 + 8;
296     int aligned_size;
297 
298     chat("add_name: %s\n", name);
299 
300     aligned_size = (new_size + 0x1f) & ~0x1f;
301     if (aligned_size - new_size < 4)
302         new_size = aligned_size;
303     else
304         new_size = (new_size + 1) & ~1;
305 
306     if (new_size > sltg->name_table.allocated)
307     {
308         sltg->name_table.allocated = max(sltg->name_table.allocated * 2, new_size);
309         sltg->name_table.data = xrealloc(sltg->name_table.data, sltg->name_table.allocated);
310     }
311 
312     memset(sltg->name_table.data + sltg->name_table.size, 0xff, 8);
313     strcpy(sltg->name_table.data + sltg->name_table.size + 8, name);
314     sltg->name_table.size = new_size;
315     sltg->name_table.data[sltg->name_table.size - 1] = 0; /* clear alignment */
316 
317     return name_offset;
318 }
319 
init_name_table(struct sltg_typelib * sltg)320 static void init_name_table(struct sltg_typelib *sltg)
321 {
322     init_sltg_data(&sltg->name_table);
323 }
324 
init_library(struct sltg_typelib * sltg)325 static void init_library(struct sltg_typelib *sltg)
326 {
327     const attr_t *attr;
328 
329     sltg->library.name = add_name(sltg, sltg->typelib->name);
330     sltg->library.helpstring = NULL;
331     sltg->library.helpcontext = 0;
332     sltg->library.syskind = (pointer_size == 8) ? SYS_WIN64 : SYS_WIN32;
333     sltg->library.lcid = 0x0409;
334     sltg->library.libflags = 0;
335     sltg->library.version = 0;
336     sltg->library.helpfile = NULL;
337     memset(&sltg->library.uuid, 0, sizeof(sltg->library.uuid));
338 
339     if (!sltg->typelib->attrs) return;
340 
341     LIST_FOR_EACH_ENTRY(attr, sltg->typelib->attrs, const attr_t, entry)
342     {
343         const expr_t *expr;
344 
345         switch (attr->type)
346         {
347         case ATTR_VERSION:
348             sltg->library.version = attr->u.ival;
349             break;
350         case ATTR_HELPSTRING:
351             sltg->library.helpstring = attr->u.pval;
352             break;
353         case ATTR_HELPFILE:
354             sltg->library.helpfile = attr->u.pval;
355             break;
356         case ATTR_UUID:
357             sltg->library.uuid = *(GUID *)attr->u.pval;
358             break;
359         case ATTR_HELPCONTEXT:
360             expr = attr->u.pval;
361             sltg->library.helpcontext = expr->cval;
362             break;
363         case ATTR_LIBLCID:
364             expr = attr->u.pval;
365             sltg->library.lcid = expr->cval;
366             break;
367         case ATTR_CONTROL:
368             sltg->library.libflags |= 0x02; /* LIBFLAG_FCONTROL */
369             break;
370         case ATTR_HIDDEN:
371             sltg->library.libflags |= 0x04; /* LIBFLAG_FHIDDEN */
372             break;
373         case ATTR_RESTRICTED:
374             sltg->library.libflags |= 0x01; /* LIBFLAG_FRESTRICTED */
375             break;
376         default:
377             break;
378         }
379     }
380 }
381 
add_block_index(struct sltg_typelib * sltg,void * data,int size,int index)382 static void add_block_index(struct sltg_typelib *sltg, void *data, int size, int index)
383 {
384     struct sltg_block *block = xmalloc(sizeof(*block));
385 
386     block->length = size;
387     block->data = data;
388     block->index_string = index;
389     block->next = NULL;
390 
391     if (sltg->blocks)
392     {
393         struct sltg_block *blocks = sltg->blocks;
394 
395         while (blocks->next)
396             blocks = blocks->next;
397 
398         blocks->next = block;
399     }
400     else
401         sltg->blocks = block;
402 
403     sltg->n_file_blocks++;
404 }
405 
add_block(struct sltg_typelib * sltg,void * data,int size,const char * name)406 static void add_block(struct sltg_typelib *sltg, void *data, int size, const char *name)
407 {
408     struct sltg_block *block = xmalloc(sizeof(*block));
409     int index;
410 
411     chat("add_block: %p,%d,\"%s\"\n", data, size, name);
412 
413     index = add_index(&sltg->index, name);
414 
415     add_block_index(sltg, data, size, index);
416 }
417 
create_library_block(struct sltg_typelib * typelib,int * size,int * index)418 static void *create_library_block(struct sltg_typelib *typelib, int *size, int *index)
419 {
420     void *block;
421     short *p;
422 
423     *size = sizeof(short) * 9 + sizeof(int) * 3 + sizeof(GUID);
424     if (typelib->library.helpstring) *size += strlen(typelib->library.helpstring);
425     if (typelib->library.helpfile) *size += strlen(typelib->library.helpfile);
426 
427     block = xmalloc(*size);
428     p = block;
429     *p++ = 0x51cc; /* magic */
430     *p++ = 3; /* res02 */
431     *p++ = typelib->library.name;
432     *p++ = 0xffff; /* res06 */
433     if (typelib->library.helpstring)
434     {
435         *p++ = strlen(typelib->library.helpstring);
436         strcpy((char *)p, typelib->library.helpstring);
437         p = (short *)((char *)p + strlen(typelib->library.helpstring));
438     }
439     else
440         *p++ = 0xffff;
441     if (typelib->library.helpfile)
442     {
443         *p++ = strlen(typelib->library.helpfile);
444         strcpy((char *)p, typelib->library.helpfile);
445         p = (short *)((char *)p + strlen(typelib->library.helpfile));
446     }
447     else
448         *p++ = 0xffff;
449     *(int *)p = typelib->library.helpcontext;
450     p += 2;
451     *p++ = typelib->library.syskind;
452     *p++ = typelib->library.lcid;
453     *(int *)p = 0; /* res12 */
454     p += 2;
455     *p++ = typelib->library.libflags;
456     *(int *)p = typelib->library.version;
457     p += 2;
458     *(GUID *)p = typelib->library.uuid;
459 
460     *index = add_index(&typelib->index, "dir");
461 
462     return block;
463 }
464 
new_index_name(void)465 static const char *new_index_name(void)
466 {
467     static char name[11] = "0000000000";
468     static int pos = 0;
469     char *new_name;
470 
471     if (name[pos] == 'Z')
472     {
473         pos++;
474         if (pos > 9)
475             error("too many index names\n");
476     }
477 
478     name[pos]++;
479 
480     new_name = xmalloc(sizeof(name));
481     strcpy(new_name, name);
482     return new_name;
483 }
484 
sltg_add_typeinfo(struct sltg_typelib * sltg,void * data,int size,const char * name)485 static void sltg_add_typeinfo(struct sltg_typelib *sltg, void *data, int size, const char *name)
486 {
487     struct sltg_block *block = xmalloc(sizeof(*block));
488 
489     chat("sltg_add_typeinfo: %p,%d,%s\n", data, size, name);
490 
491     block->length = size;
492     block->data = data;
493     block->index_string = 0;
494     block->next = NULL;
495 
496     if (sltg->typeinfo)
497     {
498         struct sltg_block *typeinfo = sltg->typeinfo;
499 
500         while (typeinfo->next)
501             typeinfo = typeinfo->next;
502 
503         typeinfo->next = block;
504     }
505     else
506         sltg->typeinfo = block;
507 
508     sltg->typeinfo_count++;
509     sltg->typeinfo_size += size;
510 }
511 
append_data(struct sltg_data * block,const void * data,int size)512 static void append_data(struct sltg_data *block, const void *data, int size)
513 {
514     int new_size = block->size + size;
515 
516     if (new_size > block->allocated)
517     {
518         block->allocated = max(block->allocated * 2, new_size);
519         block->data = xrealloc(block->data, block->allocated);
520     }
521 
522     memcpy(block->data + block->size, data, size);
523     block->size = new_size;
524 }
525 
add_module_typeinfo(struct sltg_typelib * typelib,type_t * type)526 static void add_module_typeinfo(struct sltg_typelib *typelib, type_t *type)
527 {
528     error("add_module_typeinfo: %s not implemented\n", type->name);
529 }
530 
add_typeinfo_block(struct sltg_typelib * typelib,const type_t * type,int kind)531 static const char *add_typeinfo_block(struct sltg_typelib *typelib, const type_t *type, int kind)
532 {
533     const char *index_name, *other_name;
534     void *block;
535     short *p;
536     int size, helpcontext = 0;
537     GUID guid = { 0 };
538     const expr_t *expr;
539 
540     index_name = new_index_name();
541     other_name = new_index_name();
542 
543     expr = get_attrp(type->attrs, ATTR_HELPCONTEXT);
544     if (expr) helpcontext = expr->cval;
545 
546     p = get_attrp(type->attrs, ATTR_UUID);
547     if (p) guid = *(GUID *)p;
548 
549     size = sizeof(short) * 8 + 10 /* index_name */ * 2 + sizeof(int) + sizeof(GUID);
550 
551     block = xmalloc(size);
552     p = block;
553     *p++ = strlen(index_name);
554     strcpy((char *)p, index_name);
555     p = (short *)((char *)p + strlen(index_name));
556     *p++ = strlen(other_name);
557     strcpy((char *)p, other_name);
558     p = (short *)((char *)p + strlen(other_name));
559     *p++ = -1; /* res1a */
560     *p++ = add_name(typelib, type->name); /* name offset */
561     *p++ = 0; /* FIXME: helpstring */
562     *p++ = -1; /* res20 */
563     *(int *)p = helpcontext;
564     p += 2;
565     *p++ = -1; /* res26 */
566     *(GUID *)p = guid;
567     p += sizeof(GUID)/2;
568     *p = kind;
569 
570     sltg_add_typeinfo(typelib, block, size, index_name);
571 
572     return index_name;
573 }
574 
init_typeinfo(struct sltg_typeinfo_header * ti,const type_t * type,int kind,const struct sltg_hrefmap * hrefmap)575 static void init_typeinfo(struct sltg_typeinfo_header *ti, const type_t *type, int kind,
576                           const struct sltg_hrefmap *hrefmap)
577 {
578     ti->magic = 0x0501;
579     ti->href_offset = -1;
580     ti->res06 = -1;
581     ti->res0e = -1;
582     ti->version = get_attrv(type->attrs, ATTR_VERSION);
583     ti->res16 = 0xfffe0000;
584     ti->misc.unknown1 = 0x02;
585     ti->misc.flags = 0; /* FIXME */
586     ti->misc.unknown2 = 0x02;
587     ti->misc.typekind = kind;
588     ti->res1e = 0;
589 
590     ti->member_offset = sizeof(*ti);
591 
592     if (hrefmap->href_count)
593     {
594         char name[64];
595         int i, hrefinfo_size;
596 
597         hrefinfo_size = sizeof(struct sltg_hrefinfo);
598 
599         for (i = 0; i < hrefmap->href_count; i++)
600         {
601             sprintf(name, "*\\Rffff*#%x", hrefmap->href[i]);
602             hrefinfo_size += 8 + 2 + strlen(name);
603         }
604 
605         ti->href_offset = ti->member_offset;
606         ti->member_offset += hrefinfo_size;
607     }
608 }
609 
init_sltg_tail(struct sltg_tail * tail)610 static void init_sltg_tail(struct sltg_tail *tail)
611 {
612     tail->cFuncs = 0;
613     tail->cVars = 0;
614     tail->cImplTypes = 0;
615     tail->res06 = 0;
616     tail->funcs_off = -1;
617     tail->vars_off = -1;
618     tail->impls_off = -1;
619     tail->funcs_bytes = -1;
620     tail->vars_bytes = -1;
621     tail->impls_bytes = -1;
622     tail->tdescalias_vt = -1;
623     tail->res16 = -1;
624     tail->res18 = 0;
625     tail->res1a = 0;
626     tail->simple_alias = 0;
627     tail->res1e = 0;
628     tail->cbSizeInstance = 0;
629     tail->cbAlignment = 4;
630     tail->res24 = -1;
631     tail->res26 = -1;
632     tail->cbSizeVft = 0;
633     tail->res2a = -1;
634     tail->res2c = -1;
635     tail->res2e = -1;
636     tail->res30 = -1;
637     tail->res32 = 0;
638     tail->type_bytes = 0;
639 }
640 
write_hrefmap(struct sltg_data * data,const struct sltg_hrefmap * hrefmap)641 static void write_hrefmap(struct sltg_data *data, const struct sltg_hrefmap *hrefmap)
642 {
643     struct sltg_hrefinfo hrefinfo;
644     char name[64];
645     int i;
646 
647     if (!hrefmap->href_count) return;
648 
649     hrefinfo.magic = 0xdf;
650     hrefinfo.res01 = 0;
651     hrefinfo.res02 = -1;
652     hrefinfo.res06 = -1;
653     hrefinfo.res0a = -1;
654     hrefinfo.res0e = -1;
655     hrefinfo.res12 = -1;
656     hrefinfo.res16 = -1;
657     hrefinfo.res1a = -1;
658     hrefinfo.res1e = -1;
659     hrefinfo.res22 = -1;
660     hrefinfo.res26 = -1;
661     hrefinfo.res2a = -1;
662     hrefinfo.res2e = -1;
663     hrefinfo.res32 = -1;
664     hrefinfo.res36 = -1;
665     hrefinfo.res3a = -1;
666     hrefinfo.res3e = -1;
667     hrefinfo.res42 = -1;
668     hrefinfo.number = hrefmap->href_count * 8;
669     hrefinfo.res50 = -1;
670     hrefinfo.res52 = 1;
671     hrefinfo.res53 = 0;
672     hrefinfo.resxx = 0xdf;
673 
674     append_data(data, &hrefinfo, offsetof(struct sltg_hrefinfo, res50));
675 
676     for (i = 0; i < hrefmap->href_count; i++)
677         append_data(data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8);
678 
679     append_data(data, &hrefinfo.res50, 7);
680 
681     for (i = 0; i < hrefmap->href_count; i++)
682     {
683         short len;
684 
685         sprintf(name, "*\\Rffff*#%x", hrefmap->href[i]);
686         len = strlen(name);
687 
688         append_data(data, &len, sizeof(len));
689         append_data(data, name, len);
690     }
691 
692     append_data(data, &hrefinfo.resxx, sizeof(hrefinfo.resxx));
693 }
694 
dump_var_desc(const char * data,int size)695 static void dump_var_desc(const char *data, int size)
696 {
697     const unsigned char *p = (const unsigned char *)data;
698     int i;
699 
700     if (!(debuglevel & (DEBUGLEVEL_TRACE | DEBUGLEVEL_CHAT))) return;
701 
702     chat("dump_var_desc: size %d bytes\n", size);
703 
704     for (i = 0; i < size; i++)
705         fprintf(stderr, " %02x", *p++);
706 
707     fprintf(stderr, "\n");
708 }
709 
get_element_size(type_t * type)710 static int get_element_size(type_t *type)
711 {
712     int vt = get_type_vt(type);
713 
714     switch (vt)
715     {
716     case VT_I1:
717     case VT_UI1:
718         return 1;
719 
720     case VT_INT:
721     case VT_UINT:
722         return /* typelib_kind == SYS_WIN16 ? 2 : */ 4;
723 
724     case VT_UI2:
725     case VT_I2:
726     case VT_BOOL:
727         return 2;
728 
729     case VT_I4:
730     case VT_UI4:
731     case VT_R4:
732     case VT_ERROR:
733     case VT_HRESULT:
734         return 4;
735 
736     case VT_R8:
737     case VT_I8:
738     case VT_UI8:
739     case VT_CY:
740     case VT_DATE:
741         return 8;
742 
743     case VT_DECIMAL:
744         return 16;
745 
746     case VT_PTR:
747     case VT_UNKNOWN:
748     case VT_DISPATCH:
749     case VT_BSTR:
750     case VT_LPSTR:
751     case VT_LPWSTR:
752         return pointer_size;
753 
754     case VT_VOID:
755         return 0;
756 
757     case VT_VARIANT:
758         return pointer_size == 8 ? 24 : 16;
759 
760     case VT_USERDEFINED:
761         return 0;
762 
763     default:
764         error("get_element_size: unrecognized vt %d\n", vt);
765         break;
766     }
767 
768     return 0;
769 }
770 
local_href(struct sltg_hrefmap * hrefmap,int typelib_href)771 static int local_href(struct sltg_hrefmap *hrefmap, int typelib_href)
772 {
773     int i, href = -1;
774 
775     for (i = 0; i < hrefmap->href_count; i++)
776     {
777         if (hrefmap->href[i] == typelib_href)
778         {
779             href = i;
780             break;
781         }
782     }
783 
784     if (href == -1)
785     {
786         href = hrefmap->href_count;
787 
788         if (hrefmap->href)
789             hrefmap->href = xrealloc(hrefmap->href, sizeof(*hrefmap->href) * (hrefmap->href_count + 1));
790         else
791             hrefmap->href = xmalloc(sizeof(*hrefmap->href));
792 
793         hrefmap->href[hrefmap->href_count] = typelib_href;
794         hrefmap->href_count++;
795     }
796 
797     chat("typelib href %d mapped to local href %d\n", typelib_href, href);
798 
799     return href << 2;
800 }
801 
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)802 static short write_var_desc(struct sltg_typelib *typelib, struct sltg_data *data, type_t *type, short param_flags,
803                             short flags, short base_offset, int *size_instance, struct sltg_hrefmap *hrefmap)
804 {
805     short vt, vt_flags, desc_offset;
806 
807     chat("write_var_desc: type %p, type->name %s\n",
808          type, type->name ? type->name : "NULL");
809 
810     if (is_array(type) && !type_array_is_decl_as_ptr(type))
811     {
812         int num_dims, elements, array_start, size, array_size;
813         type_t *atype;
814         struct
815         {
816             short cDims;
817             short fFeatures;
818             int cbElements;
819             int cLocks;
820             void *pvData;
821             int bound[2];
822         } *array;
823         int *bound;
824         short vt_off[2];
825 
826         elements = 1;
827         num_dims = 0;
828 
829         atype = type;
830 
831         while (is_array(atype) && !type_array_is_decl_as_ptr(atype))
832         {
833             num_dims++;
834             elements *= type_array_get_dim(atype);
835 
836             atype = type_array_get_element(atype);
837         }
838 
839         chat("write_var_desc: VT_CARRAY: %d dimensions, %d elements\n", num_dims, elements);
840 
841         array_start = data->size;
842 
843         size = sizeof(*array) + (num_dims - 1) * 8 /* sizeof(SAFEARRAYBOUND) */;
844         array = xmalloc(size);
845 
846         array->cDims = num_dims;
847         array->fFeatures = 0x0004; /* FADF_EMBEDDED */
848         array->cbElements = get_element_size(atype);
849         array->cLocks = 0;
850         array->pvData = NULL;
851 
852         bound = array->bound;
853 
854         array_size = array->cbElements;
855         atype = type;
856 
857         while (is_array(atype) && !type_array_is_decl_as_ptr(atype))
858         {
859             bound[0] = type_array_get_dim(atype);
860             array_size *= bound[0];
861             bound[1] = 0;
862             bound += 2;
863 
864             atype = type_array_get_element(atype);
865         }
866 
867         if (size_instance)
868         {
869             *size_instance += array_size;
870             size_instance = NULL; /* don't account for element size */
871         }
872 
873         append_data(data, array, size);
874 
875         desc_offset = data->size;
876 
877         vt_off[0] = VT_CARRAY;
878         vt_off[1] = array_start + base_offset;
879         append_data(data, vt_off, sizeof(vt_off));
880 
881         /* fall through to write array element description */
882         type = atype;
883     }
884     else
885         desc_offset = data->size;
886 
887     vt = get_type_vt(type);
888 
889     if (vt == VT_PTR)
890     {
891         type_t *ref = is_ptr(type) ? type_pointer_get_ref(type) : type_array_get_element(type);
892 
893         if (is_ptr(ref))
894         {
895             chat("write_var_desc: vt VT_PTR | 0x0400 | %04x\n",  param_flags);
896             vt = VT_PTR | 0x0400 | param_flags;
897             append_data(data, &vt, sizeof(vt));
898             write_var_desc(typelib, data, ref, 0, 0, base_offset, size_instance, hrefmap);
899         }
900         else
901             write_var_desc(typelib, data, ref, param_flags, 0x0e00, base_offset, size_instance, hrefmap);
902         return desc_offset;
903     }
904 
905     chat("write_var_desc: vt %d, flags %04x\n", vt, flags);
906 
907     vt_flags = vt | flags | param_flags;
908     append_data(data, &vt_flags, sizeof(vt_flags));
909 
910     if (vt == VT_USERDEFINED)
911     {
912         short href;
913 
914         while (type->typelib_idx < 0 && type_is_alias(type))
915             type = type_alias_get_aliasee(type);
916 
917         chat("write_var_desc: VT_USERDEFINED, type %p, name %s, real type %d, href %d\n",
918              type, type->name, type_get_type(type), type->typelib_idx);
919 
920         if (type->typelib_idx == -1)
921         {
922             chat("write_var_desc: trying to ref not added type\n");
923 
924             switch (type_get_type(type))
925             {
926             case TYPE_STRUCT:
927                 add_structure_typeinfo(typelib, type);
928                 break;
929             case TYPE_INTERFACE:
930                 add_interface_typeinfo(typelib, type);
931                 break;
932             case TYPE_ENUM:
933                 add_enum_typeinfo(typelib, type);
934                 break;
935             case TYPE_UNION:
936                 add_union_typeinfo(typelib, type);
937                 break;
938             case TYPE_COCLASS:
939                 add_coclass_typeinfo(typelib, type);
940                 break;
941             default:
942                 error("write_var_desc: VT_USERDEFINED - unhandled type %d\n",
943                       type_get_type(type));
944             }
945         }
946 
947         if (type->typelib_idx == -1)
948             error("write_var_desc: trying to ref not added type\n");
949 
950         href = local_href(hrefmap, type->typelib_idx);
951         chat("write_var_desc: VT_USERDEFINED, local href %d\n", href);
952 
953         append_data(data, &href, sizeof(href));
954     }
955 
956     if (size_instance)
957         *size_instance += get_element_size(type);
958 
959     return desc_offset;
960 }
961 
add_structure_typeinfo(struct sltg_typelib * typelib,type_t * type)962 static void add_structure_typeinfo(struct sltg_typelib *typelib, type_t *type)
963 {
964     struct sltg_data data, *var_data = NULL;
965     struct sltg_hrefmap hrefmap;
966     const char *index_name;
967     struct sltg_typeinfo_header ti;
968     struct sltg_member_header member;
969     struct sltg_tail tail;
970     int member_offset, var_count = 0, var_data_size = 0, size_instance = 0;
971     short *type_desc_offset = NULL;
972 
973     if (type->typelib_idx != -1) return;
974 
975     chat("add_structure_typeinfo: type %p, type->name %s\n", type, type->name);
976 
977     type->typelib_idx = typelib->n_file_blocks;
978 
979     hrefmap.href_count = 0;
980     hrefmap.href = NULL;
981 
982     if (type_struct_get_fields(type))
983     {
984         int i = 0;
985         var_t *var;
986 
987         var_count = list_count(type_struct_get_fields(type));
988 
989         var_data = xmalloc(var_count * sizeof(*var_data));
990         type_desc_offset = xmalloc(var_count * sizeof(*type_desc_offset));
991 
992         LIST_FOR_EACH_ENTRY(var, type_struct_get_fields(type), var_t, entry)
993         {
994             short base_offset;
995 
996             chat("add_structure_typeinfo: var %p (%s), type %p (%s)\n",
997                  var, var->name, var->type, var->type->name);
998 
999             init_sltg_data(&var_data[i]);
1000 
1001             base_offset = var_data_size + (i + 1) * sizeof(struct sltg_variable);
1002             type_desc_offset[i] = write_var_desc(typelib, &var_data[i], var->type, 0, 0,
1003                                                  base_offset, &size_instance, &hrefmap);
1004             dump_var_desc(var_data[i].data, var_data[i].size);
1005 
1006             if (var_data[i].size > sizeof(short))
1007                 var_data_size += var_data[i].size;
1008             i++;
1009         }
1010     }
1011 
1012     init_sltg_data(&data);
1013 
1014     index_name = add_typeinfo_block(typelib, type, TKIND_RECORD);
1015 
1016     init_typeinfo(&ti, type, TKIND_RECORD, &hrefmap);
1017     append_data(&data, &ti, sizeof(ti));
1018 
1019     write_hrefmap(&data, &hrefmap);
1020 
1021     member_offset = data.size;
1022 
1023     member.res00 = 0x0001;
1024     member.res02 = 0xffff;
1025     member.res04 = 0x01;
1026     member.extra = var_data_size + var_count * sizeof(struct sltg_variable);
1027     append_data(&data, &member, sizeof(member));
1028 
1029     var_data_size = 0;
1030 
1031     if (type_struct_get_fields(type))
1032     {
1033         int i = 0;
1034         short next = member_offset;
1035         var_t *var;
1036 
1037         LIST_FOR_EACH_ENTRY(var, type_struct_get_fields(type), var_t, entry)
1038         {
1039             struct sltg_variable variable;
1040 
1041             next += sizeof(variable);
1042 
1043             variable.magic = 0x2a; /* always write flags to simplify calculations */
1044             variable.name = add_name(typelib, var->name);
1045             variable.byte_offs = 0;
1046             if (var_data[i].size > sizeof(short))
1047             {
1048                 variable.flags = 0;
1049                 var_data_size = next - member_offset + type_desc_offset[i];
1050                 variable.type = var_data_size;
1051                 next += var_data[i].size;
1052             }
1053             else
1054             {
1055                 variable.flags = 0x02;
1056                 variable.type = *(short *)var_data[i].data;
1057             }
1058             variable.next = i < var_count - 1 ? next - member_offset : -1;
1059             variable.memid = 0x40000000 + i;
1060             variable.helpcontext = -2; /* 0xfffe */
1061             variable.helpstring = -1;
1062             variable.varflags = 0;
1063 
1064             append_data(&data, &variable, sizeof(variable));
1065             if (var_data[i].size > sizeof(short))
1066                 append_data(&data, var_data[i].data, var_data[i].size);
1067 
1068             i++;
1069         }
1070     }
1071 
1072     init_sltg_tail(&tail);
1073 
1074     tail.cVars = var_count;
1075     tail.vars_off = 0;
1076     tail.vars_bytes = var_data_size;
1077     tail.cbSizeInstance = size_instance;
1078     tail.type_bytes = data.size - member_offset - sizeof(member);
1079     append_data(&data, &tail, sizeof(tail));
1080 
1081     add_block(typelib, data.data, data.size, index_name);
1082 }
1083 
find_importinfo(typelib_t * typelib,const char * name)1084 static importinfo_t *find_importinfo(typelib_t *typelib, const char *name)
1085 {
1086     importlib_t *importlib;
1087 
1088     LIST_FOR_EACH_ENTRY(importlib, &typelib->importlibs, importlib_t, entry)
1089     {
1090         int i;
1091 
1092         for (i = 0; i < importlib->ntypeinfos; i++)
1093         {
1094             if (!strcmp(name, importlib->importinfos[i].name))
1095             {
1096                 chat("Found %s in importlib list\n", name);
1097                 return &importlib->importinfos[i];
1098             }
1099         }
1100     }
1101 
1102     return NULL;
1103 }
1104 
get_func_flags(const var_t * func,int * dispid,int * invokekind,int * helpcontext,const char ** helpstring)1105 static int get_func_flags(const var_t *func, int *dispid, int *invokekind, int *helpcontext, const char **helpstring)
1106 {
1107     const attr_t *attr;
1108     int flags;
1109 
1110     *invokekind = 1 /* INVOKE_FUNC */;
1111     *helpcontext = -2;
1112     *helpstring = NULL;
1113 
1114     if (!func->attrs) return 0;
1115 
1116     flags = 0;
1117 
1118     LIST_FOR_EACH_ENTRY(attr, func->attrs, const attr_t, entry)
1119     {
1120         expr_t *expr = attr->u.pval;
1121         switch(attr->type)
1122         {
1123         case ATTR_BINDABLE:
1124             flags |= 0x4; /* FUNCFLAG_FBINDABLE */
1125             break;
1126         case ATTR_DEFAULTBIND:
1127             flags |= 0x20; /* FUNCFLAG_FDEFAULTBIND */
1128             break;
1129         case ATTR_DEFAULTCOLLELEM:
1130             flags |= 0x100; /* FUNCFLAG_FDEFAULTCOLLELEM */
1131             break;
1132         case ATTR_DISPLAYBIND:
1133             flags |= 0x10; /* FUNCFLAG_FDISPLAYBIND */
1134             break;
1135         case ATTR_HELPCONTEXT:
1136             *helpcontext = expr->u.lval;
1137             break;
1138         case ATTR_HELPSTRING:
1139             *helpstring = attr->u.pval;
1140             break;
1141         case ATTR_HIDDEN:
1142             flags |= 0x40; /* FUNCFLAG_FHIDDEN */
1143             break;
1144         case ATTR_ID:
1145             *dispid = expr->cval;
1146             break;
1147         case ATTR_IMMEDIATEBIND:
1148             flags |= 0x1000; /* FUNCFLAG_FIMMEDIATEBIND */
1149             break;
1150         case ATTR_NONBROWSABLE:
1151             flags |= 0x400; /* FUNCFLAG_FNONBROWSABLE */
1152             break;
1153         case ATTR_PROPGET:
1154             *invokekind = 0x2; /* INVOKE_PROPERTYGET */
1155             break;
1156         case ATTR_PROPPUT:
1157             *invokekind = 0x4; /* INVOKE_PROPERTYPUT */
1158             break;
1159         case ATTR_PROPPUTREF:
1160             *invokekind = 0x8; /* INVOKE_PROPERTYPUTREF */
1161             break;
1162         /* FIXME: FUNCFLAG_FREPLACEABLE */
1163         case ATTR_REQUESTEDIT:
1164             flags |= 0x8; /* FUNCFLAG_FREQUESTEDIT */
1165             break;
1166         case ATTR_RESTRICTED:
1167             flags |= 0x1; /* FUNCFLAG_FRESTRICTED */
1168             break;
1169         case ATTR_SOURCE:
1170             flags |= 0x2; /* FUNCFLAG_FSOURCE */
1171             break;
1172         case ATTR_UIDEFAULT:
1173             flags |= 0x200; /* FUNCFLAG_FUIDEFAULT */
1174             break;
1175         case ATTR_USESGETLASTERROR:
1176             flags |= 0x80; /* FUNCFLAG_FUSESGETLASTERROR */
1177             break;
1178         default:
1179             break;
1180         }
1181     }
1182 
1183     return flags;
1184 }
1185 
get_param_flags(const var_t * param)1186 static int get_param_flags(const var_t *param)
1187 {
1188     const attr_t *attr;
1189     int flags, in, out;
1190 
1191     if (!param->attrs) return 0;
1192 
1193     flags = 0;
1194     in = out = 0;
1195 
1196     LIST_FOR_EACH_ENTRY(attr, param->attrs, const attr_t, entry)
1197     {
1198         switch(attr->type)
1199         {
1200         case ATTR_IN:
1201             in++;
1202             break;
1203         case ATTR_OUT:
1204             out++;
1205             break;
1206         case ATTR_PARAMLCID:
1207             flags |= 0x2000;
1208             break;
1209         case ATTR_RETVAL:
1210             flags |= 0x80;
1211             break;
1212         default:
1213             chat("unhandled param attr %d\n", attr->type);
1214             break;
1215         }
1216     }
1217 
1218     if (out)
1219     {
1220         if (in)
1221             flags |= 0x8000;
1222         else
1223             flags |= 0x4000;
1224     }
1225     else if (!in)
1226         flags |= 0xc000;
1227 
1228     return flags;
1229 }
1230 
1231 
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)1232 static int add_func_desc(struct sltg_typelib *typelib, struct sltg_data *data, var_t *func,
1233                          int idx, int dispid, short base_offset, struct sltg_hrefmap *hrefmap)
1234 {
1235     struct sltg_data ret_data, *arg_data;
1236     int arg_count = 0, arg_data_size, optional = 0, defaults = 0, old_size;
1237     int funcflags = 0, invokekind = 1 /* INVOKE_FUNC */, helpcontext;
1238     const char *helpstring;
1239     const var_t *arg;
1240     short ret_desc_offset, *arg_desc_offset, arg_offset;
1241     struct sltg_function func_desc;
1242 
1243     chat("add_func_desc: %s, idx %#x, dispid %#x\n", func->name, idx, dispid);
1244 
1245     old_size = data->size;
1246 
1247     init_sltg_data(&ret_data);
1248     ret_desc_offset = write_var_desc(typelib, &ret_data, type_function_get_rettype(func->type),
1249                                      0, 0, base_offset, NULL, hrefmap);
1250     dump_var_desc(ret_data.data, ret_data.size);
1251 
1252     arg_data_size = 0;
1253     arg_offset = base_offset + sizeof(struct sltg_function);
1254 
1255     if (ret_data.size > sizeof(short))
1256     {
1257         arg_data_size += ret_data.size;
1258         arg_offset += ret_data.size;
1259     }
1260 
1261     if (type_get_function_args(func->type))
1262     {
1263         int i = 0;
1264 
1265         arg_count = list_count(type_get_function_args(func->type));
1266 
1267         arg_data = xmalloc(arg_count * sizeof(*arg_data));
1268         arg_desc_offset = xmalloc(arg_count * sizeof(*arg_desc_offset));
1269 
1270         arg_offset += arg_count * 2 * sizeof(short);
1271 
1272         LIST_FOR_EACH_ENTRY(arg, type_get_function_args(func->type), const var_t, entry)
1273         {
1274             const attr_t *attr;
1275             short param_flags = get_param_flags(arg);
1276 
1277             chat("add_func_desc: arg[%d] %p (%s), type %p (%s)\n",
1278                  i, arg, arg->name, arg->type, arg->type->name);
1279 
1280             init_sltg_data(&arg_data[i]);
1281 
1282             arg_desc_offset[i] = write_var_desc(typelib, &arg_data[i], arg->type, param_flags, 0,
1283                                                 arg_offset, NULL, hrefmap);
1284             dump_var_desc(arg_data[i].data, arg_data[i].size);
1285 
1286             if (arg_data[i].size > sizeof(short))
1287             {
1288                 arg_data_size += arg_data[i].size;
1289                 arg_offset += arg_data[i].size;;
1290             }
1291 
1292             i++;
1293 
1294             if (!arg->attrs) continue;
1295 
1296             LIST_FOR_EACH_ENTRY(attr, arg->attrs, const attr_t, entry)
1297             {
1298                 if (attr->type == ATTR_DEFAULTVALUE)
1299                     defaults++;
1300                 else if(attr->type == ATTR_OPTIONAL)
1301                     optional++;
1302             }
1303         }
1304     }
1305 
1306     funcflags = get_func_flags(func, &dispid, &invokekind, &helpcontext, &helpstring);
1307 
1308     if (base_offset != -1)
1309         chat("add_func_desc: flags %#x, dispid %#x, invokekind %d, helpcontext %#x, helpstring %s\n",
1310              funcflags, dispid, invokekind, helpcontext, helpstring);
1311 
1312     func_desc.magic = 0x6c; /* always write flags to simplify calculations */
1313     func_desc.flags = (invokekind << 4) | 0x02;
1314     if (idx & 0x80000000)
1315     {
1316         func_desc.next = -1;
1317         idx &= ~0x80000000;
1318     }
1319     else
1320         func_desc.next = base_offset + sizeof(func_desc) + arg_data_size + arg_count * 2 * sizeof(short);
1321     func_desc.name = base_offset != -1 ? add_name(typelib, func->name) : -1;
1322     func_desc.dispid = dispid;
1323     func_desc.helpcontext = helpcontext;
1324     func_desc.helpstring = (helpstring && base_offset != -1) ? add_name(typelib, helpstring) : -1;
1325     func_desc.arg_off = arg_count ? base_offset + sizeof(func_desc) : -1;
1326     func_desc.nacc = (arg_count << 3) | 4 /* CC_STDCALL */;
1327     func_desc.retnextopt = (optional << 1);
1328     if (ret_data.size > sizeof(short))
1329     {
1330         func_desc.rettype = base_offset + sizeof(func_desc) + ret_desc_offset;
1331         if (arg_count)
1332             func_desc.arg_off += ret_data.size;
1333     }
1334     else
1335     {
1336         func_desc.retnextopt |= 0x80;
1337         func_desc.rettype = *(short *)ret_data.data;
1338     }
1339     func_desc.vtblpos = idx * pointer_size;
1340     func_desc.funcflags = funcflags;
1341 
1342     append_data(data, &func_desc, sizeof(func_desc));
1343 
1344     arg_offset = base_offset + sizeof(struct sltg_function);
1345 
1346     if (ret_data.size > sizeof(short))
1347     {
1348         append_data(data, ret_data.data, ret_data.size);
1349         func_desc.arg_off += ret_data.size;
1350         arg_offset += ret_data.size;
1351     }
1352 
1353     if (arg_count)
1354     {
1355         int i = 0;
1356 
1357         arg_offset += arg_count * 2 * sizeof(short);
1358 
1359         LIST_FOR_EACH_ENTRY(arg, type_get_function_args(func->type), const var_t, entry)
1360         {
1361             short name, type_offset;
1362 
1363             name = base_offset != -1 ? add_name(typelib, arg->name) : -1;
1364 
1365             if (arg_data[i].size > sizeof(short))
1366             {
1367                 type_offset = (arg_offset + arg_desc_offset[i]);
1368                 arg_offset += arg_data[i].size;
1369             }
1370             else
1371             {
1372                 name |= 1;
1373                 type_offset = *(short *)arg_data[i].data;
1374             }
1375 
1376             append_data(data, &name, sizeof(name));
1377             append_data(data, &type_offset, sizeof(type_offset));
1378 
1379             if (base_offset != -1)
1380                 chat("add_func_desc: arg[%d] - name %s (%#x), type_offset %#x\n",
1381                      i, arg->name, name, type_offset);
1382 
1383             i++;
1384         }
1385 
1386         for (i = 0; i < arg_count; i++)
1387         {
1388             if (arg_data[i].size > sizeof(short))
1389                 append_data(data, arg_data[i].data, arg_data[i].size);
1390         }
1391     }
1392 
1393     return data->size - old_size;
1394 }
1395 
write_impl_href(struct sltg_data * data,short href)1396 static void write_impl_href(struct sltg_data *data, short href)
1397 {
1398     struct sltg_impl_info impl_info;
1399 
1400     impl_info.res00 = 0x004a;
1401     impl_info.next = -1;
1402     impl_info.res04 = -1;
1403     impl_info.impltypeflags = 0;
1404     impl_info.res07 = 0x80;
1405     impl_info.res08 = 0x0012;
1406     impl_info.ref = href;
1407     impl_info.res0c = 0x4001;
1408     impl_info.res0e = -2; /* 0xfffe */
1409     impl_info.res10 = -1;
1410     impl_info.res12 = 0x001d;
1411     impl_info.pos = 0;
1412 
1413     append_data(data, &impl_info, sizeof(impl_info));
1414 }
1415 
add_interface_typeinfo(struct sltg_typelib * typelib,type_t * iface)1416 static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *iface)
1417 {
1418     const statement_t *stmt_func;
1419     importinfo_t *ref_importinfo = NULL;
1420     short inherit_href = -1;
1421     struct sltg_data data;
1422     struct sltg_hrefmap hrefmap;
1423     const char *index_name;
1424     struct sltg_typeinfo_header ti;
1425     struct sltg_member_header member;
1426     struct sltg_tail tail;
1427     int member_offset, base_offset, func_data_size, i;
1428     int func_count, inherited_func_count = 0;
1429     int dispid, inherit_level = 0;
1430 
1431     if (iface->typelib_idx != -1) return;
1432 
1433     chat("add_interface_typeinfo: type %p, type->name %s\n", iface, iface->name);
1434 
1435     if (!iface->details.iface)
1436     {
1437         error("interface %s is referenced but not defined\n", iface->name);
1438         return;
1439     }
1440 
1441     if (is_attr(iface->attrs, ATTR_DISPINTERFACE))
1442     {
1443         error("support for dispinterface %s is not implemented\n", iface->name);
1444         return;
1445     }
1446 
1447     hrefmap.href_count = 0;
1448     hrefmap.href = NULL;
1449 
1450     if (type_iface_get_inherit(iface))
1451     {
1452         type_t *inherit;
1453 
1454         inherit = type_iface_get_inherit(iface);
1455 
1456         chat("add_interface_typeinfo: inheriting from base interface %s\n", inherit->name);
1457 
1458         ref_importinfo = find_importinfo(typelib->typelib, inherit->name);
1459 
1460         if (!ref_importinfo && type_iface_get_inherit(inherit))
1461             add_interface_typeinfo(typelib, inherit);
1462 
1463         if (ref_importinfo)
1464             error("support for imported interfaces is not implemented\n");
1465 
1466         inherit_href = local_href(&hrefmap, inherit->typelib_idx);
1467 
1468         while (inherit)
1469         {
1470             inherit_level++;
1471             inherited_func_count += list_count(type_iface_get_stmts(inherit));
1472             inherit = type_iface_get_inherit(inherit);
1473         }
1474     }
1475 
1476     /* check typelib_idx again, it could have been added while resolving the parent interface */
1477     if (iface->typelib_idx != -1) return;
1478 
1479     iface->typelib_idx = typelib->n_file_blocks;
1480 
1481     /* pass 1: calculate function descriptions data size */
1482     init_sltg_data(&data);
1483 
1484     STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(iface))
1485     {
1486         add_func_desc(typelib, &data, stmt_func->u.var, -1, -1, -1, &hrefmap);
1487     }
1488 
1489     func_data_size = data.size;
1490 
1491     /* pass 2: write function descriptions */
1492     init_sltg_data(&data);
1493 
1494     func_count = list_count(type_iface_get_stmts(iface));
1495 
1496     index_name = add_typeinfo_block(typelib, iface, TKIND_INTERFACE);
1497 
1498     init_typeinfo(&ti, iface, TKIND_INTERFACE, &hrefmap);
1499     append_data(&data, &ti, sizeof(ti));
1500 
1501     write_hrefmap(&data, &hrefmap);
1502 
1503     member_offset = data.size;
1504     base_offset = 0;
1505 
1506     member.res00 = 0x0001;
1507     member.res02 = 0xffff;
1508     member.res04 = 0x01;
1509     member.extra = func_data_size;
1510     if (inherit_href != -1)
1511     {
1512         member.extra += sizeof(struct sltg_impl_info);
1513         base_offset += sizeof(struct sltg_impl_info);
1514     }
1515     append_data(&data, &member, sizeof(member));
1516 
1517     if (inherit_href != -1)
1518         write_impl_href(&data, inherit_href);
1519 
1520     i = 0;
1521     dispid = 0x60000000 | (inherit_level << 16);
1522 
1523     STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(iface))
1524     {
1525         int idx = inherited_func_count + i;
1526 
1527         if (i == func_count - 1) idx |= 0x80000000;
1528 
1529         base_offset += add_func_desc(typelib, &data, stmt_func->u.var,
1530                                      idx, dispid + i, base_offset, &hrefmap);
1531         i++;
1532     }
1533 
1534     init_sltg_tail(&tail);
1535 
1536     tail.cFuncs = func_count;
1537     tail.funcs_off = 0;
1538     tail.funcs_bytes = func_data_size;
1539     tail.cbSizeInstance = pointer_size;
1540     tail.cbAlignment = pointer_size;
1541     tail.cbSizeVft = (inherited_func_count + func_count) * pointer_size;
1542     tail.type_bytes = data.size - member_offset - sizeof(member);
1543     tail.res24 = 0;
1544     tail.res26 = 0;
1545     if (inherit_href != -1)
1546     {
1547         tail.cImplTypes++;
1548         tail.impls_off = 0;
1549         tail.impls_bytes = 0;
1550 
1551         tail.funcs_off += sizeof(struct sltg_impl_info);
1552     }
1553     append_data(&data, &tail, sizeof(tail));
1554 
1555     add_block(typelib, data.data, data.size, index_name);
1556 }
1557 
add_enum_typeinfo(struct sltg_typelib * typelib,type_t * type)1558 static void add_enum_typeinfo(struct sltg_typelib *typelib, type_t *type)
1559 {
1560     error("add_enum_typeinfo: %s not implemented\n", type->name);
1561 }
1562 
add_union_typeinfo(struct sltg_typelib * typelib,type_t * type)1563 static void add_union_typeinfo(struct sltg_typelib *typelib, type_t *type)
1564 {
1565     error("add_union_typeinfo: %s not implemented\n", type->name);
1566 }
1567 
add_coclass_typeinfo(struct sltg_typelib * typelib,type_t * type)1568 static void add_coclass_typeinfo(struct sltg_typelib *typelib, type_t *type)
1569 {
1570     error("add_coclass_typeinfo: %s not implemented\n", type->name);
1571 }
1572 
add_type_typeinfo(struct sltg_typelib * typelib,type_t * type)1573 static void add_type_typeinfo(struct sltg_typelib *typelib, type_t *type)
1574 {
1575     chat("add_type_typeinfo: adding %s, type %d\n", type->name, type_get_type(type));
1576 
1577     switch (type_get_type(type))
1578     {
1579     case TYPE_INTERFACE:
1580         add_interface_typeinfo(typelib, type);
1581         break;
1582     case TYPE_STRUCT:
1583         add_structure_typeinfo(typelib, type);
1584         break;
1585     case TYPE_ENUM:
1586         add_enum_typeinfo(typelib, type);
1587         break;
1588     case TYPE_UNION:
1589         add_union_typeinfo(typelib, type);
1590         break;
1591     case TYPE_COCLASS:
1592         add_coclass_typeinfo(typelib, type);
1593         break;
1594     case TYPE_BASIC:
1595     case TYPE_POINTER:
1596         break;
1597     default:
1598         error("add_type_typeinfo: unhandled type %d for %s\n", type_get_type(type), type->name);
1599         break;
1600     }
1601 }
1602 
add_statement(struct sltg_typelib * typelib,const statement_t * stmt)1603 static void add_statement(struct sltg_typelib *typelib, const statement_t *stmt)
1604 {
1605     switch(stmt->type)
1606     {
1607     case STMT_LIBRARY:
1608     case STMT_IMPORT:
1609     case STMT_PRAGMA:
1610     case STMT_CPPQUOTE:
1611     case STMT_DECLARATION:
1612         /* not included in typelib */
1613         break;
1614     case STMT_IMPORTLIB:
1615         /* not processed here */
1616         break;
1617 
1618     case STMT_TYPEDEF:
1619     {
1620         const type_list_t *type_entry = stmt->u.type_list;
1621         for (; type_entry; type_entry = type_entry->next)
1622         {
1623             /* in old style typelibs all types are public */
1624             add_type_typeinfo(typelib, type_entry->type);
1625         }
1626         break;
1627     }
1628 
1629     case STMT_MODULE:
1630         add_module_typeinfo(typelib, stmt->u.type);
1631         break;
1632 
1633     case STMT_TYPE:
1634     case STMT_TYPEREF:
1635     {
1636         type_t *type = stmt->u.type;
1637         add_type_typeinfo(typelib, type);
1638         break;
1639     }
1640 
1641     default:
1642         error("add_statement: unhandled statement type %d\n", stmt->type);
1643         break;
1644     }
1645 }
1646 
sltg_write_header(struct sltg_typelib * sltg,int * library_block_start)1647 static void sltg_write_header(struct sltg_typelib *sltg, int *library_block_start)
1648 {
1649     char pad[0x40];
1650     struct sltg_header
1651     {
1652         int magic;
1653         short n_file_blocks;
1654         short res06;
1655         short size_of_index;
1656         short first_blk;
1657         GUID uuid;
1658         int res1c;
1659         int res20;
1660     } header;
1661     struct sltg_block_entry
1662     {
1663         int length;
1664         short index_string;
1665         short next;
1666     } entry;
1667     struct sltg_block *block;
1668     int i;
1669 
1670     header.magic = 0x47544c53;
1671     header.n_file_blocks = sltg->n_file_blocks + 1;
1672     header.res06 = 9;
1673     header.size_of_index = sltg->index.size;
1674     header.first_blk = 1;
1675     header.uuid = sltg_library_guid;
1676     header.res1c = 0x00000044;
1677     header.res20 = 0xffff0000;
1678 
1679     put_data(&header, sizeof(header));
1680 
1681     block = sltg->blocks;
1682     for (i = 0; i < sltg->n_file_blocks - 1; i++)
1683     {
1684         assert(block->next != NULL);
1685 
1686         entry.length = block->length;
1687         entry.index_string = block->index_string;
1688         entry.next = header.first_blk + i + 1;
1689         chat("sltg_write_header: writing block entry %d: length %#x, index_string %#x, next %#x\n",
1690              i, entry.length, entry.index_string, entry.next);
1691         put_data(&entry, sizeof(entry));
1692 
1693         block = block->next;
1694     }
1695 
1696     assert(block->next == NULL);
1697 
1698     /* library block length includes helpstrings and name table */
1699     entry.length = block->length + 0x40 + 2 + sltg->typeinfo_size + 4 + 6 + 12 + 0x200 + sltg->name_table.size + 12;
1700     entry.index_string = block->index_string;
1701     entry.next = 0;
1702     chat("sltg_write_header: writing library block entry %d: length %#x, index_string %#x, next %#x\n",
1703          i, entry.length, entry.index_string, entry.next);
1704     put_data(&entry, sizeof(entry));
1705 
1706     chat("sltg_write_header: writing index: %d bytes\n", sltg->index.size);
1707     put_data(sltg->index.data, sltg->index.size);
1708     memset(pad, 0, 9);
1709     put_data(pad, 9);
1710 
1711     block = sltg->blocks;
1712     for (i = 0; i < sltg->n_file_blocks - 1; i++)
1713     {
1714         chat("sltg_write_header: writing block %d: %d bytes\n", i, block->length);
1715 
1716         put_data(block->data, block->length);
1717         block = block->next;
1718     }
1719 
1720     assert(block->next == NULL);
1721 
1722     /* library block */
1723     chat("library_block_start = %#lx\n", (SIZE_T)output_buffer_pos);
1724     *library_block_start = output_buffer_pos;
1725     chat("sltg_write_header: writing library block %d: %d bytes\n", i, block->length);
1726     put_data(block->data, block->length);
1727 
1728     chat("sltg_write_header: writing pad 0x40 bytes\n");
1729     memset(pad, 0xff, 0x40);
1730     put_data(pad, 0x40);
1731 }
1732 
sltg_write_typeinfo(struct sltg_typelib * typelib)1733 static void sltg_write_typeinfo(struct sltg_typelib *typelib)
1734 {
1735     int i;
1736     struct sltg_block *block;
1737     short count = typelib->typeinfo_count;
1738 
1739     put_data(&count, sizeof(count));
1740 
1741     block = typelib->typeinfo;
1742     for (i = 0; i < typelib->typeinfo_count; i++)
1743     {
1744         chat("sltg_write_typeinfo: writing block %d: %d bytes\n", i, block->length);
1745 
1746         put_data(block->data, block->length);
1747         block = block->next;
1748     }
1749     assert(block == NULL);
1750 }
1751 
sltg_write_helpstrings(struct sltg_typelib * typelib)1752 static void sltg_write_helpstrings(struct sltg_typelib *typelib)
1753 {
1754     static const char dummy[6];
1755 
1756     chat("sltg_write_helpstrings: writing dummy 6 bytes\n");
1757 
1758     put_data(dummy, sizeof(dummy));
1759 }
1760 
sltg_write_nametable(struct sltg_typelib * typelib)1761 static void sltg_write_nametable(struct sltg_typelib *typelib)
1762 {
1763     static const short dummy[6] = { 0xffff,1,2,0xff00,0xffff,0xffff };
1764     char pad[0x200];
1765 
1766     chat("sltg_write_nametable: writing 12+0x200+%d bytes\n", typelib->name_table.size);
1767 
1768     put_data(dummy, sizeof(dummy));
1769     memset(pad, 0xff, 0x200);
1770     put_data(pad, 0x200);
1771     put_data(&typelib->name_table.size, sizeof(typelib->name_table.size));
1772     put_data(typelib->name_table.data, typelib->name_table.size);
1773 }
1774 
sltg_write_remainder(void)1775 static void sltg_write_remainder(void)
1776 {
1777     static const short dummy1[] = { 1,0xfffe,0x0a03,0,0xffff,0xffff };
1778     static const short dummy2[] = { 0xffff,0xffff,0x0200,0,0,0 };
1779     static const char dummy3[] = { 0xf4,0x39,0xb2,0x71,0,0,0,0,0,0,0,0,0,0,0,0 };
1780     static const char TYPELIB[] = { 8,0,0,0,'T','Y','P','E','L','I','B',0 };
1781     int pad;
1782 
1783     pad = 0x01ffff01;
1784     put_data(&pad, sizeof(pad));
1785     pad = 0;
1786     put_data(&pad, sizeof(pad));
1787 
1788     put_data(dummy1, sizeof(dummy1));
1789 
1790     put_data(&sltg_library_guid, sizeof(sltg_library_guid));
1791 
1792     put_data(TYPELIB, sizeof(TYPELIB));
1793 
1794     put_data(dummy2, sizeof(dummy2));
1795     put_data(dummy3, sizeof(dummy3));
1796 }
1797 
save_all_changes(struct sltg_typelib * typelib)1798 static void save_all_changes(struct sltg_typelib *typelib)
1799 {
1800     int library_block_start;
1801     int *name_table_offset;
1802 
1803     sltg_write_header(typelib, &library_block_start);
1804     sltg_write_typeinfo(typelib);
1805 
1806     name_table_offset = (int *)(output_buffer + output_buffer_pos);
1807     chat("name_table_offset = %#lx\n", (SIZE_T)output_buffer_pos);
1808     put_data(&library_block_start, sizeof(library_block_start));
1809 
1810     sltg_write_helpstrings(typelib);
1811 
1812     *name_table_offset = output_buffer_pos - library_block_start;
1813     chat("*name_table_offset = %#x\n", *name_table_offset);
1814 
1815     sltg_write_nametable(typelib);
1816     sltg_write_remainder();
1817 
1818     if (strendswith(typelib_name, ".res")) /* create a binary resource file */
1819     {
1820         char typelib_id[13] = "#1";
1821 
1822         expr_t *expr = get_attrp(typelib->typelib->attrs, ATTR_ID);
1823         if (expr)
1824             sprintf(typelib_id, "#%d", expr->cval);
1825         add_output_to_resources("TYPELIB", typelib_id);
1826         output_typelib_regscript(typelib->typelib);
1827     }
1828     else flush_output_buffer(typelib_name);
1829 }
1830 
create_sltg_typelib(typelib_t * typelib)1831 int create_sltg_typelib(typelib_t *typelib)
1832 {
1833     struct sltg_typelib sltg;
1834     const statement_t *stmt;
1835     void *library_block;
1836     int library_block_size, library_block_index;
1837 
1838     sltg.typelib = typelib;
1839     sltg.typeinfo_count = 0;
1840     sltg.typeinfo_size = 0;
1841     sltg.typeinfo = NULL;
1842     sltg.blocks = NULL;
1843     sltg.n_file_blocks = 0;
1844     sltg.first_block = 1;
1845 
1846     init_index(&sltg.index);
1847     init_name_table(&sltg);
1848     init_library(&sltg);
1849 
1850     library_block = create_library_block(&sltg, &library_block_size, &library_block_index);
1851 
1852     if (typelib->stmts)
1853         LIST_FOR_EACH_ENTRY(stmt, typelib->stmts, const statement_t, entry)
1854             add_statement(&sltg, stmt);
1855 
1856     add_block_index(&sltg, library_block, library_block_size, library_block_index);
1857 
1858     save_all_changes(&sltg);
1859 
1860     return 1;
1861 }
1862