2 * Typelib (SLTG) generation
4 * Copyright 2015,2016 Dmitry Timoshkov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include "typelib_struct.h"
40 static const GUID sltg_library_guid
= { 0x204ff,0,0,{ 0xc0,0,0,0,0,0,0,0x46 } };
71 struct sltg_data index
;
72 struct sltg_data name_table
;
73 struct sltg_library library
;
74 struct sltg_block
*blocks
;
79 struct sltg_block
*typeinfo
;
89 struct sltg_typeinfo_header
100 unsigned unknown1
: 3;
102 unsigned unknown2
: 8;
103 unsigned typekind
: 8;
108 struct sltg_member_header
118 char magic
; /* 0x0a */
122 short byte_offs
; /* pos in struct, or offset to const type or const data (if flags & 0x08) */
123 short type
; /* if flags & 0x02 this is the type, else offset to type */
127 short varflags
; /* only present if magic & 0x20 */
135 short res06
; /* always 0000 */
136 short funcs_off
; /* offset to functions (starting from the member header) */
137 short vars_off
; /* offset to vars (starting from the member header) */
138 short impls_off
; /* offset to implemented types (starting from the member header) */
139 short funcs_bytes
; /* bytes used by function data */
140 short vars_bytes
; /* bytes used by var data */
141 short impls_bytes
; /* bytes used by implemented type data */
142 short tdescalias_vt
; /* for TKIND_ALIAS */
143 short res16
; /* always ffff */
144 short res18
; /* always 0000 */
145 short res1a
; /* always 0000 */
146 short simple_alias
; /* tdescalias_vt is a vt rather than an offset? */
147 short res1e
; /* always 0000 */
148 short cbSizeInstance
;
153 short res2a
; /* always ffff */
154 short res2c
; /* always ffff */
155 short res2e
; /* always ffff */
156 short res30
; /* always ffff */
157 short res32
; /* unknown */
158 short type_bytes
; /* bytes used by type descriptions */
163 char magic
; /* 0xdf */
164 char res01
; /* 0x00 */
165 char res02
[0x42]; /* 0xff... */
166 int number
; /* this is 8 times the number of refs */
167 /* Now we have number bytes (8 for each ref) of SLTG_UnknownRefInfo */
169 short res50
;/* 0xffff */
170 char res52
; /* 0x01 */
171 int res53
; /* 0x00000000 */
172 /* Now we have number/8 SLTG_Names (first WORD is no of bytes in the ascii
173 * string). Strings look like "*\Rxxxx*#n". If xxxx == ffff then the
174 * ref refers to the nth type listed in this library (0 based). Else
175 * the xxxx (which maybe fewer than 4 digits) is the offset into the name
176 * table to a string "*\G{<guid>}#1.0#0#C:\WINNT\System32\stdole32.tlb#"
177 * The guid is the typelib guid; the ref again refers to the nth type of
178 * the imported typelib.
181 char resxx
; /* 0xdf */
186 char magic
; /* 0x4c, 0xcb or 0x8b with optional SLTG_FUNCTION_FLAGS_PRESENT flag */
187 char flags
; /* high nibble is INVOKE_KIND, low nibble = 2 */
188 short next
; /* byte offset from beginning of group to next fn */
189 short name
; /* Offset within name table to name */
190 int dispid
; /* dispid */
191 short helpcontext
; /* helpcontext (again 1 is special) */
192 short helpstring
; /* helpstring offset to offset */
193 short arg_off
; /* offset to args from start of block */
194 char nacc
; /* lowest 3bits are CALLCONV, rest are no of args */
195 char retnextopt
; /* if 0x80 bit set ret type follows else next WORD
196 is offset to ret type. No of optional args is
198 short rettype
; /* return type VT_?? or offset to ret type */
199 short vtblpos
; /* position in vtbl? */
200 short funcflags
; /* present if magic & 0x20 */
201 /* Param list starts, repeat next two as required */
203 WORD name
; /* offset to 2nd letter of name */
204 WORD
+ type
; /* VT_ of param */
210 static void add_structure_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
);
211 static void add_interface_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
);
212 static void add_enum_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
);
213 static void add_union_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
);
214 static void add_coclass_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
);
216 static void init_sltg_data(struct sltg_data
*data
)
223 static int add_index(struct sltg_data
*index
, const char *name
)
225 int name_offset
= index
->size
;
226 int new_size
= index
->size
+ strlen(name
) + 1;
228 chat("add_index: name_offset %d, \"%s\"\n", name_offset
, name
);
230 if (new_size
> index
->allocated
)
232 index
->allocated
= index
->allocated
? max(index
->allocated
* 2, new_size
) : new_size
;
233 index
->data
= xrealloc(index
->data
, index
->allocated
);
236 strcpy(index
->data
+ index
->size
, name
);
237 index
->size
= new_size
;
242 static void init_index(struct sltg_data
*index
)
244 static const char compobj
[] = { 1,'C','o','m','p','O','b','j',0 };
246 init_sltg_data(index
);
248 add_index(index
, compobj
);
251 static int add_name(struct sltg_data
*name_table
, const char *name
)
253 int name_offset
= name_table
->size
;
254 int new_size
= name_table
->size
+ strlen(name
) + 1 + 8;
257 chat("add_name: %s\n", name
);
259 aligned_size
= (new_size
+ 0x1f) & ~0x1f;
260 if (aligned_size
- new_size
< 4)
261 new_size
= aligned_size
;
263 new_size
= (new_size
+ 1) & ~1;
265 if (new_size
> name_table
->allocated
)
267 name_table
->allocated
= name_table
->allocated
? max(name_table
->allocated
* 2, new_size
) : new_size
;
268 name_table
->data
= xrealloc(name_table
->data
, name_table
->allocated
);
271 memset(name_table
->data
+ name_table
->size
, 0xff, 8);
272 strcpy(name_table
->data
+ name_table
->size
+ 8, name
);
273 name_table
->size
= new_size
;
274 name_table
->data
[name_table
->size
- 1] = 0; /* clear alignment */
279 static void init_name_table(struct sltg_data
*name_table
)
281 init_sltg_data(name_table
);
284 static void init_library(struct sltg_typelib
*sltg
)
288 sltg
->library
.name
= add_name(&sltg
->name_table
, sltg
->typelib
->name
);
289 sltg
->library
.helpstring
= NULL
;
290 sltg
->library
.helpcontext
= 0;
291 sltg
->library
.syskind
= SYS_WIN32
;
292 sltg
->library
.lcid
= 0x0409;
293 sltg
->library
.libflags
= 0;
294 sltg
->library
.version
= 0;
295 sltg
->library
.helpfile
= NULL
;
296 memset(&sltg
->library
.uuid
, 0, sizeof(sltg
->library
.uuid
));
298 if (!sltg
->typelib
->attrs
) return;
300 LIST_FOR_EACH_ENTRY(attr
, sltg
->typelib
->attrs
, const attr_t
, entry
)
307 sltg
->library
.version
= attr
->u
.ival
;
309 case ATTR_HELPSTRING
:
310 sltg
->library
.helpstring
= attr
->u
.pval
;
313 sltg
->library
.helpfile
= attr
->u
.pval
;
316 sltg
->library
.uuid
= *(GUID
*)attr
->u
.pval
;
318 case ATTR_HELPCONTEXT
:
320 sltg
->library
.helpcontext
= expr
->cval
;
324 sltg
->library
.lcid
= expr
->cval
;
327 sltg
->library
.libflags
|= 0x02; /* LIBFLAG_FCONTROL */
330 sltg
->library
.libflags
|= 0x04; /* LIBFLAG_FHIDDEN */
332 case ATTR_RESTRICTED
:
333 sltg
->library
.libflags
|= 0x01; /* LIBFLAG_FRESTRICTED */
341 static void add_block(struct sltg_typelib
*sltg
, void *data
, int length
, const char *name
)
343 chat("add_block: %p,%d,\"%s\"\n", data
, length
, name
);
345 sltg
->blocks
= xrealloc(sltg
->blocks
, sizeof(sltg
->blocks
[0]) * (sltg
->block_count
+ 1));
346 sltg
->blocks
[sltg
->block_count
].length
= length
;
347 sltg
->blocks
[sltg
->block_count
].data
= data
;
348 sltg
->blocks
[sltg
->block_count
].index_string
= add_index(&sltg
->index
, name
);
352 static void add_library_block(struct sltg_typelib
*typelib
)
358 size
= sizeof(short) * 9 + sizeof(int) * 3 + sizeof(GUID
);
359 if (typelib
->library
.helpstring
) size
+= strlen(typelib
->library
.helpstring
);
360 if (typelib
->library
.helpfile
) size
+= strlen(typelib
->library
.helpfile
);
362 block
= xmalloc(size
);
364 *p
++ = 0x51cc; /* magic */
365 *p
++ = 3; /* res02 */
366 *p
++ = typelib
->library
.name
;
367 *p
++ = 0xffff; /* res06 */
368 if (typelib
->library
.helpstring
)
370 *p
++ = strlen(typelib
->library
.helpstring
);
371 strcpy((char *)p
, typelib
->library
.helpstring
);
372 p
= (short *)((char *)p
+ strlen(typelib
->library
.helpstring
));
376 if (typelib
->library
.helpfile
)
378 *p
++ = strlen(typelib
->library
.helpfile
);
379 strcpy((char *)p
, typelib
->library
.helpfile
);
380 p
= (short *)((char *)p
+ strlen(typelib
->library
.helpfile
));
384 *(int *)p
= typelib
->library
.helpcontext
;
386 *p
++ = typelib
->library
.syskind
;
387 *p
++ = typelib
->library
.lcid
;
388 *(int *)p
= 0; /* res12 */
390 *p
++ = typelib
->library
.libflags
;
391 *(int *)p
= typelib
->library
.version
;
393 *(GUID
*)p
= typelib
->library
.uuid
;
395 add_block(typelib
, block
, size
, "dir");
398 static const char *new_index_name(void)
400 static char name
[11] = "AAAAAAAAAA";
404 if (name
[pos
] == 'Z')
408 error("too many index names\n");
413 new_name
= xmalloc(sizeof(name
));
414 strcpy(new_name
, name
);
418 static void sltg_add_typeinfo(struct sltg_typelib
*sltg
, void *data
, int length
, const char *name
)
420 chat("sltg_add_typeinfo: %p,%d,%s\n", data
, length
, name
);
422 sltg
->typeinfo
= xrealloc(sltg
->typeinfo
, sizeof(sltg
->typeinfo
[0]) * (sltg
->typeinfo_count
+ 1));
423 sltg
->typeinfo
[sltg
->typeinfo_count
].length
= length
;
424 sltg
->typeinfo
[sltg
->typeinfo_count
].data
= data
;
425 sltg
->typeinfo
[sltg
->typeinfo_count
].index_string
= 0;
426 sltg
->typeinfo_count
++;
427 sltg
->typeinfo_size
+= length
;
430 static void append_data(struct sltg_data
*block
, const void *data
, int size
)
432 int new_size
= block
->size
+ size
;
434 if (new_size
> block
->allocated
)
436 block
->allocated
= max(block
->allocated
* 2, new_size
);
437 block
->data
= xrealloc(block
->data
, block
->allocated
);
440 memcpy(block
->data
+ block
->size
, data
, size
);
441 block
->size
= new_size
;
444 static void add_module_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
)
446 error("add_module_typeinfo: %s not implemented\n", type
->name
);
449 static const char *add_typeinfo_block(struct sltg_typelib
*typelib
, const type_t
*type
, short kind
)
451 struct sltg_data block
;
452 const char *index_name
, *other_name
;
459 index_name
= new_index_name();
460 other_name
= new_index_name();
462 expr
= get_attrp(type
->attrs
, ATTR_HELPCONTEXT
);
463 if (expr
) helpcontext
= expr
->cval
;
465 p
= get_attrp(type
->attrs
, ATTR_UUID
);
466 if (p
) guid
= *(GUID
*)p
;
468 init_sltg_data(&block
);
470 val
= strlen(index_name
);
471 append_data(&block
, &val
, sizeof(val
));
472 append_data(&block
, index_name
, val
);
473 val
= strlen(other_name
);
474 append_data(&block
, &val
, sizeof(val
));
475 append_data(&block
, other_name
, val
);
476 val
= -1; /* res1a */
477 append_data(&block
, &val
, sizeof(val
));
478 val
= add_name(&typelib
->name_table
, type
->name
); /* name offset */
479 append_data(&block
, &val
, sizeof(val
));
480 val
= 0; /* FIXME: helpstring */
481 append_data(&block
, &val
, sizeof(val
));
482 val
= -1; /* res20 */
483 append_data(&block
, &val
, sizeof(val
));
484 append_data(&block
, &helpcontext
, sizeof(helpcontext
));
485 val
= -1; /* res26 */
486 append_data(&block
, &val
, sizeof(val
));
487 append_data(&block
, &guid
, sizeof(guid
));
488 append_data(&block
, &kind
, sizeof(kind
));
490 sltg_add_typeinfo(typelib
, block
.data
, block
.size
, index_name
);
495 static void init_typeinfo(struct sltg_typeinfo_header
*ti
, const type_t
*type
, short kind
,
496 const struct sltg_hrefmap
*hrefmap
)
499 ti
->href_offset
= -1;
501 ti
->member_offset
= sizeof(*ti
);
503 ti
->version
= get_attrv(type
->attrs
, ATTR_VERSION
);
504 ti
->res16
= 0xfffe0000;
505 ti
->misc
.unknown1
= 0x02;
506 ti
->misc
.flags
= 0; /* FIXME */
507 ti
->misc
.unknown2
= 0x02;
508 ti
->misc
.typekind
= kind
;
511 if (hrefmap
->href_count
)
514 int i
, hrefinfo_size
;
516 hrefinfo_size
= sizeof(struct sltg_hrefinfo
);
518 for (i
= 0; i
< hrefmap
->href_count
; i
++)
520 sprintf(name
, "*\\Rffff*#%x", hrefmap
->href
[i
]);
521 hrefinfo_size
+= 8 + 2 + strlen(name
);
524 ti
->href_offset
= ti
->member_offset
;
525 ti
->member_offset
+= hrefinfo_size
;
529 static void write_hrefmap(struct sltg_data
*data
, const struct sltg_hrefmap
*hrefmap
)
531 struct sltg_hrefinfo hrefinfo
;
535 if (!hrefmap
->href_count
) return;
537 hrefinfo
.magic
= 0xdf;
539 memset(hrefinfo
.res02
, 0xff, sizeof(hrefinfo
.res02
));
540 hrefinfo
.number
= hrefmap
->href_count
* 8;
544 hrefinfo
.resxx
= 0xdf;
546 append_data(data
, &hrefinfo
, offsetof(struct sltg_hrefinfo
, res50
));
548 for (i
= 0; i
< hrefmap
->href_count
; i
++)
549 append_data(data
, "\xff\xff\xff\xff\xff\xff\xff\xff", 8);
551 append_data(data
, &hrefinfo
.res50
, 7);
553 for (i
= 0; i
< hrefmap
->href_count
; i
++)
557 sprintf(name
, "*\\Rffff*#%x", hrefmap
->href
[i
]);
560 append_data(data
, &len
, sizeof(len
));
561 append_data(data
, name
, len
);
564 append_data(data
, &hrefinfo
.resxx
, sizeof(hrefinfo
.resxx
));
567 static void dump_var_desc(const char *data
, int size
)
569 const unsigned char *p
= (const unsigned char *)data
;
572 if (!(debuglevel
& (DEBUGLEVEL_TRACE
| DEBUGLEVEL_CHAT
))) return;
574 chat("dump_var_desc: size %d bytes\n", size
);
576 for (i
= 0; i
< size
; i
++)
577 fprintf(stderr
, " %02x", *p
++);
579 fprintf(stderr
, "\n");
582 static int get_element_size(type_t
*type
)
584 int vt
= get_type_vt(type
);
634 error("get_element_size: unrecognized vt %d\n", vt
);
641 static int local_href(struct sltg_hrefmap
*hrefmap
, int typelib_href
)
645 for (i
= 0; i
< hrefmap
->href_count
; i
++)
647 if (hrefmap
->href
[i
] == typelib_href
)
656 href
= hrefmap
->href_count
;
659 hrefmap
->href
= xrealloc(hrefmap
->href
, sizeof(*hrefmap
->href
) * (hrefmap
->href_count
+ 1));
661 hrefmap
->href
= xmalloc(sizeof(*hrefmap
->href
));
663 hrefmap
->href
[hrefmap
->href_count
] = typelib_href
;
664 hrefmap
->href_count
++;
667 chat("typelib href %d mapped to local href %d\n", typelib_href
, href
);
672 static short write_var_desc(struct sltg_typelib
*typelib
, struct sltg_data
*data
, type_t
*type
, short flags
,
673 short base_offset
, int *size_instance
, struct sltg_hrefmap
*hrefmap
)
675 short vt
, vt_flags
, desc_offset
;
677 chat("write_var_desc: type %p, type->name %s\n",
678 type
, type
->name
? type
->name
: "NULL");
680 if (is_array(type
) && !type_array_is_decl_as_ptr(type
))
682 int num_dims
, elements
, array_start
, size
, array_size
;
701 while (is_array(atype
) && !type_array_is_decl_as_ptr(atype
))
704 elements
*= type_array_get_dim(atype
);
706 atype
= type_array_get_element_type(atype
);
709 chat("write_var_desc: VT_CARRAY: %d dimensions, %d elements\n", num_dims
, elements
);
711 array_start
= data
->size
;
713 size
= sizeof(*array
) + (num_dims
- 1) * 8 /* sizeof(SAFEARRAYBOUND) */;
714 array
= xmalloc(size
);
716 array
->cDims
= num_dims
;
717 array
->fFeatures
= 0x0004; /* FADF_EMBEDDED */
718 array
->cbElements
= get_element_size(atype
);
722 bound
= array
->bound
;
724 array_size
= array
->cbElements
;
727 while (is_array(atype
) && !type_array_is_decl_as_ptr(atype
))
729 bound
[0] = type_array_get_dim(atype
);
730 array_size
*= bound
[0];
734 atype
= type_array_get_element_type(atype
);
739 *size_instance
+= array_size
;
740 size_instance
= NULL
; /* don't account for element size */
744 append_data(data
, array
, size
);
746 desc_offset
= data
->size
;
748 vt_off
[0] = VT_CARRAY
;
749 vt_off
[1] = array_start
+ base_offset
;
750 append_data(data
, vt_off
, sizeof(vt_off
));
752 /* fall through to write array element description */
756 desc_offset
= data
->size
;
758 vt
= get_type_vt(type
);
762 type_t
*ref
= is_ptr(type
) ? type_pointer_get_ref_type(type
) : type_array_get_element_type(type
);
766 chat("write_var_desc: vt VT_PTR | 0x0400\n");
767 vt
= VT_PTR
| 0x0400;
768 append_data(data
, &vt
, sizeof(vt
));
769 write_var_desc(typelib
, data
, ref
, 0, base_offset
, size_instance
, hrefmap
);
772 write_var_desc(typelib
, data
, ref
, 0x0e00, base_offset
, size_instance
, hrefmap
);
776 chat("write_var_desc: vt %d, flags %04x\n", vt
, flags
);
778 vt_flags
= vt
| flags
;
779 append_data(data
, &vt_flags
, sizeof(vt_flags
));
781 if (vt
== VT_USERDEFINED
)
785 while (type
->typelib_idx
< 0 && type_is_alias(type
))
786 type
= type_alias_get_aliasee_type(type
);
788 chat("write_var_desc: VT_USERDEFINED, type %p, name %s, real type %d, href %d\n",
789 type
, type
->name
, type_get_type(type
), type
->typelib_idx
);
791 if (type
->typelib_idx
== -1)
793 chat("write_var_desc: trying to ref not added type\n");
795 switch (type_get_type(type
))
798 add_structure_typeinfo(typelib
, type
);
801 add_interface_typeinfo(typelib
, type
);
804 add_enum_typeinfo(typelib
, type
);
807 add_union_typeinfo(typelib
, type
);
810 add_coclass_typeinfo(typelib
, type
);
813 error("write_var_desc: VT_USERDEFINED - unhandled type %d\n",
814 type_get_type(type
));
818 if (type
->typelib_idx
== -1)
819 error("write_var_desc: trying to ref not added type\n");
821 href
= local_href(hrefmap
, type
->typelib_idx
);
822 chat("write_var_desc: VT_USERDEFINED, local href %d\n", href
);
824 append_data(data
, &href
, sizeof(href
));
828 *size_instance
+= get_element_size(type
);
833 static void init_sltg_tail(struct sltg_tail
*tail
)
837 tail
->cImplTypes
= 0;
839 tail
->funcs_off
= -1;
841 tail
->impls_off
= -1;
842 tail
->funcs_bytes
= -1;
843 tail
->vars_bytes
= -1;
844 tail
->impls_bytes
= -1;
845 tail
->tdescalias_vt
= -1;
849 tail
->simple_alias
= 0;
851 tail
->cbSizeInstance
= 0;
852 tail
->cbAlignment
= 4;
861 tail
->type_bytes
= 0;
864 static void add_structure_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
)
866 struct sltg_data data
, *var_data
= NULL
;
867 struct sltg_hrefmap hrefmap
;
868 const char *index_name
;
869 struct sltg_typeinfo_header ti
;
870 struct sltg_member_header member
;
871 struct sltg_tail tail
;
872 int member_offset
, var_count
= 0, var_data_size
= 0, size_instance
= 0;
873 short *type_desc_offset
= NULL
;
875 if (type
->typelib_idx
!= -1) return;
877 chat("add_structure_typeinfo: type %p, type->name %s\n", type
, type
->name
);
879 type
->typelib_idx
= typelib
->block_count
;
881 hrefmap
.href_count
= 0;
884 if (type_struct_get_fields(type
))
889 var_count
= list_count(type_struct_get_fields(type
));
891 var_data
= xmalloc(var_count
* sizeof(*var_data
));
892 type_desc_offset
= xmalloc(var_count
* sizeof(*type_desc_offset
));
894 LIST_FOR_EACH_ENTRY(var
, type_struct_get_fields(type
), var_t
, entry
)
898 chat("add_structure_typeinfo: var %p (%s), type %p (%s)\n",
899 var
, var
->name
, var
->declspec
.type
, var
->declspec
.type
->name
);
901 init_sltg_data(&var_data
[i
]);
903 base_offset
= var_data_size
+ (i
+ 1) * sizeof(struct sltg_variable
);
904 type_desc_offset
[i
] = write_var_desc(typelib
, &var_data
[i
], var
->declspec
.type
, 0, base_offset
, &size_instance
, &hrefmap
);
905 dump_var_desc(var_data
[i
].data
, var_data
[i
].size
);
907 if (var_data
[i
].size
> sizeof(short))
908 var_data_size
+= var_data
[i
].size
;
913 init_sltg_data(&data
);
915 index_name
= add_typeinfo_block(typelib
, type
, TKIND_RECORD
);
917 init_typeinfo(&ti
, type
, TKIND_RECORD
, &hrefmap
);
918 append_data(&data
, &ti
, sizeof(ti
));
920 write_hrefmap(&data
, &hrefmap
);
922 member_offset
= data
.size
;
924 member
.res00
= 0x0001;
925 member
.res02
= 0xffff;
927 member
.extra
= var_data_size
+ var_count
* sizeof(struct sltg_variable
);
928 append_data(&data
, &member
, sizeof(member
));
932 if (type_struct_get_fields(type
))
935 short next
= member_offset
;
938 LIST_FOR_EACH_ENTRY(var
, type_struct_get_fields(type
), var_t
, entry
)
940 struct sltg_variable variable
;
942 next
+= sizeof(variable
);
944 variable
.magic
= 0x2a; /* always write flags to simplify calculations */
945 variable
.name
= add_name(&typelib
->name_table
, var
->name
);
946 variable
.byte_offs
= 0;
947 if (var_data
[i
].size
> sizeof(short))
950 var_data_size
= next
- member_offset
+ type_desc_offset
[i
];
951 variable
.type
= var_data_size
;
952 next
+= var_data
[i
].size
;
956 variable
.flags
= 0x02;
957 variable
.type
= *(short *)var_data
[i
].data
;
959 variable
.next
= i
< var_count
- 1 ? next
- member_offset
: -1;
960 variable
.memid
= 0x40000000 + i
;
961 variable
.helpcontext
= -2; /* 0xfffe */
962 variable
.helpstring
= -1;
963 variable
.varflags
= 0;
965 append_data(&data
, &variable
, sizeof(variable
));
966 if (var_data
[i
].size
> sizeof(short))
967 append_data(&data
, var_data
[i
].data
, var_data
[i
].size
);
973 init_sltg_tail(&tail
);
974 tail
.cVars
= var_count
;
976 tail
.vars_bytes
= var_data_size
;
977 tail
.cbSizeInstance
= size_instance
;
978 tail
.type_bytes
= data
.size
- member_offset
- sizeof(member
);
979 append_data(&data
, &tail
, sizeof(tail
));
981 add_block(typelib
, data
.data
, data
.size
, index_name
);
984 static importinfo_t
*find_importinfo(typelib_t
*typelib
, const char *name
)
986 importlib_t
*importlib
;
988 LIST_FOR_EACH_ENTRY(importlib
, &typelib
->importlibs
, importlib_t
, entry
)
992 for (i
= 0; i
< importlib
->ntypeinfos
; i
++)
994 if (!strcmp(name
, importlib
->importinfos
[i
].name
))
996 chat("Found %s in importlib list\n", name
);
997 return &importlib
->importinfos
[i
];
1005 static int get_func_flags(const var_t
*func
, int *dispid
, int *invokekind
, int *helpcontext
, const char **helpstring
)
1007 static int dispid_base
= 0x60000000;
1011 *dispid
= dispid_base
++;
1012 *invokekind
= 1 /* INVOKE_FUNC */;
1016 if (!func
->attrs
) return 0;
1020 LIST_FOR_EACH_ENTRY(attr
, func
->attrs
, const attr_t
, entry
)
1022 expr_t
*expr
= attr
->u
.pval
;
1026 flags
|= 0x4; /* FUNCFLAG_FBINDABLE */
1028 case ATTR_DEFAULTBIND
:
1029 flags
|= 0x20; /* FUNCFLAG_FDEFAULTBIND */
1031 case ATTR_DEFAULTCOLLELEM
:
1032 flags
|= 0x100; /* FUNCFLAG_FDEFAULTCOLLELEM */
1034 case ATTR_DISPLAYBIND
:
1035 flags
|= 0x10; /* FUNCFLAG_FDISPLAYBIND */
1037 case ATTR_HELPCONTEXT
:
1038 *helpcontext
= expr
->u
.lval
;
1040 case ATTR_HELPSTRING
:
1041 *helpstring
= attr
->u
.pval
;
1044 flags
|= 0x40; /* FUNCFLAG_FHIDDEN */
1047 *dispid
= expr
->cval
;
1049 case ATTR_IMMEDIATEBIND
:
1050 flags
|= 0x1000; /* FUNCFLAG_FIMMEDIATEBIND */
1052 case ATTR_NONBROWSABLE
:
1053 flags
|= 0x400; /* FUNCFLAG_FNONBROWSABLE */
1056 *invokekind
= 0x2; /* INVOKE_PROPERTYGET */
1059 *invokekind
= 0x4; /* INVOKE_PROPERTYPUT */
1061 case ATTR_PROPPUTREF
:
1062 *invokekind
= 0x8; /* INVOKE_PROPERTYPUTREF */
1064 /* FIXME: FUNCFLAG_FREPLACEABLE */
1065 case ATTR_REQUESTEDIT
:
1066 flags
|= 0x8; /* FUNCFLAG_FREQUESTEDIT */
1068 case ATTR_RESTRICTED
:
1069 flags
|= 0x1; /* FUNCFLAG_FRESTRICTED */
1072 flags
|= 0x2; /* FUNCFLAG_FSOURCE */
1074 case ATTR_UIDEFAULT
:
1075 flags
|= 0x200; /* FUNCFLAG_FUIDEFAULT */
1077 case ATTR_USESGETLASTERROR
:
1078 flags
|= 0x80; /* FUNCFLAG_FUSESGETLASTERROR */
1088 static int add_func_desc(struct sltg_typelib
*typelib
, struct sltg_data
*data
, var_t
*func
,
1089 int idx
, short base_offset
, struct sltg_hrefmap
*hrefmap
)
1091 struct sltg_data ret_data
, *arg_data
;
1092 int arg_count
= 0, arg_data_size
, optional
= 0, defaults
= 0, old_size
;
1093 int funcflags
= 0, dispid
, invokekind
= 1 /* INVOKE_FUNC */, helpcontext
;
1094 const char *helpstring
;
1096 short ret_desc_offset
, *arg_desc_offset
, arg_offset
;
1097 struct sltg_function func_desc
;
1099 chat("add_func_desc: %s, idx %#x\n", func
->name
, idx
);
1101 old_size
= data
->size
;
1103 init_sltg_data(&ret_data
);
1104 ret_desc_offset
= write_var_desc(typelib
, &ret_data
, type_function_get_rettype(func
->declspec
.type
),
1105 0, base_offset
, NULL
, hrefmap
);
1106 dump_var_desc(ret_data
.data
, ret_data
.size
);
1109 arg_offset
= base_offset
+ sizeof(struct sltg_function
);
1111 if (ret_data
.size
> sizeof(short))
1113 arg_data_size
+= ret_data
.size
;
1114 arg_offset
+= ret_data
.size
;
1117 if (type_function_get_args(func
->declspec
.type
))
1121 arg_count
= list_count(type_function_get_args(func
->declspec
.type
));
1123 arg_data
= xmalloc(arg_count
* sizeof(*arg_data
));
1124 arg_desc_offset
= xmalloc(arg_count
* sizeof(*arg_desc_offset
));
1126 arg_offset
+= arg_count
* 2 * sizeof(short);
1128 LIST_FOR_EACH_ENTRY(arg
, type_function_get_args(func
->declspec
.type
), const var_t
, entry
)
1132 chat("add_func_desc: arg[%d] %p (%s), type %p (%s)\n",
1133 i
, arg
, arg
->name
, arg
->declspec
.type
, arg
->declspec
.type
->name
);
1135 init_sltg_data(&arg_data
[i
]);
1137 arg_desc_offset
[i
] = write_var_desc(typelib
, &arg_data
[i
], arg
->declspec
.type
, 0, arg_offset
, NULL
, hrefmap
);
1138 dump_var_desc(arg_data
[i
].data
, arg_data
[i
].size
);
1140 if (arg_data
[i
].size
> sizeof(short))
1142 arg_data_size
+= arg_data
[i
].size
;
1143 arg_offset
+= arg_data
[i
].size
;
1148 if (!arg
->attrs
) continue;
1150 LIST_FOR_EACH_ENTRY(attr
, arg
->attrs
, const attr_t
, entry
)
1152 if (attr
->type
== ATTR_DEFAULTVALUE
)
1154 else if(attr
->type
== ATTR_OPTIONAL
)
1160 funcflags
= get_func_flags(func
, &dispid
, &invokekind
, &helpcontext
, &helpstring
);
1162 if (base_offset
!= -1)
1163 chat("add_func_desc: flags %#x, dispid %#x, invokekind %d, helpcontext %#x, helpstring %s\n",
1164 funcflags
, dispid
, invokekind
, helpcontext
, helpstring
);
1166 func_desc
.magic
= 0x6c; /* always write flags to simplify calculations */
1167 func_desc
.flags
= (invokekind
<< 4) | 0x02;
1168 if (idx
& 0x80000000)
1170 func_desc
.next
= -1;
1174 func_desc
.next
= base_offset
+ sizeof(func_desc
) + arg_data_size
+ arg_count
* 2 * sizeof(short);
1175 func_desc
.name
= base_offset
!= -1 ? add_name(&typelib
->name_table
, func
->name
) : -1;
1176 func_desc
.dispid
= dispid
;
1177 func_desc
.helpcontext
= helpcontext
;
1178 func_desc
.helpstring
= (helpstring
&& base_offset
!= -1) ? add_name(&typelib
->name_table
, helpstring
) : -1;
1179 func_desc
.arg_off
= arg_count
? base_offset
+ sizeof(func_desc
) : -1;
1180 func_desc
.nacc
= (arg_count
<< 3) | 4 /* CC_STDCALL */;
1181 func_desc
.retnextopt
= (optional
<< 1);
1182 if (ret_data
.size
> sizeof(short))
1184 func_desc
.rettype
= base_offset
+ sizeof(func_desc
) + ret_desc_offset
;
1186 func_desc
.arg_off
+= ret_data
.size
;
1190 func_desc
.retnextopt
|= 0x80;
1191 func_desc
.rettype
= *(short *)ret_data
.data
;
1193 func_desc
.vtblpos
= idx
* pointer_size
;
1194 func_desc
.funcflags
= funcflags
;
1196 append_data(data
, &func_desc
, sizeof(func_desc
));
1198 arg_offset
= base_offset
+ sizeof(struct sltg_function
);
1200 if (ret_data
.size
> sizeof(short))
1202 append_data(data
, ret_data
.data
, ret_data
.size
);
1203 func_desc
.arg_off
+= ret_data
.size
;
1204 arg_offset
+= ret_data
.size
;
1211 arg_offset
+= arg_count
* 2 * sizeof(short);
1213 LIST_FOR_EACH_ENTRY(arg
, type_function_get_args(func
->declspec
.type
), const var_t
, entry
)
1215 short name
, type_offset
;
1217 name
= base_offset
!= -1 ? add_name(&typelib
->name_table
, arg
->name
) : -1;
1218 append_data(data
, &name
, sizeof(name
));
1220 if (arg_data
[i
].size
> sizeof(short))
1222 type_offset
= (arg_offset
+ arg_desc_offset
[i
]);
1223 arg_offset
+= arg_data
[i
].size
;
1226 type_offset
= *(short *)arg_data
[i
].data
;
1228 append_data(data
, &type_offset
, sizeof(type_offset
));
1230 if (base_offset
!= -1)
1231 chat("add_func_desc: arg[%d] - name %s (%#x), type_offset %#x\n",
1232 i
, arg
->name
, name
, type_offset
);
1237 for (i
= 0; i
< arg_count
; i
++)
1239 if (arg_data
[i
].size
> sizeof(short))
1240 append_data(data
, arg_data
[i
].data
, arg_data
[i
].size
);
1244 return data
->size
- old_size
;
1247 static void add_interface_typeinfo(struct sltg_typelib
*typelib
, type_t
*iface
)
1249 const statement_t
*stmt_func
;
1250 importinfo_t
*ref_importinfo
= NULL
;
1252 struct sltg_data data
;
1253 struct sltg_hrefmap hrefmap
;
1254 const char *index_name
;
1255 struct sltg_typeinfo_header ti
;
1256 struct sltg_member_header member
;
1257 struct sltg_tail tail
;
1258 int member_offset
, base_offset
, func_count
, func_data_size
, i
;
1260 if (iface
->typelib_idx
!= -1) return;
1262 chat("add_interface_typeinfo: type %p, type->name %s\n", iface
, iface
->name
);
1264 if (!iface
->details
.iface
)
1266 error("interface %s is referenced but not defined\n", iface
->name
);
1270 if (is_attr(iface
->attrs
, ATTR_DISPINTERFACE
))
1272 error("support for dispinterface %s is not implemented\n", iface
->name
);
1276 inherit
= type_iface_get_inherit(iface
);
1280 chat("add_interface_typeinfo: inheriting from base interface %s\n", inherit
->name
);
1282 warning("inheriting from base interface %s is not implemented\n", inherit
->name
);
1284 ref_importinfo
= find_importinfo(typelib
->typelib
, inherit
->name
);
1286 if (!ref_importinfo
&& type_iface_get_inherit(inherit
))
1287 add_interface_typeinfo(typelib
, inherit
);
1290 error("support for imported interfaces is not implemented\n");
1293 /* check typelib_idx again, it could have been added while resolving the parent interface */
1294 if (iface
->typelib_idx
!= -1) return;
1296 iface
->typelib_idx
= typelib
->block_count
;
1298 /* pass 1: calculate function descriptions data size */
1299 hrefmap
.href_count
= 0;
1300 hrefmap
.href
= NULL
;
1302 init_sltg_data(&data
);
1304 STATEMENTS_FOR_EACH_FUNC(stmt_func
, type_iface_get_stmts(iface
))
1306 add_func_desc(typelib
, &data
, stmt_func
->u
.var
, -1, -1, &hrefmap
);
1309 func_data_size
= data
.size
;
1311 /* pass 2: write function descriptions */
1312 init_sltg_data(&data
);
1314 func_count
= list_count(type_iface_get_stmts(iface
));
1316 index_name
= add_typeinfo_block(typelib
, iface
, TKIND_INTERFACE
);
1318 init_typeinfo(&ti
, iface
, TKIND_INTERFACE
, &hrefmap
);
1319 append_data(&data
, &ti
, sizeof(ti
));
1321 write_hrefmap(&data
, &hrefmap
);
1323 member_offset
= data
.size
;
1325 member
.res00
= 0x0001;
1326 member
.res02
= 0xffff;
1327 member
.res04
= 0x01;
1328 member
.extra
= func_data_size
;
1329 append_data(&data
, &member
, sizeof(member
));
1333 /* inheriting from base interface is not implemented yet
1334 if (type_iface_get_inherit(iface))
1335 add_impl_type(typeinfo, type_iface_get_inherit(iface), ref_importinfo);
1340 STATEMENTS_FOR_EACH_FUNC(stmt_func
, type_iface_get_stmts(iface
))
1342 if (i
== func_count
- 1) i
|= 0x80000000;
1344 base_offset
+= add_func_desc(typelib
, &data
, stmt_func
->u
.var
, i
, base_offset
, &hrefmap
);
1348 init_sltg_tail(&tail
);
1350 tail
.cFuncs
= func_count
;
1352 tail
.funcs_bytes
= func_data_size
;
1353 tail
.cbSizeInstance
= pointer_size
;
1354 tail
.cbAlignment
= pointer_size
;
1355 tail
.cbSizeVft
= func_count
* pointer_size
;
1356 tail
.type_bytes
= data
.size
- member_offset
- sizeof(member
);
1359 append_data(&data
, &tail
, sizeof(tail
));
1361 add_block(typelib
, data
.data
, data
.size
, index_name
);
1364 static void add_enum_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
)
1366 error("add_enum_typeinfo: %s not implemented\n", type
->name
);
1369 static void add_union_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
)
1371 error("add_union_typeinfo: %s not implemented\n", type
->name
);
1374 static void add_coclass_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
)
1376 error("add_coclass_typeinfo: %s not implemented\n", type
->name
);
1379 static void add_type_typeinfo(struct sltg_typelib
*typelib
, type_t
*type
)
1381 chat("add_type_typeinfo: adding %s, type %d\n", type
->name
, type_get_type(type
));
1383 switch (type_get_type(type
))
1385 case TYPE_INTERFACE
:
1386 add_interface_typeinfo(typelib
, type
);
1389 add_structure_typeinfo(typelib
, type
);
1392 add_enum_typeinfo(typelib
, type
);
1395 add_union_typeinfo(typelib
, type
);
1398 add_coclass_typeinfo(typelib
, type
);
1404 error("add_type_typeinfo: unhandled type %d for %s\n", type_get_type(type
), type
->name
);
1409 static void add_statement(struct sltg_typelib
*typelib
, const statement_t
*stmt
)
1417 case STMT_DECLARATION
:
1418 /* not included in typelib */
1420 case STMT_IMPORTLIB
:
1421 /* not processed here */
1428 if (!stmt
->u
.type_list
)
1431 LIST_FOR_EACH_ENTRY(ref
, stmt
->u
.type_list
, typeref_t
, entry
)
1433 /* in old style typelibs all types are public */
1434 add_type_typeinfo(typelib
, ref
->type
);
1440 add_module_typeinfo(typelib
, stmt
->u
.type
);
1446 type_t
*type
= stmt
->u
.type
;
1447 add_type_typeinfo(typelib
, type
);
1452 error("add_statement: unhandled statement type %d\n", stmt
->type
);
1457 static void sltg_write_header(struct sltg_typelib
*sltg
, int *library_block_start
)
1465 short size_of_index
;
1471 struct sltg_block_entry
1479 header
.magic
= 0x47544c53;
1480 header
.block_count
= sltg
->block_count
+ 1; /* 1-based */
1482 header
.size_of_index
= sltg
->index
.size
;
1483 header
.first_blk
= 1; /* 1-based */
1484 header
.uuid
= sltg_library_guid
;
1485 header
.res1c
= 0x00000044;
1486 header
.res20
= 0xffff0000;
1488 put_data(&header
, sizeof(header
));
1490 /* library block is written separately */
1491 for (i
= 0; i
< sltg
->block_count
- 1; i
++)
1493 entry
.length
= sltg
->blocks
[i
].length
;
1494 entry
.index_string
= sltg
->blocks
[i
].index_string
;
1495 entry
.next
= header
.first_blk
+ i
+ 1; /* point to next block */
1496 chat("sltg_write_header: writing block entry %d: length %#x, index_string %#x, next %#x\n",
1497 i
, entry
.length
, entry
.index_string
, entry
.next
);
1498 put_data(&entry
, sizeof(entry
));
1501 /* library block length includes helpstrings and name table */
1502 entry
.length
= sltg
->blocks
[sltg
->block_count
- 1].length
+ 0x40 /* pad after library block */ +
1503 sizeof(sltg
->typeinfo_count
) + sltg
->typeinfo_size
+ 4 /* library block offset */ + 6 /* dummy help strings */ +
1504 12 /* name table header */ + 0x200 /* name table hash */ + sltg
->name_table
.size
;
1505 entry
.index_string
= sltg
->blocks
[sltg
->block_count
- 1].index_string
;
1507 chat("sltg_write_header: writing library block entry %d: length %#x, index_string %#x, next %#x\n",
1508 i
, entry
.length
, entry
.index_string
, entry
.next
);
1509 put_data(&entry
, sizeof(entry
));
1511 chat("sltg_write_header: writing index: %d bytes\n", sltg
->index
.size
);
1512 put_data(sltg
->index
.data
, sltg
->index
.size
);
1516 /* library block is written separately */
1517 for (i
= 0; i
< sltg
->block_count
- 1; i
++)
1519 chat("sltg_write_header: writing block %d: %d bytes\n", i
, sltg
->blocks
[i
].length
);
1520 put_data(sltg
->blocks
[i
].data
, sltg
->blocks
[i
].length
);
1524 chat("library_block_start = %#x\n", (int)output_buffer_pos
);
1525 *library_block_start
= output_buffer_pos
;
1526 chat("sltg_write_header: writing library block %d: %d bytes\n", i
, sltg
->blocks
[i
].length
);
1527 put_data(sltg
->blocks
[sltg
->block_count
- 1].data
, sltg
->blocks
[sltg
->block_count
- 1].length
);
1529 chat("sltg_write_header: writing pad 0x40 bytes\n");
1530 memset(pad
, 0xff, 0x40);
1531 put_data(pad
, 0x40);
1534 static void sltg_write_typeinfo(struct sltg_typelib
*typelib
)
1538 put_data(&typelib
->typeinfo_count
, sizeof(typelib
->typeinfo_count
));
1540 for (i
= 0; i
< typelib
->typeinfo_count
; i
++)
1542 chat("sltg_write_typeinfo: writing block %d: %d bytes\n", i
, typelib
->typeinfo
[i
].length
);
1543 put_data(typelib
->typeinfo
[i
].data
, typelib
->typeinfo
[i
].length
);
1547 static void sltg_write_helpstrings(struct sltg_typelib
*typelib
)
1549 static const char dummy
[6];
1551 chat("sltg_write_helpstrings: writing dummy 6 bytes\n");
1553 put_data(dummy
, sizeof(dummy
));
1556 static void sltg_write_nametable(struct sltg_typelib
*typelib
)
1558 static const short dummy
[6] = { 0xffff,1,2,0xff00,0xffff,0xffff };
1561 chat("sltg_write_nametable: writing 12+0x200+%d bytes\n", typelib
->name_table
.size
);
1563 put_data(dummy
, sizeof(dummy
));
1564 memset(pad
, 0xff, 0x200);
1565 put_data(pad
, 0x200);
1566 put_data(&typelib
->name_table
.size
, sizeof(typelib
->name_table
.size
));
1567 put_data(typelib
->name_table
.data
, typelib
->name_table
.size
);
1570 static void sltg_write_remainder(void)
1572 static const short dummy1
[] = { 1,0xfffe,0x0a03,0,0xffff,0xffff };
1573 static const short dummy2
[] = { 0xffff,0xffff,0x0200,0,0,0 };
1574 static const char dummy3
[] = { 0xf4,0x39,0xb2,0x71,0,0,0,0,0,0,0,0,0,0,0,0 };
1575 static const char TYPELIB
[] = { 8,0,0,0,'T','Y','P','E','L','I','B',0 };
1579 put_data(&pad
, sizeof(pad
));
1581 put_data(&pad
, sizeof(pad
));
1583 put_data(dummy1
, sizeof(dummy1
));
1585 put_data(&sltg_library_guid
, sizeof(sltg_library_guid
));
1587 put_data(TYPELIB
, sizeof(TYPELIB
));
1589 put_data(dummy2
, sizeof(dummy2
));
1590 put_data(dummy3
, sizeof(dummy3
));
1593 static void save_all_changes(struct sltg_typelib
*typelib
)
1595 int library_block_start
;
1596 int *name_table_offset
;
1598 sltg_write_header(typelib
, &library_block_start
);
1599 sltg_write_typeinfo(typelib
);
1601 name_table_offset
= (int *)(output_buffer
+ output_buffer_pos
);
1602 chat("name_table_offset = %#x\n", (int)output_buffer_pos
);
1603 put_data(&library_block_start
, sizeof(library_block_start
));
1605 sltg_write_helpstrings(typelib
);
1607 *name_table_offset
= output_buffer_pos
- library_block_start
;
1608 chat("*name_table_offset = %#x\n", *name_table_offset
);
1610 sltg_write_nametable(typelib
);
1611 sltg_write_remainder();
1613 if (strendswith(typelib_name
, ".res")) /* create a binary resource file */
1615 char typelib_id
[13] = "#1";
1617 expr_t
*expr
= get_attrp(typelib
->typelib
->attrs
, ATTR_ID
);
1619 sprintf(typelib_id
, "#%d", expr
->cval
);
1620 add_output_to_resources("TYPELIB", typelib_id
);
1621 if (strendswith(typelib_name
, "_t.res")) /* add typelib registration */
1622 output_typelib_regscript(typelib
->typelib
);
1624 else flush_output_buffer(typelib_name
);
1627 int create_sltg_typelib(typelib_t
*typelib
)
1629 struct sltg_typelib sltg
;
1630 const statement_t
*stmt
;
1632 if (pointer_size
!= 4)
1633 error("Only 32-bit platform is supported\n");
1635 sltg
.typelib
= typelib
;
1636 sltg
.typeinfo_count
= 0;
1637 sltg
.typeinfo_size
= 0;
1638 sltg
.typeinfo
= NULL
;
1640 sltg
.block_count
= 0;
1641 sltg
.first_block
= 1;
1643 init_index(&sltg
.index
);
1644 init_name_table(&sltg
.name_table
);
1645 init_library(&sltg
);
1647 add_library_block(&sltg
);
1650 LIST_FOR_EACH_ENTRY(stmt
, typelib
->stmts
, const statement_t
, entry
)
1651 add_statement(&sltg
, stmt
);
1653 save_all_changes(&sltg
);