widl: Allow types that reference themselves.
[wine/testsucceed.git] / tools / widl / typegen.c
blobc6024e25d823e33f31c5438c0ce3d9957f0b5f31
1 /*
2 * Format String Generator for IDL Compiler
4 * Copyright 2005-2006 Eric Kohl
5 * Copyright 2005-2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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>
34 #include <limits.h>
36 #include "widl.h"
37 #include "utils.h"
38 #include "parser.h"
39 #include "header.h"
40 #include "windef.h"
41 #include "wine/list.h"
43 #include "widl.h"
44 #include "typegen.h"
46 static const func_t *current_func;
47 static const type_t *current_structure;
49 /* name of the structure variable for structure callbacks */
50 #define STRUCT_EXPR_EVAL_VAR "pS"
52 static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
54 struct expr_eval_routine
56 struct list entry;
57 const type_t *structure;
58 size_t structure_size;
59 const expr_t *expr;
62 static size_t type_memsize(const type_t *t, const array_dims_t *array, unsigned int *align);
63 static size_t fields_memsize(const var_list_t *fields, unsigned int *align);
64 static size_t write_struct_tfs(FILE *file, type_t *type, const char *name, unsigned int *tfsoff);
65 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
66 const char *name, const array_dims_t *array, int level,
67 unsigned int *tfsoff);
69 const char *string_of_type(unsigned char type)
71 switch (type)
73 case RPC_FC_BYTE: return "FC_BYTE";
74 case RPC_FC_CHAR: return "FC_CHAR";
75 case RPC_FC_SMALL: return "FC_SMALL";
76 case RPC_FC_USMALL: return "FC_USMALL";
77 case RPC_FC_WCHAR: return "FC_WCHAR";
78 case RPC_FC_SHORT: return "FC_SHORT";
79 case RPC_FC_USHORT: return "FC_USHORT";
80 case RPC_FC_LONG: return "FC_LONG";
81 case RPC_FC_ULONG: return "FC_ULONG";
82 case RPC_FC_FLOAT: return "FC_FLOAT";
83 case RPC_FC_HYPER: return "FC_HYPER";
84 case RPC_FC_DOUBLE: return "FC_DOUBLE";
85 case RPC_FC_ENUM16: return "FC_ENUM16";
86 case RPC_FC_ENUM32: return "FC_ENUM32";
87 case RPC_FC_IGNORE: return "FC_IGNORE";
88 case RPC_FC_ERROR_STATUS_T: return "FC_ERROR_STATUS_T";
89 case RPC_FC_RP: return "FC_RP";
90 case RPC_FC_UP: return "FC_UP";
91 case RPC_FC_OP: return "FC_OP";
92 case RPC_FC_FP: return "FC_FP";
93 case RPC_FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION";
94 case RPC_FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION";
95 case RPC_FC_STRUCT: return "FC_STRUCT";
96 case RPC_FC_PSTRUCT: return "FC_PSTRUCT";
97 case RPC_FC_CSTRUCT: return "FC_CSTRUCT";
98 case RPC_FC_CPSTRUCT: return "FC_CPSTRUCT";
99 case RPC_FC_CVSTRUCT: return "FC_CVSTRUCT";
100 case RPC_FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT";
101 default:
102 error("string_of_type: unknown type 0x%02x\n", type);
103 return NULL;
107 static int is_struct(unsigned char type)
109 switch (type)
111 case RPC_FC_STRUCT:
112 case RPC_FC_PSTRUCT:
113 case RPC_FC_CSTRUCT:
114 case RPC_FC_CPSTRUCT:
115 case RPC_FC_CVSTRUCT:
116 case RPC_FC_BOGUS_STRUCT:
117 return 1;
118 default:
119 return 0;
123 static int is_union(unsigned char type)
125 switch (type)
127 case RPC_FC_ENCAPSULATED_UNION:
128 case RPC_FC_NON_ENCAPSULATED_UNION:
129 return 1;
130 default:
131 return 0;
135 static void update_tfsoff(type_t *type, unsigned int offset, FILE *file)
137 type->typestring_offset = offset;
138 if (file) type->tfswrite = FALSE;
141 static void guard_rec(type_t *type)
143 /* types that contain references to themselves (like a linked list),
144 need to be shielded from infinite recursion when writing embedded
145 types */
146 if (type->typestring_offset)
147 type->tfswrite = FALSE;
148 else
149 type->typestring_offset = 1;
152 static int is_embedded_complex(const type_t *type)
154 return is_struct(type->type) || is_union(type->type);
157 static long field_offset(const type_t *strct, const char *name, var_t **pfield)
159 long offset = 0;
160 var_list_t *fields = strct->fields;
161 var_t *f;
163 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
165 unsigned int align = 0;
167 if (f->name != NULL && strcmp(name, f->name) == 0)
169 if (pfield) *pfield = f;
170 return offset;
172 else
174 /* FIXME: handle possible padding */
175 offset += type_memsize(f->type, f->array, &align);
179 if (pfield) *pfield = NULL;
180 return -1;
183 static int compare_expr(const expr_t *a, const expr_t *b)
185 int ret;
187 if (a->type != b->type)
188 return a->type - b->type;
190 switch (a->type)
192 case EXPR_NUM:
193 case EXPR_HEXNUM:
194 case EXPR_TRUEFALSE:
195 return a->u.lval - b->u.lval;
196 case EXPR_IDENTIFIER:
197 return strcmp(a->u.sval, b->u.sval);
198 case EXPR_COND:
199 ret = compare_expr(a->ref, b->ref);
200 if (ret != 0)
201 return ret;
202 ret = compare_expr(a->u.ext, b->u.ext);
203 if (ret != 0)
204 return ret;
205 return compare_expr(a->ext2, b->ext2);
206 case EXPR_OR:
207 case EXPR_AND:
208 case EXPR_ADD:
209 case EXPR_SUB:
210 case EXPR_MUL:
211 case EXPR_DIV:
212 case EXPR_SHL:
213 case EXPR_SHR:
214 ret = compare_expr(a->ref, b->ref);
215 if (ret != 0)
216 return ret;
217 return compare_expr(a->u.ext, b->u.ext);
218 case EXPR_NOT:
219 case EXPR_NEG:
220 case EXPR_PPTR:
221 case EXPR_CAST:
222 case EXPR_SIZEOF:
223 return compare_expr(a->ref, b->ref);
224 case EXPR_VOID:
225 return 0;
227 return -1;
230 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
231 do { \
232 if (file) \
233 fprintf(file, "/* %2u */\n", typestring_offset); \
234 print_file((file), 2, "0x%02x, /* " #fctype " */\n", RPC_##fctype); \
236 while (0)
238 static int print_file(FILE *file, int indent, const char *format, ...)
240 va_list va;
241 int i, r;
243 if (!file) return 0;
245 va_start(va, format);
246 for (i = 0; i < indent; i++)
247 fprintf(file, " ");
248 r = vfprintf(file, format, va);
249 va_end(va);
250 return r;
253 static void write_formatdesc(FILE *f, int indent, const char *str)
255 print_file(f, indent, "typedef struct _MIDL_%s_FORMAT_STRING\n", str);
256 print_file(f, indent, "{\n");
257 print_file(f, indent + 1, "short Pad;\n");
258 print_file(f, indent + 1, "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str);
259 print_file(f, indent, "} MIDL_%s_FORMAT_STRING;\n", str);
260 print_file(f, indent, "\n");
263 void write_formatstringsdecl(FILE *f, int indent, ifref_list_t *ifaces, int for_objects)
265 print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n",
266 get_size_typeformatstring(ifaces, for_objects));
268 print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n",
269 get_size_procformatstring(ifaces, for_objects));
271 fprintf(f, "\n");
272 write_formatdesc(f, indent, "TYPE");
273 write_formatdesc(f, indent, "PROC");
274 fprintf(f, "\n");
275 print_file(f, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n");
276 print_file(f, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n");
277 print_file(f, indent, "\n");
280 static int is_user_derived(const var_t *v)
282 const type_t *type = v->type;
284 if (v->attrs && is_attr( v->attrs, ATTR_WIREMARSHAL )) return 1;
286 while (type)
288 if (type->attrs && is_attr( type->attrs, ATTR_WIREMARSHAL )) return 1;
289 type = type->ref;
291 return 0;
294 static inline int is_base_type(unsigned char type)
296 switch (type)
298 case RPC_FC_BYTE:
299 case RPC_FC_CHAR:
300 case RPC_FC_USMALL:
301 case RPC_FC_SMALL:
302 case RPC_FC_WCHAR:
303 case RPC_FC_USHORT:
304 case RPC_FC_SHORT:
305 case RPC_FC_ULONG:
306 case RPC_FC_LONG:
307 case RPC_FC_HYPER:
308 case RPC_FC_IGNORE:
309 case RPC_FC_FLOAT:
310 case RPC_FC_DOUBLE:
311 case RPC_FC_ENUM16:
312 case RPC_FC_ENUM32:
313 case RPC_FC_ERROR_STATUS_T:
314 case RPC_FC_BIND_PRIMITIVE:
315 return TRUE;
317 default:
318 return FALSE;
322 static size_t write_procformatstring_var(FILE *file, int indent,
323 const var_t *var, int is_return)
325 size_t size;
326 const type_t *type = var->type;
328 int is_in = is_attr(var->attrs, ATTR_IN);
329 int is_out = is_attr(var->attrs, ATTR_OUT);
331 if (!is_in && !is_out) is_in = TRUE;
333 if (!var->array && is_base_type(type->type))
335 if (is_return)
336 print_file(file, indent, "0x53, /* FC_RETURN_PARAM_BASETYPE */\n");
337 else
338 print_file(file, indent, "0x4e, /* FC_IN_PARAM_BASETYPE */\n");
340 if (is_base_type(type->type))
342 print_file(file, indent, "0x%02x, /* %s */\n", type->type, string_of_type(type->type));
343 size = 2; /* includes param type prefix */
345 else if (type->type == RPC_FC_BIND_PRIMITIVE)
347 print_file(file, indent, "0x%02x, /* FC_IGNORE */\n", RPC_FC_IGNORE);
348 size = 2; /* includes param type prefix */
350 else
352 error("Unknown/unsupported type: %s (0x%02x)\n", var->name, type->type);
353 size = 0;
356 else
358 if (is_return)
359 print_file(file, indent, "0x52, /* FC_RETURN_PARAM */\n");
360 else if (is_in && is_out)
361 print_file(file, indent, "0x50, /* FC_IN_OUT_PARAM */\n");
362 else if (is_out)
363 print_file(file, indent, "0x51, /* FC_OUT_PARAM */\n");
364 else
365 print_file(file, indent, "0x4d, /* FC_IN_PARAM */\n");
367 print_file(file, indent, "0x01,\n");
368 print_file(file, indent, "NdrFcShort(0x%x),\n", type->typestring_offset);
369 size = 4; /* includes param type prefix */
371 return size;
374 void write_procformatstring(FILE *file, const ifref_list_t *ifaces, int for_objects)
376 const ifref_t *iface;
377 int indent = 0;
378 const var_t *var;
380 print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
381 print_file(file, indent, "{\n");
382 indent++;
383 print_file(file, indent, "0,\n");
384 print_file(file, indent, "{\n");
385 indent++;
387 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
389 if (for_objects != is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
390 continue;
392 if (iface->iface->funcs)
394 const func_t *func;
395 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
397 if (is_local(func->def->attrs)) continue;
398 /* emit argument data */
399 if (func->args)
401 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
402 write_procformatstring_var(file, indent, var, FALSE);
405 /* emit return value data */
406 var = func->def;
407 if (is_void(var->type))
409 print_file(file, indent, "0x5b, /* FC_END */\n");
410 print_file(file, indent, "0x5c, /* FC_PAD */\n");
412 else
413 write_procformatstring_var(file, indent, var, TRUE);
418 print_file(file, indent, "0x0\n");
419 indent--;
420 print_file(file, indent, "}\n");
421 indent--;
422 print_file(file, indent, "};\n");
423 print_file(file, indent, "\n");
426 static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
428 if (is_base_type(type->type))
430 print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
431 *typestring_offset += 1;
432 return 1;
435 return 0;
438 /* write conformance / variance descriptor */
439 static size_t write_conf_or_var_desc(FILE *file, const func_t *func, const type_t *structure, const expr_list_t *expr_list)
441 unsigned char operator_type = 0;
442 const char *operator_string = "no operators";
443 const expr_t *expr, *subexpr;
444 unsigned char correlation_type;
446 if (!file) return 4; /* optimisation for sizing pass */
448 if (list_count(expr_list) > 1)
449 error("write_conf_or_var_desc: multi-dimensional arrays not supported yet\n");
451 expr = subexpr = LIST_ENTRY( list_head(expr_list), const expr_t, entry );
453 if (expr->is_const)
455 if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
456 error("write_conf_or_var_desc: constant value %ld is greater than "
457 "the maximum constant size of %d\n", expr->cval,
458 UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
460 print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n",
461 RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
462 print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX);
463 print_file(file, 2, "NdrFcShort(0x%x),\n", expr->cval & USHRT_MAX);
465 return 4;
468 switch (subexpr->type)
470 case EXPR_PPTR:
471 subexpr = subexpr->ref;
472 operator_type = RPC_FC_DEREFERENCE;
473 operator_string = "FC_DEREFERENCE";
474 break;
475 case EXPR_DIV:
476 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
478 subexpr = subexpr->ref;
479 operator_type = RPC_FC_DIV_2;
480 operator_string = "FC_DIV_2";
482 break;
483 case EXPR_MUL:
484 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
486 subexpr = subexpr->ref;
487 operator_type = RPC_FC_MULT_2;
488 operator_string = "FC_MULT_2";
490 break;
491 case EXPR_SUB:
492 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
494 subexpr = subexpr->ref;
495 operator_type = RPC_FC_SUB_1;
496 operator_string = "FC_SUB_1";
498 break;
499 case EXPR_ADD:
500 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
502 subexpr = subexpr->ref;
503 operator_type = RPC_FC_ADD_1;
504 operator_string = "FC_ADD_1";
506 break;
507 default:
508 break;
511 if (subexpr->type == EXPR_IDENTIFIER)
513 const type_t *correlation_variable = NULL;
514 unsigned char correlation_variable_type;
515 unsigned char param_type = 0;
516 const char *param_type_string = NULL;
517 size_t offset;
519 if (structure)
521 const var_t *var;
523 offset = 0;
524 if (structure->fields) LIST_FOR_EACH_ENTRY( var, structure->fields, const var_t, entry )
526 unsigned int align = 0;
527 offset -= type_memsize(var->type, var->array, &align);
528 /* FIXME: take alignment into account */
529 if (!strcmp(var->name, subexpr->u.sval))
531 correlation_variable = var->type;
532 break;
535 if (!correlation_variable)
536 error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
537 subexpr->u.sval);
539 correlation_type = RPC_FC_NORMAL_CONFORMANCE;
541 else
543 const var_t *var;
545 offset = sizeof(void *);
546 if (func->args) LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
548 if (!strcmp(var->name, subexpr->u.sval))
550 correlation_variable = var->type;
551 break;
553 /* FIXME: not all stack variables are sizeof(void *) */
554 offset += sizeof(void *);
556 if (!correlation_variable)
557 error("write_conf_or_var_desc: couldn't find variable %s in function\n",
558 subexpr->u.sval);
560 correlation_type = RPC_FC_TOP_LEVEL_CONFORMANCE;
563 correlation_variable_type = correlation_variable->type;
565 switch (correlation_variable_type)
567 case RPC_FC_CHAR:
568 case RPC_FC_SMALL:
569 param_type = RPC_FC_SMALL;
570 param_type_string = "FC_SMALL";
571 break;
572 case RPC_FC_BYTE:
573 case RPC_FC_USMALL:
574 param_type = RPC_FC_USMALL;
575 param_type_string = "FC_USMALL";
576 break;
577 case RPC_FC_WCHAR:
578 case RPC_FC_SHORT:
579 param_type = RPC_FC_SHORT;
580 param_type_string = "FC_SHORT";
581 break;
582 case RPC_FC_USHORT:
583 param_type = RPC_FC_USHORT;
584 param_type_string = "FC_USHORT";
585 break;
586 case RPC_FC_LONG:
587 param_type = RPC_FC_LONG;
588 param_type_string = "FC_LONG";
589 break;
590 case RPC_FC_ULONG:
591 param_type = RPC_FC_ULONG;
592 param_type_string = "FC_ULONG";
593 break;
594 case RPC_FC_RP:
595 case RPC_FC_UP:
596 case RPC_FC_OP:
597 case RPC_FC_FP:
598 if (sizeof(void *) == 4) /* FIXME */
600 param_type = RPC_FC_LONG;
601 param_type_string = "FC_LONG";
603 else
605 param_type = RPC_FC_HYPER;
606 param_type_string = "FC_HYPER";
608 break;
609 default:
610 error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
611 correlation_variable_type);
614 print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
615 correlation_type | param_type,
616 correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "parameter, " : "",
617 param_type_string);
618 print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string);
619 print_file(file, 2, "NdrFcShort(0x%x), /* %soffset = %d */\n",
620 offset,
621 correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "x86 stack size / " : "",
622 offset);
624 else
626 unsigned int callback_offset = 0;
628 if (structure)
630 struct expr_eval_routine *eval;
631 int found = 0;
633 LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
635 if (!strcmp(eval->structure->name, structure->name) &&
636 !compare_expr(eval->expr, expr))
638 found = 1;
639 break;
641 callback_offset++;
644 if (!found)
646 unsigned int align = 0;
647 eval = xmalloc(sizeof(*eval));
648 eval->structure = structure;
649 eval->structure_size = fields_memsize(structure->fields, &align);
650 eval->expr = expr;
651 list_add_tail(&expr_eval_routines, &eval->entry);
654 correlation_type = RPC_FC_NORMAL_CONFORMANCE;
656 else
658 error("write_conf_or_var_desc: top-level callback conformance unimplemented\n");
659 correlation_type = RPC_FC_TOP_LEVEL_CONFORMANCE;
662 if (callback_offset > USHRT_MAX)
663 error("Maximum number of callback routines reached\n");
665 print_file(file, 2, "0x%x, /* Corr desc: %s */\n",
666 correlation_type,
667 correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "parameter" : "");
668 print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
669 print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", callback_offset, callback_offset);
671 return 4;
674 static size_t fields_memsize(const var_list_t *fields, unsigned int *align)
676 size_t size = 0;
677 const var_t *v;
679 if (!fields) return 0;
680 LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
681 size += type_memsize(v->type, v->array, align);
683 return size;
686 static size_t union_memsize(const var_list_t *fields, unsigned int *pmaxa)
688 size_t size, maxs = 0;
689 unsigned int align = *pmaxa;
690 const var_t *v;
692 if (fields) LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
694 /* we could have an empty default field with NULL type */
695 if (v->type)
697 size = type_memsize(v->type, v->array, &align);
698 if (maxs < size) maxs = size;
699 if (*pmaxa < align) *pmaxa = align;
703 return maxs;
706 static size_t get_array_size( const array_dims_t *array )
708 size_t size = 1;
709 const expr_t *dim;
711 if (!array) return 0;
713 LIST_FOR_EACH_ENTRY( dim, array, expr_t, entry )
715 if (!dim->is_const) return 0;
716 size *= dim->cval;
719 return size;
722 static size_t type_memsize(const type_t *t, const array_dims_t *array, unsigned int *align)
724 size_t size = 0;
726 if (is_ptr(t))
728 size = sizeof(void *);
729 if (size > *align) *align = size;
731 else switch (t->type)
733 case RPC_FC_BYTE:
734 case RPC_FC_CHAR:
735 case RPC_FC_USMALL:
736 case RPC_FC_SMALL:
737 size = 1;
738 if (size > *align) *align = size;
739 break;
740 case RPC_FC_WCHAR:
741 case RPC_FC_USHORT:
742 case RPC_FC_SHORT:
743 case RPC_FC_ENUM16:
744 size = 2;
745 if (size > *align) *align = size;
746 break;
747 case RPC_FC_ULONG:
748 case RPC_FC_LONG:
749 case RPC_FC_ERROR_STATUS_T:
750 case RPC_FC_ENUM32:
751 case RPC_FC_FLOAT:
752 size = 4;
753 if (size > *align) *align = size;
754 break;
755 case RPC_FC_HYPER:
756 case RPC_FC_DOUBLE:
757 size = 8;
758 if (size > *align) *align = size;
759 break;
760 case RPC_FC_STRUCT:
761 case RPC_FC_CVSTRUCT:
762 case RPC_FC_CPSTRUCT:
763 case RPC_FC_CSTRUCT:
764 case RPC_FC_PSTRUCT:
765 case RPC_FC_BOGUS_STRUCT:
766 size = fields_memsize(t->fields, align);
767 break;
768 case RPC_FC_ENCAPSULATED_UNION:
769 case RPC_FC_NON_ENCAPSULATED_UNION:
770 size = union_memsize(t->fields, align);
771 break;
772 default:
773 error("type_memsize: Unknown type %d\n", t->type);
774 size = 0;
777 if (array) size *= get_array_size( array );
778 return size;
781 static unsigned int write_nonsimple_pointer(FILE *file, const type_t *type, size_t offset)
783 short absoff = type->ref->typestring_offset;
784 short reloff = absoff - (offset + 2);
785 int ptr_attr = is_ptr(type->ref) ? 0x10 : 0x0;
787 print_file(file, 2, "0x%02x, 0x%x,\t/* %s */\n",
788 type->type, ptr_attr, string_of_type(type->type));
789 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%hd) */\n",
790 reloff, reloff, absoff);
791 return 4;
794 static unsigned int write_simple_pointer(FILE *file, const type_t *type)
796 print_file(file, 2, "0x%02x, 0x8,\t/* %s [simple_pointer] */\n",
797 type->type, string_of_type(type->type));
798 print_file(file, 2, "0x%02x,\t/* %s */\n", type->ref->type,
799 string_of_type(type->ref->type));
800 print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
801 return 4;
804 static size_t write_pointer_tfs(FILE *file, type_t *type, unsigned int *typestring_offset)
806 unsigned int offset = *typestring_offset;
808 print_file(file, 0, "/* %d */\n", offset);
809 update_tfsoff(type, offset, file);
811 if (type->ref->typestring_offset)
812 *typestring_offset += write_nonsimple_pointer(file, type, offset);
813 else if (is_base_type(type->ref->type))
814 *typestring_offset += write_simple_pointer(file, type);
816 return offset;
819 static int processed(const type_t *type)
821 return type->typestring_offset && !type->tfswrite;
824 static size_t write_pointer_description(FILE *file, const attr_list_t *attrs,
825 type_t *type, size_t mem_offset,
826 const array_dims_t *array, int level,
827 unsigned int *typestring_offset)
829 const var_t *v;
830 unsigned int align = 0;
832 /* don't generate a pointer for first-level arrays since we want to
833 * descend into them to write their pointers, not stop here */
834 if ((level == 0 || !is_ptr(type)) && is_array_type(attrs, type, array))
836 write_pointer_description(file, NULL, type, mem_offset, NULL,
837 level + 1, typestring_offset);
839 else if (is_ptr(type))
841 print_file(file, 2, "0x46,\t/* FC_NO_REPEAT */\n");
842 print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
843 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", mem_offset, mem_offset);
844 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", mem_offset, mem_offset);
845 *typestring_offset += 6;
847 if (processed(type->ref) || is_base_type(type->ref->type))
848 write_pointer_tfs(file, type, typestring_offset);
849 else
850 error("write_pointer_description: type format string unknown\n");
852 else if (level == 0 && is_struct(type->type))
854 if (type->fields)
856 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
857 mem_offset
858 += write_pointer_description(file, v->attrs, v->type,
859 mem_offset, v->array,
860 level + 1,
861 typestring_offset);
865 return type_memsize(type, array, &align);
868 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
869 const type_t *type, const array_dims_t *array,
870 const char *name, unsigned int *typestring_offset)
872 const expr_list_t *size_is = get_attrp(attrs, ATTR_SIZEIS);
873 int has_size = is_non_void(size_is);
874 size_t start_offset = *typestring_offset;
875 unsigned char flags = 0;
876 int pointer_type;
877 unsigned char rtype;
879 if (is_ptr(type))
881 pointer_type = type->type;
882 type = type->ref;
884 else
885 pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
887 if (!pointer_type)
888 pointer_type = RPC_FC_RP;
890 if (!get_attrp(attrs, ATTR_SIZEIS))
891 flags |= RPC_FC_P_SIMPLEPOINTER;
893 rtype = type->type;
895 if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR))
897 error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
898 return start_offset;
901 print_file(file, 2,"0x%x, 0x%x, /* %s%s */\n",
902 pointer_type, flags,
903 pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"),
904 (flags & RPC_FC_P_SIMPLEPOINTER) ? " [simple_pointer]" : "");
905 *typestring_offset += 2;
907 if (!(flags & RPC_FC_P_SIMPLEPOINTER))
909 print_file(file, 2, "NdrFcShort(0x2),\n");
910 *typestring_offset += 2;
913 if (array && !is_conformant_array(array))
915 /* FIXME: multi-dimensional array */
916 const expr_t *dim = LIST_ENTRY( list_head( array ), expr_t, entry );
917 if (dim->cval > USHRT_MAX)
918 error("array size for parameter %s exceeds %d bytes by %ld bytes\n",
919 name, USHRT_MAX, dim->cval - USHRT_MAX);
921 if (rtype == RPC_FC_CHAR)
922 WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
923 else
924 WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
925 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
926 *typestring_offset += 2;
928 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", dim->cval, dim->cval);
929 *typestring_offset += 2;
931 return start_offset;
933 else if (has_size)
935 if (rtype == RPC_FC_CHAR)
936 WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
937 else
938 WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
939 print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
940 *typestring_offset += 2;
942 *typestring_offset += write_conf_or_var_desc(file, current_func, NULL, size_is);
944 return start_offset;
946 else
948 if (rtype == RPC_FC_CHAR)
949 WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
950 else
951 WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
952 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
953 *typestring_offset += 2;
955 return start_offset;
959 static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
960 type_t *type, const array_dims_t *array,
961 const char *name, unsigned int *typestring_offset)
963 const expr_list_t *length_is = get_attrp(attrs, ATTR_LENGTHIS);
964 const expr_list_t *size_is = get_attrp(attrs, ATTR_SIZEIS);
965 int has_length = is_non_void(length_is);
966 int has_size = is_non_void(size_is) || is_conformant_array(array);
967 size_t start_offset;
968 int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
969 if (!pointer_type)
970 pointer_type = RPC_FC_RP;
972 print_file(file, 2, "0x%x, 0x00, /* %s */\n",
973 pointer_type,
974 pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"));
975 print_file(file, 2, "NdrFcShort(0x2),\n");
976 *typestring_offset += 4;
978 if (array && list_count(array) > 1) /* multi-dimensional array */
980 error("write_array_tfs: Multi-dimensional arrays not implemented yet (param %s)\n", name);
981 return 0;
983 else
985 const expr_t *dim = array ? LIST_ENTRY( list_head( array ), expr_t, entry ) : NULL;
986 int has_pointer = 0;
988 if (write_embedded_types(file, attrs, type, name, array, 0, typestring_offset))
989 has_pointer = 1;
991 start_offset = *typestring_offset;
993 if (!has_length && !has_size)
995 /* fixed array */
996 unsigned int align = 0;
997 size_t size = type_memsize(type, array, &align);
998 if (size < USHRT_MAX)
1000 WRITE_FCTYPE(file, FC_SMFARRAY, *typestring_offset);
1001 /* alignment */
1002 print_file(file, 2, "0x%02x,\n", align - 1);
1003 /* size */
1004 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", size, size);
1005 *typestring_offset += 4;
1007 else
1009 WRITE_FCTYPE(file, FC_LGFARRAY, *typestring_offset);
1010 /* alignment */
1011 print_file(file, 2, "0x%02x,\n", align - 1);
1012 /* size */
1013 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", size, size);
1014 *typestring_offset += 6;
1017 if (has_pointer)
1019 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1020 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1021 *typestring_offset += 2;
1022 write_pointer_description(file, attrs, type, 0, array, 0, typestring_offset);
1023 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1024 *typestring_offset += 1;
1027 if (!write_base_type( file, type, typestring_offset ))
1029 print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
1030 *typestring_offset += 1;
1032 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1033 *typestring_offset += 1;
1035 return start_offset;
1037 else if (has_length && !has_size)
1039 /* varying array */
1040 unsigned int align = 0;
1041 size_t element_size = type_memsize(type, NULL, &align);
1042 size_t elements = dim->cval;
1043 size_t total_size = element_size * elements;
1045 if (total_size < USHRT_MAX)
1047 WRITE_FCTYPE(file, FC_SMVARRAY, *typestring_offset);
1048 /* alignment */
1049 print_file(file, 2, "0x%02x,\n", align - 1);
1050 /* total size */
1051 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", total_size, total_size);
1052 /* number of elements */
1053 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", elements, elements);
1054 *typestring_offset += 6;
1056 else
1058 WRITE_FCTYPE(file, FC_LGVARRAY, *typestring_offset);
1059 /* alignment */
1060 print_file(file, 2, "0x%02x,\n", align - 1);
1061 /* total size */
1062 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", total_size, total_size);
1063 /* number of elements */
1064 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", elements, elements);
1065 *typestring_offset += 10;
1067 /* element size */
1068 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
1069 *typestring_offset += 2;
1071 *typestring_offset += write_conf_or_var_desc(file, current_func,
1072 current_structure,
1073 length_is);
1075 if (has_pointer)
1077 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1078 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1079 *typestring_offset += 2;
1080 write_pointer_description(file, attrs, type, 0, array, 0, typestring_offset);
1081 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1082 *typestring_offset += 1;
1085 if (!write_base_type( file, type, typestring_offset ))
1087 print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
1088 *typestring_offset += 1;
1090 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1091 *typestring_offset += 1;
1093 return start_offset;
1095 else if (!has_length && has_size)
1097 /* conformant array */
1098 unsigned int align = 0;
1099 size_t element_size = type_memsize(type, NULL, &align);
1101 WRITE_FCTYPE(file, FC_CARRAY, *typestring_offset);
1102 /* alignment */
1103 print_file(file, 2, "0x%02x,\n", align - 1);
1104 /* element size */
1105 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
1106 *typestring_offset += 4;
1108 *typestring_offset += write_conf_or_var_desc(file, current_func,
1109 current_structure,
1110 size_is ? size_is : array);
1112 if (has_pointer)
1114 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1115 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1116 *typestring_offset += 2;
1117 write_pointer_description(file, attrs, type, 0, array, 0, typestring_offset);
1118 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1119 *typestring_offset += 1;
1122 if (!write_base_type( file, type, typestring_offset ))
1124 print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
1125 *typestring_offset += 1;
1127 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1128 *typestring_offset += 1;
1130 return start_offset;
1132 else
1134 /* conformant varying array */
1135 unsigned int align = 0;
1136 size_t element_size = type_memsize(type, NULL, &align);
1138 WRITE_FCTYPE(file, FC_CVARRAY, *typestring_offset);
1139 /* alignment */
1140 print_file(file, 2, "0x%02x,\n", align - 1);
1141 /* element size */
1142 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
1143 *typestring_offset += 4;
1145 *typestring_offset += write_conf_or_var_desc(file, current_func,
1146 current_structure,
1147 size_is ? size_is : array);
1148 *typestring_offset += write_conf_or_var_desc(file, current_func,
1149 current_structure,
1150 length_is);
1152 if (has_pointer)
1154 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1155 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1156 *typestring_offset += 2;
1157 write_pointer_description(file, attrs, type, 0, array, 0, typestring_offset);
1158 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1159 *typestring_offset += 1;
1162 if (!write_base_type( file, type, typestring_offset ))
1164 print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
1165 *typestring_offset += 1;
1167 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1168 *typestring_offset += 1;
1170 return start_offset;
1175 static const var_t *find_array_or_string_in_struct(const type_t *type)
1177 const var_t *last_field = LIST_ENTRY( list_tail(type->fields), const var_t, entry );
1179 if (is_array_type(last_field->attrs, last_field->type, last_field->array))
1180 return last_field;
1182 assert((last_field->type->type == RPC_FC_CSTRUCT) ||
1183 (last_field->type->type == RPC_FC_CPSTRUCT) ||
1184 (last_field->type->type == RPC_FC_CVSTRUCT));
1186 return find_array_or_string_in_struct(last_field->type);
1189 static void write_struct_members(FILE *file, const type_t *type, unsigned int *typestring_offset)
1191 const var_t *field;
1193 if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1195 unsigned char rtype = field->type->type;
1197 if (field->array)
1198 write_array_tfs( file, field->attrs, field->type, field->array,
1199 field->name, typestring_offset );
1200 else if (is_ptr( field->type ))
1202 /* pointers are handled in detail earlier, here just treat them like longs */
1203 print_file( file, 2, "0x8,\t/* FC_LONG */\n" );
1204 *typestring_offset += 1;
1206 else if (is_embedded_complex(field->type))
1208 size_t absoff = (field->corrdesc
1209 ? field->corrdesc
1210 : field->type->typestring_offset);
1211 short reloff = absoff - (*typestring_offset + 2);
1213 print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
1214 /* FIXME: actually compute necessary padding */
1215 print_file(file, 2, "0x0,\t/* FIXME: padding */\n");
1216 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1217 reloff, reloff, absoff);
1218 *typestring_offset += 4;
1220 else if (!write_base_type( file, field->type, typestring_offset ))
1221 error("Unsupported member type 0x%x\n", rtype);
1224 if (!(*typestring_offset % 2))
1226 print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD);
1227 *typestring_offset += 1;
1230 print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END);
1231 *typestring_offset += 1;
1234 static size_t write_struct_tfs(FILE *file, type_t *type,
1235 const char *name, unsigned int *typestring_offset)
1237 unsigned int total_size;
1238 const var_t *array;
1239 size_t start_offset;
1240 size_t array_offset;
1241 int has_pointers;
1242 unsigned int align = 0;
1244 guard_rec(type);
1246 switch (type->type)
1248 case RPC_FC_STRUCT:
1249 case RPC_FC_PSTRUCT:
1250 total_size = type_memsize(type, NULL, &align);
1252 if (total_size > USHRT_MAX)
1253 error("structure size for %s exceeds %d bytes by %d bytes\n",
1254 name, USHRT_MAX, total_size - USHRT_MAX);
1256 if (type->type == RPC_FC_PSTRUCT)
1257 write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset);
1259 start_offset = *typestring_offset;
1260 update_tfsoff(type, start_offset, file);
1261 if (type->type == RPC_FC_STRUCT)
1262 WRITE_FCTYPE(file, FC_STRUCT, *typestring_offset);
1263 else
1264 WRITE_FCTYPE(file, FC_PSTRUCT, *typestring_offset);
1265 /* alignment */
1266 print_file(file, 2, "0x%02x,\n", align - 1);
1267 /* total size */
1268 print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1269 *typestring_offset += 4;
1271 if (type->type == RPC_FC_PSTRUCT)
1273 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1274 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1275 *typestring_offset += 2;
1276 write_pointer_description(file, NULL, type, 0, NULL, 0, typestring_offset);
1277 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1278 *typestring_offset += 1;
1281 /* member layout */
1282 write_struct_members(file, type, typestring_offset);
1283 return start_offset;
1284 case RPC_FC_CSTRUCT:
1285 case RPC_FC_CPSTRUCT:
1286 total_size = type_memsize(type, NULL, &align);
1288 if (total_size > USHRT_MAX)
1289 error("structure size for %s exceeds %d bytes by %d bytes\n",
1290 name, USHRT_MAX, total_size - USHRT_MAX);
1292 array = find_array_or_string_in_struct(type);
1293 current_structure = type;
1294 array_offset = write_array_tfs(file, array->attrs, array->type,
1295 array->array, array->name,
1296 typestring_offset);
1297 current_structure = NULL;
1299 if (type->type == RPC_FC_CPSTRUCT)
1300 write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset);
1302 start_offset = *typestring_offset;
1303 update_tfsoff(type, start_offset, file);
1304 if (type->type == RPC_FC_CSTRUCT)
1305 WRITE_FCTYPE(file, FC_CSTRUCT, *typestring_offset);
1306 else
1307 WRITE_FCTYPE(file, FC_CPSTRUCT, *typestring_offset);
1308 /* alignment */
1309 print_file(file, 2, "0x%02x,\n", align - 1);
1310 /* total size */
1311 print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1312 *typestring_offset += 4;
1313 print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d (%u) */\n",
1314 array_offset - *typestring_offset,
1315 array_offset - *typestring_offset,
1316 array_offset);
1317 *typestring_offset += 2;
1319 if (type->type == RPC_FC_CPSTRUCT)
1321 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1322 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1323 *typestring_offset += 2;
1324 write_pointer_description(file, NULL, type, 0, NULL, 0, typestring_offset);
1325 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1326 *typestring_offset += 1;
1329 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1330 *typestring_offset += 1;
1332 return start_offset;
1333 case RPC_FC_CVSTRUCT:
1334 total_size = type_memsize(type, NULL, &align);
1336 if (total_size > USHRT_MAX)
1337 error("structure size for %s exceeds %d bytes by %d bytes\n",
1338 name, USHRT_MAX, total_size - USHRT_MAX);
1340 array = find_array_or_string_in_struct(type);
1341 current_structure = type;
1342 if (is_attr(array->attrs, ATTR_STRING))
1343 array_offset = write_string_tfs(file, array->attrs, array->type,
1344 array->array, array->name,
1345 typestring_offset);
1346 else
1347 array_offset = write_array_tfs(file, array->attrs, array->type,
1348 array->array, array->name,
1349 typestring_offset);
1350 current_structure = NULL;
1352 has_pointers = write_embedded_types(file, NULL, type, name, NULL, 0,
1353 typestring_offset);
1355 start_offset = *typestring_offset;
1356 update_tfsoff(type, start_offset, file);
1357 WRITE_FCTYPE(file, FC_CVSTRUCT, *typestring_offset);
1358 /* alignment */
1359 print_file(file, 2, "0x%02x,\n", align - 1);
1360 /* total size */
1361 print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1362 *typestring_offset += 4;
1363 print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d (%u) */\n",
1364 array_offset - *typestring_offset,
1365 array_offset - *typestring_offset,
1366 array_offset);
1367 *typestring_offset += 2;
1369 if (has_pointers)
1371 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1372 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1373 *typestring_offset += 2;
1374 write_pointer_description(file, NULL, type, 0, NULL, 0, typestring_offset);
1375 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1376 *typestring_offset += 1;
1379 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1380 *typestring_offset += 1;
1382 return start_offset;
1384 case RPC_FC_BOGUS_STRUCT:
1385 total_size = type_memsize(type, NULL, &align);
1386 if (total_size > USHRT_MAX)
1387 error("structure size for %s exceeds %d bytes by %d bytes\n",
1388 name, USHRT_MAX, total_size - USHRT_MAX);
1390 write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset);
1392 start_offset = *typestring_offset;
1393 update_tfsoff(type, start_offset, file);
1394 print_file(file, 0, "/* %d */\n", start_offset);
1395 print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
1396 print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1397 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size);
1399 /* do conformant array stuff */
1400 print_file(file, 2, "NdrFcShort(0x0),\t/* FIXME: conformant array stuff */\n");
1402 /* do pointer stuff here */
1403 print_file(file, 2, "NdrFcShort(0x0),\t/* FIXME: pointer stuff */\n");
1405 *typestring_offset += 8;
1406 write_struct_members(file, type, typestring_offset);
1408 return start_offset;
1410 default:
1411 error("write_struct_tfs: Unimplemented for type 0x%x\n", type->type);
1412 return *typestring_offset;
1416 static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
1417 unsigned char flags, size_t offset,
1418 unsigned int *typeformat_offset)
1420 size_t start_offset = *typeformat_offset;
1421 short reloff = offset - (*typeformat_offset + 2);
1422 int in_attr, out_attr;
1423 in_attr = is_attr(attrs, ATTR_IN);
1424 out_attr = is_attr(attrs, ATTR_OUT);
1425 if (!in_attr && !out_attr) in_attr = 1;
1427 if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
1428 flags |= 0x04;
1430 print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
1431 pointer_type,
1432 flags,
1433 string_of_type(pointer_type));
1434 if (file)
1436 if (flags & 0x04)
1437 fprintf(file, " [allocated_on_stack]");
1438 if (flags & 0x10)
1439 fprintf(file, " [pointer_deref]");
1440 fprintf(file, " */\n");
1443 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", reloff, offset);
1444 *typeformat_offset += 4;
1446 return start_offset;
1449 static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
1451 if (is_base_type(t->type))
1453 print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n",
1454 t->type, string_of_type(t->type));
1456 else if (t->typestring_offset)
1458 short reloff = t->typestring_offset - *tfsoff;
1459 print_file(file, 2, "NdrFcShort(0x%x),\t/* Offset= %d (%d) */\n",
1460 reloff, reloff, t->typestring_offset);
1462 else
1463 error("write_branch_type: type unimplemented (0x%x)\n", t->type);
1465 *tfsoff += 2;
1468 static size_t write_union_tfs(FILE *file, type_t *type, const char *name,
1469 unsigned int *tfsoff)
1471 unsigned int align = 0;
1472 unsigned int start_offset;
1473 size_t size = type_memsize(type, NULL, &align);
1474 var_list_t *fields = type->fields;
1475 size_t nbranch = 0;
1476 type_t *deftype = NULL;
1477 short nodeftype = 0xffff;
1478 var_t *f;
1480 guard_rec(type);
1482 /* use a level of 1 so pointers always get written */
1483 write_embedded_types(file, NULL, type, name, NULL, 1, tfsoff);
1485 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
1487 expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
1488 if (cases)
1489 nbranch += list_count(cases);
1492 start_offset = *tfsoff;
1493 update_tfsoff(type, start_offset, file);
1494 print_file(file, 0, "/* %d */\n", start_offset);
1495 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", size, size);
1496 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", nbranch, nbranch);
1497 *tfsoff += 4;
1499 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
1501 type_t *ft = f->type;
1502 expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
1503 int deflt = is_attr(f->attrs, ATTR_DEFAULT);
1504 expr_t *c;
1506 if (cases == NULL && !deflt)
1507 error("union field %s with neither case nor default attribute\n", f->name);
1509 if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry)
1511 /* MIDL doesn't check for duplicate cases, even though that seems
1512 like a reasonable thing to do, it just dumps them to the TFS
1513 like we're going to do here. */
1514 print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
1515 *tfsoff += 4;
1516 write_branch_type(file, ft, tfsoff);
1519 /* MIDL allows multiple default branches, even though that seems
1520 illogical, it just chooses the last one, which is what we will
1521 do. */
1522 if (deflt)
1524 deftype = ft;
1525 nodeftype = 0;
1529 if (deftype)
1531 write_branch_type(file, deftype, tfsoff);
1533 else
1535 print_file(file, 2, "NdrFcShort(0x%x),\n", nodeftype);
1536 *tfsoff += 2;
1539 return start_offset;
1542 static size_t write_ip_tfs(FILE *file, const func_t *func, const type_t *type, const var_t *var,
1543 unsigned int *typeformat_offset)
1545 size_t i;
1546 size_t start_offset = *typeformat_offset;
1547 const var_t *iid = get_attrp(var->attrs, ATTR_IIDIS);
1549 if (iid)
1551 expr_t expr;
1552 expr_list_t expr_list;
1554 expr.type = EXPR_IDENTIFIER;
1555 expr.ref = NULL;
1556 expr.u.sval = iid->name;
1557 expr.is_const = FALSE;
1558 list_init( &expr_list );
1559 list_add_head( &expr_list, &expr.entry );
1560 print_file(file, 2, "0x2f, /* FC_IP */\n");
1561 print_file(file, 2, "0x5c, /* FC_PAD */\n");
1562 *typeformat_offset += write_conf_or_var_desc(file, func, NULL, &expr_list) + 2;
1564 else
1566 const type_t *base = is_ptr(type) ? type->ref : type;
1567 const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
1569 if (! uuid)
1570 error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
1572 print_file(file, 2, "0x2f,\t/* FC_IP */\n");
1573 print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
1574 print_file(file, 2, "NdrFcLong(0x%08lx),\n", uuid->Data1);
1575 print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2);
1576 print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3);
1577 for (i = 0; i < 8; ++i)
1578 print_file(file, 2, "0x%02x,\n", uuid->Data4[i]);
1580 if (file)
1581 fprintf(file, "\n");
1583 *typeformat_offset += 18;
1585 return start_offset;
1588 static int get_ptr_attr(const type_t *t, int def_type)
1590 while (TRUE)
1592 int ptr_attr = get_attrv(t->attrs, ATTR_POINTERTYPE);
1593 if (ptr_attr)
1594 return ptr_attr;
1595 if (t->kind != TKIND_ALIAS)
1596 return def_type;
1597 t = t->orig;
1601 static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *func,
1602 type_t *type, const var_t *var,
1603 unsigned int *typeformat_offset)
1605 int pointer_type;
1606 size_t offset;
1608 if (type == var->type) /* top-level pointers */
1610 int pointer_attr = get_attrv(var->attrs, ATTR_POINTERTYPE);
1611 if (pointer_attr != 0 && !is_ptr(type))
1612 error("'%s': pointer attribute applied to non-pointer type\n", var->name);
1614 if (pointer_attr == 0)
1615 pointer_attr = get_ptr_attr(type, RPC_FC_RP);
1617 pointer_type = pointer_attr;
1619 else
1620 pointer_type = get_ptr_attr(type, RPC_FC_UP);
1622 if (((last_ptr(type) && var->array == NULL)
1623 || (!is_ptr(type) && var->array != NULL))
1624 && is_ptrchain_attr(var, ATTR_STRING))
1626 return write_string_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
1629 if (is_array_type(var->attrs, type, var->array))
1630 return write_array_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
1632 if (!is_ptr(type))
1634 /* basic types don't need a type format string */
1635 if (is_base_type(type->type))
1636 return 0;
1638 switch (type->type)
1640 case RPC_FC_STRUCT:
1641 case RPC_FC_PSTRUCT:
1642 case RPC_FC_CSTRUCT:
1643 case RPC_FC_CPSTRUCT:
1644 case RPC_FC_CVSTRUCT:
1645 case RPC_FC_BOGUS_STRUCT:
1646 return write_struct_tfs(file, type, var->name, typeformat_offset);
1647 case RPC_FC_ENCAPSULATED_UNION:
1648 case RPC_FC_NON_ENCAPSULATED_UNION:
1649 return write_union_tfs(file, type, var->name, typeformat_offset);
1650 case RPC_FC_IGNORE:
1651 case RPC_FC_BIND_PRIMITIVE:
1652 /* nothing to do */
1653 return 0;
1654 default:
1655 error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
1658 else if (last_ptr(type))
1660 size_t start_offset = *typeformat_offset;
1661 int in_attr = is_attr(var->attrs, ATTR_IN);
1662 int out_attr = is_attr(var->attrs, ATTR_OUT);
1663 const type_t *base = type->ref;
1665 if (base->type == RPC_FC_IP)
1667 return write_ip_tfs(file, func, type, var, typeformat_offset);
1670 /* special case for pointers to base types */
1671 if (is_base_type(base->type))
1673 print_file(file, indent, "0x%x, 0x%x, /* %s %s[simple_pointer] */\n",
1674 pointer_type, (!in_attr && out_attr) ? 0x0C : 0x08,
1675 string_of_type(pointer_type),
1676 (!in_attr && out_attr) ? "[allocated_on_stack] " : "");
1677 print_file(file, indent, "0x%02x, /* %s */\n", base->type, string_of_type(base->type));
1678 print_file(file, indent, "0x5c, /* FC_PAD */\n");
1679 *typeformat_offset += 4;
1680 return start_offset;
1684 assert(is_ptr(type));
1686 offset = write_typeformatstring_var(file, indent, func, type->ref, var, typeformat_offset);
1687 if (file)
1688 fprintf(file, "/* %2u */\n", *typeformat_offset);
1689 return write_pointer_only_tfs(file, var->attrs, pointer_type,
1690 !last_ptr(type) ? 0x10 : 0,
1691 offset, typeformat_offset);
1694 static void set_tfswrite(type_t *type, int val)
1696 while (type->tfswrite != val)
1698 type->tfswrite = val;
1700 if (type->kind == TKIND_ALIAS)
1701 type = type->orig;
1702 else if (is_ptr(type))
1703 type = type->ref;
1704 else
1706 if (type->fields)
1708 var_t *v;
1709 LIST_FOR_EACH_ENTRY( v, type->fields, var_t, entry )
1710 set_tfswrite(v->type, val);
1713 return;
1718 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
1719 const char *name, const array_dims_t *array,
1720 int level, unsigned int *tfsoff)
1722 var_list_t *fields = type->fields;
1723 int retmask = 0;
1724 size_t offset = 0;
1725 var_t *f;
1727 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
1729 unsigned int align = 0;
1730 type_t *ft = f->type;
1732 if (!ft) continue;
1733 else if (ft->type == RPC_FC_NON_ENCAPSULATED_UNION)
1735 expr_t *swexp = get_attrp(f->attrs, ATTR_SWITCHIS);
1736 const char *swname;
1737 var_t *swvar;
1738 size_t corroff;
1739 unsigned char corrdesc, op = 0;
1740 short creloff, ureloff;
1742 if (swexp == NULL)
1743 error("union %s needs a switch_is attribute\n", f->name);
1744 if (swexp->type != EXPR_IDENTIFIER)
1745 error("%s: only identifiers are supported for switch_is at this time\n",
1746 f->name);
1748 if (!processed(ft))
1749 write_union_tfs(file, ft, f->name, tfsoff);
1751 swname = swexp->u.sval;
1752 corroff = field_offset(type, swname, &swvar);
1753 corrdesc = swvar->type->type;
1754 creloff = corroff - offset;
1756 f->corrdesc = *tfsoff;
1757 ureloff = ft->typestring_offset - (f->corrdesc + 6);
1758 print_file(file, 0, "/* %d */\n", f->corrdesc);
1759 print_file(file, 2, "0x%x,\t/* %s */\n", ft->type, string_of_type(ft->type));
1760 print_file(file, 2, "0x8,\t/* FIXME: support other switch types */\n");
1761 print_file(file, 2, "0x%x,\t/* Corr desc: %s */\n",
1762 corrdesc, string_of_type(corrdesc & 0xf));
1763 print_file(file, 2, "0x%x,\n", op);
1764 print_file(file, 2, "NdrFcShort(0x%hx),\t/* %hd */\n", creloff, creloff);
1765 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1766 ureloff, ureloff, ft->typestring_offset);
1767 *tfsoff += 8;
1769 else
1770 retmask |= write_embedded_types(file, attrs, ft, f->name, array,
1771 level + 1, tfsoff);
1773 /* FIXME: this doesn't take alignment/padding into account */
1774 offset += type_memsize(ft, NULL, &align);
1776 /* don't generate a pointer for first-level arrays since we want to
1777 descend into them to write their pointers, not stop here */
1778 else if ((level == 0 || !is_ptr(type)) && is_array_type(attrs, type, array))
1780 return write_embedded_types(file, NULL, type, name, NULL, level + 1, tfsoff);
1782 else if (is_ptr(type))
1784 type_t *ref = type->ref;
1786 if (!processed(ref) && !is_base_type(ref->type))
1788 if (is_ptr(ref))
1790 retmask |= write_embedded_types(file, attrs, ref, name, array,
1791 level + 1, tfsoff);
1793 else if (is_struct(ref->type))
1795 write_struct_tfs(file, ref, name, tfsoff);
1797 else
1799 error("write_embedded_types: type format string unknown for %s (0x%x)\n",
1800 name, ref->type);
1804 /* top-level pointers are handled inline */
1805 if (1 < level)
1806 write_pointer_tfs(file, type, tfsoff);
1808 retmask |= 1;
1810 else if (!is_base_type(type->type))
1811 error("write_embedded_types: unknown embedded type for %s (0x%x)\n",
1812 name, type->type);
1814 return retmask;
1817 static void set_all_tfswrite(const ifref_list_t *ifaces, int val)
1819 const ifref_t * iface;
1820 const func_t *func;
1821 const var_t *var;
1823 if (ifaces)
1824 LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
1825 if (iface->iface->funcs)
1826 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
1827 if (func->args)
1828 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
1829 set_tfswrite(var->type, val);
1832 static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, int for_objects)
1834 const var_t *var;
1835 const ifref_t *iface;
1836 unsigned int typeformat_offset = 2;
1838 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
1840 if (for_objects != is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
1841 continue;
1843 if (iface->iface->funcs)
1845 const func_t *func;
1846 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
1848 if (is_local(func->def->attrs)) continue;
1850 current_func = func;
1851 if (func->args)
1852 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
1853 update_tfsoff(
1854 var->type,
1855 write_typeformatstring_var(
1856 file, 2, func, var->type, var,
1857 &typeformat_offset),
1858 file);
1863 return typeformat_offset + 1;
1867 void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, int for_objects)
1869 int indent = 0;
1871 print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
1872 print_file(file, indent, "{\n");
1873 indent++;
1874 print_file(file, indent, "0,\n");
1875 print_file(file, indent, "{\n");
1876 indent++;
1877 print_file(file, indent, "NdrFcShort(0x0),\n");
1879 set_all_tfswrite(ifaces, TRUE);
1880 process_tfs(file, ifaces, for_objects);
1882 print_file(file, indent, "0x0\n");
1883 indent--;
1884 print_file(file, indent, "}\n");
1885 indent--;
1886 print_file(file, indent, "};\n");
1887 print_file(file, indent, "\n");
1890 static unsigned int get_required_buffer_size_type(
1891 const type_t *type, const array_dims_t *array,
1892 const char *name, unsigned int *alignment)
1894 size_t size = 0;
1896 *alignment = 0;
1897 if (!is_ptr(type))
1899 switch (type->type)
1901 case RPC_FC_BYTE:
1902 case RPC_FC_CHAR:
1903 case RPC_FC_USMALL:
1904 case RPC_FC_SMALL:
1905 *alignment = 4;
1906 size = 1;
1907 break;
1909 case RPC_FC_WCHAR:
1910 case RPC_FC_USHORT:
1911 case RPC_FC_SHORT:
1912 *alignment = 4;
1913 size = 2;
1914 break;
1916 case RPC_FC_ULONG:
1917 case RPC_FC_LONG:
1918 case RPC_FC_FLOAT:
1919 case RPC_FC_ERROR_STATUS_T:
1920 *alignment = 4;
1921 size = 4;
1922 break;
1924 case RPC_FC_HYPER:
1925 case RPC_FC_DOUBLE:
1926 *alignment = 8;
1927 size = 8;
1928 break;
1930 case RPC_FC_IGNORE:
1931 case RPC_FC_BIND_PRIMITIVE:
1932 return 0;
1934 case RPC_FC_STRUCT:
1935 case RPC_FC_PSTRUCT:
1937 const var_t *field;
1938 if (!type->fields) return 0;
1939 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1941 unsigned int alignment;
1942 size += get_required_buffer_size_type(
1943 field->type, field->array, field->name,
1944 &alignment);
1946 break;
1949 case RPC_FC_RP:
1950 if (is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT)
1951 size = get_required_buffer_size_type( type->ref, NULL, name, alignment );
1952 break;
1954 default:
1955 error("get_required_buffer_size: Unknown/unsupported type: %s (0x%02x)\n", name, type->type);
1956 return 0;
1958 if (array) size *= get_array_size( array );
1960 return size;
1963 static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
1965 expr_list_t *size_is = get_attrp(var->attrs, ATTR_SIZEIS);
1966 int has_size = is_non_void(size_is);
1967 int in_attr = is_attr(var->attrs, ATTR_IN);
1968 int out_attr = is_attr(var->attrs, ATTR_OUT);
1970 if (!in_attr && !out_attr)
1971 in_attr = 1;
1973 *alignment = 0;
1975 if (pass == PASS_OUT)
1977 if (out_attr && is_ptr(var->type))
1979 type_t *type = var->type;
1981 if (type->type == RPC_FC_STRUCT)
1983 const var_t *field;
1984 unsigned int size = 36;
1986 if (!type->fields) return size;
1987 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1989 unsigned int align;
1990 size += get_required_buffer_size_type(
1991 field->type, field->array, field->name,
1992 &align);
1994 return size;
1997 return 0;
1999 else
2001 if ((!out_attr || in_attr) && !has_size && !is_attr(var->attrs, ATTR_STRING) && !var->array)
2003 if (is_ptr(var->type))
2005 type_t *type = var->type;
2007 if (is_base_type(type->type))
2009 return 25;
2011 else if (type->type == RPC_FC_STRUCT)
2013 unsigned int size = 36;
2014 const var_t *field;
2016 if (!type->fields) return size;
2017 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2019 unsigned int align;
2020 size += get_required_buffer_size_type(
2021 field->type, field->array, field->name,
2022 &align);
2024 return size;
2029 return get_required_buffer_size_type(var->type, var->array, var->name, alignment);
2033 static unsigned int get_function_buffer_size( const func_t *func, enum pass pass )
2035 const var_t *var;
2036 unsigned int total_size = 0, alignment;
2038 if (func->args)
2040 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2042 total_size += get_required_buffer_size(var, &alignment, pass);
2043 total_size += alignment;
2047 if (pass == PASS_OUT && !is_void(func->def->type))
2049 total_size += get_required_buffer_size(func->def, &alignment, PASS_RETURN);
2050 total_size += alignment;
2052 return total_size;
2055 static void print_phase_function(FILE *file, int indent, const char *type,
2056 enum remoting_phase phase,
2057 const char *varname, unsigned int type_offset)
2059 const char *function;
2060 switch (phase)
2062 case PHASE_BUFFERSIZE:
2063 function = "BufferSize";
2064 break;
2065 case PHASE_MARSHAL:
2066 function = "Marshall";
2067 break;
2068 case PHASE_UNMARSHAL:
2069 function = "Unmarshall";
2070 break;
2071 case PHASE_FREE:
2072 function = "Free";
2073 break;
2074 default:
2075 assert(0);
2076 return;
2079 print_file(file, indent, "Ndr%s%s(\n", type, function);
2080 indent++;
2081 print_file(file, indent, "&_StubMsg,\n");
2082 print_file(file, indent, "%s%s,\n",
2083 (phase == PHASE_UNMARSHAL) ? "(unsigned char **)&" : "(unsigned char *)",
2084 varname);
2085 print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
2086 type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
2087 if (phase == PHASE_UNMARSHAL)
2088 print_file(file, indent, "0);\n");
2089 indent--;
2092 void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
2093 enum pass pass, const var_t *var,
2094 const char *varname)
2096 type_t *type = var->type;
2097 unsigned int size;
2098 unsigned int alignment = 0;
2099 unsigned char rtype;
2101 /* no work to do for other phases, buffer sizing is done elsewhere */
2102 if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
2103 return;
2105 rtype = is_ptr(type) ? type->ref->type : type->type;
2107 switch (rtype)
2109 case RPC_FC_BYTE:
2110 case RPC_FC_CHAR:
2111 case RPC_FC_SMALL:
2112 case RPC_FC_USMALL:
2113 size = 1;
2114 alignment = 1;
2115 break;
2117 case RPC_FC_WCHAR:
2118 case RPC_FC_USHORT:
2119 case RPC_FC_SHORT:
2120 size = 2;
2121 alignment = 2;
2122 break;
2124 case RPC_FC_ULONG:
2125 case RPC_FC_LONG:
2126 case RPC_FC_FLOAT:
2127 case RPC_FC_ERROR_STATUS_T:
2128 size = 4;
2129 alignment = 4;
2130 break;
2132 case RPC_FC_HYPER:
2133 case RPC_FC_DOUBLE:
2134 size = 8;
2135 alignment = 8;
2136 break;
2138 case RPC_FC_IGNORE:
2139 case RPC_FC_BIND_PRIMITIVE:
2140 /* no marshalling needed */
2141 return;
2143 default:
2144 error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, rtype);
2145 size = 0;
2148 print_file(file, indent, "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
2149 alignment - 1, alignment - 1);
2151 if (phase == PHASE_MARSHAL)
2153 print_file(file, indent, "*(");
2154 write_type(file, is_ptr(type) ? type->ref : type);
2155 if (is_ptr(type))
2156 fprintf(file, " *)_StubMsg.Buffer = *");
2157 else
2158 fprintf(file, " *)_StubMsg.Buffer = ");
2159 fprintf(file, varname);
2160 fprintf(file, ";\n");
2162 else if (phase == PHASE_UNMARSHAL)
2164 if (pass == PASS_IN || pass == PASS_RETURN)
2165 print_file(file, indent, "");
2166 else
2167 print_file(file, indent, "*");
2168 fprintf(file, varname);
2169 if (pass == PASS_IN && is_ptr(type))
2170 fprintf(file, " = (");
2171 else
2172 fprintf(file, " = *(");
2173 write_type(file, is_ptr(type) ? type->ref : type);
2174 fprintf(file, " *)_StubMsg.Buffer;\n");
2177 print_file(file, indent, "_StubMsg.Buffer += sizeof(");
2178 write_type(file, var->type);
2179 fprintf(file, ");\n");
2182 /* returns whether the MaxCount, Offset or ActualCount members need to be
2183 * filled in for the specified phase */
2184 static inline int is_size_needed_for_phase(enum remoting_phase phase)
2186 return (phase != PHASE_UNMARSHAL);
2189 void write_remoting_arguments(FILE *file, int indent, const func_t *func,
2190 enum pass pass, enum remoting_phase phase)
2192 const expr_list_t *length_is;
2193 const expr_list_t *size_is;
2194 int in_attr, out_attr, has_length, has_size, pointer_type;
2195 const var_t *var;
2197 if (!func->args)
2198 return;
2200 if (phase == PHASE_BUFFERSIZE)
2202 unsigned int size = get_function_buffer_size( func, pass );
2203 print_file(file, indent, "_StubMsg.BufferLength = %u;\n", size);
2206 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2208 const type_t *type = var->type;
2209 unsigned char rtype;
2210 size_t start_offset = type->typestring_offset;
2212 length_is = get_attrp(var->attrs, ATTR_LENGTHIS);
2213 size_is = get_attrp(var->attrs, ATTR_SIZEIS);
2214 has_length = is_non_void(length_is);
2215 has_size = is_non_void(size_is) || (var->array && is_conformant_array(var->array));
2217 pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2218 if (!pointer_type)
2219 pointer_type = RPC_FC_RP;
2221 in_attr = is_attr(var->attrs, ATTR_IN);
2222 out_attr = is_attr(var->attrs, ATTR_OUT);
2223 if (!in_attr && !out_attr)
2224 in_attr = 1;
2226 switch (pass)
2228 case PASS_IN:
2229 if (!in_attr) continue;
2230 break;
2231 case PASS_OUT:
2232 if (!out_attr) continue;
2233 break;
2234 case PASS_RETURN:
2235 break;
2238 rtype = type->type;
2240 if (is_user_derived( var ))
2242 print_phase_function(file, indent, "UserMarshal", phase, var->name, start_offset);
2244 else if (is_string_type(var->attrs, var->type, var->array))
2246 if (var->array && !is_conformant_array(var->array))
2247 print_phase_function(file, indent, "NonConformantString", phase, var->name, start_offset);
2248 else
2250 if (size_is && is_size_needed_for_phase(phase))
2252 const expr_t *size = LIST_ENTRY( list_head(size_is), const expr_t, entry );
2253 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2254 write_expr(file, size, 1);
2255 fprintf(file, ";\n");
2258 if ((phase == PHASE_FREE) || (pointer_type == RPC_FC_UP))
2259 print_phase_function(file, indent, "Pointer", phase, var->name, start_offset);
2260 else
2261 print_phase_function(file, indent, "ConformantString", phase, var->name,
2262 start_offset + (has_size ? 4 : 2));
2265 else if (is_array_type(var->attrs, var->type, var->array))
2267 const char *array_type;
2269 if (var->array && list_count(var->array) > 1) /* multi-dimensional array */
2270 array_type = "ComplexArray";
2271 else
2273 if (!has_length && !has_size)
2274 array_type = "FixedArray";
2275 else if (has_length && !has_size)
2277 if (is_size_needed_for_phase(phase))
2279 const expr_t *length = LIST_ENTRY( list_head(length_is), const expr_t, entry );
2280 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2281 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2282 write_expr(file, length, 1);
2283 fprintf(file, ";\n\n");
2285 array_type = "VaryingArray";
2287 else if (!has_length && has_size)
2289 if (is_size_needed_for_phase(phase) && phase != PHASE_FREE)
2291 const expr_t *size = LIST_ENTRY( list_head(size_is ? size_is : var->array),
2292 const expr_t, entry );
2293 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2294 write_expr(file, size, 1);
2295 fprintf(file, ";\n\n");
2297 array_type = "ConformantArray";
2299 else
2301 if (is_size_needed_for_phase(phase))
2303 const expr_t *length = LIST_ENTRY( list_head(length_is), const expr_t, entry );
2304 const expr_t *size = LIST_ENTRY( list_head(size_is ? size_is : var->array),
2305 const expr_t, entry );
2306 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2307 write_expr(file, size, 1);
2308 fprintf(file, ";\n");
2309 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2310 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2311 write_expr(file, length, 1);
2312 fprintf(file, ";\n\n");
2314 array_type = "ConformantVaryingArray";
2318 if (!in_attr && phase == PHASE_FREE)
2320 print_file(file, indent, "if (%s)\n", var->name);
2321 indent++;
2322 print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
2324 else if (phase != PHASE_FREE)
2326 if (pointer_type == RPC_FC_UP)
2327 print_phase_function(file, indent, "Pointer", phase, var->name, start_offset);
2328 else
2329 print_phase_function(file, indent, array_type, phase, var->name, start_offset);
2332 else if (!is_ptr(var->type) && is_base_type(rtype))
2334 print_phase_basetype(file, indent, phase, pass, var, var->name);
2336 else if (!is_ptr(var->type))
2338 switch (rtype)
2340 case RPC_FC_STRUCT:
2341 case RPC_FC_PSTRUCT:
2342 print_phase_function(file, indent, "SimpleStruct", phase, var->name, start_offset);
2343 break;
2344 case RPC_FC_CSTRUCT:
2345 case RPC_FC_CPSTRUCT:
2346 print_phase_function(file, indent, "ConformantStruct", phase, var->name, start_offset);
2347 break;
2348 case RPC_FC_CVSTRUCT:
2349 print_phase_function(file, indent, "ConformantVaryingStruct", phase, var->name, start_offset);
2350 break;
2351 case RPC_FC_BOGUS_STRUCT:
2352 print_phase_function(file, indent, "ComplexStruct", phase, var->name, start_offset);
2353 break;
2354 case RPC_FC_RP:
2355 if (is_base_type( var->type->ref->type ))
2357 print_phase_basetype(file, indent, phase, pass, var, var->name);
2359 else if (var->type->ref->type == RPC_FC_STRUCT)
2361 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2362 print_phase_function(file, indent, "SimpleStruct", phase, var->name, start_offset + 4);
2364 else
2366 const var_t *iid;
2367 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2368 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long)%s;\n", iid->name );
2369 print_phase_function(file, indent, "Pointer", phase, var->name, start_offset);
2371 break;
2372 default:
2373 error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype);
2376 else
2378 if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
2380 print_phase_basetype(file, indent, phase, pass, var, var->name);
2382 else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
2384 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2385 print_phase_function(file, indent, "SimpleStruct", phase, var->name, start_offset + 4);
2387 else
2389 const var_t *iid;
2390 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2391 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long)%s;\n", iid->name );
2392 print_phase_function(file, indent, "Pointer", phase, var->name, start_offset);
2395 fprintf(file, "\n");
2400 size_t get_size_procformatstring_var(const var_t *var)
2402 return write_procformatstring_var(NULL, 0, var, FALSE);
2406 size_t get_size_procformatstring_func(const func_t *func)
2408 const var_t *var;
2409 size_t size = 0;
2411 /* argument list size */
2412 if (func->args)
2413 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2414 size += get_size_procformatstring_var(var);
2416 /* return value size */
2417 if (is_void(func->def->type))
2418 size += 2; /* FC_END and FC_PAD */
2419 else
2420 size += get_size_procformatstring_var(func->def);
2422 return size;
2425 size_t get_size_procformatstring(const ifref_list_t *ifaces, int for_objects)
2427 const ifref_t *iface;
2428 size_t size = 1;
2429 const func_t *func;
2431 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
2433 if (for_objects != is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
2434 continue;
2436 if (iface->iface->funcs)
2437 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
2438 if (!is_local(func->def->attrs))
2439 size += get_size_procformatstring_func( func );
2441 return size;
2444 size_t get_size_typeformatstring(const ifref_list_t *ifaces, int for_objects)
2446 set_all_tfswrite(ifaces, FALSE);
2447 return process_tfs(NULL, ifaces, for_objects);
2450 static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
2451 const var_list_t *fields, const char *structvar)
2453 switch (e->type) {
2454 case EXPR_VOID:
2455 break;
2456 case EXPR_NUM:
2457 fprintf(h, "%lu", e->u.lval);
2458 break;
2459 case EXPR_HEXNUM:
2460 fprintf(h, "0x%lx", e->u.lval);
2461 break;
2462 case EXPR_TRUEFALSE:
2463 if (e->u.lval == 0)
2464 fprintf(h, "FALSE");
2465 else
2466 fprintf(h, "TRUE");
2467 break;
2468 case EXPR_IDENTIFIER:
2470 const var_t *field;
2471 LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
2472 if (!strcmp(e->u.sval, field->name))
2474 fprintf(h, "%s->%s", structvar, e->u.sval);
2475 break;
2478 if (&field->entry == fields) error("no field found for identifier %s\n", e->u.sval);
2479 break;
2481 case EXPR_NEG:
2482 fprintf(h, "-");
2483 write_struct_expr(h, e->ref, 1, fields, structvar);
2484 break;
2485 case EXPR_NOT:
2486 fprintf(h, "~");
2487 write_struct_expr(h, e->ref, 1, fields, structvar);
2488 break;
2489 case EXPR_PPTR:
2490 fprintf(h, "*");
2491 write_struct_expr(h, e->ref, 1, fields, structvar);
2492 break;
2493 case EXPR_CAST:
2494 fprintf(h, "(");
2495 write_type(h, e->u.tref);
2496 fprintf(h, ")");
2497 write_struct_expr(h, e->ref, 1, fields, structvar);
2498 break;
2499 case EXPR_SIZEOF:
2500 fprintf(h, "sizeof(");
2501 write_type(h, e->u.tref);
2502 fprintf(h, ")");
2503 break;
2504 case EXPR_SHL:
2505 case EXPR_SHR:
2506 case EXPR_MUL:
2507 case EXPR_DIV:
2508 case EXPR_ADD:
2509 case EXPR_SUB:
2510 case EXPR_AND:
2511 case EXPR_OR:
2512 if (brackets) fprintf(h, "(");
2513 write_struct_expr(h, e->ref, 1, fields, structvar);
2514 switch (e->type) {
2515 case EXPR_SHL: fprintf(h, " << "); break;
2516 case EXPR_SHR: fprintf(h, " >> "); break;
2517 case EXPR_MUL: fprintf(h, " * "); break;
2518 case EXPR_DIV: fprintf(h, " / "); break;
2519 case EXPR_ADD: fprintf(h, " + "); break;
2520 case EXPR_SUB: fprintf(h, " - "); break;
2521 case EXPR_AND: fprintf(h, " & "); break;
2522 case EXPR_OR: fprintf(h, " | "); break;
2523 default: break;
2525 write_struct_expr(h, e->u.ext, 1, fields, structvar);
2526 if (brackets) fprintf(h, ")");
2527 break;
2528 case EXPR_COND:
2529 if (brackets) fprintf(h, "(");
2530 write_struct_expr(h, e->ref, 1, fields, structvar);
2531 fprintf(h, " ? ");
2532 write_struct_expr(h, e->u.ext, 1, fields, structvar);
2533 fprintf(h, " : ");
2534 write_struct_expr(h, e->ext2, 1, fields, structvar);
2535 if (brackets) fprintf(h, ")");
2536 break;
2541 void declare_stub_args( FILE *file, int indent, const func_t *func )
2543 int in_attr, out_attr;
2544 int i = 0;
2545 const var_t *def = func->def;
2546 const var_t *var;
2548 /* declare return value '_RetVal' */
2549 if (!is_void(def->type))
2551 print_file(file, indent, "");
2552 write_type(file, def->type);
2553 fprintf(file, " _RetVal;\n");
2556 if (!func->args)
2557 return;
2559 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2561 const expr_list_t *size_is = get_attrp(var->attrs, ATTR_SIZEIS);
2562 int has_size = is_non_void(size_is);
2563 int is_string = is_attr(var->attrs, ATTR_STRING);
2565 in_attr = is_attr(var->attrs, ATTR_IN);
2566 out_attr = is_attr(var->attrs, ATTR_OUT);
2567 if (!out_attr && !in_attr)
2568 in_attr = 1;
2570 if (!in_attr && !has_size && !is_string)
2572 print_file(file, indent, "");
2573 write_type(file, var->type->ref);
2574 fprintf(file, " _W%u;\n", i++);
2577 print_file(file, indent, "");
2578 write_type(file, var->type);
2579 fprintf(file, " ");
2580 if (var->array) {
2581 fprintf(file, "( *");
2582 write_name(file, var);
2583 fprintf(file, " )");
2584 } else
2585 write_name(file, var);
2586 write_array(file, var->array, 0);
2587 fprintf(file, ";\n");
2592 void assign_stub_out_args( FILE *file, int indent, const func_t *func )
2594 int in_attr, out_attr;
2595 int i = 0, sep = 0;
2596 const var_t *var;
2597 const expr_list_t *size_is;
2598 int has_size;
2600 if (!func->args)
2601 return;
2603 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2605 int is_string = is_attr(var->attrs, ATTR_STRING);
2606 size_is = get_attrp(var->attrs, ATTR_SIZEIS);
2607 has_size = is_non_void(size_is);
2608 in_attr = is_attr(var->attrs, ATTR_IN);
2609 out_attr = is_attr(var->attrs, ATTR_OUT);
2610 if (!out_attr && !in_attr)
2611 in_attr = 1;
2613 if (!in_attr)
2615 print_file(file, indent, "");
2616 write_name(file, var);
2618 if (has_size)
2620 const expr_t *expr;
2621 unsigned int size, align = 0;
2622 type_t *type = var->type;
2624 fprintf(file, " = NdrAllocate(&_StubMsg, ");
2625 LIST_FOR_EACH_ENTRY( expr, size_is, const expr_t, entry )
2627 if (expr->type == EXPR_VOID) continue;
2628 write_expr( file, expr, 1 );
2629 fprintf(file, " * ");
2631 size = type_memsize(type, NULL, &align);
2632 fprintf(file, "%u);\n", size);
2634 else if (!is_string)
2636 fprintf(file, " = &_W%u;\n", i);
2637 if (is_ptr(var->type) && !last_ptr(var->type))
2638 print_file(file, indent, "_W%u = 0;\n", i);
2639 i++;
2642 sep = 1;
2645 if (sep)
2646 fprintf(file, "\n");
2650 int write_expr_eval_routines(FILE *file, const char *iface)
2652 int result = 0;
2653 struct expr_eval_routine *eval;
2654 unsigned short callback_offset = 0;
2656 LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
2658 int indent = 0;
2659 result = 1;
2660 print_file(file, indent, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
2661 iface, eval->structure->name, callback_offset);
2662 print_file(file, indent, "{\n");
2663 indent++;
2664 print_file(file, indent, "struct %s *" STRUCT_EXPR_EVAL_VAR " = (struct %s *)(pStubMsg->StackTop - %u);\n",
2665 eval->structure->name, eval->structure->name, eval->structure_size);
2666 fprintf(file, "\n");
2667 print_file(file, indent, "pStubMsg->Offset = 0;\n"); /* FIXME */
2668 print_file(file, indent, "pStubMsg->MaxCount = (unsigned long)");
2669 write_struct_expr(file, eval->expr, 1, eval->structure->fields, STRUCT_EXPR_EVAL_VAR);
2670 fprintf(file, ";\n");
2671 indent--;
2672 print_file(file, indent, "}\n\n");
2673 callback_offset++;
2675 return result;
2678 void write_expr_eval_routine_list(FILE *file, const char *iface)
2680 struct expr_eval_routine *eval;
2681 struct expr_eval_routine *cursor;
2682 unsigned short callback_offset = 0;
2684 fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
2685 fprintf(file, "{\n");
2687 LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
2689 print_file(file, 1, "%s_%sExprEval_%04u,\n",
2690 iface, eval->structure->name, callback_offset);
2692 callback_offset++;
2693 list_remove(&eval->entry);
2694 free(eval);
2697 fprintf(file, "};\n\n");
2701 void write_endpoints( FILE *f, const char *prefix, const str_list_t *list )
2703 const struct str_list_entry_t *endpoint;
2704 const char *p;
2706 /* this should be an array of RPC_PROTSEQ_ENDPOINT but we want const strings */
2707 print_file( f, 0, "static const unsigned char * %s__RpcProtseqEndpoint[][2] =\n{\n", prefix );
2708 LIST_FOR_EACH_ENTRY( endpoint, list, const struct str_list_entry_t, entry )
2710 print_file( f, 1, "{ (const unsigned char *)\"" );
2711 for (p = endpoint->str; *p && *p != ':'; p++)
2713 if (*p == '"' || *p == '\\') fputc( '\\', f );
2714 fputc( *p, f );
2716 if (!*p) goto error;
2717 if (p[1] != '[') goto error;
2719 fprintf( f, "\", (const unsigned char *)\"" );
2720 for (p += 2; *p && *p != ']'; p++)
2722 if (*p == '"' || *p == '\\') fputc( '\\', f );
2723 fputc( *p, f );
2725 if (*p != ']') goto error;
2726 fprintf( f, "\" },\n" );
2728 print_file( f, 0, "};\n\n" );
2729 return;
2731 error:
2732 error("Invalid endpoint syntax '%s'\n", endpoint->str);