widl: Changes to output for better debugability.
[wine] / tools / widl / typegen.c
1 /*
2  * Format String Generator for IDL Compiler
3  *
4  * Copyright 2005 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 expr_t *array);
63 static size_t fields_memsize(const var_t *v);
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             return a->u.lval - b->u.lval;
77         case EXPR_IDENTIFIER:
78             return strcmp(a->u.sval, b->u.sval);
79         case EXPR_COND:
80             ret = compare_expr(a->ref, b->ref);
81             if (ret != 0)
82                 return ret;
83             ret = compare_expr(a->u.ext, b->u.ext);
84             if (ret != 0)
85                 return ret;
86             return compare_expr(a->ext2, b->ext2);
87         case EXPR_OR:
88         case EXPR_AND:
89         case EXPR_ADD:
90         case EXPR_SUB:
91         case EXPR_MUL:
92         case EXPR_DIV:
93         case EXPR_SHL:
94         case EXPR_SHR:
95             ret = compare_expr(a->ref, b->ref);
96             if (ret != 0)
97                 return ret;
98             return compare_expr(a->u.ext, b->u.ext);
99         case EXPR_NOT:
100         case EXPR_NEG:
101         case EXPR_PPTR:
102         case EXPR_CAST:
103         case EXPR_SIZEOF:
104             return compare_expr(a->ref, b->ref);
105         case EXPR_VOID:
106             return 0;
107     }
108     return -1;
109 }
110
111 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
112     do { \
113         if (file) \
114             fprintf(file, "/* %2u */\n", typestring_offset); \
115         print_file((file), 2, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
116     } \
117     while (0)
118
119 static int print_file(FILE *file, int indent, const char *format, ...)
120 {
121     va_list va;
122     int i, r;
123
124     if (!file) return 0;
125
126     va_start(va, format);
127     for (i = 0; i < indent; i++)
128         fprintf(file, "    ");
129     r = vfprintf(file, format, va);
130     va_end(va);
131     return r;
132 }
133
134 static inline int type_has_ref(const type_t *type)
135 {
136     return (type->type == 0 && type->ref);
137 }
138
139 static inline int is_base_type(unsigned char type)
140 {
141     switch (type)
142     {
143     case RPC_FC_BYTE:
144     case RPC_FC_CHAR:
145     case RPC_FC_USMALL:
146     case RPC_FC_SMALL:
147     case RPC_FC_WCHAR:
148     case RPC_FC_USHORT:
149     case RPC_FC_SHORT:
150     case RPC_FC_ULONG:
151     case RPC_FC_LONG:
152     case RPC_FC_HYPER:
153     case RPC_FC_IGNORE:
154     case RPC_FC_FLOAT:
155     case RPC_FC_DOUBLE:
156     case RPC_FC_ENUM16:
157     case RPC_FC_ENUM32:
158     case RPC_FC_ERROR_STATUS_T:
159         return TRUE;
160
161     default:
162         return FALSE;
163     }
164 }
165
166 static size_t write_procformatstring_var(FILE *file, int indent,
167     const var_t *var, int is_return, unsigned int *type_offset)
168 {
169     size_t size;
170     int ptr_level = var->ptr_level;
171     const type_t *type = var->type;
172
173     int is_in = is_attr(var->attrs, ATTR_IN);
174     int is_out = is_attr(var->attrs, ATTR_OUT);
175
176     if (!is_in && !is_out) is_in = TRUE;
177
178     if (ptr_level == 0 && type_has_ref(type))
179         type = type->ref;
180
181     if (ptr_level == 0 && !var->array && is_base_type(type->type))
182     {
183         if (is_return)
184             print_file(file, indent, "0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
185         else
186             print_file(file, indent, "0x4e,    /* FC_IN_PARAM_BASETYPE */\n");
187
188         switch(type->type)
189         {
190 #define CASE_BASETYPE(fctype) \
191         case RPC_##fctype: \
192             print_file(file, indent, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
193             size = 2; /* includes param type prefix */ \
194             break
195
196         CASE_BASETYPE(FC_BYTE);
197         CASE_BASETYPE(FC_CHAR);
198         CASE_BASETYPE(FC_WCHAR);
199         CASE_BASETYPE(FC_USHORT);
200         CASE_BASETYPE(FC_SHORT);
201         CASE_BASETYPE(FC_ULONG);
202         CASE_BASETYPE(FC_LONG);
203         CASE_BASETYPE(FC_HYPER);
204         CASE_BASETYPE(FC_IGNORE);
205         CASE_BASETYPE(FC_USMALL);
206         CASE_BASETYPE(FC_SMALL);
207         CASE_BASETYPE(FC_FLOAT);
208         CASE_BASETYPE(FC_DOUBLE);
209         CASE_BASETYPE(FC_ERROR_STATUS_T);
210 #undef CASE_BASETYPE
211         default:
212             error("Unknown/unsupported type: %s (0x%02x)\n", var->name, type->type);
213             size = 0;
214         }
215     }
216     else
217     {
218         if (is_return)
219             print_file(file, indent, "0x52,    /* FC_RETURN_PARAM */\n");
220         else if (is_in && is_out)
221             print_file(file, indent, "0x50,    /* FC_IN_OUT_PARAM */\n");
222         else if (is_out)
223             print_file(file, indent, "0x51,    /* FC_OUT_PARAM */\n");
224         else
225             print_file(file, indent, "0x4d,    /* FC_IN_PARAM */\n");
226
227         print_file(file, indent, "0x01,\n");
228         print_file(file, indent, "NdrFcShort(0x%x),\n", *type_offset);
229         size = 4; /* includes param type prefix */
230     }
231     *type_offset += get_size_typeformatstring_var(var);
232     return size;
233 }
234
235 void write_procformatstring(FILE *file, type_t *iface)
236 {
237     int indent = 0;
238     var_t *var;
239     unsigned int type_offset = 2;
240
241     print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
242     print_file(file, indent, "{\n");
243     indent++;
244     print_file(file, indent, "0,\n");
245     print_file(file, indent, "{\n");
246     indent++;
247
248     if (iface->funcs)
249     {
250         func_t *func = iface->funcs;
251         while (NEXT_LINK(func)) func = NEXT_LINK(func);
252         for (; func; func = PREV_LINK(func))
253         {
254             /* emit argument data */
255             if (func->args)
256             {
257                 var = func->args;
258                 while (NEXT_LINK(var)) var = NEXT_LINK(var);
259                 while (var)
260                 {
261                     write_procformatstring_var(file, indent, var, FALSE,
262                                                &type_offset);
263
264                     var = PREV_LINK(var);
265                 }
266             }
267
268             /* emit return value data */
269             var = func->def;
270             if (is_void(var->type, NULL))
271             {
272                 print_file(file, indent, "0x5b,    /* FC_END */\n");
273                 print_file(file, indent, "0x5c,    /* FC_PAD */\n");
274             }
275             else
276                 write_procformatstring_var(file, indent, var, TRUE,
277                                            &type_offset);
278         }
279     }
280
281     print_file(file, indent, "0x0\n");
282     indent--;
283     print_file(file, indent, "}\n");
284     indent--;
285     print_file(file, indent, "};\n");
286     print_file(file, indent, "\n");
287 }
288
289 /* write conformance / variance descriptor */
290 static size_t write_conf_or_var_desc(FILE *file, const func_t *func, const type_t *structure, const expr_t *expr)
291 {
292     unsigned char operator_type = 0;
293     const char *operator_string = "no operators";
294     const expr_t *subexpr = expr;
295     unsigned char correlation_type;
296
297     if (!file) return 4; /* optimisation for sizing pass */
298
299     if (expr->is_const)
300     {
301         if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
302             error("write_conf_or_var_desc: constant value %ld is greater than "
303                   "the maximum constant size of %d\n", expr->cval,
304                   UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
305
306         print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n",
307                    RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
308         print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX);
309         print_file(file, 2, "NdrShort(0x%x),\n", expr->cval & USHRT_MAX);
310
311         return 4;
312     }
313
314     switch (subexpr->type)
315     {
316     case EXPR_PPTR:
317         subexpr = subexpr->ref;
318         operator_type = RPC_FC_DEREFERENCE;
319         operator_string = "FC_DEREFERENCE";
320         break;
321     case EXPR_DIV:
322         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
323         {
324             subexpr = subexpr->ref;
325             operator_type = RPC_FC_DIV_2;
326             operator_string = "FC_DIV_2";
327         }
328         break;
329     case EXPR_MUL:
330         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
331         {
332             subexpr = subexpr->ref;
333             operator_type = RPC_FC_MULT_2;
334             operator_string = "FC_MULT_2";
335         }
336         break;
337     case EXPR_SUB:
338         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
339         {
340             subexpr = subexpr->ref;
341             operator_type = RPC_FC_SUB_1;
342             operator_string = "FC_SUB_1";
343         }
344         break;
345     case EXPR_ADD:
346         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
347         {
348             subexpr = subexpr->ref;
349             operator_type = RPC_FC_ADD_1;
350             operator_string = "FC_ADD_1";
351         }
352         break;
353     default:
354         break;
355     }
356
357     if (subexpr->type == EXPR_IDENTIFIER)
358     {
359         const type_t *correlation_variable = NULL;
360         unsigned char param_type = 0;
361         const char *param_type_string = NULL;
362         size_t offset;
363
364         if (structure)
365         {
366             const var_t *var;
367
368             for (offset = 0, var = structure->fields; var; var = NEXT_LINK(var))
369             {
370                 offset -= type_memsize(var->type, var->ptr_level, var->array);
371                 if (!strcmp(var->name, subexpr->u.sval))
372                 {
373                     correlation_variable = var->type;
374                     break;
375                 }
376             }
377             if (!correlation_variable)
378                 error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
379                       subexpr->u.sval);
380
381             correlation_type = RPC_FC_NORMAL_CONFORMANCE;
382         }
383         else
384         {
385             const var_t *var = func->args;
386
387             while (NEXT_LINK(var)) var = NEXT_LINK(var);
388             /* FIXME: not all stack variables are sizeof(void *) */
389             for (offset = 0; var; offset += sizeof(void *), var = PREV_LINK(var))
390             {
391                 if (!strcmp(var->name, subexpr->u.sval))
392                 {
393                     correlation_variable = var->type;
394                     break;
395                 }
396             }
397             if (!correlation_variable)
398                 error("write_conf_or_var_desc: couldn't find variable %s in function\n",
399                     subexpr->u.sval);
400
401             correlation_type = RPC_FC_TOP_LEVEL_CONFORMANCE;
402         }
403
404         while (type_has_ref(correlation_variable))
405             correlation_variable = correlation_variable->ref;
406
407         switch (correlation_variable->type)
408         {
409         case RPC_FC_CHAR:
410         case RPC_FC_SMALL:
411             param_type = RPC_FC_SMALL;
412             param_type_string = "FC_SMALL";
413             break;
414         case RPC_FC_BYTE:
415         case RPC_FC_USMALL:
416             param_type = RPC_FC_USMALL;
417             param_type_string = "FC_USMALL";
418             break;
419         case RPC_FC_WCHAR:
420         case RPC_FC_SHORT:
421             param_type = RPC_FC_SHORT;
422             param_type_string = "FC_SHORT";
423             break;
424         case RPC_FC_USHORT:
425             param_type = RPC_FC_USHORT;
426             param_type_string = "FC_USHORT";
427             break;
428         case RPC_FC_LONG:
429             param_type = RPC_FC_LONG;
430             param_type_string = "FC_LONG";
431             break;
432         case RPC_FC_ULONG:
433             param_type = RPC_FC_ULONG;
434             param_type_string = "FC_ULONG";
435             break;
436         default:
437             error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
438                 correlation_variable->type);
439         }
440
441         print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
442                 correlation_type | param_type,
443                 correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "parameter, " : "",
444                 param_type_string);
445         print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string);
446         print_file(file, 2, "NdrShort(0x%x), /* %soffset = %d */\n",
447                    offset,
448                    correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "x86 stack size / " : "",
449                    offset);
450     }
451     else
452     {
453         unsigned int callback_offset = 0;
454
455         if (structure)
456         {
457             struct expr_eval_routine *eval;
458             int found = 0;
459
460             LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
461             {
462                 if (!strcmp(eval->structure->name, structure->name) &&
463                     !compare_expr(eval->expr, expr))
464                 {
465                     found = 1;
466                     break;
467                 }
468                 callback_offset++;
469             }
470
471             if (!found)
472             {
473                 eval = xmalloc(sizeof(*eval));
474                 eval->structure = structure;
475                 eval->structure_size = fields_memsize(structure->fields);
476                 eval->expr = expr;
477                 list_add_tail(&expr_eval_routines, &eval->entry);
478             }
479
480             correlation_type = RPC_FC_NORMAL_CONFORMANCE;
481         }
482         else
483         {
484             error("write_conf_or_var_desc: top-level callback conformance unimplemented\n");
485             correlation_type = RPC_FC_TOP_LEVEL_CONFORMANCE;
486         }
487
488         if (callback_offset > USHRT_MAX)
489             error("Maximum number of callback routines reached\n");
490
491         print_file(file, 2, "0x%x, /* Corr desc: %s */\n",
492                    correlation_type,
493                    correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "parameter" : "");
494         print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
495         print_file(file, 2, "NdrShort(0x%x), /* %u */\n", callback_offset, callback_offset);
496     }
497     return 4;
498 }
499
500 static size_t fields_memsize(const var_t *v)
501 {
502     size_t size = 0;
503     const var_t *first = v;
504     if (!v) return 0;
505     while (NEXT_LINK(v)) v = NEXT_LINK(v);
506     while (v) {
507         size += type_memsize(v->type, v->ptr_level, v->array);
508         if (v == first) break;
509         v = PREV_LINK(v);
510     }
511     return size;
512 }
513
514 static size_t type_memsize(const type_t *t, int ptr_level, const expr_t *array)
515 {
516     size_t size = 0;
517
518     if (ptr_level)
519         return sizeof(void *);
520
521     switch (t->type)
522     {
523     case RPC_FC_BYTE:
524     case RPC_FC_CHAR:
525     case RPC_FC_USMALL:
526     case RPC_FC_SMALL:
527         size = 1;
528         break;
529     case RPC_FC_WCHAR:
530     case RPC_FC_USHORT:
531     case RPC_FC_SHORT:
532     case RPC_FC_ENUM16:
533         size = 2;
534         break;
535     case RPC_FC_ULONG:
536     case RPC_FC_LONG:
537     case RPC_FC_ERROR_STATUS_T:
538     case RPC_FC_ENUM32:
539     case RPC_FC_FLOAT:
540         size = 4;
541         break;
542     case RPC_FC_HYPER:
543     case RPC_FC_DOUBLE:
544         size = 8;
545         break;
546     case RPC_FC_STRUCT:
547     case RPC_FC_CVSTRUCT:
548     case RPC_FC_CPSTRUCT:
549     case RPC_FC_CSTRUCT:
550     case RPC_FC_PSTRUCT:
551     case RPC_FC_BOGUS_STRUCT:
552     case RPC_FC_ENCAPSULATED_UNION:
553     case RPC_FC_NON_ENCAPSULATED_UNION:
554         size = fields_memsize(t->fields);
555         break;
556     default:
557         error("type_memsize: Unknown type %d", t->type);
558         size = 0;
559     }
560
561     if (array)
562     {
563         if (array->is_const)
564             size *= array->cval;
565         else
566             size = 0;
567     }
568
569     return size;
570 }
571
572 static size_t write_string_tfs(FILE *file, const attr_t *attrs,
573                                const type_t *type, const expr_t *array,
574                                const char *name, size_t *typestring_offset)
575 {
576     const expr_t *size_is = get_attrp(attrs, ATTR_SIZEIS);
577     int has_size = size_is && (size_is->type != EXPR_VOID);
578     size_t start_offset = *typestring_offset;
579
580     if ((type->type != RPC_FC_CHAR) && (type->type != RPC_FC_WCHAR))
581     {
582         error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", type->type, name);
583         return start_offset;
584     }
585
586     if (array && array->is_const)
587     {
588         if (array->cval > USHRT_MAX)
589             error("array size for parameter %s exceeds %d bytes by %ld bytes\n",
590                   name, USHRT_MAX, array->cval - USHRT_MAX);
591
592         if (type->type == RPC_FC_CHAR)
593             WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
594         else
595             WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
596         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
597         *typestring_offset += 2;
598
599         print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", array->cval, array->cval);
600         *typestring_offset += 2;
601
602         return start_offset;
603     }
604     else if (has_size)
605     {
606         if (type->type == RPC_FC_CHAR)
607             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
608         else
609             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
610         print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
611         *typestring_offset += 2;
612
613         *typestring_offset += write_conf_or_var_desc(file, current_func, NULL, size_is);
614
615         return start_offset;
616     }
617     else
618     {
619         if (type->type == RPC_FC_CHAR)
620             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
621         else
622             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
623         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
624         *typestring_offset += 2;
625
626         return start_offset;
627     }
628 }
629
630 static size_t write_array_tfs(FILE *file, const attr_t *attrs,
631                               const type_t *type, const expr_t *array,
632                               const char *name, size_t *typestring_offset)
633 {
634     const expr_t *length_is = get_attrp(attrs, ATTR_LENGTHIS);
635     const expr_t *size_is = get_attrp(attrs, ATTR_SIZEIS);
636     int has_length = length_is && (length_is->type != EXPR_VOID);
637     int has_size = (size_is && (size_is->type != EXPR_VOID)) || !array->is_const;
638     size_t start_offset = *typestring_offset;
639
640     /* FIXME: need to analyse type for pointers */
641
642     if (NEXT_LINK(array)) /* multi-dimensional array */
643     {
644         error("write_array_tfs: Multi-dimensional arrays not implemented yet (param %s)\n", name);
645         return 0;
646     }
647     else
648     {
649         if (!has_length && !has_size)
650         {
651             /* fixed array */
652             size_t size = type_memsize(type, 0, array);
653             if (size < USHRT_MAX)
654             {
655                 WRITE_FCTYPE(file, FC_SMFARRAY, *typestring_offset);
656                 /* alignment */
657                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
658                 /* size */
659                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", size, size);
660                 *typestring_offset += 4;
661             }
662             else
663             {
664                 WRITE_FCTYPE(file, FC_LGFARRAY, *typestring_offset);
665                 /* alignment */
666                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
667                 /* size */
668                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", size, size);
669                 *typestring_offset += 6;
670             }
671
672             /* FIXME: write out pointer descriptor if necessary */
673
674             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
675             print_file(file, 2, "FC_END,\n");
676             *typestring_offset += 2;
677
678             return start_offset;
679         }
680         else if (has_length && !has_size)
681         {
682             /* varying array */
683             size_t element_size = type_memsize(type, 0, NULL);
684             size_t elements = array->cval;
685             size_t total_size = element_size * elements;
686
687             if (total_size < USHRT_MAX)
688             {
689                 WRITE_FCTYPE(file, FC_SMVARRAY, *typestring_offset);
690                 /* alignment */
691                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
692                 /* total size */
693                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", total_size, total_size);
694                 /* number of elements */
695                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", elements, elements);
696                 *typestring_offset += 6;
697             }
698             else
699             {
700                 WRITE_FCTYPE(file, FC_LGVARRAY, *typestring_offset);
701                 /* alignment */
702                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
703                 /* total size */
704                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", total_size, total_size);
705                 /* number of elements */
706                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", elements, elements);
707                 *typestring_offset += 10;
708             }
709             /* element size */
710             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
711             *typestring_offset += 2;
712
713             *typestring_offset += write_conf_or_var_desc(file, current_func,
714                                                          current_structure,
715                                                          length_is);
716
717             /* FIXME: write out pointer descriptor if necessary */
718
719             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
720             print_file(file, 2, "FC_END,\n");
721             *typestring_offset += 2;
722
723             return start_offset;
724         }
725         else if (!has_length && has_size)
726         {
727             /* conformant array */
728             size_t element_size = type_memsize(type, 0, NULL);
729
730             WRITE_FCTYPE(file, FC_CARRAY, *typestring_offset);
731             /* alignment */
732             print_file(file, 2, "0x%x, /* 0 */\n", 0);
733             /* element size */
734             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
735             *typestring_offset += 4;
736
737             *typestring_offset += write_conf_or_var_desc(file, current_func,
738                                                          current_structure,
739                                                          size_is ? size_is : array);
740
741             /* FIXME: write out pointer descriptor if necessary */
742
743             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
744             print_file(file, 2, "FC_END,\n");
745             *typestring_offset += 2;
746
747             return start_offset;
748         }
749         else
750         {
751             /* conformant varying array */
752             size_t element_size = type_memsize(type, 0, NULL);
753
754             WRITE_FCTYPE(file, FC_CVARRAY, *typestring_offset);
755             /* alignment */
756             print_file(file, 2, "0x%x, /* 0 */\n", 0);
757             /* element size */
758             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
759             *typestring_offset += 4;
760
761             *typestring_offset += write_conf_or_var_desc(file, current_func,
762                                                          current_structure,
763                                                          size_is ? size_is : array);
764             *typestring_offset += write_conf_or_var_desc(file, current_func,
765                                                          current_structure,
766                                                          length_is);
767
768             /* FIXME: write out pointer descriptor if necessary */
769
770             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
771             print_file(file, 2, "FC_END,\n");
772             *typestring_offset += 2;
773
774             return start_offset;
775         }
776     }
777 }
778
779 static const var_t *find_array_or_string_in_struct(const type_t *type)
780 {
781     /* last field is the first in the fields linked list */
782     const var_t *last_field = type->fields;
783     if (is_array_type(last_field->attrs, last_field->ptr_level, last_field->array))
784         return last_field;
785
786     assert((last_field->type->type == RPC_FC_CSTRUCT) ||
787            (last_field->type->type == RPC_FC_CPSTRUCT) ||
788            (last_field->type->type == RPC_FC_CVSTRUCT));
789
790     return find_array_or_string_in_struct(last_field->type);
791 }
792
793 static size_t write_struct_tfs(FILE *file, const type_t *type,
794                                const char *name, size_t *typestring_offset)
795 {
796     size_t total_size;
797     const var_t *array;
798     size_t start_offset;
799     size_t array_offset;
800
801     switch (type->type)
802     {
803     case RPC_FC_STRUCT:
804         total_size = type_memsize(type, 0, NULL);
805
806         if (total_size > USHRT_MAX)
807             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
808                   name, USHRT_MAX, total_size - USHRT_MAX);
809
810         start_offset = *typestring_offset;
811         WRITE_FCTYPE(file, FC_STRUCT, *typestring_offset);
812         /* alignment */
813         print_file(file, 2, "0x0,\n");
814         /* total size */
815         print_file(file, 2, "NdrShort(0x%x), /* %u */\n", total_size, total_size);
816         *typestring_offset += 4;
817
818         /* member layout */
819         print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
820         print_file(file, 2, "FC_END,\n");
821
822         *typestring_offset += 2;
823         return start_offset;
824     case RPC_FC_CSTRUCT:
825         total_size = type_memsize(type, 0, NULL);
826
827         if (total_size > USHRT_MAX)
828             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
829                   name, USHRT_MAX, total_size - USHRT_MAX);
830
831         array = find_array_or_string_in_struct(type);
832         current_structure = type;
833         array_offset = write_array_tfs(file, array->attrs, array->type, 
834                                        array->array, array->name,
835                                        typestring_offset);
836         current_structure = NULL;
837
838         start_offset = *typestring_offset;
839         WRITE_FCTYPE(file, FC_CSTRUCT, *typestring_offset);
840         /* alignment */
841         print_file(file, 2, "0x0,\n");
842         /* total size */
843         print_file(file, 2, "NdrShort(0x%x), /* %u */\n", total_size, total_size);
844         *typestring_offset += 4;
845         print_file(file, 2, "NdrShort(0x%x), /* offset = %d (%u) */\n",
846                    array_offset - *typestring_offset,
847                    array_offset - *typestring_offset,
848                    array_offset);
849         *typestring_offset += 2;
850         print_file(file, 2, "FC_END,\n");
851         *typestring_offset += 1;
852
853         return start_offset;
854     case RPC_FC_CVSTRUCT:
855         total_size = type_memsize(type, 0, NULL);
856
857         if (total_size > USHRT_MAX)
858             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
859                   name, USHRT_MAX, total_size - USHRT_MAX);
860
861         array = find_array_or_string_in_struct(type);
862         current_structure = type;
863         if (is_attr(array->attrs, ATTR_STRING))
864             array_offset = write_string_tfs(file, array->attrs, array->type,
865                                             array->array, array->name,
866                                             typestring_offset);
867         else
868             array_offset = write_array_tfs(file, array->attrs, array->type,
869                                            array->array, array->name,
870                                            typestring_offset);
871         current_structure = NULL;
872
873         start_offset = *typestring_offset;
874         WRITE_FCTYPE(file, FC_CVSTRUCT, *typestring_offset);
875         /* alignment */
876         print_file(file, 2, "0x0,\n");
877         /* total size */
878         print_file(file, 2, "NdrShort(0x%x), /* %u */\n", total_size, total_size);
879         *typestring_offset += 4;
880         print_file(file, 2, "NdrShort(0x%x), /* offset = %d (%u) */\n",
881                    array_offset - *typestring_offset,
882                    array_offset - *typestring_offset,
883                    array_offset);
884         *typestring_offset += 2;
885         print_file(file, 2, "FC_END,\n");
886         *typestring_offset += 1;
887
888         return start_offset;
889     default:
890         error("write_struct_tfs: Unimplemented for type 0x%x\n", type->type);
891         return *typestring_offset;
892     }
893 }
894
895 static size_t write_union_tfs(FILE *file, const attr_t *attrs,
896                               const type_t *type, const char *name,
897                               size_t *typeformat_offset)
898 {
899     error("write_union_tfs: Unimplemented\n");
900     return *typeformat_offset;
901 }
902
903 static size_t write_typeformatstring_var(FILE *file, int indent,
904     const var_t *var, size_t *typeformat_offset)
905 {
906     const type_t *type = var->type;
907     int ptr_level = var->ptr_level;
908
909     while (TRUE)
910     {
911         int pointer_type;
912
913         if (is_string_type(var->attrs, ptr_level, var->array))
914             return write_string_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
915
916         if (is_array_type(var->attrs, ptr_level, var->array))
917             return write_array_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
918
919         if (ptr_level == 0)
920         {
921             /* follow reference if the type has one */
922             if (type_has_ref(type))
923             {
924                 type = type->ref;
925                 /* FIXME: get new ptr_level from type */
926                 continue;
927             }
928
929             /* basic types don't need a type format string */
930             if (is_base_type(type->type))
931                 return 0;
932
933             switch (type->type)
934             {
935             case RPC_FC_STRUCT:
936             case RPC_FC_PSTRUCT:
937             case RPC_FC_CSTRUCT:
938             case RPC_FC_CPSTRUCT:
939             case RPC_FC_CVSTRUCT:
940             case RPC_FC_BOGUS_STRUCT:
941                 return write_struct_tfs(file, type, var->name, typeformat_offset);
942             case RPC_FC_ENCAPSULATED_UNION:
943             case RPC_FC_NON_ENCAPSULATED_UNION:
944                 return write_union_tfs(file, var->attrs, type, var->name, typeformat_offset);
945             case RPC_FC_IGNORE:
946             case RPC_FC_BIND_PRIMITIVE:
947                 /* nothing to do */
948                 return 0;
949             default:
950                 error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
951             }
952         }
953         else if (ptr_level == 1 && !type_has_ref(type))
954         {
955             size_t start_offset = *typeformat_offset;
956             pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
957             if (!pointer_type) pointer_type = RPC_FC_RP;
958
959             /* special case for pointers to base types */
960             switch (type->type)
961             {
962 #define CASE_BASETYPE(fctype) \
963             case RPC_##fctype: \
964                 print_file(file, indent, "0x%x, 0x08,    /* %s [simple_pointer] */\n", \
965                            pointer_type, \
966                            pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP")); \
967                 print_file(file, indent, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
968                 print_file(file, indent, "0x5c,          /* FC_PAD */\n"); \
969                 *typeformat_offset += 4; \
970                 return start_offset
971             CASE_BASETYPE(FC_BYTE);
972             CASE_BASETYPE(FC_CHAR);
973             CASE_BASETYPE(FC_SMALL);
974             CASE_BASETYPE(FC_USMALL);
975             CASE_BASETYPE(FC_WCHAR);
976             CASE_BASETYPE(FC_SHORT);
977             CASE_BASETYPE(FC_USHORT);
978             CASE_BASETYPE(FC_LONG);
979             CASE_BASETYPE(FC_ULONG);
980             CASE_BASETYPE(FC_FLOAT);
981             CASE_BASETYPE(FC_HYPER);
982             CASE_BASETYPE(FC_DOUBLE);
983             CASE_BASETYPE(FC_ENUM16);
984             CASE_BASETYPE(FC_ENUM32);
985             CASE_BASETYPE(FC_IGNORE);
986             CASE_BASETYPE(FC_ERROR_STATUS_T);
987             default:
988                 break;
989             }
990         }
991
992         assert(ptr_level > 0);
993
994         pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
995         if (!pointer_type) pointer_type = RPC_FC_RP;
996
997         if (file)
998             fprintf(file, "/* %2u */\n", *typeformat_offset);
999         print_file(file, indent, "0x%x, 0x00,    /* %s */\n",
1000                     pointer_type,
1001                     pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"));
1002         print_file(file, indent, "NdrShort(0x2),    /* 2 */\n");
1003         *typeformat_offset += 4;
1004
1005         ptr_level--;
1006     }
1007 }
1008
1009
1010 void write_typeformatstring(FILE *file, type_t *iface)
1011 {
1012     int indent = 0;
1013     var_t *var;
1014     size_t typeformat_offset;
1015
1016     print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
1017     print_file(file, indent, "{\n");
1018     indent++;
1019     print_file(file, indent, "0,\n");
1020     print_file(file, indent, "{\n");
1021     indent++;
1022     print_file(file, indent, "NdrFcShort(0x0),\n");
1023     typeformat_offset = 2;
1024
1025     if (iface->funcs)
1026     {
1027         func_t *func = iface->funcs;
1028         while (NEXT_LINK(func)) func = NEXT_LINK(func);
1029         for (; func; func = PREV_LINK(func))
1030         {
1031             current_func = func;
1032             if (func->args)
1033             {
1034                 var = func->args;
1035                 while (NEXT_LINK(var)) var = NEXT_LINK(var);
1036                 while (var)
1037                 {
1038                     write_typeformatstring_var(file, indent, var,
1039                                                &typeformat_offset);
1040                     var = PREV_LINK(var);
1041                 }
1042             }
1043         }
1044     }
1045
1046     print_file(file, indent, "0x0\n");
1047     indent--;
1048     print_file(file, indent, "}\n");
1049     indent--;
1050     print_file(file, indent, "};\n");
1051     print_file(file, indent, "\n");
1052 }
1053
1054 static unsigned int get_required_buffer_size_type(
1055     const type_t *type, int ptr_level, const expr_t *array,
1056     const char *name, unsigned int *alignment)
1057 {
1058     *alignment = 0;
1059     if (ptr_level == 0 && !array && !type_has_ref(type))
1060     {
1061         switch (type->type)
1062         {
1063         case RPC_FC_BYTE:
1064         case RPC_FC_CHAR:
1065         case RPC_FC_USMALL:
1066         case RPC_FC_SMALL:
1067             return 1;
1068
1069         case RPC_FC_WCHAR:
1070         case RPC_FC_USHORT:
1071         case RPC_FC_SHORT:
1072             *alignment = 2;
1073             return 2;
1074
1075         case RPC_FC_ULONG:
1076         case RPC_FC_LONG:
1077         case RPC_FC_FLOAT:
1078         case RPC_FC_ERROR_STATUS_T:
1079             *alignment = 4;
1080             return 4;
1081
1082         case RPC_FC_HYPER:
1083         case RPC_FC_DOUBLE:
1084             *alignment = 8;
1085             return 8;
1086
1087         case RPC_FC_IGNORE:
1088         case RPC_FC_BIND_PRIMITIVE:
1089             return 0;
1090
1091         case RPC_FC_STRUCT:
1092         {
1093             size_t size = 0;
1094             const var_t *field;
1095             for (field = type->fields; field; field = NEXT_LINK(field))
1096             {
1097                 unsigned int alignment;
1098                 size += get_required_buffer_size_type(
1099                     field->type, field->ptr_level, field->array, field->name,
1100                     &alignment);
1101             }
1102             return size;
1103         }
1104
1105         default:
1106             error("get_required_buffer_size: Unknown/unsupported type: %s (0x%02x)\n", name, type->type);
1107             return 0;
1108         }
1109     }
1110     if (ptr_level == 0 && type_has_ref(type))
1111         return get_required_buffer_size_type(type->ref, 0 /* FIXME */, array, name, alignment);
1112     return 0;
1113 }
1114
1115 unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment)
1116 {
1117     return get_required_buffer_size_type(var->type, var->ptr_level, var->array, var->name, alignment);
1118 }
1119
1120 void marshall_arguments(FILE *file, int indent, func_t *func,
1121                         unsigned int *type_offset, enum pass pass)
1122 {
1123     unsigned int last_size = 0;
1124     var_t *var;
1125
1126     if (!func->args)
1127         return;
1128
1129     var = func->args;
1130     while (NEXT_LINK(var)) var = NEXT_LINK(var);
1131     for (; var; *type_offset += get_size_typeformatstring_var(var), var = PREV_LINK(var))
1132     {
1133         int in_attr = is_attr(var->attrs, ATTR_IN);
1134         int out_attr = is_attr(var->attrs, ATTR_OUT);
1135
1136         if (!in_attr && !out_attr)
1137             in_attr = 1;
1138
1139         switch (pass)
1140         {
1141         case PASS_IN:
1142             if (!in_attr)
1143                 continue;
1144             break;
1145         case PASS_OUT:
1146             if (!out_attr)
1147                 continue;
1148             break;
1149         case PASS_RETURN:
1150             break;
1151         }
1152
1153         if (is_string_type(var->attrs, var->ptr_level, var->array))
1154         {
1155             if (var->array && var->array->is_const)
1156                 print_file(file, indent,
1157                            "NdrNonConformantStringMarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1158                            var->name, *type_offset);
1159             else
1160                 print_file(file, indent,
1161                            "NdrConformantStringMarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1162                            var->name, *type_offset);
1163             last_size = 1;
1164         }
1165         else if (is_array_type(var->attrs, var->ptr_level, var->array))
1166         {
1167             const expr_t *length_is = get_attrp(var->attrs, ATTR_LENGTHIS);
1168             const expr_t *size_is = get_attrp(var->attrs, ATTR_SIZEIS);
1169             const char *array_type;
1170             int has_length = length_is && (length_is->type != EXPR_VOID);
1171             int has_size = (size_is && (size_is->type != EXPR_VOID)) || !var->array->is_const;
1172
1173             if (NEXT_LINK(var->array)) /* multi-dimensional array */
1174                 array_type = "ComplexArray";
1175             else
1176             {
1177                 if (!has_length && !has_size)
1178                     array_type = "FixedArray";
1179                 else if (has_length && !has_size)
1180                 {
1181                     print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
1182                     print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
1183                     write_expr(file, length_is, 1);
1184                     fprintf(file, ";\n\n");
1185                     array_type = "VaryingArray";
1186                 }
1187                 else if (!has_length && has_size)
1188                 {
1189                     print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1190                     write_expr(file, size_is ? size_is : var->array, 1);
1191                     fprintf(file, ";\n\n");
1192                     array_type = "ConformantArray";
1193                 }
1194                 else
1195                 {
1196                     print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1197                     write_expr(file, size_is ? size_is : var->array, 1);
1198                     fprintf(file, ";\n");
1199                     print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
1200                     print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
1201                     write_expr(file, length_is, 1);
1202                     fprintf(file, ";\n\n");
1203                     array_type = "ConformantVaryingArray";
1204                 }
1205             }
1206
1207             print_file(file, indent,
1208                        "Ndr%sMarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1209                        array_type, var->name, *type_offset);
1210             last_size = 1;
1211         }
1212         else if (var->ptr_level == 0 && is_base_type(var->type->type))
1213         {
1214             unsigned int size;
1215             unsigned int alignment = 0;
1216             switch (var->type->type)
1217             {
1218             case RPC_FC_BYTE:
1219             case RPC_FC_CHAR:
1220             case RPC_FC_SMALL:
1221             case RPC_FC_USMALL:
1222                 size = 1;
1223                 alignment = 0;
1224                 break;
1225
1226             case RPC_FC_WCHAR:
1227             case RPC_FC_USHORT:
1228             case RPC_FC_SHORT:
1229                 size = 2;
1230                 if (last_size != 0 && last_size < 2)
1231                     alignment = (2 - last_size);
1232                 break;
1233
1234             case RPC_FC_ULONG:
1235             case RPC_FC_LONG:
1236             case RPC_FC_FLOAT:
1237             case RPC_FC_ERROR_STATUS_T:
1238                 size = 4;
1239                 if (last_size != 0 && last_size < 4)
1240                     alignment = (4 - last_size);
1241                 break;
1242
1243             case RPC_FC_HYPER:
1244             case RPC_FC_DOUBLE:
1245                 size = 8;
1246                 if (last_size != 0 && last_size < 4)
1247                     alignment = (4 - last_size);
1248                 break;
1249
1250             default:
1251                 error("marshall_arguments: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, var->type->type);
1252                 size = 0;
1253             }
1254
1255             if (alignment != 0)
1256                 print_file(file, indent, "_StubMsg.Buffer += %u;\n", alignment);
1257
1258             print_file(file, indent, "*(");
1259             write_type(file, var->type, var, var->tname);
1260             fprintf(file, " *)_StubMsg.Buffer = ");
1261             write_name(file, var);
1262             fprintf(file, ";\n");
1263             print_file(file, indent, "_StubMsg.Buffer += sizeof(");
1264             write_type(file, var->type, var, var->tname);
1265             fprintf(file, ");\n");
1266
1267             last_size = size;
1268         }
1269         else if (var->ptr_level == 0)
1270         {
1271             const char *ndrtype;
1272
1273             switch (var->type->type)
1274             {
1275             case RPC_FC_STRUCT:
1276                 ndrtype = "SimpleStruct";
1277                 break;
1278             case RPC_FC_CSTRUCT:
1279             case RPC_FC_CPSTRUCT:
1280                 ndrtype = "ConformantStruct";
1281                 break;
1282             case RPC_FC_CVSTRUCT:
1283                 ndrtype = "ConformantVaryingStruct";
1284                 break;
1285             case RPC_FC_BOGUS_STRUCT:
1286                 ndrtype = "ComplexStruct";
1287                 break;
1288             case RPC_FC_IGNORE:
1289             case RPC_FC_BIND_PRIMITIVE:
1290                 /* no marshalling needed */
1291                 continue;
1292             default:
1293                 error("marshall_arguments: Unsupported type: %s (0x%02x, ptr_level: %d)\n",
1294                     var->name, var->type->type, var->ptr_level);
1295                 ndrtype = NULL;
1296             }
1297
1298             print_file(file, indent,
1299                 "Ndr%sMarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1300                 ndrtype, var->name, *type_offset);
1301             last_size = 1;
1302         }
1303         else
1304         {
1305             print_file(file, indent,
1306                        "NdrPointerMarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1307                        var->name, *type_offset);
1308             last_size = 1;
1309         }
1310         fprintf(file, "\n");
1311     }
1312 }
1313
1314 void unmarshall_arguments(FILE *file, int indent, func_t *func,
1315                           unsigned int *type_offset, enum pass pass)
1316 {
1317     unsigned int last_size = 0;
1318     var_t *var;
1319
1320     if (!func->args)
1321         return;
1322
1323     var = func->args;
1324     while (NEXT_LINK(var)) var = NEXT_LINK(var);
1325     for (; var; *type_offset += get_size_typeformatstring_var(var), var = PREV_LINK(var))
1326     {
1327         int in_attr = is_attr(var->attrs, ATTR_IN);
1328         int out_attr = is_attr(var->attrs, ATTR_OUT);
1329
1330         if (!in_attr && !out_attr)
1331             in_attr = 1;
1332
1333         switch (pass)
1334         {
1335         case PASS_IN:
1336             if (!in_attr)
1337                 continue;
1338             break;
1339         case PASS_OUT:
1340             if (!out_attr)
1341                 continue;
1342             break;
1343         case PASS_RETURN:
1344             break;
1345         }
1346
1347         if (is_string_type(var->attrs, var->ptr_level, var->array))
1348         {
1349             if (var->array && var->array->is_const)
1350                 print_file(file, indent,
1351                            "NdrNonConformantStringUnmarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d], 0);\n",
1352                            var->name, *type_offset);
1353             else
1354                 print_file(file, indent,
1355                            "NdrConformantStringUnmarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d], 0);\n",
1356                            var->name, *type_offset);
1357             last_size = 1;
1358         }
1359         else if (is_array_type(var->attrs, var->ptr_level, var->array))
1360         {
1361             const expr_t *length_is = get_attrp(var->attrs, ATTR_LENGTHIS);
1362             const expr_t *size_is = get_attrp(var->attrs, ATTR_SIZEIS);
1363             const char *array_type;
1364             int has_length = length_is && (length_is->type != EXPR_VOID);
1365             int has_size = (size_is && (size_is->type != EXPR_VOID)) || !var->array->is_const;
1366
1367             if (NEXT_LINK(var->array)) /* multi-dimensional array */
1368                 array_type = "ComplexArray";
1369             else
1370             {
1371                 if (!has_length && !has_size)
1372                     array_type = "FixedArray";
1373                 else if (has_length && !has_size)
1374                     array_type = "VaryingArray";
1375                 else if (!has_length && has_size)
1376                     array_type = "ConformantArray";
1377                 else
1378                     array_type = "ConformantVaryingArray";
1379             }
1380
1381             print_file(file, indent,
1382                        "Ndr%sUnmarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d], 0);\n",
1383                        array_type, var->name, *type_offset);
1384             last_size = 1;
1385         }
1386         else if (var->ptr_level == 0 && is_base_type(var->type->type))
1387         {
1388             unsigned int size;
1389             unsigned int alignment = 0;
1390
1391             switch (var->type->type)
1392             {
1393             case RPC_FC_BYTE:
1394             case RPC_FC_CHAR:
1395             case RPC_FC_SMALL:
1396             case RPC_FC_USMALL:
1397                 size = 1;
1398                 alignment = 0;
1399                 break;
1400
1401             case RPC_FC_WCHAR:
1402             case RPC_FC_USHORT:
1403             case RPC_FC_SHORT:
1404                 size = 2;
1405                 if (last_size != 0 && last_size < 2)
1406                     alignment = (2 - last_size);
1407                 break;
1408
1409             case RPC_FC_ULONG:
1410             case RPC_FC_LONG:
1411             case RPC_FC_FLOAT:
1412             case RPC_FC_ERROR_STATUS_T:
1413                 size = 4;
1414                 if (last_size != 0 && last_size < 4)
1415                     alignment = (4 - last_size);
1416                 break;
1417
1418             case RPC_FC_HYPER:
1419             case RPC_FC_DOUBLE:
1420                 size = 8;
1421                 if (last_size != 0 && last_size < 4)
1422                     alignment = (4 - last_size);
1423                 break;
1424
1425             default:
1426                 error("unmarshall_arguments: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, var->type->type);
1427                 size = 0;
1428             }
1429
1430             if (alignment != 0)
1431                 print_file(file, indent, "_StubMsg.Buffer += %u;\n", alignment);
1432
1433             print_file(file, indent, "");
1434             write_name(file, var);
1435             fprintf(file, " = *(");
1436             write_type(file, var->type, var, var->tname);
1437             fprintf(file, " *)_StubMsg.Buffer;\n");
1438             print_file(file, indent, "_StubMsg.Buffer += sizeof(");
1439             write_type(file, var->type, var, var->tname);
1440             fprintf(file, ");\n");
1441
1442             last_size = size;
1443         }
1444         else if (var->ptr_level == 0)
1445         {
1446             const char *ndrtype;
1447
1448             switch (var->type->type)
1449             {
1450             case RPC_FC_STRUCT:
1451                 ndrtype = "SimpleStruct";
1452                 break;
1453             case RPC_FC_CSTRUCT:
1454             case RPC_FC_CPSTRUCT:
1455                 ndrtype = "ConformantStruct";
1456                 break;
1457             case RPC_FC_CVSTRUCT:
1458                 ndrtype = "ConformantVaryingStruct";
1459                 break;
1460             case RPC_FC_BOGUS_STRUCT:
1461                 ndrtype = "ComplexStruct";
1462                 break;
1463             case RPC_FC_IGNORE:
1464             case RPC_FC_BIND_PRIMITIVE:
1465                 /* no unmarshalling needed */
1466                 continue;
1467             default:
1468                 error("unmarshall_arguments: Unsupported type: %s (0x%02x, ptr_level: %d)\n",
1469                     var->name, var->type->type, var->ptr_level);
1470                 ndrtype = NULL;
1471             }
1472
1473             print_file(file, indent,
1474                 "Ndr%sUnmarshall(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d], 0);\n",
1475                 ndrtype, var->name, *type_offset);
1476             last_size = 1;
1477         }
1478         else
1479         {
1480             print_file(file, indent,
1481                        "NdrPointerUnmarshall(&_StubMsg, (unsigned char **)&%s, &__MIDL_TypeFormatString.Format[%d], 0);\n",
1482                        var->name, *type_offset);
1483             last_size = 1;
1484         }
1485         fprintf(file, "\n");
1486     }
1487 }
1488
1489
1490 size_t get_size_procformatstring_var(const var_t *var)
1491 {
1492     unsigned int type_offset = 2;
1493     return write_procformatstring_var(NULL, 0, var, FALSE, &type_offset);
1494 }
1495
1496
1497 size_t get_size_typeformatstring_var(const var_t *var)
1498 {
1499     unsigned int type_offset = 0;
1500     write_typeformatstring_var(NULL, 0, var, &type_offset);
1501     return type_offset;
1502 }
1503
1504 static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
1505                               const var_t *fields, const char *structvar)
1506 {
1507     switch (e->type) {
1508         case EXPR_VOID:
1509             break;
1510         case EXPR_NUM:
1511             fprintf(h, "%ld", e->u.lval);
1512             break;
1513         case EXPR_HEXNUM:
1514             fprintf(h, "0x%lx", e->u.lval);
1515             break;
1516         case EXPR_IDENTIFIER:
1517         {
1518             const var_t *field;
1519             for (field = fields; field; field = NEXT_LINK(field))
1520             {
1521                 if (!strcmp(e->u.sval, field->name))
1522                 {
1523                     fprintf(h, "%s->%s", structvar, e->u.sval);
1524                     break;
1525                 }
1526             }
1527             if (!field) error("no field found for identifier %s\n", e->u.sval);
1528             break;
1529         }
1530         case EXPR_NEG:
1531             fprintf(h, "-");
1532             write_struct_expr(h, e->ref, 1, fields, structvar);
1533             break;
1534         case EXPR_NOT:
1535             fprintf(h, "~");
1536             write_struct_expr(h, e->ref, 1, fields, structvar);
1537             break;
1538         case EXPR_PPTR:
1539             fprintf(h, "*");
1540             write_struct_expr(h, e->ref, 1, fields, structvar);
1541             break;
1542         case EXPR_CAST:
1543             fprintf(h, "(");
1544             write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
1545             fprintf(h, ")");
1546             write_struct_expr(h, e->ref, 1, fields, structvar);
1547             break;
1548         case EXPR_SIZEOF:
1549             fprintf(h, "sizeof(");
1550             write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
1551             fprintf(h, ")");
1552             break;
1553         case EXPR_SHL:
1554         case EXPR_SHR:
1555         case EXPR_MUL:
1556         case EXPR_DIV:
1557         case EXPR_ADD:
1558         case EXPR_SUB:
1559         case EXPR_AND:
1560         case EXPR_OR:
1561             if (brackets) fprintf(h, "(");
1562             write_struct_expr(h, e->ref, 1, fields, structvar);
1563             switch (e->type) {
1564                 case EXPR_SHL: fprintf(h, " << "); break;
1565                 case EXPR_SHR: fprintf(h, " >> "); break;
1566                 case EXPR_MUL: fprintf(h, " * "); break;
1567                 case EXPR_DIV: fprintf(h, " / "); break;
1568                 case EXPR_ADD: fprintf(h, " + "); break;
1569                 case EXPR_SUB: fprintf(h, " - "); break;
1570                 case EXPR_AND: fprintf(h, " & "); break;
1571                 case EXPR_OR:  fprintf(h, " | "); break;
1572                 default: break;
1573             }
1574             write_struct_expr(h, e->u.ext, 1, fields, structvar);
1575             if (brackets) fprintf(h, ")");
1576             break;
1577         case EXPR_COND:
1578             if (brackets) fprintf(h, "(");
1579             write_struct_expr(h, e->ref, 1, fields, structvar);
1580             fprintf(h, " ? ");
1581             write_struct_expr(h, e->u.ext, 1, fields, structvar);
1582             fprintf(h, " : ");
1583             write_struct_expr(h, e->ext2, 1, fields, structvar);
1584             if (brackets) fprintf(h, ")");
1585             break;
1586     }
1587 }
1588
1589 int write_expr_eval_routines(FILE *file, const char *iface)
1590 {
1591     int result = 0;
1592     struct expr_eval_routine *eval;
1593     unsigned short callback_offset = 0;
1594
1595     LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
1596     {
1597         int indent = 0;
1598         result = 1;
1599         print_file(file, indent, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
1600                   iface, eval->structure->name, callback_offset);
1601         print_file(file, indent, "{\n");
1602         indent++;
1603         print_file(file, indent, "struct %s *" STRUCT_EXPR_EVAL_VAR " = (struct %s *)(pStubMsg->StackTop - %u);\n",
1604                    eval->structure->name, eval->structure->name, eval->structure_size);
1605         fprintf(file, "\n");
1606         print_file(file, indent, "pStubMsg->Offset = 0;\n"); /* FIXME */
1607         print_file(file, indent, "pStubMsg->MaxCount = (unsigned long)");
1608         write_struct_expr(file, eval->expr, 1, eval->structure->fields, STRUCT_EXPR_EVAL_VAR);
1609         fprintf(file, ";\n");
1610         indent--;
1611         print_file(file, indent, "}\n\n");
1612         callback_offset++;
1613     }
1614     return result;
1615 }
1616
1617 void write_expr_eval_routine_list(FILE *file, const char *iface)
1618 {
1619     struct expr_eval_routine *eval;
1620     struct expr_eval_routine *cursor;
1621     unsigned short callback_offset = 0;
1622
1623     fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
1624     fprintf(file, "{\n");
1625
1626     LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
1627     {
1628         print_file(file, 1, "%s_%sExprEval_%04u,\n",
1629                    iface, eval->structure->name, callback_offset);
1630
1631         callback_offset++;
1632         list_remove(&eval->entry);
1633         free(eval);
1634     }
1635
1636     fprintf(file, "};\n\n");
1637 }