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