Sync to Wine-0.9.58
[reactos.git] / reactos / tools / widl / typegen.c
1 /*
2 * Format String Generator for IDL Compiler
3 *
4 * Copyright 2005-2006 Eric Kohl
5 * Copyright 2005-2006 Robert Shearman
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include "config.h"
23 #include "wine/port.h"
24
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>
34
35 #include "widl.h"
36 #include "utils.h"
37 #include "parser.h"
38 #include "header.h"
39 #include "wine/list.h"
40
41 #include "typegen.h"
42
43 static const func_t *current_func;
44 static const type_t *current_structure;
45 static const ifref_t *current_iface;
46
47 static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
48 struct expr_eval_routine
49 {
50 struct list entry;
51 const type_t *structure;
52 unsigned int baseoff;
53 const expr_t *expr;
54 };
55
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
62 const char *string_of_type(unsigned char type)
63 {
64 switch (type)
65 {
66 case RPC_FC_BYTE: return "FC_BYTE";
67 case RPC_FC_CHAR: return "FC_CHAR";
68 case RPC_FC_SMALL: return "FC_SMALL";
69 case RPC_FC_USMALL: return "FC_USMALL";
70 case RPC_FC_WCHAR: return "FC_WCHAR";
71 case RPC_FC_SHORT: return "FC_SHORT";
72 case RPC_FC_USHORT: return "FC_USHORT";
73 case RPC_FC_LONG: return "FC_LONG";
74 case RPC_FC_ULONG: return "FC_ULONG";
75 case RPC_FC_FLOAT: return "FC_FLOAT";
76 case RPC_FC_HYPER: return "FC_HYPER";
77 case RPC_FC_DOUBLE: return "FC_DOUBLE";
78 case RPC_FC_ENUM16: return "FC_ENUM16";
79 case RPC_FC_ENUM32: return "FC_ENUM32";
80 case RPC_FC_IGNORE: return "FC_IGNORE";
81 case RPC_FC_ERROR_STATUS_T: return "FC_ERROR_STATUS_T";
82 case RPC_FC_RP: return "FC_RP";
83 case RPC_FC_UP: return "FC_UP";
84 case RPC_FC_OP: return "FC_OP";
85 case RPC_FC_FP: return "FC_FP";
86 case RPC_FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION";
87 case RPC_FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION";
88 case RPC_FC_STRUCT: return "FC_STRUCT";
89 case RPC_FC_PSTRUCT: return "FC_PSTRUCT";
90 case RPC_FC_CSTRUCT: return "FC_CSTRUCT";
91 case RPC_FC_CPSTRUCT: return "FC_CPSTRUCT";
92 case RPC_FC_CVSTRUCT: return "FC_CVSTRUCT";
93 case RPC_FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT";
94 case RPC_FC_SMFARRAY: return "FC_SMFARRAY";
95 case RPC_FC_LGFARRAY: return "FC_LGFARRAY";
96 case RPC_FC_SMVARRAY: return "FC_SMVARRAY";
97 case RPC_FC_LGVARRAY: return "FC_LGVARRAY";
98 case RPC_FC_CARRAY: return "FC_CARRAY";
99 case RPC_FC_CVARRAY: return "FC_CVARRAY";
100 case RPC_FC_BOGUS_ARRAY: return "FC_BOGUS_ARRAY";
101 case RPC_FC_ALIGNM4: return "FC_ALIGNM4";
102 case RPC_FC_ALIGNM8: return "FC_ALIGNM8";
103 case RPC_FC_POINTER: return "FC_POINTER";
104 case RPC_FC_C_CSTRING: return "FC_C_CSTRING";
105 case RPC_FC_C_WSTRING: return "FC_C_WSTRING";
106 case RPC_FC_CSTRING: return "FC_CSTRING";
107 case RPC_FC_WSTRING: return "FC_WSTRING";
108 default:
109 error("string_of_type: unknown type 0x%02x\n", type);
110 return NULL;
111 }
112 }
113
114 int is_struct(unsigned char type)
115 {
116 switch (type)
117 {
118 case RPC_FC_STRUCT:
119 case RPC_FC_PSTRUCT:
120 case RPC_FC_CSTRUCT:
121 case RPC_FC_CPSTRUCT:
122 case RPC_FC_CVSTRUCT:
123 case RPC_FC_BOGUS_STRUCT:
124 return 1;
125 default:
126 return 0;
127 }
128 }
129
130 static int is_non_complex_struct(const type_t *type)
131 {
132 switch (type->type)
133 {
134 case RPC_FC_STRUCT:
135 case RPC_FC_PSTRUCT:
136 case RPC_FC_CSTRUCT:
137 case RPC_FC_CPSTRUCT:
138 case RPC_FC_CVSTRUCT:
139 return 1;
140 default:
141 return 0;
142 }
143 }
144
145 int is_union(unsigned char type)
146 {
147 switch (type)
148 {
149 case RPC_FC_ENCAPSULATED_UNION:
150 case RPC_FC_NON_ENCAPSULATED_UNION:
151 return 1;
152 default:
153 return 0;
154 }
155 }
156
157 static int type_has_pointers(const type_t *type)
158 {
159 if (is_user_type(type))
160 return FALSE;
161 else if (is_ptr(type))
162 return TRUE;
163 else if (is_array(type))
164 return type_has_pointers(type->ref);
165 else if (is_struct(type->type))
166 {
167 const var_t *field;
168 if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
169 {
170 if (type_has_pointers(field->type))
171 return TRUE;
172 }
173 }
174 else if (is_union(type->type))
175 {
176 var_list_t *fields;
177 const var_t *field;
178 if (type->type == RPC_FC_ENCAPSULATED_UNION)
179 {
180 const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
181 fields = uv->type->fields;
182 }
183 else
184 fields = type->fields;
185 if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
186 {
187 if (field->type && type_has_pointers(field->type))
188 return TRUE;
189 }
190 }
191
192 return FALSE;
193 }
194
195 static int type_has_full_pointer(const type_t *type)
196 {
197 if (is_user_type(type))
198 return FALSE;
199 else if (type->type == RPC_FC_FP)
200 return TRUE;
201 else if (is_ptr(type))
202 return FALSE;
203 else if (is_array(type))
204 return type_has_full_pointer(type->ref);
205 else if (is_struct(type->type))
206 {
207 const var_t *field;
208 if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
209 {
210 if (type_has_full_pointer(field->type))
211 return TRUE;
212 }
213 }
214 else if (is_union(type->type))
215 {
216 var_list_t *fields;
217 const var_t *field;
218 if (type->type == RPC_FC_ENCAPSULATED_UNION)
219 {
220 const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
221 fields = uv->type->fields;
222 }
223 else
224 fields = type->fields;
225 if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
226 {
227 if (field->type && type_has_full_pointer(field->type))
228 return TRUE;
229 }
230 }
231
232 return FALSE;
233 }
234
235 static unsigned short user_type_offset(const char *name)
236 {
237 user_type_t *ut;
238 unsigned short off = 0;
239 LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
240 {
241 if (strcmp(name, ut->name) == 0)
242 return off;
243 ++off;
244 }
245 error("user_type_offset: couldn't find type (%s)\n", name);
246 return 0;
247 }
248
249 static void update_tfsoff(type_t *type, unsigned int offset, FILE *file)
250 {
251 type->typestring_offset = offset;
252 if (file) type->tfswrite = FALSE;
253 }
254
255 static void guard_rec(type_t *type)
256 {
257 /* types that contain references to themselves (like a linked list),
258 need to be shielded from infinite recursion when writing embedded
259 types */
260 if (type->typestring_offset)
261 type->tfswrite = FALSE;
262 else
263 type->typestring_offset = 1;
264 }
265
266 static type_t *get_user_type(const type_t *t, const char **pname)
267 {
268 for (;;)
269 {
270 type_t *ut = get_attrp(t->attrs, ATTR_WIREMARSHAL);
271 if (ut)
272 {
273 if (pname)
274 *pname = t->name;
275 return ut;
276 }
277
278 if (t->kind == TKIND_ALIAS)
279 t = t->orig;
280 else
281 return 0;
282 }
283 }
284
285 int is_user_type(const type_t *t)
286 {
287 return get_user_type(t, NULL) != NULL;
288 }
289
290 static int is_embedded_complex(const type_t *type)
291 {
292 unsigned char tc = type->type;
293 return is_struct(tc) || is_union(tc) || is_array(type) || is_user_type(type)
294 || (is_ptr(type) && type->ref->type == RPC_FC_IP);
295 }
296
297 static const char *get_context_handle_type_name(const type_t *type)
298 {
299 const type_t *t;
300 for (t = type; is_ptr(t); t = t->ref)
301 if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
302 return t->name;
303 assert(0);
304 return NULL;
305 }
306
307 /* This is actually fairly involved to implement precisely, due to the
308 effects attributes may have and things like that. Right now this is
309 only used for optimization, so just check for a very small set of
310 criteria that guarantee the types are equivalent; assume every thing
311 else is different. */
312 static int compare_type(const type_t *a, const type_t *b)
313 {
314 if (a == b
315 || (a->name
316 && b->name
317 && strcmp(a->name, b->name) == 0))
318 return 0;
319 /* Ordering doesn't need to be implemented yet. */
320 return 1;
321 }
322
323 static int compare_expr(const expr_t *a, const expr_t *b)
324 {
325 int ret;
326
327 if (a->type != b->type)
328 return a->type - b->type;
329
330 switch (a->type)
331 {
332 case EXPR_NUM:
333 case EXPR_HEXNUM:
334 case EXPR_TRUEFALSE:
335 return a->u.lval - b->u.lval;
336 case EXPR_DOUBLE:
337 return a->u.dval - b->u.dval;
338 case EXPR_IDENTIFIER:
339 return strcmp(a->u.sval, b->u.sval);
340 case EXPR_COND:
341 ret = compare_expr(a->ref, b->ref);
342 if (ret != 0)
343 return ret;
344 ret = compare_expr(a->u.ext, b->u.ext);
345 if (ret != 0)
346 return ret;
347 return compare_expr(a->ext2, b->ext2);
348 case EXPR_OR:
349 case EXPR_AND:
350 case EXPR_ADD:
351 case EXPR_SUB:
352 case EXPR_MUL:
353 case EXPR_DIV:
354 case EXPR_SHL:
355 case EXPR_SHR:
356 ret = compare_expr(a->ref, b->ref);
357 if (ret != 0)
358 return ret;
359 return compare_expr(a->u.ext, b->u.ext);
360 case EXPR_CAST:
361 ret = compare_type(a->u.tref, b->u.tref);
362 if (ret != 0)
363 return ret;
364 /* Fall through. */
365 case EXPR_NOT:
366 case EXPR_NEG:
367 case EXPR_PPTR:
368 case EXPR_ADDRESSOF:
369 return compare_expr(a->ref, b->ref);
370 case EXPR_SIZEOF:
371 return compare_type(a->u.tref, b->u.tref);
372 case EXPR_VOID:
373 return 0;
374 }
375 return -1;
376 }
377
378 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
379 do { \
380 if (file) \
381 fprintf(file, "/* %2u */\n", typestring_offset); \
382 print_file((file), 2, "0x%02x, /* " #fctype " */\n", RPC_##fctype); \
383 } \
384 while (0)
385
386 static void print_file(FILE *file, int indent, const char *format, ...)
387 {
388 va_list va;
389 va_start(va, format);
390 print(file, indent, format, va);
391 va_end(va);
392 }
393
394 void print(FILE *file, int indent, const char *format, va_list va)
395 {
396 if (file)
397 {
398 if (format[0] != '\n')
399 while (0 < indent--)
400 fprintf(file, " ");
401 vfprintf(file, format, va);
402 }
403 }
404
405
406 static void write_var_init(FILE *file, int indent, const type_t *t, const char *n)
407 {
408 if (decl_indirect(t))
409 print_file(file, indent, "MIDL_memset(&%s, 0, sizeof(%s));\n", n, n);
410 else if (is_ptr(t) || is_array(t))
411 print_file(file, indent, "%s = 0;\n", n);
412 }
413
414 void write_parameters_init(FILE *file, int indent, const func_t *func)
415 {
416 const var_t *var;
417
418 if (!is_void(func->def->type))
419 write_var_init(file, indent, func->def->type, "_RetVal");
420
421 if (!func->args)
422 return;
423
424 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
425 write_var_init(file, indent, var->type, var->name);
426
427 fprintf(file, "\n");
428 }
429
430 static void write_formatdesc(FILE *f, int indent, const char *str)
431 {
432 print_file(f, indent, "typedef struct _MIDL_%s_FORMAT_STRING\n", str);
433 print_file(f, indent, "{\n");
434 print_file(f, indent + 1, "short Pad;\n");
435 print_file(f, indent + 1, "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str);
436 print_file(f, indent, "} MIDL_%s_FORMAT_STRING;\n", str);
437 print_file(f, indent, "\n");
438 }
439
440 void write_formatstringsdecl(FILE *f, int indent, ifref_list_t *ifaces, type_pred_t pred)
441 {
442 print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n",
443 get_size_typeformatstring(ifaces, pred));
444
445 print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n",
446 get_size_procformatstring(ifaces, pred));
447
448 fprintf(f, "\n");
449 write_formatdesc(f, indent, "TYPE");
450 write_formatdesc(f, indent, "PROC");
451 fprintf(f, "\n");
452 print_file(f, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n");
453 print_file(f, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n");
454 print_file(f, indent, "\n");
455 }
456
457 static inline int is_base_type(unsigned char type)
458 {
459 switch (type)
460 {
461 case RPC_FC_BYTE:
462 case RPC_FC_CHAR:
463 case RPC_FC_USMALL:
464 case RPC_FC_SMALL:
465 case RPC_FC_WCHAR:
466 case RPC_FC_USHORT:
467 case RPC_FC_SHORT:
468 case RPC_FC_ULONG:
469 case RPC_FC_LONG:
470 case RPC_FC_HYPER:
471 case RPC_FC_IGNORE:
472 case RPC_FC_FLOAT:
473 case RPC_FC_DOUBLE:
474 case RPC_FC_ENUM16:
475 case RPC_FC_ENUM32:
476 case RPC_FC_ERROR_STATUS_T:
477 case RPC_FC_BIND_PRIMITIVE:
478 return TRUE;
479
480 default:
481 return FALSE;
482 }
483 }
484
485 int decl_indirect(const type_t *t)
486 {
487 return is_user_type(t)
488 || (!is_base_type(t->type)
489 && !is_ptr(t)
490 && !is_array(t));
491 }
492
493 static size_t write_procformatstring_var(FILE *file, int indent,
494 const var_t *var, int is_return)
495 {
496 size_t size;
497 const type_t *type = var->type;
498
499 int is_in = is_attr(var->attrs, ATTR_IN);
500 int is_out = is_attr(var->attrs, ATTR_OUT);
501
502 if (!is_in && !is_out) is_in = TRUE;
503
504 if (!type->declarray && is_base_type(type->type))
505 {
506 if (is_return)
507 print_file(file, indent, "0x53, /* FC_RETURN_PARAM_BASETYPE */\n");
508 else
509 print_file(file, indent, "0x4e, /* FC_IN_PARAM_BASETYPE */\n");
510
511 if (type->type == RPC_FC_BIND_PRIMITIVE)
512 {
513 print_file(file, indent, "0x%02x, /* FC_IGNORE */\n", RPC_FC_IGNORE);
514 size = 2; /* includes param type prefix */
515 }
516 else if (is_base_type(type->type))
517 {
518 print_file(file, indent, "0x%02x, /* %s */\n", type->type, string_of_type(type->type));
519 size = 2; /* includes param type prefix */
520 }
521 else
522 {
523 error("Unknown/unsupported type: %s (0x%02x)\n", var->name, type->type);
524 size = 0;
525 }
526 }
527 else
528 {
529 if (is_return)
530 print_file(file, indent, "0x52, /* FC_RETURN_PARAM */\n");
531 else if (is_in && is_out)
532 print_file(file, indent, "0x50, /* FC_IN_OUT_PARAM */\n");
533 else if (is_out)
534 print_file(file, indent, "0x51, /* FC_OUT_PARAM */\n");
535 else
536 print_file(file, indent, "0x4d, /* FC_IN_PARAM */\n");
537
538 print_file(file, indent, "0x01,\n");
539 print_file(file, indent, "NdrFcShort(0x%x),\n", type->typestring_offset);
540 size = 4; /* includes param type prefix */
541 }
542 return size;
543 }
544
545 void write_procformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
546 {
547 const ifref_t *iface;
548 int indent = 0;
549 const var_t *var;
550
551 print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
552 print_file(file, indent, "{\n");
553 indent++;
554 print_file(file, indent, "0,\n");
555 print_file(file, indent, "{\n");
556 indent++;
557
558 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
559 {
560 if (!pred(iface->iface))
561 continue;
562
563 if (iface->iface->funcs)
564 {
565 const func_t *func;
566 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
567 {
568 if (is_local(func->def->attrs)) continue;
569 /* emit argument data */
570 if (func->args)
571 {
572 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
573 write_procformatstring_var(file, indent, var, FALSE);
574 }
575
576 /* emit return value data */
577 var = func->def;
578 if (is_void(var->type))
579 {
580 print_file(file, indent, "0x5b, /* FC_END */\n");
581 print_file(file, indent, "0x5c, /* FC_PAD */\n");
582 }
583 else
584 write_procformatstring_var(file, indent, var, TRUE);
585 }
586 }
587 }
588
589 print_file(file, indent, "0x0\n");
590 indent--;
591 print_file(file, indent, "}\n");
592 indent--;
593 print_file(file, indent, "};\n");
594 print_file(file, indent, "\n");
595 }
596
597 static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
598 {
599 if (is_base_type(type->type))
600 {
601 print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
602 *typestring_offset += 1;
603 return 1;
604 }
605
606 return 0;
607 }
608
609 /* write conformance / variance descriptor */
610 static size_t write_conf_or_var_desc(FILE *file, const type_t *structure,
611 unsigned int baseoff, const type_t *type,
612 const expr_t *expr)
613 {
614 unsigned char operator_type = 0;
615 unsigned char conftype = RPC_FC_NORMAL_CONFORMANCE;
616 const char *conftype_string = "";
617 const char *operator_string = "no operators";
618 const expr_t *subexpr;
619
620 if (!expr)
621 {
622 print_file(file, 2, "NdrFcLong(0xffffffff),\t/* -1 */\n");
623 return 4;
624 }
625
626 if (!structure)
627 {
628 /* Top-level conformance calculations are done inline. */
629 print_file (file, 2, "0x%x,\t/* Corr desc: parameter */\n",
630 RPC_FC_TOP_LEVEL_CONFORMANCE);
631 print_file (file, 2, "0x0,\n");
632 print_file (file, 2, "NdrFcShort(0x0),\n");
633 return 4;
634 }
635
636 if (expr->is_const)
637 {
638 if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
639 error("write_conf_or_var_desc: constant value %ld is greater than "
640 "the maximum constant size of %d\n", expr->cval,
641 UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
642
643 print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n",
644 RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
645 print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX);
646 print_file(file, 2, "NdrFcShort(0x%x),\n", expr->cval & USHRT_MAX);
647
648 return 4;
649 }
650
651 if (is_ptr(type) || (is_array(type) && !type->declarray))
652 {
653 conftype = RPC_FC_POINTER_CONFORMANCE;
654 conftype_string = "field pointer, ";
655 }
656
657 subexpr = expr;
658 switch (subexpr->type)
659 {
660 case EXPR_PPTR:
661 subexpr = subexpr->ref;
662 operator_type = RPC_FC_DEREFERENCE;
663 operator_string = "FC_DEREFERENCE";
664 break;
665 case EXPR_DIV:
666 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
667 {
668 subexpr = subexpr->ref;
669 operator_type = RPC_FC_DIV_2;
670 operator_string = "FC_DIV_2";
671 }
672 break;
673 case EXPR_MUL:
674 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
675 {
676 subexpr = subexpr->ref;
677 operator_type = RPC_FC_MULT_2;
678 operator_string = "FC_MULT_2";
679 }
680 break;
681 case EXPR_SUB:
682 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
683 {
684 subexpr = subexpr->ref;
685 operator_type = RPC_FC_SUB_1;
686 operator_string = "FC_SUB_1";
687 }
688 break;
689 case EXPR_ADD:
690 if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
691 {
692 subexpr = subexpr->ref;
693 operator_type = RPC_FC_ADD_1;
694 operator_string = "FC_ADD_1";
695 }
696 break;
697 default:
698 break;
699 }
700
701 if (subexpr->type == EXPR_IDENTIFIER)
702 {
703 const type_t *correlation_variable = NULL;
704 unsigned char correlation_variable_type;
705 unsigned char param_type = 0;
706 size_t offset = 0;
707 const var_t *var;
708
709 if (structure->fields) LIST_FOR_EACH_ENTRY( var, structure->fields, const var_t, entry )
710 {
711 unsigned int align = 0;
712 /* FIXME: take alignment into account */
713 if (var->name && !strcmp(var->name, subexpr->u.sval))
714 {
715 correlation_variable = var->type;
716 break;
717 }
718 offset += type_memsize(var->type, &align);
719 }
720 if (!correlation_variable)
721 error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
722 subexpr->u.sval);
723
724 offset -= baseoff;
725 correlation_variable_type = correlation_variable->type;
726
727 switch (correlation_variable_type)
728 {
729 case RPC_FC_CHAR:
730 case RPC_FC_SMALL:
731 param_type = RPC_FC_SMALL;
732 break;
733 case RPC_FC_BYTE:
734 case RPC_FC_USMALL:
735 param_type = RPC_FC_USMALL;
736 break;
737 case RPC_FC_WCHAR:
738 case RPC_FC_SHORT:
739 case RPC_FC_ENUM16:
740 param_type = RPC_FC_SHORT;
741 break;
742 case RPC_FC_USHORT:
743 param_type = RPC_FC_USHORT;
744 break;
745 case RPC_FC_LONG:
746 case RPC_FC_ENUM32:
747 param_type = RPC_FC_LONG;
748 break;
749 case RPC_FC_ULONG:
750 param_type = RPC_FC_ULONG;
751 break;
752 case RPC_FC_RP:
753 case RPC_FC_UP:
754 case RPC_FC_OP:
755 case RPC_FC_FP:
756 if (sizeof(void *) == 4) /* FIXME */
757 param_type = RPC_FC_LONG;
758 else
759 param_type = RPC_FC_HYPER;
760 break;
761 default:
762 error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
763 correlation_variable_type);
764 }
765
766 print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
767 conftype | param_type, conftype_string, string_of_type(param_type));
768 print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string);
769 print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d */\n",
770 offset, offset);
771 }
772 else
773 {
774 unsigned int callback_offset = 0;
775 struct expr_eval_routine *eval;
776 int found = 0;
777
778 LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
779 {
780 if (!strcmp (eval->structure->name, structure->name)
781 && !compare_expr (eval->expr, expr))
782 {
783 found = 1;
784 break;
785 }
786 callback_offset++;
787 }
788
789 if (!found)
790 {
791 eval = xmalloc (sizeof(*eval));
792 eval->structure = structure;
793 eval->baseoff = baseoff;
794 eval->expr = expr;
795 list_add_tail (&expr_eval_routines, &eval->entry);
796 }
797
798 if (callback_offset > USHRT_MAX)
799 error("Maximum number of callback routines reached\n");
800
801 print_file(file, 2, "0x%x, /* Corr desc: %s */\n", conftype, conftype_string);
802 print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
803 print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", callback_offset, callback_offset);
804 }
805 return 4;
806 }
807
808 static size_t fields_memsize(const var_list_t *fields, unsigned int *align)
809 {
810 int have_align = FALSE;
811 size_t size = 0;
812 const var_t *v;
813
814 if (!fields) return 0;
815 LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
816 {
817 unsigned int falign = 0;
818 size_t fsize = type_memsize(v->type, &falign);
819 if (!have_align)
820 {
821 *align = falign;
822 have_align = TRUE;
823 }
824 size = (size + (falign - 1)) & ~(falign - 1);
825 size += fsize;
826 }
827
828 size = (size + (*align - 1)) & ~(*align - 1);
829 return size;
830 }
831
832 static size_t union_memsize(const var_list_t *fields, unsigned int *pmaxa)
833 {
834 size_t size, maxs = 0;
835 unsigned int align = *pmaxa;
836 const var_t *v;
837
838 if (fields) LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
839 {
840 /* we could have an empty default field with NULL type */
841 if (v->type)
842 {
843 size = type_memsize(v->type, &align);
844 if (maxs < size) maxs = size;
845 if (*pmaxa < align) *pmaxa = align;
846 }
847 }
848
849 return maxs;
850 }
851
852 int get_padding(const var_list_t *fields)
853 {
854 unsigned short offset = 0;
855 int salign = -1;
856 const var_t *f;
857
858 if (!fields)
859 return 0;
860
861 LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry)
862 {
863 type_t *ft = f->type;
864 unsigned int align = 0;
865 size_t size = type_memsize(ft, &align);
866 if (salign == -1)
867 salign = align;
868 offset = (offset + (align - 1)) & ~(align - 1);
869 offset += size;
870 }
871
872 return ((offset + (salign - 1)) & ~(salign - 1)) - offset;
873 }
874
875 size_t type_memsize(const type_t *t, unsigned int *align)
876 {
877 size_t size = 0;
878
879 if (t->declarray && is_conformant_array(t))
880 {
881 type_memsize(t->ref, align);
882 size = 0;
883 }
884 else if (is_ptr(t) || is_conformant_array(t))
885 {
886 size = sizeof(void *);
887 if (size > *align) *align = size;
888 }
889 else switch (t->type)
890 {
891 case RPC_FC_BYTE:
892 case RPC_FC_CHAR:
893 case RPC_FC_USMALL:
894 case RPC_FC_SMALL:
895 size = 1;
896 if (size > *align) *align = size;
897 break;
898 case RPC_FC_WCHAR:
899 case RPC_FC_USHORT:
900 case RPC_FC_SHORT:
901 case RPC_FC_ENUM16:
902 size = 2;
903 if (size > *align) *align = size;
904 break;
905 case RPC_FC_ULONG:
906 case RPC_FC_LONG:
907 case RPC_FC_ERROR_STATUS_T:
908 case RPC_FC_ENUM32:
909 case RPC_FC_FLOAT:
910 size = 4;
911 if (size > *align) *align = size;
912 break;
913 case RPC_FC_HYPER:
914 case RPC_FC_DOUBLE:
915 size = 8;
916 if (size > *align) *align = size;
917 break;
918 case RPC_FC_STRUCT:
919 case RPC_FC_CVSTRUCT:
920 case RPC_FC_CPSTRUCT:
921 case RPC_FC_CSTRUCT:
922 case RPC_FC_PSTRUCT:
923 case RPC_FC_BOGUS_STRUCT:
924 size = fields_memsize(t->fields, align);
925 break;
926 case RPC_FC_ENCAPSULATED_UNION:
927 case RPC_FC_NON_ENCAPSULATED_UNION:
928 size = union_memsize(t->fields, align);
929 break;
930 case RPC_FC_SMFARRAY:
931 case RPC_FC_LGFARRAY:
932 case RPC_FC_SMVARRAY:
933 case RPC_FC_LGVARRAY:
934 case RPC_FC_BOGUS_ARRAY:
935 size = t->dim * type_memsize(t->ref, align);
936 break;
937 default:
938 error("type_memsize: Unknown type %d\n", t->type);
939 size = 0;
940 }
941
942 return size;
943 }
944
945 int is_full_pointer_function(const func_t *func)
946 {
947 const var_t *var;
948 if (type_has_full_pointer(func->def->type))
949 return TRUE;
950 if (!func->args)
951 return FALSE;
952 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
953 if (type_has_full_pointer( var->type ))
954 return TRUE;
955 return FALSE;
956 }
957
958 void write_full_pointer_init(FILE *file, int indent, const func_t *func, int is_server)
959 {
960 print_file(file, indent, "_StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,%s);\n",
961 is_server ? "XLAT_SERVER" : "XLAT_CLIENT");
962 fprintf(file, "\n");
963 }
964
965 void write_full_pointer_free(FILE *file, int indent, const func_t *func)
966 {
967 print_file(file, indent, "NdrFullPointerXlatFree(_StubMsg.FullPtrXlatTables);\n");
968 fprintf(file, "\n");
969 }
970
971 static unsigned int write_nonsimple_pointer(FILE *file, const type_t *type, size_t offset)
972 {
973 short absoff = type->ref->typestring_offset;
974 short reloff = absoff - (offset + 2);
975 int ptr_attr = is_ptr(type->ref) ? 0x10 : 0x0;
976
977 print_file(file, 2, "0x%02x, 0x%x,\t/* %s */\n",
978 type->type, ptr_attr, string_of_type(type->type));
979 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%hd) */\n",
980 reloff, reloff, absoff);
981 return 4;
982 }
983
984 static unsigned char conf_string_type_of_char_type(unsigned char t)
985 {
986 switch (t)
987 {
988 case RPC_FC_BYTE:
989 case RPC_FC_CHAR:
990 return RPC_FC_C_CSTRING;
991 case RPC_FC_WCHAR:
992 return RPC_FC_C_WSTRING;
993 }
994
995 error("string_type_of_char_type: unrecognized type %d\n", t);
996 return 0;
997 }
998
999 static unsigned int write_simple_pointer(FILE *file, const type_t *type)
1000 {
1001 unsigned char fc
1002 = is_string_type(type->attrs, type)
1003 ? conf_string_type_of_char_type(type->ref->type)
1004 : type->ref->type;
1005 print_file(file, 2, "0x%02x, 0x8,\t/* %s [simple_pointer] */\n",
1006 type->type, string_of_type(type->type));
1007 print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
1008 print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
1009 return 4;
1010 }
1011
1012 static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff)
1013 {
1014 print_file(file, 0, "/* %u (", tfsoff);
1015 write_type_decl(file, t, NULL);
1016 print_file(file, 0, ") */\n");
1017 }
1018
1019 static size_t write_pointer_tfs(FILE *file, type_t *type, unsigned int *typestring_offset)
1020 {
1021 unsigned int offset = *typestring_offset;
1022
1023 print_start_tfs_comment(file, type, offset);
1024 update_tfsoff(type, offset, file);
1025
1026 if (type->ref->typestring_offset)
1027 *typestring_offset += write_nonsimple_pointer(file, type, offset);
1028 else if (is_base_type(type->ref->type))
1029 *typestring_offset += write_simple_pointer(file, type);
1030
1031 return offset;
1032 }
1033
1034 static int processed(const type_t *type)
1035 {
1036 return type->typestring_offset && !type->tfswrite;
1037 }
1038
1039 static int user_type_has_variable_size(const type_t *t)
1040 {
1041 if (is_ptr(t))
1042 return TRUE;
1043 else
1044 switch (t->type)
1045 {
1046 case RPC_FC_PSTRUCT:
1047 case RPC_FC_CSTRUCT:
1048 case RPC_FC_CPSTRUCT:
1049 case RPC_FC_CVSTRUCT:
1050 return TRUE;
1051 }
1052 /* Note: Since this only applies to user types, we can't have a conformant
1053 array here, and strings should get filed under pointer in this case. */
1054 return FALSE;
1055 }
1056
1057 static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
1058 {
1059 unsigned int start, absoff, flags;
1060 unsigned int align = 0, ualign = 0;
1061 const char *name;
1062 type_t *utype = get_user_type(type, &name);
1063 size_t usize = user_type_has_variable_size(utype) ? 0 : type_memsize(utype, &ualign);
1064 size_t size = type_memsize(type, &align);
1065 unsigned short funoff = user_type_offset(name);
1066 short reloff;
1067
1068 guard_rec(type);
1069
1070 if (is_base_type(utype->type))
1071 {
1072 absoff = *tfsoff;
1073 print_start_tfs_comment(file, utype, absoff);
1074 print_file(file, 2, "0x%x,\t/* %s */\n", utype->type, string_of_type(utype->type));
1075 print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
1076 *tfsoff += 2;
1077 }
1078 else
1079 {
1080 if (!processed(utype))
1081 write_embedded_types(file, NULL, utype, utype->name, TRUE, tfsoff);
1082 absoff = utype->typestring_offset;
1083 }
1084
1085 if (utype->type == RPC_FC_RP)
1086 flags = 0x40;
1087 else if (utype->type == RPC_FC_UP)
1088 flags = 0x80;
1089 else
1090 flags = 0;
1091
1092 start = *tfsoff;
1093 update_tfsoff(type, start, file);
1094 print_start_tfs_comment(file, type, start);
1095 print_file(file, 2, "0x%x,\t/* FC_USER_MARSHAL */\n", RPC_FC_USER_MARSHAL);
1096 print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
1097 flags | (align - 1), align - 1, flags);
1098 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
1099 print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", size, size);
1100 print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize);
1101 *tfsoff += 8;
1102 reloff = absoff - *tfsoff;
1103 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", reloff, reloff, absoff);
1104 *tfsoff += 2;
1105 }
1106
1107 static void write_member_type(FILE *file, const type_t *cont,
1108 const attr_list_t *attrs, const type_t *type,
1109 unsigned int *corroff, unsigned int *tfsoff)
1110 {
1111 if (is_embedded_complex(type) && !is_conformant_array(type))
1112 {
1113 size_t absoff;
1114 short reloff;
1115
1116 if (is_union(type->type) && is_attr(attrs, ATTR_SWITCHIS))
1117 {
1118 absoff = *corroff;
1119 *corroff += 8;
1120 }
1121 else
1122 {
1123 absoff = type->typestring_offset;
1124 }
1125 reloff = absoff - (*tfsoff + 2);
1126
1127 print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
1128 /* FIXME: actually compute necessary padding */
1129 print_file(file, 2, "0x0,\t/* FIXME: padding */\n");
1130 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1131 reloff, reloff, absoff);
1132 *tfsoff += 4;
1133 }
1134 else if (is_ptr(type) || is_conformant_array(type))
1135 {
1136 unsigned char fc = (cont->type == RPC_FC_BOGUS_STRUCT
1137 ? RPC_FC_POINTER
1138 : RPC_FC_LONG);
1139 print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1140 *tfsoff += 1;
1141 }
1142 else if (!write_base_type(file, type, tfsoff))
1143 error("Unsupported member type 0x%x\n", type->type);
1144 }
1145
1146 static void write_end(FILE *file, unsigned int *tfsoff)
1147 {
1148 if (*tfsoff % 2 == 0)
1149 {
1150 print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD);
1151 *tfsoff += 1;
1152 }
1153 print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END);
1154 *tfsoff += 1;
1155 }
1156
1157 static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
1158 {
1159 unsigned int offset = 0;
1160 var_list_t *fs = type->fields;
1161 var_t *f;
1162
1163 if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
1164 {
1165 unsigned int align = 0;
1166 type_t *ft = f->type;
1167 if (is_union(ft->type) && is_attr(f->attrs, ATTR_SWITCHIS))
1168 {
1169 unsigned int absoff = ft->typestring_offset;
1170 short reloff = absoff - (*tfsoff + 6);
1171 print_file(file, 0, "/* %d */\n", *tfsoff);
1172 print_file(file, 2, "0x%x,\t/* %s */\n", ft->type, string_of_type(ft->type));
1173 print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", RPC_FC_LONG);
1174 write_conf_or_var_desc(file, current_structure, offset, ft,
1175 get_attrp(f->attrs, ATTR_SWITCHIS));
1176 print_file(file, 2, "NdrFcShort(%hd),\t/* Offset= %hd (%u) */\n",
1177 reloff, reloff, absoff);
1178 *tfsoff += 8;
1179 }
1180
1181 /* FIXME: take alignment into account */
1182 offset += type_memsize(ft, &align);
1183 }
1184 }
1185
1186 static int write_no_repeat_pointer_descriptions(
1187 FILE *file, type_t *type,
1188 size_t *offset_in_memory, size_t *offset_in_buffer,
1189 unsigned int *typestring_offset)
1190 {
1191 int written = 0;
1192 unsigned int align;
1193
1194 if (is_ptr(type) || (!type->declarray && is_conformant_array(type)))
1195 {
1196 print_file(file, 2, "0x%02x, /* FC_NO_REPEAT */\n", RPC_FC_NO_REPEAT);
1197 print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1198
1199 /* pointer instance */
1200 print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1201 print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1202 *typestring_offset += 6;
1203
1204 if (is_ptr(type))
1205 write_pointer_tfs(file, type, typestring_offset);
1206 else
1207 {
1208 unsigned absoff = type->typestring_offset;
1209 short reloff = absoff - (*typestring_offset + 2);
1210 /* FIXME: get pointer attributes from field */
1211 print_file(file, 2, "0x%02x, 0x0,\t/* %s */\n", RPC_FC_UP, "FC_UP");
1212 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1213 reloff, reloff, absoff);
1214 *typestring_offset += 4;
1215 }
1216
1217 align = 0;
1218 *offset_in_memory += type_memsize(type, &align);
1219 /* FIXME: is there a case where these two are different? */
1220 align = 0;
1221 *offset_in_buffer += type_memsize(type, &align);
1222
1223 return 1;
1224 }
1225
1226 if (is_non_complex_struct(type))
1227 {
1228 const var_t *v;
1229 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1230 written += write_no_repeat_pointer_descriptions(
1231 file, v->type,
1232 offset_in_memory, offset_in_buffer, typestring_offset);
1233 }
1234 else
1235 {
1236 align = 0;
1237 *offset_in_memory += type_memsize(type, &align);
1238 /* FIXME: is there a case where these two are different? */
1239 align = 0;
1240 *offset_in_buffer += type_memsize(type, &align);
1241 }
1242
1243 return written;
1244 }
1245
1246 static int write_pointer_description_offsets(
1247 FILE *file, const attr_list_t *attrs, type_t *type,
1248 size_t *offset_in_memory, size_t *offset_in_buffer,
1249 unsigned int *typestring_offset)
1250 {
1251 int written = 0;
1252 unsigned int align;
1253
1254 if (is_ptr(type) && type->ref->type != RPC_FC_IP)
1255 {
1256 if (offset_in_memory && offset_in_buffer)
1257 {
1258 /* pointer instance */
1259 /* FIXME: sometimes from end of structure, sometimes from beginning */
1260 print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1261 print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1262
1263 align = 0;
1264 *offset_in_memory += type_memsize(type, &align);
1265 /* FIXME: is there a case where these two are different? */
1266 align = 0;
1267 *offset_in_buffer += type_memsize(type, &align);
1268 }
1269 *typestring_offset += 4;
1270
1271 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");
1275
1276 return 1;
1277 }
1278
1279 if (is_array(type))
1280 {
1281 return write_pointer_description_offsets(
1282 file, attrs, type->ref, offset_in_memory, offset_in_buffer,
1283 typestring_offset);
1284 }
1285 else if (is_non_complex_struct(type))
1286 {
1287 /* otherwise search for interesting fields to parse */
1288 const var_t *v;
1289 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1290 {
1291 written += write_pointer_description_offsets(
1292 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1293 typestring_offset);
1294 }
1295 }
1296 else
1297 {
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);
1305 }
1306
1307 return written;
1308 }
1309
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)
1316 {
1317 unsigned int align;
1318 int pointer_count = 0;
1319
1320 if (type->type == RPC_FC_SMFARRAY || type->type == RPC_FC_LGFARRAY)
1321 {
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)
1328 {
1329 unsigned int increment_size;
1330 size_t offset_of_array_pointer_mem = 0;
1331 size_t offset_of_array_pointer_buf = 0;
1332
1333 align = 0;
1334 increment_size = type_memsize(type->ref, &align);
1335
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;
1343
1344 pointer_count = write_pointer_description_offsets(
1345 file, attrs, type, &offset_of_array_pointer_mem,
1346 &offset_of_array_pointer_buf, typestring_offset);
1347 }
1348 }
1349 else if (is_struct(type->type))
1350 {
1351 const var_t *v;
1352 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1353 {
1354 pointer_count += write_fixed_array_pointer_descriptions(
1355 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1356 typestring_offset);
1357 }
1358 }
1359 else
1360 {
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);
1368 }
1369
1370 return pointer_count;
1371 }
1372
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)
1378 {
1379 unsigned int align;
1380 int pointer_count = 0;
1381
1382 if (is_conformant_array(type) && !type->length_is)
1383 {
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)
1390 {
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;
1394
1395 align = 0;
1396 increment_size = type_memsize(type->ref, &align);
1397
1398 if (increment_size > USHRT_MAX)
1399 error("array size of %u bytes is too large\n", increment_size);
1400
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;
1407
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);
1411 }
1412 }
1413
1414 return pointer_count;
1415 }
1416
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)
1423 {
1424 unsigned int align;
1425 int pointer_count = 0;
1426
1427 /* FIXME: do varying array searching here, but pointer searching in write_pointer_description_offsets */
1428
1429 if (is_array(type) && type->length_is)
1430 {
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)
1437 {
1438 unsigned int increment_size;
1439 size_t offset_of_array_pointer_mem = 0;
1440 size_t offset_of_array_pointer_buf = 0;
1441
1442 align = 0;
1443 increment_size = type_memsize(type->ref, &align);
1444
1445 if (increment_size > USHRT_MAX)
1446 error("array size of %u bytes is too large\n", increment_size);
1447
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;
1454
1455 pointer_count = write_pointer_description_offsets(
1456 file, attrs, type, &offset_of_array_pointer_mem,
1457 &offset_of_array_pointer_buf, typestring_offset);
1458 }
1459 }
1460 else if (is_struct(type->type))
1461 {
1462 const var_t *v;
1463 LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1464 {
1465 pointer_count += write_varying_array_pointer_descriptions(
1466 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1467 typestring_offset);
1468 }
1469 }
1470 else
1471 {
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);
1479 }
1480
1481 return pointer_count;
1482 }
1483
1484 static void write_pointer_description(FILE *file, type_t *type,
1485 unsigned int *typestring_offset)
1486 {
1487 size_t offset_in_buffer;
1488 size_t offset_in_memory;
1489
1490 /* pass 1: search for single instance of a pointer (i.e. don't descend
1491 * into arrays) */
1492 if (!is_array(type))
1493 {
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);
1499 }
1500
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);
1507
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)
1514 {
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);
1521 }
1522
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);
1529 }
1530
1531 int is_declptr(const type_t *t)
1532 {
1533 return is_ptr(t) || (is_conformant_array(t) && !t->declarray);
1534 }
1535
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,
1539 int toplevel)
1540 {
1541 size_t start_offset;
1542 unsigned char rtype;
1543
1544 if (toplevel && is_declptr(type))
1545 {
1546 unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER;
1547 int pointer_type = is_ptr(type) ? type->type : get_attrv(attrs, ATTR_POINTERTYPE);
1548 if (!pointer_type)
1549 pointer_type = RPC_FC_RP;
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)
1555 {
1556 print_file(file, 2, "NdrFcShort(0x2),\n");
1557 *typestring_offset += 2;
1558 }
1559 }
1560
1561 start_offset = *typestring_offset;
1562 update_tfsoff(type, start_offset, file);
1563
1564 rtype = type->ref->type;
1565
1566 if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR))
1567 {
1568 error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
1569 return start_offset;
1570 }
1571
1572 if (type->declarray && !is_conformant_array(type))
1573 {
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);
1578
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;
1585
1586 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", type->dim, type->dim);
1587 *typestring_offset += 2;
1588
1589 return start_offset;
1590 }
1591 else if (type->size_is)
1592 {
1593 unsigned int align = 0;
1594
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;
1601
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);
1608
1609 return start_offset;
1610 }
1611 else
1612 {
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;
1619
1620 return start_offset;
1621 }
1622 }
1623
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)
1626 {
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;
1638
1639 if (!pointer_type)
1640 pointer_type = RPC_FC_RP;
1641
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);
1646
1647 align = 0;
1648 size = type_memsize((is_conformant_array(type) ? type->ref : type), &align);
1649
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;
1656
1657 align = 0;
1658 if (type->type != RPC_FC_BOGUS_ARRAY)
1659 {
1660 unsigned char tc = type->type;
1661
1662 if (tc == RPC_FC_LGFARRAY || tc == RPC_FC_LGVARRAY)
1663 {
1664 print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", size, size);
1665 *typestring_offset += 4;
1666 }
1667 else
1668 {
1669 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", size, size);
1670 *typestring_offset += 2;
1671 }
1672
1673 if (is_conformant_array(type))
1674 *typestring_offset
1675 += write_conf_or_var_desc(file, current_structure, baseoff,
1676 type, size_is);
1677
1678 if (type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY)
1679 {
1680 unsigned int elalign = 0;
1681 size_t elsize = type_memsize(type->ref, &elalign);
1682
1683 if (type->type == RPC_FC_LGVARRAY)
1684 {
1685 print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", type->dim, type->dim);
1686 *typestring_offset += 4;
1687 }
1688 else
1689 {
1690 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", type->dim, type->dim);
1691 *typestring_offset += 2;
1692 }
1693
1694 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", elsize, elsize);
1695 *typestring_offset += 2;
1696 }
1697
1698 if (length_is)
1699 *typestring_offset
1700 += write_conf_or_var_desc(file, current_structure, baseoff,
1701 type, length_is);
1702
1703 if (has_pointer && (!type->declarray || !current_structure))
1704 {
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;
1711 }
1712
1713 write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1714 write_end(file, typestring_offset);
1715 }
1716 else
1717 {
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);
1729 }
1730
1731 return start_offset;
1732 }
1733
1734 static const var_t *find_array_or_string_in_struct(const type_t *type)
1735 {
1736 const var_t *last_field = LIST_ENTRY( list_tail(type->fields), const var_t, entry );
1737 const type_t *ft = last_field->type;
1738
1739 if (ft->declarray && is_conformant_array(ft))
1740 return last_field;
1741
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;
1746 }
1747
1748 static void write_struct_members(FILE *file, const type_t *type,
1749 unsigned int *corroff, unsigned int *typestring_offset)
1750 {
1751 const var_t *field;
1752 unsigned short offset = 0;
1753 int salign = -1;
1754 int padding;
1755
1756 if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1757 {
1758 type_t *ft = field->type;
1759 if (!ft->declarray || !is_conformant_array(ft))
1760 {
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)
1766 {
1767 unsigned char fc = 0;
1768 switch (align)
1769 {
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);
1778 }
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;
1782 }
1783 write_member_type(file, type, field->attrs, field->type, corroff,
1784 typestring_offset);
1785 offset += size;
1786 }
1787 }
1788
1789 padding = ((offset + (salign - 1)) & ~(salign - 1)) - offset;
1790 if (padding)
1791 {
1792 print_file(file, 2, "0x%x,\t/* FC_STRUCTPAD%d */\n",
1793 RPC_FC_STRUCTPAD1 + padding - 1,
1794 padding);
1795 *typestring_offset += 1;
1796 }
1797
1798 write_end(file, typestring_offset);
1799 }
1800
1801 static size_t write_struct_tfs(FILE *file, type_t *type,
1802 const char *name, unsigned int *tfsoff)
1803 {
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;
1813
1814 guard_rec(type);
1815 current_structure = type;
1816
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);
1821
1822 if (type->fields) LIST_FOR_EACH_ENTRY(f, type->fields, 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);
1826
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, FALSE)
1832 : write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
1833
1834 corroff = *tfsoff;
1835 write_descriptors(file, type, tfsoff);
1836
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;
1844
1845 if (array)
1846 {
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;
1852 }
1853 else if (type->type == RPC_FC_BOGUS_STRUCT)
1854 {
1855 print_file(file, 2, "NdrFcShort(0x0),\n");
1856 *tfsoff += 2;
1857 }
1858
1859 if (type->type == RPC_FC_BOGUS_STRUCT)
1860 {
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;
1869 }
1870 else if ((type->type == RPC_FC_PSTRUCT) ||
1871 (type->type == RPC_FC_CPSTRUCT) ||
1872 (type->type == RPC_FC_CVSTRUCT && has_pointers))
1873 {
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;
1880 }
1881
1882 write_struct_members(file, type, &corroff, tfsoff);
1883
1884 if (type->type == RPC_FC_BOGUS_STRUCT)
1885 {
1886 const var_list_t *fs = type->fields;
1887 const var_t *f;
1888
1889 type->ptrdesc = *tfsoff;
1890 if (fs) LIST_FOR_EACH_ENTRY(f, fs, const var_t, entry)
1891 {
1892 type_t *ft = f->type;
1893 if (is_ptr(ft))
1894 write_pointer_tfs(file, ft, tfsoff);
1895 else if (!ft->declarray && is_conformant_array(ft))
1896 {
1897 unsigned int absoff = ft->typestring_offset;
1898 short reloff = absoff - (*tfsoff + 2);
1899 int ptr_type = get_attrv(f->attrs, ATTR_POINTERTYPE);
1900 /* FIXME: We need to store pointer attributes for arrays
1901 so we don't lose pointer_default info. */
1902 if (ptr_type == 0)
1903 ptr_type = RPC_FC_UP;
1904 print_file(file, 0, "/* %d */\n", *tfsoff);
1905 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
1906 string_of_type(ptr_type));
1907 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1908 reloff, reloff, absoff);
1909 *tfsoff += 4;
1910 }
1911 }
1912 if (type->ptrdesc == *tfsoff)
1913 type->ptrdesc = 0;
1914 }
1915
1916 current_structure = save_current_structure;
1917 return start_offset;
1918 }
1919
1920 static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
1921 unsigned char flags, size_t offset,
1922 unsigned int *typeformat_offset)
1923 {
1924 size_t start_offset = *typeformat_offset;
1925 short reloff = offset - (*typeformat_offset + 2);
1926 int in_attr, out_attr;
1927 in_attr = is_attr(attrs, ATTR_IN);
1928 out_attr = is_attr(attrs, ATTR_OUT);
1929 if (!in_attr && !out_attr) in_attr = 1;
1930
1931 if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
1932 flags |= 0x04;
1933
1934 print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
1935 pointer_type,
1936 flags,
1937 string_of_type(pointer_type));
1938 if (file)
1939 {
1940 if (flags & 0x04)
1941 fprintf(file, " [allocated_on_stack]");
1942 if (flags & 0x10)
1943 fprintf(file, " [pointer_deref]");
1944 fprintf(file, " */\n");
1945 }
1946
1947 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", reloff, offset);
1948 *typeformat_offset += 4;
1949
1950 return start_offset;
1951 }
1952
1953 static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
1954 {
1955 if (t == NULL)
1956 {
1957 print_file(file, 2, "NdrFcShort(0x0),\t/* No type */\n");
1958 }
1959 else if (is_base_type(t->type))
1960 {
1961 print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n",
1962 t->type, string_of_type(t->type));
1963 }
1964 else if (t->typestring_offset)
1965 {
1966 short reloff = t->typestring_offset - *tfsoff;
1967 print_file(file, 2, "NdrFcShort(0x%x),\t/* Offset= %d (%d) */\n",
1968 reloff, reloff, t->typestring_offset);
1969 }
1970 else
1971 error("write_branch_type: type unimplemented (0x%x)\n", t->type);
1972
1973 *tfsoff += 2;
1974 }
1975
1976 static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
1977 {
1978 unsigned int align = 0;
1979 unsigned int start_offset;
1980 size_t size = type_memsize(type, &align);
1981 var_list_t *fields;
1982 size_t nbranch = 0;
1983 type_t *deftype = NULL;
1984 short nodeftype = 0xffff;
1985 var_t *f;
1986
1987 guard_rec(type);
1988
1989 if (type->type == RPC_FC_ENCAPSULATED_UNION)
1990 {
1991 const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
1992 fields = uv->type->fields;
1993 }
1994 else
1995 fields = type->fields;
1996
1997 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
1998 {
1999 expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
2000 if (cases)
2001 nbranch += list_count(cases);
2002 if (f->type)
2003 write_embedded_types(file, f->attrs, f->type, f->name, TRUE, tfsoff);
2004 }
2005
2006 start_offset = *tfsoff;
2007 update_tfsoff(type, start_offset, file);
2008 print_start_tfs_comment(file, type, start_offset);
2009 if (type->type == RPC_FC_ENCAPSULATED_UNION)
2010 {
2011 const var_t *sv = LIST_ENTRY(list_head(type->fields), const var_t, entry);
2012 const type_t *st = sv->type;
2013
2014 switch (st->type)
2015 {
2016 case RPC_FC_CHAR:
2017 case RPC_FC_SMALL:
2018 case RPC_FC_USMALL:
2019 case RPC_FC_SHORT:
2020 case RPC_FC_USHORT:
2021 case RPC_FC_LONG:
2022 case RPC_FC_ULONG:
2023 case RPC_FC_ENUM16:
2024 case RPC_FC_ENUM32:
2025 print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
2026 print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
2027 0x40 | st->type, string_of_type(st->type));
2028 *tfsoff += 2;
2029 break;
2030 default:
2031 error("union switch type must be an integer, char, or enum\n");
2032 }
2033 }
2034 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", size, size);
2035 print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", nbranch, nbranch);
2036 *tfsoff += 4;
2037
2038 if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
2039 {
2040 type_t *ft = f->type;
2041 expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
2042 int deflt = is_attr(f->attrs, ATTR_DEFAULT);
2043 expr_t *c;
2044
2045 if (cases == NULL && !deflt)
2046 error("union field %s with neither case nor default attribute\n", f->name);
2047
2048 if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry)
2049 {
2050 /* MIDL doesn't check for duplicate cases, even though that seems
2051 like a reasonable thing to do, it just dumps them to the TFS
2052 like we're going to do here. */
2053 print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
2054 *tfsoff += 4;
2055 write_branch_type(file, ft, tfsoff);
2056 }
2057
2058 /* MIDL allows multiple default branches, even though that seems
2059 illogical, it just chooses the last one, which is what we will
2060 do. */
2061 if (deflt)
2062 {
2063 deftype = ft;
2064 nodeftype = 0;
2065 }
2066 }
2067
2068 if (deftype)
2069 {
2070 write_branch_type(file, deftype, tfsoff);
2071 }
2072 else
2073 {
2074 print_file(file, 2, "NdrFcShort(0x%x),\n", nodeftype);
2075 *tfsoff += 2;
2076 }
2077
2078 return start_offset;
2079 }
2080
2081 static size_t write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
2082 unsigned int *typeformat_offset)
2083 {
2084 size_t i;
2085 size_t start_offset = *typeformat_offset;
2086 expr_t *iid = get_attrp(attrs, ATTR_IIDIS);
2087
2088 if (iid)
2089 {
2090 print_file(file, 2, "0x2f, /* FC_IP */\n");
2091 print_file(file, 2, "0x5c, /* FC_PAD */\n");
2092 *typeformat_offset
2093 += write_conf_or_var_desc(file, NULL, 0, type, iid) + 2;
2094 }
2095 else
2096 {
2097 const type_t *base = is_ptr(type) ? type->ref : type;
2098 const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
2099
2100 if (! uuid)
2101 error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
2102
2103 update_tfsoff(type, start_offset, file);
2104 print_start_tfs_comment(file, type, start_offset);
2105 print_file(file, 2, "0x2f,\t/* FC_IP */\n");
2106 print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
2107 print_file(file, 2, "NdrFcLong(0x%08lx),\n", uuid->Data1);
2108 print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2);
2109 print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3);
2110 for (i = 0; i < 8; ++i)
2111 print_file(file, 2, "0x%02x,\n", uuid->Data4[i]);
2112
2113 if (file)
2114 fprintf(file, "\n");
2115
2116 *typeformat_offset += 18;
2117 }
2118 return start_offset;
2119 }
2120
2121 static size_t write_contexthandle_tfs(FILE *file, const type_t *type,
2122 const var_t *var,
2123 unsigned int *typeformat_offset)
2124 {
2125 size_t start_offset = *typeformat_offset;
2126 unsigned char flags = 0;
2127
2128 if (is_attr(current_iface->attrs, ATTR_STRICTCONTEXTHANDLE))
2129 flags |= NDR_STRICT_CONTEXT_HANDLE;
2130
2131 if (is_ptr(type))
2132 flags |= 0x80;
2133 if (is_attr(var->attrs, ATTR_IN))
2134 {
2135 flags |= 0x40;
2136 if (!is_attr(var->attrs, ATTR_OUT))
2137 flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
2138 }
2139 if (is_attr(var->attrs, ATTR_OUT))
2140 flags |= 0x20;
2141
2142 WRITE_FCTYPE(file, FC_BIND_CONTEXT, *typeformat_offset);
2143 print_file(file, 2, "0x%x,\t/* Context flags: ", flags);
2144 /* return and can't be null values overlap */
2145 if (((flags & 0x21) != 0x21) && (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL))
2146 print_file(file, 0, "can't be null, ");
2147 if (flags & NDR_CONTEXT_HANDLE_SERIALIZE)
2148 print_file(file, 0, "serialize, ");
2149 if (flags & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
2150 print_file(file, 0, "no serialize, ");
2151 if (flags & NDR_STRICT_CONTEXT_HANDLE)
2152 print_file(file, 0, "strict, ");
2153 if ((flags & 0x21) == 0x20)
2154 print_file(file, 0, "out, ");
2155 if ((flags & 0x21) == 0x21)
2156 print_file(file, 0, "return, ");
2157 if (flags & 0x40)
2158 print_file(file, 0, "in, ");
2159 if (flags & 0x80)
2160 print_file(file, 0, "via ptr, ");
2161 print_file(file, 0, "*/\n");
2162 print_file(file, 2, "0, /* FIXME: rundown routine index*/\n");
2163 print_file(file, 2, "0, /* FIXME: param num */\n");
2164 *typeformat_offset += 4;
2165
2166 return start_offset;
2167 }
2168
2169 static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *func,
2170 type_t *type, const var_t *var,
2171 unsigned int *typeformat_offset)
2172 {
2173 size_t offset;
2174
2175 if (is_context_handle(type))
2176 return write_contexthandle_tfs(file, type, var, typeformat_offset);
2177
2178 if (is_user_type(type))
2179 {
2180 write_user_tfs(file, type, typeformat_offset);
2181 return type->typestring_offset;
2182 }
2183
2184 if ((last_ptr(type) || last_array(type)) && is_ptrchain_attr(var, ATTR_STRING))
2185 return write_string_tfs(file, var->attrs, type, var->name, typeformat_offset, TRUE);
2186
2187 if (is_array(type))
2188 {
2189 int ptr_type;
2190 size_t off;
2191 off = write_array_tfs(file, var->attrs, type, var->name, typeformat_offset);
2192 ptr_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2193 /* Top level pointers to conformant arrays may be handled specially
2194 since we can bypass the pointer, but if the array is buried
2195 beneath another pointer (e.g., "[size_is(,n)] int **p" then we
2196 always need to write the pointer. */
2197 if (!ptr_type && var->type != type)
2198 /* FIXME: This should use pointer_default, but the information
2199 isn't kept around for arrays. */
2200 ptr_type = RPC_FC_UP;
2201 if (ptr_type && ptr_type != RPC_FC_RP)
2202 {
2203 unsigned int absoff = type->typestring_offset;
2204 short reloff = absoff - (*typeformat_offset + 2);
2205 off = *typeformat_offset;
2206 print_file(file, 0, "/* %d */\n", off);
2207 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
2208 string_of_type(ptr_type));
2209 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
2210 reloff, reloff, absoff);
2211 *typeformat_offset += 4;
2212 }
2213 return off;
2214 }
2215
2216 if (!is_ptr(type))
2217 {
2218 /* basic types don't need a type format string */
2219 if (is_base_type(type->type))
2220 return 0;
2221
2222 switch (type->type)
2223 {
2224 case RPC_FC_STRUCT:
2225 case RPC_FC_PSTRUCT:
2226 case RPC_FC_CSTRUCT:
2227 case RPC_FC_CPSTRUCT:
2228 case RPC_FC_CVSTRUCT:
2229 case RPC_FC_BOGUS_STRUCT:
2230 return write_struct_tfs(file, type, var->name, typeformat_offset);
2231 case RPC_FC_ENCAPSULATED_UNION:
2232 case RPC_FC_NON_ENCAPSULATED_UNION:
2233 return write_union_tfs(file, type, typeformat_offset);
2234 case RPC_FC_IGNORE:
2235 case RPC_FC_BIND_PRIMITIVE:
2236 /* nothing to do */
2237 return 0;
2238 default:
2239 error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
2240 }
2241 }
2242 else if (last_ptr(type))
2243 {
2244 size_t start_offset = *typeformat_offset;
2245 int in_attr = is_attr(var->attrs, ATTR_IN);
2246 int out_attr = is_attr(var->attrs, ATTR_OUT);
2247 const type_t *base = type->ref;
2248
2249 if (base->type == RPC_FC_IP
2250 || (base->type == 0
2251 && is_attr(var->attrs, ATTR_IIDIS)))
2252 {
2253 return write_ip_tfs(file, var->attrs, type, typeformat_offset);
2254 }
2255
2256 /* special case for pointers to base types */
2257 if (is_base_type(base->type))
2258 {
2259 print_file(file, indent, "0x%x, 0x%x, /* %s %s[simple_pointer] */\n",
2260 type->type, (!in_attr && out_attr) ? 0x0C : 0x08,
2261 string_of_type(type->type),
2262 (!in_attr && out_attr) ? "[allocated_on_stack] " : "");
2263 print_file(file, indent, "0x%02x, /* %s */\n", base->type, string_of_type(base->type));
2264 print_file(file, indent, "0x5c, /* FC_PAD */\n");
2265 *typeformat_offset += 4;
2266 return start_offset;
2267 }
2268 }
2269
2270 assert(is_ptr(type));
2271
2272 offset = write_typeformatstring_var(file, indent, func, type->ref, var, typeformat_offset);
2273 if (file)
2274 fprintf(file, "/* %2u */\n", *typeformat_offset);
2275 return write_pointer_only_tfs(file, var->attrs, type->type,
2276 !last_ptr(type) ? 0x10 : 0,
2277 offset, typeformat_offset);
2278 }
2279
2280 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
2281 const char *name, int write_ptr, unsigned int *tfsoff)
2282 {
2283 int retmask = 0;
2284
2285 if (is_user_type(type))
2286 {
2287 write_user_tfs(file, type, tfsoff);
2288 }
2289 else if (is_ptr(type))
2290 {
2291 type_t *ref = type->ref;
2292
2293 if (ref->type == RPC_FC_IP
2294 || (ref->type == 0
2295 && is_attr(attrs, ATTR_IIDIS)))
2296 {
2297 write_ip_tfs(file, attrs, type, tfsoff);
2298 }
2299 else
2300 {
2301 if (!processed(ref) && !is_base_type(ref->type))
2302 retmask |= write_embedded_types(file, NULL, ref, name, TRUE, tfsoff);
2303
2304 if (write_ptr)
2305 write_pointer_tfs(file, type, tfsoff);
2306
2307 retmask |= 1;
2308 }
2309 }
2310 else if (last_array(type) && is_attr(attrs, ATTR_STRING))
2311 {
2312 write_string_tfs(file, attrs, type, name, tfsoff, FALSE);
2313 }
2314 else if (type->declarray && is_conformant_array(type))
2315 ; /* conformant arrays and strings are handled specially */
2316 else if (is_array(type))
2317 {
2318 write_array_tfs(file, attrs, type, name, tfsoff);
2319 if (is_conformant_array(type))
2320 retmask |= 1;
2321 }
2322 else if (is_struct(type->type))
2323 {
2324 if (!processed(type))
2325 write_struct_tfs(file, type, name, tfsoff);
2326 }
2327 else if (is_union(type->type))
2328 {
2329 if (!processed(type))
2330 write_union_tfs(file, type, tfsoff);
2331 }
2332 else if (!is_base_type(type->type))
2333 error("write_embedded_types: unknown embedded type for %s (0x%x)\n",
2334 name, type->type);
2335
2336 return retmask;
2337 }
2338
2339 static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
2340 {
2341 const var_t *var;
2342 const ifref_t *iface;
2343 unsigned int typeformat_offset = 2;
2344
2345 if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
2346 {
2347 if (!pred(iface->iface))
2348 continue;
2349
2350 if (iface->iface->funcs)
2351 {
2352 const func_t *func;
2353 current_iface = iface;
2354 LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
2355 {
2356 if (is_local(func->def->attrs)) continue;
2357
2358 if (!is_void(func->def->type))
2359 update_tfsoff(func->def->type,
2360 write_typeformatstring_var(
2361 file, 2, NULL, func->def->type,
2362 func->def, &typeformat_offset),
2363 file);
2364
2365 current_func = func;
2366 if (func->args)
2367 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2368 update_tfsoff(
2369 var->type,
2370 write_typeformatstring_var(
2371 file, 2, func, var->type, var,
2372 &typeformat_offset),
2373 file);
2374 }
2375 }
2376 }
2377
2378 return typeformat_offset + 1;
2379 }
2380
2381
2382 void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
2383 {
2384 int indent = 0;
2385
2386 print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
2387 print_file(file, indent, "{\n");
2388 indent++;
2389 print_file(file, indent, "0,\n");
2390 print_file(file, indent, "{\n");
2391 indent++;
2392 print_file(file, indent, "NdrFcShort(0x0),\n");
2393
2394 set_all_tfswrite(TRUE);
2395 process_tfs(file, ifaces, pred);
2396
2397 print_file(file, indent, "0x0\n");
2398 indent--;
2399 print_file(file, indent, "}\n");
2400 indent--;
2401 print_file(file, indent, "};\n");
2402 print_file(file, indent, "\n");
2403 }
2404
2405 static unsigned int get_required_buffer_size_type(
2406 const type_t *type, const char *name, unsigned int *alignment)
2407 {
2408 *alignment = 0;
2409 if (is_user_type(type))
2410 {
2411 const char *uname;
2412 const type_t *utype = get_user_type(type, &uname);
2413 return get_required_buffer_size_type(utype, uname, alignment);
2414 }
2415 else
2416 {
2417 switch (type->type)
2418 {
2419 case RPC_FC_BYTE:
2420 case RPC_FC_CHAR:
2421 case RPC_FC_USMALL:
2422 case RPC_FC_SMALL:
2423 *alignment = 4;
2424 return 1;
2425
2426 case RPC_FC_WCHAR:
2427 case RPC_FC_USHORT:
2428 case RPC_FC_SHORT:
2429 case RPC_FC_ENUM16:
2430 *alignment = 4;
2431 return 2;
2432
2433 case RPC_FC_ULONG:
2434 case RPC_FC_LONG:
2435 case RPC_FC_ENUM32:
2436 case RPC_FC_FLOAT:
2437 case RPC_FC_ERROR_STATUS_T:
2438 *alignment = 4;
2439 return 4;
2440
2441 case RPC_FC_HYPER:
2442 case RPC_FC_DOUBLE:
2443 *alignment = 8;
2444 return 8;
2445
2446 case RPC_FC_IGNORE:
2447 case RPC_FC_BIND_PRIMITIVE:
2448 return 0;
2449
2450 case RPC_FC_STRUCT:
2451 case RPC_FC_PSTRUCT:
2452 {
2453 size_t size = 0;
2454 const var_t *field;
2455 if (!type->fields) return 0;
2456 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2457 {
2458 unsigned int alignment;
2459 size += get_required_buffer_size_type(field->type, field->name,
2460 &alignment);
2461 }
2462 return size;
2463 }
2464
2465 case RPC_FC_RP:
2466 return
2467 is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT
2468 ? get_required_buffer_size_type( type->ref, name, alignment )
2469 : 0;
2470
2471 case RPC_FC_SMFARRAY:
2472 case RPC_FC_LGFARRAY:
2473 return type->dim * get_required_buffer_size_type(type->ref, name, alignment);
2474
2475 default:
2476 return 0;
2477 }
2478 }
2479 }
2480
2481 static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
2482 {
2483 int in_attr = is_attr(var->attrs, ATTR_IN);
2484 int out_attr = is_attr(var->attrs, ATTR_OUT);
2485 const type_t *t;
2486
2487 if (!in_attr && !out_attr)
2488 in_attr = 1;
2489
2490 *alignment = 0;
2491
2492 for (t = var->type; is_ptr(t); t = t->ref)
2493 if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
2494 {
2495 *alignment = 4;
2496 return 20;
2497 }
2498
2499 if (pass == PASS_OUT)
2500 {
2501 if (out_attr && is_ptr(var->type))
2502 {
2503 type_t *type = var->type;
2504
2505 if (type->type == RPC_FC_STRUCT)
2506 {
2507 const var_t *field;
2508 unsigned int size = 36;
2509
2510 if (!type->fields) return size;
2511 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2512 {
2513 unsigned int align;
2514 size += get_required_buffer_size_type(
2515 field->type, field->name, &align);
2516 }
2517 return size;
2518 }
2519 }
2520 return 0;
2521 }
2522 else
2523 {
2524 if ((!out_attr || in_attr) && !var->type->size_is
2525 && !is_attr(var->attrs, ATTR_STRING) && !var->type->declarray)
2526 {
2527 if (is_ptr(var->type))
2528 {
2529 type_t *type = var->type;
2530
2531 if (is_base_type(type->type))
2532 {
2533 return 25;
2534 }
2535 else if (type->type == RPC_FC_STRUCT)
2536 {
2537 unsigned int size = 36;
2538 const var_t *field;
2539
2540 if (!type->fields) return size;
2541 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2542 {
2543 unsigned int align;
2544 size += get_required_buffer_size_type(
2545 field->type, field->name, &align);
2546 }
2547 return size;
2548 }
2549 }
2550 }
2551
2552 return get_required_buffer_size_type(var->type, var->name, alignment);
2553 }
2554 }
2555
2556 static unsigned int get_function_buffer_size( const func_t *func, enum pass pass )
2557 {
2558 const var_t *var;
2559 unsigned int total_size = 0, alignment;
2560
2561 if (func->args)
2562 {
2563 LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2564 {
2565 total_size += get_required_buffer_size(var, &alignment, pass);
2566 total_size += alignment;
2567 }
2568 }
2569
2570 if (pass == PASS_OUT && !is_void(func->def->type))
2571 {
2572 total_size += get_required_buffer_size(func->def, &alignment, PASS_RETURN);
2573 total_size += alignment;
2574 }
2575 return total_size;
2576 }
2577
2578 static void print_phase_function(FILE *file, int indent, const char *type,
2579 enum remoting_phase phase,
2580 const var_t *var, unsigned int type_offset)
2581 {
2582 const char *function;
2583 switch (phase)
2584 {
2585 case PHASE_BUFFERSIZE:
2586 function = "BufferSize";
2587 break;
2588 case PHASE_MARSHAL:
2589 function = "Marshall";
2590 break;
2591 case PHASE_UNMARSHAL:
2592 function = "Unmarshall";
2593 break;
2594 case PHASE_FREE:
2595 function = "Free";
2596 break;
2597 default:
2598 assert(0);
2599 return;
2600 }
2601
2602 print_file(file, indent, "Ndr%s%s(\n", type, function);
2603 indent++;
2604 print_file(file, indent, "&_StubMsg,\n");
2605 print_file(file, indent, "%s%s%s%s,\n",
2606 (phase == PHASE_UNMARSHAL) ? "(unsigned char **)" : "(unsigned char *)",
2607 (phase == PHASE_UNMARSHAL || decl_indirect(var->type)) ? "&" : "",
2608 (phase == PHASE_UNMARSHAL && decl_indirect(var->type)) ? "_p_" : "",
2609 var->name);
2610 print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
2611 type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
2612 if (phase == PHASE_UNMARSHAL)
2613 print_file(file, indent, "0);\n");
2614 indent--;
2615 }
2616
2617 void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
2618 enum pass pass, const var_t *var,
2619 const char *varname)
2620 {
2621 type_t *type = var->type;
2622 unsigned int size;
2623 unsigned int alignment = 0;
2624 unsigned char rtype;
2625
2626 /* no work to do for other phases, buffer sizing is done elsewhere */
2627 if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
2628 return;
2629
2630 rtype = is_ptr(type) ? type->ref->type : type->type;
2631
2632 switch (rtype)
2633 {
2634 case RPC_FC_BYTE:
2635 case RPC_FC_CHAR:
2636 case RPC_FC_SMALL:
2637 case RPC_FC_USMALL:
2638 size = 1;
2639 alignment = 1;
2640 break;
2641
2642 case RPC_FC_WCHAR:
2643 case RPC_FC_USHORT:
2644 case RPC_FC_SHORT:
2645 case RPC_FC_ENUM16:
2646 size = 2;
2647 alignment = 2;
2648 break;
2649
2650 case RPC_FC_ULONG:
2651 case RPC_FC_LONG:
2652 case RPC_FC_ENUM32:
2653 case RPC_FC_FLOAT:
2654 case RPC_FC_ERROR_STATUS_T:
2655 size = 4;
2656 alignment = 4;
2657 break;
2658
2659 case RPC_FC_HYPER:
2660 case RPC_FC_DOUBLE:
2661 size = 8;
2662 alignment = 8;
2663 break;
2664
2665 case RPC_FC_IGNORE:
2666 case RPC_FC_BIND_PRIMITIVE:
2667 /* no marshalling needed */
2668 return;
2669
2670 default:
2671 error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, rtype);
2672 size = 0;
2673 }
2674
2675 if (phase == PHASE_MARSHAL)
2676 print_file(file, indent, "MIDL_memset(_StubMsg.Buffer, 0, (0x%x - (long)_StubMsg.Buffer) & 0x%x);\n", alignment, alignment - 1);
2677 print_file(file, indent, "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
2678 alignment - 1, alignment - 1);
2679
2680 if (phase == PHASE_MARSHAL)
2681 {
2682 print_file(file, indent, "*(");
2683 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2684 if (is_ptr(type))
2685 fprintf(file, " *)_StubMsg.Buffer = *");
2686 else
2687 fprintf(file, " *)_StubMsg.Buffer = ");
2688 fprintf(file, "%s", varname);
2689 fprintf(file, ";\n");
2690 }
2691 else if (phase == PHASE_UNMARSHAL)
2692 {
2693 print_file(file, indent, "if (_StubMsg.Buffer + sizeof(");
2694 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2695 fprintf(file, ") > _StubMsg.BufferEnd)\n");
2696 print_file(file, indent, "{\n");
2697 print_file(file, indent + 1, "RpcRaiseException(RPC_X_BAD_STUB_DATA);\n");
2698 print_file(file, indent, "}\n");
2699 if (pass == PASS_IN || pass == PASS_RETURN)
2700 print_file(file, indent, "");
2701 else
2702 print_file(file, indent, "*");
2703 fprintf(file, "%s", varname);
2704 if (pass == PASS_IN && is_ptr(type))
2705 fprintf(file, " = (");
2706 else
2707 fprintf(file, " = *(");
2708 write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2709 fprintf(file, " *)_StubMsg.Buffer;\n");
2710 }
2711
2712 print_file(file, indent, "_StubMsg.Buffer += sizeof(");
2713 write_type_decl(file, var->type, NULL);
2714 fprintf(file, ");\n");
2715 }
2716
2717 /* returns whether the MaxCount, Offset or ActualCount members need to be
2718 * filled in for the specified phase */
2719 static inline int is_size_needed_for_phase(enum remoting_phase phase)
2720 {
2721 return (phase != PHASE_UNMARSHAL);
2722 }
2723
2724 expr_t *get_size_is_expr(const type_t *t, const char *name)
2725 {
2726 expr_t *x = NULL;
2727
2728 for ( ; is_ptr(t) || is_array(t); t = t->ref)
2729 if (t->size_is)
2730 {
2731 if (!x)
2732 x = t->size_is;
2733 else
2734 error("%s: multidimensional conformant"
2735 " arrays not supported at the top level\n",
2736 name);
2737 }
2738
2739 return x;
2740 }
2741
2742 static void write_remoting_arg(FILE *file, int indent, const func_t *func,
2743 enum pass pass, enum remoting_phase phase,
2744 const var_t *var)
2745 {
2746 int in_attr, out_attr, pointer_type;
2747 const type_t *type = var->type;
2748 unsigned char rtype;
2749 size_t start_offset = type->typestring_offset;
2750
2751 pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2752 if (!pointer_type)
2753 pointer_type = RPC_FC_RP;
2754
2755 in_attr = is_attr(var->attrs, ATTR_IN);
2756 out_attr = is_attr(var->attrs, ATTR_OUT);
2757 if (!in_attr && !out_attr)
2758 in_attr = 1;
2759
2760 if (phase != PHASE_FREE)
2761 switch (pass)
2762 {
2763 case PASS_IN:
2764 if (!in_attr) return;
2765 break;
2766 case PASS_OUT:
2767 if (!out_attr) return;
2768 break;
2769 case PASS_RETURN:
2770 break;
2771 }
2772
2773 rtype = type->type;
2774
2775 if (is_context_handle(type))
2776 {
2777 if (phase == PHASE_MARSHAL)
2778 {
2779 if (pass == PASS_IN)
2780 {
2781 print_file(file, indent, "NdrClientContextMarshall(\n");
2782 print_file(file, indent + 1, "&_StubMsg,\n");
2783 print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ptr(type) ? "*" : "", var->name);
2784 print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
2785 }
2786 else
2787 {
2788 print_file(file, indent, "NdrServerContextNewMarshall(\n");
2789 print_file(file, indent + 1, "&_StubMsg,\n");
2790 print_file(file, indent + 1, "(NDR_SCONTEXT)%s,\n", var->name);
2791 print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown,\n", get_context_handle_type_name(var->type));
2792 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2793 }
2794 }
2795 else if (phase == PHASE_UNMARSHAL)
2796 {
2797 if (pass == PASS_OUT)
2798 {
2799 if (!in_attr)
2800 print_file(file, indent, "*%s = 0;\n", var->name);
2801 print_file(file, indent, "NdrClientContextUnmarshall(\n");
2802 print_file(file, indent + 1, "&_StubMsg,\n");
2803 print_file(file, indent + 1, "(NDR_CCONTEXT *)%s,\n", var->name);
2804 print_file(file, indent + 1, "_Handle);\n");
2805 }
2806 else
2807 {
2808 print_file(file, indent, "%s = NdrServerContextNewUnmarshall(\n", var->name);
2809 print_file(file, indent + 1, "&_StubMsg,\n");
2810 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2811 }
2812 }
2813 }
2814 else if (is_user_type(var->type))
2815 {
2816 print_phase_function(file, indent, "UserMarshal", phase, var, start_offset);
2817 }
2818 else if (is_string_type(var->attrs, var->type))
2819 {
2820 if (is_array(type) && !is_conformant_array(type))
2821 print_phase_function(file, indent, "NonConformantString", phase, var, start_offset);
2822 else
2823 {
2824 if (type->size_is && is_size_needed_for_phase(phase))
2825 {
2826 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2827 write_expr(file, type->size_is, 1);
2828 fprintf(file, ";\n");
2829 }
2830
2831 if (phase == PHASE_FREE || pass == PASS_RETURN || pointer_type == RPC_FC_UP)
2832 print_phase_function(file, indent, "Pointer", phase, var,
2833 start_offset - (type->size_is ? 4 : 2));
2834 else
2835 print_phase_function(file, indent, "ConformantString", phase, var,
2836 start_offset);
2837 }
2838 }
2839 else if (is_array(type))
2840 {
2841 unsigned char tc = type->type;
2842 const char *array_type = "FixedArray";
2843
2844 /* We already have the size_is expression since it's at the
2845 top level, but do checks for multidimensional conformant
2846 arrays. When we handle them, we'll need to extend this
2847 function to return a list, and then we'll actually use
2848 the return value. */
2849 get_size_is_expr(type, var->name);
2850
2851 if (tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY)
2852 {
2853 if (is_size_needed_for_phase(phase))
2854 {
2855 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2856 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2857 write_expr(file, type->length_is, 1);
2858 fprintf(file, ";\n\n");
2859 }
2860 array_type = "VaryingArray";
2861 }
2862 else if (tc == RPC_FC_CARRAY)
2863 {
2864 if (is_size_needed_for_phase(phase))
2865 {
2866 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2867 write_expr(file, type->size_is, 1);
2868 fprintf(file, ";\n\n");
2869 }
2870 array_type = "ConformantArray";
2871 }
2872 else if (tc == RPC_FC_CVARRAY || tc == RPC_FC_BOGUS_ARRAY)
2873 {
2874 if (is_size_needed_for_phase(phase))
2875 {
2876 if (type->size_is)
2877 {
2878 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2879 write_expr(file, type->size_is, 1);
2880 fprintf(file, ";\n");
2881 }
2882 if (type->length_is)
2883 {
2884 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2885 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2886 write_expr(file, type->length_is, 1);
2887 fprintf(file, ";\n\n");
2888 }
2889 }
2890 array_type = (tc == RPC_FC_BOGUS_ARRAY
2891 ? "ComplexArray"
2892 : "ConformantVaryingArray");
2893 }
2894
2895 if (pointer_type != RPC_FC_RP) array_type = "Pointer";
2896 print_phase_function(file, indent, array_type, phase, var, start_offset);
2897 if (phase == PHASE_FREE && pointer_type == RPC_FC_RP)
2898 {
2899 /* these are all unmarshalled by allocating memory */
2900 if (type->type == RPC_FC_BOGUS_ARRAY ||
2901 type->type == RPC_FC_CVARRAY ||
2902 ((type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY) && in_attr) ||
2903 (type->type == RPC_FC_CARRAY && !in_attr))
2904 {
2905 print_file(file, indent, "if (%s)\n", var->name);
2906 indent++;
2907 print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
2908 }
2909 }
2910 }
2911 else if (!is_ptr(var->type) && is_base_type(rtype))
2912 {
2913 if (phase != PHASE_FREE)
2914 print_phase_basetype(file, indent, phase, pass, var, var->name);
2915 }
2916 else if (!is_ptr(var->type))
2917 {
2918 switch (rtype)
2919 {
2920 case RPC_FC_STRUCT:
2921 case RPC_FC_PSTRUCT:
2922 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset);
2923 break;
2924 case RPC_FC_CSTRUCT:
2925 case RPC_FC_CPSTRUCT:
2926 print_phase_function(file, indent, "ConformantStruct", phase, var, start_offset);
2927 break;
2928 case RPC_FC_CVSTRUCT:
2929 print_phase_function(file, indent, "ConformantVaryingStruct", phase, var, start_offset);
2930 break;
2931 case RPC_FC_BOGUS_STRUCT:
2932 print_phase_function(file, indent, "ComplexStruct", phase, var, start_offset);
2933 break;
2934 case RPC_FC_RP:
2935 if (is_base_type( var->type->ref->type ))
2936 {
2937 print_phase_basetype(file, indent, phase, pass, var, var->name);
2938 }
2939 else if (var->type->ref->type == RPC_FC_STRUCT)
2940 {
2941 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2942 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
2943 }
2944 else
2945 {
2946 expr_t *iid;
2947 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2948 {
2949 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2950 write_expr( file, iid, 1 );
2951 fprintf( file, ";\n\n" );
2952 }
2953 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
2954 }
2955 break;
2956 default:
2957 error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype);
2958 }
2959 }
2960 else
2961 {
2962 if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
2963 {
2964 if (phase != PHASE_FREE)
2965 print_phase_basetype(file, indent, phase, pass, var, var->name);
2966 }
2967 else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
2968 {
2969 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2970 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
2971 }
2972 else
2973 {
2974 expr_t *iid;
2975 expr_t *sx = get_size_is_expr(type, var->name);
2976
2977 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2978 {
2979 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2980 write_expr( file, iid, 1 );
2981 fprintf( file, ";\n\n" );
2982 }
2983 else if (sx)
2984 {
2985 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long) ");
2986 write_expr(file, sx, 1);
2987 fprintf(file, ";\n\n");
2988 }
2989 if (var->type->ref->type == RPC_FC_IP)