widl: Add support for arrays in expressions.
[wine/wine-jacek.git] / tools / widl / typegen.c
blobda5c95aa262a7dc4b5def97ed3b46b7fb879e662
1 /*
2 * Format String Generator for IDL Compiler
4 * Copyright 2005-2006 Eric Kohl
5 * Copyright 2005-2006 Robert Shearman
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <string.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <limits.h>
35 #include "widl.h"
36 #include "utils.h"
37 #include "parser.h"
38 #include "header.h"
39 #include "wine/list.h"
41 #include "typegen.h"
43 static const func_t *current_func;
44 static const type_t *current_structure;
45 static const ifref_t *current_iface;
47 static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
48 struct expr_eval_routine
50 struct list entry;
51 const type_t *structure;
52 unsigned int baseoff;
53 const expr_t *expr;
56 static size_t fields_memsize(const var_list_t *fields, unsigned int *align);
57 static size_t write_struct_tfs(FILE *file, type_t *type, const char *name, unsigned int *tfsoff);
58 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
59 const char *name, int write_ptr, unsigned int *tfsoff);
60 static const var_t *find_array_or_string_in_struct(const type_t *type);
61 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
62 type_t *type,
63 const char *name, unsigned int *typestring_offset);
65 const char *string_of_type(unsigned char type)
67 switch (type)
69 case RPC_FC_BYTE: return "FC_BYTE";
70 case RPC_FC_CHAR: return "FC_CHAR";
71 case RPC_FC_SMALL: return "FC_SMALL";
72 case RPC_FC_USMALL: return "FC_USMALL";
73 case RPC_FC_WCHAR: return "FC_WCHAR";
74 case RPC_FC_SHORT: return "FC_SHORT";
75 case RPC_FC_USHORT: return "FC_USHORT";
76 case RPC_FC_LONG: return "FC_LONG";
77 case RPC_FC_ULONG: return "FC_ULONG";
78 case RPC_FC_FLOAT: return "FC_FLOAT";
79 case RPC_FC_HYPER: return "FC_HYPER";
80 case RPC_FC_DOUBLE: return "FC_DOUBLE";
81 case RPC_FC_ENUM16: return "FC_ENUM16";
82 case RPC_FC_ENUM32: return "FC_ENUM32";
83 case RPC_FC_IGNORE: return "FC_IGNORE";
84 case RPC_FC_ERROR_STATUS_T: return "FC_ERROR_STATUS_T";
85 case RPC_FC_RP: return "FC_RP";
86 case RPC_FC_UP: return "FC_UP";
87 case RPC_FC_OP: return "FC_OP";
88 case RPC_FC_FP: return "FC_FP";
89 case RPC_FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION";
90 case RPC_FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION";
91 case RPC_FC_STRUCT: return "FC_STRUCT";
92 case RPC_FC_PSTRUCT: return "FC_PSTRUCT";
93 case RPC_FC_CSTRUCT: return "FC_CSTRUCT";
94 case RPC_FC_CPSTRUCT: return "FC_CPSTRUCT";
95 case RPC_FC_CVSTRUCT: return "FC_CVSTRUCT";
96 case RPC_FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT";
97 case RPC_FC_SMFARRAY: return "FC_SMFARRAY";
98 case RPC_FC_LGFARRAY: return "FC_LGFARRAY";
99 case RPC_FC_SMVARRAY: return "FC_SMVARRAY";
100 case RPC_FC_LGVARRAY: return "FC_LGVARRAY";
101 case RPC_FC_CARRAY: return "FC_CARRAY";
102 case RPC_FC_CVARRAY: return "FC_CVARRAY";
103 case RPC_FC_BOGUS_ARRAY: return "FC_BOGUS_ARRAY";
104 case RPC_FC_ALIGNM4: return "FC_ALIGNM4";
105 case RPC_FC_ALIGNM8: return "FC_ALIGNM8";
106 case RPC_FC_POINTER: return "FC_POINTER";
107 case RPC_FC_C_CSTRING: return "FC_C_CSTRING";
108 case RPC_FC_C_WSTRING: return "FC_C_WSTRING";
109 case RPC_FC_CSTRING: return "FC_CSTRING";
110 case RPC_FC_WSTRING: return "FC_WSTRING";
111 default:
112 error("string_of_type: unknown type 0x%02x\n", type);
113 return NULL;
117 int is_struct(unsigned char type)
119 switch (type)
121 case RPC_FC_STRUCT:
122 case RPC_FC_PSTRUCT:
123 case RPC_FC_CSTRUCT:
124 case RPC_FC_CPSTRUCT:
125 case RPC_FC_CVSTRUCT:
126 case RPC_FC_BOGUS_STRUCT:
127 return 1;
128 default:
129 return 0;
133 static int is_non_complex_struct(const type_t *type)
135 switch (type->type)
137 case RPC_FC_STRUCT:
138 case RPC_FC_PSTRUCT:
139 case RPC_FC_CSTRUCT:
140 case RPC_FC_CPSTRUCT:
141 case RPC_FC_CVSTRUCT:
142 return 1;
143 default:
144 return 0;
148 int is_union(unsigned char type)
150 switch (type)
152 case RPC_FC_ENCAPSULATED_UNION:
153 case RPC_FC_NON_ENCAPSULATED_UNION:
154 return 1;
155 default:
156 return 0;
160 static int type_has_pointers(const type_t *type)
162 if (is_user_type(type))
163 return FALSE;
164 else if (is_ptr(type))
165 return TRUE;
166 else if (is_array(type))
167 return type_has_pointers(type->ref);
168 else if (is_struct(type->type))
170 const var_t *field;
171 if (type->fields_or_args) LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
173 if (type_has_pointers(field->type))
174 return TRUE;
177 else if (is_union(type->type))
179 var_list_t *fields;
180 const var_t *field;
181 if (type->type == RPC_FC_ENCAPSULATED_UNION)
183 const var_t *uv = LIST_ENTRY(list_tail(type->fields_or_args), const var_t, entry);
184 fields = uv->type->fields_or_args;
186 else
187 fields = type->fields_or_args;
188 if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
190 if (field->type && type_has_pointers(field->type))
191 return TRUE;
195 return FALSE;
198 static int type_has_full_pointer(const type_t *type)
200 if (is_user_type(type))
201 return FALSE;
202 else if (type->type == RPC_FC_FP)
203 return TRUE;
204 else if (is_ptr(type))
205 return FALSE;
206 else if (is_array(type))
207 return type_has_full_pointer(type->ref);
208 else if (is_struct(type->type))
210 const var_t *field;
211 if (type->fields_or_args) LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
213 if (type_has_full_pointer(field->type))
214 return TRUE;
217 else if (is_union(type->type))
219 var_list_t *fields;
220 const var_t *field;
221 if (type->type == RPC_FC_ENCAPSULATED_UNION)
223 const var_t *uv = LIST_ENTRY(list_tail(type->fields_or_args), const var_t, entry);
224 fields = uv->type->fields_or_args;
226 else
227 fields = type->fields_or_args;
228 if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
230 if (field->type && type_has_full_pointer(field->type))
231 return TRUE;
235 return FALSE;
238 static unsigned short user_type_offset(const char *name)
240 user_type_t *ut;
241 unsigned short off = 0;
242 LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
244 if (strcmp(name, ut->name) == 0)
245 return off;
246 ++off;
248 error("user_type_offset: couldn't find type (%s)\n", name);
249 return 0;
252 static void update_tfsoff(type_t *type, unsigned int offset, FILE *file)
254 type->typestring_offset = offset;
255 if (file) type->tfswrite = FALSE;
258 static void guard_rec(type_t *type)
260 /* types that contain references to themselves (like a linked list),
261 need to be shielded from infinite recursion when writing embedded
262 types */
263 if (type->typestring_offset)
264 type->tfswrite = FALSE;
265 else
266 type->typestring_offset = 1;
269 static type_t *get_user_type(const type_t *t, const char **pname)
271 for (;;)
273 type_t *ut = get_attrp(t->attrs, ATTR_WIREMARSHAL);
274 if (ut)
276 if (pname)
277 *pname = t->name;
278 return ut;
281 if (t->kind == TKIND_ALIAS)
282 t = t->orig;
283 else
284 return 0;
288 int is_user_type(const type_t *t)
290 return get_user_type(t, NULL) != NULL;
293 static int is_embedded_complex(const type_t *type)
295 unsigned char tc = type->type;
296 return is_struct(tc) || is_union(tc) || is_array(type) || is_user_type(type)
297 || (is_ptr(type) && type->ref->type == RPC_FC_IP);
300 static const char *get_context_handle_type_name(const type_t *type)
302 const type_t *t;
303 for (t = type; is_ptr(t); t = t->ref)
304 if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
305 return t->name;
306 assert(0);
307 return NULL;
310 /* This is actually fairly involved to implement precisely, due to the
311 effects attributes may have and things like that. Right now this is
312 only used for optimization, so just check for a very small set of
313 criteria that guarantee the types are equivalent; assume every thing
314 else is different. */
315 static int compare_type(const type_t *a, const type_t *b)
317 if (a == b
318 || (a->name
319 && b->name
320 && strcmp(a->name, b->name) == 0))
321 return 0;
322 /* Ordering doesn't need to be implemented yet. */
323 return 1;
326 static int compare_expr(const expr_t *a, const expr_t *b)
328 int ret;
330 if (a->type != b->type)
331 return a->type - b->type;
333 switch (a->type)
335 case EXPR_NUM:
336 case EXPR_HEXNUM:
337 case EXPR_TRUEFALSE:
338 return a->u.lval - b->u.lval;
339 case EXPR_DOUBLE:
340 return a->u.dval - b->u.dval;
341 case EXPR_IDENTIFIER:
342 return strcmp(a->u.sval, b->u.sval);
343 case EXPR_COND:
344 ret = compare_expr(a->ref, b->ref);
345 if (ret != 0)
346 return ret;
347 ret = compare_expr(a->u.ext, b->u.ext);
348 if (ret != 0)
349 return ret;
350 return compare_expr(a->ext2, b->ext2);
351 case EXPR_OR:
352 case EXPR_AND:
353 case EXPR_ADD:
354 case EXPR_SUB:
355 case EXPR_MUL:
356 case EXPR_DIV:
357 case EXPR_SHL:
358 case EXPR_SHR:
359 case EXPR_MEMBERPTR:
360 case EXPR_MEMBER:
361 case EXPR_ARRAY:
362 ret = compare_expr(a->ref, b->ref);
363 if (ret != 0)
364 return ret;
365 return compare_expr(a->u.ext, b->u.ext);
366 case EXPR_CAST:
367 ret = compare_type(a->u.tref, b->u.tref);
368 if (ret != 0)
369 return ret;
370 /* Fall through. */
371 case EXPR_NOT:
372 case EXPR_NEG:
373 case EXPR_PPTR:
374 case EXPR_ADDRESSOF:
375 return compare_expr(a->ref, b->ref);
376 case EXPR_SIZEOF:
377 return compare_type(a->u.tref, b->u.tref);
378 case EXPR_VOID:
379 return 0;
381 return -1;
384 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
385 do { \
386 if (file) \
387 fprintf(file, "/* %2u */\n", typestring_offset); \
388 print_file((file), 2, "0x%02x, /* " #fctype " */\n", RPC_##fctype); \
390 while (0)
392 static void print_file(FILE *file, int indent, const char *format, ...)
394 va_list va;
395 va_start(va, format);
396 print(file, indent, format, va);
397 va_end(va);
400 void print(FILE *file, int indent, const char *format, va_list va)
402 if (file)
404 if (format[0] != '\n')
405 while (0 < indent--)
406 fprintf(file, " ");
407 vfprintf(file, format, va);
412 static void write_var_init(FILE *file, int indent, const type_t *t, const char *n)
414 if (decl_indirect(t))
415 print_file(file, indent, "MIDL_memset(&%s, 0, sizeof(%s));\n", n, n);
416 else if (is_ptr(t) || is_array(t))
417 print_file(file, indent, "%s = 0;\n", n);
420 void write_parameters_init(FILE *file, int indent, const func_t *func)
422 const var_t *var;
424 if (!is_void(get_func_return_type(func)))
425 write_var_init(file, indent, get_func_return_type(func), "_RetVal");
427 if (!func->args)
428 return;
430 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
431 write_var_init(file, indent, var->type, var->name);
433 fprintf(file, "\n");
436 static void write_formatdesc(FILE *f, int indent, const char *str)
438 print_file(f, indent, "typedef struct _MIDL_%s_FORMAT_STRING\n", str);
439 print_file(f, indent, "{\n");
440 print_file(f, indent + 1, "short Pad;\n");
441 print_file(f, indent + 1, "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str);
442 print_file(f, indent, "} MIDL_%s_FORMAT_STRING;\n", str);
443 print_file(f, indent, "\n");
446 void write_formatstringsdecl(FILE *f, int indent, ifref_list_t *ifaces, type_pred_t pred)
448 print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n",
449 get_size_typeformatstring(ifaces, pred));
451 print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n",
452 get_size_procformatstring(ifaces, pred));
454 fprintf(f, "\n");
455 write_formatdesc(f, indent, "TYPE");
456 write_formatdesc(f, indent, "PROC");
457 fprintf(f, "\n");
458 print_file(f, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n");
459 print_file(f, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n");
460 print_file(f, indent, "\n");
463 static inline int is_base_type(unsigned char type)
465 switch (type)
467 case RPC_FC_BYTE:
468 case RPC_FC_CHAR:
469 case RPC_FC_USMALL:
470 case RPC_FC_SMALL:
471 case RPC_FC_WCHAR:
472 case RPC_FC_USHORT:
473 case RPC_FC_SHORT:
474 case RPC_FC_ULONG:
475 case RPC_FC_LONG:
476 case RPC_FC_HYPER:
477 case RPC_FC_IGNORE:
478 case RPC_FC_FLOAT:
479 case RPC_FC_DOUBLE:
480 case RPC_FC_ENUM16:
481 case RPC_FC_ENUM32:
482 case RPC_FC_ERROR_STATUS_T:
483 case RPC_FC_BIND_PRIMITIVE:
484 return TRUE;
486 default:
487 return FALSE;
491 int decl_indirect(const type_t *t)
493 return is_user_type(t)
494 || (!is_base_type(t->type)
495 && !is_ptr(t)
496 && !is_array(t));
499 static size_t write_procformatstring_type(FILE *file, int indent,
500 const char *name,
501 const type_t *type,
502 const attr_list_t *attrs,
503 int is_return)
505 size_t size;
507 int is_in = is_attr(attrs, ATTR_IN);
508 int is_out = is_attr(attrs, ATTR_OUT);
510 if (!is_in && !is_out) is_in = TRUE;
512 if (!type->declarray && is_base_type(type->type))
514 if (is_return)
515 print_file(file, indent, "0x53, /* FC_RETURN_PARAM_BASETYPE */\n");
516 else
517 print_file(file, indent, "0x4e, /* FC_IN_PARAM_BASETYPE */\n");
519 if (type->type == RPC_FC_BIND_PRIMITIVE)
521 print_file(file, indent, "0x%02x, /* FC_IGNORE */\n", RPC_FC_IGNORE);
522 size = 2; /* includes param type prefix */
524 else if (is_base_type(type->type))
526 print_file(file, indent, "0x%02x, /* %s */\n", type->type, string_of_type(type->type));
527 size = 2; /* includes param type prefix */
529 else
531 error("Unknown/unsupported type: %s (0x%02x)\n", name, type->type);
532 size = 0;
535 else
537 if (is_return)
538 print_file(file, indent, "0x52, /* FC_RETURN_PARAM */\n");
539 else if (is_in && is_out)
540 print_file(file, indent, "0x50, /* FC_IN_OUT_PARAM */\n");
541 else if (is_out)
542 print_file(file, indent, "0x51, /* FC_OUT_PARAM */\n");
543 else
544 print_file(file, indent, "0x4d, /* FC_IN_PARAM */\n");
546 print_file(file, indent, "0x01,\n");
547 print_file(file, indent, "NdrFcShort(0x%x),\n", type->typestring_offset);
548 size = 4; /* includes param type prefix */
550 return size;
553 void write_procformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
555 const ifref_t *iface;
556 int indent = 0;
557 const var_t *var;
559 print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
560 print_file(file, indent, "{\n");
561 indent++;
562 print_file(file, indent, "0,\n");
563 print_file(file, indent, "{\n");
564 indent++;
566 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
568 if (!pred(iface->iface))
569 continue;
571 if (iface->iface->funcs)
573 const func_t *func;
574 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
576 if (is_local(func->def->attrs)) continue;
577 /* emit argument data */
578 if (func->args)
580 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
581 write_procformatstring_type(file, indent, var->name, var->type, var->attrs, FALSE);
584 /* emit return value data */
585 if (is_void(get_func_return_type(func)))
587 print_file(file, indent, "0x5b, /* FC_END */\n");
588 print_file(file, indent, "0x5c, /* FC_PAD */\n");
590 else
591 write_procformatstring_type(file, indent, "return value", get_func_return_type(func), NULL, TRUE);
596 print_file(file, indent, "0x0\n");
597 indent--;
598 print_file(file, indent, "}\n");
599 indent--;
600 print_file(file, indent, "};\n");
601 print_file(file, indent, "\n");
604 static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
606 if (is_base_type(type->type))
608 print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
609 *typestring_offset += 1;
610 return 1;
613 return 0;
616 /* write conformance / variance descriptor */
617 static size_t write_conf_or_var_desc(FILE *file, const type_t *structure,
618 unsigned int baseoff, const type_t *type,
619 const expr_t *expr)
621 unsigned char operator_type = 0;
622 unsigned char conftype = RPC_FC_NORMAL_CONFORMANCE;
623 const char *conftype_string = "";
624 const char *operator_string = "no operators";
625 const expr_t *subexpr;
627 if (!expr)
629 print_file(file, 2, "NdrFcLong(0xffffffff),\t/* -1 */\n");
630 return 4;
633 if (!structure)
635 /* Top-level conformance calculations are done inline. */
636 print_file (file, 2, "0x%x,\t/* Corr desc: parameter */\n",
637 RPC_FC_TOP_LEVEL_CONFORMANCE);
638 print_file (file, 2, "0x0,\n");
639 print_file (file, 2, "NdrFcShort(0x0),\n");
640 return 4;
643 if (expr->is_const)
645 if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
646 error("write_conf_or_var_desc: constant value %ld is greater than "
647 "the maximum constant size of %d\n", expr->cval,
648 UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
650 print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n",
651 RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
652 print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX);
653 print_file(file, 2, "NdrFcShort(0x%x),\n", expr->cval & USHRT_MAX);
655 return 4;
658 if (is_ptr(type) || (is_array(type) && !type->declarray))
660 conftype = RPC_FC_POINTER_CONFORMANCE;
661 conftype_string = "field pointer, ";
664 subexpr = expr;
665 switch (subexpr->type)
667 case EXPR_PPTR:
668 subexpr = subexpr->ref;
669 operator_type = RPC_FC_DEREFERENCE;
670 operator_string = "FC_DEREFERENCE";
671 break;
672 case EXPR_DIV:
673 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
675 subexpr = subexpr->ref;
676 operator_type = RPC_FC_DIV_2;
677 operator_string = "FC_DIV_2";
679 break;
680 case EXPR_MUL:
681 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
683 subexpr = subexpr->ref;
684 operator_type = RPC_FC_MULT_2;
685 operator_string = "FC_MULT_2";
687 break;
688 case EXPR_SUB:
689 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
691 subexpr = subexpr->ref;
692 operator_type = RPC_FC_SUB_1;
693 operator_string = "FC_SUB_1";
695 break;
696 case EXPR_ADD:
697 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
699 subexpr = subexpr->ref;
700 operator_type = RPC_FC_ADD_1;
701 operator_string = "FC_ADD_1";
703 break;
704 default:
705 break;
708 if (subexpr->type == EXPR_IDENTIFIER)
710 const type_t *correlation_variable = NULL;
711 unsigned char correlation_variable_type;
712 unsigned char param_type = 0;
713 size_t offset = 0;
714 const var_t *var;
716 if (structure->fields_or_args) LIST_FOR_EACH_ENTRY( var, structure->fields_or_args, const var_t, entry )
718 unsigned int align = 0;
719 /* FIXME: take alignment into account */
720 if (var->name && !strcmp(var->name, subexpr->u.sval))
722 correlation_variable = var->type;
723 break;
725 offset += type_memsize(var->type, &align);
727 if (!correlation_variable)
728 error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
729 subexpr->u.sval);
731 offset -= baseoff;
732 correlation_variable_type = correlation_variable->type;
734 switch (correlation_variable_type)
736 case RPC_FC_CHAR:
737 case RPC_FC_SMALL:
738 param_type = RPC_FC_SMALL;
739 break;
740 case RPC_FC_BYTE:
741 case RPC_FC_USMALL:
742 param_type = RPC_FC_USMALL;
743 break;
744 case RPC_FC_WCHAR:
745 case RPC_FC_SHORT:
746 case RPC_FC_ENUM16:
747 param_type = RPC_FC_SHORT;
748 break;
749 case RPC_FC_USHORT:
750 param_type = RPC_FC_USHORT;
751 break;
752 case RPC_FC_LONG:
753 case RPC_FC_ENUM32:
754 param_type = RPC_FC_LONG;
755 break;
756 case RPC_FC_ULONG:
757 param_type = RPC_FC_ULONG;
758 break;
759 case RPC_FC_RP:
760 case RPC_FC_UP:
761 case RPC_FC_OP:
762 case RPC_FC_FP:
763 if (sizeof(void *) == 4) /* FIXME */
764 param_type = RPC_FC_LONG;
765 else
766 param_type = RPC_FC_HYPER;
767 break;
768 default:
769 error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
770 correlation_variable_type);
773 print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
774 conftype | param_type, conftype_string, string_of_type(param_type));
775 print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string);
776 print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d */\n",
777 offset, offset);
779 else
781 unsigned int callback_offset = 0;
782 struct expr_eval_routine *eval;
783 int found = 0;
785 LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
787 if (!strcmp (eval->structure->name, structure->name)
788 && !compare_expr (eval->expr, expr))
790 found = 1;
791 break;
793 callback_offset++;
796 if (!found)
798 eval = xmalloc (sizeof(*eval));
799 eval->structure = structure;
800 eval->baseoff = baseoff;
801 eval->expr = expr;
802 list_add_tail (&expr_eval_routines, &eval->entry);
805 if (callback_offset > USHRT_MAX)
806 error("Maximum number of callback routines reached\n");
808 print_file(file, 2, "0x%x, /* Corr desc: %s */\n", conftype, conftype_string);
809 print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
810 print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", callback_offset, callback_offset);
812 return 4;
815 static size_t fields_memsize(const var_list_t *fields, unsigned int *align)
817 int have_align = FALSE;
818 size_t size = 0;
819 const var_t *v;
821 if (!fields) return 0;
822 LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
824 unsigned int falign = 0;
825 size_t fsize = type_memsize(v->type, &falign);
826 if (!have_align)
828 *align = falign;
829 have_align = TRUE;
831 size = (size + (falign - 1)) & ~(falign - 1);
832 size += fsize;
835 size = (size + (*align - 1)) & ~(*align - 1);
836 return size;
839 static size_t union_memsize(const var_list_t *fields, unsigned int *pmaxa)
841 size_t size, maxs = 0;
842 unsigned int align = *pmaxa;
843 const var_t *v;
845 if (fields) LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
847 /* we could have an empty default field with NULL type */
848 if (v->type)
850 size = type_memsize(v->type, &align);
851 if (maxs < size) maxs = size;
852 if (*pmaxa < align) *pmaxa = align;
856 return maxs;
859 int get_padding(const var_list_t *fields)
861 unsigned short offset = 0;
862 int salign = -1;
863 const var_t *f;
865 if (!fields)
866 return 0;
868 LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry)
870 type_t *ft = f->type;
871 unsigned int align = 0;
872 size_t size = type_memsize(ft, &align);
873 if (salign == -1)
874 salign = align;
875 offset = (offset + (align - 1)) & ~(align - 1);
876 offset += size;
879 return ((offset + (salign - 1)) & ~(salign - 1)) - offset;
882 size_t type_memsize(const type_t *t, unsigned int *align)
884 size_t size = 0;
886 if (t->declarray && is_conformant_array(t))
888 type_memsize(t->ref, align);
889 size = 0;
891 else if (is_ptr(t) || is_conformant_array(t))
893 size = sizeof(void *);
894 if (size > *align) *align = size;
896 else switch (t->type)
898 case RPC_FC_BYTE:
899 case RPC_FC_CHAR:
900 case RPC_FC_USMALL:
901 case RPC_FC_SMALL:
902 size = 1;
903 if (size > *align) *align = size;
904 break;
905 case RPC_FC_WCHAR:
906 case RPC_FC_USHORT:
907 case RPC_FC_SHORT:
908 case RPC_FC_ENUM16:
909 size = 2;
910 if (size > *align) *align = size;
911 break;
912 case RPC_FC_ULONG:
913 case RPC_FC_LONG:
914 case RPC_FC_ERROR_STATUS_T:
915 case RPC_FC_ENUM32:
916 case RPC_FC_FLOAT:
917 size = 4;
918 if (size > *align) *align = size;
919 break;
920 case RPC_FC_HYPER:
921 case RPC_FC_DOUBLE:
922 size = 8;
923 if (size > *align) *align = size;
924 break;
925 case RPC_FC_STRUCT:
926 case RPC_FC_CVSTRUCT:
927 case RPC_FC_CPSTRUCT:
928 case RPC_FC_CSTRUCT:
929 case RPC_FC_PSTRUCT:
930 case RPC_FC_BOGUS_STRUCT:
931 size = fields_memsize(t->fields_or_args, align);
932 break;
933 case RPC_FC_ENCAPSULATED_UNION:
934 case RPC_FC_NON_ENCAPSULATED_UNION:
935 size = union_memsize(t->fields_or_args, align);
936 break;
937 case RPC_FC_SMFARRAY:
938 case RPC_FC_LGFARRAY:
939 case RPC_FC_SMVARRAY:
940 case RPC_FC_LGVARRAY:
941 case RPC_FC_BOGUS_ARRAY:
942 size = t->dim * type_memsize(t->ref, align);
943 break;
944 default:
945 error("type_memsize: Unknown type %d\n", t->type);
946 size = 0;
949 return size;
952 int is_full_pointer_function(const func_t *func)
954 const var_t *var;
955 if (type_has_full_pointer(get_func_return_type(func)))
956 return TRUE;
957 if (!func->args)
958 return FALSE;
959 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
960 if (type_has_full_pointer( var->type ))
961 return TRUE;
962 return FALSE;
965 void write_full_pointer_init(FILE *file, int indent, const func_t *func, int is_server)
967 print_file(file, indent, "_StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,%s);\n",
968 is_server ? "XLAT_SERVER" : "XLAT_CLIENT");
969 fprintf(file, "\n");
972 void write_full_pointer_free(FILE *file, int indent, const func_t *func)
974 print_file(file, indent, "NdrFullPointerXlatFree(_StubMsg.FullPtrXlatTables);\n");
975 fprintf(file, "\n");
978 static unsigned int write_nonsimple_pointer(FILE *file, const type_t *type, size_t offset)
980 short absoff = type->ref->typestring_offset;
981 short reloff = absoff - (offset + 2);
982 int ptr_attr = is_ptr(type->ref) ? 0x10 : 0x0;
984 print_file(file, 2, "0x%02x, 0x%x,\t/* %s */\n",
985 type->type, ptr_attr, string_of_type(type->type));
986 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%hd) */\n",
987 reloff, reloff, absoff);
988 return 4;
991 static unsigned int write_simple_pointer(FILE *file, const type_t *type)
993 unsigned char fc = type->ref->type;
994 /* for historical reasons, write_simple_pointer also handled string types,
995 * but no longer does. catch bad uses of the function with this check */
996 if (is_string_type(type->attrs, type))
997 error("write_simple_pointer: can't handle type %s which is a string type\n", type->name);
998 print_file(file, 2, "0x%02x, 0x8,\t/* %s [simple_pointer] */\n",
999 type->type, string_of_type(type->type));
1000 print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
1001 print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
1002 return 4;
1005 static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff)
1007 print_file(file, 0, "/* %u (", tfsoff);
1008 write_type_decl(file, t, NULL);
1009 print_file(file, 0, ") */\n");
1012 static size_t write_pointer_tfs(FILE *file, type_t *type, unsigned int *typestring_offset)
1014 unsigned int offset = *typestring_offset;
1016 print_start_tfs_comment(file, type, offset);
1017 update_tfsoff(type, offset, file);
1019 if (type->ref->typestring_offset)
1020 *typestring_offset += write_nonsimple_pointer(file, type, offset);
1021 else if (is_base_type(type->ref->type))
1022 *typestring_offset += write_simple_pointer(file, type);
1024 return offset;
1027 static int processed(const type_t *type)
1029 return type->typestring_offset && !type->tfswrite;
1032 static int user_type_has_variable_size(const type_t *t)
1034 if (is_ptr(t))
1035 return TRUE;
1036 else
1037 switch (t->type)
1039 case RPC_FC_PSTRUCT:
1040 case RPC_FC_CSTRUCT:
1041 case RPC_FC_CPSTRUCT:
1042 case RPC_FC_CVSTRUCT:
1043 return TRUE;
1045 /* Note: Since this only applies to user types, we can't have a conformant
1046 array here, and strings should get filed under pointer in this case. */
1047 return FALSE;
1050 static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
1052 unsigned int start, absoff, flags;
1053 unsigned int align = 0, ualign = 0;
1054 const char *name;
1055 type_t *utype = get_user_type(type, &name);
1056 size_t usize = user_type_has_variable_size(utype) ? 0 : type_memsize(utype, &ualign);
1057 size_t size = type_memsize(type, &align);
1058 unsigned short funoff = user_type_offset(name);
1059 short reloff;
1061 guard_rec(type);
1063 if (is_base_type(utype->type))
1065 absoff = *tfsoff;
1066 print_start_tfs_comment(file, utype, absoff);
1067 print_file(file, 2, "0x%x,\t/* %s */\n", utype->type, string_of_type(utype->type));
1068 print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
1069 *tfsoff += 2;
1071 else
1073 if (!processed(utype))
1074 write_embedded_types(file, NULL, utype, utype->name, TRUE, tfsoff);
1075 absoff = utype->typestring_offset;
1078 if (utype->type == RPC_FC_RP)
1079 flags = 0x40;
1080 else if (utype->type == RPC_FC_UP)
1081 flags = 0x80;
1082 else
1083 flags = 0;
1085 start = *tfsoff;
1086 update_tfsoff(type, start, file);
1087 print_start_tfs_comment(file, type, start);
1088 print_file(file, 2, "0x%x,\t/* FC_USER_MARSHAL */\n", RPC_FC_USER_MARSHAL);
1089 print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
1090 flags | (align - 1), align - 1, flags);
1091 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
1092 print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", size, size);
1093 print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize);
1094 *tfsoff += 8;
1095 reloff = absoff - *tfsoff;
1096 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", reloff, reloff, absoff);
1097 *tfsoff += 2;
1100 static void write_member_type(FILE *file, const type_t *cont,
1101 const attr_list_t *attrs, const type_t *type,
1102 unsigned int *corroff, unsigned int *tfsoff)
1104 if (is_embedded_complex(type) && !is_conformant_array(type))
1106 size_t absoff;
1107 short reloff;
1109 if (is_union(type->type) && is_attr(attrs, ATTR_SWITCHIS))
1111 absoff = *corroff;
1112 *corroff += 8;
1114 else
1116 absoff = type->typestring_offset;
1118 reloff = absoff - (*tfsoff + 2);
1120 print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
1121 /* FIXME: actually compute necessary padding */
1122 print_file(file, 2, "0x0,\t/* FIXME: padding */\n");
1123 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1124 reloff, reloff, absoff);
1125 *tfsoff += 4;
1127 else if (is_ptr(type) || is_conformant_array(type))
1129 unsigned char fc = (cont->type == RPC_FC_BOGUS_STRUCT
1130 ? RPC_FC_POINTER
1131 : RPC_FC_LONG);
1132 print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1133 *tfsoff += 1;
1135 else if (!write_base_type(file, type, tfsoff))
1136 error("Unsupported member type 0x%x\n", type->type);
1139 static void write_end(FILE *file, unsigned int *tfsoff)
1141 if (*tfsoff % 2 == 0)
1143 print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD);
1144 *tfsoff += 1;
1146 print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END);
1147 *tfsoff += 1;
1150 static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
1152 unsigned int offset = 0;
1153 var_list_t *fs = type->fields_or_args;
1154 var_t *f;
1156 if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
1158 unsigned int align = 0;
1159 type_t *ft = f->type;
1160 if (is_union(ft->type) && is_attr(f->attrs, ATTR_SWITCHIS))
1162 unsigned int absoff = ft->typestring_offset;
1163 short reloff = absoff - (*tfsoff + 6);
1164 print_file(file, 0, "/* %d */\n", *tfsoff);
1165 print_file(file, 2, "0x%x,\t/* %s */\n", ft->type, string_of_type(ft->type));
1166 print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", RPC_FC_LONG);
1167 write_conf_or_var_desc(file, current_structure, offset, ft,
1168 get_attrp(f->attrs, ATTR_SWITCHIS));
1169 print_file(file, 2, "NdrFcShort(%hd),\t/* Offset= %hd (%u) */\n",
1170 reloff, reloff, absoff);
1171 *tfsoff += 8;
1174 /* FIXME: take alignment into account */
1175 offset += type_memsize(ft, &align);
1179 static int write_no_repeat_pointer_descriptions(
1180 FILE *file, type_t *type,
1181 size_t *offset_in_memory, size_t *offset_in_buffer,
1182 unsigned int *typestring_offset)
1184 int written = 0;
1185 unsigned int align;
1187 if (is_ptr(type) || (!type->declarray && is_conformant_array(type)))
1189 print_file(file, 2, "0x%02x, /* FC_NO_REPEAT */\n", RPC_FC_NO_REPEAT);
1190 print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1192 /* pointer instance */
1193 print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1194 print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1195 *typestring_offset += 6;
1197 if (is_ptr(type))
1199 if (is_string_type(type->attrs, type))
1200 write_string_tfs(file, NULL, type, NULL, typestring_offset);
1201 else
1202 write_pointer_tfs(file, type, typestring_offset);
1204 else
1206 unsigned absoff = type->typestring_offset;
1207 short reloff = absoff - (*typestring_offset + 2);
1208 /* FIXME: get pointer attributes from field */
1209 print_file(file, 2, "0x%02x, 0x0,\t/* %s */\n", RPC_FC_UP, "FC_UP");
1210 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1211 reloff, reloff, absoff);
1212 *typestring_offset += 4;
1215 align = 0;
1216 *offset_in_memory += type_memsize(type, &align);
1217 /* FIXME: is there a case where these two are different? */
1218 align = 0;
1219 *offset_in_buffer += type_memsize(type, &align);
1221 return 1;
1224 if (is_non_complex_struct(type))
1226 const var_t *v;
1227 LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
1228 written += write_no_repeat_pointer_descriptions(
1229 file, v->type,
1230 offset_in_memory, offset_in_buffer, typestring_offset);
1232 else
1234 align = 0;
1235 *offset_in_memory += type_memsize(type, &align);
1236 /* FIXME: is there a case where these two are different? */
1237 align = 0;
1238 *offset_in_buffer += type_memsize(type, &align);
1241 return written;
1244 static int write_pointer_description_offsets(
1245 FILE *file, const attr_list_t *attrs, type_t *type,
1246 size_t *offset_in_memory, size_t *offset_in_buffer,
1247 unsigned int *typestring_offset)
1249 int written = 0;
1250 unsigned int align;
1252 if (is_ptr(type) && type->ref->type != RPC_FC_IP)
1254 if (offset_in_memory && offset_in_buffer)
1256 /* pointer instance */
1257 /* FIXME: sometimes from end of structure, sometimes from beginning */
1258 print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1259 print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1261 align = 0;
1262 *offset_in_memory += type_memsize(type, &align);
1263 /* FIXME: is there a case where these two are different? */
1264 align = 0;
1265 *offset_in_buffer += type_memsize(type, &align);
1267 *typestring_offset += 4;
1269 if (is_string_type(attrs, type))
1270 write_string_tfs(file, NULL, type, NULL, typestring_offset);
1271 else if (processed(type->ref) || is_base_type(type->ref->type))
1272 write_pointer_tfs(file, type, typestring_offset);
1273 else
1274 error("write_pointer_description_offsets: type format string unknown\n");
1276 return 1;
1279 if (is_array(type))
1281 return write_pointer_description_offsets(
1282 file, attrs, type->ref, offset_in_memory, offset_in_buffer,
1283 typestring_offset);
1285 else if (is_non_complex_struct(type))
1287 /* otherwise search for interesting fields to parse */
1288 const var_t *v;
1289 LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
1291 written += write_pointer_description_offsets(
1292 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1293 typestring_offset);
1296 else
1298 align = 0;
1299 if (offset_in_memory)
1300 *offset_in_memory += type_memsize(type, &align);
1301 /* FIXME: is there a case where these two are different? */
1302 align = 0;
1303 if (offset_in_buffer)
1304 *offset_in_buffer += type_memsize(type, &align);
1307 return written;
1310 /* Note: if file is NULL return value is number of pointers to write, else
1311 * it is the number of type format characters written */
1312 static int write_fixed_array_pointer_descriptions(
1313 FILE *file, const attr_list_t *attrs, type_t *type,
1314 size_t *offset_in_memory, size_t *offset_in_buffer,
1315 unsigned int *typestring_offset)
1317 unsigned int align;
1318 int pointer_count = 0;
1320 if (type->type == RPC_FC_SMFARRAY || type->type == RPC_FC_LGFARRAY)
1322 unsigned int temp = 0;
1323 /* unfortunately, this needs to be done in two passes to avoid
1324 * writing out redundant FC_FIXED_REPEAT descriptions */
1325 pointer_count = write_pointer_description_offsets(
1326 NULL, attrs, type->ref, NULL, NULL, &temp);
1327 if (pointer_count > 0)
1329 unsigned int increment_size;
1330 size_t offset_of_array_pointer_mem = 0;
1331 size_t offset_of_array_pointer_buf = 0;
1333 align = 0;
1334 increment_size = type_memsize(type->ref, &align);
1336 print_file(file, 2, "0x%02x, /* FC_FIXED_REPEAT */\n", RPC_FC_FIXED_REPEAT);
1337 print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1338 print_file(file, 2, "NdrFcShort(0x%x), /* Iterations = %d */\n", type->dim, type->dim);
1339 print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1340 print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory);
1341 print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1342 *typestring_offset += 10;
1344 pointer_count = write_pointer_description_offsets(
1345 file, attrs, type, &offset_of_array_pointer_mem,
1346 &offset_of_array_pointer_buf, typestring_offset);
1349 else if (is_struct(type->type))
1351 const var_t *v;
1352 LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
1354 pointer_count += write_fixed_array_pointer_descriptions(
1355 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1356 typestring_offset);
1359 else
1361 align = 0;
1362 if (offset_in_memory)
1363 *offset_in_memory += type_memsize(type, &align);
1364 /* FIXME: is there a case where these two are different? */
1365 align = 0;
1366 if (offset_in_buffer)
1367 *offset_in_buffer += type_memsize(type, &align);
1370 return pointer_count;
1373 /* Note: if file is NULL return value is number of pointers to write, else
1374 * it is the number of type format characters written */
1375 static int write_conformant_array_pointer_descriptions(
1376 FILE *file, const attr_list_t *attrs, type_t *type,
1377 size_t offset_in_memory, unsigned int *typestring_offset)
1379 unsigned int align;
1380 int pointer_count = 0;
1382 if (is_conformant_array(type) && !type->length_is)
1384 unsigned int temp = 0;
1385 /* unfortunately, this needs to be done in two passes to avoid
1386 * writing out redundant FC_VARIABLE_REPEAT descriptions */
1387 pointer_count = write_pointer_description_offsets(
1388 NULL, attrs, type->ref, NULL, NULL, &temp);
1389 if (pointer_count > 0)
1391 unsigned int increment_size;
1392 size_t offset_of_array_pointer_mem = offset_in_memory;
1393 size_t offset_of_array_pointer_buf = offset_in_memory;
1395 align = 0;
1396 increment_size = type_memsize(type->ref, &align);
1398 if (increment_size > USHRT_MAX)
1399 error("array size of %u bytes is too large\n", increment_size);
1401 print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
1402 print_file(file, 2, "0x%02x, /* FC_FIXED_OFFSET */\n", RPC_FC_FIXED_OFFSET);
1403 print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1404 print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", offset_in_memory, offset_in_memory);
1405 print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1406 *typestring_offset += 8;
1408 pointer_count = write_pointer_description_offsets(
1409 file, attrs, type->ref, &offset_of_array_pointer_mem,
1410 &offset_of_array_pointer_buf, typestring_offset);
1414 return pointer_count;
1417 /* Note: if file is NULL return value is number of pointers to write, else
1418 * it is the number of type format characters written */
1419 static int write_varying_array_pointer_descriptions(
1420 FILE *file, const attr_list_t *attrs, type_t *type,
1421 size_t *offset_in_memory, size_t *offset_in_buffer,
1422 unsigned int *typestring_offset)
1424 unsigned int align;
1425 int pointer_count = 0;
1427 /* FIXME: do varying array searching here, but pointer searching in write_pointer_description_offsets */
1429 if (is_array(type) && type->length_is)
1431 unsigned int temp = 0;
1432 /* unfortunately, this needs to be done in two passes to avoid
1433 * writing out redundant FC_VARIABLE_REPEAT descriptions */
1434 pointer_count = write_pointer_description_offsets(
1435 NULL, attrs, type->ref, NULL, NULL, &temp);
1436 if (pointer_count > 0)
1438 unsigned int increment_size;
1439 size_t offset_of_array_pointer_mem = 0;
1440 size_t offset_of_array_pointer_buf = 0;
1442 align = 0;
1443 increment_size = type_memsize(type->ref, &align);
1445 if (increment_size > USHRT_MAX)
1446 error("array size of %u bytes is too large\n", increment_size);
1448 print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
1449 print_file(file, 2, "0x%02x, /* FC_VARIABLE_OFFSET */\n", RPC_FC_VARIABLE_OFFSET);
1450 print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1451 print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory);
1452 print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1453 *typestring_offset += 8;
1455 pointer_count = write_pointer_description_offsets(
1456 file, attrs, type, &offset_of_array_pointer_mem,
1457 &offset_of_array_pointer_buf, typestring_offset);
1460 else if (is_struct(type->type))
1462 const var_t *v;
1463 LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
1465 pointer_count += write_varying_array_pointer_descriptions(
1466 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1467 typestring_offset);
1470 else
1472 align = 0;
1473 if (offset_in_memory)
1474 *offset_in_memory += type_memsize(type, &align);
1475 /* FIXME: is there a case where these two are different? */
1476 align = 0;
1477 if (offset_in_buffer)
1478 *offset_in_buffer += type_memsize(type, &align);
1481 return pointer_count;
1484 static void write_pointer_description(FILE *file, type_t *type,
1485 unsigned int *typestring_offset)
1487 size_t offset_in_buffer;
1488 size_t offset_in_memory;
1490 /* pass 1: search for single instance of a pointer (i.e. don't descend
1491 * into arrays) */
1492 if (!is_array(type))
1494 offset_in_memory = 0;
1495 offset_in_buffer = 0;
1496 write_no_repeat_pointer_descriptions(
1497 file, type,
1498 &offset_in_memory, &offset_in_buffer, typestring_offset);
1501 /* pass 2: search for pointers in fixed arrays */
1502 offset_in_memory = 0;
1503 offset_in_buffer = 0;
1504 write_fixed_array_pointer_descriptions(
1505 file, NULL, type,
1506 &offset_in_memory, &offset_in_buffer, typestring_offset);
1508 /* pass 3: search for pointers in conformant only arrays (but don't descend
1509 * into conformant varying or varying arrays) */
1510 if ((!type->declarray || !current_structure) && is_conformant_array(type))
1511 write_conformant_array_pointer_descriptions(
1512 file, NULL, type, 0, typestring_offset);
1513 else if (type->type == RPC_FC_CPSTRUCT)
1515 unsigned int align = 0;
1516 type_t *carray = find_array_or_string_in_struct(type)->type;
1517 write_conformant_array_pointer_descriptions(
1518 file, NULL, carray,
1519 type_memsize(type, &align),
1520 typestring_offset);
1523 /* pass 4: search for pointers in varying arrays */
1524 offset_in_memory = 0;
1525 offset_in_buffer = 0;
1526 write_varying_array_pointer_descriptions(
1527 file, NULL, type,
1528 &offset_in_memory, &offset_in_buffer, typestring_offset);
1531 int is_declptr(const type_t *t)
1533 return is_ptr(t) || (is_conformant_array(t) && !t->declarray);
1536 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
1537 type_t *type,
1538 const char *name, unsigned int *typestring_offset)
1540 size_t start_offset;
1541 unsigned char rtype;
1543 if (is_declptr(type))
1545 unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER;
1546 int pointer_type = is_ptr(type) ? type->type : get_attrv(attrs, ATTR_POINTERTYPE);
1547 if (!pointer_type)
1548 pointer_type = RPC_FC_RP;
1549 print_start_tfs_comment(file, type, *typestring_offset);
1550 print_file(file, 2,"0x%x, 0x%x,\t/* %s%s */\n",
1551 pointer_type, flag, string_of_type(pointer_type),
1552 flag ? " [simple_pointer]" : "");
1553 *typestring_offset += 2;
1554 if (!flag)
1556 print_file(file, 2, "NdrFcShort(0x2),\n");
1557 *typestring_offset += 2;
1561 start_offset = *typestring_offset;
1562 update_tfsoff(type, start_offset, file);
1564 rtype = type->ref->type;
1566 if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR))
1568 error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
1569 return start_offset;
1572 if (type->declarray && !is_conformant_array(type))
1574 /* FIXME: multi-dimensional array */
1575 if (0xffffuL < type->dim)
1576 error("array size for parameter %s exceeds %u bytes by %lu bytes\n",
1577 name, 0xffffu, type->dim - 0xffffu);
1579 if (rtype == RPC_FC_CHAR)
1580 WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
1581 else
1582 WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
1583 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1584 *typestring_offset += 2;
1586 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", type->dim, type->dim);
1587 *typestring_offset += 2;
1589 return start_offset;
1591 else if (type->size_is)
1593 unsigned int align = 0;
1595 if (rtype == RPC_FC_CHAR)
1596 WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
1597 else
1598 WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
1599 print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
1600 *typestring_offset += 2;
1602 *typestring_offset += write_conf_or_var_desc(
1603 file, current_structure,
1604 (type->declarray && current_structure
1605 ? type_memsize(current_structure, &align)
1606 : 0),
1607 type, type->size_is);
1609 return start_offset;
1611 else
1613 if (rtype == RPC_FC_WCHAR)
1614 WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
1615 else
1616 WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
1617 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1618 *typestring_offset += 2;
1620 return start_offset;
1624 static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
1625 const char *name, unsigned int *typestring_offset)
1627 const expr_t *length_is = type->length_is;
1628 const expr_t *size_is = type->size_is;
1629 unsigned int align = 0;
1630 size_t size;
1631 size_t start_offset;
1632 int has_pointer;
1633 int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
1634 unsigned int baseoff
1635 = type->declarray && current_structure
1636 ? type_memsize(current_structure, &align)
1637 : 0;
1639 if (!pointer_type)
1640 pointer_type = RPC_FC_RP;
1642 if (write_embedded_types(file, attrs, type->ref, name, FALSE, typestring_offset))
1643 has_pointer = TRUE;
1644 else
1645 has_pointer = type_has_pointers(type->ref);
1647 align = 0;
1648 size = type_memsize((is_conformant_array(type) ? type->ref : type), &align);
1650 start_offset = *typestring_offset;
1651 update_tfsoff(type, start_offset, file);
1652 print_start_tfs_comment(file, type, start_offset);
1653 print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
1654 print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1655 *typestring_offset += 2;
1657 align = 0;
1658 if (type->type != RPC_FC_BOGUS_ARRAY)
1660 unsigned char tc = type->type;
1662 if (tc == RPC_FC_LGFARRAY || tc == RPC_FC_LGVARRAY)
1664 print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", size, size);
1665 *typestring_offset += 4;
1667 else
1669 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", size, size);
1670 *typestring_offset += 2;
1673 if (is_conformant_array(type))
1674 *typestring_offset
1675 += write_conf_or_var_desc(file, current_structure, baseoff,
1676 type, size_is);
1678 if (type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY)
1680 unsigned int elalign = 0;
1681 size_t elsize = type_memsize(type->ref, &elalign);
1683 if (type->type == RPC_FC_LGVARRAY)
1685 print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", type->dim, type->dim);
1686 *typestring_offset += 4;
1688 else
1690 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", type->dim, type->dim);
1691 *typestring_offset += 2;
1694 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", elsize, elsize);
1695 *typestring_offset += 2;
1698 if (length_is)
1699 *typestring_offset
1700 += write_conf_or_var_desc(file, current_structure, baseoff,
1701 type, length_is);
1703 if (has_pointer && (!type->declarray || !current_structure))
1705 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1706 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1707 *typestring_offset += 2;
1708 write_pointer_description(file, type, typestring_offset);
1709 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1710 *typestring_offset += 1;
1713 write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1714 write_end(file, typestring_offset);
1716 else
1718 unsigned int dim = size_is ? 0 : type->dim;
1719 print_file(file, 2, "NdrFcShort(0x%x),\t/* %u */\n", dim, dim);
1720 *typestring_offset += 2;
1721 *typestring_offset
1722 += write_conf_or_var_desc(file, current_structure, baseoff,
1723 type, size_is);
1724 *typestring_offset
1725 += write_conf_or_var_desc(file, current_structure, baseoff,
1726 type, length_is);
1727 write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1728 write_end(file, typestring_offset);
1731 return start_offset;
1734 static const var_t *find_array_or_string_in_struct(const type_t *type)
1736 const var_t *last_field = LIST_ENTRY( list_tail(type->fields_or_args), const var_t, entry );
1737 const type_t *ft = last_field->type;
1739 if (ft->declarray && is_conformant_array(ft))
1740 return last_field;
1742 if (ft->type == RPC_FC_CSTRUCT || ft->type == RPC_FC_CPSTRUCT || ft->type == RPC_FC_CVSTRUCT)
1743 return find_array_or_string_in_struct(last_field->type);
1744 else
1745 return NULL;
1748 static void write_struct_members(FILE *file, const type_t *type,
1749 unsigned int *corroff, unsigned int *typestring_offset)
1751 const var_t *field;
1752 unsigned short offset = 0;
1753 int salign = -1;
1754 int padding;
1756 if (type->fields_or_args) LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
1758 type_t *ft = field->type;
1759 if (!ft->declarray || !is_conformant_array(ft))
1761 unsigned int align = 0;
1762 size_t size = type_memsize(ft, &align);
1763 if (salign == -1)
1764 salign = align;
1765 if ((align - 1) & offset)
1767 unsigned char fc = 0;
1768 switch (align)
1770 case 4:
1771 fc = RPC_FC_ALIGNM4;
1772 break;
1773 case 8:
1774 fc = RPC_FC_ALIGNM8;
1775 break;
1776 default:
1777 error("write_struct_members: cannot align type %d\n", ft->type);
1779 print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1780 offset = (offset + (align - 1)) & ~(align - 1);
1781 *typestring_offset += 1;
1783 write_member_type(file, type, field->attrs, field->type, corroff,
1784 typestring_offset);
1785 offset += size;
1789 padding = ((offset + (salign - 1)) & ~(salign - 1)) - offset;
1790 if (padding)
1792 print_file(file, 2, "0x%x,\t/* FC_STRUCTPAD%d */\n",
1793 RPC_FC_STRUCTPAD1 + padding - 1,
1794 padding);
1795 *typestring_offset += 1;
1798 write_end(file, typestring_offset);
1801 static size_t write_struct_tfs(FILE *file, type_t *type,
1802 const char *name, unsigned int *tfsoff)
1804 const type_t *save_current_structure = current_structure;
1805 unsigned int total_size;
1806 const var_t *array;
1807 size_t start_offset;
1808 size_t array_offset;
1809 int has_pointers = 0;
1810 unsigned int align = 0;
1811 unsigned int corroff;
1812 var_t *f;
1814 guard_rec(type);
1815 current_structure = type;
1817 total_size = type_memsize(type, &align);
1818 if (total_size > USHRT_MAX)
1819 error("structure size for %s exceeds %d bytes by %d bytes\n",
1820 name, USHRT_MAX, total_size - USHRT_MAX);
1822 if (type->fields_or_args) LIST_FOR_EACH_ENTRY(f, type->fields_or_args, var_t, entry)
1823 has_pointers |= write_embedded_types(file, f->attrs, f->type, f->name,
1824 FALSE, tfsoff);
1825 if (!has_pointers) has_pointers = type_has_pointers(type);
1827 array = find_array_or_string_in_struct(type);
1828 if (array && !processed(array->type))
1829 array_offset
1830 = is_attr(array->attrs, ATTR_STRING)
1831 ? write_string_tfs(file, array->attrs, array->type, array->name, tfsoff)
1832 : write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
1834 corroff = *tfsoff;
1835 write_descriptors(file, type, tfsoff);
1837 start_offset = *tfsoff;
1838 update_tfsoff(type, start_offset, file);
1839 print_start_tfs_comment(file, type, start_offset);
1840 print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
1841 print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1842 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size);
1843 *tfsoff += 4;
1845 if (array)
1847 unsigned int absoff = array->type->typestring_offset;
1848 short reloff = absoff - *tfsoff;
1849 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1850 reloff, reloff, absoff);
1851 *tfsoff += 2;
1853 else if (type->type == RPC_FC_BOGUS_STRUCT)
1855 print_file(file, 2, "NdrFcShort(0x0),\n");
1856 *tfsoff += 2;
1859 if (type->type == RPC_FC_BOGUS_STRUCT)
1861 /* On the sizing pass, type->ptrdesc may be zero, but it's ok as
1862 nothing is written to file yet. On the actual writing pass,
1863 this will have been updated. */
1864 unsigned int absoff = type->ptrdesc ? type->ptrdesc : *tfsoff;
1865 short reloff = absoff - *tfsoff;
1866 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1867 reloff, reloff, absoff);
1868 *tfsoff += 2;
1870 else if ((type->type == RPC_FC_PSTRUCT) ||
1871 (type->type == RPC_FC_CPSTRUCT) ||
1872 (type->type == RPC_FC_CVSTRUCT && has_pointers))
1874 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1875 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1876 *tfsoff += 2;
1877 write_pointer_description(file, type, tfsoff);
1878 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1879 *tfsoff += 1;
1882 write_struct_members(file, type, &corroff, tfsoff);
1884 if (type->type == RPC_FC_BOGUS_STRUCT)
1886 const var_list_t *fs = type->fields_or_args;
1887 const var_t *f;
1889 type->ptrdesc = *tfsoff;
1890 if (fs) LIST_FOR_EACH_ENTRY(f, fs, const var_t, entry)
1892 type_t *ft = f->type;
1893 if (is_ptr(ft))
1895 if (is_string_type(f->attrs, ft))
1896 write_string_tfs(file, f->attrs, ft, f->name, tfsoff);
1897 else
1898 write_pointer_tfs(file, ft, tfsoff);
1900 else if (!ft->declarray && is_conformant_array(ft))
1902 unsigned int absoff = ft->typestring_offset;
1903 short reloff = absoff - (*tfsoff + 2);
1904 int ptr_type = get_attrv(f->attrs, ATTR_POINTERTYPE);
1905 /* FIXME: We need to store pointer attributes for arrays
1906 so we don't lose pointer_default info. */
1907 if (ptr_type == 0)
1908 ptr_type = RPC_FC_UP;
1909 print_file(file, 0, "/* %d */\n", *tfsoff);
1910 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
1911 string_of_type(ptr_type));
1912 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1913 reloff, reloff, absoff);
1914 *tfsoff += 4;
1917 if (type->ptrdesc == *tfsoff)
1918 type->ptrdesc = 0;
1921 current_structure = save_current_structure;
1922 return start_offset;
1925 static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
1926 unsigned char flags, size_t offset,
1927 unsigned int *typeformat_offset)
1929 size_t start_offset = *typeformat_offset;
1930 short reloff = offset - (*typeformat_offset + 2);
1931 int in_attr, out_attr;
1932 in_attr = is_attr(attrs, ATTR_IN);
1933 out_attr = is_attr(attrs, ATTR_OUT);
1934 if (!in_attr && !out_attr) in_attr = 1;
1936 if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
1937 flags |= 0x04;
1939 print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
1940 pointer_type,
1941 flags,
1942 string_of_type(pointer_type));
1943 if (file)
1945 if (flags & 0x04)
1946 fprintf(file, " [allocated_on_stack]");
1947 if (flags & 0x10)
1948 fprintf(file, " [pointer_deref]");
1949 fprintf(file, " */\n");
1952 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", reloff, offset);
1953 *typeformat_offset += 4;
1955 return start_offset;
1958 static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
1960 if (t == NULL)
1962 print_file(file, 2, "NdrFcShort(0x0),\t/* No type */\n");
1964 else if (is_base_type(t->type))
1966 print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n",
1967 t->type, string_of_type(t->type));
1969 else if (t->typestring_offset)
1971 short reloff = t->typestring_offset - *tfsoff;
1972 print_file(file, 2, "NdrFcShort(0x%x),\t/* Offset= %d (%d) */\n",
1973 reloff, reloff, t->typestring_offset);
1975 else
1976 error("write_branch_type: type unimplemented (0x%x)\n", t->type);
1978 *tfsoff += 2;
1981 static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
1983 unsigned int align = 0;
1984 unsigned int start_offset;
1985 size_t size = type_memsize(type, &align);
1986 var_list_t *fields;
1987 size_t nbranch = 0;
1988 type_t *deftype = NULL;
1989 short nodeftype = 0xffff;
1990 var_t *f;
1992 guard_rec(type);
1994 if (type->type == RPC_FC_ENCAPSULATED_UNION)
1996 const var_t *uv = LIST_ENTRY(list_tail(type->fields_or_args), const var_t, entry);
1997 fields = uv->type->fields_or_args;
1999 else
2000 fields = type->fields_or_args;
2002 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
2004 expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
2005 if (cases)
2006 nbranch += list_count(cases);
2007 if (f->type)
2008 write_embedded_types(file, f->attrs, f->type, f->name, TRUE, tfsoff);
2011 start_offset = *tfsoff;
2012 update_tfsoff(type, start_offset, file);
2013 print_start_tfs_comment(file, type, start_offset);
2014 if (type->type == RPC_FC_ENCAPSULATED_UNION)
2016 const var_t *sv = LIST_ENTRY(list_head(type->fields_or_args), const var_t, entry);
2017 const type_t *st = sv->type;
2019 switch (st->type)
2021 case RPC_FC_CHAR:
2022 case RPC_FC_SMALL:
2023 case RPC_FC_USMALL:
2024 case RPC_FC_SHORT:
2025 case RPC_FC_USHORT:
2026 case RPC_FC_LONG:
2027 case RPC_FC_ULONG:
2028 case RPC_FC_ENUM16:
2029 case RPC_FC_ENUM32:
2030 print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
2031 print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
2032 0x40 | st->type, string_of_type(st->type));
2033 *tfsoff += 2;
2034 break;
2035 default:
2036 error("union switch type must be an integer, char, or enum\n");
2039 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", size, size);
2040 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", nbranch, nbranch);
2041 *tfsoff += 4;
2043 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
2045 type_t *ft = f->type;
2046 expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
2047 int deflt = is_attr(f->attrs, ATTR_DEFAULT);
2048 expr_t *c;
2050 if (cases == NULL && !deflt)
2051 error("union field %s with neither case nor default attribute\n", f->name);
2053 if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry)
2055 /* MIDL doesn't check for duplicate cases, even though that seems
2056 like a reasonable thing to do, it just dumps them to the TFS
2057 like we're going to do here. */
2058 print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
2059 *tfsoff += 4;
2060 write_branch_type(file, ft, tfsoff);
2063 /* MIDL allows multiple default branches, even though that seems
2064 illogical, it just chooses the last one, which is what we will
2065 do. */
2066 if (deflt)
2068 deftype = ft;
2069 nodeftype = 0;
2073 if (deftype)
2075 write_branch_type(file, deftype, tfsoff);
2077 else
2079 print_file(file, 2, "NdrFcShort(0x%x),\n", nodeftype);
2080 *tfsoff += 2;
2083 return start_offset;
2086 static size_t write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
2087 unsigned int *typeformat_offset)
2089 size_t i;
2090 size_t start_offset = *typeformat_offset;
2091 expr_t *iid = get_attrp(attrs, ATTR_IIDIS);
2093 if (iid)
2095 print_file(file, 2, "0x2f, /* FC_IP */\n");
2096 print_file(file, 2, "0x5c, /* FC_PAD */\n");
2097 *typeformat_offset
2098 += write_conf_or_var_desc(file, NULL, 0, type, iid) + 2;
2100 else
2102 const type_t *base = is_ptr(type) ? type->ref : type;
2103 const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
2105 if (! uuid)
2106 error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
2108 update_tfsoff(type, start_offset, file);
2109 print_start_tfs_comment(file, type, start_offset);
2110 print_file(file, 2, "0x2f,\t/* FC_IP */\n");
2111 print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
2112 print_file(file, 2, "NdrFcLong(0x%08lx),\n", uuid->Data1);
2113 print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2);
2114 print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3);
2115 for (i = 0; i < 8; ++i)
2116 print_file(file, 2, "0x%02x,\n", uuid->Data4[i]);
2118 if (file)
2119 fprintf(file, "\n");
2121 *typeformat_offset += 18;
2123 return start_offset;
2126 static size_t write_contexthandle_tfs(FILE *file, const type_t *type,
2127 const var_t *var,
2128 unsigned int *typeformat_offset)
2130 size_t start_offset = *typeformat_offset;
2131 unsigned char flags = 0;
2133 if (is_attr(current_iface->attrs, ATTR_STRICTCONTEXTHANDLE))
2134 flags |= NDR_STRICT_CONTEXT_HANDLE;
2136 if (is_ptr(type))
2137 flags |= 0x80;
2138 if (is_attr(var->attrs, ATTR_IN))
2140 flags |= 0x40;
2141 if (!is_attr(var->attrs, ATTR_OUT))
2142 flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
2144 if (is_attr(var->attrs, ATTR_OUT))
2145 flags |= 0x20;
2147 WRITE_FCTYPE(file, FC_BIND_CONTEXT, *typeformat_offset);
2148 print_file(file, 2, "0x%x,\t/* Context flags: ", flags);
2149 /* return and can't be null values overlap */
2150 if (((flags & 0x21) != 0x21) && (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL))
2151 print_file(file, 0, "can't be null, ");
2152 if (flags & NDR_CONTEXT_HANDLE_SERIALIZE)
2153 print_file(file, 0, "serialize, ");
2154 if (flags & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
2155 print_file(file, 0, "no serialize, ");
2156 if (flags & NDR_STRICT_CONTEXT_HANDLE)
2157 print_file(file, 0, "strict, ");
2158 if ((flags & 0x21) == 0x20)
2159 print_file(file, 0, "out, ");
2160 if ((flags & 0x21) == 0x21)
2161 print_file(file, 0, "return, ");
2162 if (flags & 0x40)
2163 print_file(file, 0, "in, ");
2164 if (flags & 0x80)
2165 print_file(file, 0, "via ptr, ");
2166 print_file(file, 0, "*/\n");
2167 print_file(file, 2, "0, /* FIXME: rundown routine index*/\n");
2168 print_file(file, 2, "0, /* FIXME: param num */\n");
2169 *typeformat_offset += 4;
2171 return start_offset;
2174 static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *func,
2175 type_t *type, const var_t *var,
2176 unsigned int *typeformat_offset)
2178 size_t offset;
2180 if (is_context_handle(type))
2181 return write_contexthandle_tfs(file, type, var, typeformat_offset);
2183 if (is_user_type(type))
2185 write_user_tfs(file, type, typeformat_offset);
2186 return type->typestring_offset;
2189 if (is_string_type(var->attrs, type))
2190 return write_string_tfs(file, var->attrs, type, var->name, typeformat_offset);
2192 if (is_array(type))
2194 int ptr_type;
2195 size_t off;
2196 off = write_array_tfs(file, var->attrs, type, var->name, typeformat_offset);
2197 ptr_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2198 /* Top level pointers to conformant arrays may be handled specially
2199 since we can bypass the pointer, but if the array is buried
2200 beneath another pointer (e.g., "[size_is(,n)] int **p" then we
2201 always need to write the pointer. */
2202 if (!ptr_type && var->type != type)
2203 /* FIXME: This should use pointer_default, but the information
2204 isn't kept around for arrays. */
2205 ptr_type = RPC_FC_UP;
2206 if (ptr_type && ptr_type != RPC_FC_RP)
2208 unsigned int absoff = type->typestring_offset;
2209 short reloff = absoff - (*typeformat_offset + 2);
2210 off = *typeformat_offset;
2211 print_file(file, 0, "/* %d */\n", off);
2212 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
2213 string_of_type(ptr_type));
2214 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
2215 reloff, reloff, absoff);
2216 *typeformat_offset += 4;
2218 return off;
2221 if (!is_ptr(type))
2223 /* basic types don't need a type format string */
2224 if (is_base_type(type->type))
2225 return 0;
2227 switch (type->type)
2229 case RPC_FC_STRUCT:
2230 case RPC_FC_PSTRUCT:
2231 case RPC_FC_CSTRUCT:
2232 case RPC_FC_CPSTRUCT:
2233 case RPC_FC_CVSTRUCT:
2234 case RPC_FC_BOGUS_STRUCT:
2235 return write_struct_tfs(file, type, var->name, typeformat_offset);
2236 case RPC_FC_ENCAPSULATED_UNION:
2237 case RPC_FC_NON_ENCAPSULATED_UNION:
2238 return write_union_tfs(file, type, typeformat_offset);
2239 case RPC_FC_IGNORE:
2240 case RPC_FC_BIND_PRIMITIVE:
2241 /* nothing to do */
2242 return 0;
2243 default:
2244 error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
2247 else if (last_ptr(type))
2249 size_t start_offset = *typeformat_offset;
2250 int in_attr = is_attr(var->attrs, ATTR_IN);
2251 int out_attr = is_attr(var->attrs, ATTR_OUT);
2252 const type_t *base = type->ref;
2254 if (base->type == RPC_FC_IP
2255 || (base->type == 0
2256 && is_attr(var->attrs, ATTR_IIDIS)))
2258 return write_ip_tfs(file, var->attrs, type, typeformat_offset);
2261 /* special case for pointers to base types */
2262 if (is_base_type(base->type))
2264 print_file(file, indent, "0x%x, 0x%x, /* %s %s[simple_pointer] */\n",
2265 type->type, (!in_attr && out_attr) ? 0x0C : 0x08,
2266 string_of_type(type->type),
2267 (!in_attr && out_attr) ? "[allocated_on_stack] " : "");
2268 print_file(file, indent, "0x%02x, /* %s */\n", base->type, string_of_type(base->type));
2269 print_file(file, indent, "0x5c, /* FC_PAD */\n");
2270 *typeformat_offset += 4;
2271 return start_offset;
2275 assert(is_ptr(type));
2277 offset = write_typeformatstring_var(file, indent, func, type->ref, var, typeformat_offset);
2278 if (file)
2279 fprintf(file, "/* %2u */\n", *typeformat_offset);
2280 return write_pointer_only_tfs(file, var->attrs, type->type,
2281 !last_ptr(type) ? 0x10 : 0,
2282 offset, typeformat_offset);
2285 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
2286 const char *name, int write_ptr, unsigned int *tfsoff)
2288 int retmask = 0;
2290 if (is_user_type(type))
2292 write_user_tfs(file, type, tfsoff);
2294 else if (is_string_type(attrs, type))
2296 write_string_tfs(file, attrs, type, name, tfsoff);
2298 else if (is_ptr(type))
2300 type_t *ref = type->ref;
2302 if (ref->type == RPC_FC_IP
2303 || (ref->type == 0
2304 && is_attr(attrs, ATTR_IIDIS)))
2306 write_ip_tfs(file, attrs, type, tfsoff);
2308 else
2310 if (!processed(ref) && !is_base_type(ref->type))
2311 retmask |= write_embedded_types(file, NULL, ref, name, TRUE, tfsoff);
2313 if (write_ptr)
2314 write_pointer_tfs(file, type, tfsoff);
2316 retmask |= 1;
2319 else if (type->declarray && is_conformant_array(type))
2320 ; /* conformant arrays and strings are handled specially */
2321 else if (is_array(type))
2323 write_array_tfs(file, attrs, type, name, tfsoff);
2324 if (is_conformant_array(type))
2325 retmask |= 1;
2327 else if (is_struct(type->type))
2329 if (!processed(type))
2330 write_struct_tfs(file, type, name, tfsoff);
2332 else if (is_union(type->type))
2334 if (!processed(type))
2335 write_union_tfs(file, type, tfsoff);
2337 else if (!is_base_type(type->type))
2338 error("write_embedded_types: unknown embedded type for %s (0x%x)\n",
2339 name, type->type);
2341 return retmask;
2344 static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
2346 const var_t *var;
2347 const ifref_t *iface;
2348 unsigned int typeformat_offset = 2;
2350 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
2352 if (!pred(iface->iface))
2353 continue;
2355 if (iface->iface->funcs)
2357 const func_t *func;
2358 current_iface = iface;
2359 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
2361 if (is_local(func->def->attrs)) continue;
2363 if (!is_void(get_func_return_type(func)))
2365 var_t v = *func->def;
2366 v.type = get_func_return_type(func);
2367 update_tfsoff(get_func_return_type(func),
2368 write_typeformatstring_var(
2369 file, 2, NULL, get_func_return_type(func),
2370 &v, &typeformat_offset),
2371 file);
2374 current_func = func;
2375 if (func->args)
2376 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2377 update_tfsoff(
2378 var->type,
2379 write_typeformatstring_var(
2380 file, 2, func, var->type, var,
2381 &typeformat_offset),
2382 file);
2387 return typeformat_offset + 1;
2391 void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
2393 int indent = 0;
2395 print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
2396 print_file(file, indent, "{\n");
2397 indent++;
2398 print_file(file, indent, "0,\n");
2399 print_file(file, indent, "{\n");
2400 indent++;
2401 print_file(file, indent, "NdrFcShort(0x0),\n");
2403 set_all_tfswrite(TRUE);
2404 process_tfs(file, ifaces, pred);
2406 print_file(file, indent, "0x0\n");
2407 indent--;
2408 print_file(file, indent, "}\n");
2409 indent--;
2410 print_file(file, indent, "};\n");
2411 print_file(file, indent, "\n");
2414 static unsigned int get_required_buffer_size_type(
2415 const type_t *type, const char *name, unsigned int *alignment)
2417 *alignment = 0;
2418 if (is_user_type(type))
2420 const char *uname;
2421 const type_t *utype = get_user_type(type, &uname);
2422 return get_required_buffer_size_type(utype, uname, alignment);
2424 else
2426 switch (type->type)
2428 case RPC_FC_BYTE:
2429 case RPC_FC_CHAR:
2430 case RPC_FC_USMALL:
2431 case RPC_FC_SMALL:
2432 *alignment = 4;
2433 return 1;
2435 case RPC_FC_WCHAR:
2436 case RPC_FC_USHORT:
2437 case RPC_FC_SHORT:
2438 case RPC_FC_ENUM16:
2439 *alignment = 4;
2440 return 2;
2442 case RPC_FC_ULONG:
2443 case RPC_FC_LONG:
2444 case RPC_FC_ENUM32:
2445 case RPC_FC_FLOAT:
2446 case RPC_FC_ERROR_STATUS_T:
2447 *alignment = 4;
2448 return 4;
2450 case RPC_FC_HYPER:
2451 case RPC_FC_DOUBLE:
2452 *alignment = 8;
2453 return 8;
2455 case RPC_FC_IGNORE:
2456 case RPC_FC_BIND_PRIMITIVE:
2457 return 0;
2459 case RPC_FC_STRUCT:
2460 case RPC_FC_PSTRUCT:
2462 size_t size = 0;
2463 const var_t *field;
2464 if (!type->fields_or_args) return 0;
2465 LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
2467 unsigned int alignment;
2468 size += get_required_buffer_size_type(field->type, field->name,
2469 &alignment);
2471 return size;
2474 case RPC_FC_RP:
2475 return
2476 is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT
2477 ? get_required_buffer_size_type( type->ref, name, alignment )
2478 : 0;
2480 case RPC_FC_SMFARRAY:
2481 case RPC_FC_LGFARRAY:
2482 return type->dim * get_required_buffer_size_type(type->ref, name, alignment);
2484 default:
2485 return 0;
2490 static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
2492 int in_attr = is_attr(var->attrs, ATTR_IN);
2493 int out_attr = is_attr(var->attrs, ATTR_OUT);
2494 const type_t *t;
2496 if (!in_attr && !out_attr)
2497 in_attr = 1;
2499 *alignment = 0;
2501 for (t = var->type; is_ptr(t); t = t->ref)
2502 if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
2504 *alignment = 4;
2505 return 20;
2508 if (pass == PASS_OUT)
2510 if (out_attr && is_ptr(var->type))
2512 type_t *type = var->type;
2514 if (type->type == RPC_FC_STRUCT)
2516 const var_t *field;
2517 unsigned int size = 36;
2519 if (!type->fields_or_args) return size;
2520 LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
2522 unsigned int align;
2523 size += get_required_buffer_size_type(
2524 field->type, field->name, &align);
2526 return size;
2529 return 0;
2531 else
2533 if ((!out_attr || in_attr) && !var->type->size_is
2534 && !is_attr(var->attrs, ATTR_STRING) && !var->type->declarray)
2536 if (is_ptr(var->type))
2538 type_t *type = var->type;
2540 if (is_base_type(type->type))
2542 return 25;
2544 else if (type->type == RPC_FC_STRUCT)
2546 unsigned int size = 36;
2547 const var_t *field;
2549 if (!type->fields_or_args) return size;
2550 LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
2552 unsigned int align;
2553 size += get_required_buffer_size_type(
2554 field->type, field->name, &align);
2556 return size;
2561 return get_required_buffer_size_type(var->type, var->name, alignment);
2565 static unsigned int get_function_buffer_size( const func_t *func, enum pass pass )
2567 const var_t *var;
2568 unsigned int total_size = 0, alignment;
2570 if (func->args)
2572 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2574 total_size += get_required_buffer_size(var, &alignment, pass);
2575 total_size += alignment;
2579 if (pass == PASS_OUT && !is_void(get_func_return_type(func)))
2581 var_t v = *func->def;
2582 v.type = get_func_return_type(func);
2583 total_size += get_required_buffer_size(&v, &alignment, PASS_RETURN);
2584 total_size += alignment;
2586 return total_size;
2589 static void print_phase_function(FILE *file, int indent, const char *type,
2590 enum remoting_phase phase,
2591 const var_t *var, unsigned int type_offset)
2593 const char *function;
2594 switch (phase)
2596 case PHASE_BUFFERSIZE:
2597 function = "BufferSize";
2598 break;
2599 case PHASE_MARSHAL:
2600 function = "Marshall";
2601 break;
2602 case PHASE_UNMARSHAL:
2603 function = "Unmarshall";
2604 break;
2605 case PHASE_FREE:
2606 function = "Free";
2607 break;
2608 default:
2609 assert(0);
2610 return;
2613 print_file(file, indent, "Ndr%s%s(\n", type, function);
2614 indent++;
2615 print_file(file, indent, "&_StubMsg,\n");
2616 print_file(file, indent, "%s%s%s%s,\n",
2617 (phase == PHASE_UNMARSHAL) ? "(unsigned char **)" : "(unsigned char *)",
2618 (phase == PHASE_UNMARSHAL || decl_indirect(var->type)) ? "&" : "",
2619 (phase == PHASE_UNMARSHAL && decl_indirect(var->type)) ? "_p_" : "",
2620 var->name);
2621 print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
2622 type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
2623 if (phase == PHASE_UNMARSHAL)
2624 print_file(file, indent, "0);\n");
2625 indent--;
2628 void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
2629 enum pass pass, const var_t *var,
2630 const char *varname)
2632 type_t *type = var->type;
2633 unsigned int size;
2634 unsigned int alignment = 0;
2635 unsigned char rtype;
2637 /* no work to do for other phases, buffer sizing is done elsewhere */
2638 if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
2639 return;
2641 rtype = is_ptr(type) ? type->ref->type : type->type;
2643 switch (rtype)
2645 case RPC_FC_BYTE:
2646 case RPC_FC_CHAR:
2647 case RPC_FC_SMALL:
2648 case RPC_FC_USMALL:
2649 size = 1;
2650 alignment = 1;
2651 break;
2653 case RPC_FC_WCHAR:
2654 case RPC_FC_USHORT:
2655 case RPC_FC_SHORT:
2656 case RPC_FC_ENUM16:
2657 size = 2;
2658 alignment = 2;
2659 break;
2661 case RPC_FC_ULONG:
2662 case RPC_FC_LONG:
2663 case RPC_FC_ENUM32:
2664 case RPC_FC_FLOAT:
2665 case RPC_FC_ERROR_STATUS_T:
2666 size = 4;
2667 alignment = 4;
2668 break;
2670 case RPC_FC_HYPER:
2671 case RPC_FC_DOUBLE:
2672 size = 8;
2673 alignment = 8;
2674 break;
2676 case RPC_FC_IGNORE:
2677 case RPC_FC_BIND_PRIMITIVE:
2678 /* no marshalling needed */
2679 return;
2681 default:
2682 error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, rtype);
2683 size = 0;
2686 if (phase == PHASE_MARSHAL)
2687 print_file(file, indent, "MIDL_memset(_StubMsg.Buffer, 0, (0x%x - (long)_StubMsg.Buffer) & 0x%x);\n", alignment, alignment - 1);
2688 print_file(file, indent, "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
2689 alignment - 1, alignment - 1);
2691 if (phase == PHASE_MARSHAL)
2693 print_file(file, indent, "*(");
2694 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2695 if (is_ptr(type))
2696 fprintf(file, " *)_StubMsg.Buffer = *");
2697 else
2698 fprintf(file, " *)_StubMsg.Buffer = ");
2699 fprintf(file, "%s", varname);
2700 fprintf(file, ";\n");
2702 else if (phase == PHASE_UNMARSHAL)
2704 print_file(file, indent, "if (_StubMsg.Buffer + sizeof(");
2705 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2706 fprintf(file, ") > _StubMsg.BufferEnd)\n");
2707 print_file(file, indent, "{\n");
2708 print_file(file, indent + 1, "RpcRaiseException(RPC_X_BAD_STUB_DATA);\n");
2709 print_file(file, indent, "}\n");
2710 if (pass == PASS_IN || pass == PASS_RETURN)
2711 print_file(file, indent, "");
2712 else
2713 print_file(file, indent, "*");
2714 fprintf(file, "%s", varname);
2715 if (pass == PASS_IN && is_ptr(type))
2716 fprintf(file, " = (");
2717 else
2718 fprintf(file, " = *(");
2719 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2720 fprintf(file, " *)_StubMsg.Buffer;\n");
2723 print_file(file, indent, "_StubMsg.Buffer += sizeof(");
2724 write_type_decl(file, var->type, NULL);
2725 fprintf(file, ");\n");
2728 /* returns whether the MaxCount, Offset or ActualCount members need to be
2729 * filled in for the specified phase */
2730 static inline int is_size_needed_for_phase(enum remoting_phase phase)
2732 return (phase != PHASE_UNMARSHAL);
2735 expr_t *get_size_is_expr(const type_t *t, const char *name)
2737 expr_t *x = NULL;
2739 for ( ; is_ptr(t) || is_array(t); t = t->ref)
2740 if (t->size_is)
2742 if (!x)
2743 x = t->size_is;
2744 else
2745 error("%s: multidimensional conformant"
2746 " arrays not supported at the top level\n",
2747 name);
2750 return x;
2753 static void write_remoting_arg(FILE *file, int indent, const func_t *func,
2754 enum pass pass, enum remoting_phase phase,
2755 const var_t *var)
2757 int in_attr, out_attr, pointer_type;
2758 const type_t *type = var->type;
2759 unsigned char rtype;
2760 size_t start_offset = type->typestring_offset;
2762 pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2763 if (!pointer_type)
2764 pointer_type = RPC_FC_RP;
2766 in_attr = is_attr(var->attrs, ATTR_IN);
2767 out_attr = is_attr(var->attrs, ATTR_OUT);
2768 if (!in_attr && !out_attr)
2769 in_attr = 1;
2771 if (phase != PHASE_FREE)
2772 switch (pass)
2774 case PASS_IN:
2775 if (!in_attr) return;
2776 break;
2777 case PASS_OUT:
2778 if (!out_attr) return;
2779 break;
2780 case PASS_RETURN:
2781 break;
2784 rtype = type->type;
2786 if (is_context_handle(type))
2788 if (phase == PHASE_MARSHAL)
2790 if (pass == PASS_IN)
2792 /* if the context_handle attribute appears in the chain of types
2793 * without pointers being followed, then the context handle must
2794 * be direct, otherwise it is a pointer */
2795 int is_ch_ptr = is_aliaschain_attr(type, ATTR_CONTEXTHANDLE) ? FALSE : TRUE;
2796 print_file(file, indent, "NdrClientContextMarshall(\n");
2797 print_file(file, indent + 1, "&_StubMsg,\n");
2798 print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ch_ptr ? "*" : "", var->name);
2799 print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
2801 else
2803 print_file(file, indent, "NdrServerContextNewMarshall(\n");
2804 print_file(file, indent + 1, "&_StubMsg,\n");
2805 print_file(file, indent + 1, "(NDR_SCONTEXT)%s,\n", var->name);
2806 print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown,\n", get_context_handle_type_name(var->type));
2807 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2810 else if (phase == PHASE_UNMARSHAL)
2812 if (pass == PASS_OUT)
2814 if (!in_attr)
2815 print_file(file, indent, "*%s = 0;\n", var->name);
2816 print_file(file, indent, "NdrClientContextUnmarshall(\n");
2817 print_file(file, indent + 1, "&_StubMsg,\n");
2818 print_file(file, indent + 1, "(NDR_CCONTEXT *)%s,\n", var->name);
2819 print_file(file, indent + 1, "_Handle);\n");
2821 else
2823 print_file(file, indent, "%s = NdrServerContextNewUnmarshall(\n", var->name);
2824 print_file(file, indent + 1, "&_StubMsg,\n");
2825 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2829 else if (is_user_type(var->type))
2831 print_phase_function(file, indent, "UserMarshal", phase, var, start_offset);
2833 else if (is_string_type(var->attrs, var->type))
2835 if (is_array(type) && !is_conformant_array(type))
2836 print_phase_function(file, indent, "NonConformantString", phase, var, start_offset);
2837 else
2839 if (type->size_is && is_size_needed_for_phase(phase))
2841 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2842 write_expr(file, type->size_is, 1);
2843 fprintf(file, ";\n");
2846 if (phase == PHASE_FREE || pass == PASS_RETURN || pointer_type == RPC_FC_UP)
2847 print_phase_function(file, indent, "Pointer", phase, var,
2848 start_offset - (type->size_is ? 4 : 2));
2849 else
2850 print_phase_function(file, indent, "ConformantString", phase, var,
2851 start_offset);
2854 else if (is_array(type))
2856 unsigned char tc = type->type;
2857 const char *array_type = "FixedArray";
2859 /* We already have the size_is expression since it's at the
2860 top level, but do checks for multidimensional conformant
2861 arrays. When we handle them, we'll need to extend this
2862 function to return a list, and then we'll actually use
2863 the return value. */
2864 get_size_is_expr(type, var->name);
2866 if (tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY)
2868 if (is_size_needed_for_phase(phase))
2870 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2871 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2872 write_expr(file, type->length_is, 1);
2873 fprintf(file, ";\n\n");
2875 array_type = "VaryingArray";
2877 else if (tc == RPC_FC_CARRAY)
2879 if (is_size_needed_for_phase(phase))
2881 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2882 write_expr(file, type->size_is, 1);
2883 fprintf(file, ";\n\n");
2885 array_type = "ConformantArray";
2887 else if (tc == RPC_FC_CVARRAY || tc == RPC_FC_BOGUS_ARRAY)
2889 if (is_size_needed_for_phase(phase))
2891 if (type->size_is)
2893 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2894 write_expr(file, type->size_is, 1);
2895 fprintf(file, ";\n");
2897 if (type->length_is)
2899 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2900 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2901 write_expr(file, type->length_is, 1);
2902 fprintf(file, ";\n\n");
2905 array_type = (tc == RPC_FC_BOGUS_ARRAY
2906 ? "ComplexArray"
2907 : "ConformantVaryingArray");
2910 if (pointer_type != RPC_FC_RP) array_type = "Pointer";
2911 print_phase_function(file, indent, array_type, phase, var, start_offset);
2912 if (phase == PHASE_FREE && pointer_type == RPC_FC_RP)
2914 /* these are all unmarshalled by allocating memory */
2915 if (type->type == RPC_FC_BOGUS_ARRAY ||
2916 type->type == RPC_FC_CVARRAY ||
2917 ((type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY) && in_attr) ||
2918 (type->type == RPC_FC_CARRAY && !in_attr))
2920 print_file(file, indent, "if (%s)\n", var->name);
2921 indent++;
2922 print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
2926 else if (!is_ptr(var->type) && is_base_type(rtype))
2928 if (phase != PHASE_FREE)
2929 print_phase_basetype(file, indent, phase, pass, var, var->name);
2931 else if (!is_ptr(var->type))
2933 switch (rtype)
2935 case RPC_FC_STRUCT:
2936 case RPC_FC_PSTRUCT:
2937 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset);
2938 break;
2939 case RPC_FC_CSTRUCT:
2940 case RPC_FC_CPSTRUCT:
2941 print_phase_function(file, indent, "ConformantStruct", phase, var, start_offset);
2942 break;
2943 case RPC_FC_CVSTRUCT:
2944 print_phase_function(file, indent, "ConformantVaryingStruct", phase, var, start_offset);
2945 break;
2946 case RPC_FC_BOGUS_STRUCT:
2947 print_phase_function(file, indent, "ComplexStruct", phase, var, start_offset);
2948 break;
2949 case RPC_FC_RP:
2950 if (is_base_type( var->type->ref->type ))
2952 print_phase_basetype(file, indent, phase, pass, var, var->name);
2954 else if (var->type->ref->type == RPC_FC_STRUCT)
2956 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2957 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
2959 else
2961 expr_t *iid;
2962 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2964 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2965 write_expr( file, iid, 1 );
2966 fprintf( file, ";\n\n" );
2968 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
2970 break;
2971 default:
2972 error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype);
2975 else
2977 if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
2979 if (phase != PHASE_FREE)
2980 print_phase_basetype(file, indent, phase, pass, var, var->name);
2982 else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
2984 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2985 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
2987 else
2989 expr_t *iid;
2990 expr_t *sx = get_size_is_expr(type, var->name);
2992 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2994 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2995 write_expr( file, iid, 1 );
2996 fprintf( file, ";\n\n" );
2998 else if (sx)
3000 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long) ");
3001 write_expr(file, sx, 1);
3002 fprintf(file, ";\n\n");
3004 if (var->type->ref->type == RPC_FC_IP)
3005 print_phase_function(file, indent, "InterfacePointer", phase, var, start_offset);
3006 else
3007 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
3010 fprintf(file, "\n");
3013 void write_remoting_arguments(FILE *file, int indent, const func_t *func,
3014 enum pass pass, enum remoting_phase phase)
3016 if (phase == PHASE_BUFFERSIZE && pass != PASS_RETURN)
3018 unsigned int size = get_function_buffer_size( func, pass );
3019 print_file(file, indent, "_StubMsg.BufferLength = %u;\n", size);
3022 if (pass == PASS_RETURN)
3024 var_t var;
3025 var = *func->def;
3026 var.type = get_func_return_type(func);
3027 var.name = xstrdup( "_RetVal" );
3028 write_remoting_arg( file, indent, func, pass, phase, &var );
3029 free( var.name );
3031 else
3033 const var_t *var;
3034 if (!func->args)
3035 return;
3036 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3037 write_remoting_arg( file, indent, func, pass, phase, var );
3042 size_t get_size_procformatstring_type(const char *name, const type_t *type, const attr_list_t *attrs)
3044 return write_procformatstring_type(NULL, 0, name, type, attrs, FALSE);
3048 size_t get_size_procformatstring_func(const func_t *func)
3050 const var_t *var;
3051 size_t size = 0;
3053 /* argument list size */
3054 if (func->args)
3055 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3056 size += get_size_procformatstring_type(var->name, var->type, var->attrs);
3058 /* return value size */
3059 if (is_void(get_func_return_type(func)))
3060 size += 2; /* FC_END and FC_PAD */
3061 else
3062 size += get_size_procformatstring_type("return value", get_func_return_type(func), NULL);
3064 return size;
3067 size_t get_size_procformatstring(const ifref_list_t *ifaces, type_pred_t pred)
3069 const ifref_t *iface;
3070 size_t size = 1;
3071 const func_t *func;
3073 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
3075 if (!pred(iface->iface))
3076 continue;
3078 if (iface->iface->funcs)
3079 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
3080 if (!is_local(func->def->attrs))
3081 size += get_size_procformatstring_func( func );
3083 return size;
3086 size_t get_size_typeformatstring(const ifref_list_t *ifaces, type_pred_t pred)
3088 set_all_tfswrite(FALSE);
3089 return process_tfs(NULL, ifaces, pred);
3092 static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
3093 const var_list_t *fields, const char *structvar)
3095 switch (e->type) {
3096 case EXPR_VOID:
3097 break;
3098 case EXPR_NUM:
3099 fprintf(h, "%lu", e->u.lval);
3100 break;
3101 case EXPR_HEXNUM:
3102 fprintf(h, "0x%lx", e->u.lval);
3103 break;
3104 case EXPR_DOUBLE:
3105 fprintf(h, "%#.15g", e->u.dval);
3106 break;
3107 case EXPR_TRUEFALSE:
3108 if (e->u.lval == 0)
3109 fprintf(h, "FALSE");
3110 else
3111 fprintf(h, "TRUE");
3112 break;
3113 case EXPR_IDENTIFIER:
3115 const var_t *field;
3116 LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
3117 if (!strcmp(e->u.sval, field->name))
3119 fprintf(h, "%s->%s", structvar, e->u.sval);
3120 break;
3123 if (&field->entry == fields) error("no field found for identifier %s\n", e->u.sval);
3124 break;
3126 case EXPR_NEG:
3127 fprintf(h, "-");
3128 write_struct_expr(h, e->ref, 1, fields, structvar);
3129 break;
3130 case EXPR_NOT:
3131 fprintf(h, "~");
3132 write_struct_expr(h, e->ref, 1, fields, structvar);
3133 break;
3134 case EXPR_PPTR:
3135 fprintf(h, "*");
3136 write_struct_expr(h, e->ref, 1, fields, structvar);
3137 break;
3138 case EXPR_CAST:
3139 fprintf(h, "(");
3140 write_type_decl(h, e->u.tref, NULL);
3141 fprintf(h, ")");
3142 write_struct_expr(h, e->ref, 1, fields, structvar);
3143 break;
3144 case EXPR_SIZEOF:
3145 fprintf(h, "sizeof(");
3146 write_type_decl(h, e->u.tref, NULL);
3147 fprintf(h, ")");
3148 break;
3149 case EXPR_SHL:
3150 case EXPR_SHR:
3151 case EXPR_MUL:
3152 case EXPR_DIV:
3153 case EXPR_ADD:
3154 case EXPR_SUB:
3155 case EXPR_AND:
3156 case EXPR_OR:
3157 case EXPR_MEMBERPTR:
3158 case EXPR_MEMBER:
3159 if (brackets) fprintf(h, "(");
3160 write_struct_expr(h, e->ref, 1, fields, structvar);
3161 switch (e->type) {
3162 case EXPR_SHL: fprintf(h, " << "); break;
3163 case EXPR_SHR: fprintf(h, " >> "); break;
3164 case EXPR_MUL: fprintf(h, " * "); break;
3165 case EXPR_DIV: fprintf(h, " / "); break;
3166 case EXPR_ADD: fprintf(h, " + "); break;
3167 case EXPR_SUB: fprintf(h, " - "); break;
3168 case EXPR_AND: fprintf(h, " & "); break;
3169 case EXPR_OR: fprintf(h, " | "); break;
3170 case EXPR_MEMBERPTR: fprintf(h, "->"); break;
3171 case EXPR_MEMBER: fprintf(h, "."); break;
3172 default: break;
3174 write_struct_expr(h, e->u.ext, 1, fields, structvar);
3175 if (brackets) fprintf(h, ")");
3176 break;
3177 case EXPR_COND:
3178 if (brackets) fprintf(h, "(");
3179 write_struct_expr(h, e->ref, 1, fields, structvar);
3180 fprintf(h, " ? ");
3181 write_struct_expr(h, e->u.ext, 1, fields, structvar);
3182 fprintf(h, " : ");
3183 write_struct_expr(h, e->ext2, 1, fields, structvar);
3184 if (brackets) fprintf(h, ")");
3185 break;
3186 case EXPR_ADDRESSOF:
3187 fprintf(h, "&");
3188 write_struct_expr(h, e->ref, 1, fields, structvar);
3189 break;
3190 case EXPR_ARRAY:
3191 if (brackets) fprintf(h, "(");
3192 write_struct_expr(h, e->ref, 1, fields, structvar);
3193 fprintf(h, "[");
3194 write_struct_expr(h, e->u.ext, 1, fields, structvar);
3195 fprintf(h, "]");
3196 if (brackets) fprintf(h, ")");
3197 break;
3202 void declare_stub_args( FILE *file, int indent, const func_t *func )
3204 int in_attr, out_attr;
3205 int i = 0;
3206 const var_t *var;
3208 /* declare return value '_RetVal' */
3209 if (!is_void(get_func_return_type(func)))
3211 print_file(file, indent, "");
3212 write_type_decl_left(file, get_func_return_type(func));
3213 fprintf(file, " _RetVal;\n");
3216 if (!func->args)
3217 return;
3219 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3221 int is_string = is_attr(var->attrs, ATTR_STRING);
3223 in_attr = is_attr(var->attrs, ATTR_IN);
3224 out_attr = is_attr(var->attrs, ATTR_OUT);
3225 if (!out_attr && !in_attr)
3226 in_attr = 1;
3228 if (is_context_handle(var->type))
3229 print_file(file, indent, "NDR_SCONTEXT %s;\n", var->name);
3230 else
3232 if (!in_attr && !var->type->size_is && !is_string)
3234 print_file(file, indent, "");
3235 write_type_decl(file, var->type->declarray ? var->type : var->type->ref,
3236 "_W%u", i++);
3237 fprintf(file, ";\n");
3240 print_file(file, indent, "");
3241 write_type_decl_left(file, var->type);
3242 fprintf(file, " ");
3243 if (var->type->declarray) {
3244 fprintf(file, "( *");
3245 write_name(file, var);
3246 fprintf(file, " )");
3247 } else
3248 write_name(file, var);
3249 write_type_right(file, var->type, FALSE);
3250 fprintf(file, ";\n");
3252 if (decl_indirect(var->type))
3253 print_file(file, indent, "void *_p_%s = &%s;\n",
3254 var->name, var->name);
3260 void assign_stub_out_args( FILE *file, int indent, const func_t *func )
3262 int in_attr, out_attr;
3263 int i = 0, sep = 0;
3264 const var_t *var;
3266 if (!func->args)
3267 return;
3269 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3271 int is_string = is_attr(var->attrs, ATTR_STRING);
3272 in_attr = is_attr(var->attrs, ATTR_IN);
3273 out_attr = is_attr(var->attrs, ATTR_OUT);
3274 if (!out_attr && !in_attr)
3275 in_attr = 1;
3277 if (!in_attr)
3279 print_file(file, indent, "");
3280 write_name(file, var);
3282 if (is_context_handle(var->type))
3284 fprintf(file, " = NdrContextHandleInitialize(\n");
3285 print_file(file, indent + 1, "&_StubMsg,\n");
3286 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n",
3287 var->type->typestring_offset);
3289 else if (var->type->size_is)
3291 unsigned int size, align = 0;
3292 type_t *type = var->type;
3294 fprintf(file, " = NdrAllocate(&_StubMsg, ");
3295 for ( ; type->size_is ; type = type->ref)
3297 write_expr(file, type->size_is, TRUE);
3298 fprintf(file, " * ");
3300 size = type_memsize(type, &align);
3301 fprintf(file, "%u);\n", size);
3303 else if (!is_string)
3305 fprintf(file, " = &_W%u;\n", i);
3306 if (is_ptr(var->type) && !last_ptr(var->type))
3307 print_file(file, indent, "_W%u = 0;\n", i);
3308 i++;
3311 sep = 1;
3314 if (sep)
3315 fprintf(file, "\n");
3319 int write_expr_eval_routines(FILE *file, const char *iface)
3321 static const char *var_name = "pS";
3322 int result = 0;
3323 struct expr_eval_routine *eval;
3324 unsigned short callback_offset = 0;
3326 LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
3328 const char *name = eval->structure->name;
3329 const var_list_t *fields = eval->structure->fields_or_args;
3330 result = 1;
3332 print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
3333 iface, name, callback_offset);
3334 print_file(file, 0, "{\n");
3335 print_file (file, 1, "%s *%s = (%s *)(pStubMsg->StackTop - %u);\n",
3336 name, var_name, name, eval->baseoff);
3337 print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */
3338 print_file(file, 1, "pStubMsg->MaxCount = (unsigned long)");
3339 write_struct_expr(file, eval->expr, 1, fields, var_name);
3340 fprintf(file, ";\n");
3341 print_file(file, 0, "}\n\n");
3342 callback_offset++;
3344 return result;
3347 void write_expr_eval_routine_list(FILE *file, const char *iface)
3349 struct expr_eval_routine *eval;
3350 struct expr_eval_routine *cursor;
3351 unsigned short callback_offset = 0;
3353 fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
3354 fprintf(file, "{\n");
3356 LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
3358 const char *name = eval->structure->name;
3359 print_file(file, 1, "%s_%sExprEval_%04u,\n", iface, name, callback_offset);
3360 callback_offset++;
3361 list_remove(&eval->entry);
3362 free(eval);
3365 fprintf(file, "};\n\n");
3368 void write_user_quad_list(FILE *file)
3370 user_type_t *ut;
3372 if (list_empty(&user_type_list))
3373 return;
3375 fprintf(file, "static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[] =\n");
3376 fprintf(file, "{\n");
3377 LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
3379 const char *sep = &ut->entry == list_tail(&user_type_list) ? "" : ",";
3380 print_file(file, 1, "{\n");
3381 print_file(file, 2, "(USER_MARSHAL_SIZING_ROUTINE)%s_UserSize,\n", ut->name);
3382 print_file(file, 2, "(USER_MARSHAL_MARSHALLING_ROUTINE)%s_UserMarshal,\n", ut->name);
3383 print_file(file, 2, "(USER_MARSHAL_UNMARSHALLING_ROUTINE)%s_UserUnmarshal,\n", ut->name);
3384 print_file(file, 2, "(USER_MARSHAL_FREEING_ROUTINE)%s_UserFree\n", ut->name);
3385 print_file(file, 1, "}%s\n", sep);
3387 fprintf(file, "};\n\n");
3390 void write_endpoints( FILE *f, const char *prefix, const str_list_t *list )
3392 const struct str_list_entry_t *endpoint;
3393 const char *p;
3395 /* this should be an array of RPC_PROTSEQ_ENDPOINT but we want const strings */
3396 print_file( f, 0, "static const unsigned char * %s__RpcProtseqEndpoint[][2] =\n{\n", prefix );
3397 LIST_FOR_EACH_ENTRY( endpoint, list, const struct str_list_entry_t, entry )
3399 print_file( f, 1, "{ (const unsigned char *)\"" );
3400 for (p = endpoint->str; *p && *p != ':'; p++)
3402 if (*p == '"' || *p == '\\') fputc( '\\', f );
3403 fputc( *p, f );
3405 if (!*p) goto error;
3406 if (p[1] != '[') goto error;
3408 fprintf( f, "\", (const unsigned char *)\"" );
3409 for (p += 2; *p && *p != ']'; p++)
3411 if (*p == '"' || *p == '\\') fputc( '\\', f );
3412 fputc( *p, f );
3414 if (*p != ']') goto error;
3415 fprintf( f, "\" },\n" );
3417 print_file( f, 0, "};\n\n" );
3418 return;
3420 error:
3421 error("Invalid endpoint syntax '%s'\n", endpoint->str);