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