2 * Typelib v2 (MSFT) generation
4 * Copyright 2004 Alastair Bridgewater
5 * 2004, 2005 Huw Davies
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.
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.
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
21 * --------------------------------------------------------------------------------------
26 * Only works on little-endian systems.
31 #include "wine/port.h"
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
48 #include "wine/unicode.h"
50 #include "widltypes.h"
52 #include "typelib_struct.h"
56 enum MSFT_segment_index {
57 MSFT_SEG_TYPEINFO = 0, /* type information */
58 MSFT_SEG_IMPORTINFO, /* import information */
59 MSFT_SEG_IMPORTFILES, /* import filenames */
60 MSFT_SEG_REFERENCES, /* references (?) */
61 MSFT_SEG_GUIDHASH, /* hash table for guids? */
62 MSFT_SEG_GUID, /* guid storage */
63 MSFT_SEG_NAMEHASH, /* hash table for names */
64 MSFT_SEG_NAME, /* name storage */
65 MSFT_SEG_STRING, /* string storage */
66 MSFT_SEG_TYPEDESC, /* type descriptions */
67 MSFT_SEG_ARRAYDESC, /* array descriptions */
68 MSFT_SEG_CUSTDATA, /* custom data */
69 MSFT_SEG_CUSTDATAGUID, /* custom data guids */
70 MSFT_SEG_UNKNOWN, /* ??? */
71 MSFT_SEG_UNKNOWN2, /* ??? */
72 MSFT_SEG_MAX /* total number of segments */
75 typedef struct tagMSFT_ImpFile {
79 char filename[0]; /* preceeded by two bytes of encoded (length << 2) + flags in the low two bits. */
82 typedef struct _msft_typelib_t
85 MSFT_Header typelib_header;
86 MSFT_pSeg typelib_segdir[MSFT_SEG_MAX];
87 char *typelib_segment_data[MSFT_SEG_MAX];
88 int typelib_segment_block_length[MSFT_SEG_MAX];
90 INT typelib_typeinfo_offsets[0x200]; /* Hope that's enough. */
92 INT *typelib_namehash_segment;
93 INT *typelib_guidhash_segment;
95 INT help_string_dll_offset;
97 struct _msft_typeinfo_t *typeinfos;
98 struct _msft_typeinfo_t *last_typeinfo;
101 typedef struct _msft_typeinfo_t
103 msft_typelib_t *typelib;
104 MSFT_TypeInfoBase *typeinfo;
107 int typedata_allocated;
116 struct _msft_typeinfo_t *next_typeinfo;
121 /*================== Internal functions ===================================*/
123 /****************************************************************************
126 * Initializes the type library header of a new typelib.
128 static void ctl2_init_header(
129 msft_typelib_t *typelib) /* [I] The typelib to initialize. */
131 typelib->typelib_header.magic1 = 0x5446534d;
132 typelib->typelib_header.magic2 = 0x00010002;
133 typelib->typelib_header.posguid = -1;
134 typelib->typelib_header.lcid = 0x0409; /* or do we use the current one? */
135 typelib->typelib_header.lcid2 = 0x0;
136 typelib->typelib_header.varflags = 0x40;
137 typelib->typelib_header.version = 0;
138 typelib->typelib_header.flags = 0;
139 typelib->typelib_header.nrtypeinfos = 0;
140 typelib->typelib_header.helpstring = -1;
141 typelib->typelib_header.helpstringcontext = 0;
142 typelib->typelib_header.helpcontext = 0;
143 typelib->typelib_header.nametablecount = 0;
144 typelib->typelib_header.nametablechars = 0;
145 typelib->typelib_header.NameOffset = -1;
146 typelib->typelib_header.helpfile = -1;
147 typelib->typelib_header.CustomDataOffset = -1;
148 typelib->typelib_header.res44 = 0x20;
149 typelib->typelib_header.res48 = 0x80;
150 typelib->typelib_header.dispatchpos = -1;
151 typelib->typelib_header.res50 = 0;
154 /****************************************************************************
157 * Initializes the segment directory of a new typelib.
159 static void ctl2_init_segdir(
160 msft_typelib_t *typelib) /* [I] The typelib to initialize. */
165 segdir = &typelib->typelib_segdir[MSFT_SEG_TYPEINFO];
167 for (i = 0; i < 15; i++) {
168 segdir[i].offset = -1;
169 segdir[i].length = 0;
170 segdir[i].res08 = -1;
171 segdir[i].res0c = 0x0f;
175 /****************************************************************************
178 * Generates a hash key from a GUID.
182 * The hash key for the GUID.
184 static int ctl2_hash_guid(
185 REFGUID guid) /* [I] The guid to hash. */
191 for (i = 0; i < 8; i ++) {
192 hash ^= ((const short *)guid)[i];
198 /****************************************************************************
201 * Locates a guid in a type library.
205 * The offset into the GUID segment of the guid, or -1 if not found.
207 static int ctl2_find_guid(
208 msft_typelib_t *typelib, /* [I] The typelib to operate against. */
209 int hash_key, /* [I] The hash key for the guid. */
210 REFGUID guid) /* [I] The guid to find. */
213 MSFT_GuidEntry *guidentry;
215 offset = typelib->typelib_guidhash_segment[hash_key];
216 while (offset != -1) {
217 guidentry = (MSFT_GuidEntry *)&typelib->typelib_segment_data[MSFT_SEG_GUID][offset];
219 if (!memcmp(guidentry, guid, sizeof(GUID))) return offset;
221 offset = guidentry->next_hash;
227 /****************************************************************************
230 * Locates a name in a type library.
234 * The offset into the NAME segment of the name, or -1 if not found.
238 * The name must be encoded as with ctl2_encode_name().
240 static int ctl2_find_name(
241 msft_typelib_t *typelib, /* [I] The typelib to operate against. */
242 char *name) /* [I] The encoded name to find. */
247 offset = typelib->typelib_namehash_segment[name[2] & 0x7f];
248 while (offset != -1) {
249 namestruct = (int *)&typelib->typelib_segment_data[MSFT_SEG_NAME][offset];
251 if (!((namestruct[2] ^ *((int *)name)) & 0xffff00ff)) {
252 /* hash codes and lengths match, final test */
253 if (!strncasecmp(name+4, (void *)(namestruct+3), name[0])) break;
256 /* move to next item in hash bucket */
257 offset = namestruct[1];
263 /****************************************************************************
266 * Encodes a name string to a form suitable for storing into a type library
267 * or comparing to a name stored in a type library.
271 * The length of the encoded name, including padding and length+hash fields.
275 * Will throw an exception if name or result are NULL. Is not multithread
276 * safe in the slightest.
278 static int ctl2_encode_name(
279 msft_typelib_t *typelib, /* [I] The typelib to operate against (used for LCID only). */
280 const char *name, /* [I] The name string to encode. */
281 char **result) /* [O] A pointer to a pointer to receive the encoded name. */
284 static char converted_name[0x104];
288 length = strlen(name);
289 memcpy(converted_name + 4, name, length);
290 converted_name[0] = length & 0xff;
292 converted_name[length + 4] = 0;
294 converted_name[1] = 0x00;
296 value = lhash_val_of_name_sys(typelib->typelib_header.varflags & 0x0f, typelib->typelib_header.lcid, converted_name + 4);
298 converted_name[2] = value;
299 converted_name[3] = value >> 8;
301 for (offset = (4 - length) & 3; offset; offset--) converted_name[length + offset + 3] = 0x57;
303 *result = converted_name;
305 return (length + 7) & ~3;
308 /****************************************************************************
311 * Encodes a string to a form suitable for storing into a type library or
312 * comparing to a string stored in a type library.
316 * The length of the encoded string, including padding and length fields.
320 * Will throw an exception if string or result are NULL. Is not multithread
321 * safe in the slightest.
323 static int ctl2_encode_string(
324 msft_typelib_t *typelib, /* [I] The typelib to operate against (not used?). */
325 const char *string, /* [I] The string to encode. */
326 char **result) /* [O] A pointer to a pointer to receive the encoded string. */
329 static char converted_string[0x104];
332 length = strlen(string);
333 memcpy(converted_string + 2, string, length);
334 converted_string[0] = length & 0xff;
335 converted_string[1] = (length >> 8) & 0xff;
337 if(length < 3) { /* strings of this length are padded with upto 8 bytes incl the 2 byte length */
338 for(offset = 0; offset < 4; offset++)
339 converted_string[length + offset + 2] = 0x57;
342 for (offset = (4 - (length + 2)) & 3; offset; offset--) converted_string[length + offset + 1] = 0x57;
344 *result = converted_string;
346 return (length + 5) & ~3;
349 /****************************************************************************
352 * Allocates memory from a segment in a type library.
356 * Success: The offset within the segment of the new data area.
357 * Failure: -1 (this is invariably an out of memory condition).
361 * Does not (yet) handle the case where the allocated segment memory needs to grow.
363 static int ctl2_alloc_segment(
364 msft_typelib_t *typelib, /* [I] The type library in which to allocate. */
365 enum MSFT_segment_index segment, /* [I] The segment in which to allocate. */
366 int size, /* [I] The amount to allocate. */
367 int block_size) /* [I] Initial allocation block size, or 0 for default. */
371 if(!typelib->typelib_segment_data[segment]) {
372 if (!block_size) block_size = 0x2000;
374 typelib->typelib_segment_block_length[segment] = block_size;
375 typelib->typelib_segment_data[segment] = xmalloc(block_size);
376 if (!typelib->typelib_segment_data[segment]) return -1;
377 memset(typelib->typelib_segment_data[segment], 0x57, block_size);
380 while ((typelib->typelib_segdir[segment].length + size) > typelib->typelib_segment_block_length[segment]) {
383 block_size = typelib->typelib_segment_block_length[segment];
384 block = realloc(typelib->typelib_segment_data[segment], block_size << 1);
385 if (!block) return -1;
387 if (segment == MSFT_SEG_TYPEINFO) {
388 /* TypeInfos have a direct pointer to their memory space, so we have to fix them up. */
389 msft_typeinfo_t *typeinfo;
391 for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
392 typeinfo->typeinfo = (void *)&block[((char *)typeinfo->typeinfo) - typelib->typelib_segment_data[segment]];
396 memset(block + block_size, 0x57, block_size);
397 typelib->typelib_segment_block_length[segment] = block_size << 1;
398 typelib->typelib_segment_data[segment] = block;
401 offset = typelib->typelib_segdir[segment].length;
402 typelib->typelib_segdir[segment].length += size;
407 /****************************************************************************
408 * ctl2_alloc_typeinfo
410 * Allocates and initializes a typeinfo structure in a type library.
414 * Success: The offset of the new typeinfo.
415 * Failure: -1 (this is invariably an out of memory condition).
417 static int ctl2_alloc_typeinfo(
418 msft_typelib_t *typelib, /* [I] The type library to allocate in. */
419 int nameoffset) /* [I] The offset of the name for this typeinfo. */
422 MSFT_TypeInfoBase *typeinfo;
424 offset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEINFO, sizeof(MSFT_TypeInfoBase), 0);
425 if (offset == -1) return -1;
427 typelib->typelib_typeinfo_offsets[typelib->typelib_header.nrtypeinfos++] = offset;
429 typeinfo = (void *)(typelib->typelib_segment_data[MSFT_SEG_TYPEINFO] + offset);
431 typeinfo->typekind = (typelib->typelib_header.nrtypeinfos - 1) << 16;
432 typeinfo->memoffset = -1; /* should be EOF if no elements */
437 typeinfo->cElement = 0;
442 typeinfo->posguid = -1;
444 typeinfo->NameOffset = nameoffset;
445 typeinfo->version = 0;
446 typeinfo->docstringoffs = -1;
447 typeinfo->helpstringcontext = 0;
448 typeinfo->helpcontext = 0;
449 typeinfo->oCustData = -1;
450 typeinfo->cbSizeVft = 0;
451 typeinfo->cImplTypes = 0;
453 typeinfo->datatype1 = -1;
454 typeinfo->datatype2 = 0;
456 typeinfo->res19 = -1;
461 /****************************************************************************
464 * Allocates and initializes a GUID structure in a type library. Also updates
465 * the GUID hash table as needed.
469 * Success: The offset of the new GUID.
470 * Failure: -1 (this is invariably an out of memory condition).
472 static int ctl2_alloc_guid(
473 msft_typelib_t *typelib, /* [I] The type library to allocate in. */
474 MSFT_GuidEntry *guid) /* [I] The GUID to store. */
477 MSFT_GuidEntry *guid_space;
480 hash_key = ctl2_hash_guid(&guid->guid);
482 offset = ctl2_find_guid(typelib, hash_key, &guid->guid);
483 if (offset != -1) return offset;
485 offset = ctl2_alloc_segment(typelib, MSFT_SEG_GUID, sizeof(MSFT_GuidEntry), 0);
486 if (offset == -1) return -1;
488 guid_space = (void *)(typelib->typelib_segment_data[MSFT_SEG_GUID] + offset);
491 guid_space->next_hash = typelib->typelib_guidhash_segment[hash_key];
492 typelib->typelib_guidhash_segment[hash_key] = offset;
497 /****************************************************************************
500 * Allocates and initializes a name within a type library. Also updates the
501 * name hash table as needed.
505 * Success: The offset within the segment of the new name.
506 * Failure: -1 (this is invariably an out of memory condition).
508 static int ctl2_alloc_name(
509 msft_typelib_t *typelib, /* [I] The type library to allocate in. */
510 const char *name) /* [I] The name to store. */
514 MSFT_NameIntro *name_space;
517 length = ctl2_encode_name(typelib, name, &encoded_name);
519 offset = ctl2_find_name(typelib, encoded_name);
520 if (offset != -1) return offset;
522 offset = ctl2_alloc_segment(typelib, MSFT_SEG_NAME, length + 8, 0);
523 if (offset == -1) return -1;
525 name_space = (void *)(typelib->typelib_segment_data[MSFT_SEG_NAME] + offset);
526 name_space->hreftype = -1;
527 name_space->next_hash = -1;
528 memcpy(&name_space->namelen, encoded_name, length);
530 if (typelib->typelib_namehash_segment[encoded_name[2] & 0x7f] != -1)
531 name_space->next_hash = typelib->typelib_namehash_segment[encoded_name[2] & 0x7f];
533 typelib->typelib_namehash_segment[encoded_name[2] & 0x7f] = offset;
535 typelib->typelib_header.nametablecount += 1;
536 typelib->typelib_header.nametablechars += *encoded_name;
541 /****************************************************************************
544 * Allocates and initializes a string in a type library.
548 * Success: The offset within the segment of the new string.
549 * Failure: -1 (this is invariably an out of memory condition).
551 static int ctl2_alloc_string(
552 msft_typelib_t *typelib, /* [I] The type library to allocate in. */
553 const char *string) /* [I] The string to store. */
558 char *encoded_string;
560 length = ctl2_encode_string(typelib, string, &encoded_string);
562 for (offset = 0; offset < typelib->typelib_segdir[MSFT_SEG_STRING].length;
563 offset += ((((typelib->typelib_segment_data[MSFT_SEG_STRING][offset + 1] << 8) & 0xff)
564 | (typelib->typelib_segment_data[MSFT_SEG_STRING][offset + 0] & 0xff)) + 5) & ~3) {
565 if (!memcmp(encoded_string, typelib->typelib_segment_data[MSFT_SEG_STRING] + offset, length)) return offset;
568 offset = ctl2_alloc_segment(typelib, MSFT_SEG_STRING, length, 0);
569 if (offset == -1) return -1;
571 string_space = typelib->typelib_segment_data[MSFT_SEG_STRING] + offset;
572 memcpy(string_space, encoded_string, length);
577 /****************************************************************************
578 * ctl2_alloc_importinfo
580 * Allocates and initializes an import information structure in a type library.
584 * Success: The offset of the new importinfo.
585 * Failure: -1 (this is invariably an out of memory condition).
587 static int ctl2_alloc_importinfo(
588 msft_typelib_t *typelib, /* [I] The type library to allocate in. */
589 MSFT_ImpInfo *impinfo) /* [I] The import information to store. */
592 MSFT_ImpInfo *impinfo_space;
595 offset < typelib->typelib_segdir[MSFT_SEG_IMPORTINFO].length;
596 offset += sizeof(MSFT_ImpInfo)) {
597 if (!memcmp(&(typelib->typelib_segment_data[MSFT_SEG_IMPORTINFO][offset]),
598 impinfo, sizeof(MSFT_ImpInfo))) {
603 offset = ctl2_alloc_segment(typelib, MSFT_SEG_IMPORTINFO, sizeof(MSFT_ImpInfo), 0);
604 if (offset == -1) return -1;
606 impinfo_space = (void *)(typelib->typelib_segment_data[MSFT_SEG_IMPORTINFO] + offset);
607 *impinfo_space = *impinfo;
612 /****************************************************************************
613 * ctl2_alloc_importfile
615 * Allocates and initializes an import file definition in a type library.
619 * Success: The offset of the new importinfo.
620 * Failure: -1 (this is invariably an out of memory condition).
622 static int ctl2_alloc_importfile(
623 msft_typelib_t *typelib, /* [I] The type library to allocate in. */
624 int guidoffset, /* [I] The offset to the GUID for the imported library. */
625 int major_version, /* [I] The major version number of the imported library. */
626 int minor_version, /* [I] The minor version number of the imported library. */
627 const char *filename) /* [I] The filename of the imported library. */
631 MSFT_ImpFile *importfile;
632 char *encoded_string;
634 length = ctl2_encode_string(typelib, filename, &encoded_string);
636 encoded_string[0] <<= 2;
637 encoded_string[0] |= 1;
639 for (offset = 0; offset < typelib->typelib_segdir[MSFT_SEG_IMPORTFILES].length;
640 offset += ((((typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xd] << 8) & 0xff)
641 | (typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xc] & 0xff)) >> 2) + 0xc) {
642 if (!memcmp(encoded_string, typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES] + offset + 0xc, length)) return offset;
645 offset = ctl2_alloc_segment(typelib, MSFT_SEG_IMPORTFILES, length + 0xc, 0);
646 if (offset == -1) return -1;
648 importfile = (MSFT_ImpFile *)&typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset];
649 importfile->guid = guidoffset;
650 importfile->lcid = typelib->typelib_header.lcid2;
651 importfile->version = major_version | (minor_version << 16);
652 memcpy(&importfile->filename, encoded_string, length);
657 static void add_structure_typeinfo(msft_typelib_t *typelib, type_t *structure);
658 static void add_interface_typeinfo(msft_typelib_t *typelib, type_t *interface);
660 /****************************************************************************
663 * Encodes a type, storing information in the TYPEDESC and ARRAYDESC
664 * segments as needed.
671 static int encode_type(
672 msft_typelib_t *typelib, /* [I] The type library in which to encode the TYPEDESC. */
673 int vt, /* [I] vt to encode */
674 type_t *type, /* [I] type */
675 int *encoded_type, /* [O] The encoded type description. */
676 int *width, /* [O] The width of the type, or NULL. */
677 int *alignment, /* [O] The alignment of the type, or NULL. */
678 int *decoded_size) /* [O] The total size of the unencoded TYPEDESCs, including nested descs. */
687 chat("encode_type vt %d type %p\n", vt, type);
689 default_type = 0x80000000 | (vt << 16) | vt;
690 if (!width) width = &scratch;
691 if (!alignment) alignment = &scratch;
692 if (!decoded_size) decoded_size = &scratch;
698 *encoded_type = default_type;
704 *encoded_type = 0x80000000 | (VT_I4 << 16) | VT_INT;
705 if ((typelib->typelib_header.varflags & 0x0f) == SYS_WIN16) {
715 *encoded_type = 0x80000000 | (VT_UI4 << 16) | VT_UINT;
716 if ((typelib->typelib_header.varflags & 0x0f) == SYS_WIN16) {
728 *encoded_type = default_type;
739 *encoded_type = default_type;
745 *encoded_type = default_type;
751 *encoded_type = default_type;
753 *alignment = 4; /* guess? */
757 *encoded_type = 0x80000000 | (VT_EMPTY << 16) | vt;
764 *encoded_type = default_type;
770 *encoded_type = default_type;
776 while((next_vt = get_type_vt(type->ref)) == 0) {
777 if(type->ref == NULL) {
784 encode_type(typelib, next_vt, type->ref, &target_type, NULL, NULL, &child_size);
785 if(type->ref->type == RPC_FC_IP) {
786 chat("encode_type: skipping ptr\n");
787 *encoded_type = target_type;
790 *decoded_size = child_size;
794 for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
795 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
796 if (((typedata[0] & 0xffff) == VT_PTR) && (typedata[1] == target_type)) break;
799 if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
802 if (target_type & 0x80000000) {
803 mix_field = ((target_type >> 16) & 0x3fff) | VT_BYREF;
805 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type];
806 mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
809 typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0);
810 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
812 typedata[0] = (mix_field << 16) | VT_PTR;
813 typedata[1] = target_type;
816 *encoded_type = typeoffset;
820 *decoded_size = 8 /*sizeof(TYPEDESC)*/ + child_size;
827 /* FIXME: Make with the error checking. */
828 FIXME("SAFEARRAY vartype, may not work correctly.\n");
830 ctl2_encode_typedesc(typelib, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size);
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;
837 if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
840 if (target_type & 0x80000000) {
841 mix_field = ((target_type >> 16) & VT_TYPEMASK) | VT_ARRAY;
843 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type];
844 mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
847 typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0);
848 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
850 typedata[0] = (mix_field << 16) | VT_SAFEARRAY;
851 typedata[1] = target_type;
854 *encoded_tdesc = typeoffset;
858 *decoded_size = sizeof(TYPEDESC) + child_size;
867 chat("encode_type: VT_USERDEFINED - type %p name = %s type->type %d idx %d\n", type,
868 type->name, type->type, type->typelib_idx);
870 if(type->typelib_idx == -1) {
871 chat("encode_type: trying to ref not added type\n");
874 add_structure_typeinfo(typelib, type);
877 add_interface_typeinfo(typelib, type);
880 error("encode_type: VT_USERDEFINED - unhandled type %d\n", type->type);
884 typeinfo_offset = typelib->typelib_typeinfo_offsets[type->typelib_idx];
885 for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
886 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
887 if ((typedata[0] == ((0x7fff << 16) | VT_USERDEFINED)) && (typedata[1] == typeinfo_offset)) break;
890 if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
891 typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0);
892 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
894 typedata[0] = (0x7fff << 16) | VT_USERDEFINED;
895 typedata[1] = typeinfo_offset;
898 *encoded_type = typeoffset;
902 if(type->type == RPC_FC_IP) {
903 typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0);
904 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
906 typedata[0] = (0x7fff << 16) | VT_PTR;
907 typedata[1] = *encoded_type;
908 *encoded_type = typeoffset;
917 error("encode_type: unrecognized type %d.\n", vt);
918 *encoded_type = default_type;
927 static void dump_type(type_t *t)
929 chat("dump_type: %p name %s type %d ref %p rname %s\n", t, t->name, t->type, t->ref, t->rname);
930 if(t->ref) dump_type(t->ref);
933 static int encode_var(
934 msft_typelib_t *typelib, /* [I] The type library in which to encode the TYPEDESC. */
935 var_t *var, /* [I] The type description to encode. */
936 int *encoded_type, /* [O] The encoded type description. */
937 int *width, /* [O] The width of the type, or NULL. */
938 int *alignment, /* [O] The alignment of the type, or NULL. */
939 int *decoded_size) /* [O] The total size of the unencoded TYPEDESCs, including nested descs. */
949 if (!width) width = &scratch;
950 if (!alignment) alignment = &scratch;
951 if (!decoded_size) decoded_size = &scratch;
954 chat("encode_var: var %p var->tname %s var->type %p var->ptr_level %d var->type->ref %p\n", var, var->tname, var->type, var->ptr_level, var->type->ref);
958 skip_ptr = encode_var(typelib, var, &target_type, NULL, NULL, &child_size);
962 chat("encode_var: skipping ptr\n");
963 *encoded_type = target_type;
964 *decoded_size = child_size;
970 for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
971 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
972 if (((typedata[0] & 0xffff) == VT_PTR) && (typedata[1] == target_type)) break;
975 if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
978 if (target_type & 0x80000000) {
979 mix_field = ((target_type >> 16) & 0x3fff) | VT_BYREF;
981 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type];
982 mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
985 typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0);
986 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
988 typedata[0] = (mix_field << 16) | VT_PTR;
989 typedata[1] = target_type;
992 *encoded_type = typeoffset;
996 *decoded_size = 8 /*sizeof(TYPEDESC)*/ + child_size;
1001 expr_t *dim = var->array;
1003 int num_dims = 1, elements = 1, arrayoffset;
1006 while(NEXT_LINK(dim)) {
1007 dim = NEXT_LINK(dim);
1010 chat("array with %d dimensions\n", num_dims);
1011 array_save = var->array;
1013 encode_var(typelib, var, &target_type, width, alignment, NULL);
1014 var->array = array_save;
1015 arrayoffset = ctl2_alloc_segment(typelib, MSFT_SEG_ARRAYDESC, (2 + 2 * num_dims) * sizeof(long), 0);
1016 arraydata = (void *)&typelib->typelib_segment_data[MSFT_SEG_ARRAYDESC][arrayoffset];
1018 arraydata[0] = target_type;
1019 arraydata[1] = num_dims;
1020 arraydata[1] |= ((num_dims * 2 * sizeof(long)) << 16);
1024 arraydata[0] = dim->cval;
1027 elements *= dim->cval;
1028 dim = PREV_LINK(dim);
1031 typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0);
1032 typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
1034 typedata[0] = (0x7ffe << 16) | VT_CARRAY;
1035 typedata[1] = arrayoffset;
1037 *encoded_type = typeoffset;
1038 *width = *width * elements;
1039 *decoded_size = 20 /*sizeof(ARRAYDESC)*/ + (num_dims - 1) * 8 /*sizeof(SAFEARRAYBOUND)*/;
1042 dump_type(var->type);
1044 vt = get_var_vt(var);
1047 if(type->ref == NULL) {
1052 vt = get_type_vt(type);
1054 encode_type(typelib, vt, type, encoded_type, width, alignment, decoded_size);
1055 if(type->type == RPC_FC_IP) return 2;
1060 /****************************************************************************
1061 * ctl2_find_nth_reference
1063 * Finds a reference by index into the linked list of reference records.
1067 * Success: Offset of the desired reference record.
1070 static int ctl2_find_nth_reference(
1071 msft_typelib_t *typelib, /* [I] The type library in which to search. */
1072 int offset, /* [I] The starting offset of the reference list. */
1073 int index) /* [I] The index of the reference to find. */
1075 MSFT_RefRecord *ref;
1077 for (; index && (offset != -1); index--) {
1078 ref = (MSFT_RefRecord *)&typelib->typelib_segment_data[MSFT_SEG_REFERENCES][offset];
1079 offset = ref->onext;
1086 static void write_value(msft_typelib_t* typelib, int *out, int vt, void *value)
1101 unsigned long *lv = value;
1102 if((*lv & 0x3ffffff) == *lv) {
1107 int offset = ctl2_alloc_segment(typelib, MSFT_SEG_CUSTDATA, 8, 0);
1108 *((unsigned short *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset]) = vt;
1109 memcpy(&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+2], value, 4);
1110 *((unsigned short *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+6]) = 0x5757;
1117 char *s = (char *) value;
1118 int len = strlen(s), seg_len = (len + 6 + 3) & ~0x3;
1119 int offset = ctl2_alloc_segment(typelib, MSFT_SEG_CUSTDATA, seg_len, 0);
1120 *((unsigned short *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset]) = vt;
1121 *((unsigned int *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+2]) = len;
1122 memcpy(&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+6], value, len);
1124 while(len < seg_len) {
1125 *((char *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+len]) = 0x57;
1133 warning("can't write value of type %d yet\n", vt);
1138 static HRESULT set_custdata(msft_typelib_t *typelib, REFGUID guid,
1139 int vt, void *value, int *offset)
1141 MSFT_GuidEntry guidentry;
1147 guidentry.guid = *guid;
1149 guidentry.hreftype = -1;
1150 guidentry.next_hash = -1;
1152 guidoffset = ctl2_alloc_guid(typelib, &guidentry);
1153 if (guidoffset == -1) return E_OUTOFMEMORY;
1154 write_value(typelib, &data_out, vt, value);
1156 custoffset = ctl2_alloc_segment(typelib, MSFT_SEG_CUSTDATAGUID, 12, 0);
1157 if (custoffset == -1) return E_OUTOFMEMORY;
1159 custdata = (int *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATAGUID][custoffset];
1160 custdata[0] = guidoffset;
1161 custdata[1] = data_out;
1162 custdata[2] = *offset;
1163 *offset = custoffset;
1168 static HRESULT add_func_desc(msft_typeinfo_t* typeinfo, func_t *func, int index)
1173 int decoded_size, extra_attr = 0;
1174 int num_params = 0, num_defaults = 0;
1175 var_t *arg, *last_arg = NULL;
1178 unsigned int funcflags = 0, callconv = 4 /* CC_STDCALL */;
1179 unsigned int funckind = 1 /* FUNC_PUREVIRTUAL */, invokekind = 1 /* INVOKE_FUNC */;
1180 int help_context = 0, help_string_context = 0, help_string_offset = -1;
1182 id = ((0x6000 | typeinfo->typeinfo->cImplTypes) << 16) | index;
1184 chat("add_func_desc(%p,%d)\n", typeinfo, index);
1186 for(attr = func->def->attrs; attr; attr = NEXT_LINK(attr)) {
1187 if(attr->type == ATTR_LOCAL) {
1188 chat("add_func_desc: skipping local function\n");
1193 if (!typeinfo->typedata) {
1194 typeinfo->typedata = xmalloc(0x2000);
1195 typeinfo->typedata[0] = 0;
1198 for(arg = func->args; arg; arg = NEXT_LINK(arg)) {
1201 for(attr = arg->attrs; attr; attr = NEXT_LINK(attr)) {
1202 if(attr->type == ATTR_DEFAULTVALUE_EXPR || attr->type == ATTR_DEFAULTVALUE_STRING) {
1209 chat("add_func_desc: num of params %d\n", num_params);
1211 for(attr = func->def->attrs; attr; attr = NEXT_LINK(attr)) {
1212 expr_t *expr = attr->u.pval;
1213 switch(attr->type) {
1214 case ATTR_HELPCONTEXT:
1216 help_context = expr->u.lval;
1218 case ATTR_HELPSTRING:
1220 help_string_offset = ctl2_alloc_string(typeinfo->typelib, attr->u.pval);
1222 case ATTR_HELPSTRINGCONTEXT:
1224 help_string_context = expr->u.lval;
1227 funcflags |= 0x40; /* FUNCFLAG_FHIDDEN */
1235 invokekind = 0x2; /* INVOKE_PROPERTYGET */
1238 invokekind = 0x4; /* INVOKE_PROPERTYPUT */
1240 case ATTR_RESTRICTED:
1241 funcflags |= 0x1; /* FUNCFLAG_FRESTRICTED */
1244 warning("add_func_desc: ignoring attr %d\n", attr->type);
1248 /* allocate type data space for us */
1249 offset = typeinfo->typedata[0];
1250 typeinfo->typedata[0] += 0x18 + extra_attr * sizeof(int) + (num_params * (num_defaults ? 16 : 12));
1251 typedata = typeinfo->typedata + (offset >> 2) + 1;
1253 /* fill out the basic type information */
1254 typedata[0] = (0x18 + extra_attr * sizeof(int) + (num_params * (num_defaults ? 16 : 12))) | (index << 16);
1255 encode_var(typeinfo->typelib, func->def, &typedata[1], NULL, NULL, &decoded_size);
1256 typedata[2] = funcflags;
1257 typedata[3] = ((52 /*sizeof(FUNCDESC)*/ + decoded_size) << 16) | typeinfo->typeinfo->cbSizeVft;
1258 typedata[4] = (index << 16) | (callconv << 8) | (invokekind << 3) | funckind;
1259 if(num_defaults) typedata[4] |= 0x1000;
1260 typedata[5] = num_params;
1262 /* NOTE: High word of typedata[3] is total size of FUNCDESC + size of all ELEMDESCs for params + TYPEDESCs for pointer params and return types. */
1263 /* That is, total memory allocation required to reconstitute the FUNCDESC in its entirety. */
1264 typedata[3] += (16 /*sizeof(ELEMDESC)*/ * num_params) << 16;
1265 typedata[3] += (24 /*sizeof(PARAMDESCEX)*/ * num_defaults) << 16;
1267 switch(extra_attr) {
1268 case 6: typedata[11] = help_string_context;
1269 case 5: typedata[10] = -1;
1270 case 4: typedata[9] = -1;
1271 case 3: typedata[8] = -1;
1272 case 2: typedata[7] = help_string_offset;
1273 case 1: typedata[6] = help_context;
1277 warning("unknown number of optional attrs\n");
1280 for (arg = last_arg, i = 0; arg; arg = PREV_LINK(arg), i++) {
1283 int *paramdata = typedata + 6 + extra_attr + (num_defaults ? num_params : 0) + i * 3;
1284 int *defaultdata = num_defaults ? typedata + 6 + extra_attr + i : NULL;
1286 if(defaultdata) *defaultdata = -1;
1288 encode_var(typeinfo->typelib, arg, paramdata, NULL, NULL, &decoded_size);
1289 for(attr = arg->attrs; attr; attr = NEXT_LINK(attr)) {
1290 switch(attr->type) {
1291 case ATTR_DEFAULTVALUE_EXPR:
1293 expr_t *expr = (expr_t *)attr->u.pval;
1294 paramflags |= 0x30; /* PARAMFLAG_FHASDEFAULT | PARAMFLAG_FOPT */
1295 chat("default value %ld\n", expr->cval);
1296 write_value(typeinfo->typelib, defaultdata, (*paramdata >> 16) & 0x1ff, &expr->cval);
1299 case ATTR_DEFAULTVALUE_STRING:
1301 char *s = (char *)attr->u.pval;
1302 paramflags |= 0x30; /* PARAMFLAG_FHASDEFAULT | PARAMFLAG_FOPT */
1303 chat("default value '%s'\n", s);
1304 write_value(typeinfo->typelib, defaultdata, (*paramdata >> 16) & 0x1ff, s);
1308 paramflags |= 0x01; /* PARAMFLAG_FIN */
1311 paramflags |= 0x10; /* PARAMFLAG_FOPT */
1314 paramflags |= 0x02; /* PARAMFLAG_FOUT */
1317 paramflags |= 0x08; /* PARAMFLAG_FRETVAL */
1320 chat("unhandled param attr %d\n", attr->type);
1325 paramdata[2] = paramflags;
1326 typedata[3] += decoded_size << 16;
1329 /* update the index data */
1330 typeinfo->indices[index] = id;
1331 typeinfo->names[index] = -1;
1332 typeinfo->offsets[index] = offset;
1335 if (!typeinfo->typeinfo->res2) typeinfo->typeinfo->res2 = 0x20;
1336 typeinfo->typeinfo->res2 <<= 1;
1338 if (index < 2) typeinfo->typeinfo->res2 += num_params << 4;
1340 if (typeinfo->typeinfo->res3 == -1) typeinfo->typeinfo->res3 = 0;
1341 typeinfo->typeinfo->res3 += 0x38 + num_params * 0x10;
1342 if(num_defaults) typeinfo->typeinfo->res3 += num_params * 0x4;
1344 /* adjust size of VTBL */
1345 typeinfo->typeinfo->cbSizeVft += 4;
1347 /* Increment the number of function elements */
1348 typeinfo->typeinfo->cElement += 1;
1351 offset = ctl2_alloc_name(typeinfo->typelib, func->def->name);
1352 chat("name offset = %d index %d\n", offset, index);
1353 typeinfo->names[index] = offset;
1355 namedata = typeinfo->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset;
1356 namedata[9] &= ~0x10;
1357 if (*((INT *)namedata) == -1) {
1358 *((INT *)namedata) = typeinfo->typelib->typelib_typeinfo_offsets[typeinfo->typeinfo->typekind >> 16];
1361 for (arg = last_arg, i = 0; arg; arg = PREV_LINK(arg), i++) {
1362 /* FIXME: Almost certainly easy to break */
1363 int *paramdata = &typeinfo->typedata[typeinfo->offsets[index] >> 2];
1364 paramdata += 7 + extra_attr + (num_defaults ? num_params : 0) + i * 3;
1365 offset = ctl2_alloc_name(typeinfo->typelib, arg->name);
1366 paramdata[1] = offset;
1367 chat("param %d name %s offset %d\n", i, arg->name, offset);
1373 static void set_alignment(
1374 msft_typeinfo_t* typeinfo,
1378 if (!cbAlignment) return;
1379 if (cbAlignment > 16) return;
1381 typeinfo->typeinfo->typekind &= ~0xf800;
1383 /* FIXME: There's probably some way to simplify this. */
1384 switch (typeinfo->typeinfo->typekind & 15) {
1390 case TKIND_INTERFACE:
1391 case TKIND_DISPATCH:
1393 if (cbAlignment > 4) cbAlignment = 4;
1403 typeinfo->typeinfo->typekind |= cbAlignment << 11;
1408 static HRESULT add_var_desc(msft_typeinfo_t *typeinfo, UINT index, var_t* var)
1420 chat("add_var_desc(%d,%s) array %p\n", index, var->name, var->array);
1422 if ((typeinfo->typeinfo->cElement >> 16) != index) {
1423 error("Out-of-order element.\n");
1424 return TYPE_E_ELEMENTNOTFOUND;
1428 for(attr = var->attrs; attr; attr = NEXT_LINK(attr)) {
1429 switch(attr->type) {
1431 warning("AddVarDesc: unhandled attr type %d\n", attr->type);
1436 if (!typeinfo->typedata) {
1437 typeinfo->typedata = xmalloc(0x2000);
1438 typeinfo->typedata[0] = 0;
1441 /* allocate type data space for us */
1442 offset = typeinfo->typedata[0];
1443 typeinfo->typedata[0] += 0x14;
1444 typedata = typeinfo->typedata + (offset >> 2) + 1;
1446 /* fill out the basic type information */
1447 typedata[0] = 0x14 | (index << 16);
1448 typedata[2] = varflags;
1449 typedata[3] = (36 /*sizeof(VARDESC)*/ << 16) | 0;
1451 /* update the index data */
1452 typeinfo->indices[index] = 0x40000000 + index;
1453 typeinfo->names[index] = -1;
1454 typeinfo->offsets[index] = offset;
1456 /* figure out type widths and whatnot */
1457 encode_var(typeinfo->typelib, var, &typedata[1], &var_datawidth,
1458 &var_alignment, &var_type_size);
1460 /* pad out starting position to data width */
1461 typeinfo->datawidth += var_alignment - 1;
1462 typeinfo->datawidth &= ~(var_alignment - 1);
1463 typedata[4] = typeinfo->datawidth;
1465 /* add the new variable to the total data width */
1466 typeinfo->datawidth += var_datawidth;
1468 /* add type description size to total required allocation */
1469 typedata[3] += var_type_size << 16;
1471 /* fix type alignment */
1472 alignment = (typeinfo->typeinfo->typekind >> 11) & 0x1f;
1473 if (alignment < var_alignment) {
1474 alignment = var_alignment;
1475 typeinfo->typeinfo->typekind &= ~0xf800;
1476 typeinfo->typeinfo->typekind |= alignment << 11;
1480 if (!typeinfo->typeinfo->res2) typeinfo->typeinfo->res2 = 0x1a;
1481 if ((index == 0) || (index == 1) || (index == 2) || (index == 4) || (index == 9)) {
1482 typeinfo->typeinfo->res2 <<= 1;
1486 if (typeinfo->typeinfo->res3 == -1) typeinfo->typeinfo->res3 = 0;
1487 typeinfo->typeinfo->res3 += 0x2c;
1489 /* increment the number of variable elements */
1490 typeinfo->typeinfo->cElement += 0x10000;
1492 /* pad data width to alignment */
1493 typeinfo->typeinfo->size = (typeinfo->datawidth + (alignment - 1)) & ~(alignment - 1);
1495 offset = ctl2_alloc_name(typeinfo->typelib, var->name);
1496 if (offset == -1) return E_OUTOFMEMORY;
1498 namedata = typeinfo->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset;
1499 if (*((INT *)namedata) == -1) {
1500 *((INT *)namedata) = typeinfo->typelib->typelib_typeinfo_offsets[typeinfo->typeinfo->typekind >> 16];
1501 namedata[9] |= 0x10;
1503 if ((typeinfo->typeinfo->typekind & 15) == TKIND_ENUM) {
1504 namedata[9] |= 0x20;
1506 typeinfo->names[index] = offset;
1511 static HRESULT add_impl_type(msft_typeinfo_t *typeinfo, type_t *ref)
1513 if(ref->typelib_idx == -1)
1514 add_interface_typeinfo(typeinfo->typelib, ref);
1515 if(ref->typelib_idx == -1)
1516 error("add_impl_type: unable to add inherited interface\n");
1518 typeinfo->typeinfo->datatype1 = typeinfo->typelib->typelib_typeinfo_offsets[ref->typelib_idx];
1519 typeinfo->typeinfo->cImplTypes++;
1523 static msft_typeinfo_t *create_msft_typeinfo(msft_typelib_t *typelib, enum type_kind kind,
1524 char *name, attr_t *attr, int idx)
1526 msft_typeinfo_t *msft_typeinfo;
1528 int typeinfo_offset;
1529 MSFT_TypeInfoBase *typeinfo;
1530 MSFT_GuidEntry guidentry;
1532 chat("create_msft_typeinfo: name %s kind %d\n", name, kind);
1534 msft_typeinfo = xmalloc(sizeof(*msft_typeinfo));
1536 msft_typeinfo->typelib = typelib;
1538 nameoffset = ctl2_alloc_name(typelib, name);
1539 typeinfo_offset = ctl2_alloc_typeinfo(typelib, nameoffset);
1540 typeinfo = (MSFT_TypeInfoBase *)&typelib->typelib_segment_data[MSFT_SEG_TYPEINFO][typeinfo_offset];
1542 typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset + 9] = 0x38;
1543 *((int *)&typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset]) = typeinfo_offset;
1545 msft_typeinfo->typeinfo = typeinfo;
1547 typeinfo->typekind |= kind | 0x220;
1548 set_alignment(msft_typeinfo, 4);
1550 for( ; attr; attr = NEXT_LINK(attr)) {
1551 switch(attr->type) {
1552 case ATTR_HELPCONTEXT:
1554 expr_t *expr = (expr_t*)attr->u.pval;
1555 typeinfo->helpcontext = expr->cval;
1558 case ATTR_HELPSTRING:
1560 int offset = ctl2_alloc_string(typelib, attr->u.pval);
1561 if (offset == -1) break;
1562 typeinfo->docstringoffs = offset;
1565 case ATTR_HELPSTRINGCONTEXT:
1567 expr_t *expr = (expr_t*)attr->u.pval;
1568 typeinfo->helpstringcontext = expr->cval;
1572 typeinfo->flags |= 0x10; /* TYPEFLAG_FHIDDEN */
1578 case ATTR_RESTRICTED:
1579 typeinfo->flags |= 0x200; /* TYPEFLAG_FRESTRICTED */
1583 guidentry.guid = *(GUID*)attr->u.pval;
1584 guidentry.hreftype = typelib->typelib_typeinfo_offsets[typeinfo->typekind >> 16];
1585 guidentry.next_hash = -1;
1586 typeinfo->posguid = ctl2_alloc_guid(typelib, &guidentry);
1588 if (IsEqualIID(guid, &IID_IDispatch)) {
1589 typelib->typelib_header.dispatchpos = typelib->typelib_typeinfo_offsets[typeinfo->typekind >> 16];
1595 typeinfo->version = attr->u.ival;
1599 warning("create_msft_typeinfo: ignoring attr %d\n", attr->type);
1604 if (typelib->last_typeinfo) typelib->last_typeinfo->next_typeinfo = msft_typeinfo;
1605 typelib->last_typeinfo = msft_typeinfo;
1606 if (!typelib->typeinfos) typelib->typeinfos = msft_typeinfo;
1609 return msft_typeinfo;
1613 static void add_interface_typeinfo(msft_typelib_t *typelib, type_t *interface)
1616 func_t *cur = interface->funcs;
1617 msft_typeinfo_t *msft_typeinfo;
1619 interface->typelib_idx = typelib->typelib_header.nrtypeinfos;
1620 msft_typeinfo = create_msft_typeinfo(typelib, TKIND_INTERFACE, interface->name, interface->attrs,
1621 typelib->typelib_header.nrtypeinfos);
1622 msft_typeinfo->typeinfo->size = 4;
1625 add_impl_type(msft_typeinfo, interface->ref);
1627 while(NEXT_LINK(cur)) cur = NEXT_LINK(cur);
1629 if(add_func_desc(msft_typeinfo, cur, idx) == S_OK)
1631 cur = PREV_LINK(cur);
1635 static void add_structure_typeinfo(msft_typelib_t *typelib, type_t *structure)
1638 var_t *cur = structure->fields;
1639 msft_typeinfo_t *msft_typeinfo;
1641 structure->typelib_idx = typelib->typelib_header.nrtypeinfos;
1642 msft_typeinfo = create_msft_typeinfo(typelib, TKIND_RECORD, structure->name, structure->attrs,
1643 typelib->typelib_header.nrtypeinfos);
1644 msft_typeinfo->typeinfo->size = 0;
1646 while(NEXT_LINK(cur)) cur = NEXT_LINK(cur);
1648 add_var_desc(msft_typeinfo, idx, cur);
1650 cur = PREV_LINK(cur);
1654 static void add_entry(msft_typelib_t *typelib, typelib_entry_t *entry)
1656 switch(entry->kind) {
1657 case TKIND_INTERFACE:
1658 add_interface_typeinfo(typelib, entry->u.interface);
1662 add_structure_typeinfo(typelib, entry->u.structure);
1666 error("add_entry: unhandled type %d\n", entry->kind);
1672 static void set_name(msft_typelib_t *typelib)
1676 offset = ctl2_alloc_name(typelib, typelib->typelib->name);
1677 if (offset == -1) return;
1678 typelib->typelib_header.NameOffset = offset;
1682 static void set_version(msft_typelib_t *typelib)
1684 long version = MAKELONG(0,0);
1687 for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1688 if(attr->type == ATTR_VERSION) {
1689 version = attr->u.ival;
1692 typelib->typelib_header.version = version;
1696 static void set_guid(msft_typelib_t *typelib)
1698 MSFT_GuidEntry guidentry;
1701 GUID guid = {0,0,0,{0,0,0,0,0,0}};
1703 guidentry.guid = guid;
1704 guidentry.hreftype = -2;
1705 guidentry.next_hash = -1;
1707 for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1708 if(attr->type == ATTR_UUID) {
1709 guidentry.guid = *(GUID*)(attr->u.pval);
1713 offset = ctl2_alloc_guid(typelib, &guidentry);
1715 if (offset == -1) return;
1717 typelib->typelib_header.posguid = offset;
1722 static void set_doc_string(msft_typelib_t *typelib)
1727 for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1728 if(attr->type == ATTR_HELPSTRING) {
1729 offset = ctl2_alloc_string(typelib, attr->u.pval);
1730 if (offset == -1) return;
1731 typelib->typelib_header.helpstring = offset;
1737 static void set_help_file_name(msft_typelib_t *typelib)
1741 for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1742 if(attr->type == ATTR_HELPFILE) {
1743 offset = ctl2_alloc_string(typelib, attr->u.pval);
1744 if (offset == -1) return;
1745 typelib->typelib_header.helpfile = offset;
1746 typelib->typelib_header.varflags |= 0x10;
1752 static void set_help_context(msft_typelib_t *typelib)
1755 for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1756 if(attr->type == ATTR_HELPCONTEXT) {
1757 expr_t *expr = (expr_t *)attr->u.pval;
1758 typelib->typelib_header.helpcontext = expr->cval;
1764 static void set_help_string_dll(msft_typelib_t *typelib)
1768 for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1769 if(attr->type == ATTR_HELPSTRINGDLL) {
1770 offset = ctl2_alloc_string(typelib, attr->u.pval);
1771 if (offset == -1) return;
1772 typelib->help_string_dll_offset = offset;
1773 typelib->typelib_header.varflags |= 0x100;
1779 static void set_help_string_context(msft_typelib_t *typelib)
1782 for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1783 if(attr->type == ATTR_HELPSTRINGCONTEXT) {
1784 expr_t *expr = (expr_t *)attr->u.pval;
1785 typelib->typelib_header.helpstringcontext = expr->cval;
1791 static void set_lcid(msft_typelib_t *typelib)
1793 typelib->typelib_header.lcid2 = 0x0;
1797 static void set_lib_flags(msft_typelib_t *typelib)
1801 typelib->typelib_header.flags = 0;
1802 for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) {
1803 switch(attr->type) {
1805 typelib->typelib_header.flags |= 0x02; /* LIBFLAG_FCONTROL */
1808 typelib->typelib_header.flags |= 0x04; /* LIBFLAG_FHIDDEN */
1810 case ATTR_RESTRICTED:
1811 typelib->typelib_header.flags |= 0x01; /* LIBFLAG_FRESTRICTED */
1820 static int ctl2_write_chunk(int fd, void *segment, int length)
1822 if (write(fd, segment, length) != length) {
1829 static int ctl2_write_segment(msft_typelib_t *typelib, int fd, int segment)
1831 if (write(fd, typelib->typelib_segment_data[segment], typelib->typelib_segdir[segment].length)
1832 != typelib->typelib_segdir[segment].length) {
1840 static void ctl2_finalize_typeinfos(msft_typelib_t *typelib, int filesize)
1842 msft_typeinfo_t *typeinfo;
1844 for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
1845 typeinfo->typeinfo->memoffset = filesize;
1846 if (typeinfo->typedata) {
1847 /*LayOut(typeinfo);*/
1848 filesize += typeinfo->typedata[0] + ((typeinfo->typeinfo->cElement >> 16) * 12) + ((typeinfo->typeinfo->cElement & 0xffff) * 12) + 4;
1853 static int ctl2_finalize_segment(msft_typelib_t *typelib, int filepos, int segment)
1855 if (typelib->typelib_segdir[segment].length) {
1856 typelib->typelib_segdir[segment].offset = filepos;
1858 typelib->typelib_segdir[segment].offset = -1;
1861 return typelib->typelib_segdir[segment].length;
1865 static void ctl2_write_typeinfos(msft_typelib_t *typelib, int fd)
1867 msft_typeinfo_t *typeinfo;
1869 for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
1870 if (!typeinfo->typedata) continue;
1872 ctl2_write_chunk(fd, typeinfo->typedata, typeinfo->typedata[0] + 4);
1873 ctl2_write_chunk(fd, typeinfo->indices, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
1874 chat("writing name chunk len %d %08lx\n", ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4, *(DWORD*)typeinfo->names);
1875 ctl2_write_chunk(fd, typeinfo->names, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
1876 ctl2_write_chunk(fd, typeinfo->offsets, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4);
1880 static int save_all_changes(msft_typelib_t *typelib)
1886 chat("save_all_changes(%p)\n", typelib);
1888 retval = TYPE_E_IOERROR;
1890 fd = creat(typelib->typelib->filename, 0666);
1891 if (fd == -1) return retval;
1893 filepos = sizeof(MSFT_Header) + sizeof(MSFT_SegDir);
1894 if(typelib->typelib_header.varflags & 0x100) filepos += 4; /* helpstringdll */
1895 filepos += typelib->typelib_header.nrtypeinfos * 4;
1897 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_TYPEINFO);
1898 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_GUIDHASH);
1899 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_GUID);
1900 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_IMPORTINFO);
1901 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_IMPORTFILES);
1902 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_REFERENCES);
1903 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_NAMEHASH);
1904 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_NAME);
1905 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_STRING);
1906 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_TYPEDESC);
1907 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_ARRAYDESC);
1908 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_CUSTDATA);
1909 filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_CUSTDATAGUID);
1911 ctl2_finalize_typeinfos(typelib, filepos);
1913 if (!ctl2_write_chunk(fd, &typelib->typelib_header, sizeof(typelib->typelib_header))) return retval;
1914 if(typelib->typelib_header.varflags & 0x100)
1915 if (!ctl2_write_chunk(fd, &typelib->help_string_dll_offset, sizeof(typelib->help_string_dll_offset)))
1918 if (!ctl2_write_chunk(fd, typelib->typelib_typeinfo_offsets, typelib->typelib_header.nrtypeinfos * 4)) return retval;
1919 if (!ctl2_write_chunk(fd, &typelib->typelib_segdir, sizeof(typelib->typelib_segdir))) return retval;
1920 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_TYPEINFO )) return retval;
1921 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_GUIDHASH )) return retval;
1922 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_GUID )) return retval;
1923 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_IMPORTINFO )) return retval;
1924 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_IMPORTFILES )) return retval;
1925 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_REFERENCES )) return retval;
1926 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_NAMEHASH )) return retval;
1927 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_NAME )) return retval;
1928 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_STRING )) return retval;
1929 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_TYPEDESC )) return retval;
1930 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_ARRAYDESC )) return retval;
1931 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_CUSTDATA )) return retval;
1932 if (!ctl2_write_segment(typelib, fd, MSFT_SEG_CUSTDATAGUID)) return retval;
1934 ctl2_write_typeinfos(typelib, fd);
1936 if (close(fd) == -1) return retval;
1942 int create_msft_typelib(typelib_t *typelib)
1944 msft_typelib_t *msft;
1946 typelib_entry_t *entry;
1948 unsigned int version = 5 << 24 | 1 << 16 | 164; /* 5.01.0164 */
1949 GUID midl_time_guid = {0xde77ba63,0x517c,0x11d1,{0xa2,0xda,0x00,0x00,0xf8,0x77,0x3c,0xe9}};
1950 GUID midl_version_guid = {0xde77ba64,0x517c,0x11d1,{0xa2,0xda,0x00,0x00,0xf8,0x77,0x3c,0xe9}};
1952 msft = malloc(sizeof(*msft));
1953 if (!msft) return 0;
1954 memset(msft, 0, sizeof(*msft));
1955 msft->typelib = typelib;
1957 ctl2_init_header(msft);
1958 ctl2_init_segdir(msft);
1960 msft->typelib_header.varflags |= SYS_WIN32;
1963 * The following two calls return an offset or -1 if out of memory. We
1964 * specifically need an offset of 0, however, so...
1966 if (ctl2_alloc_segment(msft, MSFT_SEG_GUIDHASH, 0x80, 0x80)) { failed = 1; }
1967 if (ctl2_alloc_segment(msft, MSFT_SEG_NAMEHASH, 0x200, 0x200)) { failed = 1; }
1969 if(failed) return 0;
1971 msft->typelib_guidhash_segment = (int *)msft->typelib_segment_data[MSFT_SEG_GUIDHASH];
1972 msft->typelib_namehash_segment = (int *)msft->typelib_segment_data[MSFT_SEG_NAMEHASH];
1974 memset(msft->typelib_guidhash_segment, 0xff, 0x80);
1975 memset(msft->typelib_namehash_segment, 0xff, 0x200);
1977 set_lib_flags(msft);
1979 set_help_file_name(msft);
1980 set_doc_string(msft);
1984 set_help_context(msft);
1985 set_help_string_dll(msft);
1986 set_help_string_context(msft);
1988 /* midl adds two sets of custom data to the library: the current unix time
1989 and midl's version number */
1990 cur_time = time(NULL);
1991 set_custdata(msft, &midl_time_guid, VT_UI4, &cur_time, &msft->typelib_header.CustomDataOffset);
1992 set_custdata(msft, &midl_version_guid, VT_UI4, &version, &msft->typelib_header.CustomDataOffset);
1994 for(entry = typelib->entry; NEXT_LINK(entry); entry = NEXT_LINK(entry))
1997 for( ; entry; entry = PREV_LINK(entry))
1998 add_entry(msft, entry);
2000 save_all_changes(msft);