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