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