Add attributes control, hidden and restricted.
[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_typedesc
652  *
653  *  Encodes a type description, 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 HRESULT add_func_desc(msft_typeinfo_t* typeinfo, func_t *func)
931 {
932     int offset;
933     int *typedata;
934     int i, index = func->idx, id;
935     int decoded_size;
936     int num_params = 0;
937     var_t *arg, *last_arg = NULL;
938     char *namedata;
939     attr_t *attr;
940     unsigned int funcflags = 0, callconv = 4;
941
942     id = ((0x6000 | typeinfo->typeinfo->cImplTypes) << 16) | index;
943
944     chat("(%p,%d)\n", typeinfo, index);
945     
946     if (!typeinfo->typedata) {
947         typeinfo->typedata = xmalloc(0x2000);
948         typeinfo->typedata[0] = 0;
949     }
950
951     for(arg = func->args; arg; arg = NEXT_LINK(arg)) {
952         last_arg = arg;
953         num_params++;
954     }
955
956     chat("num of params %d\n", num_params);
957
958     for(attr = func->def->attrs; attr; attr = NEXT_LINK(attr)) {
959         switch(attr->type) {
960         case ATTR_ID:
961           {
962             expr_t *expr = attr->u.pval; 
963             id = expr->u.lval;
964             break;
965           }
966         case ATTR_OUT:
967             break;
968
969         default:
970             warning("ignoring attr %d\n", attr->type);
971             break;
972         }
973     }
974     /* allocate type data space for us */
975     offset = typeinfo->typedata[0];
976     typeinfo->typedata[0] += 0x18 + (num_params * 12);
977     typedata = typeinfo->typedata + (offset >> 2) + 1;
978
979     /* fill out the basic type information */
980     typedata[0] = (0x18 + (num_params * 12)) | (index << 16);
981     ctl2_encode_type(typeinfo->typelib, func->def->type, func->def->ptr_level, func->def->array, &typedata[1], NULL, NULL, &decoded_size);
982     typedata[2] = funcflags;
983     typedata[3] = ((52 /*sizeof(FUNCDESC)*/ + decoded_size) << 16) | typeinfo->typeinfo->cbSizeVft;
984     typedata[4] = (index << 16) | (callconv << 8) | 9;
985     typedata[5] = num_params;
986
987     /* NOTE: High word of typedata[3] is total size of FUNCDESC + size of all ELEMDESCs for params + TYPEDESCs for pointer params and return types. */
988     /* That is, total memory allocation required to reconstitute the FUNCDESC in its entirety. */
989     typedata[3] += (16 /*sizeof(ELEMDESC)*/ * num_params) << 16;
990
991     for (arg = last_arg, i = 0; arg; arg = PREV_LINK(arg), i++) {
992         attr_t *attr;
993         int paramflags = 0;
994
995         for(attr = arg->attrs; attr; attr = NEXT_LINK(attr)) {
996             switch(attr->type) {
997             case ATTR_IN:
998                 paramflags |= 0x01; /* PARAMFLAG_FIN */
999                 break;
1000             case ATTR_OUT:
1001                 paramflags |= 0x02; /* PARAMFLAG_FOUT */
1002                 break;
1003             case ATTR_RETVAL:
1004                 paramflags |= 0x08; /* PARAMFLAG_FRETVAL */
1005                 break;
1006             default:
1007                 chat("unhandled param attr %d\n", attr->type);
1008                 break;
1009             }
1010         }
1011         ctl2_encode_type(typeinfo->typelib, arg->type, arg->ptr_level, arg->array, &typedata[6+(i*3)], NULL, NULL, &decoded_size);
1012         typedata[7+(i*3)] = -1;
1013         typedata[8+(i*3)] = paramflags;
1014         typedata[3] += decoded_size << 16;
1015
1016 #if 0
1017         /* FIXME: Doesn't work. Doesn't even come up with usable VTs for varDefaultValue. */
1018         if (pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) {
1019             ctl2_alloc_custdata(This->typelib, &pFuncDesc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue);
1020         }
1021 #endif
1022     }
1023
1024     /* update the index data */
1025     typeinfo->indices[index] = id; 
1026     typeinfo->names[index] = -1;
1027     typeinfo->offsets[index] = offset;
1028
1029     /* ??? */
1030     if (!typeinfo->typeinfo->res2) typeinfo->typeinfo->res2 = 0x20;
1031     typeinfo->typeinfo->res2 <<= 1;
1032
1033     /* ??? */
1034     if (typeinfo->typeinfo->res3 == -1) typeinfo->typeinfo->res3 = 0;
1035     typeinfo->typeinfo->res3 += 0x38;
1036
1037     /* ??? */
1038     if (index < 2) typeinfo->typeinfo->res2 += num_params << 4;
1039     typeinfo->typeinfo->res3 += num_params << 4;
1040
1041     /* adjust size of VTBL */
1042     typeinfo->typeinfo->cbSizeVft += 4;
1043
1044     /* Increment the number of function elements */
1045     typeinfo->typeinfo->cElement += 1;
1046
1047
1048     offset = ctl2_alloc_name(typeinfo->typelib, func->def->name);
1049     chat("name offset = %d index %d\n", offset, index);
1050     typeinfo->names[index] = offset;
1051
1052     namedata = typeinfo->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset;
1053     namedata[9] &= ~0x10;
1054     if (*((INT *)namedata) == -1) {
1055         *((INT *)namedata) = typeinfo->typelib->typelib_typeinfo_offsets[typeinfo->typeinfo->typekind >> 16];
1056     }
1057
1058     for (arg = last_arg, i = 0; arg; arg = PREV_LINK(arg), i++) {
1059         /* FIXME: Almost certainly easy to break */
1060         int *paramdata = &typeinfo->typedata[typeinfo->offsets[index] >> 2];
1061         
1062         offset = ctl2_alloc_name(typeinfo->typelib, arg->name);
1063         paramdata[(i * 3) + 8] = offset;
1064         chat("param %d name %s offset %d\n", i, arg->name, offset);
1065     }
1066     return S_OK;
1067 }
1068
1069
1070 static void set_alignment(
1071         msft_typeinfo_t* typeinfo,
1072         WORD cbAlignment)
1073 {
1074
1075     if (!cbAlignment) return;
1076     if (cbAlignment > 16) return;
1077
1078     typeinfo->typeinfo->typekind &= ~0xffc0;
1079     typeinfo->typeinfo->typekind |= cbAlignment << 6;
1080
1081     /* FIXME: There's probably some way to simplify this. */
1082     switch (typeinfo->typeinfo->typekind & 15) {
1083     case TKIND_ALIAS:
1084     default:
1085         break;
1086
1087     case TKIND_ENUM:
1088     case TKIND_INTERFACE:
1089     case TKIND_DISPATCH:
1090     case TKIND_COCLASS:
1091         if (cbAlignment > 4) cbAlignment = 4;
1092         break;
1093
1094     case TKIND_RECORD:
1095     case TKIND_MODULE:
1096     case TKIND_UNION:
1097         cbAlignment = 1;
1098         break;
1099     }
1100
1101     typeinfo->typeinfo->typekind |= cbAlignment << 11;
1102
1103     return;
1104 }
1105
1106 static HRESULT add_var_desc(msft_typeinfo_t *typeinfo, UINT index, var_t* var)
1107 {
1108     int offset;
1109     INT *typedata;
1110     int var_datawidth;
1111     int var_alignment;
1112     int var_type_size;
1113     int alignment;
1114     int varflags = 0;
1115     attr_t *attr;
1116     char *namedata;
1117
1118     chat("add_var_desc(%d,%s) array %p\n", index, var->name, var->array);
1119
1120     if ((typeinfo->typeinfo->cElement >> 16) != index) {
1121         error("Out-of-order element.\n");
1122         return TYPE_E_ELEMENTNOTFOUND;
1123     }
1124
1125
1126     for(attr = var->attrs; attr; attr = NEXT_LINK(attr)) {
1127         switch(attr->type) {
1128         default:
1129             warning("AddVarDesc: unhandled attr type %d\n", attr->type);
1130             break;
1131         }
1132     }
1133
1134     if (!typeinfo->typedata) {
1135         typeinfo->typedata = xmalloc(0x2000);
1136         typeinfo->typedata[0] = 0;
1137     }
1138
1139     /* allocate type data space for us */
1140     offset = typeinfo->typedata[0];
1141     typeinfo->typedata[0] += 0x14;
1142     typedata = typeinfo->typedata + (offset >> 2) + 1;
1143
1144     /* fill out the basic type information */
1145     typedata[0] = 0x14 | (index << 16);
1146     typedata[2] = varflags;
1147     typedata[3] = (36 /*sizeof(VARDESC)*/ << 16) | 0;
1148
1149     /* update the index data */
1150     typeinfo->indices[index] = 0x40000000 + index;
1151     typeinfo->names[index] = -1;
1152     typeinfo->offsets[index] = offset;
1153
1154     /* figure out type widths and whatnot */
1155     ctl2_encode_type(typeinfo->typelib, var->type, var->ptr_level, var->array,
1156                      &typedata[1], &var_datawidth, &var_alignment,
1157                      &var_type_size);
1158
1159     /* pad out starting position to data width */
1160     typeinfo->datawidth += var_alignment - 1;
1161     typeinfo->datawidth &= ~(var_alignment - 1);
1162     typedata[4] = typeinfo->datawidth;
1163     
1164     /* add the new variable to the total data width */
1165     typeinfo->datawidth += var_datawidth;
1166
1167     /* add type description size to total required allocation */
1168     typedata[3] += var_type_size << 16;
1169
1170     /* fix type alignment */
1171     alignment = (typeinfo->typeinfo->typekind >> 11) & 0x1f;
1172     if (alignment < var_alignment) {
1173         alignment = var_alignment;
1174         typeinfo->typeinfo->typekind &= ~0xf800;
1175         typeinfo->typeinfo->typekind |= alignment << 11;
1176     }
1177
1178     /* ??? */
1179     if (!typeinfo->typeinfo->res2) typeinfo->typeinfo->res2 = 0x1a;
1180     if ((index == 0) || (index == 1) || (index == 2) || (index == 4) || (index == 9)) {
1181         typeinfo->typeinfo->res2 <<= 1;
1182     }
1183
1184     /* ??? */
1185     if (typeinfo->typeinfo->res3 == -1) typeinfo->typeinfo->res3 = 0;
1186     typeinfo->typeinfo->res3 += 0x2c;
1187
1188     /* increment the number of variable elements */
1189     typeinfo->typeinfo->cElement += 0x10000;
1190
1191     /* pad data width to alignment */
1192     typeinfo->typeinfo->size = (typeinfo->datawidth + (alignment - 1)) & ~(alignment - 1);
1193
1194     offset = ctl2_alloc_name(typeinfo->typelib, var->name);
1195     if (offset == -1) return E_OUTOFMEMORY;
1196
1197     namedata = typeinfo->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset;
1198     if (*((INT *)namedata) == -1) {
1199         *((INT *)namedata) = typeinfo->typelib->typelib_typeinfo_offsets[typeinfo->typeinfo->typekind >> 16];
1200         namedata[9] |= 0x10;
1201     }
1202     if ((typeinfo->typeinfo->typekind & 15) == TKIND_ENUM) {
1203         namedata[9] |= 0x20;
1204     }
1205     typeinfo->names[index] = offset;
1206
1207     return S_OK;
1208 }
1209
1210
1211 static msft_typeinfo_t *create_msft_typeinfo(msft_typelib_t *typelib, typelib_entry_t *entry, int idx)
1212 {
1213     msft_typeinfo_t *msft_typeinfo;
1214     int nameoffset;
1215     int typeinfo_offset;
1216     MSFT_TypeInfoBase *typeinfo;
1217     char *name;
1218     MSFT_GuidEntry guidentry;
1219     attr_t *attr;
1220
1221     switch(entry->kind) {
1222     case TKIND_INTERFACE:
1223         name = entry->u.interface->name;
1224         attr = entry->u.interface->attrs;
1225         entry->u.interface->typelib_idx = idx;
1226         break;
1227     case TKIND_MODULE:
1228         name = entry->u.module->name;
1229         attr = entry->u.module->attrs;
1230         break;
1231     case TKIND_COCLASS:
1232         name = entry->u.class->name;
1233         attr = entry->u.class->attrs;
1234         break;
1235     case TKIND_RECORD:
1236         name = entry->u.structure->name;
1237         attr = entry->u.structure->attrs;
1238         entry->u.structure->typelib_idx = idx;
1239         chat("type = %p\n", entry->u.structure);
1240         break;
1241     default:
1242         error("create_msft_typeinfo: unhandled type %d\n", entry->kind);
1243         return NULL;
1244     }
1245
1246
1247     chat("Constructing msft_typeinfo for name %s kind %d\n", name, entry->kind);
1248
1249     msft_typeinfo = xmalloc(sizeof(*msft_typeinfo));
1250
1251     msft_typeinfo->typelib = typelib;
1252
1253     nameoffset = ctl2_alloc_name(typelib, name);
1254     typeinfo_offset = ctl2_alloc_typeinfo(typelib, nameoffset);
1255     typeinfo = (MSFT_TypeInfoBase *)&typelib->typelib_segment_data[MSFT_SEG_TYPEINFO][typeinfo_offset];
1256
1257     typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset + 9] = 0x38;
1258     *((int *)&typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset]) = typeinfo_offset;
1259
1260     msft_typeinfo->typeinfo = typeinfo;
1261
1262     typeinfo->typekind |= entry->kind | 0x20;
1263     set_alignment(msft_typeinfo, 4);
1264
1265     switch (entry->kind) {
1266     case TKIND_ENUM:
1267     case TKIND_INTERFACE:
1268     case TKIND_DISPATCH:
1269     case TKIND_COCLASS:
1270         typeinfo->size = 4;
1271         break;
1272
1273     case TKIND_RECORD:
1274     case TKIND_UNION:
1275         typeinfo->size = 0;
1276         break;
1277
1278     case TKIND_MODULE:
1279         typeinfo->size = 2;
1280         break;
1281
1282     case TKIND_ALIAS:
1283         typeinfo->size = -0x75;
1284         break;
1285
1286     default:
1287         error("%s unrecognized typekind %d\n", name, entry->kind);
1288         typeinfo->size = 0xdeadbeef;
1289         break;
1290     }
1291
1292
1293     for( ; attr; attr = NEXT_LINK(attr)) {
1294         if(attr->type == ATTR_UUID) {
1295             guidentry.guid = *(GUID*)attr->u.pval;
1296             guidentry.hreftype = typelib->typelib_typeinfo_offsets[typeinfo->typekind >> 16];
1297             guidentry.next_hash = -1;
1298             typeinfo->posguid = ctl2_alloc_guid(typelib, &guidentry);
1299 #if 0
1300             if (IsEqualIID(guid, &IID_IDispatch)) {
1301                 typelib->typelib_header.dispatchpos = typelib->typelib_typeinfo_offsets[typeinfo->typekind >> 16];
1302             }
1303 #endif
1304         }
1305     }
1306
1307     if (typelib->last_typeinfo) typelib->last_typeinfo->next_typeinfo = msft_typeinfo;
1308     typelib->last_typeinfo = msft_typeinfo;
1309     if (!typelib->typeinfos) typelib->typeinfos = msft_typeinfo;
1310
1311
1312     return msft_typeinfo;
1313 }
1314
1315
1316 static void set_name(msft_typelib_t *typelib)
1317 {
1318     int offset;
1319
1320     offset = ctl2_alloc_name(typelib, typelib->typelib->name);
1321     if (offset == -1) return;
1322     typelib->typelib_header.NameOffset = offset;
1323     return;
1324 }
1325
1326 static void set_version(msft_typelib_t *typelib)
1327 {
1328     long version = MAKELONG(0,0);
1329     attr_t *attr;
1330
1331     for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1332         if(attr->type == ATTR_VERSION) {
1333             version = attr->u.ival;
1334         }
1335     }
1336     typelib->typelib_header.version = version;
1337     return;
1338 }
1339
1340 static void set_guid(msft_typelib_t *typelib)
1341 {
1342     MSFT_GuidEntry guidentry;
1343     int offset;
1344     attr_t *attr;
1345     GUID guid = {0,0,0,{0,0,0,0,0,0}};
1346
1347     guidentry.guid = guid;
1348     guidentry.hreftype = -2;
1349     guidentry.next_hash = -1;
1350
1351     for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1352         if(attr->type == ATTR_UUID) {
1353             guidentry.guid = *(GUID*)(attr->u.pval);
1354         }
1355     }
1356
1357     offset = ctl2_alloc_guid(typelib, &guidentry);
1358     
1359     if (offset == -1) return;
1360
1361     typelib->typelib_header.posguid = offset;
1362
1363     return;
1364 }
1365
1366 static void set_doc_string(msft_typelib_t *typelib)
1367 {
1368     attr_t *attr;
1369     int offset;
1370
1371     for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1372         if(attr->type == ATTR_HELPSTRING) {
1373             offset = ctl2_alloc_string(typelib, attr->u.pval);
1374             if (offset == -1) return;
1375             typelib->typelib_header.helpstring = offset;
1376         }
1377     }
1378     return;
1379 }
1380
1381 static void set_help_file_name(msft_typelib_t *typelib)
1382 {
1383     int offset;
1384     offset = ctl2_alloc_string(typelib, "help file name");
1385     if (offset == -1) return;
1386     typelib->typelib_header.helpfile = offset;
1387     typelib->typelib_header.varflags |= 0x10;
1388     return;
1389 }
1390
1391 static void set_lcid(msft_typelib_t *typelib)
1392 {
1393     typelib->typelib_header.lcid2 = 0x0;
1394     return;
1395 }
1396
1397 static void set_lib_flags(msft_typelib_t *typelib)
1398 {
1399     attr_t *attr;
1400
1401     typelib->typelib_header.flags = 0;
1402     for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1403         switch(attr->type) {
1404         case ATTR_CONTROL:
1405             typelib->typelib_header.flags |= 0x02; /* LIBFLAG_FCONTROL */
1406             break;
1407         case ATTR_HIDDEN:
1408             typelib->typelib_header.flags |= 0x04; /* LIBFLAG_FHIDDEN */
1409             break;
1410         case ATTR_RESTRICTED:
1411             typelib->typelib_header.flags |= 0x01; /* LIBFLAG_FRESTRICTED */
1412             break;
1413         default:
1414             break;
1415         }
1416     }
1417     return;
1418 }
1419
1420 static int ctl2_write_chunk(int fd, void *segment, int length)
1421 {
1422     if (write(fd, segment, length) != length) {
1423         close(fd);
1424         return 0;
1425     }
1426     return -1;
1427 }
1428
1429 static int ctl2_write_segment(msft_typelib_t *typelib, int fd, int segment)
1430 {
1431     if (write(fd, typelib->typelib_segment_data[segment], typelib->typelib_segdir[segment].length)
1432         != typelib->typelib_segdir[segment].length) {
1433         close(fd);
1434         return 0;
1435     }
1436
1437     return -1;
1438 }
1439
1440 static void ctl2_finalize_typeinfos(msft_typelib_t *typelib, int filesize)
1441 {
1442     msft_typeinfo_t *typeinfo;
1443
1444     for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
1445         typeinfo->typeinfo->memoffset = filesize;
1446         if (typeinfo->typedata) {
1447             /*LayOut(typeinfo);*/
1448             filesize += typeinfo->typedata[0] + ((typeinfo->typeinfo->cElement >> 16) * 12) + ((typeinfo->typeinfo->cElement & 0xffff) * 12) + 4;
1449         }
1450     }
1451 }
1452
1453 static int ctl2_finalize_segment(msft_typelib_t *typelib, int filepos, int segment)
1454 {
1455     if (typelib->typelib_segdir[segment].length) {
1456         typelib->typelib_segdir[segment].offset = filepos;
1457     } else {
1458         typelib->typelib_segdir[segment].offset = -1;
1459     }
1460
1461     return typelib->typelib_segdir[segment].length;
1462 }
1463
1464
1465 static void ctl2_write_typeinfos(msft_typelib_t *typelib, int fd)
1466 {
1467     msft_typeinfo_t *typeinfo;
1468
1469     for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
1470         if (!typeinfo->typedata) continue;
1471
1472         ctl2_write_chunk(fd, typeinfo->typedata, typeinfo->typedata[0] + 4);
1473         ctl2_write_chunk(fd, typeinfo->indices, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
1474         chat("writing name chunk len %d %08lx\n", ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4, *(DWORD*)typeinfo->names);
1475         ctl2_write_chunk(fd, typeinfo->names, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
1476         ctl2_write_chunk(fd, typeinfo->offsets, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
1477     }
1478 }
1479
1480 static int save_all_changes(msft_typelib_t *typelib)
1481 {
1482     int retval;
1483     int filepos;
1484     int fd;
1485
1486     chat("save_all_changes(%p)\n", typelib);
1487
1488     retval = TYPE_E_IOERROR;
1489
1490     fd = creat(typelib->typelib->filename, 0666);
1491     if (fd == -1) return retval;
1492
1493     filepos = sizeof(MSFT_Header) + sizeof(MSFT_SegDir);
1494     filepos += typelib->typelib_header.nrtypeinfos * 4;
1495
1496     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_TYPEINFO);
1497     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_GUIDHASH);
1498     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_GUID);
1499     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_IMPORTINFO);
1500     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_IMPORTFILES);
1501     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_REFERENCES);
1502     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_NAMEHASH);
1503     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_NAME);
1504     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_STRING);
1505     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_TYPEDESC);
1506     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_ARRAYDESC);
1507     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_CUSTDATA);
1508     filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_CUSTDATAGUID);
1509
1510     ctl2_finalize_typeinfos(typelib, filepos);
1511
1512     if (!ctl2_write_chunk(fd, &typelib->typelib_header, sizeof(typelib->typelib_header))) return retval;
1513     if (!ctl2_write_chunk(fd, typelib->typelib_typeinfo_offsets, typelib->typelib_header.nrtypeinfos * 4)) return retval;
1514     if (!ctl2_write_chunk(fd, &typelib->typelib_segdir, sizeof(typelib->typelib_segdir))) return retval;
1515     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_TYPEINFO    )) return retval;
1516     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_GUIDHASH    )) return retval;
1517     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_GUID        )) return retval;
1518     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_IMPORTINFO  )) return retval;
1519     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_IMPORTFILES )) return retval;
1520     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_REFERENCES  )) return retval;
1521     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_NAMEHASH    )) return retval;
1522     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_NAME        )) return retval;
1523     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_STRING      )) return retval;
1524     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_TYPEDESC    )) return retval;
1525     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_ARRAYDESC   )) return retval;
1526     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_CUSTDATA    )) return retval;
1527     if (!ctl2_write_segment(typelib, fd, MSFT_SEG_CUSTDATAGUID)) return retval;
1528
1529     ctl2_write_typeinfos(typelib, fd);
1530
1531     if (close(fd) == -1) return retval;
1532
1533     retval = S_OK;
1534     return retval;
1535 }
1536
1537
1538
1539
1540 int create_msft_typelib(typelib_t *typelib)
1541 {
1542     msft_typelib_t *msft;
1543     int failed = 0, typelib_idx;
1544     typelib_entry_t *entry;
1545
1546     msft = malloc(sizeof(*msft));
1547     if (!msft) return 0;
1548     memset(msft, 0, sizeof(*msft));
1549     msft->typelib = typelib;
1550
1551     ctl2_init_header(msft);
1552     ctl2_init_segdir(msft);
1553
1554     msft->typelib_header.varflags |= SYS_WIN32;
1555
1556     /*
1557      * The following two calls return an offset or -1 if out of memory. We
1558      * specifically need an offset of 0, however, so...
1559      */
1560     if (ctl2_alloc_segment(msft, MSFT_SEG_GUIDHASH, 0x80, 0x80)) { failed = 1; }
1561     if (ctl2_alloc_segment(msft, MSFT_SEG_NAMEHASH, 0x200, 0x200)) { failed = 1; }
1562
1563     if(failed) return 0;
1564
1565     msft->typelib_guidhash_segment = (int *)msft->typelib_segment_data[MSFT_SEG_GUIDHASH];
1566     msft->typelib_namehash_segment = (int *)msft->typelib_segment_data[MSFT_SEG_NAMEHASH];
1567
1568     memset(msft->typelib_guidhash_segment, 0xff, 0x80);
1569     memset(msft->typelib_namehash_segment, 0xff, 0x200);
1570
1571     set_lib_flags(msft);
1572     set_lcid(msft);
1573 /*    set_help_file_name(msft);*/
1574     set_doc_string(msft);
1575     set_guid(msft);
1576     set_version(msft);
1577     set_name(msft);
1578
1579     typelib_idx = 0;
1580     for(entry = typelib->entry; NEXT_LINK(entry); entry = NEXT_LINK(entry))
1581         ;
1582     for( ; entry; entry = PREV_LINK(entry)) {
1583         msft_typeinfo_t *msft_typeinfo = create_msft_typeinfo(msft, entry, typelib_idx);
1584         switch(entry->kind) {
1585         case TKIND_INTERFACE:
1586           {
1587             int idx = 0;
1588             func_t *cur = entry->u.interface->funcs;
1589             while(NEXT_LINK(cur)) cur = NEXT_LINK(cur);
1590             while(cur) {
1591                 if(cur->idx == -1) cur->idx = idx;
1592                 else if(cur->idx != idx) error("method index mismatch\n");
1593                 add_func_desc(msft_typeinfo, cur);
1594                 idx++;
1595                 cur = PREV_LINK(cur);
1596             }
1597             break;
1598           }
1599         case TKIND_RECORD:
1600           {
1601             int idx = 0;
1602             var_t *cur = entry->u.structure->fields;
1603             while(NEXT_LINK(cur)) cur = NEXT_LINK(cur);
1604             while(cur) {
1605                 add_var_desc(msft_typeinfo, idx, cur);
1606                 idx++;
1607                 cur = PREV_LINK(cur);
1608             }
1609             break;
1610           }
1611                 
1612         default:
1613             error("create_msft_typelib: unhandled type %d\n", entry->kind);
1614             break;
1615         }
1616         typelib_idx++;
1617     }
1618     save_all_changes(msft);
1619     return 1;
1620 }