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