Add support for optional arguments and some suppport for the
[wine] / tools / widl / write_msft.c
1 /*
2  *      Typelib v2 (MSFT) generation
3  *
4  *      Copyright 2004  Alastair Bridgewater
5  *                2004, 2005 Huw Davies
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * --------------------------------------------------------------------------------------
22  *  Known problems:
23  *
24  *    Badly incomplete.
25  *
26  *    Only works on little-endian systems.
27  *
28  */
29
30 #include "config.h"
31 #include "wine/port.h"
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <ctype.h>
38
39 #define NONAMELESSUNION
40 #define NONAMELESSSTRUCT
41
42 #include "winerror.h"
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winnls.h"
46
47 #include "wine/unicode.h"
48
49 #include "widltypes.h"
50 #include "typelib.h"
51 #include "typelib_struct.h"
52 #include "utils.h"
53 #include "hash.h"
54
55 enum MSFT_segment_index {
56     MSFT_SEG_TYPEINFO = 0,  /* type information */
57     MSFT_SEG_IMPORTINFO,    /* import information */
58     MSFT_SEG_IMPORTFILES,   /* import filenames */
59     MSFT_SEG_REFERENCES,    /* references (?) */
60     MSFT_SEG_GUIDHASH,      /* hash table for guids? */
61     MSFT_SEG_GUID,          /* guid storage */
62     MSFT_SEG_NAMEHASH,      /* hash table for names */
63     MSFT_SEG_NAME,          /* name storage */
64     MSFT_SEG_STRING,        /* string storage */
65     MSFT_SEG_TYPEDESC,      /* type descriptions */
66     MSFT_SEG_ARRAYDESC,     /* array descriptions */
67     MSFT_SEG_CUSTDATA,      /* custom data */
68     MSFT_SEG_CUSTDATAGUID,  /* custom data guids */
69     MSFT_SEG_UNKNOWN,       /* ??? */
70     MSFT_SEG_UNKNOWN2,      /* ??? */
71     MSFT_SEG_MAX            /* total number of segments */
72 };
73
74 typedef struct tagMSFT_ImpFile {
75     int guid;
76     LCID lcid;
77     int version;
78     char filename[0]; /* preceeded by two bytes of encoded (length << 2) + flags in the low two bits. */
79 } MSFT_ImpFile;
80
81 typedef struct _msft_typelib_t
82 {
83     typelib_t *typelib;
84     MSFT_Header typelib_header;
85     MSFT_pSeg typelib_segdir[MSFT_SEG_MAX];
86     char *typelib_segment_data[MSFT_SEG_MAX];
87     int typelib_segment_block_length[MSFT_SEG_MAX];
88
89     INT typelib_typeinfo_offsets[0x200]; /* Hope that's enough. */
90
91     INT *typelib_namehash_segment;
92     INT *typelib_guidhash_segment;
93
94     struct _msft_typeinfo_t *typeinfos;
95     struct _msft_typeinfo_t *last_typeinfo;
96 } msft_typelib_t;
97
98 typedef struct _msft_typeinfo_t
99 {
100     msft_typelib_t *typelib;
101     MSFT_TypeInfoBase *typeinfo;
102
103     INT *typedata;
104     int typedata_allocated;
105     int typedata_length;
106
107     int indices[42];
108     int names[42];
109     int offsets[42];
110
111     int datawidth;
112
113     struct _msft_typeinfo_t *next_typeinfo;
114 } msft_typeinfo_t;
115
116
117
118 /*================== Internal functions ===================================*/
119
120 /****************************************************************************
121  *      ctl2_init_header
122  *
123  *  Initializes the type library header of a new typelib.
124  */
125 static void ctl2_init_header(
126         msft_typelib_t *typelib) /* [I] The typelib to initialize. */
127 {
128     typelib->typelib_header.magic1 = 0x5446534d;
129     typelib->typelib_header.magic2 = 0x00010002;
130     typelib->typelib_header.posguid = -1;
131     typelib->typelib_header.lcid = 0x0409; /* or do we use the current one? */
132     typelib->typelib_header.lcid2 = 0x0;
133     typelib->typelib_header.varflags = 0x40;
134     typelib->typelib_header.version = 0;
135     typelib->typelib_header.flags = 0;
136     typelib->typelib_header.nrtypeinfos = 0;
137     typelib->typelib_header.helpstring = -1;
138     typelib->typelib_header.helpstringcontext = 0;
139     typelib->typelib_header.helpcontext = 0;
140     typelib->typelib_header.nametablecount = 0;
141     typelib->typelib_header.nametablechars = 0;
142     typelib->typelib_header.NameOffset = -1;
143     typelib->typelib_header.helpfile = -1;
144     typelib->typelib_header.CustomDataOffset = -1;
145     typelib->typelib_header.res44 = 0x20;
146     typelib->typelib_header.res48 = 0x80;
147     typelib->typelib_header.dispatchpos = -1;
148     typelib->typelib_header.res50 = 0;
149 }
150
151 /****************************************************************************
152  *      ctl2_init_segdir
153  *
154  *  Initializes the segment directory of a new typelib.
155  */
156 static void ctl2_init_segdir(
157         msft_typelib_t *typelib) /* [I] The typelib to initialize. */
158 {
159     int i;
160     MSFT_pSeg *segdir;
161
162     segdir = &typelib->typelib_segdir[MSFT_SEG_TYPEINFO];
163
164     for (i = 0; i < 15; i++) {
165         segdir[i].offset = -1;
166         segdir[i].length = 0;
167         segdir[i].res08 = -1;
168         segdir[i].res0c = 0x0f;
169     }
170 }
171
172 /****************************************************************************
173  *      ctl2_hash_guid
174  *
175  *  Generates a hash key from a GUID.
176  *
177  * RETURNS
178  *
179  *  The hash key for the GUID.
180  */
181 static int ctl2_hash_guid(
182         REFGUID guid)                /* [I] The guid to find. */
183 {
184     int hash;
185     int i;
186
187     hash = 0;
188     for (i = 0; i < 8; i ++) {
189         hash ^= ((const short *)guid)[i];
190     }
191
192     return (hash & 0xf) | ((hash & 0x10) & (0 - !!(hash & 0xe0)));
193 }
194
195 /****************************************************************************
196  *      ctl2_find_guid
197  *
198  *  Locates a guid in a type library.
199  *
200  * RETURNS
201  *
202  *  The offset into the GUID segment of the guid, or -1 if not found.
203  */
204 static int ctl2_find_guid(
205         msft_typelib_t *typelib,   /* [I] The typelib to operate against. */
206         int hash_key,              /* [I] The hash key for the guid. */
207         REFGUID guid)              /* [I] The guid to find. */
208 {
209     int offset;
210     MSFT_GuidEntry *guidentry;
211
212     offset = typelib->typelib_guidhash_segment[hash_key];
213     while (offset != -1) {
214         guidentry = (MSFT_GuidEntry *)&typelib->typelib_segment_data[MSFT_SEG_GUID][offset];
215
216         if (!memcmp(guidentry, guid, sizeof(GUID))) return offset;
217
218         offset = guidentry->next_hash;
219     }
220
221     return offset;
222 }
223
224 /****************************************************************************
225  *      ctl2_find_name
226  *
227  *  Locates a name in a type library.
228  *
229  * RETURNS
230  *
231  *  The offset into the NAME segment of the name, or -1 if not found.
232  *
233  * NOTES
234  *
235  *  The name must be encoded as with ctl2_encode_name().
236  */
237 static int ctl2_find_name(
238         msft_typelib_t *typelib,   /* [I] The typelib to operate against. */
239         char *name)                /* [I] The encoded name to find. */
240 {
241     int offset;
242     int *namestruct;
243
244     offset = typelib->typelib_namehash_segment[name[2] & 0x7f];
245     while (offset != -1) {
246         namestruct = (int *)&typelib->typelib_segment_data[MSFT_SEG_NAME][offset];
247
248         if (!((namestruct[2] ^ *((int *)name)) & 0xffff00ff)) {
249             /* hash codes and lengths match, final test */
250             if (!strncasecmp(name+4, (void *)(namestruct+3), name[0])) break;
251         }
252
253         /* move to next item in hash bucket */
254         offset = namestruct[1];
255     }
256
257     return offset;
258 }
259
260 /****************************************************************************
261  *      ctl2_encode_name
262  *
263  *  Encodes a name string to a form suitable for storing into a type library
264  *  or comparing to a name stored in a type library.
265  *
266  * RETURNS
267  *
268  *  The length of the encoded name, including padding and length+hash fields.
269  *
270  * NOTES
271  *
272  *  Will throw an exception if name or result are NULL. Is not multithread
273  *  safe in the slightest.
274  */
275 static int ctl2_encode_name(
276         msft_typelib_t *typelib,   /* [I] The typelib to operate against (used for LCID only). */
277         const char *name,          /* [I] The name string to encode. */
278         char **result)             /* [O] A pointer to a pointer to receive the encoded name. */
279 {
280     int length;
281     static char converted_name[0x104];
282     int offset;
283     int value;
284
285     length = strlen(name);
286     memcpy(converted_name + 4, name, length);
287     converted_name[0] = length & 0xff;
288
289     converted_name[length + 4] = 0;
290
291     converted_name[1] = 0x00;
292
293     value = lhash_val_of_name_sys(typelib->typelib_header.varflags & 0x0f, typelib->typelib_header.lcid, converted_name + 4);
294
295     converted_name[2] = value;
296     converted_name[3] = value >> 8;
297
298     for (offset = (4 - length) & 3; offset; offset--) converted_name[length + offset + 3] = 0x57;
299
300     *result = converted_name;
301
302     return (length + 7) & ~3;
303 }
304
305 /****************************************************************************
306  *      ctl2_encode_string
307  *
308  *  Encodes a string to a form suitable for storing into a type library or
309  *  comparing to a string stored in a type library.
310  *
311  * RETURNS
312  *
313  *  The length of the encoded string, including padding and length fields.
314  *
315  * NOTES
316  *
317  *  Will throw an exception if string or result are NULL. Is not multithread
318  *  safe in the slightest.
319  */
320 static int ctl2_encode_string(
321         msft_typelib_t *typelib,   /* [I] The typelib to operate against (not used?). */
322         const char *string,        /* [I] The string to encode. */
323         char **result)             /* [O] A pointer to a pointer to receive the encoded string. */
324 {
325     int length;
326     static char converted_string[0x104];
327     int offset;
328
329     length = strlen(string);
330     memcpy(converted_string + 2, string, length);
331     converted_string[0] = length & 0xff;
332     converted_string[1] = (length >> 8) & 0xff;
333
334     for (offset = (4 - (length + 2)) & 3; offset; offset--) converted_string[length + offset + 1] = 0x57;
335
336     *result = converted_string;
337
338     return (length + 5) & ~3;
339 }
340
341 /****************************************************************************
342  *      ctl2_alloc_segment
343  *
344  *  Allocates memory from a segment in a type library.
345  *
346  * RETURNS
347  *
348  *  Success: The offset within the segment of the new data area.
349  *  Failure: -1 (this is invariably an out of memory condition).
350  *
351  * BUGS
352  *
353  *  Does not (yet) handle the case where the allocated segment memory needs to grow.
354  */
355 static int ctl2_alloc_segment(
356         msft_typelib_t *typelib,         /* [I] The type library in which to allocate. */
357         enum MSFT_segment_index segment, /* [I] The segment in which to allocate. */
358         int size,                        /* [I] The amount to allocate. */
359         int block_size)                  /* [I] Initial allocation block size, or 0 for default. */
360 {
361     int offset;
362
363     if(!typelib->typelib_segment_data[segment]) {
364         if (!block_size) block_size = 0x2000;
365
366         typelib->typelib_segment_block_length[segment] = block_size;
367         typelib->typelib_segment_data[segment] = xmalloc(block_size);
368         if (!typelib->typelib_segment_data[segment]) return -1;
369         memset(typelib->typelib_segment_data[segment], 0x57, block_size);
370     }
371
372     while ((typelib->typelib_segdir[segment].length + size) > typelib->typelib_segment_block_length[segment]) {
373         char *block;
374
375         block_size = typelib->typelib_segment_block_length[segment];
376         block = realloc(typelib->typelib_segment_data[segment], block_size << 1);
377         if (!block) return -1;
378
379         if (segment == MSFT_SEG_TYPEINFO) {
380             /* TypeInfos have a direct pointer to their memory space, so we have to fix them up. */
381             msft_typeinfo_t *typeinfo;
382
383             for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
384                 typeinfo->typeinfo = (void *)&block[((char *)typeinfo->typeinfo) - typelib->typelib_segment_data[segment]];
385             }
386         }
387
388         memset(block + block_size, 0x57, block_size);
389         typelib->typelib_segment_block_length[segment] = block_size << 1;
390         typelib->typelib_segment_data[segment] = block;
391     }
392
393     offset = typelib->typelib_segdir[segment].length;
394     typelib->typelib_segdir[segment].length += size;
395
396     return offset;
397 }
398
399 /****************************************************************************
400  *      ctl2_alloc_typeinfo
401  *
402  *  Allocates and initializes a typeinfo structure in a type library.
403  *
404  * RETURNS
405  *
406  *  Success: The offset of the new typeinfo.
407  *  Failure: -1 (this is invariably an out of memory condition).
408  */
409 static int ctl2_alloc_typeinfo(
410         msft_typelib_t *typelib,   /* [I] The type library to allocate in. */
411         int nameoffset)            /* [I] The offset of the name for this typeinfo. */
412 {
413     int offset;
414     MSFT_TypeInfoBase *typeinfo;
415
416     offset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEINFO, sizeof(MSFT_TypeInfoBase), 0);
417     if (offset == -1) return -1;
418
419     typelib->typelib_typeinfo_offsets[typelib->typelib_header.nrtypeinfos++] = offset;
420
421     typeinfo = (void *)(typelib->typelib_segment_data[MSFT_SEG_TYPEINFO] + offset);
422
423     typeinfo->typekind = (typelib->typelib_header.nrtypeinfos - 1) << 16;
424     typeinfo->memoffset = -1; /* should be EOF if no elements */
425     typeinfo->res2 = 0;
426     typeinfo->res3 = -1;
427     typeinfo->res4 = 3;
428     typeinfo->res5 = 0;
429     typeinfo->cElement = 0;
430     typeinfo->res7 = 0;
431     typeinfo->res8 = 0;
432     typeinfo->res9 = 0;
433     typeinfo->resA = 0;
434     typeinfo->posguid = -1;
435     typeinfo->flags = 0;
436     typeinfo->NameOffset = nameoffset;
437     typeinfo->version = 0;
438     typeinfo->docstringoffs = -1;
439     typeinfo->helpstringcontext = 0;
440     typeinfo->helpcontext = 0;
441     typeinfo->oCustData = -1;
442     typeinfo->cbSizeVft = 0;
443     typeinfo->cImplTypes = 0;
444     typeinfo->size = 0;
445     typeinfo->datatype1 = -1;
446     typeinfo->datatype2 = 0;
447     typeinfo->res18 = 0;
448     typeinfo->res19 = -1;
449
450     return offset;
451 }
452
453 /****************************************************************************
454  *      ctl2_alloc_guid
455  *
456  *  Allocates and initializes a GUID structure in a type library. Also updates
457  *  the GUID hash table as needed.
458  *
459  * RETURNS
460  *
461  *  Success: The offset of the new GUID.
462  *  Failure: -1 (this is invariably an out of memory condition).
463  */
464 static int ctl2_alloc_guid(
465         msft_typelib_t *typelib,   /* [I] The type library to allocate in. */
466         MSFT_GuidEntry *guid)      /* [I] The GUID to store. */
467 {
468     int offset;
469     MSFT_GuidEntry *guid_space;
470     int hash_key;
471
472     hash_key = ctl2_hash_guid(&guid->guid);
473
474     offset = ctl2_find_guid(typelib, hash_key, &guid->guid);
475     if (offset != -1) return offset;
476
477     offset = ctl2_alloc_segment(typelib, MSFT_SEG_GUID, sizeof(MSFT_GuidEntry), 0);
478     if (offset == -1) return -1;
479
480     guid_space = (void *)(typelib->typelib_segment_data[MSFT_SEG_GUID] + offset);
481     *guid_space = *guid;
482
483     guid_space->next_hash = typelib->typelib_guidhash_segment[hash_key];
484     typelib->typelib_guidhash_segment[hash_key] = offset;
485
486     return offset;
487 }
488
489 /****************************************************************************
490  *      ctl2_alloc_name
491  *
492  *  Allocates and initializes a name within a type library. Also updates the
493  *  name hash table as needed.
494  *
495  * RETURNS
496  *
497  *  Success: The offset within the segment of the new name.
498  *  Failure: -1 (this is invariably an out of memory condition).
499  */
500 static int ctl2_alloc_name(
501         msft_typelib_t *typelib,  /* [I] The type library to allocate in. */
502         const char *name)         /* [I] The name to store. */
503 {
504     int length;
505     int offset;
506     MSFT_NameIntro *name_space;
507     char *encoded_name;
508
509     length = ctl2_encode_name(typelib, name, &encoded_name);
510
511     offset = ctl2_find_name(typelib, encoded_name);
512     if (offset != -1) return offset;
513
514     offset = ctl2_alloc_segment(typelib, MSFT_SEG_NAME, length + 8, 0);
515     if (offset == -1) return -1;
516
517     name_space = (void *)(typelib->typelib_segment_data[MSFT_SEG_NAME] + offset);
518     name_space->hreftype = -1;
519     name_space->next_hash = -1;
520     memcpy(&name_space->namelen, encoded_name, length);
521
522     if (typelib->typelib_namehash_segment[encoded_name[2] & 0x7f] != -1)
523         name_space->next_hash = typelib->typelib_namehash_segment[encoded_name[2] & 0x7f];
524
525     typelib->typelib_namehash_segment[encoded_name[2] & 0x7f] = offset;
526
527     typelib->typelib_header.nametablecount += 1;
528     typelib->typelib_header.nametablechars += *encoded_name;
529
530     return offset;
531 }
532
533 /****************************************************************************
534  *      ctl2_alloc_string
535  *
536  *  Allocates and initializes a string in a type library.
537  *
538  * RETURNS
539  *
540  *  Success: The offset within the segment of the new string.
541  *  Failure: -1 (this is invariably an out of memory condition).
542  */
543 static int ctl2_alloc_string(
544         msft_typelib_t *typelib,  /* [I] The type library to allocate in. */
545         const char *string)       /* [I] The string to store. */
546 {
547     int length;
548     int offset;
549     char *string_space;
550     char *encoded_string;
551
552     length = ctl2_encode_string(typelib, string, &encoded_string);
553
554     for (offset = 0; offset < typelib->typelib_segdir[MSFT_SEG_STRING].length;
555          offset += ((((typelib->typelib_segment_data[MSFT_SEG_STRING][offset + 1] << 8) & 0xff)
556              | (typelib->typelib_segment_data[MSFT_SEG_STRING][offset + 0] & 0xff)) + 5) & ~3) {
557         if (!memcmp(encoded_string, typelib->typelib_segment_data[MSFT_SEG_STRING] + offset, length)) return offset;
558     }
559
560     offset = ctl2_alloc_segment(typelib, MSFT_SEG_STRING, length, 0);
561     if (offset == -1) return -1;
562
563     string_space = typelib->typelib_segment_data[MSFT_SEG_STRING] + offset;
564     memcpy(string_space, encoded_string, length);
565
566     return offset;
567 }
568
569 /****************************************************************************
570  *      ctl2_alloc_importinfo
571  *
572  *  Allocates and initializes an import information structure in a type library.
573  *
574  * RETURNS
575  *
576  *  Success: The offset of the new importinfo.
577  *  Failure: -1 (this is invariably an out of memory condition).
578  */
579 static int ctl2_alloc_importinfo(
580         msft_typelib_t *typelib,   /* [I] The type library to allocate in. */
581         MSFT_ImpInfo *impinfo)     /* [I] The import information to store. */
582 {
583     int offset;
584     MSFT_ImpInfo *impinfo_space;
585
586     for (offset = 0;
587          offset < typelib->typelib_segdir[MSFT_SEG_IMPORTINFO].length;
588          offset += sizeof(MSFT_ImpInfo)) {
589         if (!memcmp(&(typelib->typelib_segment_data[MSFT_SEG_IMPORTINFO][offset]),
590                     impinfo, sizeof(MSFT_ImpInfo))) {
591             return offset;
592         }
593     }
594
595     offset = ctl2_alloc_segment(typelib, MSFT_SEG_IMPORTINFO, sizeof(MSFT_ImpInfo), 0);
596     if (offset == -1) return -1;
597
598     impinfo_space = (void *)(typelib->typelib_segment_data[MSFT_SEG_IMPORTINFO] + offset);
599     *impinfo_space = *impinfo;
600
601     return offset;
602 }
603
604 /****************************************************************************
605  *      ctl2_alloc_importfile
606  *
607  *  Allocates and initializes an import file definition in a type library.
608  *
609  * RETURNS
610  *
611  *  Success: The offset of the new importinfo.
612  *  Failure: -1 (this is invariably an out of memory condition).
613  */
614 static int ctl2_alloc_importfile(
615         msft_typelib_t *typelib,   /* [I] The type library to allocate in. */
616         int guidoffset,            /* [I] The offset to the GUID for the imported library. */
617         int major_version,         /* [I] The major version number of the imported library. */
618         int minor_version,         /* [I] The minor version number of the imported library. */
619         const char *filename)      /* [I] The filename of the imported library. */
620 {
621     int length;
622     int offset;
623     MSFT_ImpFile *importfile;
624     char *encoded_string;
625
626     length = ctl2_encode_string(typelib, filename, &encoded_string);
627
628     encoded_string[0] <<= 2;
629     encoded_string[0] |= 1;
630
631     for (offset = 0; offset < typelib->typelib_segdir[MSFT_SEG_IMPORTFILES].length;
632          offset += ((((typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xd] << 8) & 0xff)
633              | (typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xc] & 0xff)) >> 2) + 0xc) {
634         if (!memcmp(encoded_string, typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES] + offset + 0xc, length)) return offset;
635     }
636
637     offset = ctl2_alloc_segment(typelib, MSFT_SEG_IMPORTFILES, length + 0xc, 0);
638     if (offset == -1) return -1;
639
640     importfile = (MSFT_ImpFile *)&typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset];
641     importfile->guid = guidoffset;
642     importfile->lcid = typelib->typelib_header.lcid2;
643     importfile->version = major_version | (minor_version << 16);
644     memcpy(&importfile->filename, encoded_string, length);
645
646     return offset;
647 }
648
649
650 /****************************************************************************
651  *      ctl2_encode_type
652  *
653  *  Encodes a type, storing information in the TYPEDESC and ARRAYDESC
654  *  segments as needed.
655  *
656  * RETURNS
657  *
658  *  Success: 0.
659  *  Failure: -1.
660  */
661 static int ctl2_encode_type(
662         msft_typelib_t *typelib,   /* [I] The type library in which to encode the TYPEDESC. */
663         type_t *type,              /* [I] The type description to encode. */
664         int ptr_level,             /* [I] ptr level */
665         expr_t *array,             /* [I] arrary description */
666         int *encoded_type,         /* [O] The encoded type description. */
667         int *width,                /* [O] The width of the type, or NULL. */
668         int *alignment,            /* [O] The alignment of the type, or NULL. */
669         int *decoded_size)         /* [O] The total size of the unencoded TYPEDESCs, including nested descs. */
670 {
671     int default_type;
672     int scratch;
673     int typeoffset;
674     int arrayoffset;
675     int *typedata;
676     int *arraydata;
677     int target_type;
678     int child_size;
679     unsigned short vt = get_type_vt(type);
680
681     chat("encode_type vt %d ptr_level %d\n", vt, ptr_level);
682
683     default_type = 0x80000000 | (vt << 16) | vt;
684     if (!width) width = &scratch;
685     if (!alignment) alignment = &scratch;
686     if (!decoded_size) decoded_size = &scratch;
687
688     *decoded_size = 0;
689
690     if(ptr_level--) {
691
692         ctl2_encode_type(typelib, type, ptr_level, array, &target_type, NULL, NULL, &child_size);
693
694         for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
695             typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
696             if (((typedata[0] & 0xffff) == VT_PTR) && (typedata[1] == target_type)) break;
697         }
698
699         if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
700             int mix_field;
701             
702             if (target_type & 0x80000000) {
703                 mix_field = ((target_type >> 16) & 0x3fff) | VT_BYREF;
704             } else {
705                 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type];
706                 mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
707             }
708
709             typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0);
710             typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
711
712             typedata[0] = (mix_field << 16) | VT_PTR;
713             typedata[1] = target_type;
714         }
715
716         *encoded_type = typeoffset;
717
718         *width = 4;
719         *alignment = 4;
720         *decoded_size = 8 /*sizeof(TYPEDESC)*/ + child_size;
721         return 0;
722     }
723
724     if(array) {
725         expr_t *dim = array;
726         int num_dims = 1, elements = 1;
727
728         while(NEXT_LINK(dim)) {
729             dim = NEXT_LINK(dim);
730             num_dims++;
731         }
732         chat("array with %d dimensions\n", num_dims);
733         ctl2_encode_type(typelib, type, 0, NULL, &target_type, width, alignment, NULL);
734         arrayoffset = ctl2_alloc_segment(typelib, MSFT_SEG_ARRAYDESC, (2 + 2 * num_dims) * sizeof(long), 0);
735         arraydata = (void *)&typelib->typelib_segment_data[MSFT_SEG_ARRAYDESC][arrayoffset];
736
737         arraydata[0] = target_type;
738         arraydata[1] = num_dims;
739         arraydata[1] |= ((num_dims * 2 * sizeof(long)) << 16);
740
741         arraydata += 2;
742         while(dim) {
743             arraydata[0] = dim->cval;
744             arraydata[1] = 0;
745             arraydata += 2;
746             elements *= dim->cval;
747             dim = PREV_LINK(dim);
748         }
749
750         typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0);
751         typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
752
753         typedata[0] = (0x7ffe << 16) | VT_CARRAY;
754         typedata[1] = arrayoffset;
755
756         *encoded_type = typeoffset;
757         *width = *width * elements;
758         *decoded_size = 20 /*sizeof(ARRAYDESC)*/ + (num_dims - 1) * 8 /*sizeof(SAFEARRAYBOUND)*/;
759         return 0;
760     }
761
762     switch (vt) {
763     case VT_I1:
764     case VT_UI1:
765         *encoded_type = default_type;
766         *width = 1;
767         *alignment = 1;
768         break;
769
770     case VT_INT:
771         *encoded_type = 0x80000000 | (VT_I4 << 16) | VT_INT;
772         if ((typelib->typelib_header.varflags & 0x0f) == SYS_WIN16) {
773             *width = 2;
774             *alignment = 2;
775         } else {
776             *width = 4;
777             *alignment = 4;
778         }
779         break;
780
781     case VT_UINT:
782         *encoded_type = 0x80000000 | (VT_UI4 << 16) | VT_UINT;
783         if ((typelib->typelib_header.varflags & 0x0f) == SYS_WIN16) {
784             *width = 2;
785             *alignment = 2;
786         } else {
787             *width = 4;
788             *alignment = 4;
789         }
790         break;
791
792     case VT_UI2:
793     case VT_I2:
794     case VT_BOOL:
795         *encoded_type = default_type;
796         *width = 2;
797         *alignment = 2;
798         break;
799
800     case VT_I4:
801     case VT_UI4:
802     case VT_R4:
803     case VT_ERROR:
804     case VT_BSTR:
805     case VT_HRESULT:
806         *encoded_type = default_type;
807         *width = 4;
808         *alignment = 4;
809         break;
810
811     case VT_CY:
812         *encoded_type = default_type;
813         *width = 8;
814         *alignment = 4; /* guess? */
815         break;
816
817     case VT_VOID:
818         *encoded_type = 0x80000000 | (VT_EMPTY << 16) | vt;
819         *width = 0;
820         *alignment = 1;
821         break;
822
823 #if 0
824
825
826     case VT_SAFEARRAY:
827         /* FIXME: Make with the error checking. */
828         FIXME("SAFEARRAY vartype, may not work correctly.\n");
829
830         ctl2_encode_typedesc(typelib, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size);
831
832         for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
833             typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
834             if (((typedata[0] & 0xffff) == VT_SAFEARRAY) && (typedata[1] == target_type)) break;
835         }
836
837         if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
838             int mix_field;
839             
840             if (target_type & 0x80000000) {
841                 mix_field = ((target_type >> 16) & VT_TYPEMASK) | VT_ARRAY;
842             } else {
843                 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type];
844                 mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
845             }
846
847             typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0);
848             typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
849
850             typedata[0] = (mix_field << 16) | VT_SAFEARRAY;
851             typedata[1] = target_type;
852         }
853
854         *encoded_tdesc = typeoffset;
855
856         *width = 4;
857         *alignment = 4;
858         *decoded_size = sizeof(TYPEDESC) + child_size;
859         break;
860
861
862 #endif
863
864     case VT_USERDEFINED:
865       {
866         int typeinfo_offset;
867         chat("USERDEFINED.\n");
868         chat("type %p name = %s idx %d\n", type, type->name, type->typelib_idx);
869
870         if(type->typelib_idx == -1)
871             error("trying to ref not added type\n");
872
873         typeinfo_offset = typelib->typelib_typeinfo_offsets[type->typelib_idx];
874         for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
875             typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
876             if ((typedata[0] == ((0x7fff << 16) | VT_USERDEFINED)) && (typedata[1] == typeinfo_offset)) break;
877         }
878
879         if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
880             typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0);
881             typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
882
883             typedata[0] = (0x7fff << 16) | VT_USERDEFINED;
884             typedata[1] = typeinfo_offset;
885         }
886
887         *encoded_type = typeoffset;
888         *width = 0;
889         *alignment = 1;
890         break;
891       }
892
893     default:
894         error("Unrecognized type %d.\n", vt);
895         *encoded_type = default_type;
896         *width = 0;
897         *alignment = 1;
898         break;
899     }
900
901     return 0;
902 }
903
904 /****************************************************************************
905  *      ctl2_find_nth_reference
906  *
907  *  Finds a reference by index into the linked list of reference records.
908  *
909  * RETURNS
910  *
911  *  Success: Offset of the desired reference record.
912  *  Failure: -1.
913  */
914 static int ctl2_find_nth_reference(
915         msft_typelib_t *typelib,   /* [I] The type library in which to search. */
916         int offset,                /* [I] The starting offset of the reference list. */
917         int index)                 /* [I] The index of the reference to find. */
918 {
919     MSFT_RefRecord *ref;
920
921     for (; index && (offset != -1); index--) {
922         ref = (MSFT_RefRecord *)&typelib->typelib_segment_data[MSFT_SEG_REFERENCES][offset];
923         offset = ref->onext;
924     }
925
926     return offset;
927 }
928
929
930 static void write_value(msft_typeinfo_t* typeinfo, int *out, var_t *arg, int type, void *value)
931 {
932     int vt = (type >> 16) & 0x1ff;
933     switch(vt) {
934     case VT_I2:
935     case VT_I4:
936     case VT_R4:
937     case VT_BOOL:
938     case VT_I1:
939     case VT_UI1:
940     case VT_UI2:
941     case VT_UI4:
942     case VT_INT:
943     case VT_UINT:
944     case VT_HRESULT:
945       {
946         unsigned long *lv = value;
947         if((*lv & 0x3ffffff) == *lv) {
948             *out = 0x80000000;
949             *out |= vt << 26;
950             *out |= *lv;
951         } else {
952             int offset = ctl2_alloc_segment(typeinfo->typelib, MSFT_SEG_CUSTDATA, 8, 0);
953             *((unsigned short *)&typeinfo->typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset]) = vt;
954             memcpy(&typeinfo->typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+2], value, 4);
955             *((unsigned short *)&typeinfo->typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+6]) = 0x5757;
956             *out = offset;
957         }
958         return;
959       }
960     case VT_BSTR:
961         warning("default value BSTR %s\n", (char*)value);
962         break;
963
964       default:
965           warning("can't write value of type %d yet\n", vt);
966     }
967     return;
968 }
969
970 static HRESULT add_func_desc(msft_typeinfo_t* typeinfo, func_t *func)
971 {
972     int offset;
973     int *typedata;
974     int i, index = func->idx, id;
975     int decoded_size;
976     int num_params = 0, num_defaults = 0;
977     var_t *arg, *last_arg = NULL;
978     char *namedata;
979     attr_t *attr;
980     unsigned int funcflags = 0, callconv = 4;
981
982     id = ((0x6000 | typeinfo->typeinfo->cImplTypes) << 16) | index;
983
984     chat("(%p,%d)\n", typeinfo, index);
985     
986     if (!typeinfo->typedata) {
987         typeinfo->typedata = xmalloc(0x2000);
988         typeinfo->typedata[0] = 0;
989     }
990
991     for(arg = func->args; arg; arg = NEXT_LINK(arg)) {
992         last_arg = arg;
993         num_params++;
994         for(attr = arg->attrs; attr; attr = NEXT_LINK(attr)) {
995             if(attr->type == ATTR_DEFAULTVALUE_EXPR || attr->type == ATTR_DEFAULTVALUE_STRING) {
996                 num_defaults++;
997                 break;
998             }
999         }
1000     }
1001
1002     chat("num of params %d\n", num_params);
1003
1004     for(attr = func->def->attrs; attr; attr = NEXT_LINK(attr)) {
1005         switch(attr->type) {
1006         case ATTR_ID:
1007           {
1008             expr_t *expr = attr->u.pval; 
1009             id = expr->u.lval;
1010             break;
1011           }
1012         case ATTR_OUT:
1013             break;
1014
1015         default:
1016             warning("ignoring attr %d\n", attr->type);
1017             break;
1018         }
1019     }
1020     /* allocate type data space for us */
1021     offset = typeinfo->typedata[0];
1022     typeinfo->typedata[0] += 0x18 + (num_params * (num_defaults ? 16 : 12));
1023     typedata = typeinfo->typedata + (offset >> 2) + 1;
1024
1025     /* fill out the basic type information */
1026     typedata[0] = (0x18 + (num_params * (num_defaults ? 16 : 12))) | (index << 16);
1027     ctl2_encode_type(typeinfo->typelib, func->def->type, func->def->ptr_level, func->def->array, &typedata[1], NULL, NULL, &decoded_size);
1028     typedata[2] = funcflags;
1029     typedata[3] = ((52 /*sizeof(FUNCDESC)*/ + decoded_size) << 16) | typeinfo->typeinfo->cbSizeVft;
1030     typedata[4] = (index << 16) | (callconv << 8) | 9;
1031     if(num_defaults) typedata[4] |= 0x10;
1032     typedata[5] = num_params;
1033
1034     /* NOTE: High word of typedata[3] is total size of FUNCDESC + size of all ELEMDESCs for params + TYPEDESCs for pointer params and return types. */
1035     /* That is, total memory allocation required to reconstitute the FUNCDESC in its entirety. */
1036     typedata[3] += (16 /*sizeof(ELEMDESC)*/ * num_params) << 16;
1037     typedata[3] += (24 /*sizeof(PARAMDESCEX)*/ * num_defaults) << 16;
1038
1039     for (arg = last_arg, i = 0; arg; arg = PREV_LINK(arg), i++) {
1040         attr_t *attr;
1041         int paramflags = 0;
1042         int *paramdata = typedata + 6 + (num_defaults ? num_params : 0) + i * 3;
1043         int *defaultdata = num_defaults ? typedata + 6 + i : NULL;
1044
1045         if(defaultdata) *defaultdata = -1;
1046
1047         ctl2_encode_type(typeinfo->typelib, arg->type, arg->ptr_level, arg->array, paramdata, NULL, NULL, &decoded_size);
1048         for(attr = arg->attrs; attr; attr = NEXT_LINK(attr)) {
1049             switch(attr->type) {
1050             case ATTR_DEFAULTVALUE_EXPR:
1051               {
1052                 expr_t *expr = (expr_t *)attr->u.pval;
1053                 paramflags |= 0x30; /* PARAMFLAG_FHASDEFAULT | PARAMFLAG_FOPT */
1054                 chat("default value %ld\n", expr->cval);
1055                 write_value(typeinfo, defaultdata, arg, *paramdata, &expr->cval);
1056                 break;
1057               }
1058             case ATTR_DEFAULTVALUE_STRING:
1059               {
1060                 char *s = (char *)attr->u.pval;
1061                 paramflags |= 0x30; /* PARAMFLAG_FHASDEFAULT | PARAMFLAG_FOPT */
1062                 chat("default value '%s'\n", s);
1063                 write_value(typeinfo, defaultdata, arg, *paramdata, s);
1064                 break;
1065               }
1066             case ATTR_IN:
1067                 paramflags |= 0x01; /* PARAMFLAG_FIN */
1068                 break;
1069             case ATTR_OPTIONAL:
1070                 paramflags |= 0x10; /* PARAMFLAG_FOPT */
1071                 break;
1072             case ATTR_OUT:
1073                 paramflags |= 0x02; /* PARAMFLAG_FOUT */
1074                 break;
1075             case ATTR_RETVAL:
1076                 paramflags |= 0x08; /* PARAMFLAG_FRETVAL */
1077                 break;
1078             default:
1079                 chat("unhandled param attr %d\n", attr->type);
1080                 break;
1081             }
1082         }
1083         paramdata[1] = -1;
1084         paramdata[2] = paramflags;
1085         typedata[3] += decoded_size << 16;
1086     }
1087
1088     /* update the index data */
1089     typeinfo->indices[index] = id; 
1090     typeinfo->names[index] = -1;
1091     typeinfo->offsets[index] = offset;
1092
1093     /* ??? */
1094     if (!typeinfo->typeinfo->res2) typeinfo->typeinfo->res2 = 0x20;
1095     typeinfo->typeinfo->res2 <<= 1;
1096     /* ??? */
1097     if (index < 2) typeinfo->typeinfo->res2 += num_params << 4;
1098
1099     if (typeinfo->typeinfo->res3 == -1) typeinfo->typeinfo->res3 = 0;
1100     typeinfo->typeinfo->res3 += 0x38 + num_params * 0x10;
1101     if(num_defaults) typeinfo->typeinfo->res3 += num_params * 0x4;
1102
1103     /* adjust size of VTBL */
1104     typeinfo->typeinfo->cbSizeVft += 4;
1105
1106     /* Increment the number of function elements */
1107     typeinfo->typeinfo->cElement += 1;
1108
1109
1110     offset = ctl2_alloc_name(typeinfo->typelib, func->def->name);
1111     chat("name offset = %d index %d\n", offset, index);
1112     typeinfo->names[index] = offset;
1113
1114     namedata = typeinfo->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset;
1115     namedata[9] &= ~0x10;
1116     if (*((INT *)namedata) == -1) {
1117         *((INT *)namedata) = typeinfo->typelib->typelib_typeinfo_offsets[typeinfo->typeinfo->typekind >> 16];
1118     }
1119
1120     for (arg = last_arg, i = 0; arg; arg = PREV_LINK(arg), i++) {
1121         /* FIXME: Almost certainly easy to break */
1122         int *paramdata = &typeinfo->typedata[typeinfo->offsets[index] >> 2];
1123         paramdata += 7 + (num_defaults ? num_params : 0) + i * 3;
1124         offset = ctl2_alloc_name(typeinfo->typelib, arg->name);
1125         paramdata[1] = offset;
1126         chat("param %d name %s offset %d\n", i, arg->name, offset);
1127     }
1128     return S_OK;
1129 }
1130
1131
1132 static void set_alignment(
1133         msft_typeinfo_t* typeinfo,
1134         WORD cbAlignment)
1135 {
1136
1137     if (!cbAlignment) return;
1138     if (cbAlignment > 16) return;
1139
1140     typeinfo->typeinfo->typekind &= ~0xffc0;
1141     typeinfo->typeinfo->typekind |= cbAlignment << 6;
1142
1143     /* FIXME: There's probably some way to simplify this. */
1144     switch (typeinfo->typeinfo->typekind & 15) {
1145     case TKIND_ALIAS:
1146     default:
1147         break;
1148
1149     case TKIND_ENUM:
1150     case TKIND_INTERFACE:
1151     case TKIND_DISPATCH:
1152     case TKIND_COCLASS:
1153         if (cbAlignment > 4) cbAlignment = 4;
1154         break;
1155
1156     case TKIND_RECORD:
1157     case TKIND_MODULE:
1158     case TKIND_UNION:
1159         cbAlignment = 1;
1160         break;
1161     }
1162
1163     typeinfo->typeinfo->typekind |= cbAlignment << 11;
1164
1165     return;
1166 }
1167
1168 static HRESULT add_var_desc(msft_typeinfo_t *typeinfo, UINT index, var_t* var)
1169 {
1170     int offset;
1171     INT *typedata;
1172     int var_datawidth;
1173     int var_alignment;
1174     int var_type_size;
1175     int alignment;
1176     int varflags = 0;
1177     attr_t *attr;
1178     char *namedata;
1179
1180     chat("add_var_desc(%d,%s) array %p\n", index, var->name, var->array);
1181
1182     if ((typeinfo->typeinfo->cElement >> 16) != index) {
1183         error("Out-of-order element.\n");
1184         return TYPE_E_ELEMENTNOTFOUND;
1185     }
1186
1187
1188     for(attr = var->attrs; attr; attr = NEXT_LINK(attr)) {
1189         switch(attr->type) {
1190         default:
1191             warning("AddVarDesc: unhandled attr type %d\n", attr->type);
1192             break;
1193         }
1194     }
1195
1196     if (!typeinfo->typedata) {
1197         typeinfo->typedata = xmalloc(0x2000);
1198         typeinfo->typedata[0] = 0;
1199     }
1200
1201     /* allocate type data space for us */
1202     offset = typeinfo->typedata[0];
1203     typeinfo->typedata[0] += 0x14;
1204     typedata = typeinfo->typedata + (offset >> 2) + 1;
1205
1206     /* fill out the basic type information */
1207     typedata[0] = 0x14 | (index << 16);
1208     typedata[2] = varflags;
1209     typedata[3] = (36 /*sizeof(VARDESC)*/ << 16) | 0;
1210
1211     /* update the index data */
1212     typeinfo->indices[index] = 0x40000000 + index;
1213     typeinfo->names[index] = -1;
1214     typeinfo->offsets[index] = offset;
1215
1216     /* figure out type widths and whatnot */
1217     ctl2_encode_type(typeinfo->typelib, var->type, var->ptr_level, var->array,
1218                      &typedata[1], &var_datawidth, &var_alignment,
1219                      &var_type_size);
1220
1221     /* pad out starting position to data width */
1222     typeinfo->datawidth += var_alignment - 1;
1223     typeinfo->datawidth &= ~(var_alignment - 1);
1224     typedata[4] = typeinfo->datawidth;
1225     
1226     /* add the new variable to the total data width */
1227     typeinfo->datawidth += var_datawidth;
1228
1229     /* add type description size to total required allocation */
1230     typedata[3] += var_type_size << 16;
1231
1232     /* fix type alignment */
1233     alignment = (typeinfo->typeinfo->typekind >> 11) & 0x1f;
1234     if (alignment < var_alignment) {
1235         alignment = var_alignment;
1236         typeinfo->typeinfo->typekind &= ~0xf800;
1237         typeinfo->typeinfo->typekind |= alignment << 11;
1238     }
1239
1240     /* ??? */
1241     if (!typeinfo->typeinfo->res2) typeinfo->typeinfo->res2 = 0x1a;
1242     if ((index == 0) || (index == 1) || (index == 2) || (index == 4) || (index == 9)) {
1243         typeinfo->typeinfo->res2 <<= 1;
1244     }
1245
1246     /* ??? */
1247     if (typeinfo->typeinfo->res3 == -1) typeinfo->typeinfo->res3 = 0;
1248     typeinfo->typeinfo->res3 += 0x2c;
1249
1250     /* increment the number of variable elements */
1251     typeinfo->typeinfo->cElement += 0x10000;
1252
1253     /* pad data width to alignment */
1254     typeinfo->typeinfo->size = (typeinfo->datawidth + (alignment - 1)) & ~(alignment - 1);
1255
1256     offset = ctl2_alloc_name(typeinfo->typelib, var->name);
1257     if (offset == -1) return E_OUTOFMEMORY;
1258
1259     namedata = typeinfo->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset;
1260     if (*((INT *)namedata) == -1) {
1261         *((INT *)namedata) = typeinfo->typelib->typelib_typeinfo_offsets[typeinfo->typeinfo->typekind >> 16];
1262         namedata[9] |= 0x10;
1263     }
1264     if ((typeinfo->typeinfo->typekind & 15) == TKIND_ENUM) {
1265         namedata[9] |= 0x20;
1266     }
1267     typeinfo->names[index] = offset;
1268
1269     return S_OK;
1270 }
1271
1272
1273 static msft_typeinfo_t *create_msft_typeinfo(msft_typelib_t *typelib, typelib_entry_t *entry, int idx)
1274 {
1275     msft_typeinfo_t *msft_typeinfo;
1276     int nameoffset;
1277     int typeinfo_offset;
1278     MSFT_TypeInfoBase *typeinfo;
1279     char *name;
1280     MSFT_GuidEntry guidentry;
1281     attr_t *attr;
1282
1283     switch(entry->kind) {
1284     case TKIND_INTERFACE:
1285         name = entry->u.interface->name;
1286         attr = entry->u.interface->attrs;
1287         entry->u.interface->typelib_idx = idx;
1288         break;
1289     case TKIND_MODULE:
1290         name = entry->u.module->name;
1291         attr = entry->u.module->attrs;
1292         break;
1293     case TKIND_COCLASS:
1294         name = entry->u.class->name;
1295         attr = entry->u.class->attrs;
1296         break;
1297     case TKIND_RECORD:
1298         name = entry->u.structure->name;
1299         attr = entry->u.structure->attrs;
1300         entry->u.structure->typelib_idx = idx;
1301         chat("type = %p\n", entry->u.structure);
1302         break;
1303     default:
1304         error("create_msft_typeinfo: unhandled type %d\n", entry->kind);
1305         return NULL;
1306     }
1307
1308
1309     chat("Constructing msft_typeinfo for name %s kind %d\n", name, entry->kind);
1310
1311     msft_typeinfo = xmalloc(sizeof(*msft_typeinfo));
1312
1313     msft_typeinfo->typelib = typelib;
1314
1315     nameoffset = ctl2_alloc_name(typelib, name);
1316     typeinfo_offset = ctl2_alloc_typeinfo(typelib, nameoffset);
1317     typeinfo = (MSFT_TypeInfoBase *)&typelib->typelib_segment_data[MSFT_SEG_TYPEINFO][typeinfo_offset];
1318
1319     typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset + 9] = 0x38;
1320     *((int *)&typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset]) = typeinfo_offset;
1321
1322     msft_typeinfo->typeinfo = typeinfo;
1323
1324     typeinfo->typekind |= entry->kind | 0x20;
1325     set_alignment(msft_typeinfo, 4);
1326
1327     switch (entry->kind) {
1328     case TKIND_ENUM:
1329     case TKIND_INTERFACE:
1330     case TKIND_DISPATCH:
1331     case TKIND_COCLASS:
1332         typeinfo->size = 4;
1333         break;
1334
1335     case TKIND_RECORD:
1336     case TKIND_UNION:
1337         typeinfo->size = 0;
1338         break;
1339
1340     case TKIND_MODULE:
1341         typeinfo->size = 2;
1342         break;
1343
1344     case TKIND_ALIAS:
1345         typeinfo->size = -0x75;
1346         break;
1347
1348     default:
1349         error("%s unrecognized typekind %d\n", name, entry->kind);
1350         typeinfo->size = 0xdeadbeef;
1351         break;
1352     }
1353
1354
1355     for( ; attr; attr = NEXT_LINK(attr)) {
1356         switch(attr->type) {
1357         case ATTR_HIDDEN:
1358             typeinfo->flags |= 0x10; /* TYPEFLAG_FHIDDEN */
1359             break;
1360
1361         case ATTR_RESTRICTED:
1362             typeinfo->flags |= 0x200; /* TYPEFLAG_FRESTRICTED */
1363             break;
1364
1365         case ATTR_UUID:
1366             guidentry.guid = *(GUID*)attr->u.pval;
1367             guidentry.hreftype = typelib->typelib_typeinfo_offsets[typeinfo->typekind >> 16];
1368             guidentry.next_hash = -1;
1369             typeinfo->posguid = ctl2_alloc_guid(typelib, &guidentry);
1370 #if 0
1371             if (IsEqualIID(guid, &IID_IDispatch)) {
1372                 typelib->typelib_header.dispatchpos = typelib->typelib_typeinfo_offsets[typeinfo->typekind >> 16];
1373             }
1374 #endif
1375
1376         case ATTR_VERSION:
1377             typeinfo->version = attr->u.ival;
1378             break;
1379
1380         default:
1381             warning("create_msft_typeinfo: ignoring attr %d\n", attr->type);
1382             break;
1383         }
1384     }
1385
1386     if (typelib->last_typeinfo) typelib->last_typeinfo->next_typeinfo = msft_typeinfo;
1387     typelib->last_typeinfo = msft_typeinfo;
1388     if (!typelib->typeinfos) typelib->typeinfos = msft_typeinfo;
1389
1390
1391     return msft_typeinfo;
1392 }
1393
1394
1395 static void set_name(msft_typelib_t *typelib)
1396 {
1397     int offset;
1398
1399     offset = ctl2_alloc_name(typelib, typelib->typelib->name);
1400     if (offset == -1) return;
1401     typelib->typelib_header.NameOffset = offset;
1402     return;
1403 }
1404
1405 static void set_version(msft_typelib_t *typelib)
1406 {
1407     long version = MAKELONG(0,0);
1408     attr_t *attr;
1409
1410     for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1411         if(attr->type == ATTR_VERSION) {
1412             version = attr->u.ival;
1413         }
1414     }
1415     typelib->typelib_header.version = version;
1416     return;
1417 }
1418
1419 static void set_guid(msft_typelib_t *typelib)
1420 {
1421     MSFT_GuidEntry guidentry;
1422     int offset;
1423     attr_t *attr;
1424     GUID guid = {0,0,0,{0,0,0,0,0,0}};
1425
1426     guidentry.guid = guid;
1427     guidentry.hreftype = -2;
1428     guidentry.next_hash = -1;
1429
1430     for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1431         if(attr->type == ATTR_UUID) {
1432             guidentry.guid = *(GUID*)(attr->u.pval);
1433         }
1434     }
1435
1436     offset = ctl2_alloc_guid(typelib, &guidentry);
1437     
1438     if (offset == -1) return;
1439
1440     typelib->typelib_header.posguid = offset;
1441
1442     return;
1443 }
1444
1445 static void set_doc_string(msft_typelib_t *typelib)
1446 {
1447     attr_t *attr;
1448     int offset;
1449
1450     for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1451         if(attr->type == ATTR_HELPSTRING) {
1452             offset = ctl2_alloc_string(typelib, attr->u.pval);
1453             if (offset == -1) return;
1454             typelib->typelib_header.helpstring = offset;
1455         }
1456     }
1457     return;
1458 }
1459
1460 static void set_help_file_name(msft_typelib_t *typelib)
1461 {
1462     int offset;
1463     offset = ctl2_alloc_string(typelib, "help file name");
1464     if (offset == -1) return;
1465     typelib->typelib_header.helpfile = offset;
1466     typelib->typelib_header.varflags |= 0x10;
1467     return;
1468 }
1469
1470 static void set_lcid(msft_typelib_t *typelib)
1471 {
1472     typelib->typelib_header.lcid2 = 0x0;
1473     return;
1474 }
1475
1476 static void set_lib_flags(msft_typelib_t *typelib)
1477 {
1478     attr_t *attr;
1479
1480     typelib->typelib_header.flags = 0;
1481     for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1482         switch(attr->type) {
1483         case ATTR_CONTROL:
1484             typelib->typelib_header.flags |= 0x02; /* LIBFLAG_FCONTROL */
1485             break;
1486         case ATTR_HIDDEN:
1487             typelib->typelib_header.flags |= 0x04; /* LIBFLAG_FHIDDEN */
1488             break;
1489         case ATTR_RESTRICTED:
1490             typelib->typelib_header.flags |= 0x01; /* LIBFLAG_FRESTRICTED */
1491             break;
1492         default:
1493             break;
1494         }
1495     }
1496     return;
1497 }
1498
1499 static int ctl2_write_chunk(int fd, void *segment, int length)
1500 {
1501     if (write(fd, segment, length) != length) {
1502         close(fd);
1503         return 0;
1504     }
1505     return -1;
1506 }
1507
1508 static int ctl2_write_segment(msft_typelib_t *typelib, int fd, int segment)
1509 {
1510     if (write(fd, typelib->typelib_segment_data[segment], typelib->typelib_segdir[segment].length)
1511         != typelib->typelib_segdir[segment].length) {
1512         close(fd);
1513         return 0;
1514     }
1515
1516     return -1;
1517 }
1518
1519 static void ctl2_finalize_typeinfos(msft_typelib_t *typelib, int filesize)
1520 {
1521     msft_typeinfo_t *typeinfo;
1522
1523     for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
1524         typeinfo->typeinfo->memoffset = filesize;
1525         if (typeinfo->typedata) {
1526             /*LayOut(typeinfo);*/
1527             filesize += typeinfo->typedata[0] + ((typeinfo->typeinfo->cElement >> 16) * 12) + ((typeinfo->typeinfo->cElement & 0xffff) * 12) + 4;
1528         }
1529     }
1530 }
1531
1532 static int ctl2_finalize_segment(msft_typelib_t *typelib, int filepos, int segment)
1533 {
1534     if (typelib->typelib_segdir[segment].length) {
1535         typelib->typelib_segdir[segment].offset = filepos;
1536     } else {
1537         typelib->typelib_segdir[segment].offset = -1;
1538     }
1539
1540     return typelib->typelib_segdir[segment].length;
1541 }
1542
1543
1544 static void ctl2_write_typeinfos(msft_typelib_t *typelib, int fd)
1545 {
1546     msft_typeinfo_t *typeinfo;
1547
1548     for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
1549         if (!typeinfo->typedata) continue;
1550
1551         ctl2_write_chunk(fd, typeinfo->typedata, typeinfo->typedata[0] + 4);
1552         ctl2_write_chunk(fd, typeinfo->indices, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
1553         chat("writing name chunk len %d %08lx\n", ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4, *(DWORD*)typeinfo->names);
1554         ctl2_write_chunk(fd, typeinfo->names, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
1555         ctl2_write_chunk(fd, typeinfo->offsets, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
1556     }
1557 }
1558
1559 static int save_all_changes(msft_typelib_t *typelib)
1560 {
1561     int retval;
1562     int filepos;
1563     int fd;
1564
1565     chat("save_all_changes(%p)\n", typelib);
1566
1567     retval = TYPE_E_IOERROR;
1568
1569     fd = creat(typelib->typelib->filename, 0666);
1570     if (fd == -1) return retval;
1571
1572     filepos = sizeof(MSFT_Header) + sizeof(MSFT_SegDir);
1573     filepos += typelib->typelib_header.nrtypeinfos * 4;
1574
1575     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_TYPEINFO);
1576     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_GUIDHASH);
1577     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_GUID);
1578     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_IMPORTINFO);
1579     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_IMPORTFILES);
1580     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_REFERENCES);
1581     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_NAMEHASH);
1582     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_NAME);
1583     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_STRING);
1584     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_TYPEDESC);
1585     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_ARRAYDESC);
1586     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_CUSTDATA);
1587     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_CUSTDATAGUID);
1588
1589     ctl2_finalize_typeinfos(typelib, filepos);
1590
1591     if (!ctl2_write_chunk(fd, &typelib->typelib_header, sizeof(typelib->typelib_header))) return retval;
1592     if (!ctl2_write_chunk(fd, typelib->typelib_typeinfo_offsets, typelib->typelib_header.nrtypeinfos * 4)) return retval;
1593     if (!ctl2_write_chunk(fd, &typelib->typelib_segdir, sizeof(typelib->typelib_segdir))) return retval;
1594     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_TYPEINFO    )) return retval;
1595     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_GUIDHASH    )) return retval;
1596     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_GUID        )) return retval;
1597     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_IMPORTINFO  )) return retval;
1598     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_IMPORTFILES )) return retval;
1599     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_REFERENCES  )) return retval;
1600     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_NAMEHASH    )) return retval;
1601     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_NAME        )) return retval;
1602     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_STRING      )) return retval;
1603     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_TYPEDESC    )) return retval;
1604     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_ARRAYDESC   )) return retval;
1605     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_CUSTDATA    )) return retval;
1606     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_CUSTDATAGUID)) return retval;
1607
1608     ctl2_write_typeinfos(typelib, fd);
1609
1610     if (close(fd) == -1) return retval;
1611
1612     retval = S_OK;
1613     return retval;
1614 }
1615
1616
1617
1618
1619 int create_msft_typelib(typelib_t *typelib)
1620 {
1621     msft_typelib_t *msft;
1622     int failed = 0, typelib_idx;
1623     typelib_entry_t *entry;
1624
1625     msft = malloc(sizeof(*msft));
1626     if (!msft) return 0;
1627     memset(msft, 0, sizeof(*msft));
1628     msft->typelib = typelib;
1629
1630     ctl2_init_header(msft);
1631     ctl2_init_segdir(msft);
1632
1633     msft->typelib_header.varflags |= SYS_WIN32;
1634
1635     /*
1636      * The following two calls return an offset or -1 if out of memory. We
1637      * specifically need an offset of 0, however, so...
1638      */
1639     if (ctl2_alloc_segment(msft, MSFT_SEG_GUIDHASH, 0x80, 0x80)) { failed = 1; }
1640     if (ctl2_alloc_segment(msft, MSFT_SEG_NAMEHASH, 0x200, 0x200)) { failed = 1; }
1641
1642     if(failed) return 0;
1643
1644     msft->typelib_guidhash_segment = (int *)msft->typelib_segment_data[MSFT_SEG_GUIDHASH];
1645     msft->typelib_namehash_segment = (int *)msft->typelib_segment_data[MSFT_SEG_NAMEHASH];
1646
1647     memset(msft->typelib_guidhash_segment, 0xff, 0x80);
1648     memset(msft->typelib_namehash_segment, 0xff, 0x200);
1649
1650     set_lib_flags(msft);
1651     set_lcid(msft);
1652 /*    set_help_file_name(msft);*/
1653     set_doc_string(msft);
1654     set_guid(msft);
1655     set_version(msft);
1656     set_name(msft);
1657
1658     typelib_idx = 0;
1659     for(entry = typelib->entry; NEXT_LINK(entry); entry = NEXT_LINK(entry))
1660         ;
1661     for( ; entry; entry = PREV_LINK(entry)) {
1662         msft_typeinfo_t *msft_typeinfo = create_msft_typeinfo(msft, entry, typelib_idx);
1663         switch(entry->kind) {
1664         case TKIND_INTERFACE:
1665           {
1666             int idx = 0;
1667             func_t *cur = entry->u.interface->funcs;
1668             while(NEXT_LINK(cur)) cur = NEXT_LINK(cur);
1669             while(cur) {
1670                 if(cur->idx == -1) cur->idx = idx;
1671                 else if(cur->idx != idx) error("method index mismatch\n");
1672                 add_func_desc(msft_typeinfo, cur);
1673                 idx++;
1674                 cur = PREV_LINK(cur);
1675             }
1676             break;
1677           }
1678         case TKIND_RECORD:
1679           {
1680             int idx = 0;
1681             var_t *cur = entry->u.structure->fields;
1682             while(NEXT_LINK(cur)) cur = NEXT_LINK(cur);
1683             while(cur) {
1684                 add_var_desc(msft_typeinfo, idx, cur);
1685                 idx++;
1686                 cur = PREV_LINK(cur);
1687             }
1688             break;
1689           }
1690                 
1691         default:
1692             error("create_msft_typelib: unhandled type %d\n", entry->kind);
1693             break;
1694         }
1695         typelib_idx++;
1696     }
1697     save_all_changes(msft);
1698     return 1;
1699 }