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