dinput: Move SetEventNotification and associated event into base class.
[wine] / tools / widl / typelib.c
1 /*
2  * IDL Compiler
3  *
4  * Copyright 2004 Ove Kaaven
5  * Copyright 2006 Jacek Caban for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/wpp.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <signal.h>
34
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
37
38 #include "windef.h"
39 #include "winbase.h"
40
41 #include "widl.h"
42 #include "utils.h"
43 #include "parser.h"
44 #include "header.h"
45 #include "typelib.h"
46 #include "widltypes.h"
47 #include "typelib_struct.h"
48
49 int in_typelib = 0;
50
51 static typelib_t *typelib;
52
53 type_t *duptype(type_t *t, int dupname)
54 {
55   type_t *d = xmalloc(sizeof *d);
56
57   *d = *t;
58   if (dupname && t->name)
59     d->name = xstrdup(t->name);
60
61   d->orig = t;
62   return d;
63 }
64
65 type_t *alias(type_t *t, const char *name)
66 {
67   type_t *a = duptype(t, 0);
68
69   a->name = xstrdup(name);
70   a->kind = TKIND_ALIAS;
71   a->attrs = NULL;
72
73   return a;
74 }
75
76 int is_ptr(const type_t *t)
77 {
78   unsigned char c = t->type;
79   return c == RPC_FC_RP
80       || c == RPC_FC_UP
81       || c == RPC_FC_FP
82       || c == RPC_FC_OP;
83 }
84
85 /* List of oleauto types that should be recognized by name.
86  * (most of) these seem to be intrinsic types in mktyplib. */
87
88 static struct oatype {
89   const char *kw;
90   unsigned short vt;
91 } oatypes[] = {
92   {"BSTR",          VT_BSTR},
93   {"CURRENCY",      VT_CY},
94   {"DATE",          VT_DATE},
95   {"DECIMAL",       VT_DECIMAL},
96   {"HRESULT",       VT_HRESULT},
97   {"LPSTR",         VT_LPSTR},
98   {"LPWSTR",        VT_LPWSTR},
99   {"SCODE",         VT_ERROR},
100   {"VARIANT",       VT_VARIANT},
101   {"VARIANT_BOOL",  VT_BOOL}
102 };
103 #define NTYPES (sizeof(oatypes)/sizeof(oatypes[0]))
104 #define KWP(p) ((const struct oatype *)(p))
105
106 static int kw_cmp_func(const void *s1, const void *s2)
107 {
108         return strcmp(KWP(s1)->kw, KWP(s2)->kw);
109 }
110
111 static unsigned short builtin_vt(const char *kw)
112 {
113   struct oatype key, *kwp;
114   key.kw = kw;
115 #ifdef KW_BSEARCH
116   kwp = bsearch(&key, oatypes, NTYPES, sizeof(oatypes[0]), kw_cmp_func);
117 #else
118   {
119     unsigned int i;
120     for (kwp=NULL, i=0; i < NTYPES; i++)
121       if (!kw_cmp_func(&key, &oatypes[i])) {
122         kwp = &oatypes[i];
123         break;
124       }
125   }
126 #endif
127   if (kwp) {
128     return kwp->vt;
129   }
130   return 0;
131 }
132
133 static int match(const char*n, const char*m)
134 {
135   if (!n) return 0;
136   return !strcmp(n, m);
137 }
138
139 unsigned short get_type_vt(type_t *t)
140 {
141   unsigned short vt;
142
143   chat("get_type_vt: %p type->name %s\n", t, t->name);
144   if (t->name) {
145     vt = builtin_vt(t->name);
146     if (vt) return vt;
147   }
148
149   if (t->kind == TKIND_ALIAS && t->attrs)
150     return VT_USERDEFINED;
151
152   switch (t->type) {
153   case RPC_FC_BYTE:
154   case RPC_FC_USMALL:
155     return VT_UI1;
156   case RPC_FC_CHAR:
157   case RPC_FC_SMALL:
158     return VT_I1;
159   case RPC_FC_WCHAR:
160     return VT_I2; /* mktyplib seems to parse wchar_t as short */
161   case RPC_FC_SHORT:
162     return VT_I2;
163   case RPC_FC_USHORT:
164     return VT_UI2;
165   case RPC_FC_LONG:
166     if (match(t->name, "int")) return VT_INT;
167     return VT_I4;
168   case RPC_FC_ULONG:
169     if (match(t->name, "int")) return VT_UINT;
170     return VT_UI4;
171   case RPC_FC_HYPER:
172     if (t->sign < 0) return VT_UI8;
173     if (match(t->name, "MIDL_uhyper")) return VT_UI8;
174     return VT_I8;
175   case RPC_FC_FLOAT:
176     return VT_R4;
177   case RPC_FC_DOUBLE:
178     return VT_R8;
179   case RPC_FC_RP:
180   case RPC_FC_UP:
181   case RPC_FC_OP:
182   case RPC_FC_FP:
183     if(t->ref)
184       return VT_PTR;
185
186     error("get_type_vt: unknown-deref-type: %d\n", t->ref->type);
187     break;
188   case RPC_FC_IP:
189     if(match(t->name, "IUnknown"))
190       return VT_UNKNOWN;
191     if(match(t->name, "IDispatch"))
192       return VT_DISPATCH;
193     return VT_USERDEFINED;
194
195   case RPC_FC_ENUM16:
196   case RPC_FC_STRUCT:
197   case RPC_FC_PSTRUCT:
198   case RPC_FC_CSTRUCT:
199   case RPC_FC_CPSTRUCT:
200   case RPC_FC_CVSTRUCT:
201   case RPC_FC_BOGUS_STRUCT:
202     return VT_USERDEFINED;
203   case 0:
204     return t->kind == TKIND_PRIMITIVE ? VT_VOID : VT_USERDEFINED;
205   default:
206     error("get_type_vt: unknown type: 0x%02x\n", t->type);
207   }
208   return 0;
209 }
210
211 unsigned short get_var_vt(var_t *v)
212 {
213   unsigned short vt;
214
215   chat("get_var_vt: %p tname %s\n", v, v->tname);
216   if (v->tname) {
217     vt = builtin_vt(v->tname);
218     if (vt) return vt;
219   }
220
221   return get_type_vt(v->type);
222 }
223
224 void start_typelib(char *name, attr_t *attrs)
225 {
226     in_typelib++;
227     if (!do_typelib) return;
228
229     typelib = xmalloc(sizeof(*typelib));
230     typelib->name = xstrdup(name);
231     typelib->filename = xstrdup(typelib_name);
232     typelib->attrs = attrs;
233     typelib->entry = NULL;
234     typelib->importlibs = NULL;
235 }
236
237 void end_typelib(void)
238 {
239     in_typelib--;
240     if (!typelib) return;
241
242     create_msft_typelib(typelib);
243     return;
244 }
245
246 void add_typelib_entry(type_t *t)
247 {
248     typelib_entry_t *entry;
249     if (!typelib) return;
250
251     chat("add kind %i: %s\n", t->kind, t->name);
252     entry = xmalloc(sizeof(*entry));
253     entry->type = t;
254     LINK(entry, typelib->entry);
255     typelib->entry = entry;
256 }
257
258 static void tlb_read(int fd, void *buf, int count)
259 {
260     if(read(fd, buf, count) < count)
261         error("error while reading importlib.\n");
262 }
263
264 static void tlb_lseek(int fd, off_t offset)
265 {
266     if(lseek(fd, offset, SEEK_SET) == -1)
267         error("lseek failed\n");
268 }
269
270 static void msft_read_guid(int fd, MSFT_SegDir *segdir, int offset, GUID *guid)
271 {
272     tlb_lseek(fd, segdir->pGuidTab.offset+offset);
273     tlb_read(fd, guid, sizeof(GUID));
274 }
275
276 static void read_msft_importlib(importlib_t *importlib, int fd)
277 {
278     MSFT_Header header;
279     MSFT_SegDir segdir;
280     int *typeinfo_offs;
281     int i;
282
283     importlib->allocated = 0;
284
285     tlb_lseek(fd, 0);
286     tlb_read(fd, &header, sizeof(header));
287
288     importlib->version = header.version;
289
290     typeinfo_offs = xmalloc(header.nrtypeinfos*sizeof(INT));
291     tlb_read(fd, typeinfo_offs, header.nrtypeinfos*sizeof(INT));
292     tlb_read(fd, &segdir, sizeof(segdir));
293
294     msft_read_guid(fd, &segdir, header.posguid, &importlib->guid);
295
296     importlib->ntypeinfos = header.nrtypeinfos;
297     importlib->importinfos = xmalloc(importlib->ntypeinfos*sizeof(importinfo_t));
298
299     for(i=0; i < importlib->ntypeinfos; i++) {
300         MSFT_TypeInfoBase base;
301         MSFT_NameIntro nameintro;
302         int len;
303
304         tlb_lseek(fd, sizeof(MSFT_Header) + header.nrtypeinfos*sizeof(INT) + sizeof(MSFT_SegDir)
305                  + typeinfo_offs[i]);
306         tlb_read(fd, &base, sizeof(base));
307
308         importlib->importinfos[i].importlib = importlib;
309         importlib->importinfos[i].flags = (base.typekind&0xf)<<24;
310         importlib->importinfos[i].offset = -1;
311         importlib->importinfos[i].id = i;
312
313         if(base.posguid != -1) {
314             importlib->importinfos[i].flags |= MSFT_IMPINFO_OFFSET_IS_GUID;
315             msft_read_guid(fd, &segdir, base.posguid, &importlib->importinfos[i].guid);
316         }
317         else memset( &importlib->importinfos[i].guid, 0, sizeof(importlib->importinfos[i].guid));
318
319         tlb_lseek(fd, segdir.pNametab.offset + base.NameOffset);
320         tlb_read(fd, &nameintro, sizeof(nameintro));
321
322         len = nameintro.namelen & 0xff;
323
324         importlib->importinfos[i].name = xmalloc(len+1);
325         tlb_read(fd, importlib->importinfos[i].name, len);
326         importlib->importinfos[i].name[len] = 0;
327     }
328
329     free(typeinfo_offs);
330 }
331
332 static void read_importlib(importlib_t *importlib)
333 {
334     int fd;
335     INT magic;
336     char *file_name;
337
338     file_name = wpp_find_include(importlib->name, NULL);
339     if(file_name) {
340         fd = open(file_name, O_RDONLY);
341         free(file_name);
342     }else {
343         fd = open(importlib->name, O_RDONLY);
344     }
345
346     if(fd < 0)
347         error("Could not open importlib %s.\n", importlib->name);
348
349     tlb_read(fd, &magic, sizeof(magic));
350
351     switch(magic) {
352     case MSFT_MAGIC:
353         read_msft_importlib(importlib, fd);
354         break;
355     default:
356         error("Wrong or unsupported typelib magic %x\n", magic);
357     };
358
359     close(fd);
360 }
361
362 void add_importlib(const char *name)
363 {
364     importlib_t *importlib;
365
366     if(!typelib) return;
367
368     for(importlib = typelib->importlibs; importlib; importlib = NEXT_LINK(importlib)) {
369         if(!strcmp(name, importlib->name))
370             return;
371     }
372
373     chat("add_importlib: %s\n", name);
374
375     importlib = xmalloc(sizeof(*importlib));
376     memset( importlib, 0, sizeof(*importlib) );
377     importlib->name = xstrdup(name);
378
379     read_importlib(importlib);
380
381     LINK(importlib, typelib->importlibs);
382     typelib->importlibs = importlib;
383 }