widl: Add a function to get the return type of a parsed function.
[wine/multimedia.git] / tools / widl / typegen.c
blob203258d3d29d4f19e72502f303eba58c33e6cd30
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 <limits.h>
35 #include "widl.h"
36 #include "utils.h"
37 #include "parser.h"
38 #include "header.h"
39 #include "wine/list.h"
41 #include "typegen.h"
43 static const func_t *current_func;
44 static const type_t *current_structure;
45 static const ifref_t *current_iface;
47 static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
48 struct expr_eval_routine
50 struct list entry;
51 const type_t *structure;
52 unsigned int baseoff;
53 const expr_t *expr;
56 static size_t fields_memsize(const var_list_t *fields, unsigned int *align);
57 static size_t write_struct_tfs(FILE *file, type_t *type, const char *name, unsigned int *tfsoff);
58 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
59 const char *name, int write_ptr, unsigned int *tfsoff);
60 static const var_t *find_array_or_string_in_struct(const type_t *type);
61 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
62 type_t *type,
63 const char *name, unsigned int *typestring_offset);
65 const char *string_of_type(unsigned char type)
67 switch (type)
69 case RPC_FC_BYTE: return "FC_BYTE";
70 case RPC_FC_CHAR: return "FC_CHAR";
71 case RPC_FC_SMALL: return "FC_SMALL";
72 case RPC_FC_USMALL: return "FC_USMALL";
73 case RPC_FC_WCHAR: return "FC_WCHAR";
74 case RPC_FC_SHORT: return "FC_SHORT";
75 case RPC_FC_USHORT: return "FC_USHORT";
76 case RPC_FC_LONG: return "FC_LONG";
77 case RPC_FC_ULONG: return "FC_ULONG";
78 case RPC_FC_FLOAT: return "FC_FLOAT";
79 case RPC_FC_HYPER: return "FC_HYPER";
80 case RPC_FC_DOUBLE: return "FC_DOUBLE";
81 case RPC_FC_ENUM16: return "FC_ENUM16";
82 case RPC_FC_ENUM32: return "FC_ENUM32";
83 case RPC_FC_IGNORE: return "FC_IGNORE";
84 case RPC_FC_ERROR_STATUS_T: return "FC_ERROR_STATUS_T";
85 case RPC_FC_RP: return "FC_RP";
86 case RPC_FC_UP: return "FC_UP";
87 case RPC_FC_OP: return "FC_OP";
88 case RPC_FC_FP: return "FC_FP";
89 case RPC_FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION";
90 case RPC_FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION";
91 case RPC_FC_STRUCT: return "FC_STRUCT";
92 case RPC_FC_PSTRUCT: return "FC_PSTRUCT";
93 case RPC_FC_CSTRUCT: return "FC_CSTRUCT";
94 case RPC_FC_CPSTRUCT: return "FC_CPSTRUCT";
95 case RPC_FC_CVSTRUCT: return "FC_CVSTRUCT";
96 case RPC_FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT";
97 case RPC_FC_SMFARRAY: return "FC_SMFARRAY";
98 case RPC_FC_LGFARRAY: return "FC_LGFARRAY";
99 case RPC_FC_SMVARRAY: return "FC_SMVARRAY";
100 case RPC_FC_LGVARRAY: return "FC_LGVARRAY";
101 case RPC_FC_CARRAY: return "FC_CARRAY";
102 case RPC_FC_CVARRAY: return "FC_CVARRAY";
103 case RPC_FC_BOGUS_ARRAY: return "FC_BOGUS_ARRAY";
104 case RPC_FC_ALIGNM4: return "FC_ALIGNM4";
105 case RPC_FC_ALIGNM8: return "FC_ALIGNM8";
106 case RPC_FC_POINTER: return "FC_POINTER";
107 case RPC_FC_C_CSTRING: return "FC_C_CSTRING";
108 case RPC_FC_C_WSTRING: return "FC_C_WSTRING";
109 case RPC_FC_CSTRING: return "FC_CSTRING";
110 case RPC_FC_WSTRING: return "FC_WSTRING";
111 default:
112 error("string_of_type: unknown type 0x%02x\n", type);
113 return NULL;
117 int is_struct(unsigned char type)
119 switch (type)
121 case RPC_FC_STRUCT:
122 case RPC_FC_PSTRUCT:
123 case RPC_FC_CSTRUCT:
124 case RPC_FC_CPSTRUCT:
125 case RPC_FC_CVSTRUCT:
126 case RPC_FC_BOGUS_STRUCT:
127 return 1;
128 default:
129 return 0;
133 static int is_non_complex_struct(const type_t *type)
135 switch (type->type)
137 case RPC_FC_STRUCT:
138 case RPC_FC_PSTRUCT:
139 case RPC_FC_CSTRUCT:
140 case RPC_FC_CPSTRUCT:
141 case RPC_FC_CVSTRUCT:
142 return 1;
143 default:
144 return 0;
148 int is_union(unsigned char type)
150 switch (type)
152 case RPC_FC_ENCAPSULATED_UNION:
153 case RPC_FC_NON_ENCAPSULATED_UNION:
154 return 1;
155 default:
156 return 0;
160 static int type_has_pointers(const type_t *type)
162 if (is_user_type(type))
163 return FALSE;
164 else if (is_ptr(type))
165 return TRUE;
166 else if (is_array(type))
167 return type_has_pointers(type->ref);
168 else if (is_struct(type->type))
170 const var_t *field;
171 if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
173 if (type_has_pointers(field->type))
174 return TRUE;
177 else if (is_union(type->type))
179 var_list_t *fields;
180 const var_t *field;
181 if (type->type == RPC_FC_ENCAPSULATED_UNION)
183 const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
184 fields = uv->type->fields;
186 else
187 fields = type->fields;
188 if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
190 if (field->type && type_has_pointers(field->type))
191 return TRUE;
195 return FALSE;
198 static int type_has_full_pointer(const type_t *type)
200 if (is_user_type(type))
201 return FALSE;
202 else if (type->type == RPC_FC_FP)
203 return TRUE;
204 else if (is_ptr(type))
205 return FALSE;
206 else if (is_array(type))
207 return type_has_full_pointer(type->ref);
208 else if (is_struct(type->type))
210 const var_t *field;
211 if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
213 if (type_has_full_pointer(field->type))
214 return TRUE;
217 else if (is_union(type->type))
219 var_list_t *fields;
220 const var_t *field;
221 if (type->type == RPC_FC_ENCAPSULATED_UNION)
223 const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
224 fields = uv->type->fields;
226 else
227 fields = type->fields;
228 if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
230 if (field->type && type_has_full_pointer(field->type))
231 return TRUE;
235 return FALSE;
238 static unsigned short user_type_offset(const char *name)
240 user_type_t *ut;
241 unsigned short off = 0;
242 LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
244 if (strcmp(name, ut->name) == 0)
245 return off;
246 ++off;
248 error("user_type_offset: couldn't find type (%s)\n", name);
249 return 0;
252 static void update_tfsoff(type_t *type, unsigned int offset, FILE *file)
254 type->typestring_offset = offset;
255 if (file) type->tfswrite = FALSE;
258 static void guard_rec(type_t *type)
260 /* types that contain references to themselves (like a linked list),
261 need to be shielded from infinite recursion when writing embedded
262 types */
263 if (type->typestring_offset)
264 type->tfswrite = FALSE;
265 else
266 type->typestring_offset = 1;
269 static type_t *get_user_type(const type_t *t, const char **pname)
271 for (;;)
273 type_t *ut = get_attrp(t->attrs, ATTR_WIREMARSHAL);
274 if (ut)
276 if (pname)
277 *pname = t->name;
278 return ut;
281 if (t->kind == TKIND_ALIAS)
282 t = t->orig;
283 else
284 return 0;
288 int is_user_type(const type_t *t)
290 return get_user_type(t, NULL) != NULL;
293 static int is_embedded_complex(const type_t *type)
295 unsigned char tc = type->type;
296 return is_struct(tc) || is_union(tc) || is_array(type) || is_user_type(type)
297 || (is_ptr(type) && type->ref->type == RPC_FC_IP);
300 static const char *get_context_handle_type_name(const type_t *type)
302 const type_t *t;
303 for (t = type; is_ptr(t); t = t->ref)
304 if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
305 return t->name;
306 assert(0);
307 return NULL;
310 /* This is actually fairly involved to implement precisely, due to the
311 effects attributes may have and things like that. Right now this is
312 only used for optimization, so just check for a very small set of
313 criteria that guarantee the types are equivalent; assume every thing
314 else is different. */
315 static int compare_type(const type_t *a, const type_t *b)
317 if (a == b
318 || (a->name
319 && b->name
320 && strcmp(a->name, b->name) == 0))
321 return 0;
322 /* Ordering doesn't need to be implemented yet. */
323 return 1;
326 static int compare_expr(const expr_t *a, const expr_t *b)
328 int ret;
330 if (a->type != b->type)
331 return a->type - b->type;
333 switch (a->type)
335 case EXPR_NUM:
336 case EXPR_HEXNUM:
337 case EXPR_TRUEFALSE:
338 return a->u.lval - b->u.lval;
339 case EXPR_DOUBLE:
340 return a->u.dval - b->u.dval;
341 case EXPR_IDENTIFIER:
342 return strcmp(a->u.sval, b->u.sval);
343 case EXPR_COND:
344 ret = compare_expr(a->ref, b->ref);
345 if (ret != 0)
346 return ret;
347 ret = compare_expr(a->u.ext, b->u.ext);
348 if (ret != 0)
349 return ret;
350 return compare_expr(a->ext2, b->ext2);
351 case EXPR_OR:
352 case EXPR_AND:
353 case EXPR_ADD:
354 case EXPR_SUB:
355 case EXPR_MUL:
356 case EXPR_DIV:
357 case EXPR_SHL:
358 case EXPR_SHR:
359 ret = compare_expr(a->ref, b->ref);
360 if (ret != 0)
361 return ret;
362 return compare_expr(a->u.ext, b->u.ext);
363 case EXPR_CAST:
364 ret = compare_type(a->u.tref, b->u.tref);
365 if (ret != 0)
366 return ret;
367 /* Fall through. */
368 case EXPR_NOT:
369 case EXPR_NEG:
370 case EXPR_PPTR:
371 case EXPR_ADDRESSOF:
372 return compare_expr(a->ref, b->ref);
373 case EXPR_SIZEOF:
374 return compare_type(a->u.tref, b->u.tref);
375 case EXPR_VOID:
376 return 0;
378 return -1;
381 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
382 do { \
383 if (file) \
384 fprintf(file, "/* %2u */\n", typestring_offset); \
385 print_file((file), 2, "0x%02x, /* " #fctype " */\n", RPC_##fctype); \
387 while (0)
389 static void print_file(FILE *file, int indent, const char *format, ...)
391 va_list va;
392 va_start(va, format);
393 print(file, indent, format, va);
394 va_end(va);
397 void print(FILE *file, int indent, const char *format, va_list va)
399 if (file)
401 if (format[0] != '\n')
402 while (0 < indent--)
403 fprintf(file, " ");
404 vfprintf(file, format, va);
409 static void write_var_init(FILE *file, int indent, const type_t *t, const char *n)
411 if (decl_indirect(t))
412 print_file(file, indent, "MIDL_memset(&%s, 0, sizeof(%s));\n", n, n);
413 else if (is_ptr(t) || is_array(t))
414 print_file(file, indent, "%s = 0;\n", n);
417 void write_parameters_init(FILE *file, int indent, const func_t *func)
419 const var_t *var;
421 if (!is_void(get_func_return_type(func)))
422 write_var_init(file, indent, get_func_return_type(func), "_RetVal");
424 if (!func->args)
425 return;
427 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
428 write_var_init(file, indent, var->type, var->name);
430 fprintf(file, "\n");
433 static void write_formatdesc(FILE *f, int indent, const char *str)
435 print_file(f, indent, "typedef struct _MIDL_%s_FORMAT_STRING\n", str);
436 print_file(f, indent, "{\n");
437 print_file(f, indent + 1, "short Pad;\n");
438 print_file(f, indent + 1, "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str);
439 print_file(f, indent, "} MIDL_%s_FORMAT_STRING;\n", str);
440 print_file(f, indent, "\n");
443 void write_formatstringsdecl(FILE *f, int indent, ifref_list_t *ifaces, type_pred_t pred)
445 print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n",
446 get_size_typeformatstring(ifaces, pred));
448 print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n",
449 get_size_procformatstring(ifaces, pred));
451 fprintf(f, "\n");
452 write_formatdesc(f, indent, "TYPE");
453 write_formatdesc(f, indent, "PROC");
454 fprintf(f, "\n");
455 print_file(f, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n");
456 print_file(f, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n");
457 print_file(f, indent, "\n");
460 static inline int is_base_type(unsigned char type)
462 switch (type)
464 case RPC_FC_BYTE:
465 case RPC_FC_CHAR:
466 case RPC_FC_USMALL:
467 case RPC_FC_SMALL:
468 case RPC_FC_WCHAR:
469 case RPC_FC_USHORT:
470 case RPC_FC_SHORT:
471 case RPC_FC_ULONG:
472 case RPC_FC_LONG:
473 case RPC_FC_HYPER:
474 case RPC_FC_IGNORE:
475 case RPC_FC_FLOAT:
476 case RPC_FC_DOUBLE:
477 case RPC_FC_ENUM16:
478 case RPC_FC_ENUM32:
479 case RPC_FC_ERROR_STATUS_T:
480 case RPC_FC_BIND_PRIMITIVE:
481 return TRUE;
483 default:
484 return FALSE;
488 int decl_indirect(const type_t *t)
490 return is_user_type(t)
491 || (!is_base_type(t->type)
492 && !is_ptr(t)
493 && !is_array(t));
496 static size_t write_procformatstring_type(FILE *file, int indent,
497 const char *name,
498 const type_t *type,
499 const attr_list_t *attrs,
500 int is_return)
502 size_t size;
504 int is_in = is_attr(attrs, ATTR_IN);
505 int is_out = is_attr(attrs, ATTR_OUT);
507 if (!is_in && !is_out) is_in = TRUE;
509 if (!type->declarray && is_base_type(type->type))
511 if (is_return)
512 print_file(file, indent, "0x53, /* FC_RETURN_PARAM_BASETYPE */\n");
513 else
514 print_file(file, indent, "0x4e, /* FC_IN_PARAM_BASETYPE */\n");
516 if (type->type == RPC_FC_BIND_PRIMITIVE)
518 print_file(file, indent, "0x%02x, /* FC_IGNORE */\n", RPC_FC_IGNORE);
519 size = 2; /* includes param type prefix */
521 else if (is_base_type(type->type))
523 print_file(file, indent, "0x%02x, /* %s */\n", type->type, string_of_type(type->type));
524 size = 2; /* includes param type prefix */
526 else
528 error("Unknown/unsupported type: %s (0x%02x)\n", name, type->type);
529 size = 0;
532 else
534 if (is_return)
535 print_file(file, indent, "0x52, /* FC_RETURN_PARAM */\n");
536 else if (is_in && is_out)
537 print_file(file, indent, "0x50, /* FC_IN_OUT_PARAM */\n");
538 else if (is_out)
539 print_file(file, indent, "0x51, /* FC_OUT_PARAM */\n");
540 else
541 print_file(file, indent, "0x4d, /* FC_IN_PARAM */\n");
543 print_file(file, indent, "0x01,\n");
544 print_file(file, indent, "NdrFcShort(0x%x),\n", type->typestring_offset);
545 size = 4; /* includes param type prefix */
547 return size;
550 void write_procformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
552 const ifref_t *iface;
553 int indent = 0;
554 const var_t *var;
556 print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
557 print_file(file, indent, "{\n");
558 indent++;
559 print_file(file, indent, "0,\n");
560 print_file(file, indent, "{\n");
561 indent++;
563 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
565 if (!pred(iface->iface))
566 continue;
568 if (iface->iface->funcs)
570 const func_t *func;
571 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
573 if (is_local(func->def->attrs)) continue;
574 /* emit argument data */
575 if (func->args)
577 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
578 write_procformatstring_type(file, indent, var->name, var->type, var->attrs, FALSE);
581 /* emit return value data */
582 if (is_void(get_func_return_type(func)))
584 print_file(file, indent, "0x5b, /* FC_END */\n");
585 print_file(file, indent, "0x5c, /* FC_PAD */\n");
587 else
588 write_procformatstring_type(file, indent, "return value", get_func_return_type(func), NULL, TRUE);
593 print_file(file, indent, "0x0\n");
594 indent--;
595 print_file(file, indent, "}\n");
596 indent--;
597 print_file(file, indent, "};\n");
598 print_file(file, indent, "\n");
601 static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
603 if (is_base_type(type->type))
605 print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
606 *typestring_offset += 1;
607 return 1;
610 return 0;
613 /* write conformance / variance descriptor */
614 static size_t write_conf_or_var_desc(FILE *file, const type_t *structure,
615 unsigned int baseoff, const type_t *type,
616 const expr_t *expr)
618 unsigned char operator_type = 0;
619 unsigned char conftype = RPC_FC_NORMAL_CONFORMANCE;
620 const char *conftype_string = "";
621 const char *operator_string = "no operators";
622 const expr_t *subexpr;
624 if (!expr)
626 print_file(file, 2, "NdrFcLong(0xffffffff),\t/* -1 */\n");
627 return 4;
630 if (!structure)
632 /* Top-level conformance calculations are done inline. */
633 print_file (file, 2, "0x%x,\t/* Corr desc: parameter */\n",
634 RPC_FC_TOP_LEVEL_CONFORMANCE);
635 print_file (file, 2, "0x0,\n");
636 print_file (file, 2, "NdrFcShort(0x0),\n");
637 return 4;
640 if (expr->is_const)
642 if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
643 error("write_conf_or_var_desc: constant value %ld is greater than "
644 "the maximum constant size of %d\n", expr->cval,
645 UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
647 print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n",
648 RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
649 print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX);
650 print_file(file, 2, "NdrFcShort(0x%x),\n", expr->cval & USHRT_MAX);
652 return 4;
655 if (is_ptr(type) || (is_array(type) && !type->declarray))
657 conftype = RPC_FC_POINTER_CONFORMANCE;
658 conftype_string = "field pointer, ";
661 subexpr = expr;
662 switch (subexpr->type)
664 case EXPR_PPTR:
665 subexpr = subexpr->ref;
666 operator_type = RPC_FC_DEREFERENCE;
667 operator_string = "FC_DEREFERENCE";
668 break;
669 case EXPR_DIV:
670 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
672 subexpr = subexpr->ref;
673 operator_type = RPC_FC_DIV_2;
674 operator_string = "FC_DIV_2";
676 break;
677 case EXPR_MUL:
678 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
680 subexpr = subexpr->ref;
681 operator_type = RPC_FC_MULT_2;
682 operator_string = "FC_MULT_2";
684 break;
685 case EXPR_SUB:
686 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
688 subexpr = subexpr->ref;
689 operator_type = RPC_FC_SUB_1;
690 operator_string = "FC_SUB_1";
692 break;
693 case EXPR_ADD:
694 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
696 subexpr = subexpr->ref;
697 operator_type = RPC_FC_ADD_1;
698 operator_string = "FC_ADD_1";
700 break;
701 default:
702 break;
705 if (subexpr->type == EXPR_IDENTIFIER)
707 const type_t *correlation_variable = NULL;
708 unsigned char correlation_variable_type;
709 unsigned char param_type = 0;
710 size_t offset = 0;
711 const var_t *var;
713 if (structure->fields) LIST_FOR_EACH_ENTRY( var, structure->fields, const var_t, entry )
715 unsigned int align = 0;
716 /* FIXME: take alignment into account */
717 if (var->name && !strcmp(var->name, subexpr->u.sval))
719 correlation_variable = var->type;
720 break;
722 offset += type_memsize(var->type, &align);
724 if (!correlation_variable)
725 error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
726 subexpr->u.sval);
728 offset -= baseoff;
729 correlation_variable_type = correlation_variable->type;
731 switch (correlation_variable_type)
733 case RPC_FC_CHAR:
734 case RPC_FC_SMALL:
735 param_type = RPC_FC_SMALL;
736 break;
737 case RPC_FC_BYTE:
738 case RPC_FC_USMALL:
739 param_type = RPC_FC_USMALL;
740 break;
741 case RPC_FC_WCHAR:
742 case RPC_FC_SHORT:
743 case RPC_FC_ENUM16:
744 param_type = RPC_FC_SHORT;
745 break;
746 case RPC_FC_USHORT:
747 param_type = RPC_FC_USHORT;
748 break;
749 case RPC_FC_LONG:
750 case RPC_FC_ENUM32:
751 param_type = RPC_FC_LONG;
752 break;
753 case RPC_FC_ULONG:
754 param_type = RPC_FC_ULONG;
755 break;
756 case RPC_FC_RP:
757 case RPC_FC_UP:
758 case RPC_FC_OP:
759 case RPC_FC_FP:
760 if (sizeof(void *) == 4) /* FIXME */
761 param_type = RPC_FC_LONG;
762 else
763 param_type = RPC_FC_HYPER;
764 break;
765 default:
766 error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
767 correlation_variable_type);
770 print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
771 conftype | param_type, conftype_string, string_of_type(param_type));
772 print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string);
773 print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d */\n",
774 offset, offset);
776 else
778 unsigned int callback_offset = 0;
779 struct expr_eval_routine *eval;
780 int found = 0;
782 LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
784 if (!strcmp (eval->structure->name, structure->name)
785 && !compare_expr (eval->expr, expr))
787 found = 1;
788 break;
790 callback_offset++;
793 if (!found)
795 eval = xmalloc (sizeof(*eval));
796 eval->structure = structure;
797 eval->baseoff = baseoff;
798 eval->expr = expr;
799 list_add_tail (&expr_eval_routines, &eval->entry);
802 if (callback_offset > USHRT_MAX)
803 error("Maximum number of callback routines reached\n");
805 print_file(file, 2, "0x%x, /* Corr desc: %s */\n", conftype, conftype_string);
806 print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
807 print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", callback_offset, callback_offset);
809 return 4;
812 static size_t fields_memsize(const var_list_t *fields, unsigned int *align)
814 int have_align = FALSE;
815 size_t size = 0;
816 const var_t *v;
818 if (!fields) return 0;
819 LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
821 unsigned int falign = 0;
822 size_t fsize = type_memsize(v->type, &falign);
823 if (!have_align)
825 *align = falign;
826 have_align = TRUE;
828 size = (size + (falign - 1)) & ~(falign - 1);
829 size += fsize;
832 size = (size + (*align - 1)) & ~(*align - 1);
833 return size;
836 static size_t union_memsize(const var_list_t *fields, unsigned int *pmaxa)
838 size_t size, maxs = 0;
839 unsigned int align = *pmaxa;
840 const var_t *v;
842 if (fields) LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
844 /* we could have an empty default field with NULL type */
845 if (v->type)
847 size = type_memsize(v->type, &align);
848 if (maxs < size) maxs = size;
849 if (*pmaxa < align) *pmaxa = align;
853 return maxs;
856 int get_padding(const var_list_t *fields)
858 unsigned short offset = 0;
859 int salign = -1;
860 const var_t *f;
862 if (!fields)
863 return 0;
865 LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry)
867 type_t *ft = f->type;
868 unsigned int align = 0;
869 size_t size = type_memsize(ft, &align);
870 if (salign == -1)
871 salign = align;
872 offset = (offset + (align - 1)) & ~(align - 1);
873 offset += size;
876 return ((offset + (salign - 1)) & ~(salign - 1)) - offset;
879 size_t type_memsize(const type_t *t, unsigned int *align)
881 size_t size = 0;
883 if (t->declarray && is_conformant_array(t))
885 type_memsize(t->ref, align);
886 size = 0;
888 else if (is_ptr(t) || is_conformant_array(t))
890 size = sizeof(void *);
891 if (size > *align) *align = size;
893 else switch (t->type)
895 case RPC_FC_BYTE:
896 case RPC_FC_CHAR:
897 case RPC_FC_USMALL:
898 case RPC_FC_SMALL:
899 size = 1;
900 if (size > *align) *align = size;
901 break;
902 case RPC_FC_WCHAR:
903 case RPC_FC_USHORT:
904 case RPC_FC_SHORT:
905 case RPC_FC_ENUM16:
906 size = 2;
907 if (size > *align) *align = size;
908 break;
909 case RPC_FC_ULONG:
910 case RPC_FC_LONG:
911 case RPC_FC_ERROR_STATUS_T:
912 case RPC_FC_ENUM32:
913 case RPC_FC_FLOAT:
914 size = 4;
915 if (size > *align) *align = size;
916 break;
917 case RPC_FC_HYPER:
918 case RPC_FC_DOUBLE:
919 size = 8;
920 if (size > *align) *align = size;
921 break;
922 case RPC_FC_STRUCT:
923 case RPC_FC_CVSTRUCT:
924 case RPC_FC_CPSTRUCT:
925 case RPC_FC_CSTRUCT:
926 case RPC_FC_PSTRUCT:
927 case RPC_FC_BOGUS_STRUCT:
928 size = fields_memsize(t->fields, align);
929 break;
930 case RPC_FC_ENCAPSULATED_UNION:
931 case RPC_FC_NON_ENCAPSULATED_UNION:
932 size = union_memsize(t->fields, align);
933 break;
934 case RPC_FC_SMFARRAY:
935 case RPC_FC_LGFARRAY:
936 case RPC_FC_SMVARRAY:
937 case RPC_FC_LGVARRAY:
938 case RPC_FC_BOGUS_ARRAY:
939 size = t->dim * type_memsize(t->ref, align);
940 break;
941 default:
942 error("type_memsize: Unknown type %d\n", t->type);
943 size = 0;
946 return size;
949 int is_full_pointer_function(const func_t *func)
951 const var_t *var;
952 if (type_has_full_pointer(get_func_return_type(func)))
953 return TRUE;
954 if (!func->args)
955 return FALSE;
956 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
957 if (type_has_full_pointer( var->type ))
958 return TRUE;
959 return FALSE;
962 void write_full_pointer_init(FILE *file, int indent, const func_t *func, int is_server)
964 print_file(file, indent, "_StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,%s);\n",
965 is_server ? "XLAT_SERVER" : "XLAT_CLIENT");
966 fprintf(file, "\n");
969 void write_full_pointer_free(FILE *file, int indent, const func_t *func)
971 print_file(file, indent, "NdrFullPointerXlatFree(_StubMsg.FullPtrXlatTables);\n");
972 fprintf(file, "\n");
975 static unsigned int write_nonsimple_pointer(FILE *file, const type_t *type, size_t offset)
977 short absoff = type->ref->typestring_offset;
978 short reloff = absoff - (offset + 2);
979 int ptr_attr = is_ptr(type->ref) ? 0x10 : 0x0;
981 print_file(file, 2, "0x%02x, 0x%x,\t/* %s */\n",
982 type->type, ptr_attr, string_of_type(type->type));
983 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%hd) */\n",
984 reloff, reloff, absoff);
985 return 4;
988 static unsigned int write_simple_pointer(FILE *file, const type_t *type)
990 unsigned char fc = type->ref->type;
991 /* for historical reasons, write_simple_pointer also handled string types,
992 * but no longer does. catch bad uses of the function with this check */
993 if (is_string_type(type->attrs, type))
994 error("write_simple_pointer: can't handle type %s which is a string type\n", type->name);
995 print_file(file, 2, "0x%02x, 0x8,\t/* %s [simple_pointer] */\n",
996 type->type, string_of_type(type->type));
997 print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
998 print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
999 return 4;
1002 static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff)
1004 print_file(file, 0, "/* %u (", tfsoff);
1005 write_type_decl(file, t, NULL);
1006 print_file(file, 0, ") */\n");
1009 static size_t write_pointer_tfs(FILE *file, type_t *type, unsigned int *typestring_offset)
1011 unsigned int offset = *typestring_offset;
1013 print_start_tfs_comment(file, type, offset);
1014 update_tfsoff(type, offset, file);
1016 if (type->ref->typestring_offset)
1017 *typestring_offset += write_nonsimple_pointer(file, type, offset);
1018 else if (is_base_type(type->ref->type))
1019 *typestring_offset += write_simple_pointer(file, type);
1021 return offset;
1024 static int processed(const type_t *type)
1026 return type->typestring_offset && !type->tfswrite;
1029 static int user_type_has_variable_size(const type_t *t)
1031 if (is_ptr(t))
1032 return TRUE;
1033 else
1034 switch (t->type)
1036 case RPC_FC_PSTRUCT:
1037 case RPC_FC_CSTRUCT:
1038 case RPC_FC_CPSTRUCT:
1039 case RPC_FC_CVSTRUCT:
1040 return TRUE;
1042 /* Note: Since this only applies to user types, we can't have a conformant
1043 array here, and strings should get filed under pointer in this case. */
1044 return FALSE;
1047 static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
1049 unsigned int start, absoff, flags;
1050 unsigned int align = 0, ualign = 0;
1051 const char *name;
1052 type_t *utype = get_user_type(type, &name);
1053 size_t usize = user_type_has_variable_size(utype) ? 0 : type_memsize(utype, &ualign);
1054 size_t size = type_memsize(type, &align);
1055 unsigned short funoff = user_type_offset(name);
1056 short reloff;
1058 guard_rec(type);
1060 if (is_base_type(utype->type))
1062 absoff = *tfsoff;
1063 print_start_tfs_comment(file, utype, absoff);
1064 print_file(file, 2, "0x%x,\t/* %s */\n", utype->type, string_of_type(utype->type));
1065 print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
1066 *tfsoff += 2;
1068 else
1070 if (!processed(utype))
1071 write_embedded_types(file, NULL, utype, utype->name, TRUE, tfsoff);
1072 absoff = utype->typestring_offset;
1075 if (utype->type == RPC_FC_RP)
1076 flags = 0x40;
1077 else if (utype->type == RPC_FC_UP)
1078 flags = 0x80;
1079 else
1080 flags = 0;
1082 start = *tfsoff;
1083 update_tfsoff(type, start, file);
1084 print_start_tfs_comment(file, type, start);
1085 print_file(file, 2, "0x%x,\t/* FC_USER_MARSHAL */\n", RPC_FC_USER_MARSHAL);
1086 print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
1087 flags | (align - 1), align - 1, flags);
1088 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
1089 print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", size, size);
1090 print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize);
1091 *tfsoff += 8;
1092 reloff = absoff - *tfsoff;
1093 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", reloff, reloff, absoff);
1094 *tfsoff += 2;
1097 static void write_member_type(FILE *file, const type_t *cont,
1098 const attr_list_t *attrs, const type_t *type,
1099 unsigned int *corroff, unsigned int *tfsoff)
1101 if (is_embedded_complex(type) && !is_conformant_array(type))
1103 size_t absoff;
1104 short reloff;
1106 if (is_union(type->type) && is_attr(attrs, ATTR_SWITCHIS))
1108 absoff = *corroff;
1109 *corroff += 8;
1111 else
1113 absoff = type->typestring_offset;
1115 reloff = absoff - (*tfsoff + 2);
1117 print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
1118 /* FIXME: actually compute necessary padding */
1119 print_file(file, 2, "0x0,\t/* FIXME: padding */\n");
1120 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1121 reloff, reloff, absoff);
1122 *tfsoff += 4;
1124 else if (is_ptr(type) || is_conformant_array(type))
1126 unsigned char fc = (cont->type == RPC_FC_BOGUS_STRUCT
1127 ? RPC_FC_POINTER
1128 : RPC_FC_LONG);
1129 print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1130 *tfsoff += 1;
1132 else if (!write_base_type(file, type, tfsoff))
1133 error("Unsupported member type 0x%x\n", type->type);
1136 static void write_end(FILE *file, unsigned int *tfsoff)
1138 if (*tfsoff % 2 == 0)
1140 print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD);
1141 *tfsoff += 1;
1143 print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END);
1144 *tfsoff += 1;
1147 static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
1149 unsigned int offset = 0;
1150 var_list_t *fs = type->fields;
1151 var_t *f;
1153 if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
1155 unsigned int align = 0;
1156 type_t *ft = f->type;
1157 if (is_union(ft->type) && is_attr(f->attrs, ATTR_SWITCHIS))
1159 unsigned int absoff = ft->typestring_offset;
1160 short reloff = absoff - (*tfsoff + 6);
1161 print_file(file, 0, "/* %d */\n", *tfsoff);
1162 print_file(file, 2, "0x%x,\t/* %s */\n", ft->type, string_of_type(ft->type));
1163 print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", RPC_FC_LONG);
1164 write_conf_or_var_desc(file, current_structure, offset, ft,
1165 get_attrp(f->attrs, ATTR_SWITCHIS));
1166 print_file(file, 2, "NdrFcShort(%hd),\t/* Offset= %hd (%u) */\n",
1167 reloff, reloff, absoff);
1168 *tfsoff += 8;
1171 /* FIXME: take alignment into account */
1172 offset += type_memsize(ft, &align);
1176 static int write_no_repeat_pointer_descriptions(
1177 FILE *file, type_t *type,
1178 size_t *offset_in_memory, size_t *offset_in_buffer,
1179 unsigned int *typestring_offset)
1181 int written = 0;
1182 unsigned int align;
1184 if (is_ptr(type) || (!type->declarray && is_conformant_array(type)))
1186 print_file(file, 2, "0x%02x, /* FC_NO_REPEAT */\n", RPC_FC_NO_REPEAT);
1187 print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1189 /* pointer instance */
1190 print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1191 print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1192 *typestring_offset += 6;
1194 if (is_ptr(type))
1196 if (is_string_type(type->attrs, type))
1197 write_string_tfs(file, NULL, type, NULL, typestring_offset);
1198 else
1199 write_pointer_tfs(file, type, typestring_offset);
1201 else
1203 unsigned absoff = type->typestring_offset;
1204 short reloff = absoff - (*typestring_offset + 2);
1205 /* FIXME: get pointer attributes from field */
1206 print_file(file, 2, "0x%02x, 0x0,\t/* %s */\n", RPC_FC_UP, "FC_UP");
1207 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1208 reloff, reloff, absoff);
1209 *typestring_offset += 4;
1212 align = 0;
1213 *offset_in_memory += type_memsize(type, &align);
1214 /* FIXME: is there a case where these two are different? */
1215 align = 0;
1216 *offset_in_buffer += type_memsize(type, &align);
1218 return 1;
1221 if (is_non_complex_struct(type))
1223 const var_t *v;
1224 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1225 written += write_no_repeat_pointer_descriptions(
1226 file, v->type,
1227 offset_in_memory, offset_in_buffer, typestring_offset);
1229 else
1231 align = 0;
1232 *offset_in_memory += type_memsize(type, &align);
1233 /* FIXME: is there a case where these two are different? */
1234 align = 0;
1235 *offset_in_buffer += type_memsize(type, &align);
1238 return written;
1241 static int write_pointer_description_offsets(
1242 FILE *file, const attr_list_t *attrs, type_t *type,
1243 size_t *offset_in_memory, size_t *offset_in_buffer,
1244 unsigned int *typestring_offset)
1246 int written = 0;
1247 unsigned int align;
1249 if (is_ptr(type) && type->ref->type != RPC_FC_IP)
1251 if (offset_in_memory && offset_in_buffer)
1253 /* pointer instance */
1254 /* FIXME: sometimes from end of structure, sometimes from beginning */
1255 print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1256 print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1258 align = 0;
1259 *offset_in_memory += type_memsize(type, &align);
1260 /* FIXME: is there a case where these two are different? */
1261 align = 0;
1262 *offset_in_buffer += type_memsize(type, &align);
1264 *typestring_offset += 4;
1266 if (is_string_type(attrs, type))
1267 write_string_tfs(file, NULL, type, NULL, typestring_offset);
1268 else if (processed(type->ref) || is_base_type(type->ref->type))
1269 write_pointer_tfs(file, type, typestring_offset);
1270 else
1271 error("write_pointer_description_offsets: type format string unknown\n");
1273 return 1;
1276 if (is_array(type))
1278 return write_pointer_description_offsets(
1279 file, attrs, type->ref, offset_in_memory, offset_in_buffer,
1280 typestring_offset);
1282 else if (is_non_complex_struct(type))
1284 /* otherwise search for interesting fields to parse */
1285 const var_t *v;
1286 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1288 written += write_pointer_description_offsets(
1289 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1290 typestring_offset);
1293 else
1295 align = 0;
1296 if (offset_in_memory)
1297 *offset_in_memory += type_memsize(type, &align);
1298 /* FIXME: is there a case where these two are different? */
1299 align = 0;
1300 if (offset_in_buffer)
1301 *offset_in_buffer += type_memsize(type, &align);
1304 return written;
1307 /* Note: if file is NULL return value is number of pointers to write, else
1308 * it is the number of type format characters written */
1309 static int write_fixed_array_pointer_descriptions(
1310 FILE *file, const attr_list_t *attrs, type_t *type,
1311 size_t *offset_in_memory, size_t *offset_in_buffer,
1312 unsigned int *typestring_offset)
1314 unsigned int align;
1315 int pointer_count = 0;
1317 if (type->type == RPC_FC_SMFARRAY || type->type == RPC_FC_LGFARRAY)
1319 unsigned int temp = 0;
1320 /* unfortunately, this needs to be done in two passes to avoid
1321 * writing out redundant FC_FIXED_REPEAT descriptions */
1322 pointer_count = write_pointer_description_offsets(
1323 NULL, attrs, type->ref, NULL, NULL, &temp);
1324 if (pointer_count > 0)
1326 unsigned int increment_size;
1327 size_t offset_of_array_pointer_mem = 0;
1328 size_t offset_of_array_pointer_buf = 0;
1330 align = 0;
1331 increment_size = type_memsize(type->ref, &align);
1333 print_file(file, 2, "0x%02x, /* FC_FIXED_REPEAT */\n", RPC_FC_FIXED_REPEAT);
1334 print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1335 print_file(file, 2, "NdrFcShort(0x%x), /* Iterations = %d */\n", type->dim, type->dim);
1336 print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1337 print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory);
1338 print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1339 *typestring_offset += 10;
1341 pointer_count = write_pointer_description_offsets(
1342 file, attrs, type, &offset_of_array_pointer_mem,
1343 &offset_of_array_pointer_buf, typestring_offset);
1346 else if (is_struct(type->type))
1348 const var_t *v;
1349 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1351 pointer_count += write_fixed_array_pointer_descriptions(
1352 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1353 typestring_offset);
1356 else
1358 align = 0;
1359 if (offset_in_memory)
1360 *offset_in_memory += type_memsize(type, &align);
1361 /* FIXME: is there a case where these two are different? */
1362 align = 0;
1363 if (offset_in_buffer)
1364 *offset_in_buffer += type_memsize(type, &align);
1367 return pointer_count;
1370 /* Note: if file is NULL return value is number of pointers to write, else
1371 * it is the number of type format characters written */
1372 static int write_conformant_array_pointer_descriptions(
1373 FILE *file, const attr_list_t *attrs, type_t *type,
1374 size_t offset_in_memory, unsigned int *typestring_offset)
1376 unsigned int align;
1377 int pointer_count = 0;
1379 if (is_conformant_array(type) && !type->length_is)
1381 unsigned int temp = 0;
1382 /* unfortunately, this needs to be done in two passes to avoid
1383 * writing out redundant FC_VARIABLE_REPEAT descriptions */
1384 pointer_count = write_pointer_description_offsets(
1385 NULL, attrs, type->ref, NULL, NULL, &temp);
1386 if (pointer_count > 0)
1388 unsigned int increment_size;
1389 size_t offset_of_array_pointer_mem = offset_in_memory;
1390 size_t offset_of_array_pointer_buf = offset_in_memory;
1392 align = 0;
1393 increment_size = type_memsize(type->ref, &align);
1395 if (increment_size > USHRT_MAX)
1396 error("array size of %u bytes is too large\n", increment_size);
1398 print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
1399 print_file(file, 2, "0x%02x, /* FC_FIXED_OFFSET */\n", RPC_FC_FIXED_OFFSET);
1400 print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1401 print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", offset_in_memory, offset_in_memory);
1402 print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1403 *typestring_offset += 8;
1405 pointer_count = write_pointer_description_offsets(
1406 file, attrs, type->ref, &offset_of_array_pointer_mem,
1407 &offset_of_array_pointer_buf, typestring_offset);
1411 return pointer_count;
1414 /* Note: if file is NULL return value is number of pointers to write, else
1415 * it is the number of type format characters written */
1416 static int write_varying_array_pointer_descriptions(
1417 FILE *file, const attr_list_t *attrs, type_t *type,
1418 size_t *offset_in_memory, size_t *offset_in_buffer,
1419 unsigned int *typestring_offset)
1421 unsigned int align;
1422 int pointer_count = 0;
1424 /* FIXME: do varying array searching here, but pointer searching in write_pointer_description_offsets */
1426 if (is_array(type) && type->length_is)
1428 unsigned int temp = 0;
1429 /* unfortunately, this needs to be done in two passes to avoid
1430 * writing out redundant FC_VARIABLE_REPEAT descriptions */
1431 pointer_count = write_pointer_description_offsets(
1432 NULL, attrs, type->ref, NULL, NULL, &temp);
1433 if (pointer_count > 0)
1435 unsigned int increment_size;
1436 size_t offset_of_array_pointer_mem = 0;
1437 size_t offset_of_array_pointer_buf = 0;
1439 align = 0;
1440 increment_size = type_memsize(type->ref, &align);
1442 if (increment_size > USHRT_MAX)
1443 error("array size of %u bytes is too large\n", increment_size);
1445 print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
1446 print_file(file, 2, "0x%02x, /* FC_VARIABLE_OFFSET */\n", RPC_FC_VARIABLE_OFFSET);
1447 print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1448 print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory);
1449 print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1450 *typestring_offset += 8;
1452 pointer_count = write_pointer_description_offsets(
1453 file, attrs, type, &offset_of_array_pointer_mem,
1454 &offset_of_array_pointer_buf, typestring_offset);
1457 else if (is_struct(type->type))
1459 const var_t *v;
1460 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1462 pointer_count += write_varying_array_pointer_descriptions(
1463 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1464 typestring_offset);
1467 else
1469 align = 0;
1470 if (offset_in_memory)
1471 *offset_in_memory += type_memsize(type, &align);
1472 /* FIXME: is there a case where these two are different? */
1473 align = 0;
1474 if (offset_in_buffer)
1475 *offset_in_buffer += type_memsize(type, &align);
1478 return pointer_count;
1481 static void write_pointer_description(FILE *file, type_t *type,
1482 unsigned int *typestring_offset)
1484 size_t offset_in_buffer;
1485 size_t offset_in_memory;
1487 /* pass 1: search for single instance of a pointer (i.e. don't descend
1488 * into arrays) */
1489 if (!is_array(type))
1491 offset_in_memory = 0;
1492 offset_in_buffer = 0;
1493 write_no_repeat_pointer_descriptions(
1494 file, type,
1495 &offset_in_memory, &offset_in_buffer, typestring_offset);
1498 /* pass 2: search for pointers in fixed arrays */
1499 offset_in_memory = 0;
1500 offset_in_buffer = 0;
1501 write_fixed_array_pointer_descriptions(
1502 file, NULL, type,
1503 &offset_in_memory, &offset_in_buffer, typestring_offset);
1505 /* pass 3: search for pointers in conformant only arrays (but don't descend
1506 * into conformant varying or varying arrays) */
1507 if ((!type->declarray || !current_structure) && is_conformant_array(type))
1508 write_conformant_array_pointer_descriptions(
1509 file, NULL, type, 0, typestring_offset);
1510 else if (type->type == RPC_FC_CPSTRUCT)
1512 unsigned int align = 0;
1513 type_t *carray = find_array_or_string_in_struct(type)->type;
1514 write_conformant_array_pointer_descriptions(
1515 file, NULL, carray,
1516 type_memsize(type, &align),
1517 typestring_offset);
1520 /* pass 4: search for pointers in varying arrays */
1521 offset_in_memory = 0;
1522 offset_in_buffer = 0;
1523 write_varying_array_pointer_descriptions(
1524 file, NULL, type,
1525 &offset_in_memory, &offset_in_buffer, typestring_offset);
1528 int is_declptr(const type_t *t)
1530 return is_ptr(t) || (is_conformant_array(t) && !t->declarray);
1533 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
1534 type_t *type,
1535 const char *name, unsigned int *typestring_offset)
1537 size_t start_offset;
1538 unsigned char rtype;
1540 if (is_declptr(type))
1542 unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER;
1543 int pointer_type = is_ptr(type) ? type->type : get_attrv(attrs, ATTR_POINTERTYPE);
1544 if (!pointer_type)
1545 pointer_type = RPC_FC_RP;
1546 print_start_tfs_comment(file, type, *typestring_offset);
1547 print_file(file, 2,"0x%x, 0x%x,\t/* %s%s */\n",
1548 pointer_type, flag, string_of_type(pointer_type),
1549 flag ? " [simple_pointer]" : "");
1550 *typestring_offset += 2;
1551 if (!flag)
1553 print_file(file, 2, "NdrFcShort(0x2),\n");
1554 *typestring_offset += 2;
1558 start_offset = *typestring_offset;
1559 update_tfsoff(type, start_offset, file);
1561 rtype = type->ref->type;
1563 if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR))
1565 error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
1566 return start_offset;
1569 if (type->declarray && !is_conformant_array(type))
1571 /* FIXME: multi-dimensional array */
1572 if (0xffffuL < type->dim)
1573 error("array size for parameter %s exceeds %u bytes by %lu bytes\n",
1574 name, 0xffffu, type->dim - 0xffffu);
1576 if (rtype == RPC_FC_CHAR)
1577 WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
1578 else
1579 WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
1580 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1581 *typestring_offset += 2;
1583 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", type->dim, type->dim);
1584 *typestring_offset += 2;
1586 return start_offset;
1588 else if (type->size_is)
1590 unsigned int align = 0;
1592 if (rtype == RPC_FC_CHAR)
1593 WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
1594 else
1595 WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
1596 print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
1597 *typestring_offset += 2;
1599 *typestring_offset += write_conf_or_var_desc(
1600 file, current_structure,
1601 (type->declarray && current_structure
1602 ? type_memsize(current_structure, &align)
1603 : 0),
1604 type, type->size_is);
1606 return start_offset;
1608 else
1610 if (rtype == RPC_FC_WCHAR)
1611 WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
1612 else
1613 WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
1614 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1615 *typestring_offset += 2;
1617 return start_offset;
1621 static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
1622 const char *name, unsigned int *typestring_offset)
1624 const expr_t *length_is = type->length_is;
1625 const expr_t *size_is = type->size_is;
1626 unsigned int align = 0;
1627 size_t size;
1628 size_t start_offset;
1629 int has_pointer;
1630 int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
1631 unsigned int baseoff
1632 = type->declarray && current_structure
1633 ? type_memsize(current_structure, &align)
1634 : 0;
1636 if (!pointer_type)
1637 pointer_type = RPC_FC_RP;
1639 if (write_embedded_types(file, attrs, type->ref, name, FALSE, typestring_offset))
1640 has_pointer = TRUE;
1641 else
1642 has_pointer = type_has_pointers(type->ref);
1644 align = 0;
1645 size = type_memsize((is_conformant_array(type) ? type->ref : type), &align);
1647 start_offset = *typestring_offset;
1648 update_tfsoff(type, start_offset, file);
1649 print_start_tfs_comment(file, type, start_offset);
1650 print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
1651 print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1652 *typestring_offset += 2;
1654 align = 0;
1655 if (type->type != RPC_FC_BOGUS_ARRAY)
1657 unsigned char tc = type->type;
1659 if (tc == RPC_FC_LGFARRAY || tc == RPC_FC_LGVARRAY)
1661 print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", size, size);
1662 *typestring_offset += 4;
1664 else
1666 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", size, size);
1667 *typestring_offset += 2;
1670 if (is_conformant_array(type))
1671 *typestring_offset
1672 += write_conf_or_var_desc(file, current_structure, baseoff,
1673 type, size_is);
1675 if (type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY)
1677 unsigned int elalign = 0;
1678 size_t elsize = type_memsize(type->ref, &elalign);
1680 if (type->type == RPC_FC_LGVARRAY)
1682 print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", type->dim, type->dim);
1683 *typestring_offset += 4;
1685 else
1687 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", type->dim, type->dim);
1688 *typestring_offset += 2;
1691 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", elsize, elsize);
1692 *typestring_offset += 2;
1695 if (length_is)
1696 *typestring_offset
1697 += write_conf_or_var_desc(file, current_structure, baseoff,
1698 type, length_is);
1700 if (has_pointer && (!type->declarray || !current_structure))
1702 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1703 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1704 *typestring_offset += 2;
1705 write_pointer_description(file, type, typestring_offset);
1706 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1707 *typestring_offset += 1;
1710 write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1711 write_end(file, typestring_offset);
1713 else
1715 unsigned int dim = size_is ? 0 : type->dim;
1716 print_file(file, 2, "NdrFcShort(0x%x),\t/* %u */\n", dim, dim);
1717 *typestring_offset += 2;
1718 *typestring_offset
1719 += write_conf_or_var_desc(file, current_structure, baseoff,
1720 type, size_is);
1721 *typestring_offset
1722 += write_conf_or_var_desc(file, current_structure, baseoff,
1723 type, length_is);
1724 write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1725 write_end(file, typestring_offset);
1728 return start_offset;
1731 static const var_t *find_array_or_string_in_struct(const type_t *type)
1733 const var_t *last_field = LIST_ENTRY( list_tail(type->fields), const var_t, entry );
1734 const type_t *ft = last_field->type;
1736 if (ft->declarray && is_conformant_array(ft))
1737 return last_field;
1739 if (ft->type == RPC_FC_CSTRUCT || ft->type == RPC_FC_CPSTRUCT || ft->type == RPC_FC_CVSTRUCT)
1740 return find_array_or_string_in_struct(last_field->type);
1741 else
1742 return NULL;
1745 static void write_struct_members(FILE *file, const type_t *type,
1746 unsigned int *corroff, unsigned int *typestring_offset)
1748 const var_t *field;
1749 unsigned short offset = 0;
1750 int salign = -1;
1751 int padding;
1753 if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1755 type_t *ft = field->type;
1756 if (!ft->declarray || !is_conformant_array(ft))
1758 unsigned int align = 0;
1759 size_t size = type_memsize(ft, &align);
1760 if (salign == -1)
1761 salign = align;
1762 if ((align - 1) & offset)
1764 unsigned char fc = 0;
1765 switch (align)
1767 case 4:
1768 fc = RPC_FC_ALIGNM4;
1769 break;
1770 case 8:
1771 fc = RPC_FC_ALIGNM8;
1772 break;
1773 default:
1774 error("write_struct_members: cannot align type %d\n", ft->type);
1776 print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1777 offset = (offset + (align - 1)) & ~(align - 1);
1778 *typestring_offset += 1;
1780 write_member_type(file, type, field->attrs, field->type, corroff,
1781 typestring_offset);
1782 offset += size;
1786 padding = ((offset + (salign - 1)) & ~(salign - 1)) - offset;
1787 if (padding)
1789 print_file(file, 2, "0x%x,\t/* FC_STRUCTPAD%d */\n",
1790 RPC_FC_STRUCTPAD1 + padding - 1,
1791 padding);
1792 *typestring_offset += 1;
1795 write_end(file, typestring_offset);
1798 static size_t write_struct_tfs(FILE *file, type_t *type,
1799 const char *name, unsigned int *tfsoff)
1801 const type_t *save_current_structure = current_structure;
1802 unsigned int total_size;
1803 const var_t *array;
1804 size_t start_offset;
1805 size_t array_offset;
1806 int has_pointers = 0;
1807 unsigned int align = 0;
1808 unsigned int corroff;
1809 var_t *f;
1811 guard_rec(type);
1812 current_structure = type;
1814 total_size = type_memsize(type, &align);
1815 if (total_size > USHRT_MAX)
1816 error("structure size for %s exceeds %d bytes by %d bytes\n",
1817 name, USHRT_MAX, total_size - USHRT_MAX);
1819 if (type->fields) LIST_FOR_EACH_ENTRY(f, type->fields, var_t, entry)
1820 has_pointers |= write_embedded_types(file, f->attrs, f->type, f->name,
1821 FALSE, tfsoff);
1822 if (!has_pointers) has_pointers = type_has_pointers(type);
1824 array = find_array_or_string_in_struct(type);
1825 if (array && !processed(array->type))
1826 array_offset
1827 = is_attr(array->attrs, ATTR_STRING)
1828 ? write_string_tfs(file, array->attrs, array->type, array->name, tfsoff)
1829 : write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
1831 corroff = *tfsoff;
1832 write_descriptors(file, type, tfsoff);
1834 start_offset = *tfsoff;
1835 update_tfsoff(type, start_offset, file);
1836 print_start_tfs_comment(file, type, start_offset);
1837 print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
1838 print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1839 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size);
1840 *tfsoff += 4;
1842 if (array)
1844 unsigned int absoff = array->type->typestring_offset;
1845 short reloff = absoff - *tfsoff;
1846 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1847 reloff, reloff, absoff);
1848 *tfsoff += 2;
1850 else if (type->type == RPC_FC_BOGUS_STRUCT)
1852 print_file(file, 2, "NdrFcShort(0x0),\n");
1853 *tfsoff += 2;
1856 if (type->type == RPC_FC_BOGUS_STRUCT)
1858 /* On the sizing pass, type->ptrdesc may be zero, but it's ok as
1859 nothing is written to file yet. On the actual writing pass,
1860 this will have been updated. */
1861 unsigned int absoff = type->ptrdesc ? type->ptrdesc : *tfsoff;
1862 short reloff = absoff - *tfsoff;
1863 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1864 reloff, reloff, absoff);
1865 *tfsoff += 2;
1867 else if ((type->type == RPC_FC_PSTRUCT) ||
1868 (type->type == RPC_FC_CPSTRUCT) ||
1869 (type->type == RPC_FC_CVSTRUCT && has_pointers))
1871 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1872 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1873 *tfsoff += 2;
1874 write_pointer_description(file, type, tfsoff);
1875 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1876 *tfsoff += 1;
1879 write_struct_members(file, type, &corroff, tfsoff);
1881 if (type->type == RPC_FC_BOGUS_STRUCT)
1883 const var_list_t *fs = type->fields;
1884 const var_t *f;
1886 type->ptrdesc = *tfsoff;
1887 if (fs) LIST_FOR_EACH_ENTRY(f, fs, const var_t, entry)
1889 type_t *ft = f->type;
1890 if (is_ptr(ft))
1892 if (is_string_type(f->attrs, ft))
1893 write_string_tfs(file, f->attrs, ft, f->name, tfsoff);
1894 else
1895 write_pointer_tfs(file, ft, tfsoff);
1897 else if (!ft->declarray && is_conformant_array(ft))
1899 unsigned int absoff = ft->typestring_offset;
1900 short reloff = absoff - (*tfsoff + 2);
1901 int ptr_type = get_attrv(f->attrs, ATTR_POINTERTYPE);
1902 /* FIXME: We need to store pointer attributes for arrays
1903 so we don't lose pointer_default info. */
1904 if (ptr_type == 0)
1905 ptr_type = RPC_FC_UP;
1906 print_file(file, 0, "/* %d */\n", *tfsoff);
1907 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
1908 string_of_type(ptr_type));
1909 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1910 reloff, reloff, absoff);
1911 *tfsoff += 4;
1914 if (type->ptrdesc == *tfsoff)
1915 type->ptrdesc = 0;
1918 current_structure = save_current_structure;
1919 return start_offset;
1922 static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
1923 unsigned char flags, size_t offset,
1924 unsigned int *typeformat_offset)
1926 size_t start_offset = *typeformat_offset;
1927 short reloff = offset - (*typeformat_offset + 2);
1928 int in_attr, out_attr;
1929 in_attr = is_attr(attrs, ATTR_IN);
1930 out_attr = is_attr(attrs, ATTR_OUT);
1931 if (!in_attr && !out_attr) in_attr = 1;
1933 if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
1934 flags |= 0x04;
1936 print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
1937 pointer_type,
1938 flags,
1939 string_of_type(pointer_type));
1940 if (file)
1942 if (flags & 0x04)
1943 fprintf(file, " [allocated_on_stack]");
1944 if (flags & 0x10)
1945 fprintf(file, " [pointer_deref]");
1946 fprintf(file, " */\n");
1949 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", reloff, offset);
1950 *typeformat_offset += 4;
1952 return start_offset;
1955 static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
1957 if (t == NULL)
1959 print_file(file, 2, "NdrFcShort(0x0),\t/* No type */\n");
1961 else if (is_base_type(t->type))
1963 print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n",
1964 t->type, string_of_type(t->type));
1966 else if (t->typestring_offset)
1968 short reloff = t->typestring_offset - *tfsoff;
1969 print_file(file, 2, "NdrFcShort(0x%x),\t/* Offset= %d (%d) */\n",
1970 reloff, reloff, t->typestring_offset);
1972 else
1973 error("write_branch_type: type unimplemented (0x%x)\n", t->type);
1975 *tfsoff += 2;
1978 static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
1980 unsigned int align = 0;
1981 unsigned int start_offset;
1982 size_t size = type_memsize(type, &align);
1983 var_list_t *fields;
1984 size_t nbranch = 0;
1985 type_t *deftype = NULL;
1986 short nodeftype = 0xffff;
1987 var_t *f;
1989 guard_rec(type);
1991 if (type->type == RPC_FC_ENCAPSULATED_UNION)
1993 const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
1994 fields = uv->type->fields;
1996 else
1997 fields = type->fields;
1999 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
2001 expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
2002 if (cases)
2003 nbranch += list_count(cases);
2004 if (f->type)
2005 write_embedded_types(file, f->attrs, f->type, f->name, TRUE, tfsoff);
2008 start_offset = *tfsoff;
2009 update_tfsoff(type, start_offset, file);
2010 print_start_tfs_comment(file, type, start_offset);
2011 if (type->type == RPC_FC_ENCAPSULATED_UNION)
2013 const var_t *sv = LIST_ENTRY(list_head(type->fields), const var_t, entry);
2014 const type_t *st = sv->type;
2016 switch (st->type)
2018 case RPC_FC_CHAR:
2019 case RPC_FC_SMALL:
2020 case RPC_FC_USMALL:
2021 case RPC_FC_SHORT:
2022 case RPC_FC_USHORT:
2023 case RPC_FC_LONG:
2024 case RPC_FC_ULONG:
2025 case RPC_FC_ENUM16:
2026 case RPC_FC_ENUM32:
2027 print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
2028 print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
2029 0x40 | st->type, string_of_type(st->type));
2030 *tfsoff += 2;
2031 break;
2032 default:
2033 error("union switch type must be an integer, char, or enum\n");
2036 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", size, size);
2037 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", nbranch, nbranch);
2038 *tfsoff += 4;
2040 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
2042 type_t *ft = f->type;
2043 expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
2044 int deflt = is_attr(f->attrs, ATTR_DEFAULT);
2045 expr_t *c;
2047 if (cases == NULL && !deflt)
2048 error("union field %s with neither case nor default attribute\n", f->name);
2050 if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry)
2052 /* MIDL doesn't check for duplicate cases, even though that seems
2053 like a reasonable thing to do, it just dumps them to the TFS
2054 like we're going to do here. */
2055 print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
2056 *tfsoff += 4;
2057 write_branch_type(file, ft, tfsoff);
2060 /* MIDL allows multiple default branches, even though that seems
2061 illogical, it just chooses the last one, which is what we will
2062 do. */
2063 if (deflt)
2065 deftype = ft;
2066 nodeftype = 0;
2070 if (deftype)
2072 write_branch_type(file, deftype, tfsoff);
2074 else
2076 print_file(file, 2, "NdrFcShort(0x%x),\n", nodeftype);
2077 *tfsoff += 2;
2080 return start_offset;
2083 static size_t write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
2084 unsigned int *typeformat_offset)
2086 size_t i;
2087 size_t start_offset = *typeformat_offset;
2088 expr_t *iid = get_attrp(attrs, ATTR_IIDIS);
2090 if (iid)
2092 print_file(file, 2, "0x2f, /* FC_IP */\n");
2093 print_file(file, 2, "0x5c, /* FC_PAD */\n");
2094 *typeformat_offset
2095 += write_conf_or_var_desc(file, NULL, 0, type, iid) + 2;
2097 else
2099 const type_t *base = is_ptr(type) ? type->ref : type;
2100 const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
2102 if (! uuid)
2103 error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
2105 update_tfsoff(type, start_offset, file);
2106 print_start_tfs_comment(file, type, start_offset);
2107 print_file(file, 2, "0x2f,\t/* FC_IP */\n");
2108 print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
2109 print_file(file, 2, "NdrFcLong(0x%08lx),\n", uuid->Data1);
2110 print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2);
2111 print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3);
2112 for (i = 0; i < 8; ++i)
2113 print_file(file, 2, "0x%02x,\n", uuid->Data4[i]);
2115 if (file)
2116 fprintf(file, "\n");
2118 *typeformat_offset += 18;
2120 return start_offset;
2123 static size_t write_contexthandle_tfs(FILE *file, const type_t *type,
2124 const var_t *var,
2125 unsigned int *typeformat_offset)
2127 size_t start_offset = *typeformat_offset;
2128 unsigned char flags = 0;
2130 if (is_attr(current_iface->attrs, ATTR_STRICTCONTEXTHANDLE))
2131 flags |= NDR_STRICT_CONTEXT_HANDLE;
2133 if (is_ptr(type))
2134 flags |= 0x80;
2135 if (is_attr(var->attrs, ATTR_IN))
2137 flags |= 0x40;
2138 if (!is_attr(var->attrs, ATTR_OUT))
2139 flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
2141 if (is_attr(var->attrs, ATTR_OUT))
2142 flags |= 0x20;
2144 WRITE_FCTYPE(file, FC_BIND_CONTEXT, *typeformat_offset);
2145 print_file(file, 2, "0x%x,\t/* Context flags: ", flags);
2146 /* return and can't be null values overlap */
2147 if (((flags & 0x21) != 0x21) && (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL))
2148 print_file(file, 0, "can't be null, ");
2149 if (flags & NDR_CONTEXT_HANDLE_SERIALIZE)
2150 print_file(file, 0, "serialize, ");
2151 if (flags & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
2152 print_file(file, 0, "no serialize, ");
2153 if (flags & NDR_STRICT_CONTEXT_HANDLE)
2154 print_file(file, 0, "strict, ");
2155 if ((flags & 0x21) == 0x20)
2156 print_file(file, 0, "out, ");
2157 if ((flags & 0x21) == 0x21)
2158 print_file(file, 0, "return, ");
2159 if (flags & 0x40)
2160 print_file(file, 0, "in, ");
2161 if (flags & 0x80)
2162 print_file(file, 0, "via ptr, ");
2163 print_file(file, 0, "*/\n");
2164 print_file(file, 2, "0, /* FIXME: rundown routine index*/\n");
2165 print_file(file, 2, "0, /* FIXME: param num */\n");
2166 *typeformat_offset += 4;
2168 return start_offset;
2171 static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *func,
2172 type_t *type, const var_t *var,
2173 unsigned int *typeformat_offset)
2175 size_t offset;
2177 if (is_context_handle(type))
2178 return write_contexthandle_tfs(file, type, var, typeformat_offset);
2180 if (is_user_type(type))
2182 write_user_tfs(file, type, typeformat_offset);
2183 return type->typestring_offset;
2186 if (is_string_type(var->attrs, type))
2187 return write_string_tfs(file, var->attrs, type, var->name, typeformat_offset);
2189 if (is_array(type))
2191 int ptr_type;
2192 size_t off;
2193 off = write_array_tfs(file, var->attrs, type, var->name, typeformat_offset);
2194 ptr_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2195 /* Top level pointers to conformant arrays may be handled specially
2196 since we can bypass the pointer, but if the array is buried
2197 beneath another pointer (e.g., "[size_is(,n)] int **p" then we
2198 always need to write the pointer. */
2199 if (!ptr_type && var->type != type)
2200 /* FIXME: This should use pointer_default, but the information
2201 isn't kept around for arrays. */
2202 ptr_type = RPC_FC_UP;
2203 if (ptr_type && ptr_type != RPC_FC_RP)
2205 unsigned int absoff = type->typestring_offset;
2206 short reloff = absoff - (*typeformat_offset + 2);
2207 off = *typeformat_offset;
2208 print_file(file, 0, "/* %d */\n", off);
2209 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
2210 string_of_type(ptr_type));
2211 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
2212 reloff, reloff, absoff);
2213 *typeformat_offset += 4;
2215 return off;
2218 if (!is_ptr(type))
2220 /* basic types don't need a type format string */
2221 if (is_base_type(type->type))
2222 return 0;
2224 switch (type->type)
2226 case RPC_FC_STRUCT:
2227 case RPC_FC_PSTRUCT:
2228 case RPC_FC_CSTRUCT:
2229 case RPC_FC_CPSTRUCT:
2230 case RPC_FC_CVSTRUCT:
2231 case RPC_FC_BOGUS_STRUCT:
2232 return write_struct_tfs(file, type, var->name, typeformat_offset);
2233 case RPC_FC_ENCAPSULATED_UNION:
2234 case RPC_FC_NON_ENCAPSULATED_UNION:
2235 return write_union_tfs(file, type, typeformat_offset);
2236 case RPC_FC_IGNORE:
2237 case RPC_FC_BIND_PRIMITIVE:
2238 /* nothing to do */
2239 return 0;
2240 default:
2241 error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
2244 else if (last_ptr(type))
2246 size_t start_offset = *typeformat_offset;
2247 int in_attr = is_attr(var->attrs, ATTR_IN);
2248 int out_attr = is_attr(var->attrs, ATTR_OUT);
2249 const type_t *base = type->ref;
2251 if (base->type == RPC_FC_IP
2252 || (base->type == 0
2253 && is_attr(var->attrs, ATTR_IIDIS)))
2255 return write_ip_tfs(file, var->attrs, type, typeformat_offset);
2258 /* special case for pointers to base types */
2259 if (is_base_type(base->type))
2261 print_file(file, indent, "0x%x, 0x%x, /* %s %s[simple_pointer] */\n",
2262 type->type, (!in_attr && out_attr) ? 0x0C : 0x08,
2263 string_of_type(type->type),
2264 (!in_attr && out_attr) ? "[allocated_on_stack] " : "");
2265 print_file(file, indent, "0x%02x, /* %s */\n", base->type, string_of_type(base->type));
2266 print_file(file, indent, "0x5c, /* FC_PAD */\n");
2267 *typeformat_offset += 4;
2268 return start_offset;
2272 assert(is_ptr(type));
2274 offset = write_typeformatstring_var(file, indent, func, type->ref, var, typeformat_offset);
2275 if (file)
2276 fprintf(file, "/* %2u */\n", *typeformat_offset);
2277 return write_pointer_only_tfs(file, var->attrs, type->type,
2278 !last_ptr(type) ? 0x10 : 0,
2279 offset, typeformat_offset);
2282 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
2283 const char *name, int write_ptr, unsigned int *tfsoff)
2285 int retmask = 0;
2287 if (is_user_type(type))
2289 write_user_tfs(file, type, tfsoff);
2291 else if (is_string_type(attrs, type))
2293 write_string_tfs(file, attrs, type, name, tfsoff);
2295 else if (is_ptr(type))
2297 type_t *ref = type->ref;
2299 if (ref->type == RPC_FC_IP
2300 || (ref->type == 0
2301 && is_attr(attrs, ATTR_IIDIS)))
2303 write_ip_tfs(file, attrs, type, tfsoff);
2305 else
2307 if (!processed(ref) && !is_base_type(ref->type))
2308 retmask |= write_embedded_types(file, NULL, ref, name, TRUE, tfsoff);
2310 if (write_ptr)
2311 write_pointer_tfs(file, type, tfsoff);
2313 retmask |= 1;
2316 else if (type->declarray && is_conformant_array(type))
2317 ; /* conformant arrays and strings are handled specially */
2318 else if (is_array(type))
2320 write_array_tfs(file, attrs, type, name, tfsoff);
2321 if (is_conformant_array(type))
2322 retmask |= 1;
2324 else if (is_struct(type->type))
2326 if (!processed(type))
2327 write_struct_tfs(file, type, name, tfsoff);
2329 else if (is_union(type->type))
2331 if (!processed(type))
2332 write_union_tfs(file, type, tfsoff);
2334 else if (!is_base_type(type->type))
2335 error("write_embedded_types: unknown embedded type for %s (0x%x)\n",
2336 name, type->type);
2338 return retmask;
2341 static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
2343 const var_t *var;
2344 const ifref_t *iface;
2345 unsigned int typeformat_offset = 2;
2347 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
2349 if (!pred(iface->iface))
2350 continue;
2352 if (iface->iface->funcs)
2354 const func_t *func;
2355 current_iface = iface;
2356 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
2358 if (is_local(func->def->attrs)) continue;
2360 if (!is_void(get_func_return_type(func)))
2362 var_t v = *func->def;
2363 v.type = get_func_return_type(func);
2364 update_tfsoff(get_func_return_type(func),
2365 write_typeformatstring_var(
2366 file, 2, NULL, get_func_return_type(func),
2367 &v, &typeformat_offset),
2368 file);
2371 current_func = func;
2372 if (func->args)
2373 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2374 update_tfsoff(
2375 var->type,
2376 write_typeformatstring_var(
2377 file, 2, func, var->type, var,
2378 &typeformat_offset),
2379 file);
2384 return typeformat_offset + 1;
2388 void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
2390 int indent = 0;
2392 print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
2393 print_file(file, indent, "{\n");
2394 indent++;
2395 print_file(file, indent, "0,\n");
2396 print_file(file, indent, "{\n");
2397 indent++;
2398 print_file(file, indent, "NdrFcShort(0x0),\n");
2400 set_all_tfswrite(TRUE);
2401 process_tfs(file, ifaces, pred);
2403 print_file(file, indent, "0x0\n");
2404 indent--;
2405 print_file(file, indent, "}\n");
2406 indent--;
2407 print_file(file, indent, "};\n");
2408 print_file(file, indent, "\n");
2411 static unsigned int get_required_buffer_size_type(
2412 const type_t *type, const char *name, unsigned int *alignment)
2414 *alignment = 0;
2415 if (is_user_type(type))
2417 const char *uname;
2418 const type_t *utype = get_user_type(type, &uname);
2419 return get_required_buffer_size_type(utype, uname, alignment);
2421 else
2423 switch (type->type)
2425 case RPC_FC_BYTE:
2426 case RPC_FC_CHAR:
2427 case RPC_FC_USMALL:
2428 case RPC_FC_SMALL:
2429 *alignment = 4;
2430 return 1;
2432 case RPC_FC_WCHAR:
2433 case RPC_FC_USHORT:
2434 case RPC_FC_SHORT:
2435 case RPC_FC_ENUM16:
2436 *alignment = 4;
2437 return 2;
2439 case RPC_FC_ULONG:
2440 case RPC_FC_LONG:
2441 case RPC_FC_ENUM32:
2442 case RPC_FC_FLOAT:
2443 case RPC_FC_ERROR_STATUS_T:
2444 *alignment = 4;
2445 return 4;
2447 case RPC_FC_HYPER:
2448 case RPC_FC_DOUBLE:
2449 *alignment = 8;
2450 return 8;
2452 case RPC_FC_IGNORE:
2453 case RPC_FC_BIND_PRIMITIVE:
2454 return 0;
2456 case RPC_FC_STRUCT:
2457 case RPC_FC_PSTRUCT:
2459 size_t size = 0;
2460 const var_t *field;
2461 if (!type->fields) return 0;
2462 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2464 unsigned int alignment;
2465 size += get_required_buffer_size_type(field->type, field->name,
2466 &alignment);
2468 return size;
2471 case RPC_FC_RP:
2472 return
2473 is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT
2474 ? get_required_buffer_size_type( type->ref, name, alignment )
2475 : 0;
2477 case RPC_FC_SMFARRAY:
2478 case RPC_FC_LGFARRAY:
2479 return type->dim * get_required_buffer_size_type(type->ref, name, alignment);
2481 default:
2482 return 0;
2487 static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
2489 int in_attr = is_attr(var->attrs, ATTR_IN);
2490 int out_attr = is_attr(var->attrs, ATTR_OUT);
2491 const type_t *t;
2493 if (!in_attr && !out_attr)
2494 in_attr = 1;
2496 *alignment = 0;
2498 for (t = var->type; is_ptr(t); t = t->ref)
2499 if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
2501 *alignment = 4;
2502 return 20;
2505 if (pass == PASS_OUT)
2507 if (out_attr && is_ptr(var->type))
2509 type_t *type = var->type;
2511 if (type->type == RPC_FC_STRUCT)
2513 const var_t *field;
2514 unsigned int size = 36;
2516 if (!type->fields) return size;
2517 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2519 unsigned int align;
2520 size += get_required_buffer_size_type(
2521 field->type, field->name, &align);
2523 return size;
2526 return 0;
2528 else
2530 if ((!out_attr || in_attr) && !var->type->size_is
2531 && !is_attr(var->attrs, ATTR_STRING) && !var->type->declarray)
2533 if (is_ptr(var->type))
2535 type_t *type = var->type;
2537 if (is_base_type(type->type))
2539 return 25;
2541 else if (type->type == RPC_FC_STRUCT)
2543 unsigned int size = 36;
2544 const var_t *field;
2546 if (!type->fields) return size;
2547 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2549 unsigned int align;
2550 size += get_required_buffer_size_type(
2551 field->type, field->name, &align);
2553 return size;
2558 return get_required_buffer_size_type(var->type, var->name, alignment);
2562 static unsigned int get_function_buffer_size( const func_t *func, enum pass pass )
2564 const var_t *var;
2565 unsigned int total_size = 0, alignment;
2567 if (func->args)
2569 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2571 total_size += get_required_buffer_size(var, &alignment, pass);
2572 total_size += alignment;
2576 if (pass == PASS_OUT && !is_void(get_func_return_type(func)))
2578 var_t v = *func->def;
2579 v.type = get_func_return_type(func);
2580 total_size += get_required_buffer_size(&v, &alignment, PASS_RETURN);
2581 total_size += alignment;
2583 return total_size;
2586 static void print_phase_function(FILE *file, int indent, const char *type,
2587 enum remoting_phase phase,
2588 const var_t *var, unsigned int type_offset)
2590 const char *function;
2591 switch (phase)
2593 case PHASE_BUFFERSIZE:
2594 function = "BufferSize";
2595 break;
2596 case PHASE_MARSHAL:
2597 function = "Marshall";
2598 break;
2599 case PHASE_UNMARSHAL:
2600 function = "Unmarshall";
2601 break;
2602 case PHASE_FREE:
2603 function = "Free";
2604 break;
2605 default:
2606 assert(0);
2607 return;
2610 print_file(file, indent, "Ndr%s%s(\n", type, function);
2611 indent++;
2612 print_file(file, indent, "&_StubMsg,\n");
2613 print_file(file, indent, "%s%s%s%s,\n",
2614 (phase == PHASE_UNMARSHAL) ? "(unsigned char **)" : "(unsigned char *)",
2615 (phase == PHASE_UNMARSHAL || decl_indirect(var->type)) ? "&" : "",
2616 (phase == PHASE_UNMARSHAL && decl_indirect(var->type)) ? "_p_" : "",
2617 var->name);
2618 print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
2619 type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
2620 if (phase == PHASE_UNMARSHAL)
2621 print_file(file, indent, "0);\n");
2622 indent--;
2625 void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
2626 enum pass pass, const var_t *var,
2627 const char *varname)
2629 type_t *type = var->type;
2630 unsigned int size;
2631 unsigned int alignment = 0;
2632 unsigned char rtype;
2634 /* no work to do for other phases, buffer sizing is done elsewhere */
2635 if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
2636 return;
2638 rtype = is_ptr(type) ? type->ref->type : type->type;
2640 switch (rtype)
2642 case RPC_FC_BYTE:
2643 case RPC_FC_CHAR:
2644 case RPC_FC_SMALL:
2645 case RPC_FC_USMALL:
2646 size = 1;
2647 alignment = 1;
2648 break;
2650 case RPC_FC_WCHAR:
2651 case RPC_FC_USHORT:
2652 case RPC_FC_SHORT:
2653 case RPC_FC_ENUM16:
2654 size = 2;
2655 alignment = 2;
2656 break;
2658 case RPC_FC_ULONG:
2659 case RPC_FC_LONG:
2660 case RPC_FC_ENUM32:
2661 case RPC_FC_FLOAT:
2662 case RPC_FC_ERROR_STATUS_T:
2663 size = 4;
2664 alignment = 4;
2665 break;
2667 case RPC_FC_HYPER:
2668 case RPC_FC_DOUBLE:
2669 size = 8;
2670 alignment = 8;
2671 break;
2673 case RPC_FC_IGNORE:
2674 case RPC_FC_BIND_PRIMITIVE:
2675 /* no marshalling needed */
2676 return;
2678 default:
2679 error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, rtype);
2680 size = 0;
2683 if (phase == PHASE_MARSHAL)
2684 print_file(file, indent, "MIDL_memset(_StubMsg.Buffer, 0, (0x%x - (long)_StubMsg.Buffer) & 0x%x);\n", alignment, alignment - 1);
2685 print_file(file, indent, "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
2686 alignment - 1, alignment - 1);
2688 if (phase == PHASE_MARSHAL)
2690 print_file(file, indent, "*(");
2691 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2692 if (is_ptr(type))
2693 fprintf(file, " *)_StubMsg.Buffer = *");
2694 else
2695 fprintf(file, " *)_StubMsg.Buffer = ");
2696 fprintf(file, "%s", varname);
2697 fprintf(file, ";\n");
2699 else if (phase == PHASE_UNMARSHAL)
2701 print_file(file, indent, "if (_StubMsg.Buffer + sizeof(");
2702 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2703 fprintf(file, ") > _StubMsg.BufferEnd)\n");
2704 print_file(file, indent, "{\n");
2705 print_file(file, indent + 1, "RpcRaiseException(RPC_X_BAD_STUB_DATA);\n");
2706 print_file(file, indent, "}\n");
2707 if (pass == PASS_IN || pass == PASS_RETURN)
2708 print_file(file, indent, "");
2709 else
2710 print_file(file, indent, "*");
2711 fprintf(file, "%s", varname);
2712 if (pass == PASS_IN && is_ptr(type))
2713 fprintf(file, " = (");
2714 else
2715 fprintf(file, " = *(");
2716 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2717 fprintf(file, " *)_StubMsg.Buffer;\n");
2720 print_file(file, indent, "_StubMsg.Buffer += sizeof(");
2721 write_type_decl(file, var->type, NULL);
2722 fprintf(file, ");\n");
2725 /* returns whether the MaxCount, Offset or ActualCount members need to be
2726 * filled in for the specified phase */
2727 static inline int is_size_needed_for_phase(enum remoting_phase phase)
2729 return (phase != PHASE_UNMARSHAL);
2732 expr_t *get_size_is_expr(const type_t *t, const char *name)
2734 expr_t *x = NULL;
2736 for ( ; is_ptr(t) || is_array(t); t = t->ref)
2737 if (t->size_is)
2739 if (!x)
2740 x = t->size_is;
2741 else
2742 error("%s: multidimensional conformant"
2743 " arrays not supported at the top level\n",
2744 name);
2747 return x;
2750 static void write_remoting_arg(FILE *file, int indent, const func_t *func,
2751 enum pass pass, enum remoting_phase phase,
2752 const var_t *var)
2754 int in_attr, out_attr, pointer_type;
2755 const type_t *type = var->type;
2756 unsigned char rtype;
2757 size_t start_offset = type->typestring_offset;
2759 pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2760 if (!pointer_type)
2761 pointer_type = RPC_FC_RP;
2763 in_attr = is_attr(var->attrs, ATTR_IN);
2764 out_attr = is_attr(var->attrs, ATTR_OUT);
2765 if (!in_attr && !out_attr)
2766 in_attr = 1;
2768 if (phase != PHASE_FREE)
2769 switch (pass)
2771 case PASS_IN:
2772 if (!in_attr) return;
2773 break;
2774 case PASS_OUT:
2775 if (!out_attr) return;
2776 break;
2777 case PASS_RETURN:
2778 break;
2781 rtype = type->type;
2783 if (is_context_handle(type))
2785 if (phase == PHASE_MARSHAL)
2787 if (pass == PASS_IN)
2789 /* if the context_handle attribute appears in the chain of types
2790 * without pointers being followed, then the context handle must
2791 * be direct, otherwise it is a pointer */
2792 int is_ch_ptr = is_aliaschain_attr(type, ATTR_CONTEXTHANDLE) ? FALSE : TRUE;
2793 print_file(file, indent, "NdrClientContextMarshall(\n");
2794 print_file(file, indent + 1, "&_StubMsg,\n");
2795 print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ch_ptr ? "*" : "", var->name);
2796 print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
2798 else
2800 print_file(file, indent, "NdrServerContextNewMarshall(\n");
2801 print_file(file, indent + 1, "&_StubMsg,\n");
2802 print_file(file, indent + 1, "(NDR_SCONTEXT)%s,\n", var->name);
2803 print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown,\n", get_context_handle_type_name(var->type));
2804 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2807 else if (phase == PHASE_UNMARSHAL)
2809 if (pass == PASS_OUT)
2811 if (!in_attr)
2812 print_file(file, indent, "*%s = 0;\n", var->name);
2813 print_file(file, indent, "NdrClientContextUnmarshall(\n");
2814 print_file(file, indent + 1, "&_StubMsg,\n");
2815 print_file(file, indent + 1, "(NDR_CCONTEXT *)%s,\n", var->name);
2816 print_file(file, indent + 1, "_Handle);\n");
2818 else
2820 print_file(file, indent, "%s = NdrServerContextNewUnmarshall(\n", var->name);
2821 print_file(file, indent + 1, "&_StubMsg,\n");
2822 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2826 else if (is_user_type(var->type))
2828 print_phase_function(file, indent, "UserMarshal", phase, var, start_offset);
2830 else if (is_string_type(var->attrs, var->type))
2832 if (is_array(type) && !is_conformant_array(type))
2833 print_phase_function(file, indent, "NonConformantString", phase, var, start_offset);
2834 else
2836 if (type->size_is && is_size_needed_for_phase(phase))
2838 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2839 write_expr(file, type->size_is, 1);
2840 fprintf(file, ";\n");
2843 if (phase == PHASE_FREE || pass == PASS_RETURN || pointer_type == RPC_FC_UP)
2844 print_phase_function(file, indent, "Pointer", phase, var,
2845 start_offset - (type->size_is ? 4 : 2));
2846 else
2847 print_phase_function(file, indent, "ConformantString", phase, var,
2848 start_offset);
2851 else if (is_array(type))
2853 unsigned char tc = type->type;
2854 const char *array_type = "FixedArray";
2856 /* We already have the size_is expression since it's at the
2857 top level, but do checks for multidimensional conformant
2858 arrays. When we handle them, we'll need to extend this
2859 function to return a list, and then we'll actually use
2860 the return value. */
2861 get_size_is_expr(type, var->name);
2863 if (tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY)
2865 if (is_size_needed_for_phase(phase))
2867 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2868 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2869 write_expr(file, type->length_is, 1);
2870 fprintf(file, ";\n\n");
2872 array_type = "VaryingArray";
2874 else if (tc == RPC_FC_CARRAY)
2876 if (is_size_needed_for_phase(phase))
2878 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2879 write_expr(file, type->size_is, 1);
2880 fprintf(file, ";\n\n");
2882 array_type = "ConformantArray";
2884 else if (tc == RPC_FC_CVARRAY || tc == RPC_FC_BOGUS_ARRAY)
2886 if (is_size_needed_for_phase(phase))
2888 if (type->size_is)
2890 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2891 write_expr(file, type->size_is, 1);
2892 fprintf(file, ";\n");
2894 if (type->length_is)
2896 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2897 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2898 write_expr(file, type->length_is, 1);
2899 fprintf(file, ";\n\n");
2902 array_type = (tc == RPC_FC_BOGUS_ARRAY
2903 ? "ComplexArray"
2904 : "ConformantVaryingArray");
2907 if (pointer_type != RPC_FC_RP) array_type = "Pointer";
2908 print_phase_function(file, indent, array_type, phase, var, start_offset);
2909 if (phase == PHASE_FREE && pointer_type == RPC_FC_RP)
2911 /* these are all unmarshalled by allocating memory */
2912 if (type->type == RPC_FC_BOGUS_ARRAY ||
2913 type->type == RPC_FC_CVARRAY ||
2914 ((type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY) && in_attr) ||
2915 (type->type == RPC_FC_CARRAY && !in_attr))
2917 print_file(file, indent, "if (%s)\n", var->name);
2918 indent++;
2919 print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
2923 else if (!is_ptr(var->type) && is_base_type(rtype))
2925 if (phase != PHASE_FREE)
2926 print_phase_basetype(file, indent, phase, pass, var, var->name);
2928 else if (!is_ptr(var->type))
2930 switch (rtype)
2932 case RPC_FC_STRUCT:
2933 case RPC_FC_PSTRUCT:
2934 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset);
2935 break;
2936 case RPC_FC_CSTRUCT:
2937 case RPC_FC_CPSTRUCT:
2938 print_phase_function(file, indent, "ConformantStruct", phase, var, start_offset);
2939 break;
2940 case RPC_FC_CVSTRUCT:
2941 print_phase_function(file, indent, "ConformantVaryingStruct", phase, var, start_offset);
2942 break;
2943 case RPC_FC_BOGUS_STRUCT:
2944 print_phase_function(file, indent, "ComplexStruct", phase, var, start_offset);
2945 break;
2946 case RPC_FC_RP:
2947 if (is_base_type( var->type->ref->type ))
2949 print_phase_basetype(file, indent, phase, pass, var, var->name);
2951 else if (var->type->ref->type == RPC_FC_STRUCT)
2953 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2954 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
2956 else
2958 expr_t *iid;
2959 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2961 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2962 write_expr( file, iid, 1 );
2963 fprintf( file, ";\n\n" );
2965 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
2967 break;
2968 default:
2969 error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype);
2972 else
2974 if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
2976 if (phase != PHASE_FREE)
2977 print_phase_basetype(file, indent, phase, pass, var, var->name);
2979 else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
2981 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2982 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
2984 else
2986 expr_t *iid;
2987 expr_t *sx = get_size_is_expr(type, var->name);
2989 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2991 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2992 write_expr( file, iid, 1 );
2993 fprintf( file, ";\n\n" );
2995 else if (sx)
2997 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long) ");
2998 write_expr(file, sx, 1);
2999 fprintf(file, ";\n\n");
3001 if (var->type->ref->type == RPC_FC_IP)
3002 print_phase_function(file, indent, "InterfacePointer", phase, var, start_offset);
3003 else
3004 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
3007 fprintf(file, "\n");
3010 void write_remoting_arguments(FILE *file, int indent, const func_t *func,
3011 enum pass pass, enum remoting_phase phase)
3013 if (phase == PHASE_BUFFERSIZE && pass != PASS_RETURN)
3015 unsigned int size = get_function_buffer_size( func, pass );
3016 print_file(file, indent, "_StubMsg.BufferLength = %u;\n", size);
3019 if (pass == PASS_RETURN)
3021 var_t var;
3022 var = *func->def;
3023 var.type = get_func_return_type(func);
3024 var.name = xstrdup( "_RetVal" );
3025 write_remoting_arg( file, indent, func, pass, phase, &var );
3026 free( var.name );
3028 else
3030 const var_t *var;
3031 if (!func->args)
3032 return;
3033 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3034 write_remoting_arg( file, indent, func, pass, phase, var );
3039 size_t get_size_procformatstring_type(const char *name, const type_t *type, const attr_list_t *attrs)
3041 return write_procformatstring_type(NULL, 0, name, type, attrs, FALSE);
3045 size_t get_size_procformatstring_func(const func_t *func)
3047 const var_t *var;
3048 size_t size = 0;
3050 /* argument list size */
3051 if (func->args)
3052 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3053 size += get_size_procformatstring_type(var->name, var->type, var->attrs);
3055 /* return value size */
3056 if (is_void(get_func_return_type(func)))
3057 size += 2; /* FC_END and FC_PAD */
3058 else
3059 size += get_size_procformatstring_type("return value", get_func_return_type(func), NULL);
3061 return size;
3064 size_t get_size_procformatstring(const ifref_list_t *ifaces, type_pred_t pred)
3066 const ifref_t *iface;
3067 size_t size = 1;
3068 const func_t *func;
3070 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
3072 if (!pred(iface->iface))
3073 continue;
3075 if (iface->iface->funcs)
3076 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
3077 if (!is_local(func->def->attrs))
3078 size += get_size_procformatstring_func( func );
3080 return size;
3083 size_t get_size_typeformatstring(const ifref_list_t *ifaces, type_pred_t pred)
3085 set_all_tfswrite(FALSE);
3086 return process_tfs(NULL, ifaces, pred);
3089 static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
3090 const var_list_t *fields, const char *structvar)
3092 switch (e->type) {
3093 case EXPR_VOID:
3094 break;
3095 case EXPR_NUM:
3096 fprintf(h, "%lu", e->u.lval);
3097 break;
3098 case EXPR_HEXNUM:
3099 fprintf(h, "0x%lx", e->u.lval);
3100 break;
3101 case EXPR_DOUBLE:
3102 fprintf(h, "%#.15g", e->u.dval);
3103 break;
3104 case EXPR_TRUEFALSE:
3105 if (e->u.lval == 0)
3106 fprintf(h, "FALSE");
3107 else
3108 fprintf(h, "TRUE");
3109 break;
3110 case EXPR_IDENTIFIER:
3112 const var_t *field;
3113 LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
3114 if (!strcmp(e->u.sval, field->name))
3116 fprintf(h, "%s->%s", structvar, e->u.sval);
3117 break;
3120 if (&field->entry == fields) error("no field found for identifier %s\n", e->u.sval);
3121 break;
3123 case EXPR_NEG:
3124 fprintf(h, "-");
3125 write_struct_expr(h, e->ref, 1, fields, structvar);
3126 break;
3127 case EXPR_NOT:
3128 fprintf(h, "~");
3129 write_struct_expr(h, e->ref, 1, fields, structvar);
3130 break;
3131 case EXPR_PPTR:
3132 fprintf(h, "*");
3133 write_struct_expr(h, e->ref, 1, fields, structvar);
3134 break;
3135 case EXPR_CAST:
3136 fprintf(h, "(");
3137 write_type_decl(h, e->u.tref, NULL);
3138 fprintf(h, ")");
3139 write_struct_expr(h, e->ref, 1, fields, structvar);
3140 break;
3141 case EXPR_SIZEOF:
3142 fprintf(h, "sizeof(");
3143 write_type_decl(h, e->u.tref, NULL);
3144 fprintf(h, ")");
3145 break;
3146 case EXPR_SHL:
3147 case EXPR_SHR:
3148 case EXPR_MUL:
3149 case EXPR_DIV:
3150 case EXPR_ADD:
3151 case EXPR_SUB:
3152 case EXPR_AND:
3153 case EXPR_OR:
3154 if (brackets) fprintf(h, "(");
3155 write_struct_expr(h, e->ref, 1, fields, structvar);
3156 switch (e->type) {
3157 case EXPR_SHL: fprintf(h, " << "); break;
3158 case EXPR_SHR: fprintf(h, " >> "); break;
3159 case EXPR_MUL: fprintf(h, " * "); break;
3160 case EXPR_DIV: fprintf(h, " / "); break;
3161 case EXPR_ADD: fprintf(h, " + "); break;
3162 case EXPR_SUB: fprintf(h, " - "); break;
3163 case EXPR_AND: fprintf(h, " & "); break;
3164 case EXPR_OR: fprintf(h, " | "); break;
3165 default: break;
3167 write_struct_expr(h, e->u.ext, 1, fields, structvar);
3168 if (brackets) fprintf(h, ")");
3169 break;
3170 case EXPR_COND:
3171 if (brackets) fprintf(h, "(");
3172 write_struct_expr(h, e->ref, 1, fields, structvar);
3173 fprintf(h, " ? ");
3174 write_struct_expr(h, e->u.ext, 1, fields, structvar);
3175 fprintf(h, " : ");
3176 write_struct_expr(h, e->ext2, 1, fields, structvar);
3177 if (brackets) fprintf(h, ")");
3178 break;
3179 case EXPR_ADDRESSOF:
3180 fprintf(h, "&");
3181 write_struct_expr(h, e->ref, 1, fields, structvar);
3182 break;
3187 void declare_stub_args( FILE *file, int indent, const func_t *func )
3189 int in_attr, out_attr;
3190 int i = 0;
3191 const var_t *var;
3193 /* declare return value '_RetVal' */
3194 if (!is_void(get_func_return_type(func)))
3196 print_file(file, indent, "");
3197 write_type_decl_left(file, get_func_return_type(func));
3198 fprintf(file, " _RetVal;\n");
3201 if (!func->args)
3202 return;
3204 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3206 int is_string = is_attr(var->attrs, ATTR_STRING);
3208 in_attr = is_attr(var->attrs, ATTR_IN);
3209 out_attr = is_attr(var->attrs, ATTR_OUT);
3210 if (!out_attr && !in_attr)
3211 in_attr = 1;
3213 if (is_context_handle(var->type))
3214 print_file(file, indent, "NDR_SCONTEXT %s;\n", var->name);
3215 else
3217 if (!in_attr && !var->type->size_is && !is_string)
3219 print_file(file, indent, "");
3220 write_type_decl(file, var->type->declarray ? var->type : var->type->ref,
3221 "_W%u", i++);
3222 fprintf(file, ";\n");
3225 print_file(file, indent, "");
3226 write_type_decl_left(file, var->type);
3227 fprintf(file, " ");
3228 if (var->type->declarray) {
3229 fprintf(file, "( *");
3230 write_name(file, var);
3231 fprintf(file, " )");
3232 } else
3233 write_name(file, var);
3234 write_type_right(file, var->type, FALSE);
3235 fprintf(file, ";\n");
3237 if (decl_indirect(var->type))
3238 print_file(file, indent, "void *_p_%s = &%s;\n",
3239 var->name, var->name);
3245 void assign_stub_out_args( FILE *file, int indent, const func_t *func )
3247 int in_attr, out_attr;
3248 int i = 0, sep = 0;
3249 const var_t *var;
3251 if (!func->args)
3252 return;
3254 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3256 int is_string = is_attr(var->attrs, ATTR_STRING);
3257 in_attr = is_attr(var->attrs, ATTR_IN);
3258 out_attr = is_attr(var->attrs, ATTR_OUT);
3259 if (!out_attr && !in_attr)
3260 in_attr = 1;
3262 if (!in_attr)
3264 print_file(file, indent, "");
3265 write_name(file, var);
3267 if (is_context_handle(var->type))
3269 fprintf(file, " = NdrContextHandleInitialize(\n");
3270 print_file(file, indent + 1, "&_StubMsg,\n");
3271 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n",
3272 var->type->typestring_offset);
3274 else if (var->type->size_is)
3276 unsigned int size, align = 0;
3277 type_t *type = var->type;
3279 fprintf(file, " = NdrAllocate(&_StubMsg, ");
3280 for ( ; type->size_is ; type = type->ref)
3282 write_expr(file, type->size_is, TRUE);
3283 fprintf(file, " * ");
3285 size = type_memsize(type, &align);
3286 fprintf(file, "%u);\n", size);
3288 else if (!is_string)
3290 fprintf(file, " = &_W%u;\n", i);
3291 if (is_ptr(var->type) && !last_ptr(var->type))
3292 print_file(file, indent, "_W%u = 0;\n", i);
3293 i++;
3296 sep = 1;
3299 if (sep)
3300 fprintf(file, "\n");
3304 int write_expr_eval_routines(FILE *file, const char *iface)
3306 static const char *var_name = "pS";
3307 int result = 0;
3308 struct expr_eval_routine *eval;
3309 unsigned short callback_offset = 0;
3311 LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
3313 const char *name = eval->structure->name;
3314 const var_list_t *fields = eval->structure->fields;
3315 result = 1;
3317 print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
3318 iface, name, callback_offset);
3319 print_file(file, 0, "{\n");
3320 print_file (file, 1, "%s *%s = (%s *)(pStubMsg->StackTop - %u);\n",
3321 name, var_name, name, eval->baseoff);
3322 print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */
3323 print_file(file, 1, "pStubMsg->MaxCount = (unsigned long)");
3324 write_struct_expr(file, eval->expr, 1, fields, var_name);
3325 fprintf(file, ";\n");
3326 print_file(file, 0, "}\n\n");
3327 callback_offset++;
3329 return result;
3332 void write_expr_eval_routine_list(FILE *file, const char *iface)
3334 struct expr_eval_routine *eval;
3335 struct expr_eval_routine *cursor;
3336 unsigned short callback_offset = 0;
3338 fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
3339 fprintf(file, "{\n");
3341 LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
3343 const char *name = eval->structure->name;
3344 print_file(file, 1, "%s_%sExprEval_%04u,\n", iface, name, callback_offset);
3345 callback_offset++;
3346 list_remove(&eval->entry);
3347 free(eval);
3350 fprintf(file, "};\n\n");
3353 void write_user_quad_list(FILE *file)
3355 user_type_t *ut;
3357 if (list_empty(&user_type_list))
3358 return;
3360 fprintf(file, "static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[] =\n");
3361 fprintf(file, "{\n");
3362 LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
3364 const char *sep = &ut->entry == list_tail(&user_type_list) ? "" : ",";
3365 print_file(file, 1, "{\n");
3366 print_file(file, 2, "(USER_MARSHAL_SIZING_ROUTINE)%s_UserSize,\n", ut->name);
3367 print_file(file, 2, "(USER_MARSHAL_MARSHALLING_ROUTINE)%s_UserMarshal,\n", ut->name);
3368 print_file(file, 2, "(USER_MARSHAL_UNMARSHALLING_ROUTINE)%s_UserUnmarshal,\n", ut->name);
3369 print_file(file, 2, "(USER_MARSHAL_FREEING_ROUTINE)%s_UserFree\n", ut->name);
3370 print_file(file, 1, "}%s\n", sep);
3372 fprintf(file, "};\n\n");
3375 void write_endpoints( FILE *f, const char *prefix, const str_list_t *list )
3377 const struct str_list_entry_t *endpoint;
3378 const char *p;
3380 /* this should be an array of RPC_PROTSEQ_ENDPOINT but we want const strings */
3381 print_file( f, 0, "static const unsigned char * %s__RpcProtseqEndpoint[][2] =\n{\n", prefix );
3382 LIST_FOR_EACH_ENTRY( endpoint, list, const struct str_list_entry_t, entry )
3384 print_file( f, 1, "{ (const unsigned char *)\"" );
3385 for (p = endpoint->str; *p && *p != ':'; p++)
3387 if (*p == '"' || *p == '\\') fputc( '\\', f );
3388 fputc( *p, f );
3390 if (!*p) goto error;
3391 if (p[1] != '[') goto error;
3393 fprintf( f, "\", (const unsigned char *)\"" );
3394 for (p += 2; *p && *p != ']'; p++)
3396 if (*p == '"' || *p == '\\') fputc( '\\', f );
3397 fputc( *p, f );
3399 if (*p != ']') goto error;
3400 fprintf( f, "\" },\n" );
3402 print_file( f, 0, "};\n\n" );
3403 return;
3405 error:
3406 error("Invalid endpoint syntax '%s'\n", endpoint->str);