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