push b59ba84f7e04af9ef068bd4c6e96701941f0256e
[wine/hacks.git] / tools / widl / typegen.c
blob0e8a09681b851b76d72b58ce1b0428da7462c7b6
1 /*
2 * Format String Generator for IDL Compiler
4 * Copyright 2005-2006 Eric Kohl
5 * Copyright 2005-2006 Robert Shearman
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <string.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <signal.h>
34 #include <limits.h>
36 #include "widl.h"
37 #include "utils.h"
38 #include "parser.h"
39 #include "header.h"
40 #include "wine/list.h"
42 #include "typegen.h"
44 static const func_t *current_func;
45 static const type_t *current_structure;
46 static const ifref_t *current_iface;
48 static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
49 struct expr_eval_routine
51 struct list entry;
52 const type_t *structure;
53 unsigned int baseoff;
54 const expr_t *expr;
57 static size_t fields_memsize(const var_list_t *fields, unsigned int *align);
58 static size_t write_struct_tfs(FILE *file, type_t *type, const char *name, unsigned int *tfsoff);
59 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
60 const char *name, int write_ptr, unsigned int *tfsoff);
61 static const var_t *find_array_or_string_in_struct(const type_t *type);
63 const char *string_of_type(unsigned char type)
65 switch (type)
67 case RPC_FC_BYTE: return "FC_BYTE";
68 case RPC_FC_CHAR: return "FC_CHAR";
69 case RPC_FC_SMALL: return "FC_SMALL";
70 case RPC_FC_USMALL: return "FC_USMALL";
71 case RPC_FC_WCHAR: return "FC_WCHAR";
72 case RPC_FC_SHORT: return "FC_SHORT";
73 case RPC_FC_USHORT: return "FC_USHORT";
74 case RPC_FC_LONG: return "FC_LONG";
75 case RPC_FC_ULONG: return "FC_ULONG";
76 case RPC_FC_FLOAT: return "FC_FLOAT";
77 case RPC_FC_HYPER: return "FC_HYPER";
78 case RPC_FC_DOUBLE: return "FC_DOUBLE";
79 case RPC_FC_ENUM16: return "FC_ENUM16";
80 case RPC_FC_ENUM32: return "FC_ENUM32";
81 case RPC_FC_IGNORE: return "FC_IGNORE";
82 case RPC_FC_ERROR_STATUS_T: return "FC_ERROR_STATUS_T";
83 case RPC_FC_RP: return "FC_RP";
84 case RPC_FC_UP: return "FC_UP";
85 case RPC_FC_OP: return "FC_OP";
86 case RPC_FC_FP: return "FC_FP";
87 case RPC_FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION";
88 case RPC_FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION";
89 case RPC_FC_STRUCT: return "FC_STRUCT";
90 case RPC_FC_PSTRUCT: return "FC_PSTRUCT";
91 case RPC_FC_CSTRUCT: return "FC_CSTRUCT";
92 case RPC_FC_CPSTRUCT: return "FC_CPSTRUCT";
93 case RPC_FC_CVSTRUCT: return "FC_CVSTRUCT";
94 case RPC_FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT";
95 case RPC_FC_SMFARRAY: return "FC_SMFARRAY";
96 case RPC_FC_LGFARRAY: return "FC_LGFARRAY";
97 case RPC_FC_SMVARRAY: return "FC_SMVARRAY";
98 case RPC_FC_LGVARRAY: return "FC_LGVARRAY";
99 case RPC_FC_CARRAY: return "FC_CARRAY";
100 case RPC_FC_CVARRAY: return "FC_CVARRAY";
101 case RPC_FC_BOGUS_ARRAY: return "FC_BOGUS_ARRAY";
102 case RPC_FC_ALIGNM4: return "FC_ALIGNM4";
103 case RPC_FC_ALIGNM8: return "FC_ALIGNM8";
104 case RPC_FC_POINTER: return "FC_POINTER";
105 case RPC_FC_C_CSTRING: return "FC_C_CSTRING";
106 case RPC_FC_C_WSTRING: return "FC_C_WSTRING";
107 case RPC_FC_CSTRING: return "FC_CSTRING";
108 case RPC_FC_WSTRING: return "FC_WSTRING";
109 default:
110 error("string_of_type: unknown type 0x%02x\n", type);
111 return NULL;
115 int is_struct(unsigned char type)
117 switch (type)
119 case RPC_FC_STRUCT:
120 case RPC_FC_PSTRUCT:
121 case RPC_FC_CSTRUCT:
122 case RPC_FC_CPSTRUCT:
123 case RPC_FC_CVSTRUCT:
124 case RPC_FC_BOGUS_STRUCT:
125 return 1;
126 default:
127 return 0;
131 static int is_non_complex_struct(const type_t *type)
133 switch (type->type)
135 case RPC_FC_STRUCT:
136 case RPC_FC_PSTRUCT:
137 case RPC_FC_CSTRUCT:
138 case RPC_FC_CPSTRUCT:
139 case RPC_FC_CVSTRUCT:
140 return 1;
141 default:
142 return 0;
146 int is_union(unsigned char type)
148 switch (type)
150 case RPC_FC_ENCAPSULATED_UNION:
151 case RPC_FC_NON_ENCAPSULATED_UNION:
152 return 1;
153 default:
154 return 0;
158 static int type_has_pointers(const type_t *type)
160 if (is_user_type(type))
161 return FALSE;
162 else if (is_ptr(type))
163 return TRUE;
164 else if (is_array(type))
165 return type_has_pointers(type->ref);
166 else if (is_struct(type->type))
168 const var_t *field;
169 if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
171 if (type_has_pointers(field->type))
172 return TRUE;
175 else if (is_union(type->type))
177 var_list_t *fields;
178 const var_t *field;
179 if (type->type == RPC_FC_ENCAPSULATED_UNION)
181 const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
182 fields = uv->type->fields;
184 else
185 fields = type->fields;
186 if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
188 if (field->type && type_has_pointers(field->type))
189 return TRUE;
193 return FALSE;
196 static unsigned short user_type_offset(const char *name)
198 user_type_t *ut;
199 unsigned short off = 0;
200 LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
202 if (strcmp(name, ut->name) == 0)
203 return off;
204 ++off;
206 error("user_type_offset: couldn't find type (%s)\n", name);
207 return 0;
210 static void update_tfsoff(type_t *type, unsigned int offset, FILE *file)
212 type->typestring_offset = offset;
213 if (file) type->tfswrite = FALSE;
216 static void guard_rec(type_t *type)
218 /* types that contain references to themselves (like a linked list),
219 need to be shielded from infinite recursion when writing embedded
220 types */
221 if (type->typestring_offset)
222 type->tfswrite = FALSE;
223 else
224 type->typestring_offset = 1;
227 static type_t *get_user_type(const type_t *t, const char **pname)
229 for (;;)
231 type_t *ut = get_attrp(t->attrs, ATTR_WIREMARSHAL);
232 if (ut)
234 if (pname)
235 *pname = t->name;
236 return ut;
239 if (t->kind == TKIND_ALIAS)
240 t = t->orig;
241 else
242 return 0;
246 int is_user_type(const type_t *t)
248 return get_user_type(t, NULL) != NULL;
251 static int is_embedded_complex(const type_t *type)
253 unsigned char tc = type->type;
254 return is_struct(tc) || is_union(tc) || is_array(type) || is_user_type(type)
255 || (is_ptr(type) && type->ref->type == RPC_FC_IP);
258 static const char *get_context_handle_type_name(const type_t *type)
260 const type_t *t;
261 for (t = type; is_ptr(t); t = t->ref)
262 if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
263 return t->name;
264 assert(0);
265 return NULL;
268 /* This is actually fairly involved to implement precisely, due to the
269 effects attributes may have and things like that. Right now this is
270 only used for optimization, so just check for a very small set of
271 criteria that guarantee the types are equivalent; assume every thing
272 else is different. */
273 static int compare_type(const type_t *a, const type_t *b)
275 if (a == b
276 || (a->name
277 && b->name
278 && strcmp(a->name, b->name) == 0))
279 return 0;
280 /* Ordering doesn't need to be implemented yet. */
281 return 1;
284 static int compare_expr(const expr_t *a, const expr_t *b)
286 int ret;
288 if (a->type != b->type)
289 return a->type - b->type;
291 switch (a->type)
293 case EXPR_NUM:
294 case EXPR_HEXNUM:
295 case EXPR_TRUEFALSE:
296 return a->u.lval - b->u.lval;
297 case EXPR_DOUBLE:
298 return a->u.dval - b->u.dval;
299 case EXPR_IDENTIFIER:
300 return strcmp(a->u.sval, b->u.sval);
301 case EXPR_COND:
302 ret = compare_expr(a->ref, b->ref);
303 if (ret != 0)
304 return ret;
305 ret = compare_expr(a->u.ext, b->u.ext);
306 if (ret != 0)
307 return ret;
308 return compare_expr(a->ext2, b->ext2);
309 case EXPR_OR:
310 case EXPR_AND:
311 case EXPR_ADD:
312 case EXPR_SUB:
313 case EXPR_MUL:
314 case EXPR_DIV:
315 case EXPR_SHL:
316 case EXPR_SHR:
317 ret = compare_expr(a->ref, b->ref);
318 if (ret != 0)
319 return ret;
320 return compare_expr(a->u.ext, b->u.ext);
321 case EXPR_CAST:
322 ret = compare_type(a->u.tref, b->u.tref);
323 if (ret != 0)
324 return ret;
325 /* Fall through. */
326 case EXPR_NOT:
327 case EXPR_NEG:
328 case EXPR_PPTR:
329 case EXPR_ADDRESSOF:
330 return compare_expr(a->ref, b->ref);
331 case EXPR_SIZEOF:
332 return compare_type(a->u.tref, b->u.tref);
333 case EXPR_VOID:
334 return 0;
336 return -1;
339 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
340 do { \
341 if (file) \
342 fprintf(file, "/* %2u */\n", typestring_offset); \
343 print_file((file), 2, "0x%02x, /* " #fctype " */\n", RPC_##fctype); \
345 while (0)
347 static void print_file(FILE *file, int indent, const char *format, ...)
349 va_list va;
350 va_start(va, format);
351 print(file, indent, format, va);
352 va_end(va);
355 void print(FILE *file, int indent, const char *format, va_list va)
357 if (file)
359 if (format[0] != '\n')
360 while (0 < indent--)
361 fprintf(file, " ");
362 vfprintf(file, format, va);
367 static void write_var_init(FILE *file, int indent, const type_t *t, const char *n)
369 if (decl_indirect(t))
370 print_file(file, indent, "MIDL_memset(&%s, 0, sizeof(%s));\n", n, n);
371 else if (is_ptr(t) || is_array(t))
372 print_file(file, indent, "%s = 0;\n", n);
375 void write_parameters_init(FILE *file, int indent, const func_t *func)
377 const var_t *var;
379 if (!is_void(func->def->type))
380 write_var_init(file, indent, func->def->type, "_RetVal");
382 if (!func->args)
383 return;
385 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
386 write_var_init(file, indent, var->type, var->name);
388 fprintf(file, "\n");
391 static void write_formatdesc(FILE *f, int indent, const char *str)
393 print_file(f, indent, "typedef struct _MIDL_%s_FORMAT_STRING\n", str);
394 print_file(f, indent, "{\n");
395 print_file(f, indent + 1, "short Pad;\n");
396 print_file(f, indent + 1, "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str);
397 print_file(f, indent, "} MIDL_%s_FORMAT_STRING;\n", str);
398 print_file(f, indent, "\n");
401 void write_formatstringsdecl(FILE *f, int indent, ifref_list_t *ifaces, type_pred_t pred)
403 print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n",
404 get_size_typeformatstring(ifaces, pred));
406 print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n",
407 get_size_procformatstring(ifaces, pred));
409 fprintf(f, "\n");
410 write_formatdesc(f, indent, "TYPE");
411 write_formatdesc(f, indent, "PROC");
412 fprintf(f, "\n");
413 print_file(f, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n");
414 print_file(f, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n");
415 print_file(f, indent, "\n");
418 static inline int is_base_type(unsigned char type)
420 switch (type)
422 case RPC_FC_BYTE:
423 case RPC_FC_CHAR:
424 case RPC_FC_USMALL:
425 case RPC_FC_SMALL:
426 case RPC_FC_WCHAR:
427 case RPC_FC_USHORT:
428 case RPC_FC_SHORT:
429 case RPC_FC_ULONG:
430 case RPC_FC_LONG:
431 case RPC_FC_HYPER:
432 case RPC_FC_IGNORE:
433 case RPC_FC_FLOAT:
434 case RPC_FC_DOUBLE:
435 case RPC_FC_ENUM16:
436 case RPC_FC_ENUM32:
437 case RPC_FC_ERROR_STATUS_T:
438 case RPC_FC_BIND_PRIMITIVE:
439 return TRUE;
441 default:
442 return FALSE;
446 int decl_indirect(const type_t *t)
448 return is_user_type(t)
449 || (!is_base_type(t->type)
450 && !is_ptr(t)
451 && !is_array(t));
454 static size_t write_procformatstring_var(FILE *file, int indent,
455 const var_t *var, int is_return)
457 size_t size;
458 const type_t *type = var->type;
460 int is_in = is_attr(var->attrs, ATTR_IN);
461 int is_out = is_attr(var->attrs, ATTR_OUT);
463 if (!is_in && !is_out) is_in = TRUE;
465 if (!type->declarray && is_base_type(type->type))
467 if (is_return)
468 print_file(file, indent, "0x53, /* FC_RETURN_PARAM_BASETYPE */\n");
469 else
470 print_file(file, indent, "0x4e, /* FC_IN_PARAM_BASETYPE */\n");
472 if (type->type == RPC_FC_BIND_PRIMITIVE)
474 print_file(file, indent, "0x%02x, /* FC_IGNORE */\n", RPC_FC_IGNORE);
475 size = 2; /* includes param type prefix */
477 else if (is_base_type(type->type))
479 print_file(file, indent, "0x%02x, /* %s */\n", type->type, string_of_type(type->type));
480 size = 2; /* includes param type prefix */
482 else
484 error("Unknown/unsupported type: %s (0x%02x)\n", var->name, type->type);
485 size = 0;
488 else
490 if (is_return)
491 print_file(file, indent, "0x52, /* FC_RETURN_PARAM */\n");
492 else if (is_in && is_out)
493 print_file(file, indent, "0x50, /* FC_IN_OUT_PARAM */\n");
494 else if (is_out)
495 print_file(file, indent, "0x51, /* FC_OUT_PARAM */\n");
496 else
497 print_file(file, indent, "0x4d, /* FC_IN_PARAM */\n");
499 print_file(file, indent, "0x01,\n");
500 print_file(file, indent, "NdrFcShort(0x%x),\n", type->typestring_offset);
501 size = 4; /* includes param type prefix */
503 return size;
506 void write_procformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
508 const ifref_t *iface;
509 int indent = 0;
510 const var_t *var;
512 print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
513 print_file(file, indent, "{\n");
514 indent++;
515 print_file(file, indent, "0,\n");
516 print_file(file, indent, "{\n");
517 indent++;
519 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
521 if (!pred(iface->iface))
522 continue;
524 if (iface->iface->funcs)
526 const func_t *func;
527 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
529 if (is_local(func->def->attrs)) continue;
530 /* emit argument data */
531 if (func->args)
533 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
534 write_procformatstring_var(file, indent, var, FALSE);
537 /* emit return value data */
538 var = func->def;
539 if (is_void(var->type))
541 print_file(file, indent, "0x5b, /* FC_END */\n");
542 print_file(file, indent, "0x5c, /* FC_PAD */\n");
544 else
545 write_procformatstring_var(file, indent, var, TRUE);
550 print_file(file, indent, "0x0\n");
551 indent--;
552 print_file(file, indent, "}\n");
553 indent--;
554 print_file(file, indent, "};\n");
555 print_file(file, indent, "\n");
558 static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
560 if (is_base_type(type->type))
562 print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
563 *typestring_offset += 1;
564 return 1;
567 return 0;
570 /* write conformance / variance descriptor */
571 static size_t write_conf_or_var_desc(FILE *file, const type_t *structure,
572 unsigned int baseoff, const type_t *type,
573 const expr_t *expr)
575 unsigned char operator_type = 0;
576 unsigned char conftype = RPC_FC_NORMAL_CONFORMANCE;
577 const char *conftype_string = "";
578 const char *operator_string = "no operators";
579 const expr_t *subexpr;
581 if (!expr)
583 print_file(file, 2, "NdrFcLong(0xffffffff),\t/* -1 */\n");
584 return 4;
587 if (!structure)
589 /* Top-level conformance calculations are done inline. */
590 print_file (file, 2, "0x%x,\t/* Corr desc: parameter */\n",
591 RPC_FC_TOP_LEVEL_CONFORMANCE);
592 print_file (file, 2, "0x0,\n");
593 print_file (file, 2, "NdrFcShort(0x0),\n");
594 return 4;
597 if (expr->is_const)
599 if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
600 error("write_conf_or_var_desc: constant value %ld is greater than "
601 "the maximum constant size of %d\n", expr->cval,
602 UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
604 print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n",
605 RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
606 print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX);
607 print_file(file, 2, "NdrFcShort(0x%x),\n", expr->cval & USHRT_MAX);
609 return 4;
612 if (is_ptr(type) || (is_array(type) && !type->declarray))
614 conftype = RPC_FC_POINTER_CONFORMANCE;
615 conftype_string = "field pointer, ";
618 subexpr = expr;
619 switch (subexpr->type)
621 case EXPR_PPTR:
622 subexpr = subexpr->ref;
623 operator_type = RPC_FC_DEREFERENCE;
624 operator_string = "FC_DEREFERENCE";
625 break;
626 case EXPR_DIV:
627 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
629 subexpr = subexpr->ref;
630 operator_type = RPC_FC_DIV_2;
631 operator_string = "FC_DIV_2";
633 break;
634 case EXPR_MUL:
635 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
637 subexpr = subexpr->ref;
638 operator_type = RPC_FC_MULT_2;
639 operator_string = "FC_MULT_2";
641 break;
642 case EXPR_SUB:
643 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
645 subexpr = subexpr->ref;
646 operator_type = RPC_FC_SUB_1;
647 operator_string = "FC_SUB_1";
649 break;
650 case EXPR_ADD:
651 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
653 subexpr = subexpr->ref;
654 operator_type = RPC_FC_ADD_1;
655 operator_string = "FC_ADD_1";
657 break;
658 default:
659 break;
662 if (subexpr->type == EXPR_IDENTIFIER)
664 const type_t *correlation_variable = NULL;
665 unsigned char correlation_variable_type;
666 unsigned char param_type = 0;
667 size_t offset = 0;
668 const var_t *var;
670 if (structure->fields) LIST_FOR_EACH_ENTRY( var, structure->fields, const var_t, entry )
672 unsigned int align = 0;
673 /* FIXME: take alignment into account */
674 if (var->name && !strcmp(var->name, subexpr->u.sval))
676 correlation_variable = var->type;
677 break;
679 offset += type_memsize(var->type, &align);
681 if (!correlation_variable)
682 error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
683 subexpr->u.sval);
685 offset -= baseoff;
686 correlation_variable_type = correlation_variable->type;
688 switch (correlation_variable_type)
690 case RPC_FC_CHAR:
691 case RPC_FC_SMALL:
692 param_type = RPC_FC_SMALL;
693 break;
694 case RPC_FC_BYTE:
695 case RPC_FC_USMALL:
696 param_type = RPC_FC_USMALL;
697 break;
698 case RPC_FC_WCHAR:
699 case RPC_FC_SHORT:
700 case RPC_FC_ENUM16:
701 param_type = RPC_FC_SHORT;
702 break;
703 case RPC_FC_USHORT:
704 param_type = RPC_FC_USHORT;
705 break;
706 case RPC_FC_LONG:
707 case RPC_FC_ENUM32:
708 param_type = RPC_FC_LONG;
709 break;
710 case RPC_FC_ULONG:
711 param_type = RPC_FC_ULONG;
712 break;
713 case RPC_FC_RP:
714 case RPC_FC_UP:
715 case RPC_FC_OP:
716 case RPC_FC_FP:
717 if (sizeof(void *) == 4) /* FIXME */
718 param_type = RPC_FC_LONG;
719 else
720 param_type = RPC_FC_HYPER;
721 break;
722 default:
723 error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
724 correlation_variable_type);
727 print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
728 conftype | param_type, conftype_string, string_of_type(param_type));
729 print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string);
730 print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d */\n",
731 offset, offset);
733 else
735 unsigned int callback_offset = 0;
736 struct expr_eval_routine *eval;
737 int found = 0;
739 LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
741 if (!strcmp (eval->structure->name, structure->name)
742 && !compare_expr (eval->expr, expr))
744 found = 1;
745 break;
747 callback_offset++;
750 if (!found)
752 eval = xmalloc (sizeof(*eval));
753 eval->structure = structure;
754 eval->baseoff = baseoff;
755 eval->expr = expr;
756 list_add_tail (&expr_eval_routines, &eval->entry);
759 if (callback_offset > USHRT_MAX)
760 error("Maximum number of callback routines reached\n");
762 print_file(file, 2, "0x%x, /* Corr desc: %s */\n", conftype, conftype_string);
763 print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
764 print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", callback_offset, callback_offset);
766 return 4;
769 static size_t fields_memsize(const var_list_t *fields, unsigned int *align)
771 int have_align = FALSE;
772 size_t size = 0;
773 const var_t *v;
775 if (!fields) return 0;
776 LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
778 unsigned int falign = 0;
779 size_t fsize = type_memsize(v->type, &falign);
780 if (!have_align)
782 *align = falign;
783 have_align = TRUE;
785 size = (size + (falign - 1)) & ~(falign - 1);
786 size += fsize;
789 size = (size + (*align - 1)) & ~(*align - 1);
790 return size;
793 static size_t union_memsize(const var_list_t *fields, unsigned int *pmaxa)
795 size_t size, maxs = 0;
796 unsigned int align = *pmaxa;
797 const var_t *v;
799 if (fields) LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
801 /* we could have an empty default field with NULL type */
802 if (v->type)
804 size = type_memsize(v->type, &align);
805 if (maxs < size) maxs = size;
806 if (*pmaxa < align) *pmaxa = align;
810 return maxs;
813 int get_padding(const var_list_t *fields)
815 unsigned short offset = 0;
816 int salign = -1;
817 const var_t *f;
819 if (!fields)
820 return 0;
822 LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry)
824 type_t *ft = f->type;
825 unsigned int align = 0;
826 size_t size = type_memsize(ft, &align);
827 if (salign == -1)
828 salign = align;
829 offset = (offset + (align - 1)) & ~(align - 1);
830 offset += size;
833 return ((offset + (salign - 1)) & ~(salign - 1)) - offset;
836 size_t type_memsize(const type_t *t, unsigned int *align)
838 size_t size = 0;
840 if (t->declarray && is_conformant_array(t))
842 type_memsize(t->ref, align);
843 size = 0;
845 else if (is_ptr(t) || is_conformant_array(t))
847 size = sizeof(void *);
848 if (size > *align) *align = size;
850 else switch (t->type)
852 case RPC_FC_BYTE:
853 case RPC_FC_CHAR:
854 case RPC_FC_USMALL:
855 case RPC_FC_SMALL:
856 size = 1;
857 if (size > *align) *align = size;
858 break;
859 case RPC_FC_WCHAR:
860 case RPC_FC_USHORT:
861 case RPC_FC_SHORT:
862 case RPC_FC_ENUM16:
863 size = 2;
864 if (size > *align) *align = size;
865 break;
866 case RPC_FC_ULONG:
867 case RPC_FC_LONG:
868 case RPC_FC_ERROR_STATUS_T:
869 case RPC_FC_ENUM32:
870 case RPC_FC_FLOAT:
871 size = 4;
872 if (size > *align) *align = size;
873 break;
874 case RPC_FC_HYPER:
875 case RPC_FC_DOUBLE:
876 size = 8;
877 if (size > *align) *align = size;
878 break;
879 case RPC_FC_STRUCT:
880 case RPC_FC_CVSTRUCT:
881 case RPC_FC_CPSTRUCT:
882 case RPC_FC_CSTRUCT:
883 case RPC_FC_PSTRUCT:
884 case RPC_FC_BOGUS_STRUCT:
885 size = fields_memsize(t->fields, align);
886 break;
887 case RPC_FC_ENCAPSULATED_UNION:
888 case RPC_FC_NON_ENCAPSULATED_UNION:
889 size = union_memsize(t->fields, align);
890 break;
891 case RPC_FC_SMFARRAY:
892 case RPC_FC_LGFARRAY:
893 case RPC_FC_SMVARRAY:
894 case RPC_FC_LGVARRAY:
895 case RPC_FC_BOGUS_ARRAY:
896 size = t->dim * type_memsize(t->ref, align);
897 break;
898 default:
899 error("type_memsize: Unknown type %d\n", t->type);
900 size = 0;
903 return size;
906 static unsigned int write_nonsimple_pointer(FILE *file, const type_t *type, size_t offset)
908 short absoff = type->ref->typestring_offset;
909 short reloff = absoff - (offset + 2);
910 int ptr_attr = is_ptr(type->ref) ? 0x10 : 0x0;
912 print_file(file, 2, "0x%02x, 0x%x,\t/* %s */\n",
913 type->type, ptr_attr, string_of_type(type->type));
914 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%hd) */\n",
915 reloff, reloff, absoff);
916 return 4;
919 static unsigned char conf_string_type_of_char_type(unsigned char t)
921 switch (t)
923 case RPC_FC_BYTE:
924 case RPC_FC_CHAR:
925 return RPC_FC_C_CSTRING;
926 case RPC_FC_WCHAR:
927 return RPC_FC_C_WSTRING;
930 error("string_type_of_char_type: unrecognized type %d\n", t);
931 return 0;
934 static unsigned int write_simple_pointer(FILE *file, const type_t *type)
936 unsigned char fc
937 = is_string_type(type->attrs, type)
938 ? conf_string_type_of_char_type(type->ref->type)
939 : type->ref->type;
940 print_file(file, 2, "0x%02x, 0x8,\t/* %s [simple_pointer] */\n",
941 type->type, string_of_type(type->type));
942 print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
943 print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
944 return 4;
947 static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff)
949 print_file(file, 0, "/* %u (", tfsoff);
950 write_type_decl(file, t, NULL);
951 print_file(file, 0, ") */\n");
954 static size_t write_pointer_tfs(FILE *file, type_t *type, unsigned int *typestring_offset)
956 unsigned int offset = *typestring_offset;
958 print_start_tfs_comment(file, type, offset);
959 update_tfsoff(type, offset, file);
961 if (type->ref->typestring_offset)
962 *typestring_offset += write_nonsimple_pointer(file, type, offset);
963 else if (is_base_type(type->ref->type))
964 *typestring_offset += write_simple_pointer(file, type);
966 return offset;
969 static int processed(const type_t *type)
971 return type->typestring_offset && !type->tfswrite;
974 static int user_type_has_variable_size(const type_t *t)
976 if (is_ptr(t))
977 return TRUE;
978 else
979 switch (t->type)
981 case RPC_FC_PSTRUCT:
982 case RPC_FC_CSTRUCT:
983 case RPC_FC_CPSTRUCT:
984 case RPC_FC_CVSTRUCT:
985 return TRUE;
987 /* Note: Since this only applies to user types, we can't have a conformant
988 array here, and strings should get filed under pointer in this case. */
989 return FALSE;
992 static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
994 unsigned int start, absoff, flags;
995 unsigned int align = 0, ualign = 0;
996 const char *name;
997 type_t *utype = get_user_type(type, &name);
998 size_t usize = user_type_has_variable_size(utype) ? 0 : type_memsize(utype, &ualign);
999 size_t size = type_memsize(type, &align);
1000 unsigned short funoff = user_type_offset(name);
1001 short reloff;
1003 guard_rec(type);
1005 if (is_base_type(utype->type))
1007 absoff = *tfsoff;
1008 print_start_tfs_comment(file, utype, absoff);
1009 print_file(file, 2, "0x%x,\t/* %s */\n", utype->type, string_of_type(utype->type));
1010 print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
1011 *tfsoff += 2;
1013 else
1015 if (!processed(utype))
1016 write_embedded_types(file, NULL, utype, utype->name, TRUE, tfsoff);
1017 absoff = utype->typestring_offset;
1020 if (utype->type == RPC_FC_RP)
1021 flags = 0x40;
1022 else if (utype->type == RPC_FC_UP)
1023 flags = 0x80;
1024 else
1025 flags = 0;
1027 start = *tfsoff;
1028 update_tfsoff(type, start, file);
1029 print_start_tfs_comment(file, type, start);
1030 print_file(file, 2, "0x%x,\t/* FC_USER_MARSHAL */\n", RPC_FC_USER_MARSHAL);
1031 print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
1032 flags | (align - 1), align - 1, flags);
1033 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
1034 print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", size, size);
1035 print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize);
1036 *tfsoff += 8;
1037 reloff = absoff - *tfsoff;
1038 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", reloff, reloff, absoff);
1039 *tfsoff += 2;
1042 static void write_member_type(FILE *file, const type_t *cont,
1043 const attr_list_t *attrs, const type_t *type,
1044 unsigned int *corroff, unsigned int *tfsoff)
1046 if (is_embedded_complex(type) && !is_conformant_array(type))
1048 size_t absoff;
1049 short reloff;
1051 if (is_union(type->type) && is_attr(attrs, ATTR_SWITCHIS))
1053 absoff = *corroff;
1054 *corroff += 8;
1056 else
1058 absoff = type->typestring_offset;
1060 reloff = absoff - (*tfsoff + 2);
1062 print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
1063 /* FIXME: actually compute necessary padding */
1064 print_file(file, 2, "0x0,\t/* FIXME: padding */\n");
1065 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1066 reloff, reloff, absoff);
1067 *tfsoff += 4;
1069 else if (is_ptr(type) || is_conformant_array(type))
1071 unsigned char fc = (cont->type == RPC_FC_BOGUS_STRUCT
1072 ? RPC_FC_POINTER
1073 : RPC_FC_LONG);
1074 print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1075 *tfsoff += 1;
1077 else if (!write_base_type(file, type, tfsoff))
1078 error("Unsupported member type 0x%x\n", type->type);
1081 static void write_end(FILE *file, unsigned int *tfsoff)
1083 if (*tfsoff % 2 == 0)
1085 print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD);
1086 *tfsoff += 1;
1088 print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END);
1089 *tfsoff += 1;
1092 static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
1094 unsigned int offset = 0;
1095 var_list_t *fs = type->fields;
1096 var_t *f;
1098 if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
1100 unsigned int align = 0;
1101 type_t *ft = f->type;
1102 if (is_union(ft->type) && is_attr(f->attrs, ATTR_SWITCHIS))
1104 unsigned int absoff = ft->typestring_offset;
1105 short reloff = absoff - (*tfsoff + 6);
1106 print_file(file, 0, "/* %d */\n", *tfsoff);
1107 print_file(file, 2, "0x%x,\t/* %s */\n", ft->type, string_of_type(ft->type));
1108 print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", RPC_FC_LONG);
1109 write_conf_or_var_desc(file, current_structure, offset, ft,
1110 get_attrp(f->attrs, ATTR_SWITCHIS));
1111 print_file(file, 2, "NdrFcShort(%hd),\t/* Offset= %hd (%u) */\n",
1112 reloff, reloff, absoff);
1113 *tfsoff += 8;
1116 /* FIXME: take alignment into account */
1117 offset += type_memsize(ft, &align);
1121 static int write_no_repeat_pointer_descriptions(
1122 FILE *file, type_t *type,
1123 size_t *offset_in_memory, size_t *offset_in_buffer,
1124 unsigned int *typestring_offset)
1126 int written = 0;
1127 unsigned int align;
1129 if (is_ptr(type) || (!type->declarray && is_conformant_array(type)))
1131 print_file(file, 2, "0x%02x, /* FC_NO_REPEAT */\n", RPC_FC_NO_REPEAT);
1132 print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1134 /* pointer instance */
1135 print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1136 print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1137 *typestring_offset += 6;
1139 if (is_ptr(type))
1140 write_pointer_tfs(file, type, typestring_offset);
1141 else
1143 unsigned absoff = type->typestring_offset;
1144 short reloff = absoff - (*typestring_offset + 2);
1145 /* FIXME: get pointer attributes from field */
1146 print_file(file, 2, "0x%02x, 0x0,\t/* %s */\n", RPC_FC_UP, "FC_UP");
1147 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1148 reloff, reloff, absoff);
1149 *typestring_offset += 4;
1152 align = 0;
1153 *offset_in_memory += type_memsize(type, &align);
1154 /* FIXME: is there a case where these two are different? */
1155 align = 0;
1156 *offset_in_buffer += type_memsize(type, &align);
1158 return 1;
1161 if (is_non_complex_struct(type))
1163 const var_t *v;
1164 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1165 written += write_no_repeat_pointer_descriptions(
1166 file, v->type,
1167 offset_in_memory, offset_in_buffer, typestring_offset);
1169 else
1171 align = 0;
1172 *offset_in_memory += type_memsize(type, &align);
1173 /* FIXME: is there a case where these two are different? */
1174 align = 0;
1175 *offset_in_buffer += type_memsize(type, &align);
1178 return written;
1181 static int write_pointer_description_offsets(
1182 FILE *file, const attr_list_t *attrs, type_t *type,
1183 size_t *offset_in_memory, size_t *offset_in_buffer,
1184 unsigned int *typestring_offset)
1186 int written = 0;
1187 unsigned int align;
1189 if (is_ptr(type) && type->ref->type != RPC_FC_IP)
1191 if (offset_in_memory && offset_in_buffer)
1193 /* pointer instance */
1194 /* FIXME: sometimes from end of structure, sometimes from beginning */
1195 print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1196 print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1198 align = 0;
1199 *offset_in_memory += type_memsize(type, &align);
1200 /* FIXME: is there a case where these two are different? */
1201 align = 0;
1202 *offset_in_buffer += type_memsize(type, &align);
1204 *typestring_offset += 4;
1206 if (processed(type->ref) || is_base_type(type->ref->type))
1207 write_pointer_tfs(file, type, typestring_offset);
1208 else
1209 error("write_pointer_description_offsets: type format string unknown\n");
1211 return 1;
1214 if (is_array(type))
1216 return write_pointer_description_offsets(
1217 file, attrs, type->ref, offset_in_memory, offset_in_buffer,
1218 typestring_offset);
1220 else if (is_non_complex_struct(type))
1222 /* otherwise search for interesting fields to parse */
1223 const var_t *v;
1224 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1226 written += write_pointer_description_offsets(
1227 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1228 typestring_offset);
1231 else
1233 align = 0;
1234 if (offset_in_memory)
1235 *offset_in_memory += type_memsize(type, &align);
1236 /* FIXME: is there a case where these two are different? */
1237 align = 0;
1238 if (offset_in_buffer)
1239 *offset_in_buffer += type_memsize(type, &align);
1242 return written;
1245 /* Note: if file is NULL return value is number of pointers to write, else
1246 * it is the number of type format characters written */
1247 static int write_fixed_array_pointer_descriptions(
1248 FILE *file, const attr_list_t *attrs, type_t *type,
1249 size_t *offset_in_memory, size_t *offset_in_buffer,
1250 unsigned int *typestring_offset)
1252 unsigned int align;
1253 int pointer_count = 0;
1255 if (type->type == RPC_FC_SMFARRAY || type->type == RPC_FC_LGFARRAY)
1257 unsigned int temp = 0;
1258 /* unfortunately, this needs to be done in two passes to avoid
1259 * writing out redundant FC_FIXED_REPEAT descriptions */
1260 pointer_count = write_pointer_description_offsets(
1261 NULL, attrs, type->ref, NULL, NULL, &temp);
1262 if (pointer_count > 0)
1264 unsigned int increment_size;
1265 size_t offset_of_array_pointer_mem = 0;
1266 size_t offset_of_array_pointer_buf = 0;
1268 align = 0;
1269 increment_size = type_memsize(type->ref, &align);
1271 print_file(file, 2, "0x%02x, /* FC_FIXED_REPEAT */\n", RPC_FC_FIXED_REPEAT);
1272 print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1273 print_file(file, 2, "NdrFcShort(0x%x), /* Iterations = %d */\n", type->dim, type->dim);
1274 print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1275 print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory);
1276 print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1277 *typestring_offset += 10;
1279 pointer_count = write_pointer_description_offsets(
1280 file, attrs, type, &offset_of_array_pointer_mem,
1281 &offset_of_array_pointer_buf, typestring_offset);
1284 else if (is_struct(type->type))
1286 const var_t *v;
1287 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1289 pointer_count += write_fixed_array_pointer_descriptions(
1290 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1291 typestring_offset);
1294 else
1296 align = 0;
1297 if (offset_in_memory)
1298 *offset_in_memory += type_memsize(type, &align);
1299 /* FIXME: is there a case where these two are different? */
1300 align = 0;
1301 if (offset_in_buffer)
1302 *offset_in_buffer += type_memsize(type, &align);
1305 return pointer_count;
1308 /* Note: if file is NULL return value is number of pointers to write, else
1309 * it is the number of type format characters written */
1310 static int write_conformant_array_pointer_descriptions(
1311 FILE *file, const attr_list_t *attrs, type_t *type,
1312 size_t offset_in_memory, unsigned int *typestring_offset)
1314 unsigned int align;
1315 int pointer_count = 0;
1317 if (is_conformant_array(type) && !type->length_is)
1319 unsigned int temp = 0;
1320 /* unfortunately, this needs to be done in two passes to avoid
1321 * writing out redundant FC_VARIABLE_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 = offset_in_memory;
1328 size_t offset_of_array_pointer_buf = offset_in_memory;
1330 align = 0;
1331 increment_size = type_memsize(type->ref, &align);
1333 if (increment_size > USHRT_MAX)
1334 error("array size of %u bytes is too large\n", increment_size);
1336 print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
1337 print_file(file, 2, "0x%02x, /* FC_FIXED_OFFSET */\n", RPC_FC_FIXED_OFFSET);
1338 print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1339 print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", offset_in_memory, offset_in_memory);
1340 print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1341 *typestring_offset += 8;
1343 pointer_count = write_pointer_description_offsets(
1344 file, attrs, type->ref, &offset_of_array_pointer_mem,
1345 &offset_of_array_pointer_buf, typestring_offset);
1349 return pointer_count;
1352 /* Note: if file is NULL return value is number of pointers to write, else
1353 * it is the number of type format characters written */
1354 static int write_varying_array_pointer_descriptions(
1355 FILE *file, const attr_list_t *attrs, type_t *type,
1356 size_t *offset_in_memory, size_t *offset_in_buffer,
1357 unsigned int *typestring_offset)
1359 unsigned int align;
1360 int pointer_count = 0;
1362 /* FIXME: do varying array searching here, but pointer searching in write_pointer_description_offsets */
1364 if (is_array(type) && type->length_is)
1366 unsigned int temp = 0;
1367 /* unfortunately, this needs to be done in two passes to avoid
1368 * writing out redundant FC_VARIABLE_REPEAT descriptions */
1369 pointer_count = write_pointer_description_offsets(
1370 NULL, attrs, type->ref, NULL, NULL, &temp);
1371 if (pointer_count > 0)
1373 unsigned int increment_size;
1374 size_t offset_of_array_pointer_mem = 0;
1375 size_t offset_of_array_pointer_buf = 0;
1377 align = 0;
1378 increment_size = type_memsize(type->ref, &align);
1380 if (increment_size > USHRT_MAX)
1381 error("array size of %u bytes is too large\n", increment_size);
1383 print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
1384 print_file(file, 2, "0x%02x, /* FC_VARIABLE_OFFSET */\n", RPC_FC_VARIABLE_OFFSET);
1385 print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1386 print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory);
1387 print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1388 *typestring_offset += 8;
1390 pointer_count = write_pointer_description_offsets(
1391 file, attrs, type, &offset_of_array_pointer_mem,
1392 &offset_of_array_pointer_buf, typestring_offset);
1395 else if (is_struct(type->type))
1397 const var_t *v;
1398 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1400 pointer_count += write_varying_array_pointer_descriptions(
1401 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1402 typestring_offset);
1405 else
1407 align = 0;
1408 if (offset_in_memory)
1409 *offset_in_memory += type_memsize(type, &align);
1410 /* FIXME: is there a case where these two are different? */
1411 align = 0;
1412 if (offset_in_buffer)
1413 *offset_in_buffer += type_memsize(type, &align);
1416 return pointer_count;
1419 static void write_pointer_description(FILE *file, type_t *type,
1420 unsigned int *typestring_offset)
1422 size_t offset_in_buffer;
1423 size_t offset_in_memory;
1425 /* pass 1: search for single instance of a pointer (i.e. don't descend
1426 * into arrays) */
1427 if (!is_array(type))
1429 offset_in_memory = 0;
1430 offset_in_buffer = 0;
1431 write_no_repeat_pointer_descriptions(
1432 file, type,
1433 &offset_in_memory, &offset_in_buffer, typestring_offset);
1436 /* pass 2: search for pointers in fixed arrays */
1437 offset_in_memory = 0;
1438 offset_in_buffer = 0;
1439 write_fixed_array_pointer_descriptions(
1440 file, NULL, type,
1441 &offset_in_memory, &offset_in_buffer, typestring_offset);
1443 /* pass 3: search for pointers in conformant only arrays (but don't descend
1444 * into conformant varying or varying arrays) */
1445 if ((!type->declarray || !current_structure) && is_conformant_array(type))
1446 write_conformant_array_pointer_descriptions(
1447 file, NULL, type, 0, typestring_offset);
1448 else if (type->type == RPC_FC_CPSTRUCT)
1450 unsigned int align = 0;
1451 type_t *carray = find_array_or_string_in_struct(type)->type;
1452 write_conformant_array_pointer_descriptions(
1453 file, NULL, carray,
1454 type_memsize(type, &align),
1455 typestring_offset);
1458 /* pass 4: search for pointers in varying arrays */
1459 offset_in_memory = 0;
1460 offset_in_buffer = 0;
1461 write_varying_array_pointer_descriptions(
1462 file, NULL, type,
1463 &offset_in_memory, &offset_in_buffer, typestring_offset);
1466 int is_declptr(const type_t *t)
1468 return is_ptr(t) || (is_conformant_array(t) && !t->declarray);
1471 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
1472 type_t *type,
1473 const char *name, unsigned int *typestring_offset,
1474 int toplevel)
1476 size_t start_offset;
1477 unsigned char rtype;
1479 if (toplevel && is_declptr(type))
1481 unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER;
1482 int pointer_type = is_ptr(type) ? type->type : get_attrv(attrs, ATTR_POINTERTYPE);
1483 if (!pointer_type)
1484 pointer_type = RPC_FC_RP;
1485 print_file(file, 2,"0x%x, 0x%x,\t/* %s%s */\n",
1486 pointer_type, flag, string_of_type(pointer_type),
1487 flag ? " [simple_pointer]" : "");
1488 *typestring_offset += 2;
1489 if (!flag)
1491 print_file(file, 2, "NdrFcShort(0x2),\n");
1492 *typestring_offset += 2;
1496 start_offset = *typestring_offset;
1497 update_tfsoff(type, start_offset, file);
1499 rtype = type->ref->type;
1501 if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR))
1503 error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
1504 return start_offset;
1507 if (type->declarray && !is_conformant_array(type))
1509 /* FIXME: multi-dimensional array */
1510 if (0xffffuL < type->dim)
1511 error("array size for parameter %s exceeds %u bytes by %lu bytes\n",
1512 name, 0xffffu, type->dim - 0xffffu);
1514 if (rtype == RPC_FC_CHAR)
1515 WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
1516 else
1517 WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
1518 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1519 *typestring_offset += 2;
1521 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", type->dim, type->dim);
1522 *typestring_offset += 2;
1524 return start_offset;
1526 else if (type->size_is)
1528 unsigned int align = 0;
1530 if (rtype == RPC_FC_CHAR)
1531 WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
1532 else
1533 WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
1534 print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
1535 *typestring_offset += 2;
1537 *typestring_offset += write_conf_or_var_desc(
1538 file, current_structure,
1539 (type->declarray && current_structure
1540 ? type_memsize(current_structure, &align)
1541 : 0),
1542 type, type->size_is);
1544 return start_offset;
1546 else
1548 if (rtype == RPC_FC_WCHAR)
1549 WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
1550 else
1551 WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
1552 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1553 *typestring_offset += 2;
1555 return start_offset;
1559 static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
1560 const char *name, unsigned int *typestring_offset)
1562 const expr_t *length_is = type->length_is;
1563 const expr_t *size_is = type->size_is;
1564 unsigned int align = 0;
1565 size_t size;
1566 size_t start_offset;
1567 int has_pointer;
1568 int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
1569 unsigned int baseoff
1570 = type->declarray && current_structure
1571 ? type_memsize(current_structure, &align)
1572 : 0;
1574 if (!pointer_type)
1575 pointer_type = RPC_FC_RP;
1577 if (write_embedded_types(file, attrs, type->ref, name, FALSE, typestring_offset))
1578 has_pointer = TRUE;
1579 else
1580 has_pointer = type_has_pointers(type->ref);
1582 align = 0;
1583 size = type_memsize((is_conformant_array(type) ? type->ref : type), &align);
1585 start_offset = *typestring_offset;
1586 update_tfsoff(type, start_offset, file);
1587 print_start_tfs_comment(file, type, start_offset);
1588 print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
1589 print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1590 *typestring_offset += 2;
1592 align = 0;
1593 if (type->type != RPC_FC_BOGUS_ARRAY)
1595 unsigned char tc = type->type;
1597 if (tc == RPC_FC_LGFARRAY || tc == RPC_FC_LGVARRAY)
1599 print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", size, size);
1600 *typestring_offset += 4;
1602 else
1604 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", size, size);
1605 *typestring_offset += 2;
1608 if (is_conformant_array(type))
1609 *typestring_offset
1610 += write_conf_or_var_desc(file, current_structure, baseoff,
1611 type, size_is);
1613 if (type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY)
1615 unsigned int elalign = 0;
1616 size_t elsize = type_memsize(type->ref, &elalign);
1618 if (type->type == RPC_FC_LGVARRAY)
1620 print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", type->dim, type->dim);
1621 *typestring_offset += 4;
1623 else
1625 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", type->dim, type->dim);
1626 *typestring_offset += 2;
1629 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", elsize, elsize);
1630 *typestring_offset += 2;
1633 if (length_is)
1634 *typestring_offset
1635 += write_conf_or_var_desc(file, current_structure, baseoff,
1636 type, length_is);
1638 if (has_pointer && (!type->declarray || !current_structure))
1640 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1641 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1642 *typestring_offset += 2;
1643 write_pointer_description(file, type, typestring_offset);
1644 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1645 *typestring_offset += 1;
1648 write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1649 write_end(file, typestring_offset);
1651 else
1653 unsigned int dim = size_is ? 0 : type->dim;
1654 print_file(file, 2, "NdrFcShort(0x%x),\t/* %u */\n", dim, dim);
1655 *typestring_offset += 2;
1656 *typestring_offset
1657 += write_conf_or_var_desc(file, current_structure, baseoff,
1658 type, size_is);
1659 *typestring_offset
1660 += write_conf_or_var_desc(file, current_structure, baseoff,
1661 type, length_is);
1662 write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1663 write_end(file, typestring_offset);
1666 return start_offset;
1669 static const var_t *find_array_or_string_in_struct(const type_t *type)
1671 const var_t *last_field = LIST_ENTRY( list_tail(type->fields), const var_t, entry );
1672 const type_t *ft = last_field->type;
1674 if (ft->declarray && is_conformant_array(ft))
1675 return last_field;
1677 if (ft->type == RPC_FC_CSTRUCT || ft->type == RPC_FC_CPSTRUCT || ft->type == RPC_FC_CVSTRUCT)
1678 return find_array_or_string_in_struct(last_field->type);
1679 else
1680 return NULL;
1683 static void write_struct_members(FILE *file, const type_t *type,
1684 unsigned int *corroff, unsigned int *typestring_offset)
1686 const var_t *field;
1687 unsigned short offset = 0;
1688 int salign = -1;
1689 int padding;
1691 if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1693 type_t *ft = field->type;
1694 if (!ft->declarray || !is_conformant_array(ft))
1696 unsigned int align = 0;
1697 size_t size = type_memsize(ft, &align);
1698 if (salign == -1)
1699 salign = align;
1700 if ((align - 1) & offset)
1702 unsigned char fc = 0;
1703 switch (align)
1705 case 4:
1706 fc = RPC_FC_ALIGNM4;
1707 break;
1708 case 8:
1709 fc = RPC_FC_ALIGNM8;
1710 break;
1711 default:
1712 error("write_struct_members: cannot align type %d\n", ft->type);
1714 print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1715 offset = (offset + (align - 1)) & ~(align - 1);
1716 *typestring_offset += 1;
1718 write_member_type(file, type, field->attrs, field->type, corroff,
1719 typestring_offset);
1720 offset += size;
1724 padding = ((offset + (salign - 1)) & ~(salign - 1)) - offset;
1725 if (padding)
1727 print_file(file, 2, "0x%x,\t/* FC_STRUCTPAD%d */\n",
1728 RPC_FC_STRUCTPAD1 + padding - 1,
1729 padding);
1730 *typestring_offset += 1;
1733 write_end(file, typestring_offset);
1736 static size_t write_struct_tfs(FILE *file, type_t *type,
1737 const char *name, unsigned int *tfsoff)
1739 const type_t *save_current_structure = current_structure;
1740 unsigned int total_size;
1741 const var_t *array;
1742 size_t start_offset;
1743 size_t array_offset;
1744 int has_pointers = 0;
1745 unsigned int align = 0;
1746 unsigned int corroff;
1747 var_t *f;
1749 guard_rec(type);
1750 current_structure = type;
1752 total_size = type_memsize(type, &align);
1753 if (total_size > USHRT_MAX)
1754 error("structure size for %s exceeds %d bytes by %d bytes\n",
1755 name, USHRT_MAX, total_size - USHRT_MAX);
1757 if (type->fields) LIST_FOR_EACH_ENTRY(f, type->fields, var_t, entry)
1758 has_pointers |= write_embedded_types(file, f->attrs, f->type, f->name,
1759 FALSE, tfsoff);
1760 if (!has_pointers) has_pointers = type_has_pointers(type);
1762 array = find_array_or_string_in_struct(type);
1763 if (array && !processed(array->type))
1764 array_offset
1765 = is_attr(array->attrs, ATTR_STRING)
1766 ? write_string_tfs(file, array->attrs, array->type, array->name, tfsoff, FALSE)
1767 : write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
1769 corroff = *tfsoff;
1770 write_descriptors(file, type, tfsoff);
1772 start_offset = *tfsoff;
1773 update_tfsoff(type, start_offset, file);
1774 print_start_tfs_comment(file, type, start_offset);
1775 print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
1776 print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1777 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size);
1778 *tfsoff += 4;
1780 if (array)
1782 unsigned int absoff = array->type->typestring_offset;
1783 short reloff = absoff - *tfsoff;
1784 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1785 reloff, reloff, absoff);
1786 *tfsoff += 2;
1788 else if (type->type == RPC_FC_BOGUS_STRUCT)
1790 print_file(file, 2, "NdrFcShort(0x0),\n");
1791 *tfsoff += 2;
1794 if (type->type == RPC_FC_BOGUS_STRUCT)
1796 /* On the sizing pass, type->ptrdesc may be zero, but it's ok as
1797 nothing is written to file yet. On the actual writing pass,
1798 this will have been updated. */
1799 unsigned int absoff = type->ptrdesc ? type->ptrdesc : *tfsoff;
1800 short reloff = absoff - *tfsoff;
1801 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1802 reloff, reloff, absoff);
1803 *tfsoff += 2;
1805 else if ((type->type == RPC_FC_PSTRUCT) ||
1806 (type->type == RPC_FC_CPSTRUCT) ||
1807 (type->type == RPC_FC_CVSTRUCT && has_pointers))
1809 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1810 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1811 *tfsoff += 2;
1812 write_pointer_description(file, type, tfsoff);
1813 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1814 *tfsoff += 1;
1817 write_struct_members(file, type, &corroff, tfsoff);
1819 if (type->type == RPC_FC_BOGUS_STRUCT)
1821 const var_list_t *fs = type->fields;
1822 const var_t *f;
1824 type->ptrdesc = *tfsoff;
1825 if (fs) LIST_FOR_EACH_ENTRY(f, fs, const var_t, entry)
1827 type_t *ft = f->type;
1828 if (is_ptr(ft))
1829 write_pointer_tfs(file, ft, tfsoff);
1830 else if (!ft->declarray && is_conformant_array(ft))
1832 unsigned int absoff = ft->typestring_offset;
1833 short reloff = absoff - (*tfsoff + 2);
1834 int ptr_type = get_attrv(f->attrs, ATTR_POINTERTYPE);
1835 /* FIXME: We need to store pointer attributes for arrays
1836 so we don't lose pointer_default info. */
1837 if (ptr_type == 0)
1838 ptr_type = RPC_FC_UP;
1839 print_file(file, 0, "/* %d */\n", *tfsoff);
1840 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
1841 string_of_type(ptr_type));
1842 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1843 reloff, reloff, absoff);
1844 *tfsoff += 4;
1847 if (type->ptrdesc == *tfsoff)
1848 type->ptrdesc = 0;
1851 current_structure = save_current_structure;
1852 return start_offset;
1855 static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
1856 unsigned char flags, size_t offset,
1857 unsigned int *typeformat_offset)
1859 size_t start_offset = *typeformat_offset;
1860 short reloff = offset - (*typeformat_offset + 2);
1861 int in_attr, out_attr;
1862 in_attr = is_attr(attrs, ATTR_IN);
1863 out_attr = is_attr(attrs, ATTR_OUT);
1864 if (!in_attr && !out_attr) in_attr = 1;
1866 if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
1867 flags |= 0x04;
1869 print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
1870 pointer_type,
1871 flags,
1872 string_of_type(pointer_type));
1873 if (file)
1875 if (flags & 0x04)
1876 fprintf(file, " [allocated_on_stack]");
1877 if (flags & 0x10)
1878 fprintf(file, " [pointer_deref]");
1879 fprintf(file, " */\n");
1882 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", reloff, offset);
1883 *typeformat_offset += 4;
1885 return start_offset;
1888 static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
1890 if (t == NULL)
1892 print_file(file, 2, "NdrFcShort(0x0),\t/* No type */\n");
1894 else if (is_base_type(t->type))
1896 print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n",
1897 t->type, string_of_type(t->type));
1899 else if (t->typestring_offset)
1901 short reloff = t->typestring_offset - *tfsoff;
1902 print_file(file, 2, "NdrFcShort(0x%x),\t/* Offset= %d (%d) */\n",
1903 reloff, reloff, t->typestring_offset);
1905 else
1906 error("write_branch_type: type unimplemented (0x%x)\n", t->type);
1908 *tfsoff += 2;
1911 static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
1913 unsigned int align = 0;
1914 unsigned int start_offset;
1915 size_t size = type_memsize(type, &align);
1916 var_list_t *fields;
1917 size_t nbranch = 0;
1918 type_t *deftype = NULL;
1919 short nodeftype = 0xffff;
1920 var_t *f;
1922 guard_rec(type);
1924 if (type->type == RPC_FC_ENCAPSULATED_UNION)
1926 const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
1927 fields = uv->type->fields;
1929 else
1930 fields = type->fields;
1932 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
1934 expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
1935 if (cases)
1936 nbranch += list_count(cases);
1937 if (f->type)
1938 write_embedded_types(file, f->attrs, f->type, f->name, TRUE, tfsoff);
1941 start_offset = *tfsoff;
1942 update_tfsoff(type, start_offset, file);
1943 print_start_tfs_comment(file, type, start_offset);
1944 if (type->type == RPC_FC_ENCAPSULATED_UNION)
1946 const var_t *sv = LIST_ENTRY(list_head(type->fields), const var_t, entry);
1947 const type_t *st = sv->type;
1949 switch (st->type)
1951 case RPC_FC_CHAR:
1952 case RPC_FC_SMALL:
1953 case RPC_FC_USMALL:
1954 case RPC_FC_SHORT:
1955 case RPC_FC_USHORT:
1956 case RPC_FC_LONG:
1957 case RPC_FC_ULONG:
1958 case RPC_FC_ENUM16:
1959 case RPC_FC_ENUM32:
1960 print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
1961 print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
1962 0x40 | st->type, string_of_type(st->type));
1963 *tfsoff += 2;
1964 break;
1965 default:
1966 error("union switch type must be an integer, char, or enum\n");
1969 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", size, size);
1970 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", nbranch, nbranch);
1971 *tfsoff += 4;
1973 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
1975 type_t *ft = f->type;
1976 expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
1977 int deflt = is_attr(f->attrs, ATTR_DEFAULT);
1978 expr_t *c;
1980 if (cases == NULL && !deflt)
1981 error("union field %s with neither case nor default attribute\n", f->name);
1983 if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry)
1985 /* MIDL doesn't check for duplicate cases, even though that seems
1986 like a reasonable thing to do, it just dumps them to the TFS
1987 like we're going to do here. */
1988 print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
1989 *tfsoff += 4;
1990 write_branch_type(file, ft, tfsoff);
1993 /* MIDL allows multiple default branches, even though that seems
1994 illogical, it just chooses the last one, which is what we will
1995 do. */
1996 if (deflt)
1998 deftype = ft;
1999 nodeftype = 0;
2003 if (deftype)
2005 write_branch_type(file, deftype, tfsoff);
2007 else
2009 print_file(file, 2, "NdrFcShort(0x%x),\n", nodeftype);
2010 *tfsoff += 2;
2013 return start_offset;
2016 static size_t write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
2017 unsigned int *typeformat_offset)
2019 size_t i;
2020 size_t start_offset = *typeformat_offset;
2021 expr_t *iid = get_attrp(attrs, ATTR_IIDIS);
2023 if (iid)
2025 print_file(file, 2, "0x2f, /* FC_IP */\n");
2026 print_file(file, 2, "0x5c, /* FC_PAD */\n");
2027 *typeformat_offset
2028 += write_conf_or_var_desc(file, NULL, 0, type, iid) + 2;
2030 else
2032 const type_t *base = is_ptr(type) ? type->ref : type;
2033 const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
2035 if (! uuid)
2036 error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
2038 update_tfsoff(type, start_offset, file);
2039 print_start_tfs_comment(file, type, start_offset);
2040 print_file(file, 2, "0x2f,\t/* FC_IP */\n");
2041 print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
2042 print_file(file, 2, "NdrFcLong(0x%08lx),\n", uuid->Data1);
2043 print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2);
2044 print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3);
2045 for (i = 0; i < 8; ++i)
2046 print_file(file, 2, "0x%02x,\n", uuid->Data4[i]);
2048 if (file)
2049 fprintf(file, "\n");
2051 *typeformat_offset += 18;
2053 return start_offset;
2056 static size_t write_contexthandle_tfs(FILE *file, const type_t *type,
2057 const var_t *var,
2058 unsigned int *typeformat_offset)
2060 size_t start_offset = *typeformat_offset;
2061 unsigned char flags = 0;
2063 if (is_attr(current_iface->attrs, ATTR_STRICTCONTEXTHANDLE))
2064 flags |= NDR_STRICT_CONTEXT_HANDLE;
2066 if (is_ptr(type))
2067 flags |= 0x80;
2068 if (is_attr(var->attrs, ATTR_IN))
2070 flags |= 0x40;
2071 if (!is_attr(var->attrs, ATTR_OUT))
2072 flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
2074 if (is_attr(var->attrs, ATTR_OUT))
2075 flags |= 0x20;
2077 WRITE_FCTYPE(file, FC_BIND_CONTEXT, *typeformat_offset);
2078 print_file(file, 2, "0x%x,\t/* Context flags: ", flags);
2079 /* return and can't be null values overlap */
2080 if (((flags & 0x21) != 0x21) && (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL))
2081 print_file(file, 0, "can't be null, ");
2082 if (flags & NDR_CONTEXT_HANDLE_SERIALIZE)
2083 print_file(file, 0, "serialize, ");
2084 if (flags & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
2085 print_file(file, 0, "no serialize, ");
2086 if (flags & NDR_STRICT_CONTEXT_HANDLE)
2087 print_file(file, 0, "strict, ");
2088 if ((flags & 0x21) == 0x20)
2089 print_file(file, 0, "out, ");
2090 if ((flags & 0x21) == 0x21)
2091 print_file(file, 0, "return, ");
2092 if (flags & 0x40)
2093 print_file(file, 0, "in, ");
2094 if (flags & 0x80)
2095 print_file(file, 0, "via ptr, ");
2096 print_file(file, 0, "*/\n");
2097 print_file(file, 2, "0, /* FIXME: rundown routine index*/\n");
2098 print_file(file, 2, "0, /* FIXME: param num */\n");
2099 *typeformat_offset += 4;
2101 return start_offset;
2104 static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *func,
2105 type_t *type, const var_t *var,
2106 unsigned int *typeformat_offset)
2108 size_t offset;
2110 if (is_context_handle(type))
2111 return write_contexthandle_tfs(file, type, var, typeformat_offset);
2113 if (is_user_type(type))
2115 write_user_tfs(file, type, typeformat_offset);
2116 return type->typestring_offset;
2119 if ((last_ptr(type) || last_array(type)) && is_ptrchain_attr(var, ATTR_STRING))
2120 return write_string_tfs(file, var->attrs, type, var->name, typeformat_offset, TRUE);
2122 if (is_array(type))
2124 int ptr_type;
2125 size_t off;
2126 off = write_array_tfs(file, var->attrs, type, var->name, typeformat_offset);
2127 ptr_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2128 /* Top level pointers to conformant arrays may be handled specially
2129 since we can bypass the pointer, but if the array is buried
2130 beneath another pointer (e.g., "[size_is(,n)] int **p" then we
2131 always need to write the pointer. */
2132 if (!ptr_type && var->type != type)
2133 /* FIXME: This should use pointer_default, but the information
2134 isn't kept around for arrays. */
2135 ptr_type = RPC_FC_UP;
2136 if (ptr_type && ptr_type != RPC_FC_RP)
2138 unsigned int absoff = type->typestring_offset;
2139 short reloff = absoff - (*typeformat_offset + 2);
2140 off = *typeformat_offset;
2141 print_file(file, 0, "/* %d */\n", off);
2142 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
2143 string_of_type(ptr_type));
2144 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
2145 reloff, reloff, absoff);
2146 *typeformat_offset += 4;
2148 return off;
2151 if (!is_ptr(type))
2153 /* basic types don't need a type format string */
2154 if (is_base_type(type->type))
2155 return 0;
2157 switch (type->type)
2159 case RPC_FC_STRUCT:
2160 case RPC_FC_PSTRUCT:
2161 case RPC_FC_CSTRUCT:
2162 case RPC_FC_CPSTRUCT:
2163 case RPC_FC_CVSTRUCT:
2164 case RPC_FC_BOGUS_STRUCT:
2165 return write_struct_tfs(file, type, var->name, typeformat_offset);
2166 case RPC_FC_ENCAPSULATED_UNION:
2167 case RPC_FC_NON_ENCAPSULATED_UNION:
2168 return write_union_tfs(file, type, typeformat_offset);
2169 case RPC_FC_IGNORE:
2170 case RPC_FC_BIND_PRIMITIVE:
2171 /* nothing to do */
2172 return 0;
2173 default:
2174 error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
2177 else if (last_ptr(type))
2179 size_t start_offset = *typeformat_offset;
2180 int in_attr = is_attr(var->attrs, ATTR_IN);
2181 int out_attr = is_attr(var->attrs, ATTR_OUT);
2182 const type_t *base = type->ref;
2184 if (base->type == RPC_FC_IP
2185 || (base->type == 0
2186 && is_attr(var->attrs, ATTR_IIDIS)))
2188 return write_ip_tfs(file, var->attrs, type, typeformat_offset);
2191 /* special case for pointers to base types */
2192 if (is_base_type(base->type))
2194 print_file(file, indent, "0x%x, 0x%x, /* %s %s[simple_pointer] */\n",
2195 type->type, (!in_attr && out_attr) ? 0x0C : 0x08,
2196 string_of_type(type->type),
2197 (!in_attr && out_attr) ? "[allocated_on_stack] " : "");
2198 print_file(file, indent, "0x%02x, /* %s */\n", base->type, string_of_type(base->type));
2199 print_file(file, indent, "0x5c, /* FC_PAD */\n");
2200 *typeformat_offset += 4;
2201 return start_offset;
2205 assert(is_ptr(type));
2207 offset = write_typeformatstring_var(file, indent, func, type->ref, var, typeformat_offset);
2208 if (file)
2209 fprintf(file, "/* %2u */\n", *typeformat_offset);
2210 return write_pointer_only_tfs(file, var->attrs, type->type,
2211 !last_ptr(type) ? 0x10 : 0,
2212 offset, typeformat_offset);
2215 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
2216 const char *name, int write_ptr, unsigned int *tfsoff)
2218 int retmask = 0;
2220 if (is_user_type(type))
2222 write_user_tfs(file, type, tfsoff);
2224 else if (is_ptr(type))
2226 type_t *ref = type->ref;
2228 if (ref->type == RPC_FC_IP
2229 || (ref->type == 0
2230 && is_attr(attrs, ATTR_IIDIS)))
2232 write_ip_tfs(file, attrs, type, tfsoff);
2234 else
2236 if (!processed(ref) && !is_base_type(ref->type))
2237 retmask |= write_embedded_types(file, NULL, ref, name, TRUE, tfsoff);
2239 if (write_ptr)
2240 write_pointer_tfs(file, type, tfsoff);
2242 retmask |= 1;
2245 else if (last_array(type) && is_attr(attrs, ATTR_STRING))
2247 write_string_tfs(file, attrs, type, name, tfsoff, FALSE);
2249 else if (type->declarray && is_conformant_array(type))
2250 ; /* conformant arrays and strings are handled specially */
2251 else if (is_array(type))
2253 write_array_tfs(file, attrs, type, name, tfsoff);
2254 if (is_conformant_array(type))
2255 retmask |= 1;
2257 else if (is_struct(type->type))
2259 if (!processed(type))
2260 write_struct_tfs(file, type, name, tfsoff);
2262 else if (is_union(type->type))
2264 if (!processed(type))
2265 write_union_tfs(file, type, tfsoff);
2267 else if (!is_base_type(type->type))
2268 error("write_embedded_types: unknown embedded type for %s (0x%x)\n",
2269 name, type->type);
2271 return retmask;
2274 static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
2276 const var_t *var;
2277 const ifref_t *iface;
2278 unsigned int typeformat_offset = 2;
2280 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
2282 if (!pred(iface->iface))
2283 continue;
2285 if (iface->iface->funcs)
2287 const func_t *func;
2288 current_iface = iface;
2289 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
2291 if (is_local(func->def->attrs)) continue;
2293 current_func = func;
2294 if (func->args)
2295 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2296 update_tfsoff(
2297 var->type,
2298 write_typeformatstring_var(
2299 file, 2, func, var->type, var,
2300 &typeformat_offset),
2301 file);
2306 return typeformat_offset + 1;
2310 void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
2312 int indent = 0;
2314 print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
2315 print_file(file, indent, "{\n");
2316 indent++;
2317 print_file(file, indent, "0,\n");
2318 print_file(file, indent, "{\n");
2319 indent++;
2320 print_file(file, indent, "NdrFcShort(0x0),\n");
2322 set_all_tfswrite(TRUE);
2323 process_tfs(file, ifaces, pred);
2325 print_file(file, indent, "0x0\n");
2326 indent--;
2327 print_file(file, indent, "}\n");
2328 indent--;
2329 print_file(file, indent, "};\n");
2330 print_file(file, indent, "\n");
2333 static unsigned int get_required_buffer_size_type(
2334 const type_t *type, const char *name, unsigned int *alignment)
2336 *alignment = 0;
2337 if (is_user_type(type))
2339 const char *uname;
2340 const type_t *utype = get_user_type(type, &uname);
2341 return get_required_buffer_size_type(utype, uname, alignment);
2343 else
2345 switch (type->type)
2347 case RPC_FC_BYTE:
2348 case RPC_FC_CHAR:
2349 case RPC_FC_USMALL:
2350 case RPC_FC_SMALL:
2351 *alignment = 4;
2352 return 1;
2354 case RPC_FC_WCHAR:
2355 case RPC_FC_USHORT:
2356 case RPC_FC_SHORT:
2357 case RPC_FC_ENUM16:
2358 *alignment = 4;
2359 return 2;
2361 case RPC_FC_ULONG:
2362 case RPC_FC_LONG:
2363 case RPC_FC_ENUM32:
2364 case RPC_FC_FLOAT:
2365 case RPC_FC_ERROR_STATUS_T:
2366 *alignment = 4;
2367 return 4;
2369 case RPC_FC_HYPER:
2370 case RPC_FC_DOUBLE:
2371 *alignment = 8;
2372 return 8;
2374 case RPC_FC_IGNORE:
2375 case RPC_FC_BIND_PRIMITIVE:
2376 return 0;
2378 case RPC_FC_STRUCT:
2379 case RPC_FC_PSTRUCT:
2381 size_t size = 0;
2382 const var_t *field;
2383 if (!type->fields) return 0;
2384 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2386 unsigned int alignment;
2387 size += get_required_buffer_size_type(field->type, field->name,
2388 &alignment);
2390 return size;
2393 case RPC_FC_RP:
2394 return
2395 is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT
2396 ? get_required_buffer_size_type( type->ref, name, alignment )
2397 : 0;
2399 case RPC_FC_SMFARRAY:
2400 case RPC_FC_LGFARRAY:
2401 return type->dim * get_required_buffer_size_type(type->ref, name, alignment);
2403 default:
2404 return 0;
2409 static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
2411 int in_attr = is_attr(var->attrs, ATTR_IN);
2412 int out_attr = is_attr(var->attrs, ATTR_OUT);
2413 const type_t *t;
2415 if (!in_attr && !out_attr)
2416 in_attr = 1;
2418 *alignment = 0;
2420 for (t = var->type; is_ptr(t); t = t->ref)
2421 if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
2423 *alignment = 4;
2424 return 20;
2427 if (pass == PASS_OUT)
2429 if (out_attr && is_ptr(var->type))
2431 type_t *type = var->type;
2433 if (type->type == RPC_FC_STRUCT)
2435 const var_t *field;
2436 unsigned int size = 36;
2438 if (!type->fields) return size;
2439 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2441 unsigned int align;
2442 size += get_required_buffer_size_type(
2443 field->type, field->name, &align);
2445 return size;
2448 return 0;
2450 else
2452 if ((!out_attr || in_attr) && !var->type->size_is
2453 && !is_attr(var->attrs, ATTR_STRING) && !var->type->declarray)
2455 if (is_ptr(var->type))
2457 type_t *type = var->type;
2459 if (is_base_type(type->type))
2461 return 25;
2463 else if (type->type == RPC_FC_STRUCT)
2465 unsigned int size = 36;
2466 const var_t *field;
2468 if (!type->fields) return size;
2469 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2471 unsigned int align;
2472 size += get_required_buffer_size_type(
2473 field->type, field->name, &align);
2475 return size;
2480 return get_required_buffer_size_type(var->type, var->name, alignment);
2484 static unsigned int get_function_buffer_size( const func_t *func, enum pass pass )
2486 const var_t *var;
2487 unsigned int total_size = 0, alignment;
2489 if (func->args)
2491 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2493 total_size += get_required_buffer_size(var, &alignment, pass);
2494 total_size += alignment;
2498 if (pass == PASS_OUT && !is_void(func->def->type))
2500 total_size += get_required_buffer_size(func->def, &alignment, PASS_RETURN);
2501 total_size += alignment;
2503 return total_size;
2506 static void print_phase_function(FILE *file, int indent, const char *type,
2507 enum remoting_phase phase,
2508 const var_t *var, unsigned int type_offset)
2510 const char *function;
2511 switch (phase)
2513 case PHASE_BUFFERSIZE:
2514 function = "BufferSize";
2515 break;
2516 case PHASE_MARSHAL:
2517 function = "Marshall";
2518 break;
2519 case PHASE_UNMARSHAL:
2520 function = "Unmarshall";
2521 break;
2522 case PHASE_FREE:
2523 function = "Free";
2524 break;
2525 default:
2526 assert(0);
2527 return;
2530 print_file(file, indent, "Ndr%s%s(\n", type, function);
2531 indent++;
2532 print_file(file, indent, "&_StubMsg,\n");
2533 print_file(file, indent, "%s%s%s%s,\n",
2534 (phase == PHASE_UNMARSHAL) ? "(unsigned char **)" : "(unsigned char *)",
2535 (phase == PHASE_UNMARSHAL || decl_indirect(var->type)) ? "&" : "",
2536 (phase == PHASE_UNMARSHAL && decl_indirect(var->type)) ? "_p_" : "",
2537 var->name);
2538 print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
2539 type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
2540 if (phase == PHASE_UNMARSHAL)
2541 print_file(file, indent, "0);\n");
2542 indent--;
2545 void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
2546 enum pass pass, const var_t *var,
2547 const char *varname)
2549 type_t *type = var->type;
2550 unsigned int size;
2551 unsigned int alignment = 0;
2552 unsigned char rtype;
2554 /* no work to do for other phases, buffer sizing is done elsewhere */
2555 if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
2556 return;
2558 rtype = is_ptr(type) ? type->ref->type : type->type;
2560 switch (rtype)
2562 case RPC_FC_BYTE:
2563 case RPC_FC_CHAR:
2564 case RPC_FC_SMALL:
2565 case RPC_FC_USMALL:
2566 size = 1;
2567 alignment = 1;
2568 break;
2570 case RPC_FC_WCHAR:
2571 case RPC_FC_USHORT:
2572 case RPC_FC_SHORT:
2573 case RPC_FC_ENUM16:
2574 size = 2;
2575 alignment = 2;
2576 break;
2578 case RPC_FC_ULONG:
2579 case RPC_FC_LONG:
2580 case RPC_FC_ENUM32:
2581 case RPC_FC_FLOAT:
2582 case RPC_FC_ERROR_STATUS_T:
2583 size = 4;
2584 alignment = 4;
2585 break;
2587 case RPC_FC_HYPER:
2588 case RPC_FC_DOUBLE:
2589 size = 8;
2590 alignment = 8;
2591 break;
2593 case RPC_FC_IGNORE:
2594 case RPC_FC_BIND_PRIMITIVE:
2595 /* no marshalling needed */
2596 return;
2598 default:
2599 error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, rtype);
2600 size = 0;
2603 if (phase == PHASE_MARSHAL)
2604 print_file(file, indent, "MIDL_memset(_StubMsg.Buffer, 0, (0x%x - (long)_StubMsg.Buffer) & 0x%x);\n", alignment, alignment - 1);
2605 print_file(file, indent, "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
2606 alignment - 1, alignment - 1);
2608 if (phase == PHASE_MARSHAL)
2610 print_file(file, indent, "*(");
2611 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2612 if (is_ptr(type))
2613 fprintf(file, " *)_StubMsg.Buffer = *");
2614 else
2615 fprintf(file, " *)_StubMsg.Buffer = ");
2616 fprintf(file, "%s", varname);
2617 fprintf(file, ";\n");
2619 else if (phase == PHASE_UNMARSHAL)
2621 print_file(file, indent, "if (_StubMsg.Buffer + sizeof(");
2622 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2623 fprintf(file, ") > _StubMsg.BufferEnd)\n");
2624 print_file(file, indent, "{\n");
2625 print_file(file, indent + 1, "RpcRaiseException(RPC_X_BAD_STUB_DATA);\n");
2626 print_file(file, indent, "}\n");
2627 if (pass == PASS_IN || pass == PASS_RETURN)
2628 print_file(file, indent, "");
2629 else
2630 print_file(file, indent, "*");
2631 fprintf(file, "%s", varname);
2632 if (pass == PASS_IN && is_ptr(type))
2633 fprintf(file, " = (");
2634 else
2635 fprintf(file, " = *(");
2636 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2637 fprintf(file, " *)_StubMsg.Buffer;\n");
2640 print_file(file, indent, "_StubMsg.Buffer += sizeof(");
2641 write_type_decl(file, var->type, NULL);
2642 fprintf(file, ");\n");
2645 /* returns whether the MaxCount, Offset or ActualCount members need to be
2646 * filled in for the specified phase */
2647 static inline int is_size_needed_for_phase(enum remoting_phase phase)
2649 return (phase != PHASE_UNMARSHAL);
2652 expr_t *get_size_is_expr(const type_t *t, const char *name)
2654 expr_t *x = NULL;
2656 for ( ; is_ptr(t) || is_array(t); t = t->ref)
2657 if (t->size_is)
2659 if (!x)
2660 x = t->size_is;
2661 else
2662 error("%s: multidimensional conformant"
2663 " arrays not supported at the top level\n",
2664 name);
2667 return x;
2670 static void write_remoting_arg(FILE *file, int indent, const func_t *func,
2671 enum pass pass, enum remoting_phase phase,
2672 const var_t *var)
2674 int in_attr, out_attr, pointer_type;
2675 const type_t *type = var->type;
2676 unsigned char rtype;
2677 size_t start_offset = type->typestring_offset;
2679 pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2680 if (!pointer_type)
2681 pointer_type = RPC_FC_RP;
2683 in_attr = is_attr(var->attrs, ATTR_IN);
2684 out_attr = is_attr(var->attrs, ATTR_OUT);
2685 if (!in_attr && !out_attr)
2686 in_attr = 1;
2688 if (phase != PHASE_FREE)
2689 switch (pass)
2691 case PASS_IN:
2692 if (!in_attr) return;
2693 break;
2694 case PASS_OUT:
2695 if (!out_attr) return;
2696 break;
2697 case PASS_RETURN:
2698 break;
2701 rtype = type->type;
2703 if (is_context_handle(type))
2705 if (phase == PHASE_MARSHAL)
2707 if (pass == PASS_IN)
2709 print_file(file, indent, "NdrClientContextMarshall(\n");
2710 print_file(file, indent + 1, "&_StubMsg,\n");
2711 print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ptr(type) ? "*" : "", var->name);
2712 print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
2714 else
2716 print_file(file, indent, "NdrServerContextNewMarshall(\n");
2717 print_file(file, indent + 1, "&_StubMsg,\n");
2718 print_file(file, indent + 1, "(NDR_SCONTEXT)%s,\n", var->name);
2719 print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown,\n", get_context_handle_type_name(var->type));
2720 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2723 else if (phase == PHASE_UNMARSHAL)
2725 if (pass == PASS_OUT)
2727 if (!in_attr)
2728 print_file(file, indent, "*%s = 0;\n", var->name);
2729 print_file(file, indent, "NdrClientContextUnmarshall(\n");
2730 print_file(file, indent + 1, "&_StubMsg,\n");
2731 print_file(file, indent + 1, "(NDR_CCONTEXT *)%s,\n", var->name);
2732 print_file(file, indent + 1, "_Handle);\n");
2734 else
2736 print_file(file, indent, "%s = NdrServerContextNewUnmarshall(\n", var->name);
2737 print_file(file, indent + 1, "&_StubMsg,\n");
2738 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2742 else if (is_user_type(var->type))
2744 print_phase_function(file, indent, "UserMarshal", phase, var, start_offset);
2746 else if (is_string_type(var->attrs, var->type))
2748 if (is_array(type) && !is_conformant_array(type))
2749 print_phase_function(file, indent, "NonConformantString", phase, var, start_offset);
2750 else
2752 if (type->size_is && is_size_needed_for_phase(phase))
2754 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2755 write_expr(file, type->size_is, 1);
2756 fprintf(file, ";\n");
2759 if ((phase == PHASE_FREE) || (pointer_type == RPC_FC_UP))
2760 print_phase_function(file, indent, "Pointer", phase, var,
2761 start_offset - (type->size_is ? 4 : 2));
2762 else
2763 print_phase_function(file, indent, "ConformantString", phase, var,
2764 start_offset);
2767 else if (is_array(type))
2769 unsigned char tc = type->type;
2770 const char *array_type = "FixedArray";
2772 /* We already have the size_is expression since it's at the
2773 top level, but do checks for multidimensional conformant
2774 arrays. When we handle them, we'll need to extend this
2775 function to return a list, and then we'll actually use
2776 the return value. */
2777 get_size_is_expr(type, var->name);
2779 if (tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY)
2781 if (is_size_needed_for_phase(phase))
2783 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2784 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2785 write_expr(file, type->length_is, 1);
2786 fprintf(file, ";\n\n");
2788 array_type = "VaryingArray";
2790 else if (tc == RPC_FC_CARRAY)
2792 if (is_size_needed_for_phase(phase))
2794 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2795 write_expr(file, type->size_is, 1);
2796 fprintf(file, ";\n\n");
2798 array_type = "ConformantArray";
2800 else if (tc == RPC_FC_CVARRAY || tc == RPC_FC_BOGUS_ARRAY)
2802 if (is_size_needed_for_phase(phase))
2804 if (type->size_is)
2806 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2807 write_expr(file, type->size_is, 1);
2808 fprintf(file, ";\n");
2810 if (type->length_is)
2812 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2813 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2814 write_expr(file, type->length_is, 1);
2815 fprintf(file, ";\n\n");
2818 array_type = (tc == RPC_FC_BOGUS_ARRAY
2819 ? "ComplexArray"
2820 : "ConformantVaryingArray");
2823 if (pointer_type != RPC_FC_RP) array_type = "Pointer";
2824 print_phase_function(file, indent, array_type, phase, var, start_offset);
2825 if (phase == PHASE_FREE && pointer_type == RPC_FC_RP)
2827 /* these are all unmarshalled by allocating memory */
2828 if (type->type == RPC_FC_BOGUS_ARRAY ||
2829 type->type == RPC_FC_CVARRAY ||
2830 ((type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY) && in_attr) ||
2831 (type->type == RPC_FC_CARRAY && !in_attr))
2833 print_file(file, indent, "if (%s)\n", var->name);
2834 indent++;
2835 print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
2839 else if (!is_ptr(var->type) && is_base_type(rtype))
2841 if (phase != PHASE_FREE)
2842 print_phase_basetype(file, indent, phase, pass, var, var->name);
2844 else if (!is_ptr(var->type))
2846 switch (rtype)
2848 case RPC_FC_STRUCT:
2849 case RPC_FC_PSTRUCT:
2850 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset);
2851 break;
2852 case RPC_FC_CSTRUCT:
2853 case RPC_FC_CPSTRUCT:
2854 print_phase_function(file, indent, "ConformantStruct", phase, var, start_offset);
2855 break;
2856 case RPC_FC_CVSTRUCT:
2857 print_phase_function(file, indent, "ConformantVaryingStruct", phase, var, start_offset);
2858 break;
2859 case RPC_FC_BOGUS_STRUCT:
2860 print_phase_function(file, indent, "ComplexStruct", phase, var, start_offset);
2861 break;
2862 case RPC_FC_RP:
2863 if (is_base_type( var->type->ref->type ))
2865 print_phase_basetype(file, indent, phase, pass, var, var->name);
2867 else if (var->type->ref->type == RPC_FC_STRUCT)
2869 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2870 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
2872 else
2874 expr_t *iid;
2875 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2877 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2878 write_expr( file, iid, 1 );
2879 fprintf( file, ";\n\n" );
2881 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
2883 break;
2884 default:
2885 error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype);
2888 else
2890 if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
2892 if (phase != PHASE_FREE)
2893 print_phase_basetype(file, indent, phase, pass, var, var->name);
2895 else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
2897 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2898 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
2900 else
2902 expr_t *iid;
2903 expr_t *sx = get_size_is_expr(type, var->name);
2905 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2907 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2908 write_expr( file, iid, 1 );
2909 fprintf( file, ";\n\n" );
2911 else if (sx)
2913 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long) ");
2914 write_expr(file, sx, 1);
2915 fprintf(file, ";\n\n");
2917 if (var->type->ref->type == RPC_FC_IP)
2918 print_phase_function(file, indent, "InterfacePointer", phase, var, start_offset);
2919 else
2920 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
2923 fprintf(file, "\n");
2926 void write_remoting_arguments(FILE *file, int indent, const func_t *func,
2927 enum pass pass, enum remoting_phase phase)
2929 if (phase == PHASE_BUFFERSIZE && pass != PASS_RETURN)
2931 unsigned int size = get_function_buffer_size( func, pass );
2932 print_file(file, indent, "_StubMsg.BufferLength = %u;\n", size);
2935 if (pass == PASS_RETURN)
2937 var_t var;
2938 var = *func->def;
2939 var.name = xstrdup( "_RetVal" );
2940 write_remoting_arg( file, indent, func, pass, phase, &var );
2941 free( var.name );
2943 else
2945 const var_t *var;
2946 if (!func->args)
2947 return;
2948 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2949 write_remoting_arg( file, indent, func, pass, phase, var );
2954 size_t get_size_procformatstring_var(const var_t *var)
2956 return write_procformatstring_var(NULL, 0, var, FALSE);
2960 size_t get_size_procformatstring_func(const func_t *func)
2962 const var_t *var;
2963 size_t size = 0;
2965 /* argument list size */
2966 if (func->args)
2967 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2968 size += get_size_procformatstring_var(var);
2970 /* return value size */
2971 if (is_void(func->def->type))
2972 size += 2; /* FC_END and FC_PAD */
2973 else
2974 size += get_size_procformatstring_var(func->def);
2976 return size;
2979 size_t get_size_procformatstring(const ifref_list_t *ifaces, type_pred_t pred)
2981 const ifref_t *iface;
2982 size_t size = 1;
2983 const func_t *func;
2985 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
2987 if (!pred(iface->iface))
2988 continue;
2990 if (iface->iface->funcs)
2991 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
2992 if (!is_local(func->def->attrs))
2993 size += get_size_procformatstring_func( func );
2995 return size;
2998 size_t get_size_typeformatstring(const ifref_list_t *ifaces, type_pred_t pred)
3000 set_all_tfswrite(FALSE);
3001 return process_tfs(NULL, ifaces, pred);
3004 static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
3005 const var_list_t *fields, const char *structvar)
3007 switch (e->type) {
3008 case EXPR_VOID:
3009 break;
3010 case EXPR_NUM:
3011 fprintf(h, "%lu", e->u.lval);
3012 break;
3013 case EXPR_HEXNUM:
3014 fprintf(h, "0x%lx", e->u.lval);
3015 break;
3016 case EXPR_DOUBLE:
3017 fprintf(h, "%#.15g", e->u.dval);
3018 break;
3019 case EXPR_TRUEFALSE:
3020 if (e->u.lval == 0)
3021 fprintf(h, "FALSE");
3022 else
3023 fprintf(h, "TRUE");
3024 break;
3025 case EXPR_IDENTIFIER:
3027 const var_t *field;
3028 LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
3029 if (!strcmp(e->u.sval, field->name))
3031 fprintf(h, "%s->%s", structvar, e->u.sval);
3032 break;
3035 if (&field->entry == fields) error("no field found for identifier %s\n", e->u.sval);
3036 break;
3038 case EXPR_NEG:
3039 fprintf(h, "-");
3040 write_struct_expr(h, e->ref, 1, fields, structvar);
3041 break;
3042 case EXPR_NOT:
3043 fprintf(h, "~");
3044 write_struct_expr(h, e->ref, 1, fields, structvar);
3045 break;
3046 case EXPR_PPTR:
3047 fprintf(h, "*");
3048 write_struct_expr(h, e->ref, 1, fields, structvar);
3049 break;
3050 case EXPR_CAST:
3051 fprintf(h, "(");
3052 write_type_decl(h, e->u.tref, NULL);
3053 fprintf(h, ")");
3054 write_struct_expr(h, e->ref, 1, fields, structvar);
3055 break;
3056 case EXPR_SIZEOF:
3057 fprintf(h, "sizeof(");
3058 write_type_decl(h, e->u.tref, NULL);
3059 fprintf(h, ")");
3060 break;
3061 case EXPR_SHL:
3062 case EXPR_SHR:
3063 case EXPR_MUL:
3064 case EXPR_DIV:
3065 case EXPR_ADD:
3066 case EXPR_SUB:
3067 case EXPR_AND:
3068 case EXPR_OR:
3069 if (brackets) fprintf(h, "(");
3070 write_struct_expr(h, e->ref, 1, fields, structvar);
3071 switch (e->type) {
3072 case EXPR_SHL: fprintf(h, " << "); break;
3073 case EXPR_SHR: fprintf(h, " >> "); break;
3074 case EXPR_MUL: fprintf(h, " * "); break;
3075 case EXPR_DIV: fprintf(h, " / "); break;
3076 case EXPR_ADD: fprintf(h, " + "); break;
3077 case EXPR_SUB: fprintf(h, " - "); break;
3078 case EXPR_AND: fprintf(h, " & "); break;
3079 case EXPR_OR: fprintf(h, " | "); break;
3080 default: break;
3082 write_struct_expr(h, e->u.ext, 1, fields, structvar);
3083 if (brackets) fprintf(h, ")");
3084 break;
3085 case EXPR_COND:
3086 if (brackets) fprintf(h, "(");
3087 write_struct_expr(h, e->ref, 1, fields, structvar);
3088 fprintf(h, " ? ");
3089 write_struct_expr(h, e->u.ext, 1, fields, structvar);
3090 fprintf(h, " : ");
3091 write_struct_expr(h, e->ext2, 1, fields, structvar);
3092 if (brackets) fprintf(h, ")");
3093 break;
3094 case EXPR_ADDRESSOF:
3095 fprintf(h, "&");
3096 write_struct_expr(h, e->ref, 1, fields, structvar);
3097 break;
3102 void declare_stub_args( FILE *file, int indent, const func_t *func )
3104 int in_attr, out_attr;
3105 int i = 0;
3106 const var_t *def = func->def;
3107 const var_t *var;
3109 /* declare return value '_RetVal' */
3110 if (!is_void(def->type))
3112 print_file(file, indent, "");
3113 write_type_decl_left(file, def->type);
3114 fprintf(file, " _RetVal;\n");
3117 if (!func->args)
3118 return;
3120 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3122 int is_string = is_attr(var->attrs, ATTR_STRING);
3124 in_attr = is_attr(var->attrs, ATTR_IN);
3125 out_attr = is_attr(var->attrs, ATTR_OUT);
3126 if (!out_attr && !in_attr)
3127 in_attr = 1;
3129 if (is_context_handle(var->type))
3130 print_file(file, indent, "NDR_SCONTEXT %s;\n", var->name);
3131 else
3133 if (!in_attr && !var->type->size_is && !is_string)
3135 print_file(file, indent, "");
3136 write_type_decl(file, var->type->declarray ? var->type : var->type->ref,
3137 "_W%u", i++);
3138 fprintf(file, ";\n");
3141 print_file(file, indent, "");
3142 write_type_decl_left(file, var->type);
3143 fprintf(file, " ");
3144 if (var->type->declarray) {
3145 fprintf(file, "( *");
3146 write_name(file, var);
3147 fprintf(file, " )");
3148 } else
3149 write_name(file, var);
3150 write_type_right(file, var->type, FALSE);
3151 fprintf(file, ";\n");
3153 if (decl_indirect(var->type))
3154 print_file(file, indent, "void *_p_%s = &%s;\n",
3155 var->name, var->name);
3161 void assign_stub_out_args( FILE *file, int indent, const func_t *func )
3163 int in_attr, out_attr;
3164 int i = 0, sep = 0;
3165 const var_t *var;
3167 if (!func->args)
3168 return;
3170 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3172 int is_string = is_attr(var->attrs, ATTR_STRING);
3173 in_attr = is_attr(var->attrs, ATTR_IN);
3174 out_attr = is_attr(var->attrs, ATTR_OUT);
3175 if (!out_attr && !in_attr)
3176 in_attr = 1;
3178 if (!in_attr)
3180 print_file(file, indent, "");
3181 write_name(file, var);
3183 if (is_context_handle(var->type))
3185 fprintf(file, " = NdrContextHandleInitialize(\n");
3186 print_file(file, indent + 1, "&_StubMsg,\n");
3187 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n",
3188 var->type->typestring_offset);
3190 else if (var->type->size_is)
3192 unsigned int size, align = 0;
3193 type_t *type = var->type;
3195 fprintf(file, " = NdrAllocate(&_StubMsg, ");
3196 for ( ; type->size_is ; type = type->ref)
3198 write_expr(file, type->size_is, TRUE);
3199 fprintf(file, " * ");
3201 size = type_memsize(type, &align);
3202 fprintf(file, "%u);\n", size);
3204 else if (!is_string)
3206 fprintf(file, " = &_W%u;\n", i);
3207 if (is_ptr(var->type) && !last_ptr(var->type))
3208 print_file(file, indent, "_W%u = 0;\n", i);
3209 i++;
3212 sep = 1;
3215 if (sep)
3216 fprintf(file, "\n");
3220 int write_expr_eval_routines(FILE *file, const char *iface)
3222 static const char *var_name = "pS";
3223 int result = 0;
3224 struct expr_eval_routine *eval;
3225 unsigned short callback_offset = 0;
3227 LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
3229 const char *name = eval->structure->name;
3230 const var_list_t *fields = eval->structure->fields;
3231 result = 1;
3233 print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
3234 iface, name, callback_offset);
3235 print_file(file, 0, "{\n");
3236 print_file (file, 1, "%s *%s = (%s *)(pStubMsg->StackTop - %u);\n",
3237 name, var_name, name, eval->baseoff);
3238 print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */
3239 print_file(file, 1, "pStubMsg->MaxCount = (unsigned long)");
3240 write_struct_expr(file, eval->expr, 1, fields, var_name);
3241 fprintf(file, ";\n");
3242 print_file(file, 0, "}\n\n");
3243 callback_offset++;
3245 return result;
3248 void write_expr_eval_routine_list(FILE *file, const char *iface)
3250 struct expr_eval_routine *eval;
3251 struct expr_eval_routine *cursor;
3252 unsigned short callback_offset = 0;
3254 fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
3255 fprintf(file, "{\n");
3257 LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
3259 const char *name = eval->structure->name;
3260 print_file(file, 1, "%s_%sExprEval_%04u,\n", iface, name, callback_offset);
3261 callback_offset++;
3262 list_remove(&eval->entry);
3263 free(eval);
3266 fprintf(file, "};\n\n");
3269 void write_user_quad_list(FILE *file)
3271 user_type_t *ut;
3273 if (list_empty(&user_type_list))
3274 return;
3276 fprintf(file, "static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[] =\n");
3277 fprintf(file, "{\n");
3278 LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
3280 const char *sep = &ut->entry == list_tail(&user_type_list) ? "" : ",";
3281 print_file(file, 1, "{\n");
3282 print_file(file, 2, "(USER_MARSHAL_SIZING_ROUTINE)%s_UserSize,\n", ut->name);
3283 print_file(file, 2, "(USER_MARSHAL_MARSHALLING_ROUTINE)%s_UserMarshal,\n", ut->name);
3284 print_file(file, 2, "(USER_MARSHAL_UNMARSHALLING_ROUTINE)%s_UserUnmarshal,\n", ut->name);
3285 print_file(file, 2, "(USER_MARSHAL_FREEING_ROUTINE)%s_UserFree\n", ut->name);
3286 print_file(file, 1, "}%s\n", sep);
3288 fprintf(file, "};\n\n");
3291 void write_endpoints( FILE *f, const char *prefix, const str_list_t *list )
3293 const struct str_list_entry_t *endpoint;
3294 const char *p;
3296 /* this should be an array of RPC_PROTSEQ_ENDPOINT but we want const strings */
3297 print_file( f, 0, "static const unsigned char * %s__RpcProtseqEndpoint[][2] =\n{\n", prefix );
3298 LIST_FOR_EACH_ENTRY( endpoint, list, const struct str_list_entry_t, entry )
3300 print_file( f, 1, "{ (const unsigned char *)\"" );
3301 for (p = endpoint->str; *p && *p != ':'; p++)
3303 if (*p == '"' || *p == '\\') fputc( '\\', f );
3304 fputc( *p, f );
3306 if (!*p) goto error;
3307 if (p[1] != '[') goto error;
3309 fprintf( f, "\", (const unsigned char *)\"" );
3310 for (p += 2; *p && *p != ']'; p++)
3312 if (*p == '"' || *p == '\\') fputc( '\\', f );
3313 fputc( *p, f );
3315 if (*p != ']') goto error;
3316 fprintf( f, "\" },\n" );
3318 print_file( f, 0, "};\n\n" );
3319 return;
3321 error:
3322 error("Invalid endpoint syntax '%s'\n", endpoint->str);