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