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
);
658 /****************************************************************************
661 * Encodes a type, storing information in the TYPEDESC and ARRAYDESC
662 * segments as needed.
669 static int encode_type(
670 msft_typelib_t
*typelib
, /* [I] The type library in which to encode the TYPEDESC. */
671 int vt
, /* [I] vt to encode */
672 type_t
*type
, /* [I] type */
673 int *encoded_type
, /* [O] The encoded type description. */
674 int *width
, /* [O] The width of the type, or NULL. */
675 int *alignment
, /* [O] The alignment of the type, or NULL. */
676 int *decoded_size
) /* [O] The total size of the unencoded TYPEDESCs, including nested descs. */
685 chat("encode_type vt %d type %p\n", vt
, type
);
687 default_type
= 0x80000000 | (vt
<< 16) | vt
;
688 if (!width
) width
= &scratch
;
689 if (!alignment
) alignment
= &scratch
;
690 if (!decoded_size
) decoded_size
= &scratch
;
696 *encoded_type
= default_type
;
702 *encoded_type
= 0x80000000 | (VT_I4
<< 16) | VT_INT
;
703 if ((typelib
->typelib_header
.varflags
& 0x0f) == SYS_WIN16
) {
713 *encoded_type
= 0x80000000 | (VT_UI4
<< 16) | VT_UINT
;
714 if ((typelib
->typelib_header
.varflags
& 0x0f) == SYS_WIN16
) {
726 *encoded_type
= default_type
;
737 *encoded_type
= default_type
;
743 *encoded_type
= default_type
;
745 *alignment
= 4; /* guess? */
749 *encoded_type
= 0x80000000 | (VT_EMPTY
<< 16) | vt
;
756 *encoded_type
= default_type
;
762 *encoded_type
= default_type
;
768 while((next_vt
= get_type_vt(type
->ref
)) == 0) {
770 if(!type
) error("encode_type: type->ref is null\n");
773 encode_type(typelib
, next_vt
, type
->ref
, &target_type
, NULL
, NULL
, &child_size
);
774 if(type
->ref
->type
== RPC_FC_IP
) {
775 chat("encode_type: skipping ptr\n");
776 *encoded_type
= target_type
;
779 *decoded_size
= child_size
;
783 for (typeoffset
= 0; typeoffset
< typelib
->typelib_segdir
[MSFT_SEG_TYPEDESC
].length
; typeoffset
+= 8) {
784 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][typeoffset
];
785 if (((typedata
[0] & 0xffff) == VT_PTR
) && (typedata
[1] == target_type
)) break;
788 if (typeoffset
== typelib
->typelib_segdir
[MSFT_SEG_TYPEDESC
].length
) {
791 if (target_type
& 0x80000000) {
792 mix_field
= ((target_type
>> 16) & 0x3fff) | VT_BYREF
;
794 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][target_type
];
795 mix_field
= ((typedata
[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
798 typeoffset
= ctl2_alloc_segment(typelib
, MSFT_SEG_TYPEDESC
, 8, 0);
799 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][typeoffset
];
801 typedata
[0] = (mix_field
<< 16) | VT_PTR
;
802 typedata
[1] = target_type
;
805 *encoded_type
= typeoffset
;
809 *decoded_size
= 8 /*sizeof(TYPEDESC)*/ + child_size
;
816 /* FIXME: Make with the error checking. */
817 FIXME("SAFEARRAY vartype, may not work correctly.\n");
819 ctl2_encode_typedesc(typelib
, tdesc
->u
.lptdesc
, &target_type
, NULL
, NULL
, &child_size
);
821 for (typeoffset
= 0; typeoffset
< typelib
->typelib_segdir
[MSFT_SEG_TYPEDESC
].length
; typeoffset
+= 8) {
822 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][typeoffset
];
823 if (((typedata
[0] & 0xffff) == VT_SAFEARRAY
) && (typedata
[1] == target_type
)) break;
826 if (typeoffset
== typelib
->typelib_segdir
[MSFT_SEG_TYPEDESC
].length
) {
829 if (target_type
& 0x80000000) {
830 mix_field
= ((target_type
>> 16) & VT_TYPEMASK
) | VT_ARRAY
;
832 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][target_type
];
833 mix_field
= ((typedata
[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
836 typeoffset
= ctl2_alloc_segment(typelib
, MSFT_SEG_TYPEDESC
, 8, 0);
837 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][typeoffset
];
839 typedata
[0] = (mix_field
<< 16) | VT_SAFEARRAY
;
840 typedata
[1] = target_type
;
843 *encoded_tdesc
= typeoffset
;
847 *decoded_size
= sizeof(TYPEDESC
) + child_size
;
856 chat("encode_type: VT_USERDEFINED - type %p name = %s idx %d\n", type
, type
->name
, type
->typelib_idx
);
858 if(type
->typelib_idx
== -1)
859 error("encode_type: trying to ref not added type\n");
861 typeinfo_offset
= typelib
->typelib_typeinfo_offsets
[type
->typelib_idx
];
862 for (typeoffset
= 0; typeoffset
< typelib
->typelib_segdir
[MSFT_SEG_TYPEDESC
].length
; typeoffset
+= 8) {
863 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][typeoffset
];
864 if ((typedata
[0] == ((0x7fff << 16) | VT_USERDEFINED
)) && (typedata
[1] == typeinfo_offset
)) break;
867 if (typeoffset
== typelib
->typelib_segdir
[MSFT_SEG_TYPEDESC
].length
) {
868 typeoffset
= ctl2_alloc_segment(typelib
, MSFT_SEG_TYPEDESC
, 8, 0);
869 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][typeoffset
];
871 typedata
[0] = (0x7fff << 16) | VT_USERDEFINED
;
872 typedata
[1] = typeinfo_offset
;
875 *encoded_type
= typeoffset
;
879 if(type
->type
== RPC_FC_IP
) {
880 typeoffset
= ctl2_alloc_segment(typelib
, MSFT_SEG_TYPEDESC
, 8, 0);
881 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][typeoffset
];
883 typedata
[0] = (0x7fff << 16) | VT_PTR
;
884 typedata
[1] = *encoded_type
;
885 *encoded_type
= typeoffset
;
894 error("encode_type: unrecognized type %d.\n", vt
);
895 *encoded_type
= default_type
;
904 static void dump_type(type_t
*t
)
906 chat("dump_type: %p name %s type %d ref %p rname %s\n", t
, t
->name
, t
->type
, t
->ref
, t
->rname
);
907 if(t
->ref
) dump_type(t
->ref
);
910 static int encode_var(
911 msft_typelib_t
*typelib
, /* [I] The type library in which to encode the TYPEDESC. */
912 var_t
*var
, /* [I] The type description to encode. */
913 int *encoded_type
, /* [O] The encoded type description. */
914 int *width
, /* [O] The width of the type, or NULL. */
915 int *alignment
, /* [O] The alignment of the type, or NULL. */
916 int *decoded_size
) /* [O] The total size of the unencoded TYPEDESCs, including nested descs. */
926 if (!width
) width
= &scratch
;
927 if (!alignment
) alignment
= &scratch
;
928 if (!decoded_size
) decoded_size
= &scratch
;
931 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
);
935 skip_ptr
= encode_var(typelib
, var
, &target_type
, NULL
, NULL
, &child_size
);
939 chat("encode_var: skipping ptr\n");
940 *encoded_type
= target_type
;
941 *decoded_size
= child_size
;
947 for (typeoffset
= 0; typeoffset
< typelib
->typelib_segdir
[MSFT_SEG_TYPEDESC
].length
; typeoffset
+= 8) {
948 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][typeoffset
];
949 if (((typedata
[0] & 0xffff) == VT_PTR
) && (typedata
[1] == target_type
)) break;
952 if (typeoffset
== typelib
->typelib_segdir
[MSFT_SEG_TYPEDESC
].length
) {
955 if (target_type
& 0x80000000) {
956 mix_field
= ((target_type
>> 16) & 0x3fff) | VT_BYREF
;
958 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][target_type
];
959 mix_field
= ((typedata
[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
962 typeoffset
= ctl2_alloc_segment(typelib
, MSFT_SEG_TYPEDESC
, 8, 0);
963 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][typeoffset
];
965 typedata
[0] = (mix_field
<< 16) | VT_PTR
;
966 typedata
[1] = target_type
;
969 *encoded_type
= typeoffset
;
973 *decoded_size
= 8 /*sizeof(TYPEDESC)*/ + child_size
;
978 expr_t
*dim
= var
->array
;
980 int num_dims
= 1, elements
= 1, arrayoffset
;
983 while(NEXT_LINK(dim
)) {
984 dim
= NEXT_LINK(dim
);
987 chat("array with %d dimensions\n", num_dims
);
988 array_save
= var
->array
;
990 encode_var(typelib
, var
, &target_type
, width
, alignment
, NULL
);
991 var
->array
= array_save
;
992 arrayoffset
= ctl2_alloc_segment(typelib
, MSFT_SEG_ARRAYDESC
, (2 + 2 * num_dims
) * sizeof(long), 0);
993 arraydata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_ARRAYDESC
][arrayoffset
];
995 arraydata
[0] = target_type
;
996 arraydata
[1] = num_dims
;
997 arraydata
[1] |= ((num_dims
* 2 * sizeof(long)) << 16);
1001 arraydata
[0] = dim
->cval
;
1004 elements
*= dim
->cval
;
1005 dim
= PREV_LINK(dim
);
1008 typeoffset
= ctl2_alloc_segment(typelib
, MSFT_SEG_TYPEDESC
, 8, 0);
1009 typedata
= (void *)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEDESC
][typeoffset
];
1011 typedata
[0] = (0x7ffe << 16) | VT_CARRAY
;
1012 typedata
[1] = arrayoffset
;
1014 *encoded_type
= typeoffset
;
1015 *width
= *width
* elements
;
1016 *decoded_size
= 20 /*sizeof(ARRAYDESC)*/ + (num_dims
- 1) * 8 /*sizeof(SAFEARRAYBOUND)*/;
1019 dump_type(var
->type
);
1021 vt
= get_var_vt(var
);
1025 if(!type
) error("encode_var: type->ref is null\n");
1026 vt
= get_type_vt(type
);
1028 encode_type(typelib
, vt
, type
, encoded_type
, width
, alignment
, decoded_size
);
1029 if(type
->type
== RPC_FC_IP
) return 2;
1034 /****************************************************************************
1035 * ctl2_find_nth_reference
1037 * Finds a reference by index into the linked list of reference records.
1041 * Success: Offset of the desired reference record.
1044 static int ctl2_find_nth_reference(
1045 msft_typelib_t
*typelib
, /* [I] The type library in which to search. */
1046 int offset
, /* [I] The starting offset of the reference list. */
1047 int index
) /* [I] The index of the reference to find. */
1049 MSFT_RefRecord
*ref
;
1051 for (; index
&& (offset
!= -1); index
--) {
1052 ref
= (MSFT_RefRecord
*)&typelib
->typelib_segment_data
[MSFT_SEG_REFERENCES
][offset
];
1053 offset
= ref
->onext
;
1060 static void write_value(msft_typelib_t
* typelib
, int *out
, int vt
, void *value
)
1075 unsigned long *lv
= value
;
1076 if((*lv
& 0x3ffffff) == *lv
) {
1081 int offset
= ctl2_alloc_segment(typelib
, MSFT_SEG_CUSTDATA
, 8, 0);
1082 *((unsigned short *)&typelib
->typelib_segment_data
[MSFT_SEG_CUSTDATA
][offset
]) = vt
;
1083 memcpy(&typelib
->typelib_segment_data
[MSFT_SEG_CUSTDATA
][offset
+2], value
, 4);
1084 *((unsigned short *)&typelib
->typelib_segment_data
[MSFT_SEG_CUSTDATA
][offset
+6]) = 0x5757;
1091 char *s
= (char *) value
;
1092 int len
= strlen(s
), seg_len
= (len
+ 6 + 3) & ~0x3;
1093 int offset
= ctl2_alloc_segment(typelib
, MSFT_SEG_CUSTDATA
, seg_len
, 0);
1094 *((unsigned short *)&typelib
->typelib_segment_data
[MSFT_SEG_CUSTDATA
][offset
]) = vt
;
1095 *((unsigned int *)&typelib
->typelib_segment_data
[MSFT_SEG_CUSTDATA
][offset
+2]) = len
;
1096 memcpy(&typelib
->typelib_segment_data
[MSFT_SEG_CUSTDATA
][offset
+6], value
, len
);
1098 while(len
< seg_len
) {
1099 *((char *)&typelib
->typelib_segment_data
[MSFT_SEG_CUSTDATA
][offset
+len
]) = 0x57;
1107 warning("can't write value of type %d yet\n", vt
);
1112 static HRESULT
set_custdata(msft_typelib_t
*typelib
, REFGUID guid
,
1113 int vt
, void *value
, int *offset
)
1115 MSFT_GuidEntry guidentry
;
1121 guidentry
.guid
= *guid
;
1123 guidentry
.hreftype
= -1;
1124 guidentry
.next_hash
= -1;
1126 guidoffset
= ctl2_alloc_guid(typelib
, &guidentry
);
1127 if (guidoffset
== -1) return E_OUTOFMEMORY
;
1128 write_value(typelib
, &data_out
, vt
, value
);
1130 custoffset
= ctl2_alloc_segment(typelib
, MSFT_SEG_CUSTDATAGUID
, 12, 0);
1131 if (custoffset
== -1) return E_OUTOFMEMORY
;
1133 custdata
= (int *)&typelib
->typelib_segment_data
[MSFT_SEG_CUSTDATAGUID
][custoffset
];
1134 custdata
[0] = guidoffset
;
1135 custdata
[1] = data_out
;
1136 custdata
[2] = *offset
;
1137 *offset
= custoffset
;
1142 static HRESULT
add_func_desc(msft_typeinfo_t
* typeinfo
, func_t
*func
)
1146 int i
, index
= func
->idx
, id
;
1147 int decoded_size
, extra_attr
= 0;
1148 int num_params
= 0, num_defaults
= 0;
1149 var_t
*arg
, *last_arg
= NULL
;
1152 unsigned int funcflags
= 0, callconv
= 4 /* CC_STDCALL */;
1153 unsigned int funckind
= 1 /* FUNC_PUREVIRTUAL */, invokekind
= 1 /* INVOKE_FUNC */;
1154 int help_context
= 0, help_string_context
= 0, help_string_offset
= -1;
1156 id
= ((0x6000 | typeinfo
->typeinfo
->cImplTypes
) << 16) | index
;
1158 chat("(%p,%d)\n", typeinfo
, index
);
1160 if (!typeinfo
->typedata
) {
1161 typeinfo
->typedata
= xmalloc(0x2000);
1162 typeinfo
->typedata
[0] = 0;
1165 for(arg
= func
->args
; arg
; arg
= NEXT_LINK(arg
)) {
1168 for(attr
= arg
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1169 if(attr
->type
== ATTR_DEFAULTVALUE_EXPR
|| attr
->type
== ATTR_DEFAULTVALUE_STRING
) {
1176 chat("num of params %d\n", num_params
);
1178 for(attr
= func
->def
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1179 expr_t
*expr
= attr
->u
.pval
;
1180 switch(attr
->type
) {
1184 case ATTR_HELPCONTEXT
:
1186 help_context
= expr
->u
.lval
;
1188 case ATTR_HELPSTRING
:
1190 help_string_offset
= ctl2_alloc_string(typeinfo
->typelib
, attr
->u
.pval
);
1192 case ATTR_HELPSTRINGCONTEXT
:
1194 help_string_context
= expr
->u
.lval
;
1199 invokekind
= 0x2; /* INVOKE_PROPERTYGET */
1202 invokekind
= 0x4; /* INVOKE_PROPERTYPUT */
1205 warning("ignoring attr %d\n", attr
->type
);
1209 /* allocate type data space for us */
1210 offset
= typeinfo
->typedata
[0];
1211 typeinfo
->typedata
[0] += 0x18 + extra_attr
* sizeof(int) + (num_params
* (num_defaults
? 16 : 12));
1212 typedata
= typeinfo
->typedata
+ (offset
>> 2) + 1;
1214 /* fill out the basic type information */
1215 typedata
[0] = (0x18 + extra_attr
* sizeof(int) + (num_params
* (num_defaults
? 16 : 12))) | (index
<< 16);
1216 encode_var(typeinfo
->typelib
, func
->def
, &typedata
[1], NULL
, NULL
, &decoded_size
);
1217 typedata
[2] = funcflags
;
1218 typedata
[3] = ((52 /*sizeof(FUNCDESC)*/ + decoded_size
) << 16) | typeinfo
->typeinfo
->cbSizeVft
;
1219 typedata
[4] = (index
<< 16) | (callconv
<< 8) | (invokekind
<< 3) | funckind
;
1220 if(num_defaults
) typedata
[4] |= 0x1000;
1221 typedata
[5] = num_params
;
1223 /* NOTE: High word of typedata[3] is total size of FUNCDESC + size of all ELEMDESCs for params + TYPEDESCs for pointer params and return types. */
1224 /* That is, total memory allocation required to reconstitute the FUNCDESC in its entirety. */
1225 typedata
[3] += (16 /*sizeof(ELEMDESC)*/ * num_params
) << 16;
1226 typedata
[3] += (24 /*sizeof(PARAMDESCEX)*/ * num_defaults
) << 16;
1228 switch(extra_attr
) {
1229 case 6: typedata
[11] = help_string_context
;
1230 case 5: typedata
[10] = -1;
1231 case 4: typedata
[9] = -1;
1232 case 3: typedata
[8] = -1;
1233 case 2: typedata
[7] = help_string_offset
;
1234 case 1: typedata
[6] = help_context
;
1238 warning("unknown number of optional attrs\n");
1241 for (arg
= last_arg
, i
= 0; arg
; arg
= PREV_LINK(arg
), i
++) {
1244 int *paramdata
= typedata
+ 6 + extra_attr
+ (num_defaults
? num_params
: 0) + i
* 3;
1245 int *defaultdata
= num_defaults
? typedata
+ 6 + extra_attr
+ i
: NULL
;
1247 if(defaultdata
) *defaultdata
= -1;
1249 encode_var(typeinfo
->typelib
, arg
, paramdata
, NULL
, NULL
, &decoded_size
);
1250 for(attr
= arg
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1251 switch(attr
->type
) {
1252 case ATTR_DEFAULTVALUE_EXPR
:
1254 expr_t
*expr
= (expr_t
*)attr
->u
.pval
;
1255 paramflags
|= 0x30; /* PARAMFLAG_FHASDEFAULT | PARAMFLAG_FOPT */
1256 chat("default value %ld\n", expr
->cval
);
1257 write_value(typeinfo
->typelib
, defaultdata
, (*paramdata
>> 16) & 0x1ff, &expr
->cval
);
1260 case ATTR_DEFAULTVALUE_STRING
:
1262 char *s
= (char *)attr
->u
.pval
;
1263 paramflags
|= 0x30; /* PARAMFLAG_FHASDEFAULT | PARAMFLAG_FOPT */
1264 chat("default value '%s'\n", s
);
1265 write_value(typeinfo
->typelib
, defaultdata
, (*paramdata
>> 16) & 0x1ff, s
);
1269 paramflags
|= 0x01; /* PARAMFLAG_FIN */
1272 paramflags
|= 0x10; /* PARAMFLAG_FOPT */
1275 paramflags
|= 0x02; /* PARAMFLAG_FOUT */
1278 paramflags
|= 0x08; /* PARAMFLAG_FRETVAL */
1281 chat("unhandled param attr %d\n", attr
->type
);
1286 paramdata
[2] = paramflags
;
1287 typedata
[3] += decoded_size
<< 16;
1290 /* update the index data */
1291 typeinfo
->indices
[index
] = id
;
1292 typeinfo
->names
[index
] = -1;
1293 typeinfo
->offsets
[index
] = offset
;
1296 if (!typeinfo
->typeinfo
->res2
) typeinfo
->typeinfo
->res2
= 0x20;
1297 typeinfo
->typeinfo
->res2
<<= 1;
1299 if (index
< 2) typeinfo
->typeinfo
->res2
+= num_params
<< 4;
1301 if (typeinfo
->typeinfo
->res3
== -1) typeinfo
->typeinfo
->res3
= 0;
1302 typeinfo
->typeinfo
->res3
+= 0x38 + num_params
* 0x10;
1303 if(num_defaults
) typeinfo
->typeinfo
->res3
+= num_params
* 0x4;
1305 /* adjust size of VTBL */
1306 typeinfo
->typeinfo
->cbSizeVft
+= 4;
1308 /* Increment the number of function elements */
1309 typeinfo
->typeinfo
->cElement
+= 1;
1312 offset
= ctl2_alloc_name(typeinfo
->typelib
, func
->def
->name
);
1313 chat("name offset = %d index %d\n", offset
, index
);
1314 typeinfo
->names
[index
] = offset
;
1316 namedata
= typeinfo
->typelib
->typelib_segment_data
[MSFT_SEG_NAME
] + offset
;
1317 namedata
[9] &= ~0x10;
1318 if (*((INT
*)namedata
) == -1) {
1319 *((INT
*)namedata
) = typeinfo
->typelib
->typelib_typeinfo_offsets
[typeinfo
->typeinfo
->typekind
>> 16];
1322 for (arg
= last_arg
, i
= 0; arg
; arg
= PREV_LINK(arg
), i
++) {
1323 /* FIXME: Almost certainly easy to break */
1324 int *paramdata
= &typeinfo
->typedata
[typeinfo
->offsets
[index
] >> 2];
1325 paramdata
+= 7 + extra_attr
+ (num_defaults
? num_params
: 0) + i
* 3;
1326 offset
= ctl2_alloc_name(typeinfo
->typelib
, arg
->name
);
1327 paramdata
[1] = offset
;
1328 chat("param %d name %s offset %d\n", i
, arg
->name
, offset
);
1334 static void set_alignment(
1335 msft_typeinfo_t
* typeinfo
,
1339 if (!cbAlignment
) return;
1340 if (cbAlignment
> 16) return;
1342 typeinfo
->typeinfo
->typekind
&= ~0xffc0;
1343 typeinfo
->typeinfo
->typekind
|= cbAlignment
<< 6;
1345 /* FIXME: There's probably some way to simplify this. */
1346 switch (typeinfo
->typeinfo
->typekind
& 15) {
1352 case TKIND_INTERFACE
:
1353 case TKIND_DISPATCH
:
1355 if (cbAlignment
> 4) cbAlignment
= 4;
1365 typeinfo
->typeinfo
->typekind
|= cbAlignment
<< 11;
1370 static HRESULT
add_var_desc(msft_typeinfo_t
*typeinfo
, UINT index
, var_t
* var
)
1382 chat("add_var_desc(%d,%s) array %p\n", index
, var
->name
, var
->array
);
1384 if ((typeinfo
->typeinfo
->cElement
>> 16) != index
) {
1385 error("Out-of-order element.\n");
1386 return TYPE_E_ELEMENTNOTFOUND
;
1390 for(attr
= var
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1391 switch(attr
->type
) {
1393 warning("AddVarDesc: unhandled attr type %d\n", attr
->type
);
1398 if (!typeinfo
->typedata
) {
1399 typeinfo
->typedata
= xmalloc(0x2000);
1400 typeinfo
->typedata
[0] = 0;
1403 /* allocate type data space for us */
1404 offset
= typeinfo
->typedata
[0];
1405 typeinfo
->typedata
[0] += 0x14;
1406 typedata
= typeinfo
->typedata
+ (offset
>> 2) + 1;
1408 /* fill out the basic type information */
1409 typedata
[0] = 0x14 | (index
<< 16);
1410 typedata
[2] = varflags
;
1411 typedata
[3] = (36 /*sizeof(VARDESC)*/ << 16) | 0;
1413 /* update the index data */
1414 typeinfo
->indices
[index
] = 0x40000000 + index
;
1415 typeinfo
->names
[index
] = -1;
1416 typeinfo
->offsets
[index
] = offset
;
1418 /* figure out type widths and whatnot */
1419 encode_var(typeinfo
->typelib
, var
, &typedata
[1], &var_datawidth
,
1420 &var_alignment
, &var_type_size
);
1422 /* pad out starting position to data width */
1423 typeinfo
->datawidth
+= var_alignment
- 1;
1424 typeinfo
->datawidth
&= ~(var_alignment
- 1);
1425 typedata
[4] = typeinfo
->datawidth
;
1427 /* add the new variable to the total data width */
1428 typeinfo
->datawidth
+= var_datawidth
;
1430 /* add type description size to total required allocation */
1431 typedata
[3] += var_type_size
<< 16;
1433 /* fix type alignment */
1434 alignment
= (typeinfo
->typeinfo
->typekind
>> 11) & 0x1f;
1435 if (alignment
< var_alignment
) {
1436 alignment
= var_alignment
;
1437 typeinfo
->typeinfo
->typekind
&= ~0xf800;
1438 typeinfo
->typeinfo
->typekind
|= alignment
<< 11;
1442 if (!typeinfo
->typeinfo
->res2
) typeinfo
->typeinfo
->res2
= 0x1a;
1443 if ((index
== 0) || (index
== 1) || (index
== 2) || (index
== 4) || (index
== 9)) {
1444 typeinfo
->typeinfo
->res2
<<= 1;
1448 if (typeinfo
->typeinfo
->res3
== -1) typeinfo
->typeinfo
->res3
= 0;
1449 typeinfo
->typeinfo
->res3
+= 0x2c;
1451 /* increment the number of variable elements */
1452 typeinfo
->typeinfo
->cElement
+= 0x10000;
1454 /* pad data width to alignment */
1455 typeinfo
->typeinfo
->size
= (typeinfo
->datawidth
+ (alignment
- 1)) & ~(alignment
- 1);
1457 offset
= ctl2_alloc_name(typeinfo
->typelib
, var
->name
);
1458 if (offset
== -1) return E_OUTOFMEMORY
;
1460 namedata
= typeinfo
->typelib
->typelib_segment_data
[MSFT_SEG_NAME
] + offset
;
1461 if (*((INT
*)namedata
) == -1) {
1462 *((INT
*)namedata
) = typeinfo
->typelib
->typelib_typeinfo_offsets
[typeinfo
->typeinfo
->typekind
>> 16];
1463 namedata
[9] |= 0x10;
1465 if ((typeinfo
->typeinfo
->typekind
& 15) == TKIND_ENUM
) {
1466 namedata
[9] |= 0x20;
1468 typeinfo
->names
[index
] = offset
;
1474 static msft_typeinfo_t
*create_msft_typeinfo(msft_typelib_t
*typelib
, typelib_entry_t
*entry
, int idx
)
1476 msft_typeinfo_t
*msft_typeinfo
;
1478 int typeinfo_offset
;
1479 MSFT_TypeInfoBase
*typeinfo
;
1481 MSFT_GuidEntry guidentry
;
1484 switch(entry
->kind
) {
1485 case TKIND_INTERFACE
:
1486 name
= entry
->u
.interface
->name
;
1487 attr
= entry
->u
.interface
->attrs
;
1488 entry
->u
.interface
->typelib_idx
= idx
;
1491 name
= entry
->u
.module
->name
;
1492 attr
= entry
->u
.module
->attrs
;
1495 name
= entry
->u
.class->name
;
1496 attr
= entry
->u
.class->attrs
;
1499 name
= entry
->u
.structure
->name
;
1500 attr
= entry
->u
.structure
->attrs
;
1501 entry
->u
.structure
->typelib_idx
= idx
;
1502 chat("type = %p\n", entry
->u
.structure
);
1505 error("create_msft_typeinfo: unhandled type %d\n", entry
->kind
);
1510 chat("Constructing msft_typeinfo for name %s kind %d\n", name
, entry
->kind
);
1512 msft_typeinfo
= xmalloc(sizeof(*msft_typeinfo
));
1514 msft_typeinfo
->typelib
= typelib
;
1516 nameoffset
= ctl2_alloc_name(typelib
, name
);
1517 typeinfo_offset
= ctl2_alloc_typeinfo(typelib
, nameoffset
);
1518 typeinfo
= (MSFT_TypeInfoBase
*)&typelib
->typelib_segment_data
[MSFT_SEG_TYPEINFO
][typeinfo_offset
];
1520 typelib
->typelib_segment_data
[MSFT_SEG_NAME
][nameoffset
+ 9] = 0x38;
1521 *((int *)&typelib
->typelib_segment_data
[MSFT_SEG_NAME
][nameoffset
]) = typeinfo_offset
;
1523 msft_typeinfo
->typeinfo
= typeinfo
;
1525 typeinfo
->typekind
|= entry
->kind
| 0x20;
1526 set_alignment(msft_typeinfo
, 4);
1528 switch (entry
->kind
) {
1530 case TKIND_INTERFACE
:
1531 case TKIND_DISPATCH
:
1546 typeinfo
->size
= -0x75;
1550 error("%s unrecognized typekind %d\n", name
, entry
->kind
);
1551 typeinfo
->size
= 0xdeadbeef;
1556 for( ; attr
; attr
= NEXT_LINK(attr
)) {
1557 switch(attr
->type
) {
1558 case ATTR_HELPCONTEXT
:
1560 expr_t
*expr
= (expr_t
*)attr
->u
.pval
;
1561 typeinfo
->helpcontext
= expr
->cval
;
1564 case ATTR_HELPSTRING
:
1566 int offset
= ctl2_alloc_string(typelib
, attr
->u
.pval
);
1567 if (offset
== -1) break;
1568 typeinfo
->docstringoffs
= offset
;
1571 case ATTR_HELPSTRINGCONTEXT
:
1573 expr_t
*expr
= (expr_t
*)attr
->u
.pval
;
1574 typeinfo
->helpstringcontext
= expr
->cval
;
1578 typeinfo
->flags
|= 0x10; /* TYPEFLAG_FHIDDEN */
1581 case ATTR_RESTRICTED
:
1582 typeinfo
->flags
|= 0x200; /* TYPEFLAG_FRESTRICTED */
1586 guidentry
.guid
= *(GUID
*)attr
->u
.pval
;
1587 guidentry
.hreftype
= typelib
->typelib_typeinfo_offsets
[typeinfo
->typekind
>> 16];
1588 guidentry
.next_hash
= -1;
1589 typeinfo
->posguid
= ctl2_alloc_guid(typelib
, &guidentry
);
1591 if (IsEqualIID(guid
, &IID_IDispatch
)) {
1592 typelib
->typelib_header
.dispatchpos
= typelib
->typelib_typeinfo_offsets
[typeinfo
->typekind
>> 16];
1598 typeinfo
->version
= attr
->u
.ival
;
1602 warning("create_msft_typeinfo: ignoring attr %d\n", attr
->type
);
1607 if (typelib
->last_typeinfo
) typelib
->last_typeinfo
->next_typeinfo
= msft_typeinfo
;
1608 typelib
->last_typeinfo
= msft_typeinfo
;
1609 if (!typelib
->typeinfos
) typelib
->typeinfos
= msft_typeinfo
;
1612 return msft_typeinfo
;
1616 static void set_name(msft_typelib_t
*typelib
)
1620 offset
= ctl2_alloc_name(typelib
, typelib
->typelib
->name
);
1621 if (offset
== -1) return;
1622 typelib
->typelib_header
.NameOffset
= offset
;
1626 static void set_version(msft_typelib_t
*typelib
)
1628 long version
= MAKELONG(0,0);
1631 for(attr
= typelib
->typelib
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1632 if(attr
->type
== ATTR_VERSION
) {
1633 version
= attr
->u
.ival
;
1636 typelib
->typelib_header
.version
= version
;
1640 static void set_guid(msft_typelib_t
*typelib
)
1642 MSFT_GuidEntry guidentry
;
1645 GUID guid
= {0,0,0,{0,0,0,0,0,0}};
1647 guidentry
.guid
= guid
;
1648 guidentry
.hreftype
= -2;
1649 guidentry
.next_hash
= -1;
1651 for(attr
= typelib
->typelib
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1652 if(attr
->type
== ATTR_UUID
) {
1653 guidentry
.guid
= *(GUID
*)(attr
->u
.pval
);
1657 offset
= ctl2_alloc_guid(typelib
, &guidentry
);
1659 if (offset
== -1) return;
1661 typelib
->typelib_header
.posguid
= offset
;
1666 static void set_doc_string(msft_typelib_t
*typelib
)
1671 for(attr
= typelib
->typelib
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1672 if(attr
->type
== ATTR_HELPSTRING
) {
1673 offset
= ctl2_alloc_string(typelib
, attr
->u
.pval
);
1674 if (offset
== -1) return;
1675 typelib
->typelib_header
.helpstring
= offset
;
1681 static void set_help_file_name(msft_typelib_t
*typelib
)
1685 for(attr
= typelib
->typelib
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1686 if(attr
->type
== ATTR_HELPFILE
) {
1687 offset
= ctl2_alloc_string(typelib
, attr
->u
.pval
);
1688 if (offset
== -1) return;
1689 typelib
->typelib_header
.helpfile
= offset
;
1690 typelib
->typelib_header
.varflags
|= 0x10;
1696 static void set_help_context(msft_typelib_t
*typelib
)
1699 for(attr
= typelib
->typelib
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1700 if(attr
->type
== ATTR_HELPCONTEXT
) {
1701 expr_t
*expr
= (expr_t
*)attr
->u
.pval
;
1702 typelib
->typelib_header
.helpcontext
= expr
->cval
;
1708 static void set_help_string_dll(msft_typelib_t
*typelib
)
1712 for(attr
= typelib
->typelib
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1713 if(attr
->type
== ATTR_HELPSTRINGDLL
) {
1714 offset
= ctl2_alloc_string(typelib
, attr
->u
.pval
);
1715 if (offset
== -1) return;
1716 typelib
->help_string_dll_offset
= offset
;
1717 typelib
->typelib_header
.varflags
|= 0x100;
1723 static void set_help_string_context(msft_typelib_t
*typelib
)
1726 for(attr
= typelib
->typelib
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1727 if(attr
->type
== ATTR_HELPSTRINGCONTEXT
) {
1728 expr_t
*expr
= (expr_t
*)attr
->u
.pval
;
1729 typelib
->typelib_header
.helpstringcontext
= expr
->cval
;
1735 static void set_lcid(msft_typelib_t
*typelib
)
1737 typelib
->typelib_header
.lcid2
= 0x0;
1741 static void set_lib_flags(msft_typelib_t
*typelib
)
1745 typelib
->typelib_header
.flags
= 0;
1746 for(attr
= typelib
->typelib
->attrs
; attr
; attr
= NEXT_LINK(attr
)) {
1747 switch(attr
->type
) {
1749 typelib
->typelib_header
.flags
|= 0x02; /* LIBFLAG_FCONTROL */
1752 typelib
->typelib_header
.flags
|= 0x04; /* LIBFLAG_FHIDDEN */
1754 case ATTR_RESTRICTED
:
1755 typelib
->typelib_header
.flags
|= 0x01; /* LIBFLAG_FRESTRICTED */
1764 static int ctl2_write_chunk(int fd
, void *segment
, int length
)
1766 if (write(fd
, segment
, length
) != length
) {
1773 static int ctl2_write_segment(msft_typelib_t
*typelib
, int fd
, int segment
)
1775 if (write(fd
, typelib
->typelib_segment_data
[segment
], typelib
->typelib_segdir
[segment
].length
)
1776 != typelib
->typelib_segdir
[segment
].length
) {
1784 static void ctl2_finalize_typeinfos(msft_typelib_t
*typelib
, int filesize
)
1786 msft_typeinfo_t
*typeinfo
;
1788 for (typeinfo
= typelib
->typeinfos
; typeinfo
; typeinfo
= typeinfo
->next_typeinfo
) {
1789 typeinfo
->typeinfo
->memoffset
= filesize
;
1790 if (typeinfo
->typedata
) {
1791 /*LayOut(typeinfo);*/
1792 filesize
+= typeinfo
->typedata
[0] + ((typeinfo
->typeinfo
->cElement
>> 16) * 12) + ((typeinfo
->typeinfo
->cElement
& 0xffff) * 12) + 4;
1797 static int ctl2_finalize_segment(msft_typelib_t
*typelib
, int filepos
, int segment
)
1799 if (typelib
->typelib_segdir
[segment
].length
) {
1800 typelib
->typelib_segdir
[segment
].offset
= filepos
;
1802 typelib
->typelib_segdir
[segment
].offset
= -1;
1805 return typelib
->typelib_segdir
[segment
].length
;
1809 static void ctl2_write_typeinfos(msft_typelib_t
*typelib
, int fd
)
1811 msft_typeinfo_t
*typeinfo
;
1813 for (typeinfo
= typelib
->typeinfos
; typeinfo
; typeinfo
= typeinfo
->next_typeinfo
) {
1814 if (!typeinfo
->typedata
) continue;
1816 ctl2_write_chunk(fd
, typeinfo
->typedata
, typeinfo
->typedata
[0] + 4);
1817 ctl2_write_chunk(fd
, typeinfo
->indices
, ((typeinfo
->typeinfo
->cElement
& 0xffff) + (typeinfo
->typeinfo
->cElement
>> 16)) * 4);
1818 chat("writing name chunk len %d %08lx\n", ((typeinfo
->typeinfo
->cElement
& 0xffff) + (typeinfo
->typeinfo
->cElement
>> 16)) * 4, *(DWORD
*)typeinfo
->names
);
1819 ctl2_write_chunk(fd
, typeinfo
->names
, ((typeinfo
->typeinfo
->cElement
& 0xffff) + (typeinfo
->typeinfo
->cElement
>> 16)) * 4);
1820 ctl2_write_chunk(fd
, typeinfo
->offsets
, ((typeinfo
->typeinfo
->cElement
& 0xffff) + (typeinfo
->typeinfo
->cElement
>> 16)) * 4);
1824 static int save_all_changes(msft_typelib_t
*typelib
)
1830 chat("save_all_changes(%p)\n", typelib
);
1832 retval
= TYPE_E_IOERROR
;
1834 fd
= creat(typelib
->typelib
->filename
, 0666);
1835 if (fd
== -1) return retval
;
1837 filepos
= sizeof(MSFT_Header
) + sizeof(MSFT_SegDir
);
1838 if(typelib
->typelib_header
.varflags
& 0x100) filepos
+= 4; /* helpstringdll */
1839 filepos
+= typelib
->typelib_header
.nrtypeinfos
* 4;
1841 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_TYPEINFO
);
1842 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_GUIDHASH
);
1843 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_GUID
);
1844 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_IMPORTINFO
);
1845 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_IMPORTFILES
);
1846 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_REFERENCES
);
1847 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_NAMEHASH
);
1848 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_NAME
);
1849 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_STRING
);
1850 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_TYPEDESC
);
1851 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_ARRAYDESC
);
1852 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_CUSTDATA
);
1853 filepos
+= ctl2_finalize_segment(typelib
, filepos
, MSFT_SEG_CUSTDATAGUID
);
1855 ctl2_finalize_typeinfos(typelib
, filepos
);
1857 if (!ctl2_write_chunk(fd
, &typelib
->typelib_header
, sizeof(typelib
->typelib_header
))) return retval
;
1858 if(typelib
->typelib_header
.varflags
& 0x100)
1859 if (!ctl2_write_chunk(fd
, &typelib
->help_string_dll_offset
, sizeof(typelib
->help_string_dll_offset
)))
1862 if (!ctl2_write_chunk(fd
, typelib
->typelib_typeinfo_offsets
, typelib
->typelib_header
.nrtypeinfos
* 4)) return retval
;
1863 if (!ctl2_write_chunk(fd
, &typelib
->typelib_segdir
, sizeof(typelib
->typelib_segdir
))) return retval
;
1864 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_TYPEINFO
)) return retval
;
1865 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_GUIDHASH
)) return retval
;
1866 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_GUID
)) return retval
;
1867 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_IMPORTINFO
)) return retval
;
1868 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_IMPORTFILES
)) return retval
;
1869 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_REFERENCES
)) return retval
;
1870 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_NAMEHASH
)) return retval
;
1871 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_NAME
)) return retval
;
1872 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_STRING
)) return retval
;
1873 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_TYPEDESC
)) return retval
;
1874 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_ARRAYDESC
)) return retval
;
1875 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_CUSTDATA
)) return retval
;
1876 if (!ctl2_write_segment(typelib
, fd
, MSFT_SEG_CUSTDATAGUID
)) return retval
;
1878 ctl2_write_typeinfos(typelib
, fd
);
1880 if (close(fd
) == -1) return retval
;
1889 int create_msft_typelib(typelib_t
*typelib
)
1891 msft_typelib_t
*msft
;
1892 int failed
= 0, typelib_idx
;
1893 typelib_entry_t
*entry
;
1895 unsigned int version
= 5 << 24 | 1 << 16 | 164; /* 5.01.0164 */
1896 GUID midl_time_guid
= {0xde77ba63,0x517c,0x11d1,{0xa2,0xda,0x00,0x00,0xf8,0x77,0x3c,0xe9}};
1897 GUID midl_version_guid
= {0xde77ba64,0x517c,0x11d1,{0xa2,0xda,0x00,0x00,0xf8,0x77,0x3c,0xe9}};
1899 msft
= malloc(sizeof(*msft
));
1900 if (!msft
) return 0;
1901 memset(msft
, 0, sizeof(*msft
));
1902 msft
->typelib
= typelib
;
1904 ctl2_init_header(msft
);
1905 ctl2_init_segdir(msft
);
1907 msft
->typelib_header
.varflags
|= SYS_WIN32
;
1910 * The following two calls return an offset or -1 if out of memory. We
1911 * specifically need an offset of 0, however, so...
1913 if (ctl2_alloc_segment(msft
, MSFT_SEG_GUIDHASH
, 0x80, 0x80)) { failed
= 1; }
1914 if (ctl2_alloc_segment(msft
, MSFT_SEG_NAMEHASH
, 0x200, 0x200)) { failed
= 1; }
1916 if(failed
) return 0;
1918 msft
->typelib_guidhash_segment
= (int *)msft
->typelib_segment_data
[MSFT_SEG_GUIDHASH
];
1919 msft
->typelib_namehash_segment
= (int *)msft
->typelib_segment_data
[MSFT_SEG_NAMEHASH
];
1921 memset(msft
->typelib_guidhash_segment
, 0xff, 0x80);
1922 memset(msft
->typelib_namehash_segment
, 0xff, 0x200);
1924 set_lib_flags(msft
);
1926 set_help_file_name(msft
);
1927 set_doc_string(msft
);
1931 set_help_context(msft
);
1932 set_help_string_dll(msft
);
1933 set_help_string_context(msft
);
1935 /* midl adds two sets of custom data to the library: the current unix time
1936 and midl's version number */
1937 cur_time
= time(NULL
);
1938 set_custdata(msft
, &midl_time_guid
, VT_UI4
, &cur_time
, &msft
->typelib_header
.CustomDataOffset
);
1939 set_custdata(msft
, &midl_version_guid
, VT_UI4
, &version
, &msft
->typelib_header
.CustomDataOffset
);
1942 for(entry
= typelib
->entry
; NEXT_LINK(entry
); entry
= NEXT_LINK(entry
))
1944 for( ; entry
; entry
= PREV_LINK(entry
)) {
1945 msft_typeinfo_t
*msft_typeinfo
= create_msft_typeinfo(msft
, entry
, typelib_idx
);
1946 switch(entry
->kind
) {
1947 case TKIND_INTERFACE
:
1950 func_t
*cur
= entry
->u
.interface
->funcs
;
1951 while(NEXT_LINK(cur
)) cur
= NEXT_LINK(cur
);
1953 if(cur
->idx
== -1) cur
->idx
= idx
;
1954 else if(cur
->idx
!= idx
) error("method index mismatch\n");
1955 add_func_desc(msft_typeinfo
, cur
);
1957 cur
= PREV_LINK(cur
);
1964 var_t
*cur
= entry
->u
.structure
->fields
;
1965 while(NEXT_LINK(cur
)) cur
= NEXT_LINK(cur
);
1967 add_var_desc(msft_typeinfo
, idx
, cur
);
1969 cur
= PREV_LINK(cur
);
1975 error("create_msft_typelib: unhandled type %d\n", entry
->kind
);
1980 save_all_changes(msft
);