crypt32: Fix a failing test in Vista.
[wine] / 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         size = sizeof(void *);
827         if (size > *align) *align = size;
828     }
829     else switch (t->type)
830     {
831     case RPC_FC_BYTE:
832     case RPC_FC_CHAR:
833     case RPC_FC_USMALL:
834     case RPC_FC_SMALL:
835         size = 1;
836         if (size > *align) *align = size;
837         break;
838     case RPC_FC_WCHAR:
839     case RPC_FC_USHORT:
840     case RPC_FC_SHORT:
841     case RPC_FC_ENUM16:
842         size = 2;
843         if (size > *align) *align = size;
844         break;
845     case RPC_FC_ULONG:
846     case RPC_FC_LONG:
847     case RPC_FC_ERROR_STATUS_T:
848     case RPC_FC_ENUM32:
849     case RPC_FC_FLOAT:
850         size = 4;
851         if (size > *align) *align = size;
852         break;
853     case RPC_FC_HYPER:
854     case RPC_FC_DOUBLE:
855         size = 8;
856         if (size > *align) *align = size;
857         break;
858     case RPC_FC_STRUCT:
859     case RPC_FC_CVSTRUCT:
860     case RPC_FC_CPSTRUCT:
861     case RPC_FC_CSTRUCT:
862     case RPC_FC_PSTRUCT:
863     case RPC_FC_BOGUS_STRUCT:
864         size = fields_memsize(t->fields_or_args, align);
865         break;
866     case RPC_FC_ENCAPSULATED_UNION:
867     case RPC_FC_NON_ENCAPSULATED_UNION:
868         size = union_memsize(t->fields_or_args, align);
869         break;
870     case RPC_FC_SMFARRAY:
871     case RPC_FC_LGFARRAY:
872     case RPC_FC_SMVARRAY:
873     case RPC_FC_LGVARRAY:
874     case RPC_FC_BOGUS_ARRAY:
875         size = t->dim * type_memsize(t->ref, align);
876         break;
877     default:
878         error("type_memsize: Unknown type %d\n", t->type);
879         size = 0;
880     }
881
882     return size;
883 }
884
885 int is_full_pointer_function(const func_t *func)
886 {
887     const var_t *var;
888     if (type_has_full_pointer(get_func_return_type(func)))
889         return TRUE;
890     if (!func->args)
891         return FALSE;
892     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
893         if (type_has_full_pointer( var->type ))
894             return TRUE;
895     return FALSE;
896 }
897
898 void write_full_pointer_init(FILE *file, int indent, const func_t *func, int is_server)
899 {
900     print_file(file, indent, "_StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,%s);\n",
901                    is_server ? "XLAT_SERVER" : "XLAT_CLIENT");
902     fprintf(file, "\n");
903 }
904
905 void write_full_pointer_free(FILE *file, int indent, const func_t *func)
906 {
907     print_file(file, indent, "NdrFullPointerXlatFree(_StubMsg.FullPtrXlatTables);\n");
908     fprintf(file, "\n");
909 }
910
911 static unsigned int write_nonsimple_pointer(FILE *file, const type_t *type, size_t offset)
912 {
913     short absoff = type->ref->typestring_offset;
914     short reloff = absoff - (offset + 2);
915     int ptr_attr = is_ptr(type->ref) ? 0x10 : 0x0;
916
917     print_file(file, 2, "0x%02x, 0x%x,\t/* %s */\n",
918                type->type, ptr_attr, string_of_type(type->type));
919     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%hd) */\n",
920                reloff, reloff, absoff);
921     return 4;
922 }
923
924 static unsigned int write_simple_pointer(FILE *file, const type_t *type)
925 {
926     unsigned char fc = type->ref->type;
927     /* for historical reasons, write_simple_pointer also handled string types,
928      * but no longer does. catch bad uses of the function with this check */
929     if (is_string_type(type->attrs, type))
930         error("write_simple_pointer: can't handle type %s which is a string type\n", type->name);
931     print_file(file, 2, "0x%02x, 0x8,\t/* %s [simple_pointer] */\n",
932                type->type, string_of_type(type->type));
933     print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
934     print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
935     return 4;
936 }
937
938 static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff)
939 {
940     print_file(file, 0, "/* %u (", tfsoff);
941     write_type_decl(file, t, NULL);
942     print_file(file, 0, ") */\n");
943 }
944
945 static size_t write_pointer_tfs(FILE *file, type_t *type, unsigned int *typestring_offset)
946 {
947     unsigned int offset = *typestring_offset;
948
949     print_start_tfs_comment(file, type, offset);
950     update_tfsoff(type, offset, file);
951
952     if (type->ref->typestring_offset)
953         *typestring_offset += write_nonsimple_pointer(file, type, offset);
954     else if (is_base_type(type->ref->type))
955         *typestring_offset += write_simple_pointer(file, type);
956
957     return offset;
958 }
959
960 static int processed(const type_t *type)
961 {
962     return type->typestring_offset && !type->tfswrite;
963 }
964
965 static int user_type_has_variable_size(const type_t *t)
966 {
967     if (is_ptr(t))
968         return TRUE;
969     else
970         switch (t->type)
971         {
972         case RPC_FC_PSTRUCT:
973         case RPC_FC_CSTRUCT:
974         case RPC_FC_CPSTRUCT:
975         case RPC_FC_CVSTRUCT:
976             return TRUE;
977         }
978     /* Note: Since this only applies to user types, we can't have a conformant
979        array here, and strings should get filed under pointer in this case.  */
980     return FALSE;
981 }
982
983 static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
984 {
985     unsigned int start, absoff, flags;
986     unsigned int align = 0, ualign = 0;
987     const char *name = NULL;
988     type_t *utype = get_user_type(type, &name);
989     size_t usize = user_type_has_variable_size(utype) ? 0 : type_memsize(utype, &ualign);
990     size_t size = type_memsize(type, &align);
991     unsigned short funoff = user_type_offset(name);
992     short reloff;
993
994     guard_rec(type);
995
996     if (is_base_type(utype->type))
997     {
998         absoff = *tfsoff;
999         print_start_tfs_comment(file, utype, absoff);
1000         print_file(file, 2, "0x%x,\t/* %s */\n", utype->type, string_of_type(utype->type));
1001         print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
1002         *tfsoff += 2;
1003     }
1004     else
1005     {
1006         if (!processed(utype))
1007             write_embedded_types(file, NULL, utype, utype->name, TRUE, tfsoff);
1008         absoff = utype->typestring_offset;
1009     }
1010
1011     if (utype->type == RPC_FC_RP)
1012         flags = 0x40;
1013     else if (utype->type == RPC_FC_UP)
1014         flags = 0x80;
1015     else
1016         flags = 0;
1017
1018     start = *tfsoff;
1019     update_tfsoff(type, start, file);
1020     print_start_tfs_comment(file, type, start);
1021     print_file(file, 2, "0x%x,\t/* FC_USER_MARSHAL */\n", RPC_FC_USER_MARSHAL);
1022     print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
1023                flags | (align - 1), align - 1, flags);
1024     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
1025     print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", size, size);
1026     print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize);
1027     *tfsoff += 8;
1028     reloff = absoff - *tfsoff;
1029     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", reloff, reloff, absoff);
1030     *tfsoff += 2;
1031 }
1032
1033 static void write_member_type(FILE *file, const type_t *cont,
1034                               const attr_list_t *attrs, const type_t *type,
1035                               unsigned int *corroff, unsigned int *tfsoff)
1036 {
1037     if (is_embedded_complex(type) && !is_conformant_array(type))
1038     {
1039         size_t absoff;
1040         short reloff;
1041
1042         if (is_union(type->type) && is_attr(attrs, ATTR_SWITCHIS))
1043         {
1044             absoff = *corroff;
1045             *corroff += 8;
1046         }
1047         else
1048         {
1049             absoff = type->typestring_offset;
1050         }
1051         reloff = absoff - (*tfsoff + 2);
1052
1053         print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
1054         /* FIXME: actually compute necessary padding */
1055         print_file(file, 2, "0x0,\t/* FIXME: padding */\n");
1056         print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1057                    reloff, reloff, absoff);
1058         *tfsoff += 4;
1059     }
1060     else if (is_ptr(type) || is_conformant_array(type))
1061     {
1062         unsigned char fc = (cont->type == RPC_FC_BOGUS_STRUCT
1063                             ? RPC_FC_POINTER
1064                             : RPC_FC_LONG);
1065         print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1066         *tfsoff += 1;
1067     }
1068     else if (!write_base_type(file, type, tfsoff))
1069         error("Unsupported member type 0x%x\n", type->type);
1070 }
1071
1072 static void write_end(FILE *file, unsigned int *tfsoff)
1073 {
1074     if (*tfsoff % 2 == 0)
1075     {
1076         print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD);
1077         *tfsoff += 1;
1078     }
1079     print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END);
1080     *tfsoff += 1;
1081 }
1082
1083 static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
1084 {
1085     unsigned int offset = 0;
1086     var_list_t *fs = type->fields_or_args;
1087     var_t *f;
1088
1089     if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
1090     {
1091         unsigned int align = 0;
1092         type_t *ft = f->type;
1093         if (is_union(ft->type) && is_attr(f->attrs, ATTR_SWITCHIS))
1094         {
1095             unsigned int absoff = ft->typestring_offset;
1096             short reloff = absoff - (*tfsoff + 6);
1097             print_file(file, 0, "/* %d */\n", *tfsoff);
1098             print_file(file, 2, "0x%x,\t/* %s */\n", ft->type, string_of_type(ft->type));
1099             print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", RPC_FC_LONG);
1100             write_conf_or_var_desc(file, current_structure, offset, ft,
1101                                    get_attrp(f->attrs, ATTR_SWITCHIS));
1102             print_file(file, 2, "NdrFcShort(%hd),\t/* Offset= %hd (%u) */\n",
1103                        reloff, reloff, absoff);
1104             *tfsoff += 8;
1105         }
1106
1107         /* FIXME: take alignment into account */
1108         offset += type_memsize(ft, &align);
1109     }
1110 }
1111
1112 static int write_no_repeat_pointer_descriptions(
1113     FILE *file, type_t *type,
1114     size_t *offset_in_memory, size_t *offset_in_buffer,
1115     unsigned int *typestring_offset)
1116 {
1117     int written = 0;
1118     unsigned int align;
1119
1120     if (is_ptr(type) || (!type->declarray && is_conformant_array(type)))
1121     {
1122         size_t memsize;
1123
1124         print_file(file, 2, "0x%02x, /* FC_NO_REPEAT */\n", RPC_FC_NO_REPEAT);
1125         print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1126
1127         /* pointer instance */
1128         print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1129         print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1130         *typestring_offset += 6;
1131
1132         if (is_ptr(type))
1133         {
1134             if (is_string_type(type->attrs, type))
1135                 write_string_tfs(file, NULL, type, NULL, typestring_offset);
1136             else
1137                 write_pointer_tfs(file, type, typestring_offset);
1138         }
1139         else
1140         {
1141             unsigned absoff = type->typestring_offset;
1142             short reloff = absoff - (*typestring_offset + 2);
1143             /* FIXME: get pointer attributes from field */
1144             print_file(file, 2, "0x%02x, 0x0,\t/* %s */\n", RPC_FC_UP, "FC_UP");
1145             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1146                        reloff, reloff, absoff);
1147             *typestring_offset += 4;
1148         }
1149
1150         align = 0;
1151         memsize = type_memsize(type, &align);
1152         *offset_in_memory += memsize;
1153         /* increment these separately as in the case of conformant (varying)
1154          * structures these start at different values */
1155         *offset_in_buffer += memsize;
1156
1157         return 1;
1158     }
1159
1160     if (is_non_complex_struct(type))
1161     {
1162         const var_t *v;
1163         LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
1164         {
1165             if (offset_in_memory && offset_in_buffer)
1166             {
1167                 size_t padding;
1168                 align = 0;
1169                 type_memsize(v->type, &align);
1170                 padding = ROUNDING(*offset_in_memory, align);
1171                 *offset_in_memory += padding;
1172                 *offset_in_buffer += padding;
1173             }
1174             written += write_no_repeat_pointer_descriptions(
1175                 file, v->type,
1176                 offset_in_memory, offset_in_buffer, typestring_offset);
1177         }
1178     }
1179     else
1180     {
1181         size_t memsize;
1182         align = 0;
1183         memsize = type_memsize(type, &align);
1184         *offset_in_memory += memsize;
1185         /* increment these separately as in the case of conformant (varying)
1186          * structures these start at different values */
1187         *offset_in_buffer += memsize;
1188     }
1189
1190     return written;
1191 }
1192
1193 static int write_pointer_description_offsets(
1194     FILE *file, const attr_list_t *attrs, type_t *type,
1195     size_t *offset_in_memory, size_t *offset_in_buffer,
1196     unsigned int *typestring_offset)
1197 {
1198     int written = 0;
1199     unsigned int align;
1200
1201     if (is_ptr(type) && type->ref->type != RPC_FC_IP)
1202     {
1203         if (offset_in_memory && offset_in_buffer)
1204         {
1205             size_t memsize;
1206
1207             /* pointer instance */
1208             /* FIXME: sometimes from end of structure, sometimes from beginning */
1209             print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1210             print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1211
1212             align = 0;
1213             memsize = type_memsize(type, &align);
1214             *offset_in_memory += memsize;
1215             /* increment these separately as in the case of conformant (varying)
1216              * structures these start at different values */
1217             *offset_in_buffer += memsize;
1218         }
1219         *typestring_offset += 4;
1220
1221         if (is_string_type(attrs, type))
1222             write_string_tfs(file, NULL, type, NULL, typestring_offset);
1223         else if (processed(type->ref) || is_base_type(type->ref->type))
1224             write_pointer_tfs(file, type, typestring_offset);
1225         else
1226             error("write_pointer_description_offsets: type format string unknown\n");
1227
1228         return 1;
1229     }
1230
1231     if (is_array(type))
1232     {
1233         return write_pointer_description_offsets(
1234             file, attrs, type->ref, offset_in_memory, offset_in_buffer,
1235             typestring_offset);
1236     }
1237     else if (is_non_complex_struct(type))
1238     {
1239         /* otherwise search for interesting fields to parse */
1240         const var_t *v;
1241         LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
1242         {
1243             if (offset_in_memory && offset_in_buffer)
1244             {
1245                 size_t padding;
1246                 align = 0;
1247                 type_memsize(v->type, &align);
1248                 padding = ROUNDING(*offset_in_memory, align);
1249                 *offset_in_memory += padding;
1250                 *offset_in_buffer += padding;
1251             }
1252             written += write_pointer_description_offsets(
1253                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1254                 typestring_offset);
1255         }
1256     }
1257     else
1258     {
1259         if (offset_in_memory && offset_in_buffer)
1260         {
1261             size_t memsize;
1262             align = 0;
1263             memsize = type_memsize(type, &align);
1264             *offset_in_memory += memsize;
1265             /* increment these separately as in the case of conformant (varying)
1266              * structures these start at different values */
1267             *offset_in_buffer += memsize;
1268         }
1269     }
1270
1271     return written;
1272 }
1273
1274 /* Note: if file is NULL return value is number of pointers to write, else
1275  * it is the number of type format characters written */
1276 static int write_fixed_array_pointer_descriptions(
1277     FILE *file, const attr_list_t *attrs, type_t *type,
1278     size_t *offset_in_memory, size_t *offset_in_buffer,
1279     unsigned int *typestring_offset)
1280 {
1281     unsigned int align;
1282     int pointer_count = 0;
1283
1284     if (type->type == RPC_FC_SMFARRAY || type->type == RPC_FC_LGFARRAY)
1285     {
1286         unsigned int temp = 0;
1287         /* unfortunately, this needs to be done in two passes to avoid
1288          * writing out redundant FC_FIXED_REPEAT descriptions */
1289         pointer_count = write_pointer_description_offsets(
1290             NULL, attrs, type->ref, NULL, NULL, &temp);
1291         if (pointer_count > 0)
1292         {
1293             unsigned int increment_size;
1294             size_t offset_of_array_pointer_mem = 0;
1295             size_t offset_of_array_pointer_buf = 0;
1296
1297             align = 0;
1298             increment_size = type_memsize(type->ref, &align);
1299
1300             print_file(file, 2, "0x%02x, /* FC_FIXED_REPEAT */\n", RPC_FC_FIXED_REPEAT);
1301             print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1302             print_file(file, 2, "NdrFcShort(0x%x), /* Iterations = %d */\n", type->dim, type->dim);
1303             print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1304             print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory);
1305             print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1306             *typestring_offset += 10;
1307
1308             pointer_count = write_pointer_description_offsets(
1309                 file, attrs, type, &offset_of_array_pointer_mem,
1310                 &offset_of_array_pointer_buf, typestring_offset);
1311         }
1312     }
1313     else if (is_struct(type->type))
1314     {
1315         const var_t *v;
1316         LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
1317         {
1318             if (offset_in_memory && offset_in_buffer)
1319             {
1320                 size_t padding;
1321                 align = 0;
1322                 type_memsize(v->type, &align);
1323                 padding = ROUNDING(*offset_in_memory, align);
1324                 *offset_in_memory += padding;
1325                 *offset_in_buffer += padding;
1326             }
1327             pointer_count += write_fixed_array_pointer_descriptions(
1328                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1329                 typestring_offset);
1330         }
1331     }
1332     else
1333     {
1334         if (offset_in_memory && offset_in_buffer)
1335         {
1336             size_t memsize;
1337             align = 0;
1338             memsize = type_memsize(type, &align);
1339             *offset_in_memory += memsize;
1340             /* increment these separately as in the case of conformant (varying)
1341              * structures these start at different values */
1342             *offset_in_buffer += memsize;
1343         }
1344     }
1345
1346     return pointer_count;
1347 }
1348
1349 /* Note: if file is NULL return value is number of pointers to write, else
1350  * it is the number of type format characters written */
1351 static int write_conformant_array_pointer_descriptions(
1352     FILE *file, const attr_list_t *attrs, type_t *type,
1353     size_t offset_in_memory, unsigned int *typestring_offset)
1354 {
1355     unsigned int align;
1356     int pointer_count = 0;
1357
1358     if (is_conformant_array(type) && !type->length_is)
1359     {
1360         unsigned int temp = 0;
1361         /* unfortunately, this needs to be done in two passes to avoid
1362          * writing out redundant FC_VARIABLE_REPEAT descriptions */
1363         pointer_count = write_pointer_description_offsets(
1364             NULL, attrs, type->ref, NULL, NULL, &temp);
1365         if (pointer_count > 0)
1366         {
1367             unsigned int increment_size;
1368             size_t offset_of_array_pointer_mem = offset_in_memory;
1369             size_t offset_of_array_pointer_buf = offset_in_memory;
1370
1371             align = 0;
1372             increment_size = type_memsize(type->ref, &align);
1373
1374             if (increment_size > USHRT_MAX)
1375                 error("array size of %u bytes is too large\n", increment_size);
1376
1377             print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
1378             print_file(file, 2, "0x%02x, /* FC_FIXED_OFFSET */\n", RPC_FC_FIXED_OFFSET);
1379             print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1380             print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", offset_in_memory, offset_in_memory);
1381             print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1382             *typestring_offset += 8;
1383
1384             pointer_count = write_pointer_description_offsets(
1385                 file, attrs, type->ref, &offset_of_array_pointer_mem,
1386                 &offset_of_array_pointer_buf, typestring_offset);
1387         }
1388     }
1389
1390     return pointer_count;
1391 }
1392
1393 /* Note: if file is NULL return value is number of pointers to write, else
1394  * it is the number of type format characters written */
1395 static int write_varying_array_pointer_descriptions(
1396     FILE *file, const attr_list_t *attrs, type_t *type,
1397     size_t *offset_in_memory, size_t *offset_in_buffer,
1398     unsigned int *typestring_offset)
1399 {
1400     unsigned int align;
1401     int pointer_count = 0;
1402
1403     if (is_array(type) && type->length_is)
1404     {
1405         unsigned int temp = 0;
1406         /* unfortunately, this needs to be done in two passes to avoid
1407          * writing out redundant FC_VARIABLE_REPEAT descriptions */
1408         pointer_count = write_pointer_description_offsets(
1409             NULL, attrs, type->ref, NULL, NULL, &temp);
1410         if (pointer_count > 0)
1411         {
1412             unsigned int increment_size;
1413
1414             align = 0;
1415             increment_size = type_memsize(type->ref, &align);
1416
1417             if (increment_size > USHRT_MAX)
1418                 error("array size of %u bytes is too large\n", increment_size);
1419
1420             print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
1421             print_file(file, 2, "0x%02x, /* FC_VARIABLE_OFFSET */\n", RPC_FC_VARIABLE_OFFSET);
1422             print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1423             print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory);
1424             print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1425             *typestring_offset += 8;
1426
1427             pointer_count = write_pointer_description_offsets(
1428                 file, attrs, type, offset_in_memory,
1429                 offset_in_buffer, typestring_offset);
1430         }
1431     }
1432     else if (is_struct(type->type))
1433     {
1434         const var_t *v;
1435         LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
1436         {
1437             if (offset_in_memory && offset_in_buffer)
1438             {
1439                 size_t padding;
1440
1441                 if (is_array(v->type) && v->type->length_is)
1442                 {
1443                     *offset_in_buffer = ROUND_SIZE(*offset_in_buffer, 4);
1444                     /* skip over variance and offset in buffer */
1445                     *offset_in_buffer += 8;
1446                 }
1447
1448                 align = 0;
1449                 type_memsize(v->type, &align);
1450                 padding = ROUNDING(*offset_in_memory, align);
1451                 *offset_in_memory += padding;
1452                 *offset_in_buffer += padding;
1453             }
1454             pointer_count += write_varying_array_pointer_descriptions(
1455                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1456                 typestring_offset);
1457         }
1458     }
1459     else
1460     {
1461         if (offset_in_memory && offset_in_buffer)
1462         {
1463             size_t memsize;
1464             align = 0;
1465             memsize = type_memsize(type, &align);
1466             *offset_in_memory += memsize;
1467             /* increment these separately as in the case of conformant (varying)
1468              * structures these start at different values */
1469             *offset_in_buffer += memsize;
1470         }
1471     }
1472
1473     return pointer_count;
1474 }
1475
1476 static void write_pointer_description(FILE *file, type_t *type,
1477                                       unsigned int *typestring_offset)
1478 {
1479     size_t offset_in_buffer;
1480     size_t offset_in_memory;
1481
1482     /* pass 1: search for single instance of a pointer (i.e. don't descend
1483      * into arrays) */
1484     if (!is_array(type))
1485     {
1486         offset_in_memory = 0;
1487         offset_in_buffer = 0;
1488         write_no_repeat_pointer_descriptions(
1489             file, type,
1490             &offset_in_memory, &offset_in_buffer, typestring_offset);
1491     }
1492
1493     /* pass 2: search for pointers in fixed arrays */
1494     offset_in_memory = 0;
1495     offset_in_buffer = 0;
1496     write_fixed_array_pointer_descriptions(
1497         file, NULL, type,
1498         &offset_in_memory, &offset_in_buffer, typestring_offset);
1499
1500     /* pass 3: search for pointers in conformant only arrays (but don't descend
1501      * into conformant varying or varying arrays) */
1502     if ((!type->declarray || !current_structure) && is_conformant_array(type))
1503         write_conformant_array_pointer_descriptions(
1504             file, NULL, type, 0, typestring_offset);
1505     else if (type->type == RPC_FC_CPSTRUCT)
1506     {
1507         unsigned int align = 0;
1508         type_t *carray = find_array_or_string_in_struct(type)->type;
1509         write_conformant_array_pointer_descriptions(
1510             file, NULL, carray,
1511             type_memsize(type, &align),
1512             typestring_offset);
1513     }
1514
1515     /* pass 4: search for pointers in varying arrays */
1516     offset_in_memory = 0;
1517     offset_in_buffer = 0;
1518     write_varying_array_pointer_descriptions(
1519             file, NULL, type,
1520             &offset_in_memory, &offset_in_buffer, typestring_offset);
1521 }
1522
1523 int is_declptr(const type_t *t)
1524 {
1525   return is_ptr(t) || (is_conformant_array(t) && !t->declarray);
1526 }
1527
1528 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
1529                                type_t *type,
1530                                const char *name, unsigned int *typestring_offset)
1531 {
1532     size_t start_offset;
1533     unsigned char rtype;
1534
1535     if (is_declptr(type))
1536     {
1537         unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER;
1538         int pointer_type = is_ptr(type) ? type->type : get_attrv(attrs, ATTR_POINTERTYPE);
1539         if (!pointer_type)
1540             pointer_type = RPC_FC_RP;
1541         print_start_tfs_comment(file, type, *typestring_offset);
1542         print_file(file, 2,"0x%x, 0x%x,\t/* %s%s */\n",
1543                    pointer_type, flag, string_of_type(pointer_type),
1544                    flag ? " [simple_pointer]" : "");
1545         *typestring_offset += 2;
1546         if (!flag)
1547         {
1548             print_file(file, 2, "NdrFcShort(0x2),\n");
1549             *typestring_offset += 2;
1550         }
1551     }
1552
1553     start_offset = *typestring_offset;
1554     update_tfsoff(type, start_offset, file);
1555
1556     rtype = type->ref->type;
1557
1558     if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR))
1559     {
1560         error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
1561         return start_offset;
1562     }
1563
1564     if (type->declarray && !is_conformant_array(type))
1565     {
1566         /* FIXME: multi-dimensional array */
1567         if (0xffffuL < type->dim)
1568             error("array size for parameter %s exceeds %u bytes by %lu bytes\n",
1569                   name, 0xffffu, type->dim - 0xffffu);
1570
1571         if (rtype == RPC_FC_CHAR)
1572             WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
1573         else
1574             WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
1575         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1576         *typestring_offset += 2;
1577
1578         print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", type->dim, type->dim);
1579         *typestring_offset += 2;
1580
1581         return start_offset;
1582     }
1583     else if (type->size_is)
1584     {
1585         unsigned int align = 0;
1586
1587         if (rtype == RPC_FC_CHAR)
1588             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
1589         else
1590             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
1591         print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
1592         *typestring_offset += 2;
1593
1594         *typestring_offset += write_conf_or_var_desc(
1595             file, current_structure,
1596             (type->declarray && current_structure
1597              ? type_memsize(current_structure, &align)
1598              : 0),
1599             type, type->size_is);
1600
1601         return start_offset;
1602     }
1603     else
1604     {
1605         if (rtype == RPC_FC_WCHAR)
1606             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
1607         else
1608             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
1609         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1610         *typestring_offset += 2;
1611
1612         return start_offset;
1613     }
1614 }
1615
1616 static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
1617                               const char *name, unsigned int *typestring_offset)
1618 {
1619     const expr_t *length_is = type->length_is;
1620     const expr_t *size_is = type->size_is;
1621     unsigned int align = 0;
1622     size_t size;
1623     size_t start_offset;
1624     int has_pointer;
1625     int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
1626     unsigned int baseoff
1627         = type->declarray && current_structure
1628         ? type_memsize(current_structure, &align)
1629         : 0;
1630
1631     if (!pointer_type)
1632         pointer_type = RPC_FC_RP;
1633
1634     if (write_embedded_types(file, attrs, type->ref, name, FALSE, typestring_offset))
1635         has_pointer = TRUE;
1636     else
1637         has_pointer = type_has_pointers(type->ref);
1638
1639     align = 0;
1640     size = type_memsize((is_conformant_array(type) ? type->ref : type), &align);
1641
1642     start_offset = *typestring_offset;
1643     update_tfsoff(type, start_offset, file);
1644     print_start_tfs_comment(file, type, start_offset);
1645     print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
1646     print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1647     *typestring_offset += 2;
1648
1649     align = 0;
1650     if (type->type != RPC_FC_BOGUS_ARRAY)
1651     {
1652         unsigned char tc = type->type;
1653
1654         if (tc == RPC_FC_LGFARRAY || tc == RPC_FC_LGVARRAY)
1655         {
1656             print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", size, size);
1657             *typestring_offset += 4;
1658         }
1659         else
1660         {
1661             print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", size, size);
1662             *typestring_offset += 2;
1663         }
1664
1665         if (is_conformant_array(type))
1666             *typestring_offset
1667                 += write_conf_or_var_desc(file, current_structure, baseoff,
1668                                           type, size_is);
1669
1670         if (type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY)
1671         {
1672             unsigned int elalign = 0;
1673             size_t elsize = type_memsize(type->ref, &elalign);
1674
1675             if (type->type == RPC_FC_LGVARRAY)
1676             {
1677                 print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", type->dim, type->dim);
1678                 *typestring_offset += 4;
1679             }
1680             else
1681             {
1682                 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", type->dim, type->dim);
1683                 *typestring_offset += 2;
1684             }
1685
1686             print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", elsize, elsize);
1687             *typestring_offset += 2;
1688         }
1689
1690         if (length_is)
1691             *typestring_offset
1692                 += write_conf_or_var_desc(file, current_structure, baseoff,
1693                                           type, length_is);
1694
1695         if (has_pointer && (!type->declarray || !current_structure))
1696         {
1697             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1698             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1699             *typestring_offset += 2;
1700             write_pointer_description(file, type, typestring_offset);
1701             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1702             *typestring_offset += 1;
1703         }
1704
1705         write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1706         write_end(file, typestring_offset);
1707     }
1708     else
1709     {
1710         unsigned int dim = size_is ? 0 : type->dim;
1711         print_file(file, 2, "NdrFcShort(0x%x),\t/* %u */\n", dim, dim);
1712         *typestring_offset += 2;
1713         *typestring_offset
1714             += write_conf_or_var_desc(file, current_structure, baseoff,
1715                                       type, size_is);
1716         *typestring_offset
1717             += write_conf_or_var_desc(file, current_structure, baseoff,
1718                                       type, length_is);
1719         write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1720         write_end(file, typestring_offset);
1721     }
1722
1723     return start_offset;
1724 }
1725
1726 static const var_t *find_array_or_string_in_struct(const type_t *type)
1727 {
1728     const var_t *last_field;
1729     const type_t *ft;
1730
1731     if (!type->fields_or_args || list_empty(type->fields_or_args))
1732         return NULL;
1733
1734     last_field = LIST_ENTRY( list_tail(type->fields_or_args), const var_t, entry );
1735     ft = last_field->type;
1736
1737     if (ft->declarray && is_conformant_array(ft))
1738         return last_field;
1739
1740     if (ft->type == RPC_FC_CSTRUCT || ft->type == RPC_FC_CPSTRUCT || ft->type == RPC_FC_CVSTRUCT)
1741         return find_array_or_string_in_struct(ft);
1742     else
1743         return NULL;
1744 }
1745
1746 static void write_struct_members(FILE *file, const type_t *type,
1747                                  unsigned int *corroff, unsigned int *typestring_offset)
1748 {
1749     const var_t *field;
1750     unsigned short offset = 0;
1751     int salign = -1;
1752     int padding;
1753
1754     if (type->fields_or_args) LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
1755     {
1756         type_t *ft = field->type;
1757         if (!ft->declarray || !is_conformant_array(ft))
1758         {
1759             unsigned int align = 0;
1760             size_t size = type_memsize(ft, &align);
1761             if (salign == -1)
1762                 salign = align;
1763             if ((align - 1) & offset)
1764             {
1765                 unsigned char fc = 0;
1766                 switch (align)
1767                 {
1768                 case 4:
1769                     fc = RPC_FC_ALIGNM4;
1770                     break;
1771                 case 8:
1772                     fc = RPC_FC_ALIGNM8;
1773                     break;
1774                 default:
1775                     error("write_struct_members: cannot align type %d\n", ft->type);
1776                 }
1777                 print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1778                 offset = ROUND_SIZE(offset, align);
1779                 *typestring_offset += 1;
1780             }
1781             write_member_type(file, type, field->attrs, field->type, corroff,
1782                               typestring_offset);
1783             offset += size;
1784         }
1785     }
1786
1787     padding = ROUNDING(offset, salign);
1788     if (padding)
1789     {
1790         print_file(file, 2, "0x%x,\t/* FC_STRUCTPAD%d */\n",
1791                    RPC_FC_STRUCTPAD1 + padding - 1,
1792                    padding);
1793         *typestring_offset += 1;
1794     }
1795
1796     write_end(file, typestring_offset);
1797 }
1798
1799 static size_t write_struct_tfs(FILE *file, type_t *type,
1800                                const char *name, unsigned int *tfsoff)
1801 {
1802     const type_t *save_current_structure = current_structure;
1803     unsigned int total_size;
1804     const var_t *array;
1805     size_t start_offset;
1806     size_t array_offset;
1807     int has_pointers = 0;
1808     unsigned int align = 0;
1809     unsigned int corroff;
1810     var_t *f;
1811
1812     guard_rec(type);
1813     current_structure = type;
1814
1815     total_size = type_memsize(type, &align);
1816     if (total_size > USHRT_MAX)
1817         error("structure size for %s exceeds %d bytes by %d bytes\n",
1818               name, USHRT_MAX, total_size - USHRT_MAX);
1819
1820     if (type->fields_or_args) LIST_FOR_EACH_ENTRY(f, type->fields_or_args, var_t, entry)
1821         has_pointers |= write_embedded_types(file, f->attrs, f->type, f->name,
1822                                              FALSE, tfsoff);
1823     if (!has_pointers) has_pointers = type_has_pointers(type);
1824
1825     array = find_array_or_string_in_struct(type);
1826     if (array && !processed(array->type))
1827         array_offset
1828             = is_attr(array->attrs, ATTR_STRING)
1829             ? write_string_tfs(file, array->attrs, array->type, array->name, tfsoff)
1830             : write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
1831
1832     corroff = *tfsoff;
1833     write_descriptors(file, type, tfsoff);
1834
1835     start_offset = *tfsoff;
1836     update_tfsoff(type, start_offset, file);
1837     print_start_tfs_comment(file, type, start_offset);
1838     print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
1839     print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1840     print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size);
1841     *tfsoff += 4;
1842
1843     if (array)
1844     {
1845         unsigned int absoff = array->type->typestring_offset;
1846         short reloff = absoff - *tfsoff;
1847         print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1848                    reloff, reloff, absoff);
1849         *tfsoff += 2;
1850     }
1851     else if (type->type == RPC_FC_BOGUS_STRUCT)
1852     {
1853         print_file(file, 2, "NdrFcShort(0x0),\n");
1854         *tfsoff += 2;
1855     }
1856
1857     if (type->type == RPC_FC_BOGUS_STRUCT)
1858     {
1859         /* On the sizing pass, type->ptrdesc may be zero, but it's ok as
1860            nothing is written to file yet.  On the actual writing pass,
1861            this will have been updated.  */
1862         unsigned int absoff = type->ptrdesc ? type->ptrdesc : *tfsoff;
1863         short reloff = absoff - *tfsoff;
1864         print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1865                    reloff, reloff, absoff);
1866         *tfsoff += 2;
1867     }
1868     else if ((type->type == RPC_FC_PSTRUCT) ||
1869              (type->type == RPC_FC_CPSTRUCT) ||
1870              (type->type == RPC_FC_CVSTRUCT && has_pointers))
1871     {
1872         print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1873         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1874         *tfsoff += 2;
1875         write_pointer_description(file, type, tfsoff);
1876         print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1877         *tfsoff += 1;
1878     }
1879
1880     write_struct_members(file, type, &corroff, tfsoff);
1881
1882     if (type->type == RPC_FC_BOGUS_STRUCT)
1883     {
1884         const var_list_t *fs = type->fields_or_args;
1885         const var_t *f;
1886
1887         type->ptrdesc = *tfsoff;
1888         if (fs) LIST_FOR_EACH_ENTRY(f, fs, const var_t, entry)
1889         {
1890             type_t *ft = f->type;
1891             if (is_ptr(ft))
1892             {
1893                 if (is_string_type(f->attrs, ft))
1894                     write_string_tfs(file, f->attrs, ft, f->name, tfsoff);
1895                 else
1896                     write_pointer_tfs(file, ft, tfsoff);
1897             }
1898             else if (!ft->declarray && is_conformant_array(ft))
1899             {
1900                 unsigned int absoff = ft->typestring_offset;
1901                 short reloff = absoff - (*tfsoff + 2);
1902                 int ptr_type = get_attrv(f->attrs, ATTR_POINTERTYPE);
1903                 /* FIXME: We need to store pointer attributes for arrays
1904                    so we don't lose pointer_default info.  */
1905                 if (ptr_type == 0)
1906                     ptr_type = RPC_FC_UP;
1907                 print_file(file, 0, "/* %d */\n", *tfsoff);
1908                 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
1909                            string_of_type(ptr_type));
1910                 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1911                            reloff, reloff, absoff);
1912                 *tfsoff += 4;
1913             }
1914         }
1915         if (type->ptrdesc == *tfsoff)
1916             type->ptrdesc = 0;
1917     }
1918
1919     current_structure = save_current_structure;
1920     return start_offset;
1921 }
1922
1923 static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
1924                                      unsigned char flags, size_t offset,
1925                                      unsigned int *typeformat_offset)
1926 {
1927     size_t start_offset = *typeformat_offset;
1928     short reloff = offset - (*typeformat_offset + 2);
1929     int in_attr, out_attr;
1930     in_attr = is_attr(attrs, ATTR_IN);
1931     out_attr = is_attr(attrs, ATTR_OUT);
1932     if (!in_attr && !out_attr) in_attr = 1;
1933
1934     if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
1935         flags |= 0x04;
1936
1937     print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
1938                pointer_type,
1939                flags,
1940                string_of_type(pointer_type));
1941     if (file)
1942     {
1943         if (flags & 0x04)
1944             fprintf(file, " [allocated_on_stack]");
1945         if (flags & 0x10)
1946             fprintf(file, " [pointer_deref]");
1947         fprintf(file, " */\n");
1948     }
1949
1950     print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", reloff, offset);
1951     *typeformat_offset += 4;
1952
1953     return start_offset;
1954 }
1955
1956 static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
1957 {
1958     if (t == NULL)
1959     {
1960         print_file(file, 2, "NdrFcShort(0x0),\t/* No type */\n");
1961     }
1962     else if (is_base_type(t->type))
1963     {
1964         print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n",
1965                    t->type, string_of_type(t->type));
1966     }
1967     else if (t->typestring_offset)
1968     {
1969         short reloff = t->typestring_offset - *tfsoff;
1970         print_file(file, 2, "NdrFcShort(0x%x),\t/* Offset= %d (%d) */\n",
1971                    reloff, reloff, t->typestring_offset);
1972     }
1973     else
1974         error("write_branch_type: type unimplemented (0x%x)\n", t->type);
1975
1976     *tfsoff += 2;
1977 }
1978
1979 static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
1980 {
1981     unsigned int align = 0;
1982     unsigned int start_offset;
1983     size_t size = type_memsize(type, &align);
1984     var_list_t *fields;
1985     size_t nbranch = 0;
1986     type_t *deftype = NULL;
1987     short nodeftype = 0xffff;
1988     var_t *f;
1989
1990     guard_rec(type);
1991
1992     if (type->type == RPC_FC_ENCAPSULATED_UNION)
1993     {
1994         const var_t *uv = LIST_ENTRY(list_tail(type->fields_or_args), const var_t, entry);
1995         fields = uv->type->fields_or_args;
1996     }
1997     else
1998         fields = type->fields_or_args;
1999
2000     if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
2001     {
2002         expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
2003         if (cases)
2004             nbranch += list_count(cases);
2005         if (f->type)
2006             write_embedded_types(file, f->attrs, f->type, f->name, TRUE, tfsoff);
2007     }
2008
2009     start_offset = *tfsoff;
2010     update_tfsoff(type, start_offset, file);
2011     print_start_tfs_comment(file, type, start_offset);
2012     if (type->type == RPC_FC_ENCAPSULATED_UNION)
2013     {
2014         const var_t *sv = LIST_ENTRY(list_head(type->fields_or_args), const var_t, entry);
2015         const type_t *st = sv->type;
2016
2017         switch (st->type)
2018         {
2019         case RPC_FC_CHAR:
2020         case RPC_FC_SMALL:
2021         case RPC_FC_USMALL:
2022         case RPC_FC_SHORT:
2023         case RPC_FC_USHORT:
2024         case RPC_FC_LONG:
2025         case RPC_FC_ULONG:
2026         case RPC_FC_ENUM16:
2027         case RPC_FC_ENUM32:
2028             print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
2029             print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
2030                        0x40 | st->type, string_of_type(st->type));
2031             *tfsoff += 2;
2032             break;
2033         default:
2034             error("union switch type must be an integer, char, or enum\n");
2035         }
2036     }
2037     else if (is_attr(type->attrs, ATTR_SWITCHTYPE))
2038     {
2039         static const expr_t dummy_expr;  /* FIXME */
2040         const type_t *st = get_attrp(type->attrs, ATTR_SWITCHTYPE);
2041
2042         switch (st->type)
2043         {
2044         case RPC_FC_CHAR:
2045         case RPC_FC_SMALL:
2046         case RPC_FC_USMALL:
2047         case RPC_FC_SHORT:
2048         case RPC_FC_USHORT:
2049         case RPC_FC_LONG:
2050         case RPC_FC_ULONG:
2051         case RPC_FC_ENUM16:
2052         case RPC_FC_ENUM32:
2053             print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
2054             print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
2055                        st->type, string_of_type(st->type));
2056             *tfsoff += 2;
2057             break;
2058         default:
2059             error("union switch type must be an integer, char, or enum\n");
2060         }
2061
2062         *tfsoff += write_conf_or_var_desc(file, NULL, *tfsoff, st, &dummy_expr );
2063     }
2064
2065     print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", size, size);
2066     print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", nbranch, nbranch);
2067     *tfsoff += 4;
2068
2069     if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
2070     {
2071         type_t *ft = f->type;
2072         expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
2073         int deflt = is_attr(f->attrs, ATTR_DEFAULT);
2074         expr_t *c;
2075
2076         if (cases == NULL && !deflt)
2077             error("union field %s with neither case nor default attribute\n", f->name);
2078
2079         if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry)
2080         {
2081             /* MIDL doesn't check for duplicate cases, even though that seems
2082                like a reasonable thing to do, it just dumps them to the TFS
2083                like we're going to do here.  */
2084             print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
2085             *tfsoff += 4;
2086             write_branch_type(file, ft, tfsoff);
2087         }
2088
2089         /* MIDL allows multiple default branches, even though that seems
2090            illogical, it just chooses the last one, which is what we will
2091            do.  */
2092         if (deflt)
2093         {
2094             deftype = ft;
2095             nodeftype = 0;
2096         }
2097     }
2098
2099     if (deftype)
2100     {
2101         write_branch_type(file, deftype, tfsoff);
2102     }
2103     else
2104     {
2105         print_file(file, 2, "NdrFcShort(0x%x),\n", nodeftype);
2106         *tfsoff += 2;
2107     }
2108
2109     return start_offset;
2110 }
2111
2112 static size_t write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
2113                            unsigned int *typeformat_offset)
2114 {
2115     size_t i;
2116     size_t start_offset = *typeformat_offset;
2117     expr_t *iid = get_attrp(attrs, ATTR_IIDIS);
2118
2119     if (iid)
2120     {
2121         print_file(file, 2, "0x2f,  /* FC_IP */\n");
2122         print_file(file, 2, "0x5c,  /* FC_PAD */\n");
2123         *typeformat_offset
2124             += write_conf_or_var_desc(file, NULL, 0, type, iid) + 2;
2125     }
2126     else
2127     {
2128         const type_t *base = is_ptr(type) ? type->ref : type;
2129         const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
2130
2131         if (! uuid)
2132             error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
2133
2134         update_tfsoff(type, start_offset, file);
2135         print_start_tfs_comment(file, type, start_offset);
2136         print_file(file, 2, "0x2f,\t/* FC_IP */\n");
2137         print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
2138         print_file(file, 2, "NdrFcLong(0x%08lx),\n", uuid->Data1);
2139         print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2);
2140         print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3);
2141         for (i = 0; i < 8; ++i)
2142             print_file(file, 2, "0x%02x,\n", uuid->Data4[i]);
2143
2144         if (file)
2145             fprintf(file, "\n");
2146
2147         *typeformat_offset += 18;
2148     }
2149     return start_offset;
2150 }
2151
2152 static size_t write_contexthandle_tfs(FILE *file, const type_t *type,
2153                                       const var_t *var,
2154                                       unsigned int *typeformat_offset)
2155 {
2156     size_t start_offset = *typeformat_offset;
2157     unsigned char flags = 0;
2158
2159     if (is_attr(current_iface->attrs, ATTR_STRICTCONTEXTHANDLE))
2160         flags |= NDR_STRICT_CONTEXT_HANDLE;
2161
2162     if (is_ptr(type))
2163         flags |= 0x80;
2164     if (is_attr(var->attrs, ATTR_IN))
2165     {
2166         flags |= 0x40;
2167         if (!is_attr(var->attrs, ATTR_OUT))
2168             flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
2169     }
2170     if (is_attr(var->attrs, ATTR_OUT))
2171         flags |= 0x20;
2172
2173     WRITE_FCTYPE(file, FC_BIND_CONTEXT, *typeformat_offset);
2174     print_file(file, 2, "0x%x,\t/* Context flags: ", flags);
2175     /* return and can't be null values overlap */
2176     if (((flags & 0x21) != 0x21) && (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL))
2177         print_file(file, 0, "can't be null, ");
2178     if (flags & NDR_CONTEXT_HANDLE_SERIALIZE)
2179         print_file(file, 0, "serialize, ");
2180     if (flags & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
2181         print_file(file, 0, "no serialize, ");
2182     if (flags & NDR_STRICT_CONTEXT_HANDLE)
2183         print_file(file, 0, "strict, ");
2184     if ((flags & 0x21) == 0x20)
2185         print_file(file, 0, "out, ");
2186     if ((flags & 0x21) == 0x21)
2187         print_file(file, 0, "return, ");
2188     if (flags & 0x40)
2189         print_file(file, 0, "in, ");
2190     if (flags & 0x80)
2191         print_file(file, 0, "via ptr, ");
2192     print_file(file, 0, "*/\n");
2193     print_file(file, 2, "0, /* FIXME: rundown routine index*/\n");
2194     print_file(file, 2, "0, /* FIXME: param num */\n");
2195     *typeformat_offset += 4;
2196
2197     return start_offset;
2198 }
2199
2200 static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *func,
2201                                          type_t *type, const var_t *var,
2202                                          unsigned int *typeformat_offset)
2203 {
2204     size_t offset;
2205
2206     if (is_context_handle(type))
2207         return write_contexthandle_tfs(file, type, var, typeformat_offset);
2208
2209     if (is_user_type(type))
2210     {
2211         write_user_tfs(file, type, typeformat_offset);
2212         return type->typestring_offset;
2213     }
2214
2215     if (is_string_type(var->attrs, type))
2216         return write_string_tfs(file, var->attrs, type, var->name, typeformat_offset);
2217
2218     if (is_array(type))
2219     {
2220         int ptr_type;
2221         size_t off;
2222         off = write_array_tfs(file, var->attrs, type, var->name, typeformat_offset);
2223         ptr_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2224         /* Top level pointers to conformant arrays may be handled specially
2225            since we can bypass the pointer, but if the array is buried
2226            beneath another pointer (e.g., "[size_is(,n)] int **p" then we
2227            always need to write the pointer.  */
2228         if (!ptr_type && var->type != type)
2229           /* FIXME:  This should use pointer_default, but the information
2230              isn't kept around for arrays.  */
2231           ptr_type = RPC_FC_UP;
2232         if (ptr_type && ptr_type != RPC_FC_RP)
2233         {
2234             unsigned int absoff = type->typestring_offset;
2235             short reloff = absoff - (*typeformat_offset + 2);
2236             off = *typeformat_offset;
2237             print_file(file, 0, "/* %d */\n", off);
2238             print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
2239                        string_of_type(ptr_type));
2240             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
2241                        reloff, reloff, absoff);
2242             *typeformat_offset += 4;
2243         }
2244         return off;
2245     }
2246
2247     if (!is_ptr(type))
2248     {
2249         /* basic types don't need a type format string */
2250         if (is_base_type(type->type))
2251             return 0;
2252
2253         switch (type->type)
2254         {
2255         case RPC_FC_STRUCT:
2256         case RPC_FC_PSTRUCT:
2257         case RPC_FC_CSTRUCT:
2258         case RPC_FC_CPSTRUCT:
2259         case RPC_FC_CVSTRUCT:
2260         case RPC_FC_BOGUS_STRUCT:
2261             return write_struct_tfs(file, type, var->name, typeformat_offset);
2262         case RPC_FC_ENCAPSULATED_UNION:
2263         case RPC_FC_NON_ENCAPSULATED_UNION:
2264             return write_union_tfs(file, type, typeformat_offset);
2265         case RPC_FC_IGNORE:
2266         case RPC_FC_BIND_PRIMITIVE:
2267             /* nothing to do */
2268             return 0;
2269         default:
2270             error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
2271         }
2272     }
2273     else if (last_ptr(type))
2274     {
2275         size_t start_offset = *typeformat_offset;
2276         int in_attr = is_attr(var->attrs, ATTR_IN);
2277         int out_attr = is_attr(var->attrs, ATTR_OUT);
2278         const type_t *base = type->ref;
2279
2280         if (base->type == RPC_FC_IP
2281             || (base->type == 0
2282                 && is_attr(var->attrs, ATTR_IIDIS)))
2283         {
2284             return write_ip_tfs(file, var->attrs, type, typeformat_offset);
2285         }
2286
2287         /* special case for pointers to base types */
2288         if (is_base_type(base->type))
2289         {
2290             print_file(file, indent, "0x%x, 0x%x,    /* %s %s[simple_pointer] */\n",
2291                        type->type, (!in_attr && out_attr) ? 0x0C : 0x08,
2292                        string_of_type(type->type),
2293                        (!in_attr && out_attr) ? "[allocated_on_stack] " : "");
2294             print_file(file, indent, "0x%02x,    /* %s */\n", base->type, string_of_type(base->type));
2295             print_file(file, indent, "0x5c,          /* FC_PAD */\n");
2296             *typeformat_offset += 4;
2297             return start_offset;
2298         }
2299     }
2300
2301     assert(is_ptr(type));
2302
2303     offset = write_typeformatstring_var(file, indent, func, type->ref, var, typeformat_offset);
2304     if (file)
2305         fprintf(file, "/* %2u */\n", *typeformat_offset);
2306     return write_pointer_only_tfs(file, var->attrs, type->type,
2307                            !last_ptr(type) ? 0x10 : 0,
2308                            offset, typeformat_offset);
2309 }
2310
2311 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
2312                                 const char *name, int write_ptr, unsigned int *tfsoff)
2313 {
2314     int retmask = 0;
2315
2316     if (is_user_type(type))
2317     {
2318         write_user_tfs(file, type, tfsoff);
2319     }
2320     else if (is_string_type(attrs, type))
2321     {
2322         write_string_tfs(file, attrs, type, name, tfsoff);
2323     }
2324     else if (is_ptr(type))
2325     {
2326         type_t *ref = type->ref;
2327
2328         if (ref->type == RPC_FC_IP
2329             || (ref->type == 0
2330                 && is_attr(attrs, ATTR_IIDIS)))
2331         {
2332             write_ip_tfs(file, attrs, type, tfsoff);
2333         }
2334         else
2335         {
2336             if (!processed(ref) && !is_base_type(ref->type))
2337                 retmask |= write_embedded_types(file, NULL, ref, name, TRUE, tfsoff);
2338
2339             if (write_ptr)
2340                 write_pointer_tfs(file, type, tfsoff);
2341
2342             retmask |= 1;
2343         }
2344     }
2345     else if (type->declarray && is_conformant_array(type))
2346         ;    /* conformant arrays and strings are handled specially */
2347     else if (is_array(type))
2348     {
2349         write_array_tfs(file, attrs, type, name, tfsoff);
2350         if (is_conformant_array(type))
2351             retmask |= 1;
2352     }
2353     else if (is_struct(type->type))
2354     {
2355         if (!processed(type))
2356             write_struct_tfs(file, type, name, tfsoff);
2357     }
2358     else if (is_union(type->type))
2359     {
2360         if (!processed(type))
2361             write_union_tfs(file, type, tfsoff);
2362     }
2363     else if (!is_base_type(type->type))
2364         error("write_embedded_types: unknown embedded type for %s (0x%x)\n",
2365               name, type->type);
2366
2367     return retmask;
2368 }
2369
2370 static size_t process_tfs_stmts(FILE *file, const statement_list_t *stmts,
2371                                 type_pred_t pred, unsigned int *typeformat_offset)
2372 {
2373     const var_t *var;
2374     const statement_t *stmt;
2375
2376     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
2377     {
2378         const type_t *iface;
2379         if (stmt->type == STMT_LIBRARY)
2380         {
2381             process_tfs_stmts(file, stmt->u.lib->stmts, pred, typeformat_offset);
2382             continue;
2383         }
2384         else if (stmt->type != STMT_TYPE || stmt->u.type->type != RPC_FC_IP)
2385             continue;
2386
2387         iface = stmt->u.type;
2388         if (!pred(iface))
2389             continue;
2390
2391         if (iface->funcs)
2392         {
2393             const func_t *func;
2394             current_iface = iface;
2395             LIST_FOR_EACH_ENTRY( func, iface->funcs, const func_t, entry )
2396             {
2397                 if (is_local(func->def->attrs)) continue;
2398
2399                 if (!is_void(get_func_return_type(func)))
2400                 {
2401                     var_t v = *func->def;
2402                     v.type = get_func_return_type(func);
2403                     update_tfsoff(get_func_return_type(func),
2404                                   write_typeformatstring_var(
2405                                       file, 2, NULL, get_func_return_type(func),
2406                                       &v, typeformat_offset),
2407                                   file);
2408                 }
2409
2410                 current_func = func;
2411                 if (func->args)
2412                     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2413                         update_tfsoff(
2414                             var->type,
2415                             write_typeformatstring_var(
2416                                 file, 2, func, var->type, var,
2417                                 typeformat_offset),
2418                             file);
2419             }
2420         }
2421     }
2422
2423     return *typeformat_offset + 1;
2424 }
2425
2426 static size_t process_tfs(FILE *file, const statement_list_t *stmts, type_pred_t pred)
2427 {
2428     unsigned int typeformat_offset = 2;
2429
2430     return process_tfs_stmts(file, stmts, pred, &typeformat_offset);
2431 }
2432
2433
2434 void write_typeformatstring(FILE *file, const statement_list_t *stmts, type_pred_t pred)
2435 {
2436     int indent = 0;
2437
2438     print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
2439     print_file(file, indent, "{\n");
2440     indent++;
2441     print_file(file, indent, "0,\n");
2442     print_file(file, indent, "{\n");
2443     indent++;
2444     print_file(file, indent, "NdrFcShort(0x0),\n");
2445
2446     set_all_tfswrite(TRUE);
2447     process_tfs(file, stmts, pred);
2448
2449     print_file(file, indent, "0x0\n");
2450     indent--;
2451     print_file(file, indent, "}\n");
2452     indent--;
2453     print_file(file, indent, "};\n");
2454     print_file(file, indent, "\n");
2455 }
2456
2457 static unsigned int get_required_buffer_size_type(
2458     const type_t *type, const char *name, unsigned int *alignment)
2459 {
2460     const char *uname;
2461     const type_t *utype;
2462
2463     *alignment = 0;
2464     if ((utype = get_user_type(type, &uname)))
2465     {
2466         return get_required_buffer_size_type(utype, uname, alignment);
2467     }
2468     else
2469     {
2470         switch (type->type)
2471         {
2472         case RPC_FC_BYTE:
2473         case RPC_FC_CHAR:
2474         case RPC_FC_USMALL:
2475         case RPC_FC_SMALL:
2476             *alignment = 4;
2477             return 1;
2478
2479         case RPC_FC_WCHAR:
2480         case RPC_FC_USHORT:
2481         case RPC_FC_SHORT:
2482         case RPC_FC_ENUM16:
2483             *alignment = 4;
2484             return 2;
2485
2486         case RPC_FC_ULONG:
2487         case RPC_FC_LONG:
2488         case RPC_FC_ENUM32:
2489         case RPC_FC_FLOAT:
2490         case RPC_FC_ERROR_STATUS_T:
2491             *alignment = 4;
2492             return 4;
2493
2494         case RPC_FC_HYPER:
2495         case RPC_FC_DOUBLE:
2496             *alignment = 8;
2497             return 8;
2498
2499         case RPC_FC_IGNORE:
2500         case RPC_FC_BIND_PRIMITIVE:
2501             return 0;
2502
2503         case RPC_FC_STRUCT:
2504         case RPC_FC_PSTRUCT:
2505         {
2506             size_t size = 0;
2507             const var_t *field;
2508             if (!type->fields_or_args) return 0;
2509             LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
2510             {
2511                 unsigned int alignment;
2512                 size += get_required_buffer_size_type(field->type, field->name,
2513                                                       &alignment);
2514             }
2515             return size;
2516         }
2517
2518         case RPC_FC_RP:
2519             return
2520                 is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT
2521                 ? get_required_buffer_size_type( type->ref, name, alignment )
2522                 : 0;
2523
2524         case RPC_FC_SMFARRAY:
2525         case RPC_FC_LGFARRAY:
2526             return type->dim * get_required_buffer_size_type(type->ref, name, alignment);
2527
2528         default:
2529             return 0;
2530         }
2531     }
2532 }
2533
2534 static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
2535 {
2536     int in_attr = is_attr(var->attrs, ATTR_IN);
2537     int out_attr = is_attr(var->attrs, ATTR_OUT);
2538     const type_t *t;
2539
2540     if (!in_attr && !out_attr)
2541         in_attr = 1;
2542
2543     *alignment = 0;
2544
2545     for (t = var->type; is_ptr(t); t = t->ref)
2546         if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
2547         {
2548             *alignment = 4;
2549             return 20;
2550         }
2551
2552     if (pass == PASS_OUT)
2553     {
2554         if (out_attr && is_ptr(var->type))
2555         {
2556             type_t *type = var->type;
2557
2558             if (type->type == RPC_FC_STRUCT)
2559             {
2560                 const var_t *field;
2561                 unsigned int size = 36;
2562
2563                 if (!type->fields_or_args) return size;
2564                 LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
2565                 {
2566                     unsigned int align;
2567                     size += get_required_buffer_size_type(
2568                         field->type, field->name, &align);
2569                 }
2570                 return size;
2571             }
2572         }
2573         return 0;
2574     }
2575     else
2576     {
2577         if ((!out_attr || in_attr) && !var->type->size_is
2578             && !is_attr(var->attrs, ATTR_STRING) && !var->type->declarray)
2579         {
2580             if (is_ptr(var->type))
2581             {
2582                 type_t *type = var->type;
2583
2584                 if (is_base_type(type->type))
2585                 {
2586                     return 25;
2587                 }
2588                 else if (type->type == RPC_FC_STRUCT)
2589                 {
2590                     unsigned int size = 36;
2591                     const var_t *field;
2592
2593                     if (!type->fields_or_args) return size;
2594                     LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
2595                     {
2596                         unsigned int align;
2597                         size += get_required_buffer_size_type(
2598                             field->type, field->name, &align);
2599                     }
2600                     return size;
2601                 }
2602             }
2603         }
2604
2605         return get_required_buffer_size_type(var->type, var->name, alignment);
2606     }
2607 }
2608
2609 static unsigned int get_function_buffer_size( const func_t *func, enum pass pass )
2610 {
2611     const var_t *var;
2612     unsigned int total_size = 0, alignment;
2613
2614     if (func->args)
2615     {
2616         LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2617         {
2618             total_size += get_required_buffer_size(var, &alignment, pass);
2619             total_size += alignment;
2620         }
2621     }
2622
2623     if (pass == PASS_OUT && !is_void(get_func_return_type(func)))
2624     {
2625         var_t v = *func->def;
2626         v.type = get_func_return_type(func);
2627         total_size += get_required_buffer_size(&v, &alignment, PASS_RETURN);
2628         total_size += alignment;
2629     }
2630     return total_size;
2631 }
2632
2633 static void print_phase_function(FILE *file, int indent, const char *type,
2634                                  enum remoting_phase phase,
2635                                  const var_t *var, unsigned int type_offset)
2636 {
2637     const char *function;
2638     switch (phase)
2639     {
2640     case PHASE_BUFFERSIZE:
2641         function = "BufferSize";
2642         break;
2643     case PHASE_MARSHAL:
2644         function = "Marshall";
2645         break;
2646     case PHASE_UNMARSHAL:
2647         function = "Unmarshall";
2648         break;
2649     case PHASE_FREE:
2650         function = "Free";
2651         break;
2652     default:
2653         assert(0);
2654         return;
2655     }
2656
2657     print_file(file, indent, "Ndr%s%s(\n", type, function);
2658     indent++;
2659     print_file(file, indent, "&_StubMsg,\n");
2660     print_file(file, indent, "%s%s%s%s,\n",
2661                (phase == PHASE_UNMARSHAL) ? "(unsigned char **)" : "(unsigned char *)",
2662                (phase == PHASE_UNMARSHAL || decl_indirect(var->type)) ? "&" : "",
2663                (phase == PHASE_UNMARSHAL && decl_indirect(var->type)) ? "_p_" : "",
2664                var->name);
2665     print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
2666                type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
2667     if (phase == PHASE_UNMARSHAL)
2668         print_file(file, indent, "0);\n");
2669     indent--;
2670 }
2671
2672 void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
2673                           enum pass pass, const var_t *var,
2674                           const char *varname)
2675 {
2676     type_t *type = var->type;
2677     unsigned int size;
2678     unsigned int alignment = 0;
2679     unsigned char rtype;
2680
2681     /* no work to do for other phases, buffer sizing is done elsewhere */
2682     if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
2683         return;
2684
2685     rtype = is_ptr(type) ? type->ref->type : type->type;
2686
2687     switch (rtype)
2688     {
2689         case RPC_FC_BYTE:
2690         case RPC_FC_CHAR:
2691         case RPC_FC_SMALL:
2692         case RPC_FC_USMALL:
2693             size = 1;
2694             alignment = 1;
2695             break;
2696
2697         case RPC_FC_WCHAR:
2698         case RPC_FC_USHORT:
2699         case RPC_FC_SHORT:
2700         case RPC_FC_ENUM16:
2701             size = 2;
2702             alignment = 2;
2703             break;
2704
2705         case RPC_FC_ULONG:
2706         case RPC_FC_LONG:
2707         case RPC_FC_ENUM32:
2708         case RPC_FC_FLOAT:
2709         case RPC_FC_ERROR_STATUS_T:
2710             size = 4;
2711             alignment = 4;
2712             break;
2713
2714         case RPC_FC_HYPER:
2715         case RPC_FC_DOUBLE:
2716             size = 8;
2717             alignment = 8;
2718             break;
2719
2720         case RPC_FC_IGNORE:
2721         case RPC_FC_BIND_PRIMITIVE:
2722             /* no marshalling needed */
2723             return;
2724
2725         default:
2726             error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, rtype);
2727             size = 0;
2728     }
2729
2730     if (phase == PHASE_MARSHAL)
2731         print_file(file, indent, "MIDL_memset(_StubMsg.Buffer, 0, (0x%x - (long)_StubMsg.Buffer) & 0x%x);\n", alignment, alignment - 1);
2732     print_file(file, indent, "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
2733                 alignment - 1, alignment - 1);
2734
2735     if (phase == PHASE_MARSHAL)
2736     {
2737         print_file(file, indent, "*(");
2738         write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2739         if (is_ptr(type))
2740             fprintf(file, " *)_StubMsg.Buffer = *");
2741         else
2742             fprintf(file, " *)_StubMsg.Buffer = ");
2743         fprintf(file, "%s", varname);
2744         fprintf(file, ";\n");
2745     }
2746     else if (phase == PHASE_UNMARSHAL)
2747     {
2748         print_file(file, indent, "if (_StubMsg.Buffer + sizeof(");
2749         write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2750         fprintf(file, ") > _StubMsg.BufferEnd)\n");
2751         print_file(file, indent, "{\n");
2752         print_file(file, indent + 1, "RpcRaiseException(RPC_X_BAD_STUB_DATA);\n");
2753         print_file(file, indent, "}\n");
2754         if (pass == PASS_IN || pass == PASS_RETURN)
2755             print_file(file, indent, "");
2756         else
2757             print_file(file, indent, "*");
2758         fprintf(file, "%s", varname);
2759         if (pass == PASS_IN && is_ptr(type))
2760             fprintf(file, " = (");
2761         else
2762             fprintf(file, " = *(");
2763         write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2764         fprintf(file, " *)_StubMsg.Buffer;\n");
2765     }
2766
2767     print_file(file, indent, "_StubMsg.Buffer += sizeof(");
2768     write_type_decl(file, var->type, NULL);
2769     fprintf(file, ");\n");
2770 }
2771
2772 /* returns whether the MaxCount, Offset or ActualCount members need to be
2773  * filled in for the specified phase */
2774 static inline int is_conformance_needed_for_phase(enum remoting_phase phase)
2775 {
2776     return (phase != PHASE_UNMARSHAL);
2777 }
2778
2779 expr_t *get_size_is_expr(const type_t *t, const char *name)
2780 {
2781     expr_t *x = NULL;
2782
2783     for ( ; is_ptr(t) || is_array(t); t = t->ref)
2784         if (t->size_is)
2785         {
2786             if (!x)
2787                 x = t->size_is;
2788             else
2789                 error("%s: multidimensional conformant"
2790                       " arrays not supported at the top level\n",
2791                       name);
2792         }
2793
2794     return x;
2795 }
2796
2797 static void write_parameter_conf_or_var_exprs(FILE *file, int indent,
2798                                               enum remoting_phase phase,
2799                                               const var_t *var)
2800 {
2801     const type_t *type = var->type;
2802     /* get fundamental type for the argument */
2803     for (;;)
2804     {
2805         if (is_attr(type->attrs, ATTR_WIREMARSHAL))
2806             break;
2807         else if (is_attr(type->attrs, ATTR_CONTEXTHANDLE))
2808             break;
2809         else if (is_array(type) || is_string_type(var->attrs, type))
2810         {
2811             if (is_conformance_needed_for_phase(phase))
2812             {
2813                 if (type->size_is)
2814                 {
2815                     print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2816                     write_expr(file, type->size_is, 1, 1, NULL, NULL);
2817                     fprintf(file, ";\n\n");
2818                 }
2819                 if (type->length_is)
2820                 {
2821                     print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2822                                print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2823                                write_expr(file, type->length_is, 1, 1, NULL, NULL);
2824                                fprintf(file, ";\n\n");
2825                 }
2826             }
2827             break;
2828         }
2829         else if (type->type == RPC_FC_NON_ENCAPSULATED_UNION)
2830         {
2831             if (is_conformance_needed_for_phase(phase))
2832             {
2833                 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2834                 write_expr(file, get_attrp(var->attrs, ATTR_SWITCHIS), 1, 1, NULL, NULL);
2835                 fprintf(file, ";\n\n");
2836             }
2837             break;
2838         }
2839         else if (type->type == RPC_FC_IP)
2840         {
2841             expr_t *iid;
2842
2843             if (is_conformance_needed_for_phase(phase) && (iid = get_attrp( var->attrs, ATTR_IIDIS )))
2844             {
2845                 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2846                 write_expr( file, iid, 1, 1, NULL, NULL );
2847                 fprintf( file, ";\n\n" );
2848             }
2849             break;
2850         }
2851         else if (is_ptr(type))
2852             type = type->ref;
2853         else
2854             break;
2855     }
2856 }
2857
2858 static void write_remoting_arg(FILE *file, int indent, const func_t *func,
2859                               enum pass pass, enum remoting_phase phase,
2860                               const var_t *var)
2861 {
2862     int in_attr, out_attr, pointer_type;
2863     const type_t *type = var->type;
2864     unsigned char rtype;
2865     size_t start_offset = type->typestring_offset;
2866
2867     pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2868     if (!pointer_type)
2869         pointer_type = RPC_FC_RP;
2870
2871     in_attr = is_attr(var->attrs, ATTR_IN);
2872     out_attr = is_attr(var->attrs, ATTR_OUT);
2873     if (!in_attr && !out_attr)
2874         in_attr = 1;
2875
2876     if (phase != PHASE_FREE)
2877         switch (pass)
2878         {
2879         case PASS_IN:
2880             if (!in_attr) return;
2881             break;
2882         case PASS_OUT:
2883             if (!out_attr) return;
2884             break;
2885         case PASS_RETURN:
2886             break;
2887         }
2888
2889     write_parameter_conf_or_var_exprs(file, indent, phase, var);
2890     rtype = type->type;
2891
2892     if (is_context_handle(type))
2893     {
2894         if (phase == PHASE_MARSHAL)
2895         {
2896             if (pass == PASS_IN)
2897             {
2898                 /* if the context_handle attribute appears in the chain of types
2899                  * without pointers being followed, then the context handle must
2900                  * be direct, otherwise it is a pointer */
2901                 int is_ch_ptr = is_aliaschain_attr(type, ATTR_CONTEXTHANDLE) ? FALSE : TRUE;
2902                 print_file(file, indent, "NdrClientContextMarshall(\n");
2903                 print_file(file, indent + 1, "&_StubMsg,\n");
2904                 print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ch_ptr ? "*" : "", var->name);
2905                 print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
2906             }
2907             else
2908             {
2909                 print_file(file, indent, "NdrServerContextNewMarshall(\n");
2910                 print_file(file, indent + 1, "&_StubMsg,\n");
2911                 print_file(file, indent + 1, "(NDR_SCONTEXT)%s,\n", var->name);
2912                 print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown,\n", get_context_handle_type_name(var->type));
2913                 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2914             }
2915         }
2916         else if (phase == PHASE_UNMARSHAL)
2917         {
2918             if (pass == PASS_OUT)
2919             {
2920                 if (!in_attr)
2921                     print_file(file, indent, "*%s = 0;\n", var->name);
2922                 print_file(file, indent, "NdrClientContextUnmarshall(\n");
2923                 print_file(file, indent + 1, "&_StubMsg,\n");
2924                 print_file(file, indent + 1, "(NDR_CCONTEXT *)%s,\n", var->name);
2925                 print_file(file, indent + 1, "_Handle);\n");
2926             }
2927             else
2928             {
2929                 print_file(file, indent, "%s = NdrServerContextNewUnmarshall(\n", var->name);
2930                 print_file(file, indent + 1, "&_StubMsg,\n");
2931                 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2932             }
2933         }
2934     }
2935     else if (is_user_type(var->type))
2936     {
2937         print_phase_function(file, indent, "UserMarshal", phase, var, start_offset);
2938     }
2939     else if (is_string_type(var->attrs, var->type))
2940     {
2941         if (is_array(type) && !is_conformant_array(type))
2942             print_phase_function(file, indent, "NonConformantString", phase, var, start_offset);
2943         else
2944         {
2945             if (phase == PHASE_FREE || pass == PASS_RETURN || pointer_type == RPC_FC_UP)
2946                 print_phase_function(file, indent, "Pointer", phase, var,
2947                                      start_offset - (type->size_is ? 4 : 2));
2948             else
2949                 print_phase_function(file, indent, "ConformantString", phase, var,
2950                                      start_offset);
2951         }
2952     }
2953     else if (is_array(type))
2954     {
2955         unsigned char tc = type->type;
2956         const char *array_type = "FixedArray";
2957
2958         /* We already have the size_is expression since it's at the
2959            top level, but do checks for multidimensional conformant
2960            arrays.  When we handle them, we'll need to extend this
2961            function to return a list, and then we'll actually use
2962            the return value.  */
2963         get_size_is_expr(type, var->name);
2964
2965         if (tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY)
2966         {
2967             array_type = "VaryingArray";
2968         }
2969         else if (tc == RPC_FC_CARRAY)
2970         {
2971             array_type = "ConformantArray";
2972         }
2973         else if (tc == RPC_FC_CVARRAY || tc == RPC_FC_BOGUS_ARRAY)
2974         {
2975             array_type = (tc == RPC_FC_BOGUS_ARRAY
2976                           ? "ComplexArray"
2977                           : "ConformantVaryingArray");
2978         }
2979
2980         if (pointer_type != RPC_FC_RP) array_type = "Pointer";
2981         print_phase_function(file, indent, array_type, phase, var, start_offset);
2982         if (phase == PHASE_FREE && pointer_type == RPC_FC_RP)
2983         {
2984             /* these are all unmarshalled by allocating memory */
2985             if (type->type == RPC_FC_BOGUS_ARRAY ||
2986                 type->type == RPC_FC_CVARRAY ||
2987                 ((type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY) && in_attr) ||
2988                 (type->type == RPC_FC_CARRAY && !in_attr))
2989             {
2990                 print_file(file, indent, "if (%s)\n", var->name);
2991                 indent++;
2992                 print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
2993             }
2994         }
2995     }
2996     else if (!is_ptr(var->type) && is_base_type(rtype))
2997     {
2998         if (phase != PHASE_FREE)
2999             print_phase_basetype(file, indent, phase, pass, var, var->name);
3000     }
3001     else if (!is_ptr(var->type))
3002     {
3003         switch (rtype)
3004         {
3005         case RPC_FC_STRUCT:
3006         case RPC_FC_PSTRUCT:
3007             print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset);
3008             break;
3009         case RPC_FC_CSTRUCT:
3010         case RPC_FC_CPSTRUCT:
3011             print_phase_function(file, indent, "ConformantStruct", phase, var, start_offset);
3012             break;
3013         case RPC_FC_CVSTRUCT:
3014             print_phase_function(file, indent, "ConformantVaryingStruct", phase, var, start_offset);
3015             break;
3016         case RPC_FC_BOGUS_STRUCT:
3017             print_phase_function(file, indent, "ComplexStruct", phase, var, start_offset);
3018             break;
3019         case RPC_FC_RP:
3020             if (is_base_type( var->type->ref->type ))
3021             {
3022                 print_phase_basetype(file, indent, phase, pass, var, var->name);
3023             }
3024             else if (var->type->ref->type == RPC_FC_STRUCT)
3025             {
3026                 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
3027                     print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
3028             }
3029             else
3030             {
3031                 expr_t *iid;
3032                 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
3033                 {
3034                     print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
3035                     write_expr( file, iid, 1, 1, NULL, NULL );
3036                     fprintf( file, ";\n\n" );
3037                 }
3038                 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
3039             }
3040             break;
3041         default:
3042             error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype);
3043         }
3044     }
3045     else
3046     {
3047         if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
3048         {
3049             if (phase != PHASE_FREE)
3050                 print_phase_basetype(file, indent, phase, pass, var, var->name);
3051         }
3052         else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
3053         {
3054             if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
3055                 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
3056         }
3057         else
3058         {
3059             if (var->type->ref->type == RPC_FC_IP)
3060                 print_phase_function(file, indent, "InterfacePointer", phase, var, start_offset);
3061             else
3062                 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
3063         }
3064     }
3065     fprintf(file, "\n");
3066 }
3067
3068 void write_remoting_arguments(FILE *file, int indent, const func_t *func,
3069                               enum pass pass, enum remoting_phase phase)
3070 {
3071     if (phase == PHASE_BUFFERSIZE && pass != PASS_RETURN)
3072     {
3073         unsigned int size = get_function_buffer_size( func, pass );
3074         print_file(file, indent, "_StubMsg.BufferLength = %u;\n", size);
3075     }
3076
3077     if (pass == PASS_RETURN)
3078     {
3079         var_t var;
3080         var = *func->def;
3081         var.type = get_func_return_type(func);
3082         var.name = xstrdup( "_RetVal" );
3083         write_remoting_arg( file, indent, func, pass, phase, &var );
3084         free( var.name );
3085     }
3086     else
3087     {
3088         const var_t *var;
3089         if (!func->args)
3090             return;
3091         LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3092             write_remoting_arg( file, indent, func, pass, phase, var );
3093     }
3094 }
3095
3096
3097 size_t get_size_procformatstring_type(const char *name, const type_t *type, const attr_list_t *attrs)
3098 {
3099     return write_procformatstring_type(NULL, 0, name, type, attrs, FALSE);
3100 }
3101
3102
3103 size_t get_size_procformatstring_func(const func_t *func)
3104 {
3105     const var_t *var;
3106     size_t size = 0;
3107
3108     /* argument list size */
3109     if (func->args)
3110         LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3111             size += get_size_procformatstring_type(var->name, var->type, var->attrs);
3112
3113     /* return value size */
3114     if (is_void(get_func_return_type(func)))
3115         size += 2; /* FC_END and FC_PAD */
3116     else
3117         size += get_size_procformatstring_type("return value", get_func_return_type(func), NULL);
3118
3119     return size;
3120 }
3121
3122 size_t get_size_procformatstring(const statement_list_t *stmts, type_pred_t pred)
3123 {
3124     const statement_t *stmt;
3125     size_t size = 1;
3126     const func_t *func;
3127
3128     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
3129     {
3130         const type_t *iface;
3131         if (stmt->type == STMT_LIBRARY)
3132         {
3133             size += get_size_procformatstring(stmt->u.lib->stmts, pred) - 1;
3134             continue;
3135         }
3136         else if (stmt->type != STMT_TYPE && stmt->u.type->type != RPC_FC_IP)
3137             continue;
3138
3139         iface = stmt->u.type;
3140         if (!pred(iface))
3141             continue;
3142
3143         if (iface->funcs)
3144             LIST_FOR_EACH_ENTRY( func, iface->funcs, const func_t, entry )
3145                 if (!is_local(func->def->attrs))
3146                     size += get_size_procformatstring_func( func );
3147     }
3148     return size;
3149 }
3150
3151 size_t get_size_typeformatstring(const statement_list_t *stmts, type_pred_t pred)
3152 {
3153     set_all_tfswrite(FALSE);
3154     return process_tfs(NULL, stmts, pred);
3155 }
3156
3157 void declare_stub_args( FILE *file, int indent, const func_t *func )
3158 {
3159     int in_attr, out_attr;
3160     int i = 0;
3161     const var_t *var;
3162
3163     /* declare return value '_RetVal' */
3164     if (!is_void(get_func_return_type(func)))
3165     {
3166         print_file(file, indent, "");
3167         write_type_decl_left(file, get_func_return_type(func));
3168         fprintf(file, " _RetVal;\n");
3169     }
3170
3171     if (!func->args)
3172         return;
3173
3174     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3175     {
3176         int is_string = is_attr(var->attrs, ATTR_STRING);
3177
3178         in_attr = is_attr(var->attrs, ATTR_IN);
3179         out_attr = is_attr(var->attrs, ATTR_OUT);
3180         if (!out_attr && !in_attr)
3181             in_attr = 1;
3182
3183         if (is_context_handle(var->type))
3184             print_file(file, indent, "NDR_SCONTEXT %s;\n", var->name);
3185         else
3186         {
3187             if (!in_attr && !var->type->size_is && !is_string)
3188             {
3189                 print_file(file, indent, "");
3190                 write_type_decl(file, var->type->declarray ? var->type : var->type->ref,
3191                                 "_W%u", i++);
3192                 fprintf(file, ";\n");
3193             }
3194
3195             print_file(file, indent, "");
3196             write_type_decl_left(file, var->type);
3197             fprintf(file, " ");
3198             if (var->type->declarray) {
3199                 fprintf(file, "( *");
3200                 write_name(file, var);
3201                 fprintf(file, " )");
3202             } else
3203                 write_name(file, var);
3204             write_type_right(file, var->type, FALSE);
3205             fprintf(file, ";\n");
3206
3207             if (decl_indirect(var->type))
3208                 print_file(file, indent, "void *_p_%s = &%s;\n",
3209                            var->name, var->name);
3210         }
3211     }
3212 }
3213
3214
3215 void assign_stub_out_args( FILE *file, int indent, const func_t *func )
3216 {
3217     int in_attr, out_attr;
3218     int i = 0, sep = 0;
3219     const var_t *var;
3220
3221     if (!func->args)
3222         return;
3223
3224     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3225     {
3226         int is_string = is_attr(var->attrs, ATTR_STRING);
3227         in_attr = is_attr(var->attrs, ATTR_IN);
3228         out_attr = is_attr(var->attrs, ATTR_OUT);
3229         if (!out_attr && !in_attr)
3230             in_attr = 1;
3231
3232         if (!in_attr)
3233         {
3234             print_file(file, indent, "");
3235             write_name(file, var);
3236
3237             if (is_context_handle(var->type))
3238             {
3239                 fprintf(file, " = NdrContextHandleInitialize(\n");
3240                 print_file(file, indent + 1, "&_StubMsg,\n");
3241                 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n",
3242                            var->type->typestring_offset);
3243             }
3244             else if (var->type->size_is)
3245             {
3246                 unsigned int size, align = 0;
3247                 type_t *type = var->type;
3248
3249                 fprintf(file, " = NdrAllocate(&_StubMsg, ");
3250                 for ( ; type->size_is ; type = type->ref)
3251                 {
3252                     write_expr(file, type->size_is, TRUE, TRUE, NULL, NULL);
3253                     fprintf(file, " * ");
3254                 }
3255                 size = type_memsize(type, &align);
3256                 fprintf(file, "%u);\n", size);
3257             }
3258             else if (!is_string)
3259             {
3260                 fprintf(file, " = &_W%u;\n", i);
3261                 if (is_ptr(var->type) && !last_ptr(var->type))
3262                     print_file(file, indent, "_W%u = 0;\n", i);
3263                 i++;
3264             }
3265
3266             sep = 1;
3267         }
3268     }
3269     if (sep)
3270         fprintf(file, "\n");
3271 }
3272
3273
3274 int write_expr_eval_routines(FILE *file, const char *iface)
3275 {
3276     static const char *var_name = "pS";
3277     static const char *var_name_expr = "pS->";
3278     int result = 0;
3279     struct expr_eval_routine *eval;
3280     unsigned short callback_offset = 0;
3281
3282     LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
3283     {
3284         const char *name = eval->structure->name;
3285         result = 1;
3286
3287         print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
3288                    iface, name, callback_offset);
3289         print_file(file, 0, "{\n");
3290         print_file (file, 1, "%s *%s = (%s *)(pStubMsg->StackTop - %u);\n",
3291                     name, var_name, name, eval->baseoff);
3292         print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */
3293         print_file(file, 1, "pStubMsg->MaxCount = (unsigned long)");
3294         write_expr(file, eval->expr, 1, 1, var_name_expr, eval->structure);
3295         fprintf(file, ";\n");
3296         print_file(file, 0, "}\n\n");
3297         callback_offset++;
3298     }
3299     return result;
3300 }
3301
3302 void write_expr_eval_routine_list(FILE *file, const char *iface)
3303 {
3304     struct expr_eval_routine *eval;
3305     struct expr_eval_routine *cursor;
3306     unsigned short callback_offset = 0;
3307
3308     fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
3309     fprintf(file, "{\n");
3310
3311     LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
3312     {
3313         const char *name = eval->structure->name;
3314         print_file(file, 1, "%s_%sExprEval_%04u,\n", iface, name, callback_offset);
3315         callback_offset++;
3316         list_remove(&eval->entry);
3317         free(eval);
3318     }
3319
3320     fprintf(file, "};\n\n");
3321 }
3322
3323 void write_user_quad_list(FILE *file)
3324 {
3325     user_type_t *ut;
3326
3327     if (list_empty(&user_type_list))
3328         return;
3329
3330     fprintf(file, "static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[] =\n");
3331     fprintf(file, "{\n");
3332     LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
3333     {
3334         const char *sep = &ut->entry == list_tail(&user_type_list) ? "" : ",";
3335         print_file(file, 1, "{\n");
3336         print_file(file, 2, "(USER_MARSHAL_SIZING_ROUTINE)%s_UserSize,\n", ut->name);
3337         print_file(file, 2, "(USER_MARSHAL_MARSHALLING_ROUTINE)%s_UserMarshal,\n", ut->name);
3338         print_file(file, 2, "(USER_MARSHAL_UNMARSHALLING_ROUTINE)%s_UserUnmarshal,\n", ut->name);
3339         print_file(file, 2, "(USER_MARSHAL_FREEING_ROUTINE)%s_UserFree\n", ut->name);
3340         print_file(file, 1, "}%s\n", sep);
3341     }
3342     fprintf(file, "};\n\n");
3343 }
3344
3345 void write_endpoints( FILE *f, const char *prefix, const str_list_t *list )
3346 {
3347     const struct str_list_entry_t *endpoint;
3348     const char *p;
3349
3350     /* this should be an array of RPC_PROTSEQ_ENDPOINT but we want const strings */
3351     print_file( f, 0, "static const unsigned char * %s__RpcProtseqEndpoint[][2] =\n{\n", prefix );
3352     LIST_FOR_EACH_ENTRY( endpoint, list, const struct str_list_entry_t, entry )
3353     {
3354         print_file( f, 1, "{ (const unsigned char *)\"" );
3355         for (p = endpoint->str; *p && *p != ':'; p++)
3356         {
3357             if (*p == '"' || *p == '\\') fputc( '\\', f );
3358             fputc( *p, f );
3359         }
3360         if (!*p) goto error;
3361         if (p[1] != '[') goto error;
3362
3363         fprintf( f, "\", (const unsigned char *)\"" );
3364         for (p += 2; *p && *p != ']'; p++)
3365         {
3366             if (*p == '"' || *p == '\\') fputc( '\\', f );
3367             fputc( *p, f );
3368         }
3369         if (*p != ']') goto error;
3370         fprintf( f, "\" },\n" );
3371     }
3372     print_file( f, 0, "};\n\n" );
3373     return;
3374
3375 error:
3376     error("Invalid endpoint syntax '%s'\n", endpoint->str);
3377 }