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