msi: Only insert entries into listbox if property value matches.
[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 <signal.h>
34 #include <limits.h>
35
36 #include "widl.h"
37 #include "utils.h"
38 #include "parser.h"
39 #include "header.h"
40 #include "windef.h"
41 #include "wine/list.h"
42
43 #include "widl.h"
44 #include "typegen.h"
45
46 static const func_t *current_func;
47 static const type_t *current_structure;
48
49 /* name of the structure variable for structure callbacks */
50 #define STRUCT_EXPR_EVAL_VAR "pS"
51
52 static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
53
54 struct expr_eval_routine
55 {
56     struct list entry;
57     const type_t *structure;
58     size_t structure_size;
59     const expr_t *expr;
60 };
61
62 static size_t type_memsize(const type_t *t, int ptr_level, const array_dims_t *array, unsigned int *align);
63 static size_t fields_memsize(const var_list_t *fields, unsigned int *align);
64
65 static int compare_expr(const expr_t *a, const expr_t *b)
66 {
67     int ret;
68
69     if (a->type != b->type)
70         return a->type - b->type;
71
72     switch (a->type)
73     {
74         case EXPR_NUM:
75         case EXPR_HEXNUM:
76         case EXPR_TRUEFALSE:
77             return a->u.lval - b->u.lval;
78         case EXPR_IDENTIFIER:
79             return strcmp(a->u.sval, b->u.sval);
80         case EXPR_COND:
81             ret = compare_expr(a->ref, b->ref);
82             if (ret != 0)
83                 return ret;
84             ret = compare_expr(a->u.ext, b->u.ext);
85             if (ret != 0)
86                 return ret;
87             return compare_expr(a->ext2, b->ext2);
88         case EXPR_OR:
89         case EXPR_AND:
90         case EXPR_ADD:
91         case EXPR_SUB:
92         case EXPR_MUL:
93         case EXPR_DIV:
94         case EXPR_SHL:
95         case EXPR_SHR:
96             ret = compare_expr(a->ref, b->ref);
97             if (ret != 0)
98                 return ret;
99             return compare_expr(a->u.ext, b->u.ext);
100         case EXPR_NOT:
101         case EXPR_NEG:
102         case EXPR_PPTR:
103         case EXPR_CAST:
104         case EXPR_SIZEOF:
105             return compare_expr(a->ref, b->ref);
106         case EXPR_VOID:
107             return 0;
108     }
109     return -1;
110 }
111
112 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
113     do { \
114         if (file) \
115             fprintf(file, "/* %2u */\n", typestring_offset); \
116         print_file((file), 2, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
117     } \
118     while (0)
119
120 static int print_file(FILE *file, int indent, const char *format, ...)
121 {
122     va_list va;
123     int i, r;
124
125     if (!file) return 0;
126
127     va_start(va, format);
128     for (i = 0; i < indent; i++)
129         fprintf(file, "    ");
130     r = vfprintf(file, format, va);
131     va_end(va);
132     return r;
133 }
134
135 static void write_formatdesc(FILE *f, int indent, const char *str)
136 {
137     print_file(f, indent, "typedef struct _MIDL_%s_FORMAT_STRING\n", str);
138     print_file(f, indent, "{\n");
139     print_file(f, indent + 1, "short Pad;\n");
140     print_file(f, indent + 1, "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str);
141     print_file(f, indent, "} MIDL_%s_FORMAT_STRING;\n", str);
142     print_file(f, indent, "\n");
143 }
144
145 void write_formatstringsdecl(FILE *f, int indent, ifref_list_t *ifaces, int for_objects)
146 {
147     print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n",
148                get_size_typeformatstring(ifaces, for_objects));
149
150     print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n",
151                get_size_procformatstring(ifaces, for_objects));
152
153     fprintf(f, "\n");
154     write_formatdesc(f, indent, "TYPE");
155     write_formatdesc(f, indent, "PROC");
156     fprintf(f, "\n");
157     print_file(f, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n");
158     print_file(f, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n");
159     print_file(f, indent, "\n");
160 }
161
162 static int is_user_derived(const var_t *v)
163 {
164     const type_t *type = v->type;
165
166     if (v->attrs && is_attr( v->attrs, ATTR_WIREMARSHAL )) return 1;
167
168     while (type)
169     {
170         if (type->attrs && is_attr( type->attrs, ATTR_WIREMARSHAL )) return 1;
171         type = type->ref;
172     }
173     return 0;
174 }
175
176 static inline int is_base_type(unsigned char type)
177 {
178     switch (type)
179     {
180     case RPC_FC_BYTE:
181     case RPC_FC_CHAR:
182     case RPC_FC_USMALL:
183     case RPC_FC_SMALL:
184     case RPC_FC_WCHAR:
185     case RPC_FC_USHORT:
186     case RPC_FC_SHORT:
187     case RPC_FC_ULONG:
188     case RPC_FC_LONG:
189     case RPC_FC_HYPER:
190     case RPC_FC_IGNORE:
191     case RPC_FC_FLOAT:
192     case RPC_FC_DOUBLE:
193     case RPC_FC_ENUM16:
194     case RPC_FC_ENUM32:
195     case RPC_FC_ERROR_STATUS_T:
196     case RPC_FC_BIND_PRIMITIVE:
197         return TRUE;
198
199     default:
200         return FALSE;
201     }
202 }
203
204 static size_t write_procformatstring_var(FILE *file, int indent,
205     const var_t *var, int is_return, unsigned int *type_offset)
206 {
207     size_t size;
208     int ptr_level = var->ptr_level;
209     const type_t *type = var->type;
210
211     int is_in = is_attr(var->attrs, ATTR_IN);
212     int is_out = is_attr(var->attrs, ATTR_OUT);
213
214     if (!is_in && !is_out) is_in = TRUE;
215
216     if (ptr_level == 0 && !var->array && is_base_type(type->type))
217     {
218         if (is_return)
219             print_file(file, indent, "0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
220         else
221             print_file(file, indent, "0x4e,    /* FC_IN_PARAM_BASETYPE */\n");
222
223         switch(type->type)
224         {
225 #define CASE_BASETYPE(fctype) \
226         case RPC_##fctype: \
227             print_file(file, indent, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
228             size = 2; /* includes param type prefix */ \
229             break
230
231         CASE_BASETYPE(FC_BYTE);
232         CASE_BASETYPE(FC_CHAR);
233         CASE_BASETYPE(FC_WCHAR);
234         CASE_BASETYPE(FC_USHORT);
235         CASE_BASETYPE(FC_SHORT);
236         CASE_BASETYPE(FC_ULONG);
237         CASE_BASETYPE(FC_LONG);
238         CASE_BASETYPE(FC_HYPER);
239         CASE_BASETYPE(FC_IGNORE);
240         CASE_BASETYPE(FC_USMALL);
241         CASE_BASETYPE(FC_SMALL);
242         CASE_BASETYPE(FC_FLOAT);
243         CASE_BASETYPE(FC_DOUBLE);
244         CASE_BASETYPE(FC_ERROR_STATUS_T);
245 #undef CASE_BASETYPE
246
247         case RPC_FC_BIND_PRIMITIVE:
248             print_file(file, indent, "0x%02x,    /* FC_IGNORE */\n", RPC_FC_IGNORE);
249             size = 2; /* includes param type prefix */
250             break;
251
252         default:
253             error("Unknown/unsupported type: %s (0x%02x)\n", var->name, type->type);
254             size = 0;
255         }
256     }
257     else
258     {
259         if (is_return)
260             print_file(file, indent, "0x52,    /* FC_RETURN_PARAM */\n");
261         else if (is_in && is_out)
262             print_file(file, indent, "0x50,    /* FC_IN_OUT_PARAM */\n");
263         else if (is_out)
264             print_file(file, indent, "0x51,    /* FC_OUT_PARAM */\n");
265         else
266             print_file(file, indent, "0x4d,    /* FC_IN_PARAM */\n");
267
268         print_file(file, indent, "0x01,\n");
269         print_file(file, indent, "NdrFcShort(0x%x),\n", *type_offset);
270         size = 4; /* includes param type prefix */
271     }
272     *type_offset += get_size_typeformatstring_var(var);
273     return size;
274 }
275
276 void write_procformatstring(FILE *file, const ifref_list_t *ifaces, int for_objects)
277 {
278     const ifref_t *iface;
279     int indent = 0;
280     const var_t *var;
281     unsigned int type_offset = 2;
282
283     print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
284     print_file(file, indent, "{\n");
285     indent++;
286     print_file(file, indent, "0,\n");
287     print_file(file, indent, "{\n");
288     indent++;
289
290     if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
291     {
292         if (for_objects != is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
293             continue;
294
295         if (iface->iface->funcs)
296         {
297             const func_t *func;
298             LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
299             {
300                 if (is_local(func->def->attrs)) continue;
301                 /* emit argument data */
302                 if (func->args)
303                 {
304                     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
305                         write_procformatstring_var(file, indent, var, FALSE, &type_offset);
306                 }
307
308                 /* emit return value data */
309                 var = func->def;
310                 if (is_void(var->type, NULL))
311                 {
312                     print_file(file, indent, "0x5b,    /* FC_END */\n");
313                     print_file(file, indent, "0x5c,    /* FC_PAD */\n");
314                 }
315                 else
316                     write_procformatstring_var(file, indent, var, TRUE,
317                                                &type_offset);
318             }
319         }
320     }
321
322     print_file(file, indent, "0x0\n");
323     indent--;
324     print_file(file, indent, "}\n");
325     indent--;
326     print_file(file, indent, "};\n");
327     print_file(file, indent, "\n");
328 }
329
330 static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
331 {
332     switch (type->type)
333     {
334 #define CASE_BASETYPE(fctype) \
335         case RPC_##fctype: \
336             print_file(file, 2, "0x%02x,  /* " #fctype " */\n", RPC_##fctype); \
337             *typestring_offset += 1; \
338             return 1;
339
340         CASE_BASETYPE(FC_BYTE);
341         CASE_BASETYPE(FC_CHAR);
342         CASE_BASETYPE(FC_SMALL);
343         CASE_BASETYPE(FC_USMALL);
344         CASE_BASETYPE(FC_WCHAR);
345         CASE_BASETYPE(FC_SHORT);
346         CASE_BASETYPE(FC_USHORT);
347         CASE_BASETYPE(FC_LONG);
348         CASE_BASETYPE(FC_ULONG);
349         CASE_BASETYPE(FC_FLOAT);
350         CASE_BASETYPE(FC_HYPER);
351         CASE_BASETYPE(FC_DOUBLE);
352         CASE_BASETYPE(FC_ENUM16);
353         CASE_BASETYPE(FC_ENUM32);
354         CASE_BASETYPE(FC_IGNORE);
355         CASE_BASETYPE(FC_ERROR_STATUS_T);
356 #undef CASE_BASETYPE
357     }
358     return 0;
359 }
360
361 /* write conformance / variance descriptor */
362 static size_t write_conf_or_var_desc(FILE *file, const func_t *func, const type_t *structure, const expr_list_t *expr_list)
363 {
364     unsigned char operator_type = 0;
365     const char *operator_string = "no operators";
366     const expr_t *expr, *subexpr;
367     unsigned char correlation_type;
368
369     if (!file) return 4; /* optimisation for sizing pass */
370
371     if (list_count(expr_list) > 1)
372         error("write_conf_or_var_desc: multi-dimensional arrays not supported yet\n");
373
374     expr = subexpr = LIST_ENTRY( list_head(expr_list), const expr_t, entry );
375
376     if (expr->is_const)
377     {
378         if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
379             error("write_conf_or_var_desc: constant value %ld is greater than "
380                   "the maximum constant size of %d\n", expr->cval,
381                   UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
382
383         print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n",
384                    RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
385         print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX);
386         print_file(file, 2, "NdrFcShort(0x%x),\n", expr->cval & USHRT_MAX);
387
388         return 4;
389     }
390
391     switch (subexpr->type)
392     {
393     case EXPR_PPTR:
394         subexpr = subexpr->ref;
395         operator_type = RPC_FC_DEREFERENCE;
396         operator_string = "FC_DEREFERENCE";
397         break;
398     case EXPR_DIV:
399         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
400         {
401             subexpr = subexpr->ref;
402             operator_type = RPC_FC_DIV_2;
403             operator_string = "FC_DIV_2";
404         }
405         break;
406     case EXPR_MUL:
407         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
408         {
409             subexpr = subexpr->ref;
410             operator_type = RPC_FC_MULT_2;
411             operator_string = "FC_MULT_2";
412         }
413         break;
414     case EXPR_SUB:
415         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
416         {
417             subexpr = subexpr->ref;
418             operator_type = RPC_FC_SUB_1;
419             operator_string = "FC_SUB_1";
420         }
421         break;
422     case EXPR_ADD:
423         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
424         {
425             subexpr = subexpr->ref;
426             operator_type = RPC_FC_ADD_1;
427             operator_string = "FC_ADD_1";
428         }
429         break;
430     default:
431         break;
432     }
433
434     if (subexpr->type == EXPR_IDENTIFIER)
435     {
436         const type_t *correlation_variable = NULL;
437         unsigned char correlation_variable_type;
438         unsigned char param_type = 0;
439         const char *param_type_string = NULL;
440         size_t offset;
441
442         if (structure)
443         {
444             const var_t *var;
445
446             offset = 0;
447             if (structure->fields) LIST_FOR_EACH_ENTRY( var, structure->fields, const var_t, entry )
448             {
449                 unsigned int align = 0;
450                 offset -= type_memsize(var->type, var->ptr_level, var->array, &align);
451                 /* FIXME: take alignment into account */
452                 if (!strcmp(var->name, subexpr->u.sval))
453                 {
454                     correlation_variable = var->type;
455                     break;
456                 }
457             }
458             if (!correlation_variable)
459                 error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
460                       subexpr->u.sval);
461
462             correlation_type = RPC_FC_NORMAL_CONFORMANCE;
463         }
464         else
465         {
466             const var_t *var;
467
468             offset = sizeof(void *);
469             if (func->args) LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
470             {
471                 if (!strcmp(var->name, subexpr->u.sval))
472                 {
473                     correlation_variable = var->type;
474                     break;
475                 }
476                 /* FIXME: not all stack variables are sizeof(void *) */
477                 offset += sizeof(void *);
478             }
479             if (!correlation_variable)
480                 error("write_conf_or_var_desc: couldn't find variable %s in function\n",
481                     subexpr->u.sval);
482
483             correlation_type = RPC_FC_TOP_LEVEL_CONFORMANCE;
484         }
485
486         correlation_variable_type = correlation_variable->type;
487
488         switch (correlation_variable_type)
489         {
490         case RPC_FC_CHAR:
491         case RPC_FC_SMALL:
492             param_type = RPC_FC_SMALL;
493             param_type_string = "FC_SMALL";
494             break;
495         case RPC_FC_BYTE:
496         case RPC_FC_USMALL:
497             param_type = RPC_FC_USMALL;
498             param_type_string = "FC_USMALL";
499             break;
500         case RPC_FC_WCHAR:
501         case RPC_FC_SHORT:
502             param_type = RPC_FC_SHORT;
503             param_type_string = "FC_SHORT";
504             break;
505         case RPC_FC_USHORT:
506             param_type = RPC_FC_USHORT;
507             param_type_string = "FC_USHORT";
508             break;
509         case RPC_FC_LONG:
510             param_type = RPC_FC_LONG;
511             param_type_string = "FC_LONG";
512             break;
513         case RPC_FC_ULONG:
514             param_type = RPC_FC_ULONG;
515             param_type_string = "FC_ULONG";
516             break;
517         case RPC_FC_RP:
518         case RPC_FC_UP:
519         case RPC_FC_OP:
520         case RPC_FC_FP:
521             if (sizeof(void *) == 4)  /* FIXME */
522             {
523                 param_type = RPC_FC_LONG;
524                 param_type_string = "FC_LONG";
525             }
526             else
527             {
528                 param_type = RPC_FC_HYPER;
529                 param_type_string = "FC_HYPER";
530             }
531             break;
532         default:
533             error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
534                 correlation_variable_type);
535         }
536
537         print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
538                 correlation_type | param_type,
539                 correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "parameter, " : "",
540                 param_type_string);
541         print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string);
542         print_file(file, 2, "NdrFcShort(0x%x), /* %soffset = %d */\n",
543                    offset,
544                    correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "x86 stack size / " : "",
545                    offset);
546     }
547     else
548     {
549         unsigned int callback_offset = 0;
550
551         if (structure)
552         {
553             struct expr_eval_routine *eval;
554             int found = 0;
555
556             LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
557             {
558                 if (!strcmp(eval->structure->name, structure->name) &&
559                     !compare_expr(eval->expr, expr))
560                 {
561                     found = 1;
562                     break;
563                 }
564                 callback_offset++;
565             }
566
567             if (!found)
568             {
569                 unsigned int align = 0;
570                 eval = xmalloc(sizeof(*eval));
571                 eval->structure = structure;
572                 eval->structure_size = fields_memsize(structure->fields, &align);
573                 eval->expr = expr;
574                 list_add_tail(&expr_eval_routines, &eval->entry);
575             }
576
577             correlation_type = RPC_FC_NORMAL_CONFORMANCE;
578         }
579         else
580         {
581             error("write_conf_or_var_desc: top-level callback conformance unimplemented\n");
582             correlation_type = RPC_FC_TOP_LEVEL_CONFORMANCE;
583         }
584
585         if (callback_offset > USHRT_MAX)
586             error("Maximum number of callback routines reached\n");
587
588         print_file(file, 2, "0x%x, /* Corr desc: %s */\n",
589                    correlation_type,
590                    correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "parameter" : "");
591         print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
592         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", callback_offset, callback_offset);
593     }
594     return 4;
595 }
596
597 static size_t fields_memsize(const var_list_t *fields, unsigned int *align)
598 {
599     size_t size = 0;
600     const var_t *v;
601
602     if (!fields) return 0;
603     LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
604         size += type_memsize(v->type, v->ptr_level, v->array, align);
605
606     return size;
607 }
608
609 static size_t get_array_size( const array_dims_t *array )
610 {
611     size_t size = 1;
612     const expr_t *dim;
613
614     if (!array) return 0;
615
616     LIST_FOR_EACH_ENTRY( dim, array, expr_t, entry )
617     {
618         if (!dim->is_const) return 0;
619         size *= dim->cval;
620     }
621
622     return size;
623 }
624
625 static size_t type_memsize(const type_t *t, int ptr_level, const array_dims_t *array, unsigned int *align)
626 {
627     size_t size = 0;
628
629     if (ptr_level)
630     {
631         size = sizeof(void *);
632         if (size > *align) *align = size;
633     }
634     else switch (t->type)
635     {
636     case RPC_FC_BYTE:
637     case RPC_FC_CHAR:
638     case RPC_FC_USMALL:
639     case RPC_FC_SMALL:
640         size = 1;
641         if (size > *align) *align = size;
642         break;
643     case RPC_FC_WCHAR:
644     case RPC_FC_USHORT:
645     case RPC_FC_SHORT:
646     case RPC_FC_ENUM16:
647         size = 2;
648         if (size > *align) *align = size;
649         break;
650     case RPC_FC_ULONG:
651     case RPC_FC_LONG:
652     case RPC_FC_ERROR_STATUS_T:
653     case RPC_FC_ENUM32:
654     case RPC_FC_FLOAT:
655         size = 4;
656         if (size > *align) *align = size;
657         break;
658     case RPC_FC_HYPER:
659     case RPC_FC_DOUBLE:
660         size = 8;
661         if (size > *align) *align = size;
662         break;
663     case RPC_FC_STRUCT:
664     case RPC_FC_CVSTRUCT:
665     case RPC_FC_CPSTRUCT:
666     case RPC_FC_CSTRUCT:
667     case RPC_FC_PSTRUCT:
668     case RPC_FC_BOGUS_STRUCT:
669     case RPC_FC_ENCAPSULATED_UNION:
670     case RPC_FC_NON_ENCAPSULATED_UNION:
671         size = fields_memsize(t->fields, align);
672         break;
673     default:
674         error("type_memsize: Unknown type %d\n", t->type);
675         size = 0;
676     }
677
678     if (array) size *= get_array_size( array );
679     return size;
680 }
681
682 static int write_pointers(FILE *file, const attr_list_t *attrs,
683                           const type_t *type, int ptr_level,
684                           const array_dims_t *array, int level,
685                           unsigned int *typestring_offset)
686 {
687     int pointers_written = 0;
688     const var_t *v;
689
690     /* don't generate a pointer for first-level arrays since we want to
691     * descend into them to write their pointers, not stop here */
692     if ((level == 0 || ptr_level == 0) && is_array_type(attrs, ptr_level, array))
693     {
694         return write_pointers(file, NULL, type, 0, NULL, level + 1, typestring_offset);
695     }
696
697     if (ptr_level != 0)
698     {
699         /* FIXME: only general algorithm implemented, not the actual writing */
700         error("write_pointers: Writing type format string for pointer is unimplemented\n");
701         return 1;
702     }
703
704     switch (type->type)
705     {
706         /* note: don't descend into complex structures or unions since these
707          * will always be generated as a separate type */
708         case RPC_FC_STRUCT:
709         case RPC_FC_CVSTRUCT:
710         case RPC_FC_CPSTRUCT:
711         case RPC_FC_CSTRUCT:
712         case RPC_FC_PSTRUCT:
713             if (!type->fields) break;
714             LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
715                 pointers_written += write_pointers(file, v->attrs, v->type,
716                                                    v->ptr_level, v->array,
717                                                    level + 1,
718                                                    typestring_offset);
719
720             break;
721
722         default:
723             /* nothing to do */
724             break;
725     }
726
727     return pointers_written;
728 }
729
730 static size_t write_pointer_description(FILE *file, const attr_list_t *attrs,
731                                         const type_t *type, int ptr_level,
732                                         const array_dims_t *array, int level,
733                                         size_t typestring_offset)
734 {
735     size_t size = 0;
736     const var_t *v;
737
738     /* don't generate a pointer for first-level arrays since we want to
739      * descend into them to write their pointers, not stop here */
740     if ((level == 0 || ptr_level == 0) && is_array_type(attrs, ptr_level, array))
741     {
742         return write_pointer_description(file, NULL, type, 0, NULL,
743                                          level + 1, typestring_offset);
744     }
745
746     if (ptr_level != 0)
747     {
748         /* FIXME: only general algorithm implemented, not the actual writing */
749         error("write_pointer_description: Writing pointer description is unimplemented\n");
750         return 0;
751     }
752
753     /* FIXME: search through all refs for pointers too */
754
755     switch (type->type)
756     {
757         /* note: don't descend into complex structures or unions since these
758          * will always be generated as a separate type */
759         case RPC_FC_STRUCT:
760         case RPC_FC_CVSTRUCT:
761         case RPC_FC_CPSTRUCT:
762         case RPC_FC_CSTRUCT:
763         case RPC_FC_PSTRUCT:
764             if (!type->fields) break;
765             LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
766                 size += write_pointer_description(file, v->attrs, v->type,
767                                                   v->ptr_level, v->array,
768                                                   level + 1,
769                                                   typestring_offset);
770
771             break;
772
773         default:
774             /* nothing to do */
775             break;
776     }
777
778     return size;
779 }
780
781 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
782                                const type_t *type, const array_dims_t *array,
783                                const char *name, unsigned int *typestring_offset)
784 {
785     const expr_list_t *size_is = get_attrp(attrs, ATTR_SIZEIS);
786     int has_size = is_non_void(size_is);
787     size_t start_offset = *typestring_offset;
788     unsigned char flags = 0;
789     int pointer_type;
790     unsigned char rtype;
791
792     if (is_ptr(type))
793     {
794         pointer_type = type->type;
795         type = type->ref;
796     }
797     else
798         pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
799
800     if (!pointer_type)
801         pointer_type = RPC_FC_RP;
802
803     if (!get_attrp(attrs, ATTR_SIZEIS))
804         flags |= RPC_FC_P_SIMPLEPOINTER;
805
806     rtype = type->type;
807
808     if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR))
809     {
810         error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
811         return start_offset;
812     }
813
814     print_file(file, 2,"0x%x, 0x%x,    /* %s%s */\n",
815                pointer_type, flags,
816                pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"),
817                (flags & RPC_FC_P_SIMPLEPOINTER) ? " [simple_pointer]" : "");
818     *typestring_offset += 2;
819
820     if (!(flags & RPC_FC_P_SIMPLEPOINTER))
821     {
822         print_file(file, 2, "NdrFcShort(0x2),\n");
823         *typestring_offset += 2;
824     }
825
826     if (array && !is_conformant_array(array))
827     {
828         /* FIXME: multi-dimensional array */
829         const expr_t *dim = LIST_ENTRY( list_head( array ), expr_t, entry );
830         if (dim->cval > USHRT_MAX)
831             error("array size for parameter %s exceeds %d bytes by %ld bytes\n",
832                   name, USHRT_MAX, dim->cval - USHRT_MAX);
833
834         if (rtype == RPC_FC_CHAR)
835             WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
836         else
837             WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
838         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
839         *typestring_offset += 2;
840
841         print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", dim->cval, dim->cval);
842         *typestring_offset += 2;
843
844         return start_offset;
845     }
846     else if (has_size)
847     {
848         if (rtype == RPC_FC_CHAR)
849             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
850         else
851             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
852         print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
853         *typestring_offset += 2;
854
855         *typestring_offset += write_conf_or_var_desc(file, current_func, NULL, size_is);
856
857         return start_offset;
858     }
859     else
860     {
861         if (rtype == RPC_FC_CHAR)
862             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
863         else
864             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
865         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
866         *typestring_offset += 2;
867
868         return start_offset;
869     }
870 }
871
872 static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
873                               const type_t *type, const array_dims_t *array,
874                               const char *name, unsigned int *typestring_offset)
875 {
876     const expr_list_t *length_is = get_attrp(attrs, ATTR_LENGTHIS);
877     const expr_list_t *size_is = get_attrp(attrs, ATTR_SIZEIS);
878     int has_length = is_non_void(length_is);
879     int has_size = is_non_void(size_is) || is_conformant_array(array);
880     size_t start_offset;
881     int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
882     if (!pointer_type)
883         pointer_type = RPC_FC_RP;
884
885     print_file(file, 2, "0x%x, 0x00,    /* %s */\n",
886                pointer_type,
887                pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"));
888     print_file(file, 2, "NdrFcShort(0x2),\n");
889     *typestring_offset += 4;
890
891     if (array && list_count(array) > 1) /* multi-dimensional array */
892     {
893         error("write_array_tfs: Multi-dimensional arrays not implemented yet (param %s)\n", name);
894         return 0;
895     }
896     else
897     {
898         const expr_t *dim = array ? LIST_ENTRY( list_head( array ), expr_t, entry ) : NULL;
899         size_t pointer_start_offset = *typestring_offset;
900         int has_pointer = 0;
901
902         if (write_pointers(file, attrs, type, 0, array, 0, typestring_offset) > 0)
903             has_pointer = 1;
904
905         start_offset = *typestring_offset;
906
907         if (!has_length && !has_size)
908         {
909             /* fixed array */
910             unsigned int align = 0;
911             size_t size = type_memsize(type, 0, array, &align);
912             if (size < USHRT_MAX)
913             {
914                 WRITE_FCTYPE(file, FC_SMFARRAY, *typestring_offset);
915                 /* alignment */
916                 print_file(file, 2, "0x%02x,\n", align - 1);
917                 /* size */
918                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", size, size);
919                 *typestring_offset += 4;
920             }
921             else
922             {
923                 WRITE_FCTYPE(file, FC_LGFARRAY, *typestring_offset);
924                 /* alignment */
925                 print_file(file, 2, "0x%02x,\n", align - 1);
926                 /* size */
927                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", size, size);
928                 *typestring_offset += 6;
929             }
930
931             if (has_pointer)
932             {
933                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
934                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
935                 *typestring_offset += 2;
936                 *typestring_offset = write_pointer_description(file, attrs,
937                     type, 0, array, 0, pointer_start_offset);
938                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
939                 *typestring_offset += 1;
940             }
941
942             if (!write_base_type( file, type, typestring_offset ))
943             {
944                 print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
945                 *typestring_offset += 1;
946             }
947             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
948             *typestring_offset += 1;
949
950             return start_offset;
951         }
952         else if (has_length && !has_size)
953         {
954             /* varying array */
955             unsigned int align = 0;
956             size_t element_size = type_memsize(type, 0, NULL, &align);
957             size_t elements = dim->cval;
958             size_t total_size = element_size * elements;
959
960             if (total_size < USHRT_MAX)
961             {
962                 WRITE_FCTYPE(file, FC_SMVARRAY, *typestring_offset);
963                 /* alignment */
964                 print_file(file, 2, "0x%02x,\n", align - 1);
965                 /* total size */
966                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", total_size, total_size);
967                 /* number of elements */
968                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", elements, elements);
969                 *typestring_offset += 6;
970             }
971             else
972             {
973                 WRITE_FCTYPE(file, FC_LGVARRAY, *typestring_offset);
974                 /* alignment */
975                 print_file(file, 2, "0x%02x,\n", align - 1);
976                 /* total size */
977                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", total_size, total_size);
978                 /* number of elements */
979                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", elements, elements);
980                 *typestring_offset += 10;
981             }
982             /* element size */
983             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
984             *typestring_offset += 2;
985
986             *typestring_offset += write_conf_or_var_desc(file, current_func,
987                                                          current_structure,
988                                                          length_is);
989
990             if (has_pointer)
991             {
992                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
993                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
994                 *typestring_offset += 2;
995                 *typestring_offset += write_pointer_description(file, attrs,
996                     type, 0, array, 0, pointer_start_offset);
997                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
998                 *typestring_offset += 1;
999             }
1000
1001             if (!write_base_type( file, type, typestring_offset ))
1002             {
1003                 print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
1004                 *typestring_offset += 1;
1005             }
1006             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1007             *typestring_offset += 1;
1008
1009             return start_offset;
1010         }
1011         else if (!has_length && has_size)
1012         {
1013             /* conformant array */
1014             unsigned int align = 0;
1015             size_t element_size = type_memsize(type, 0, NULL, &align);
1016
1017             WRITE_FCTYPE(file, FC_CARRAY, *typestring_offset);
1018             /* alignment */
1019             print_file(file, 2, "0x%02x,\n", align - 1);
1020             /* element size */
1021             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
1022             *typestring_offset += 4;
1023
1024             *typestring_offset += write_conf_or_var_desc(file, current_func,
1025                                                          current_structure,
1026                                                          size_is ? size_is : array);
1027
1028             if (has_pointer)
1029             {
1030                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1031                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1032                 *typestring_offset += 2;
1033                 *typestring_offset += write_pointer_description(file, attrs,
1034                     type, 0, array, 0, pointer_start_offset);
1035                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1036                 *typestring_offset += 1;
1037             }
1038
1039             if (!write_base_type( file, type, typestring_offset ))
1040             {
1041                 print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
1042                 *typestring_offset += 1;
1043             }
1044             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1045             *typestring_offset += 1;
1046
1047             return start_offset;
1048         }
1049         else
1050         {
1051             /* conformant varying array */
1052             unsigned int align = 0;
1053             size_t element_size = type_memsize(type, 0, NULL, &align);
1054
1055             WRITE_FCTYPE(file, FC_CVARRAY, *typestring_offset);
1056             /* alignment */
1057             print_file(file, 2, "0x%02x,\n", align - 1);
1058             /* element size */
1059             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
1060             *typestring_offset += 4;
1061
1062             *typestring_offset += write_conf_or_var_desc(file, current_func,
1063                                                          current_structure,
1064                                                          size_is ? size_is : array);
1065             *typestring_offset += write_conf_or_var_desc(file, current_func,
1066                                                          current_structure,
1067                                                          length_is);
1068
1069             if (has_pointer)
1070             {
1071                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1072                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1073                 *typestring_offset += 2;
1074                 *typestring_offset += write_pointer_description(file, attrs,
1075                     type, 0, array, 0, pointer_start_offset);
1076                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1077                 *typestring_offset += 1;
1078             }
1079
1080             if (!write_base_type( file, type, typestring_offset ))
1081             {
1082                 print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
1083                 *typestring_offset += 1;
1084             }
1085             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1086             *typestring_offset += 1;
1087
1088             return start_offset;
1089         }
1090     }
1091 }
1092
1093 static const var_t *find_array_or_string_in_struct(const type_t *type)
1094 {
1095     const var_t *last_field = LIST_ENTRY( list_tail(type->fields), const var_t, entry );
1096
1097     if (is_array_type(last_field->attrs, last_field->ptr_level, last_field->array))
1098         return last_field;
1099
1100     assert((last_field->type->type == RPC_FC_CSTRUCT) ||
1101            (last_field->type->type == RPC_FC_CPSTRUCT) ||
1102            (last_field->type->type == RPC_FC_CVSTRUCT));
1103
1104     return find_array_or_string_in_struct(last_field->type);
1105 }
1106
1107 static void write_struct_members(FILE *file, const type_t *type, unsigned int *typestring_offset)
1108 {
1109     const var_t *field;
1110
1111     if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1112     {
1113         unsigned char rtype = field->type->type;
1114
1115         if (field->array)
1116             write_array_tfs( file, field->attrs, field->type, field->array,
1117                              field->name, typestring_offset );
1118         else if (!write_base_type( file, field->type, typestring_offset ))
1119             error("Unsupported member type 0x%x\n", rtype);
1120     }
1121
1122     if (!(*typestring_offset % 2))
1123     {
1124         print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD);
1125         *typestring_offset += 1;
1126     }
1127
1128     print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END);
1129     *typestring_offset += 1;
1130 }
1131
1132 static size_t write_struct_tfs(FILE *file, const type_t *type,
1133                                const char *name, unsigned int *typestring_offset)
1134 {
1135     unsigned int total_size;
1136     const var_t *array;
1137     size_t start_offset;
1138     size_t array_offset;
1139     size_t pointer_offset;
1140     unsigned int align = 0;
1141
1142     switch (type->type)
1143     {
1144     case RPC_FC_STRUCT:
1145     case RPC_FC_PSTRUCT:
1146         total_size = type_memsize(type, 0, NULL, &align);
1147
1148         if (total_size > USHRT_MAX)
1149             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
1150                   name, USHRT_MAX, total_size - USHRT_MAX);
1151
1152         if (type->type == RPC_FC_PSTRUCT)
1153         {
1154             pointer_offset = *typestring_offset;
1155             write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset);
1156         }
1157         else pointer_offset = 0; /* silence warning */
1158
1159         start_offset = *typestring_offset;
1160         if (type->type == RPC_FC_STRUCT)
1161             WRITE_FCTYPE(file, FC_STRUCT, *typestring_offset);
1162         else
1163             WRITE_FCTYPE(file, FC_PSTRUCT, *typestring_offset);
1164         /* alignment */
1165         print_file(file, 2, "0x%02x,\n", align - 1);
1166         /* total size */
1167         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1168         *typestring_offset += 4;
1169
1170         if (type->type == RPC_FC_PSTRUCT)
1171         {
1172             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1173             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1174             *typestring_offset += 2;
1175             *typestring_offset += write_pointer_description(file, NULL,
1176                 type, 0, NULL, 0, pointer_offset);
1177             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1178             *typestring_offset += 1;
1179         }
1180
1181         /* member layout */
1182         write_struct_members(file, type, typestring_offset);
1183         return start_offset;
1184     case RPC_FC_CSTRUCT:
1185     case RPC_FC_CPSTRUCT:
1186         total_size = type_memsize(type, 0, NULL, &align);
1187
1188         if (total_size > USHRT_MAX)
1189             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
1190                   name, USHRT_MAX, total_size - USHRT_MAX);
1191
1192         array = find_array_or_string_in_struct(type);
1193         current_structure = type;
1194         array_offset = write_array_tfs(file, array->attrs, array->type,
1195                                        array->array, array->name,
1196                                        typestring_offset);
1197         current_structure = NULL;
1198
1199         if (type->type == RPC_FC_CPSTRUCT)
1200         {
1201             pointer_offset = *typestring_offset;
1202             write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset);
1203         }
1204         else pointer_offset = 0; /* silence warning */
1205
1206         start_offset = *typestring_offset;
1207         if (type->type == RPC_FC_CSTRUCT)
1208             WRITE_FCTYPE(file, FC_CSTRUCT, *typestring_offset);
1209         else
1210             WRITE_FCTYPE(file, FC_CPSTRUCT, *typestring_offset);
1211         /* alignment */
1212         print_file(file, 2, "0x%02x,\n", align - 1);
1213         /* total size */
1214         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1215         *typestring_offset += 4;
1216         print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d (%u) */\n",
1217                    array_offset - *typestring_offset,
1218                    array_offset - *typestring_offset,
1219                    array_offset);
1220         *typestring_offset += 2;
1221
1222         if (type->type == RPC_FC_CPSTRUCT)
1223         {
1224             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1225             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1226             *typestring_offset += 2;
1227             *typestring_offset += write_pointer_description(file, NULL,
1228                 type, 0, NULL, 0, pointer_offset);
1229             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1230             *typestring_offset += 1;
1231         }
1232
1233         print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1234         *typestring_offset += 1;
1235
1236         return start_offset;
1237     case RPC_FC_CVSTRUCT:
1238         total_size = type_memsize(type, 0, NULL, &align);
1239
1240         if (total_size > USHRT_MAX)
1241             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
1242                   name, USHRT_MAX, total_size - USHRT_MAX);
1243
1244         array = find_array_or_string_in_struct(type);
1245         current_structure = type;
1246         if (is_attr(array->attrs, ATTR_STRING))
1247             array_offset = write_string_tfs(file, array->attrs, array->type,
1248                                             array->array, array->name,
1249                                             typestring_offset);
1250         else
1251             array_offset = write_array_tfs(file, array->attrs, array->type,
1252                                            array->array, array->name,
1253                                            typestring_offset);
1254         current_structure = NULL;
1255
1256         pointer_offset = *typestring_offset;
1257         if (!write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset))
1258             pointer_offset = 0;
1259
1260         start_offset = *typestring_offset;
1261         WRITE_FCTYPE(file, FC_CVSTRUCT, *typestring_offset);
1262         /* alignment */
1263         print_file(file, 2, "0x%02x,\n", align - 1);
1264         /* total size */
1265         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1266         *typestring_offset += 4;
1267         print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d (%u) */\n",
1268                    array_offset - *typestring_offset,
1269                    array_offset - *typestring_offset,
1270                    array_offset);
1271         *typestring_offset += 2;
1272
1273         if (pointer_offset != 0)
1274         {
1275             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1276             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1277             *typestring_offset += 2;
1278             *typestring_offset += write_pointer_description(file, NULL,
1279                 type, 0, NULL, 0, pointer_offset);
1280             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1281             *typestring_offset += 1;
1282         }
1283
1284         print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1285         *typestring_offset += 1;
1286
1287         return start_offset;
1288     default:
1289         error("write_struct_tfs: Unimplemented for type 0x%x\n", type->type);
1290         return *typestring_offset;
1291     }
1292 }
1293
1294 static void write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
1295                                    unsigned char flags, size_t offset,
1296                                    unsigned int *typeformat_offset)
1297 {
1298     int in_attr, out_attr;
1299     in_attr = is_attr(attrs, ATTR_IN);
1300     out_attr = is_attr(attrs, ATTR_OUT);
1301     if (!in_attr && !out_attr) in_attr = 1;
1302
1303     if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
1304         flags |= 0x04;
1305
1306     print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
1307                pointer_type,
1308                flags,
1309                pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"));
1310     if (file)
1311     {
1312         if (flags & 0x04)
1313             fprintf(file, " [allocated_on_stack]");
1314         if (flags & 0x10)
1315             fprintf(file, " [pointer_deref]");
1316         fprintf(file, " */\n");
1317     }
1318
1319     print_file(file, 2, "NdrFcShort(0x%x),    /* %d */\n", offset, offset);
1320     *typeformat_offset += 4;
1321 }
1322
1323 static size_t write_union_tfs(FILE *file, const attr_list_t *attrs,
1324                               const type_t *type, const char *name,
1325                               unsigned int *typeformat_offset)
1326 {
1327     error("write_union_tfs: Unimplemented\n");
1328     return *typeformat_offset;
1329 }
1330
1331 static size_t write_ip_tfs(FILE *file, const func_t *func, const var_t *var,
1332                            unsigned int *typeformat_offset)
1333 {
1334     size_t i;
1335     size_t start_offset = *typeformat_offset;
1336     const var_t *iid = get_attrp(var->attrs, ATTR_IIDIS);
1337
1338     if (iid)
1339     {
1340         expr_t expr;
1341         expr_list_t expr_list;
1342
1343         expr.type = EXPR_IDENTIFIER;
1344         expr.ref  = NULL;
1345         expr.u.sval = iid->name;
1346         expr.is_const = FALSE;
1347         list_init( &expr_list );
1348         list_add_head( &expr_list, &expr.entry );
1349         print_file(file, 2, "0x2f,  /* FC_IP */\n");
1350         print_file(file, 2, "0x5c,  /* FC_PAD */\n");
1351         *typeformat_offset += write_conf_or_var_desc(file, func, NULL, &expr_list) + 2;
1352     }
1353     else
1354     {
1355         const type_t *base = is_ptr(var->type) ? var->type->ref : var->type;
1356         const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
1357
1358         if (! uuid)
1359             error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
1360
1361         print_file(file, 2, "0x2f,\t/* FC_IP */\n");
1362         print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
1363         print_file(file, 2, "NdrFcLong(0x%08lx),\n", uuid->Data1);
1364         print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2);
1365         print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3);
1366         for (i = 0; i < 8; ++i)
1367             print_file(file, 2, "0x%02x,\n", uuid->Data4[i]);
1368
1369         if (file)
1370             fprintf(file, "\n");
1371
1372         *typeformat_offset += 18;
1373     }
1374     return start_offset;
1375 }
1376
1377 static int get_ptr_attr(const type_t *t, int def_type)
1378 {
1379     while (TRUE)
1380     {
1381         int ptr_attr = get_attrv(t->attrs, ATTR_POINTERTYPE);
1382         if (ptr_attr)
1383             return ptr_attr;
1384         if (t->kind != TKIND_ALIAS)
1385             return def_type;
1386         t = t->orig;
1387     }
1388 }
1389
1390 static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *func,
1391                                          const var_t *var, unsigned int *typeformat_offset)
1392 {
1393     const type_t *type = var->type;
1394     int var_ptrs = var->ptr_level, type_ptrs = 0;
1395     int is_str = is_attr(var->attrs, ATTR_STRING);
1396
1397     chat("write_typeformatstring_var: %s\n", var->name);
1398
1399     while (TRUE)
1400     {
1401         is_str = is_str || is_attr(type->attrs, ATTR_STRING);
1402         if (type->kind == TKIND_ALIAS)
1403             type = type->orig;
1404         else if (is_ptr(type))
1405         {
1406             ++type_ptrs;
1407             type = type->ref;
1408         }
1409         else
1410         {
1411             type = var->type;
1412             break;
1413         }
1414     }
1415
1416     while (TRUE)
1417     {
1418         int ptr_level = var_ptrs + type_ptrs;
1419         int pointer_type = 0;
1420
1421         chat("write_typeformatstring: type->type = 0x%x, type->name = %s, ptr_level = %d\n", type->type, type->name, ptr_level);
1422
1423         /* var attrs only effect the rightmost pointer  */
1424         if ((0 < var->ptr_level && var_ptrs == var->ptr_level)
1425             || (var->ptr_level == 0 && type == var->type))
1426         {
1427             int pointer_attr = get_attrv(var->attrs, ATTR_POINTERTYPE);
1428             if (pointer_attr)
1429             {
1430                 if (! ptr_level)
1431                     error("'%s': pointer attribute applied to non-pointer type",
1432                           var->name);
1433                 pointer_type = pointer_attr;
1434             }
1435             else
1436                 pointer_type = RPC_FC_RP;
1437         }
1438         else                            /* pointers below other pointers default to unique */
1439             pointer_type = var_ptrs ? RPC_FC_UP : get_ptr_attr(type, RPC_FC_UP);
1440
1441         if (is_str && ptr_level + (var->array != NULL) == 1)
1442             return write_string_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
1443
1444         if (is_array_type(var->attrs, ptr_level, var->array))
1445             return write_array_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
1446
1447         if (ptr_level == 0)
1448         {
1449             /* basic types don't need a type format string */
1450             if (is_base_type(type->type))
1451                 return 0;
1452
1453             switch (type->type)
1454             {
1455             case RPC_FC_STRUCT:
1456             case RPC_FC_PSTRUCT:
1457             case RPC_FC_CSTRUCT:
1458             case RPC_FC_CPSTRUCT:
1459             case RPC_FC_CVSTRUCT:
1460             case RPC_FC_BOGUS_STRUCT:
1461                 return write_struct_tfs(file, type, var->name, typeformat_offset);
1462             case RPC_FC_ENCAPSULATED_UNION:
1463             case RPC_FC_NON_ENCAPSULATED_UNION:
1464                 return write_union_tfs(file, var->attrs, type, var->name, typeformat_offset);
1465             case RPC_FC_IGNORE:
1466             case RPC_FC_BIND_PRIMITIVE:
1467                 /* nothing to do */
1468                 return 0;
1469             default:
1470                 error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
1471             }
1472         }
1473         else if (ptr_level == 1)
1474         {
1475             size_t start_offset = *typeformat_offset;
1476             int in_attr = is_attr(var->attrs, ATTR_IN);
1477             int out_attr = is_attr(var->attrs, ATTR_OUT);
1478             const type_t *base = is_ptr(type) ? type->ref : type;
1479
1480             if (base->type == RPC_FC_IP)
1481             {
1482                 return write_ip_tfs(file, func, var, typeformat_offset);
1483             }
1484
1485             /* special case for pointers to base types */
1486             switch (base->type)
1487             {
1488 #define CASE_BASETYPE(fctype) \
1489             case RPC_##fctype: \
1490                 print_file(file, indent, "0x%x, 0x%x,    /* %s %s[simple_pointer] */\n", \
1491                            pointer_type, \
1492                            (!in_attr && out_attr) ? 0x0C : 0x08, \
1493                            pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"), \
1494                            (!in_attr && out_attr) ? "[allocated_on_stack] " : ""); \
1495                 print_file(file, indent, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
1496                 print_file(file, indent, "0x5c,          /* FC_PAD */\n"); \
1497                 *typeformat_offset += 4; \
1498                 return start_offset
1499             CASE_BASETYPE(FC_BYTE);
1500             CASE_BASETYPE(FC_CHAR);
1501             CASE_BASETYPE(FC_SMALL);
1502             CASE_BASETYPE(FC_USMALL);
1503             CASE_BASETYPE(FC_WCHAR);
1504             CASE_BASETYPE(FC_SHORT);
1505             CASE_BASETYPE(FC_USHORT);
1506             CASE_BASETYPE(FC_LONG);
1507             CASE_BASETYPE(FC_ULONG);
1508             CASE_BASETYPE(FC_FLOAT);
1509             CASE_BASETYPE(FC_HYPER);
1510             CASE_BASETYPE(FC_DOUBLE);
1511             CASE_BASETYPE(FC_ENUM16);
1512             CASE_BASETYPE(FC_ENUM32);
1513             CASE_BASETYPE(FC_IGNORE);
1514             CASE_BASETYPE(FC_ERROR_STATUS_T);
1515             default:
1516                 break;
1517             }
1518         }
1519
1520         assert(ptr_level > 0);
1521
1522         if (file)
1523             fprintf(file, "/* %2u */\n", *typeformat_offset);
1524         write_pointer_only_tfs(file, var->attrs, pointer_type,
1525                                1 < ptr_level ? 0x10 : 0,
1526                                2, typeformat_offset);
1527
1528         if (var_ptrs)
1529             --var_ptrs;
1530         else
1531         {
1532             --type_ptrs;
1533             type = type->ref;
1534         }
1535     }
1536 }
1537
1538
1539 void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, int for_objects)
1540 {
1541     int indent = 0;
1542     const var_t *var;
1543     unsigned int typeformat_offset;
1544     const ifref_t *iface;
1545
1546     print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
1547     print_file(file, indent, "{\n");
1548     indent++;
1549     print_file(file, indent, "0,\n");
1550     print_file(file, indent, "{\n");
1551     indent++;
1552     print_file(file, indent, "NdrFcShort(0x0),\n");
1553     typeformat_offset = 2;
1554
1555     if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
1556     {
1557         if (for_objects != is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
1558             continue;
1559
1560         if (iface->iface->funcs)
1561         {
1562             const func_t *func;
1563             LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
1564             {
1565                 if (is_local(func->def->attrs)) continue;
1566                 current_func = func;
1567                 if (func->args)
1568                     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
1569                         write_typeformatstring_var(file, indent, func, var,
1570                                                    &typeformat_offset);
1571             }
1572         }
1573     }
1574
1575     print_file(file, indent, "0x0\n");
1576     indent--;
1577     print_file(file, indent, "}\n");
1578     indent--;
1579     print_file(file, indent, "};\n");
1580     print_file(file, indent, "\n");
1581 }
1582
1583 static unsigned int get_required_buffer_size_type(
1584     const type_t *type, int ptr_level, const array_dims_t *array,
1585     const char *name, unsigned int *alignment)
1586 {
1587     size_t size = 0;
1588
1589     *alignment = 0;
1590     if (ptr_level == 0)
1591     {
1592         switch (type->type)
1593         {
1594         case RPC_FC_BYTE:
1595         case RPC_FC_CHAR:
1596         case RPC_FC_USMALL:
1597         case RPC_FC_SMALL:
1598             *alignment = 4;
1599             size = 1;
1600             break;
1601
1602         case RPC_FC_WCHAR:
1603         case RPC_FC_USHORT:
1604         case RPC_FC_SHORT:
1605             *alignment = 4;
1606             size = 2;
1607             break;
1608
1609         case RPC_FC_ULONG:
1610         case RPC_FC_LONG:
1611         case RPC_FC_FLOAT:
1612         case RPC_FC_ERROR_STATUS_T:
1613             *alignment = 4;
1614             size = 4;
1615             break;
1616
1617         case RPC_FC_HYPER:
1618         case RPC_FC_DOUBLE:
1619             *alignment = 8;
1620             size = 8;
1621             break;
1622
1623         case RPC_FC_IGNORE:
1624         case RPC_FC_BIND_PRIMITIVE:
1625             return 0;
1626
1627         case RPC_FC_STRUCT:
1628         {
1629             const var_t *field;
1630             if (!type->fields) return 0;
1631             LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1632             {
1633                 unsigned int alignment;
1634                 size += get_required_buffer_size_type(
1635                     field->type, field->ptr_level, field->array, field->name,
1636                     &alignment);
1637             }
1638             break;
1639         }
1640
1641         case RPC_FC_RP:
1642             if (is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT)
1643                 size = get_required_buffer_size_type( type->ref, 0, NULL, name, alignment );
1644             break;
1645
1646         default:
1647             error("get_required_buffer_size: Unknown/unsupported type: %s (0x%02x)\n", name, type->type);
1648             return 0;
1649         }
1650         if (array) size *= get_array_size( array );
1651     }
1652     return size;
1653 }
1654
1655 static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
1656 {
1657     expr_list_t *size_is = get_attrp(var->attrs, ATTR_SIZEIS);
1658     int has_size = is_non_void(size_is);
1659     int in_attr = is_attr(var->attrs, ATTR_IN);
1660     int out_attr = is_attr(var->attrs, ATTR_OUT);
1661
1662     if (!in_attr && !out_attr)
1663         in_attr = 1;
1664
1665     *alignment = 0;
1666
1667     if (pass == PASS_OUT)
1668     {
1669         if (out_attr && var->ptr_level > 0)
1670         {
1671             type_t *type = var->type;
1672
1673             if (type->type == RPC_FC_STRUCT)
1674             {
1675                 const var_t *field;
1676                 unsigned int size = 36;
1677
1678                 if (!type->fields) return size;
1679                 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1680                 {
1681                     unsigned int align;
1682                     size += get_required_buffer_size_type(
1683                         field->type, field->ptr_level, field->array, field->name,
1684                         &align);
1685                 }
1686                 return size;
1687             }
1688         }
1689         return 0;
1690     }
1691     else
1692     {
1693         if ((!out_attr || in_attr) && !has_size && !is_attr(var->attrs, ATTR_STRING) && !var->array)
1694         {
1695             if (var->ptr_level > 0)
1696             {
1697                 type_t *type = var->type;
1698
1699                 if (is_base_type(type->type))
1700                 {
1701                     return 25;
1702                 }
1703                 else if (type->type == RPC_FC_STRUCT)
1704                 {
1705                     unsigned int size = 36;
1706                     const var_t *field;
1707
1708                     if (!type->fields) return size;
1709                     LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1710                     {
1711                         unsigned int align;
1712                         size += get_required_buffer_size_type(
1713                             field->type, field->ptr_level, field->array, field->name,
1714                             &align);
1715                     }
1716                     return size;
1717                 }
1718             }
1719         }
1720
1721         return get_required_buffer_size_type(var->type, var->ptr_level, var->array, var->name, alignment);
1722     }
1723 }
1724
1725 static unsigned int get_function_buffer_size( const func_t *func, enum pass pass )
1726 {
1727     const var_t *var;
1728     unsigned int total_size = 0, alignment;
1729
1730     if (func->args)
1731     {
1732         LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
1733         {
1734             total_size += get_required_buffer_size(var, &alignment, pass);
1735             total_size += alignment;
1736         }
1737     }
1738
1739     if (pass == PASS_OUT && !is_void(func->def->type, NULL))
1740     {
1741         total_size += get_required_buffer_size(func->def, &alignment, PASS_RETURN);
1742         total_size += alignment;
1743     }
1744     return total_size;
1745 }
1746
1747 static void print_phase_function(FILE *file, int indent, const char *type,
1748                                  enum remoting_phase phase,
1749                                  const char *varname, unsigned int type_offset)
1750 {
1751     const char *function;
1752     switch (phase)
1753     {
1754     case PHASE_BUFFERSIZE:
1755         function = "BufferSize";
1756         break;
1757     case PHASE_MARSHAL:
1758         function = "Marshall";
1759         break;
1760     case PHASE_UNMARSHAL:
1761         function = "Unmarshall";
1762         break;
1763     case PHASE_FREE:
1764         function = "Free";
1765         break;
1766     default:
1767         assert(0);
1768         return;
1769     }
1770
1771     print_file(file, indent, "Ndr%s%s(\n", type, function);
1772     indent++;
1773     print_file(file, indent, "&_StubMsg,\n");
1774     print_file(file, indent, "%s%s,\n",
1775                (phase == PHASE_UNMARSHAL) ? "(unsigned char **)&" : "(unsigned char *)",
1776                varname);
1777     print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
1778                type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
1779     if (phase == PHASE_UNMARSHAL)
1780         print_file(file, indent, "0);\n");
1781     indent--;
1782 }
1783
1784 void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
1785                           enum pass pass, const var_t *var,
1786                           const char *varname)
1787 {
1788     const type_t *type = var->type;
1789     unsigned int size;
1790     unsigned int alignment = 0;
1791     unsigned char rtype;
1792
1793     /* no work to do for other phases, buffer sizing is done elsewhere */
1794     if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
1795         return;
1796
1797     rtype = type->type;
1798
1799     switch (rtype)
1800     {
1801         case RPC_FC_BYTE:
1802         case RPC_FC_CHAR:
1803         case RPC_FC_SMALL:
1804         case RPC_FC_USMALL:
1805             size = 1;
1806             alignment = 1;
1807             break;
1808
1809         case RPC_FC_WCHAR:
1810         case RPC_FC_USHORT:
1811         case RPC_FC_SHORT:
1812             size = 2;
1813             alignment = 2;
1814             break;
1815
1816         case RPC_FC_ULONG:
1817         case RPC_FC_LONG:
1818         case RPC_FC_FLOAT:
1819         case RPC_FC_ERROR_STATUS_T:
1820             size = 4;
1821             alignment = 4;
1822             break;
1823
1824         case RPC_FC_HYPER:
1825         case RPC_FC_DOUBLE:
1826             size = 8;
1827             alignment = 8;
1828             break;
1829
1830         case RPC_FC_IGNORE:
1831         case RPC_FC_BIND_PRIMITIVE:
1832             /* no marshalling needed */
1833             return;
1834
1835         default:
1836             error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, rtype);
1837             size = 0;
1838     }
1839
1840     print_file(file, indent, "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
1841                 alignment - 1, alignment - 1);
1842
1843     if (phase == PHASE_MARSHAL)
1844     {
1845         print_file(file, indent, "*(");
1846         write_type(file, var->type, NULL, var->tname);
1847         if (var->ptr_level)
1848             fprintf(file, " *)_StubMsg.Buffer = *");
1849         else
1850             fprintf(file, " *)_StubMsg.Buffer = ");
1851         fprintf(file, varname);
1852         fprintf(file, ";\n");
1853     }
1854     else if (phase == PHASE_UNMARSHAL)
1855     {
1856         if (pass == PASS_IN || pass == PASS_RETURN)
1857             print_file(file, indent, "");
1858         else
1859             print_file(file, indent, "*");
1860         fprintf(file, varname);
1861         if (pass == PASS_IN && var->ptr_level)
1862             fprintf(file, " = (");
1863         else
1864             fprintf(file, " = *(");
1865         write_type(file, var->type, NULL, var->tname);
1866         fprintf(file, " *)_StubMsg.Buffer;\n");
1867     }
1868
1869     print_file(file, indent, "_StubMsg.Buffer += sizeof(");
1870     write_type(file, var->type, NULL, var->tname);
1871     fprintf(file, ");\n");
1872 }
1873
1874 /* returns whether the MaxCount, Offset or ActualCount members need to be
1875  * filled in for the specified phase */
1876 static inline int is_size_needed_for_phase(enum remoting_phase phase)
1877 {
1878     return (phase != PHASE_UNMARSHAL);
1879 }
1880
1881 void write_remoting_arguments(FILE *file, int indent, const func_t *func,
1882                               unsigned int *type_offset, enum pass pass,
1883                               enum remoting_phase phase)
1884 {
1885     const expr_list_t *length_is;
1886     const expr_list_t *size_is;
1887     int in_attr, out_attr, has_length, has_size, pointer_type;
1888     const var_t *var;
1889
1890     if (!func->args)
1891         return;
1892
1893     if (phase == PHASE_BUFFERSIZE)
1894     {
1895         unsigned int size = get_function_buffer_size( func, pass );
1896         print_file(file, indent, "_StubMsg.BufferLength = %u;\n", size);
1897     }
1898
1899     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
1900     {
1901         const type_t *type = var->type;
1902         unsigned char rtype;
1903
1904         length_is = get_attrp(var->attrs, ATTR_LENGTHIS);
1905         size_is = get_attrp(var->attrs, ATTR_SIZEIS);
1906         has_length = is_non_void(length_is);
1907         has_size = is_non_void(size_is) || (var->array && is_conformant_array(var->array));
1908
1909         pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
1910         if (!pointer_type)
1911             pointer_type = RPC_FC_RP;
1912
1913         in_attr = is_attr(var->attrs, ATTR_IN);
1914         out_attr = is_attr(var->attrs, ATTR_OUT);
1915         if (!in_attr && !out_attr)
1916             in_attr = 1;
1917
1918         switch (pass)
1919         {
1920         case PASS_IN:
1921             if (!in_attr) goto next;
1922             break;
1923         case PASS_OUT:
1924             if (!out_attr) goto next;
1925             break;
1926         case PASS_RETURN:
1927             break;
1928         }
1929
1930         rtype = type->type;
1931
1932         if (is_user_derived( var ))
1933         {
1934             print_phase_function(file, indent, "UserMarshal", phase, var->name, *type_offset);
1935         }
1936         else if (is_string_type(var->attrs, var->ptr_level, var->array))
1937         {
1938             if (var->array && !is_conformant_array(var->array))
1939                 print_phase_function(file, indent, "NonConformantString", phase, var->name, *type_offset);
1940             else
1941             {
1942                 if (size_is && is_size_needed_for_phase(phase))
1943                 {
1944                     const expr_t *size = LIST_ENTRY( list_head(size_is), const expr_t, entry );
1945                     print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1946                     write_expr(file, size, 1);
1947                     fprintf(file, ";\n");
1948                 }
1949
1950                 if ((phase == PHASE_FREE) || (pointer_type == RPC_FC_UP))
1951                     print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
1952                 else
1953                     print_phase_function(file, indent, "ConformantString", phase, var->name,
1954                                          *type_offset + (has_size ? 4 : 2));
1955             }
1956         }
1957         else if (is_array_type(var->attrs, var->ptr_level, var->array))
1958         {
1959             const char *array_type;
1960
1961             if (var->array && list_count(var->array) > 1) /* multi-dimensional array */
1962                 array_type = "ComplexArray";
1963             else
1964             {
1965                 if (!has_length && !has_size)
1966                     array_type = "FixedArray";
1967                 else if (has_length && !has_size)
1968                 {
1969                     if (is_size_needed_for_phase(phase))
1970                     {
1971                         const expr_t *length = LIST_ENTRY( list_head(length_is), const expr_t, entry );
1972                         print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
1973                         print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
1974                         write_expr(file, length, 1);
1975                         fprintf(file, ";\n\n");
1976                     }
1977                     array_type = "VaryingArray";
1978                 }
1979                 else if (!has_length && has_size)
1980                 {
1981                     if (is_size_needed_for_phase(phase) && phase != PHASE_FREE)
1982                     {
1983                         const expr_t *size = LIST_ENTRY( list_head(size_is ? size_is : var->array),
1984                                                          const expr_t, entry );
1985                         print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1986                         write_expr(file, size, 1);
1987                         fprintf(file, ";\n\n");
1988                     }
1989                     array_type = "ConformantArray";
1990                 }
1991                 else
1992                 {
1993                     if (is_size_needed_for_phase(phase))
1994                     {
1995                         const expr_t *length = LIST_ENTRY( list_head(length_is), const expr_t, entry );
1996                         const expr_t *size = LIST_ENTRY( list_head(size_is ? size_is : var->array),
1997                                                          const expr_t, entry );
1998                         print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1999                         write_expr(file, size, 1);
2000                         fprintf(file, ";\n");
2001                         print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2002                         print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2003                         write_expr(file, length, 1);
2004                         fprintf(file, ";\n\n");
2005                     }
2006                     array_type = "ConformantVaryingArray";
2007                 }
2008             }
2009
2010             if (!in_attr && phase == PHASE_FREE)
2011             {
2012                 print_file(file, indent, "if (%s)\n", var->name);
2013                 indent++;
2014                 print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
2015             }
2016             else if (phase != PHASE_FREE)
2017             {
2018                 if (pointer_type == RPC_FC_UP)
2019                     print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
2020                 else
2021                     print_phase_function(file, indent, array_type, phase, var->name, *type_offset + 4);
2022             }
2023         }
2024         else if (var->ptr_level == 0 && is_base_type(rtype))
2025         {
2026             print_phase_basetype(file, indent, phase, pass, var, var->name);
2027         }
2028         else if (var->ptr_level == 0)
2029         {
2030             switch (rtype)
2031             {
2032             case RPC_FC_STRUCT:
2033                 print_phase_function(file, indent, "SimpleStruct", phase, var->name, *type_offset);
2034                 break;
2035             case RPC_FC_CSTRUCT:
2036             case RPC_FC_CPSTRUCT:
2037                 print_phase_function(file, indent, "ConformantStruct", phase, var->name, *type_offset);
2038                 break;
2039             case RPC_FC_CVSTRUCT:
2040                 print_phase_function(file, indent, "ConformantVaryingStruct", phase, var->name, *type_offset);
2041                 break;
2042             case RPC_FC_BOGUS_STRUCT:
2043                 print_phase_function(file, indent, "ComplexStruct", phase, var->name, *type_offset);
2044                 break;
2045             case RPC_FC_RP:
2046                 if (is_base_type( var->type->ref->type ))
2047                 {
2048                     print_phase_basetype(file, indent, phase, pass, var, var->name);
2049                 }
2050                 else if (var->type->ref->type == RPC_FC_STRUCT)
2051                 {
2052                     if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2053                         print_phase_function(file, indent, "SimpleStruct", phase, var->name, *type_offset + 4);
2054                 }
2055                 else
2056                 {
2057                     const var_t *iid;
2058                     if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2059                         print_file( file, indent, "_StubMsg.MaxCount = (unsigned long)%s;\n", iid->name );
2060                     print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
2061                 }
2062                 break;
2063             default:
2064                 error("write_remoting_arguments: Unsupported type: %s (0x%02x, ptr_level: %d)\n",
2065                     var->name, rtype, var->ptr_level);
2066             }
2067         }
2068         else
2069         {
2070             if ((var->ptr_level == 1) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
2071             {
2072                 print_phase_basetype(file, indent, phase, pass, var, var->name);
2073             }
2074             else if ((var->ptr_level == 1) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
2075             {
2076                 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2077                     print_phase_function(file, indent, "SimpleStruct", phase, var->name, *type_offset + 4);
2078             }
2079             else
2080             {
2081                 const var_t *iid;
2082                 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2083                     print_file( file, indent, "_StubMsg.MaxCount = (unsigned long)%s;\n", iid->name );
2084                 print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
2085             }
2086         }
2087         fprintf(file, "\n");
2088     next:
2089         *type_offset += get_size_typeformatstring_var(var);
2090     }
2091 }
2092
2093
2094 size_t get_size_procformatstring_var(const var_t *var)
2095 {
2096     unsigned int type_offset = 2;
2097     return write_procformatstring_var(NULL, 0, var, FALSE, &type_offset);
2098 }
2099
2100
2101 size_t get_size_procformatstring_func(const func_t *func)
2102 {
2103     const var_t *var;
2104     size_t size = 0;
2105
2106     /* argument list size */
2107     if (func->args)
2108         LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2109             size += get_size_procformatstring_var(var);
2110
2111     /* return value size */
2112     if (is_void(func->def->type, NULL))
2113         size += 2; /* FC_END and FC_PAD */
2114     else
2115         size += get_size_procformatstring_var(func->def);
2116
2117     return size;
2118 }
2119
2120 size_t get_size_typeformatstring_var(const var_t *var)
2121 {
2122     unsigned int type_offset = 0;
2123     write_typeformatstring_var(NULL, 0, NULL, var, &type_offset);
2124     return type_offset;
2125 }
2126
2127 size_t get_size_procformatstring(const ifref_list_t *ifaces, int for_objects)
2128 {
2129     const ifref_t *iface;
2130     size_t size = 1;
2131     const func_t *func;
2132
2133     if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
2134     {
2135         if (for_objects != is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
2136             continue;
2137
2138         if (iface->iface->funcs)
2139             LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
2140                 if (!is_local(func->def->attrs))
2141                     size += get_size_procformatstring_func( func );
2142     }
2143     return size;
2144 }
2145
2146 size_t get_size_typeformatstring(const ifref_list_t *ifaces, int for_objects)
2147 {
2148     const ifref_t *iface;
2149     size_t size = 3;
2150     const func_t *func;
2151     const var_t *var;
2152
2153     if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
2154     {
2155         if (for_objects != is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
2156             continue;
2157
2158         if (iface->iface->funcs)
2159         {
2160             LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
2161             {
2162                 if (is_local(func->def->attrs)) continue;
2163                 /* argument list size */
2164                 if (func->args)
2165                     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2166                         size += get_size_typeformatstring_var(var);
2167             }
2168         }
2169     }
2170     return size;
2171 }
2172
2173 static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
2174                               const var_list_t *fields, const char *structvar)
2175 {
2176     switch (e->type) {
2177         case EXPR_VOID:
2178             break;
2179         case EXPR_NUM:
2180             fprintf(h, "%ld", e->u.lval);
2181             break;
2182         case EXPR_HEXNUM:
2183             fprintf(h, "0x%lx", e->u.lval);
2184             break;
2185         case EXPR_TRUEFALSE:
2186             if (e->u.lval == 0)
2187                 fprintf(h, "FALSE");
2188             else
2189                 fprintf(h, "TRUE");
2190             break;
2191         case EXPR_IDENTIFIER:
2192         {
2193             const var_t *field;
2194             LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
2195                 if (!strcmp(e->u.sval, field->name))
2196                 {
2197                     fprintf(h, "%s->%s", structvar, e->u.sval);
2198                     break;
2199                 }
2200
2201             if (&field->entry == fields) error("no field found for identifier %s\n", e->u.sval);
2202             break;
2203         }
2204         case EXPR_NEG:
2205             fprintf(h, "-");
2206             write_struct_expr(h, e->ref, 1, fields, structvar);
2207             break;
2208         case EXPR_NOT:
2209             fprintf(h, "~");
2210             write_struct_expr(h, e->ref, 1, fields, structvar);
2211             break;
2212         case EXPR_PPTR:
2213             fprintf(h, "*");
2214             write_struct_expr(h, e->ref, 1, fields, structvar);
2215             break;
2216         case EXPR_CAST:
2217             fprintf(h, "(");
2218             write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
2219             fprintf(h, ")");
2220             write_struct_expr(h, e->ref, 1, fields, structvar);
2221             break;
2222         case EXPR_SIZEOF:
2223             fprintf(h, "sizeof(");
2224             write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
2225             fprintf(h, ")");
2226             break;
2227         case EXPR_SHL:
2228         case EXPR_SHR:
2229         case EXPR_MUL:
2230         case EXPR_DIV:
2231         case EXPR_ADD:
2232         case EXPR_SUB:
2233         case EXPR_AND:
2234         case EXPR_OR:
2235             if (brackets) fprintf(h, "(");
2236             write_struct_expr(h, e->ref, 1, fields, structvar);
2237             switch (e->type) {
2238                 case EXPR_SHL: fprintf(h, " << "); break;
2239                 case EXPR_SHR: fprintf(h, " >> "); break;
2240                 case EXPR_MUL: fprintf(h, " * "); break;
2241                 case EXPR_DIV: fprintf(h, " / "); break;
2242                 case EXPR_ADD: fprintf(h, " + "); break;
2243                 case EXPR_SUB: fprintf(h, " - "); break;
2244                 case EXPR_AND: fprintf(h, " & "); break;
2245                 case EXPR_OR:  fprintf(h, " | "); break;
2246                 default: break;
2247             }
2248             write_struct_expr(h, e->u.ext, 1, fields, structvar);
2249             if (brackets) fprintf(h, ")");
2250             break;
2251         case EXPR_COND:
2252             if (brackets) fprintf(h, "(");
2253             write_struct_expr(h, e->ref, 1, fields, structvar);
2254             fprintf(h, " ? ");
2255             write_struct_expr(h, e->u.ext, 1, fields, structvar);
2256             fprintf(h, " : ");
2257             write_struct_expr(h, e->ext2, 1, fields, structvar);
2258             if (brackets) fprintf(h, ")");
2259             break;
2260     }
2261 }
2262
2263
2264 void declare_stub_args( FILE *file, int indent, const func_t *func )
2265 {
2266     int in_attr, out_attr;
2267     int i = 0;
2268     const var_t *def = func->def;
2269     const var_t *var;
2270
2271     /* declare return value '_RetVal' */
2272     if (!is_void(def->type, NULL))
2273     {
2274         print_file(file, indent, "");
2275         write_type(file, def->type, def, def->tname);
2276         fprintf(file, " _RetVal;\n");
2277     }
2278
2279     if (!func->args)
2280         return;
2281
2282     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2283     {
2284         const expr_list_t *size_is = get_attrp(var->attrs, ATTR_SIZEIS);
2285         int has_size = is_non_void(size_is);
2286         int is_string = is_attr(var->attrs, ATTR_STRING);
2287
2288         in_attr = is_attr(var->attrs, ATTR_IN);
2289         out_attr = is_attr(var->attrs, ATTR_OUT);
2290         if (!out_attr && !in_attr)
2291             in_attr = 1;
2292
2293         if (!in_attr && !has_size && !is_string)
2294         {
2295             int indirection;
2296             print_file(file, indent, "");
2297             write_type(file, var->type, NULL, var->tname);
2298             for (indirection = 0; indirection < var->ptr_level - 1; indirection++)
2299                 fprintf(file, "*");
2300             fprintf(file, " _W%u;\n", i++);
2301         }
2302
2303         print_file(file, indent, "");
2304         write_type(file, var->type, var, var->tname);
2305         fprintf(file, " ");
2306         write_name(file, var);
2307         write_array(file, var->array, 0);
2308         fprintf(file, ";\n");
2309     }
2310 }
2311
2312
2313 void assign_stub_out_args( FILE *file, int indent, const func_t *func )
2314 {
2315     int in_attr, out_attr;
2316     int i = 0, sep = 0;
2317     const var_t *var;
2318     const expr_list_t *size_is;
2319     int has_size;
2320
2321     if (!func->args)
2322         return;
2323
2324     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2325     {
2326         int is_string = is_attr(var->attrs, ATTR_STRING);
2327         size_is = get_attrp(var->attrs, ATTR_SIZEIS);
2328         has_size = is_non_void(size_is);
2329         in_attr = is_attr(var->attrs, ATTR_IN);
2330         out_attr = is_attr(var->attrs, ATTR_OUT);
2331         if (!out_attr && !in_attr)
2332             in_attr = 1;
2333
2334         if (!in_attr)
2335         {
2336             print_file(file, indent, "");
2337             write_name(file, var);
2338
2339             if (has_size)
2340             {
2341                 const expr_t *expr;
2342                 unsigned int size, align = 0;
2343                 type_t *type = var->type;
2344
2345                 fprintf(file, " = NdrAllocate(&_StubMsg, ");
2346                 LIST_FOR_EACH_ENTRY( expr, size_is, const expr_t, entry )
2347                 {
2348                     if (expr->type == EXPR_VOID) continue;
2349                     write_expr( file, expr, 1 );
2350                     fprintf(file, " * ");
2351                 }
2352                 size = type_memsize(type, 0, NULL, &align);
2353                 fprintf(file, "%u);\n", size);
2354             }
2355             else if (!is_string)
2356             {
2357                 fprintf(file, " = &_W%u;\n", i);
2358                 if (var->ptr_level > 1)
2359                     print_file(file, indent, "_W%u = 0;\n", i);
2360                 i++;
2361             }
2362
2363             sep = 1;
2364         }
2365     }
2366     if (sep)
2367         fprintf(file, "\n");
2368 }
2369
2370
2371 int write_expr_eval_routines(FILE *file, const char *iface)
2372 {
2373     int result = 0;
2374     struct expr_eval_routine *eval;
2375     unsigned short callback_offset = 0;
2376
2377     LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
2378     {
2379         int indent = 0;
2380         result = 1;
2381         print_file(file, indent, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
2382                   iface, eval->structure->name, callback_offset);
2383         print_file(file, indent, "{\n");
2384         indent++;
2385         print_file(file, indent, "struct %s *" STRUCT_EXPR_EVAL_VAR " = (struct %s *)(pStubMsg->StackTop - %u);\n",
2386                    eval->structure->name, eval->structure->name, eval->structure_size);
2387         fprintf(file, "\n");
2388         print_file(file, indent, "pStubMsg->Offset = 0;\n"); /* FIXME */
2389         print_file(file, indent, "pStubMsg->MaxCount = (unsigned long)");
2390         write_struct_expr(file, eval->expr, 1, eval->structure->fields, STRUCT_EXPR_EVAL_VAR);
2391         fprintf(file, ";\n");
2392         indent--;
2393         print_file(file, indent, "}\n\n");
2394         callback_offset++;
2395     }
2396     return result;
2397 }
2398
2399 void write_expr_eval_routine_list(FILE *file, const char *iface)
2400 {
2401     struct expr_eval_routine *eval;
2402     struct expr_eval_routine *cursor;
2403     unsigned short callback_offset = 0;
2404
2405     fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
2406     fprintf(file, "{\n");
2407
2408     LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
2409     {
2410         print_file(file, 1, "%s_%sExprEval_%04u,\n",
2411                    iface, eval->structure->name, callback_offset);
2412
2413         callback_offset++;
2414         list_remove(&eval->entry);
2415         free(eval);
2416     }
2417
2418     fprintf(file, "};\n\n");
2419 }