widl: Handle marshaling and unmarshaling structures.
[wine/wine64.git] / tools / widl / typegen.c
blobf1f791dc77f5b2951833b28140e8188a7826af97
1 /*
2 * Format String Generator for IDL Compiler
4 * Copyright 2005 Eric Kohl
5 * Copyright 2005 Robert Shearman
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
22 #include "config.h"
23 #include "wine/port.h"
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>
35 #include "widl.h"
36 #include "utils.h"
37 #include "parser.h"
38 #include "header.h"
39 #include "windef.h"
41 #include "widl.h"
42 #include "typegen.h"
44 static int print_file(FILE *file, int indent, const char *format, ...)
46 va_list va;
47 int i, r;
49 if (!file) return 0;
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;
59 static size_t write_procformatstring_var(FILE *file, int indent, var_t *var, int is_return, unsigned int *type_offset)
61 size_t size;
62 if (var->ptr_level == 0 && !var->array)
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");
69 switch(var->type->type)
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
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;
97 else
99 int in_attr = is_attr(var->attrs, ATTR_IN);
100 int out_attr = is_attr(var->attrs, ATTR_OUT);
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");
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 */
115 *type_offset += get_size_typeformatstring_var(var);
116 return size;
119 void write_procformatstring(FILE *file, type_t *iface)
121 int indent = 0;
122 var_t *var;
123 unsigned int type_offset = 2;
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++;
132 if (iface->funcs)
134 func_t *func = iface->funcs;
135 while (NEXT_LINK(func)) func = NEXT_LINK(func);
136 for (; func; func = PREV_LINK(func))
138 /* emit argument data */
139 if (func->args)
141 var = func->args;
142 while (NEXT_LINK(var)) var = NEXT_LINK(var);
143 while (var)
145 write_procformatstring_var(file, indent, var, FALSE, &type_offset);
146 var = PREV_LINK(var);
150 /* emit return value data */
151 var = func->def;
152 if (is_void(var->type, NULL))
154 print_file(file, indent, "0x5b, /* FC_END */\n");
155 print_file(file, indent, "0x5c, /* FC_PAD */\n");
157 else
158 write_procformatstring_var(file, indent, var, TRUE, &type_offset);
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");
171 static size_t write_typeformatstring_var(FILE *file, int indent, var_t *var)
173 int ptr_level = var->ptr_level;
175 /* basic types don't need a type format string */
176 if (ptr_level == 0 && !var->array)
177 return 0;
179 if (ptr_level == 1 ||
180 (var->ptr_level == 0 && var->array && !NEXT_LINK(var->array)))
182 switch (var->type->type)
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);
210 error("write_typeformatstring_var: Pointer level %d not supported for variable %s\n", ptr_level, var->name);
211 return 0;
215 void write_typeformatstring(FILE *file, type_t *iface)
217 int indent = 0;
218 var_t *var;
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");
228 if (iface->funcs)
230 func_t *func = iface->funcs;
231 while (NEXT_LINK(func)) func = NEXT_LINK(func);
232 for (; func; func = PREV_LINK(func))
234 if (func->args)
236 var = func->args;
237 while (NEXT_LINK(var)) var = NEXT_LINK(var);
238 while (var)
240 write_typeformatstring_var(file, indent, var);
241 var = PREV_LINK(var);
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");
256 unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment)
258 *alignment = 0;
259 if (var->ptr_level == 0 && !var->array)
261 switch (var->type->type)
263 case RPC_FC_BYTE:
264 case RPC_FC_CHAR:
265 case RPC_FC_USMALL:
266 case RPC_FC_SMALL:
267 return 1;
269 case RPC_FC_WCHAR:
270 case RPC_FC_USHORT:
271 case RPC_FC_SHORT:
272 *alignment = 2;
273 return 2;
275 case RPC_FC_ULONG:
276 case RPC_FC_LONG:
277 case RPC_FC_FLOAT:
278 case RPC_FC_ERROR_STATUS_T:
279 *alignment = 4;
280 return 4;
282 case RPC_FC_HYPER:
283 case RPC_FC_DOUBLE:
284 *alignment = 8;
285 return 8;
287 default:
288 error("get_required_buffer_size: Unknown/unsupported type: %s (0x%02x)\n", var->name, var->type->type);
289 return 0;
292 return 0;
295 void marshall_arguments(FILE *file, int indent, func_t *func,
296 unsigned int *type_offset, enum pass pass)
298 unsigned int last_size = 0;
299 var_t *var;
301 if (!func->args)
302 return;
304 var = func->args;
305 while (NEXT_LINK(var)) var = NEXT_LINK(var);
306 for (; var; *type_offset += get_size_typeformatstring_var(var), var = PREV_LINK(var))
308 int in_attr = is_attr(var->attrs, ATTR_IN);
309 int out_attr = is_attr(var->attrs, ATTR_OUT);
311 if (!in_attr && !out_attr)
312 in_attr = 1;
314 switch (pass)
316 case PASS_IN:
317 if (!in_attr)
318 continue;
319 break;
320 case PASS_OUT:
321 if (!out_attr)
322 continue;
323 break;
324 case PASS_RETURN:
325 break;
328 if (var->ptr_level == 0 && !var->array)
330 unsigned int size;
331 unsigned int alignment = 0;
332 switch (var->type->type)
334 case RPC_FC_BYTE:
335 case RPC_FC_CHAR:
336 case RPC_FC_SMALL:
337 case RPC_FC_USMALL:
338 size = 1;
339 alignment = 0;
340 break;
342 case RPC_FC_WCHAR:
343 case RPC_FC_USHORT:
344 case RPC_FC_SHORT:
345 size = 2;
346 if (last_size != 0 && last_size < 2)
347 alignment = (2 - last_size);
348 break;
350 case RPC_FC_ULONG:
351 case RPC_FC_LONG:
352 case RPC_FC_FLOAT:
353 case RPC_FC_ERROR_STATUS_T:
354 size = 4;
355 if (last_size != 0 && last_size < 4)
356 alignment = (4 - last_size);
357 break;
359 case RPC_FC_HYPER:
360 case RPC_FC_DOUBLE:
361 size = 8;
362 if (last_size != 0 && last_size < 4)
363 alignment = (4 - last_size);
364 break;
366 default:
367 error("marshall_arguments: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, var->type->type);
368 size = 0;
371 if (alignment != 0)
372 print_file(file, indent, "_StubMsg.Buffer += %u;\n", alignment);
374 print_file(file, indent, "*(");
375 write_type(file, var->type, var, var->tname);
376 fprintf(file, " *)_StubMsg.Buffer = ");
377 write_name(file, var);
378 fprintf(file, ";\n");
379 fprintf(file, "_StubMsg.Buffer += sizeof(");
380 write_type(file, var->type, var, var->tname);
381 fprintf(file, ");\n");
382 fprintf(file, "\n");
384 last_size = size;
386 else if ((var->ptr_level == 1 && !var->array) ||
387 (var->ptr_level == 0 && var->array))
389 if (is_attr(var->attrs, ATTR_STRING))
391 switch (var->type->type)
393 case RPC_FC_CHAR:
394 case RPC_FC_WCHAR:
395 print_file(file, indent,
396 "NdrConformantStringMarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
397 var->name, *type_offset);
398 break;
399 default:
400 error("marshall_arguments: Unsupported [string] type: %s (0x%02x, ptr_level: 1)\n", var->name, var->type->type);
403 else if (var->array)
405 const expr_t *length_is = get_attrp(var->attrs, ATTR_LENGTHIS);
406 const expr_t *size_is = get_attrp(var->attrs, ATTR_SIZEIS);
407 const char *array_type;
408 int has_length = length_is && (length_is->type != EXPR_VOID);
409 int has_size = size_is && (size_is->type != EXPR_VOID) && !var->array->is_const;
411 if (NEXT_LINK(var->array)) /* multi-dimensional array */
412 array_type = "ComplexArray";
413 else
415 if (!has_length && !has_size)
416 array_type = "FixedArray";
417 else if (has_length && !has_size)
418 array_type = "VaryingArray";
419 else if (!has_length && has_size)
420 array_type = "ConformantArray";
421 else
422 array_type = "ConformantVaryingArray";
425 print_file(file, indent,
426 "Ndr%sMarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
427 array_type, var->name, *type_offset);
429 else
431 const char *ndrtype;
433 switch (var->type->type)
435 case RPC_FC_STRUCT:
436 ndrtype = "SimpleStruct";
437 break;
438 case RPC_FC_CSTRUCT:
439 case RPC_FC_CPSTRUCT:
440 ndrtype = "ConformantStruct";
441 break;
442 case RPC_FC_CVSTRUCT:
443 ndrtype = "ConformantVaryingStruct";
444 break;
445 case RPC_FC_BOGUS_STRUCT:
446 ndrtype = "ComplexStruct";
447 break;
448 default:
449 error("marshall_arguments: Unsupported type: %s (0x%02x, ptr_level: %d)\n",
450 var->name, var->type->type, var->ptr_level);
451 ndrtype = NULL;
454 print_file(file, indent,
455 "Ndr%sMarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
456 ndrtype, var->name, *type_offset);
458 last_size = 1;
460 else
462 error("marshall_arguments: Pointer level %d not supported for variable %s\n", var->ptr_level, var->name);
463 last_size = 1;
465 fprintf(file, "\n");
469 void unmarshall_arguments(FILE *file, int indent, func_t *func,
470 unsigned int *type_offset, enum pass pass)
472 unsigned int last_size = 0;
473 var_t *var;
475 if (!func->args)
476 return;
478 var = func->args;
479 while (NEXT_LINK(var)) var = NEXT_LINK(var);
480 for (; var; *type_offset += get_size_typeformatstring_var(var), var = PREV_LINK(var))
482 int in_attr = is_attr(var->attrs, ATTR_IN);
483 int out_attr = is_attr(var->attrs, ATTR_OUT);
485 if (!in_attr && !out_attr)
486 in_attr = 1;
488 switch (pass)
490 case PASS_IN:
491 if (!in_attr)
492 continue;
493 break;
494 case PASS_OUT:
495 if (!out_attr)
496 continue;
497 break;
498 case PASS_RETURN:
499 break;
502 if (var->ptr_level == 0 && !var->array)
504 unsigned int size;
505 unsigned int alignment = 0;
507 switch (var->type->type)
509 case RPC_FC_BYTE:
510 case RPC_FC_CHAR:
511 case RPC_FC_SMALL:
512 case RPC_FC_USMALL:
513 size = 1;
514 alignment = 0;
515 break;
517 case RPC_FC_WCHAR:
518 case RPC_FC_USHORT:
519 case RPC_FC_SHORT:
520 size = 2;
521 if (last_size != 0 && last_size < 2)
522 alignment = (2 - last_size);
523 break;
525 case RPC_FC_ULONG:
526 case RPC_FC_LONG:
527 case RPC_FC_FLOAT:
528 case RPC_FC_ERROR_STATUS_T:
529 size = 4;
530 if (last_size != 0 && last_size < 4)
531 alignment = (4 - last_size);
532 break;
534 case RPC_FC_HYPER:
535 case RPC_FC_DOUBLE:
536 size = 8;
537 if (last_size != 0 && last_size < 4)
538 alignment = (4 - last_size);
539 break;
541 default:
542 error("unmarshall_arguments: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, var->type->type);
543 size = 0;
546 if (alignment != 0)
547 print_file(file, indent, "_StubMsg.Buffer += %u;\n", alignment);
549 print_file(file, indent, "");
550 write_name(file, var);
551 fprintf(file, " = *(");
552 write_type(file, var->type, var, var->tname);
553 fprintf(file, " *)_StubMsg.Buffer;\n");
554 fprintf(file, "_StubMsg.Buffer += sizeof(");
555 write_type(file, var->type, var, var->tname);
556 fprintf(file, ");\n");
557 fprintf(file, "\n");
559 last_size = size;
561 else if ((var->ptr_level == 1 && !var->array) ||
562 (var->ptr_level == 0 && var->array))
564 if (is_attr(var->attrs, ATTR_STRING))
566 switch (var->type->type)
568 case RPC_FC_CHAR:
569 case RPC_FC_WCHAR:
570 print_file(file, indent,
571 "NdrConformantStringUnmarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d], 0);\n",
572 var->name, *type_offset);
573 break;
574 default:
575 error("unmarshall_arguments: Unsupported [string] type: %s (0x%02x, ptr_level: %d)\n",
576 var->name, var->type->type, var->ptr_level);
579 else if (var->array)
581 const expr_t *length_is = get_attrp(var->attrs, ATTR_LENGTHIS);
582 const expr_t *size_is = get_attrp(var->attrs, ATTR_SIZEIS);
583 const char *array_type;
584 int has_length = length_is && (length_is->type != EXPR_VOID);
585 int has_size = size_is && (size_is->type != EXPR_VOID) && !var->array->is_const;
587 if (NEXT_LINK(var->array)) /* multi-dimensional array */
588 array_type = "ComplexArray";
589 else
591 if (!has_length && !has_size)
592 array_type = "FixedArray";
593 else if (has_length && !has_size)
594 array_type = "VaryingArray";
595 else if (!has_length && has_size)
596 array_type = "ConformantArray";
597 else
598 array_type = "ConformantVaryingArray";
601 print_file(file, indent,
602 "Ndr%sUnmarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d], 0);\n",
603 array_type, var->name, *type_offset);
605 else
607 const char *ndrtype;
609 switch (var->type->type)
611 case RPC_FC_STRUCT:
612 ndrtype = "SimpleStruct";
613 break;
614 case RPC_FC_CSTRUCT:
615 case RPC_FC_CPSTRUCT:
616 ndrtype = "ConformantStruct";
617 break;
618 case RPC_FC_CVSTRUCT:
619 ndrtype = "ConformantVaryingStruct";
620 break;
621 case RPC_FC_BOGUS_STRUCT:
622 ndrtype = "ComplexStruct";
623 break;
624 default:
625 error("unmarshall_arguments: Unsupported type: %s (0x%02x, ptr_level: %d)\n",
626 var->name, var->type->type, var->ptr_level);
627 ndrtype = NULL;
630 print_file(file, indent,
631 "Ndr%sUnmarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d], 0);\n",
632 ndrtype, var->name, *type_offset);
634 last_size = 1;
636 else
638 error("unmarshall_arguments: Pointer level %d not supported for variable %s\n", var->ptr_level, var->name);
639 last_size = 1;
641 fprintf(file, "\n");
646 size_t get_size_procformatstring_var(var_t *var)
648 unsigned int type_offset = 2;
649 return write_procformatstring_var(NULL, 0, var, FALSE, &type_offset);
653 size_t get_size_typeformatstring_var(var_t *var)
655 return write_typeformatstring_var(NULL, 0, var);