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