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