widl: Fix SEGVs with client and server code generation when an
[wine] / tools / widl / typegen.c
1 /*
2  * Format String Generator for IDL Compiler
3  *
4  * Copyright 2005 Eric Kohl
5  * Copyright 2005 Robert Shearman
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <string.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <signal.h>
34
35 #include "widl.h"
36 #include "utils.h"
37 #include "parser.h"
38 #include "header.h"
39 #include "windef.h"
40
41 #include "widl.h"
42 #include "typegen.h"
43
44 static int print_file(FILE *file, int indent, const char *format, ...)
45 {
46     va_list va;
47     int i, r;
48
49     if (!file) return 0;
50
51     va_start(va, format);
52     for (i = 0; i < indent; i++)
53         fprintf(file, "    ");
54     r = vfprintf(file, format, va);
55     va_end(va);
56     return r;
57 }
58
59 static size_t write_procformatstring_var(FILE *file, int indent, var_t *var, int is_return, unsigned int *type_offset)
60 {
61     size_t size;
62     if (var->ptr_level == 0 && !var->array)
63     {
64         if (is_return)
65             print_file(file, indent, "0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
66         else
67             print_file(file, indent, "0x4e,    /* FC_IN_PARAM_BASETYPE */\n");
68
69         switch(var->type->type)
70         {
71 #define CASE_BASETYPE(fctype) \
72         case RPC_##fctype: \
73             print_file(file, indent, "0x%02x,    /* " #fctype " */\n", var->type->type); \
74             size = 2; /* includes param type prefix */ \
75             break
76
77         CASE_BASETYPE(FC_BYTE);
78         CASE_BASETYPE(FC_CHAR);
79         CASE_BASETYPE(FC_WCHAR);
80         CASE_BASETYPE(FC_USHORT);
81         CASE_BASETYPE(FC_SHORT);
82         CASE_BASETYPE(FC_ULONG);
83         CASE_BASETYPE(FC_LONG);
84         CASE_BASETYPE(FC_HYPER);
85         CASE_BASETYPE(FC_IGNORE);
86         CASE_BASETYPE(FC_USMALL);
87         CASE_BASETYPE(FC_SMALL);
88         CASE_BASETYPE(FC_FLOAT);
89         CASE_BASETYPE(FC_DOUBLE);
90         CASE_BASETYPE(FC_ERROR_STATUS_T);
91 #undef CASE_BASETYPE
92         default:
93             error("Unknown/unsupported type: %s (0x%02x)\n", var->name, var->type->type);
94             size = 0;
95         }
96     }
97     else
98     {
99         int in_attr = is_attr(var->attrs, ATTR_IN);
100         int out_attr = is_attr(var->attrs, ATTR_OUT);
101
102         if (is_return)
103             print_file(file, indent, "0x52,    /* FC_RETURN_PARAM */\n");
104         else if (in_attr && out_attr)
105             print_file(file, indent, "0x50,    /* FC_IN_OUT_PARAM */\n");
106         else if (out_attr)
107             print_file(file, indent, "0x51,    /* FC_OUT_PARAM */\n");
108         else
109             print_file(file, indent, "0x4d,    /* FC_IN_PARAM */\n");
110
111         print_file(file, indent, "0x01,\n");
112         print_file(file, indent, "NdrFcShort(0x%x),\n", *type_offset);
113         size = 4; /* includes param type prefix */
114     }
115     *type_offset += get_size_typeformatstring_var(var);
116     return size;
117 }
118
119 void write_procformatstring(FILE *file, type_t *iface)
120 {
121     int indent = 0;
122     var_t *var;
123     unsigned int type_offset = 2;
124
125     print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
126     print_file(file, indent, "{\n");
127     indent++;
128     print_file(file, indent, "0,\n");
129     print_file(file, indent, "{\n");
130     indent++;
131
132     if (iface->funcs)
133     {
134         func_t *func = iface->funcs;
135         while (NEXT_LINK(func)) func = NEXT_LINK(func);
136         for (; func; func = PREV_LINK(func))
137         {
138             /* emit argument data */
139             if (func->args)
140             {
141                 var = func->args;
142                 while (NEXT_LINK(var)) var = NEXT_LINK(var);
143                 while (var)
144                 {
145                     write_procformatstring_var(file, indent, var, FALSE, &type_offset);
146                     var = PREV_LINK(var);
147                 }
148             }
149     
150             /* emit return value data */
151             var = func->def;
152             if (is_void(var->type, NULL))
153             {
154                 print_file(file, indent, "0x5b,    /* FC_END */\n");
155                 print_file(file, indent, "0x5c,    /* FC_PAD */\n");
156             }
157             else
158                 write_procformatstring_var(file, indent, var, TRUE, &type_offset);
159         }
160     }
161
162     print_file(file, indent, "0x0\n");
163     indent--;
164     print_file(file, indent, "}\n");
165     indent--;
166     print_file(file, indent, "};\n");
167     print_file(file, indent, "\n");
168 }
169
170
171 static size_t write_typeformatstring_var(FILE *file, int indent, var_t *var)
172 {
173     int ptr_level = var->ptr_level;
174
175     /* basic types don't need a type format string */
176     if (ptr_level == 0 && !var->array)
177         return 0;
178
179     if (ptr_level == 1 ||
180         (var->ptr_level == 0 && var->array && !NEXT_LINK(var->array)))
181     {
182         switch (var->type->type)
183         {
184 #define CASE_BASETYPE(fctype) \
185         case RPC_##fctype: \
186             print_file(file, indent, "0x11, 0x08,    /* FC_RP [simple_pointer] */\n"); \
187             print_file(file, indent, "0x%02x,    /* " #fctype " */\n", var->type->type); \
188             print_file(file, indent, "0x5c,          /* FC_PAD */\n"); \
189             return 4
190         CASE_BASETYPE(FC_BYTE);
191         CASE_BASETYPE(FC_CHAR);
192         CASE_BASETYPE(FC_SMALL);
193         CASE_BASETYPE(FC_USMALL);
194         CASE_BASETYPE(FC_WCHAR);
195         CASE_BASETYPE(FC_SHORT);
196         CASE_BASETYPE(FC_USHORT);
197         CASE_BASETYPE(FC_LONG);
198         CASE_BASETYPE(FC_ULONG);
199         CASE_BASETYPE(FC_FLOAT);
200         CASE_BASETYPE(FC_HYPER);
201         CASE_BASETYPE(FC_DOUBLE);
202         CASE_BASETYPE(FC_ENUM16);
203         CASE_BASETYPE(FC_ENUM32);
204         CASE_BASETYPE(FC_IGNORE);
205         CASE_BASETYPE(FC_ERROR_STATUS_T);
206         default:
207             error("write_typeformatstring_var: Unknown/unsupported type: %s (0x%02x)\n", var->name, var->type->type);
208         }
209     }
210     error("write_typeformatstring_var: Pointer level %d not supported for variable %s\n", ptr_level, var->name);
211     return 0;
212 }
213
214
215 void write_typeformatstring(FILE *file, type_t *iface)
216 {
217     int indent = 0;
218     var_t *var;
219
220     print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
221     print_file(file, indent, "{\n");
222     indent++;
223     print_file(file, indent, "0,\n");
224     print_file(file, indent, "{\n");
225     indent++;
226     print_file(file, indent, "NdrFcShort(0x0),\n");
227
228     if (iface->funcs)
229     {
230         func_t *func = iface->funcs;
231         while (NEXT_LINK(func)) func = NEXT_LINK(func);
232         for (; func; func = PREV_LINK(func))
233         {
234             if (func->args)
235             {
236                 var = func->args;
237                 while (NEXT_LINK(var)) var = NEXT_LINK(var);
238                 while (var)
239                 {
240                     write_typeformatstring_var(file, indent, var);
241                     var = PREV_LINK(var);
242                 }
243             }
244         }
245     }
246
247     print_file(file, indent, "0x0\n");
248     indent--;
249     print_file(file, indent, "}\n");
250     indent--;
251     print_file(file, indent, "};\n");
252     print_file(file, indent, "\n");
253 }
254
255
256 unsigned int get_required_buffer_size(type_t *type)
257 {
258     switch(type->type)
259     {
260         case RPC_FC_BYTE:
261         case RPC_FC_CHAR:
262         case RPC_FC_WCHAR:
263         case RPC_FC_USHORT:
264         case RPC_FC_SHORT:
265         case RPC_FC_USMALL:
266         case RPC_FC_SMALL:
267         case RPC_FC_ULONG:
268         case RPC_FC_LONG:
269         case RPC_FC_FLOAT:
270         case RPC_FC_IGNORE:
271         case RPC_FC_ERROR_STATUS_T:
272             return 4;
273
274         case RPC_FC_HYPER:
275         case RPC_FC_DOUBLE:
276             return 8;
277
278         default:
279             error("Unknown/unsupported type: %s (0x%02x)\n", type->name, type->type);
280             return 0;
281     }
282 }
283
284 void marshall_arguments(FILE *file, int indent, func_t *func)
285 {
286     unsigned int alignment;
287     unsigned int size;
288     unsigned int last_size = 0;
289     var_t *var;
290
291     if (!func->args)
292         return;
293
294     var = func->args;
295     while (NEXT_LINK(var)) var = NEXT_LINK(var);
296     while (var)
297     {
298         alignment = 0;
299         switch (var->type->type)
300         {
301         case RPC_FC_BYTE:
302         case RPC_FC_CHAR:
303         case RPC_FC_SMALL:
304         case RPC_FC_USMALL:
305             size = 1;
306             alignment = 0;
307             break;
308
309         case RPC_FC_WCHAR:
310         case RPC_FC_USHORT:
311         case RPC_FC_SHORT:
312             size = 2;
313             if (last_size != 0 && last_size < 2)
314                 alignment = (2 - last_size);
315             break;
316
317         case RPC_FC_ULONG:
318         case RPC_FC_LONG:
319         case RPC_FC_FLOAT:
320         case RPC_FC_ERROR_STATUS_T:
321             size = 4;
322             if (last_size != 0 && last_size < 4)
323                 alignment = (4 - last_size);
324             break;
325
326         case RPC_FC_HYPER:
327         case RPC_FC_DOUBLE:
328             size = 8;
329             if (last_size != 0 && last_size < 4)
330                 alignment = (4 - last_size);
331             break;
332
333         default:
334             size = 0;
335             error("Unknown/unsupported type: %s (0x%02x)\n", var->name, var->type->type);
336         }
337
338         if (alignment != 0)
339             print_file(file, indent, "_StubMsg.Buffer += %u;\n", alignment);
340
341         print_file(file, indent, "*(");
342         write_type(file, var->type, var, var->tname);
343         fprintf(file, " *)_StubMsg.Buffer = ");
344         write_name(file, var);
345         fprintf(file, ";\n");
346         fprintf(file, "_StubMsg.Buffer += sizeof(");
347         write_type(file, var->type, var, var->tname);
348         fprintf(file, ");\n");
349         fprintf(file, "\n");
350
351         last_size = size;
352
353         var = PREV_LINK(var);
354     }
355 }
356
357 void unmarshall_arguments(FILE *file, int indent, func_t *func)
358 {
359     unsigned int alignment;
360     unsigned int size;
361     unsigned int last_size = 0;
362     var_t *var;
363
364     if (!func->args)
365         return;
366
367     var = func->args;
368     while (NEXT_LINK(var)) var = NEXT_LINK(var);
369     while (var)
370     {
371         alignment = 0;
372         switch (var->type->type)
373         {
374         case RPC_FC_BYTE:
375         case RPC_FC_CHAR:
376         case RPC_FC_SMALL:
377         case RPC_FC_USMALL:
378             size = 1;
379             alignment = 0;
380             break;
381
382         case RPC_FC_WCHAR:
383         case RPC_FC_USHORT:
384         case RPC_FC_SHORT:
385             size = 2;
386             if (last_size != 0 && last_size < 2)
387                 alignment = (2 - last_size);
388             break;
389
390         case RPC_FC_ULONG:
391         case RPC_FC_LONG:
392         case RPC_FC_FLOAT:
393         case RPC_FC_ERROR_STATUS_T:
394             size = 4;
395             if (last_size != 0 && last_size < 4)
396                 alignment = (4 - last_size);
397             break;
398
399         case RPC_FC_HYPER:
400         case RPC_FC_DOUBLE:
401             size = 8;
402             if (last_size != 0 && last_size < 4)
403                 alignment = (4 - last_size);
404             break;
405
406         default:
407             size = 0;
408             error("Unknown/unsupported type: %s (0x%02x)\n", var->name, var->type->type);
409         }
410
411         if (alignment != 0)
412             print_file(file, indent, "_StubMsg.Buffer += %u;\n", alignment);
413
414         print_file(file, indent, "");
415         write_name(file, var);
416         fprintf(file, " = *(");
417         write_type(file, var->type, var, var->tname);
418         fprintf(file, " *)_StubMsg.Buffer;\n");
419         fprintf(file, "_StubMsg.Buffer += sizeof(");
420         write_type(file, var->type, var, var->tname);
421         fprintf(file, ");\n");
422         fprintf(file, "\n");
423
424         last_size = size;
425
426         var = PREV_LINK(var);
427     }
428 }
429
430
431 size_t get_size_procformatstring_var(var_t *var)
432 {
433     unsigned int type_offset = 2;
434     return write_procformatstring_var(NULL, 0, var, FALSE, &type_offset);
435 }
436
437
438 size_t get_size_typeformatstring_var(var_t *var)
439 {
440     return write_typeformatstring_var(NULL, 0, var);
441 }