widl: Output NULL ref pointer check for pointer levels > 1 too.
[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., 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     case RPC_FC_BIND_PRIMITIVE:
160         return TRUE;
161
162     default:
163         return FALSE;
164     }
165 }
166
167 static size_t write_procformatstring_var(FILE *file, int indent,
168     const var_t *var, int is_return, unsigned int *type_offset)
169 {
170     size_t size;
171     int ptr_level = var->ptr_level;
172     const type_t *type = var->type;
173
174     int is_in = is_attr(var->attrs, ATTR_IN);
175     int is_out = is_attr(var->attrs, ATTR_OUT);
176
177     if (!is_in && !is_out) is_in = TRUE;
178
179     if (ptr_level == 0 && type_has_ref(type))
180         type = type->ref;
181
182     if (ptr_level == 0 && !var->array && is_base_type(type->type))
183     {
184         if (is_return)
185             print_file(file, indent, "0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
186         else
187             print_file(file, indent, "0x4e,    /* FC_IN_PARAM_BASETYPE */\n");
188
189         switch(type->type)
190         {
191 #define CASE_BASETYPE(fctype) \
192         case RPC_##fctype: \
193             print_file(file, indent, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
194             size = 2; /* includes param type prefix */ \
195             break
196
197         CASE_BASETYPE(FC_BYTE);
198         CASE_BASETYPE(FC_CHAR);
199         CASE_BASETYPE(FC_WCHAR);
200         CASE_BASETYPE(FC_USHORT);
201         CASE_BASETYPE(FC_SHORT);
202         CASE_BASETYPE(FC_ULONG);
203         CASE_BASETYPE(FC_LONG);
204         CASE_BASETYPE(FC_HYPER);
205         CASE_BASETYPE(FC_IGNORE);
206         CASE_BASETYPE(FC_USMALL);
207         CASE_BASETYPE(FC_SMALL);
208         CASE_BASETYPE(FC_FLOAT);
209         CASE_BASETYPE(FC_DOUBLE);
210         CASE_BASETYPE(FC_ERROR_STATUS_T);
211 #undef CASE_BASETYPE
212
213         case RPC_FC_BIND_PRIMITIVE:
214             print_file(file, indent, "0x%02x,    /* FC_IGNORE */\n", RPC_FC_IGNORE);
215             size = 2; /* includes param type prefix */
216             break;
217
218         default:
219             error("Unknown/unsupported type: %s (0x%02x)\n", var->name, type->type);
220             size = 0;
221         }
222     }
223     else
224     {
225         if (is_return)
226             print_file(file, indent, "0x52,    /* FC_RETURN_PARAM */\n");
227         else if (is_in && is_out)
228             print_file(file, indent, "0x50,    /* FC_IN_OUT_PARAM */\n");
229         else if (is_out)
230             print_file(file, indent, "0x51,    /* FC_OUT_PARAM */\n");
231         else
232             print_file(file, indent, "0x4d,    /* FC_IN_PARAM */\n");
233
234         print_file(file, indent, "0x01,\n");
235         print_file(file, indent, "NdrFcShort(0x%x),\n", *type_offset);
236         size = 4; /* includes param type prefix */
237     }
238     *type_offset += get_size_typeformatstring_var(var);
239     return size;
240 }
241
242 void write_procformatstring(FILE *file, type_t *iface)
243 {
244     int indent = 0;
245     var_t *var;
246     unsigned int type_offset = 2;
247
248     print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
249     print_file(file, indent, "{\n");
250     indent++;
251     print_file(file, indent, "0,\n");
252     print_file(file, indent, "{\n");
253     indent++;
254
255     if (iface->funcs)
256     {
257         func_t *func = iface->funcs;
258         while (NEXT_LINK(func)) func = NEXT_LINK(func);
259         for (; func; func = PREV_LINK(func))
260         {
261             /* emit argument data */
262             if (func->args)
263             {
264                 var = func->args;
265                 while (NEXT_LINK(var)) var = NEXT_LINK(var);
266                 while (var)
267                 {
268                     write_procformatstring_var(file, indent, var, FALSE,
269                                                &type_offset);
270
271                     var = PREV_LINK(var);
272                 }
273             }
274
275             /* emit return value data */
276             var = func->def;
277             if (is_void(var->type, NULL))
278             {
279                 print_file(file, indent, "0x5b,    /* FC_END */\n");
280                 print_file(file, indent, "0x5c,    /* FC_PAD */\n");
281             }
282             else
283                 write_procformatstring_var(file, indent, var, TRUE,
284                                            &type_offset);
285         }
286     }
287
288     print_file(file, indent, "0x0\n");
289     indent--;
290     print_file(file, indent, "}\n");
291     indent--;
292     print_file(file, indent, "};\n");
293     print_file(file, indent, "\n");
294 }
295
296 /* write conformance / variance descriptor */
297 static size_t write_conf_or_var_desc(FILE *file, const func_t *func, const type_t *structure, const expr_t *expr)
298 {
299     unsigned char operator_type = 0;
300     const char *operator_string = "no operators";
301     const expr_t *subexpr = expr;
302     unsigned char correlation_type;
303
304     if (!file) return 4; /* optimisation for sizing pass */
305
306     if (expr->is_const)
307     {
308         if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
309             error("write_conf_or_var_desc: constant value %ld is greater than "
310                   "the maximum constant size of %d\n", expr->cval,
311                   UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
312
313         print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n",
314                    RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
315         print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX);
316         print_file(file, 2, "NdrFcShort(0x%x),\n", expr->cval & USHRT_MAX);
317
318         return 4;
319     }
320
321     switch (subexpr->type)
322     {
323     case EXPR_PPTR:
324         subexpr = subexpr->ref;
325         operator_type = RPC_FC_DEREFERENCE;
326         operator_string = "FC_DEREFERENCE";
327         break;
328     case EXPR_DIV:
329         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
330         {
331             subexpr = subexpr->ref;
332             operator_type = RPC_FC_DIV_2;
333             operator_string = "FC_DIV_2";
334         }
335         break;
336     case EXPR_MUL:
337         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
338         {
339             subexpr = subexpr->ref;
340             operator_type = RPC_FC_MULT_2;
341             operator_string = "FC_MULT_2";
342         }
343         break;
344     case EXPR_SUB:
345         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
346         {
347             subexpr = subexpr->ref;
348             operator_type = RPC_FC_SUB_1;
349             operator_string = "FC_SUB_1";
350         }
351         break;
352     case EXPR_ADD:
353         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
354         {
355             subexpr = subexpr->ref;
356             operator_type = RPC_FC_ADD_1;
357             operator_string = "FC_ADD_1";
358         }
359         break;
360     default:
361         break;
362     }
363
364     if (subexpr->type == EXPR_IDENTIFIER)
365     {
366         const type_t *correlation_variable = NULL;
367         unsigned char param_type = 0;
368         const char *param_type_string = NULL;
369         size_t offset;
370
371         if (structure)
372         {
373             const var_t *var;
374
375             for (offset = 0, var = structure->fields; var; var = NEXT_LINK(var))
376             {
377                 offset -= type_memsize(var->type, var->ptr_level, var->array);
378                 if (!strcmp(var->name, subexpr->u.sval))
379                 {
380                     correlation_variable = var->type;
381                     break;
382                 }
383             }
384             if (!correlation_variable)
385                 error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
386                       subexpr->u.sval);
387
388             correlation_type = RPC_FC_NORMAL_CONFORMANCE;
389         }
390         else
391         {
392             const var_t *var = func->args;
393
394             while (NEXT_LINK(var)) var = NEXT_LINK(var);
395             /* FIXME: not all stack variables are sizeof(void *) */
396             for (offset = 0; var; offset += sizeof(void *), var = PREV_LINK(var))
397             {
398                 if (!strcmp(var->name, subexpr->u.sval))
399                 {
400                     correlation_variable = var->type;
401                     break;
402                 }
403             }
404             if (!correlation_variable)
405                 error("write_conf_or_var_desc: couldn't find variable %s in function\n",
406                     subexpr->u.sval);
407
408             correlation_type = RPC_FC_TOP_LEVEL_CONFORMANCE;
409         }
410
411         while (type_has_ref(correlation_variable))
412             correlation_variable = correlation_variable->ref;
413
414         switch (correlation_variable->type)
415         {
416         case RPC_FC_CHAR:
417         case RPC_FC_SMALL:
418             param_type = RPC_FC_SMALL;
419             param_type_string = "FC_SMALL";
420             break;
421         case RPC_FC_BYTE:
422         case RPC_FC_USMALL:
423             param_type = RPC_FC_USMALL;
424             param_type_string = "FC_USMALL";
425             break;
426         case RPC_FC_WCHAR:
427         case RPC_FC_SHORT:
428             param_type = RPC_FC_SHORT;
429             param_type_string = "FC_SHORT";
430             break;
431         case RPC_FC_USHORT:
432             param_type = RPC_FC_USHORT;
433             param_type_string = "FC_USHORT";
434             break;
435         case RPC_FC_LONG:
436             param_type = RPC_FC_LONG;
437             param_type_string = "FC_LONG";
438             break;
439         case RPC_FC_ULONG:
440             param_type = RPC_FC_ULONG;
441             param_type_string = "FC_ULONG";
442             break;
443         default:
444             error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
445                 correlation_variable->type);
446         }
447
448         print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
449                 correlation_type | param_type,
450                 correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "parameter, " : "",
451                 param_type_string);
452         print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string);
453         print_file(file, 2, "NdrFcShort(0x%x), /* %soffset = %d */\n",
454                    offset,
455                    correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "x86 stack size / " : "",
456                    offset);
457     }
458     else
459     {
460         unsigned int callback_offset = 0;
461
462         if (structure)
463         {
464             struct expr_eval_routine *eval;
465             int found = 0;
466
467             LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
468             {
469                 if (!strcmp(eval->structure->name, structure->name) &&
470                     !compare_expr(eval->expr, expr))
471                 {
472                     found = 1;
473                     break;
474                 }
475                 callback_offset++;
476             }
477
478             if (!found)
479             {
480                 eval = xmalloc(sizeof(*eval));
481                 eval->structure = structure;
482                 eval->structure_size = fields_memsize(structure->fields);
483                 eval->expr = expr;
484                 list_add_tail(&expr_eval_routines, &eval->entry);
485             }
486
487             correlation_type = RPC_FC_NORMAL_CONFORMANCE;
488         }
489         else
490         {
491             error("write_conf_or_var_desc: top-level callback conformance unimplemented\n");
492             correlation_type = RPC_FC_TOP_LEVEL_CONFORMANCE;
493         }
494
495         if (callback_offset > USHRT_MAX)
496             error("Maximum number of callback routines reached\n");
497
498         print_file(file, 2, "0x%x, /* Corr desc: %s */\n",
499                    correlation_type,
500                    correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "parameter" : "");
501         print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
502         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", callback_offset, callback_offset);
503     }
504     return 4;
505 }
506
507 static size_t fields_memsize(const var_t *v)
508 {
509     size_t size = 0;
510     const var_t *first = v;
511     if (!v) return 0;
512     while (NEXT_LINK(v)) v = NEXT_LINK(v);
513     while (v) {
514         size += type_memsize(v->type, v->ptr_level, v->array);
515         if (v == first) break;
516         v = PREV_LINK(v);
517     }
518     return size;
519 }
520
521 static size_t type_memsize(const type_t *t, int ptr_level, const expr_t *array)
522 {
523     size_t size = 0;
524
525     if (ptr_level)
526         return sizeof(void *);
527
528     if (type_has_ref(t))
529         return type_memsize(t->ref, 0 /* FIXME */, NULL);
530
531     switch (t->type)
532     {
533     case RPC_FC_BYTE:
534     case RPC_FC_CHAR:
535     case RPC_FC_USMALL:
536     case RPC_FC_SMALL:
537         size = 1;
538         break;
539     case RPC_FC_WCHAR:
540     case RPC_FC_USHORT:
541     case RPC_FC_SHORT:
542     case RPC_FC_ENUM16:
543         size = 2;
544         break;
545     case RPC_FC_ULONG:
546     case RPC_FC_LONG:
547     case RPC_FC_ERROR_STATUS_T:
548     case RPC_FC_ENUM32:
549     case RPC_FC_FLOAT:
550         size = 4;
551         break;
552     case RPC_FC_HYPER:
553     case RPC_FC_DOUBLE:
554         size = 8;
555         break;
556     case RPC_FC_STRUCT:
557     case RPC_FC_CVSTRUCT:
558     case RPC_FC_CPSTRUCT:
559     case RPC_FC_CSTRUCT:
560     case RPC_FC_PSTRUCT:
561     case RPC_FC_BOGUS_STRUCT:
562     case RPC_FC_ENCAPSULATED_UNION:
563     case RPC_FC_NON_ENCAPSULATED_UNION:
564         size = fields_memsize(t->fields);
565         break;
566     default:
567         error("type_memsize: Unknown type %d\n", t->type);
568         size = 0;
569     }
570
571     if (array)
572     {
573         if (array->is_const)
574             size *= array->cval;
575         else
576             size = 0;
577     }
578
579     return size;
580 }
581
582 size_t get_type_memsize(const type_t *type)
583 {
584     return type_memsize(type, 0, NULL);
585 }
586
587 static int write_pointers(FILE *file, const attr_t *attrs,
588                           const type_t *type, int ptr_level,
589                           const expr_t *array, int level,
590                           size_t *typestring_offset)
591 {
592     int pointers_written = 0;
593     const var_t *v;
594
595     /* don't generate a pointer for first-level arrays since we want to
596     * descend into them to write their pointers, not stop here */
597     if ((level == 0 || ptr_level == 0) && is_array_type(attrs, ptr_level, array))
598     {
599         return write_pointers(file, NULL, type, 0, NULL, level + 1, typestring_offset);
600     }
601
602     if (ptr_level != 0)
603     {
604         /* FIXME: only general algorithm implemented, not the actual writing */
605         error("write_pointers: Writing type format string for pointer is unimplemented\n");
606         return 1;
607     }
608
609     /* FIXME: search through all refs for pointers too */
610     while(type_has_ref(type))
611         type = type->ref;
612
613     switch (type->type)
614     {
615         /* note: don't descend into complex structures or unions since these
616          * will always be generated as a separate type */
617         case RPC_FC_STRUCT:
618         case RPC_FC_CVSTRUCT:
619         case RPC_FC_CPSTRUCT:
620         case RPC_FC_CSTRUCT:
621         case RPC_FC_PSTRUCT:
622             v = type->fields;
623             if (!v) break;
624             while (NEXT_LINK(v)) v = NEXT_LINK(v);
625             for (; v; v = PREV_LINK(v))
626                 pointers_written += write_pointers(file, v->attrs, v->type,
627                                                    v->ptr_level, v->array,
628                                                    level + 1,
629                                                    typestring_offset);
630
631             break;
632
633         default:
634             /* nothing to do */
635             break;
636     }
637
638     return pointers_written;
639 }
640
641 static size_t write_pointer_description(FILE *file, const attr_t *attrs,
642                                         const type_t *type, int ptr_level,
643                                         const expr_t *array, int level,
644                                         size_t typestring_offset)
645 {
646     size_t size = 0;
647     const var_t *v;
648
649     /* don't generate a pointer for first-level arrays since we want to
650      * descend into them to write their pointers, not stop here */
651     if ((level == 0 || ptr_level == 0) && is_array_type(attrs, ptr_level, array))
652     {
653         return write_pointer_description(file, NULL, type, 0, NULL,
654                                          level + 1, typestring_offset);
655     }
656
657     if (ptr_level != 0)
658     {
659         /* FIXME: only general algorithm implemented, not the actual writing */
660         error("write_pointer_description: Writing pointer description is unimplemented\n");
661         return 0;
662     }
663
664     /* FIXME: search through all refs for pointers too */
665
666     switch (type->type)
667     {
668         /* note: don't descend into complex structures or unions since these
669          * will always be generated as a separate type */
670         case RPC_FC_STRUCT:
671         case RPC_FC_CVSTRUCT:
672         case RPC_FC_CPSTRUCT:
673         case RPC_FC_CSTRUCT:
674         case RPC_FC_PSTRUCT:
675             v = type->fields;
676             if (!v) break;
677             while (NEXT_LINK(v)) v = NEXT_LINK(v);
678             for (; v; v = PREV_LINK(v))
679                 size += write_pointer_description(file, v->attrs, v->type,
680                                                   v->ptr_level, v->array,
681                                                   level + 1,
682                                                   typestring_offset);
683
684             break;
685
686         default:
687             /* nothing to do */
688             break;
689     }
690
691     return size;
692 }
693
694 static size_t write_string_tfs(FILE *file, const attr_t *attrs,
695                                const type_t *type, const expr_t *array,
696                                const char *name, size_t *typestring_offset)
697 {
698     const expr_t *size_is = get_attrp(attrs, ATTR_SIZEIS);
699     int has_size = size_is && (size_is->type != EXPR_VOID);
700     size_t start_offset = *typestring_offset;
701     unsigned char flags = 0;
702     int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
703     if (!pointer_type)
704         pointer_type = RPC_FC_RP;
705
706     if (!get_attrp(attrs, ATTR_SIZEIS))
707         flags |= RPC_FC_P_SIMPLEPOINTER;
708
709     while (type_has_ref(type))
710         type = type->ref;
711
712     if ((type->type != RPC_FC_BYTE) && (type->type != RPC_FC_CHAR) && (type->type != RPC_FC_WCHAR))
713     {
714         error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", type->type, name);
715         return start_offset;
716     }
717
718     print_file(file, 2,"0x%x, 0x%x,    /* %s%s */\n",
719                pointer_type, flags,
720                pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"),
721                (flags & RPC_FC_P_SIMPLEPOINTER) ? " [simple_pointer]" : "");
722     *typestring_offset += 2;
723
724     if (!(flags & RPC_FC_P_SIMPLEPOINTER))
725     {
726         print_file(file, 2, "NdrFcShort(0x2);\n");
727         *typestring_offset += 2;
728     }
729
730     if (array && array->is_const)
731     {
732         if (array->cval > USHRT_MAX)
733             error("array size for parameter %s exceeds %d bytes by %ld bytes\n",
734                   name, USHRT_MAX, array->cval - USHRT_MAX);
735
736         if (type->type == RPC_FC_CHAR)
737             WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
738         else
739             WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
740         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
741         *typestring_offset += 2;
742
743         print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", array->cval, array->cval);
744         *typestring_offset += 2;
745
746         return start_offset;
747     }
748     else if (has_size)
749     {
750         if (type->type == RPC_FC_CHAR)
751             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
752         else
753             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
754         print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
755         *typestring_offset += 2;
756
757         *typestring_offset += write_conf_or_var_desc(file, current_func, NULL, size_is);
758
759         return start_offset;
760     }
761     else
762     {
763         if (type->type == RPC_FC_CHAR)
764             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
765         else
766             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
767         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
768         *typestring_offset += 2;
769
770         return start_offset;
771     }
772 }
773
774 static size_t write_array_tfs(FILE *file, const attr_t *attrs,
775                               const type_t *type, const expr_t *array,
776                               const char *name, size_t *typestring_offset)
777 {
778     const expr_t *length_is = get_attrp(attrs, ATTR_LENGTHIS);
779     const expr_t *size_is = get_attrp(attrs, ATTR_SIZEIS);
780     int has_length = length_is && (length_is->type != EXPR_VOID);
781     int has_size = (size_is && (size_is->type != EXPR_VOID)) || !array->is_const;
782     size_t start_offset;
783
784     if (array && NEXT_LINK(array)) /* multi-dimensional array */
785     {
786         error("write_array_tfs: Multi-dimensional arrays not implemented yet (param %s)\n", name);
787         return 0;
788     }
789     else
790     {
791         size_t pointer_start_offset = *typestring_offset;
792         int has_pointer = 0;
793
794         if (write_pointers(file, attrs, type, 0, array, 0, typestring_offset) > 0)
795             has_pointer = 1;
796
797         start_offset = *typestring_offset;
798
799         if (!has_length && !has_size)
800         {
801             /* fixed array */
802             size_t size = type_memsize(type, 0, array);
803             if (size < USHRT_MAX)
804             {
805                 WRITE_FCTYPE(file, FC_SMFARRAY, *typestring_offset);
806                 /* alignment */
807                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
808                 /* size */
809                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", size, size);
810                 *typestring_offset += 4;
811             }
812             else
813             {
814                 WRITE_FCTYPE(file, FC_LGFARRAY, *typestring_offset);
815                 /* alignment */
816                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
817                 /* size */
818                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", size, size);
819                 *typestring_offset += 6;
820             }
821
822             if (has_pointer)
823             {
824                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
825                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
826                 *typestring_offset += 2;
827                 *typestring_offset = write_pointer_description(file, attrs,
828                     type, 0, array, 0, pointer_start_offset);
829                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
830                 *typestring_offset += 1;
831             }
832
833             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
834             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
835             *typestring_offset += 2;
836
837             return start_offset;
838         }
839         else if (has_length && !has_size)
840         {
841             /* varying array */
842             size_t element_size = type_memsize(type, 0, NULL);
843             size_t elements = array->cval;
844             size_t total_size = element_size * elements;
845
846             if (total_size < USHRT_MAX)
847             {
848                 WRITE_FCTYPE(file, FC_SMVARRAY, *typestring_offset);
849                 /* alignment */
850                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
851                 /* total size */
852                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", total_size, total_size);
853                 /* number of elements */
854                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", elements, elements);
855                 *typestring_offset += 6;
856             }
857             else
858             {
859                 WRITE_FCTYPE(file, FC_LGVARRAY, *typestring_offset);
860                 /* alignment */
861                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
862                 /* total size */
863                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", total_size, total_size);
864                 /* number of elements */
865                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", elements, elements);
866                 *typestring_offset += 10;
867             }
868             /* element size */
869             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
870             *typestring_offset += 2;
871
872             *typestring_offset += write_conf_or_var_desc(file, current_func,
873                                                          current_structure,
874                                                          length_is);
875
876             if (has_pointer)
877             {
878                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
879                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
880                 *typestring_offset += 2;
881                 *typestring_offset += write_pointer_description(file, attrs,
882                     type, 0, array, 0, pointer_start_offset);
883                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
884                 *typestring_offset += 1;
885             }
886
887             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
888             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
889             *typestring_offset += 2;
890
891             return start_offset;
892         }
893         else if (!has_length && has_size)
894         {
895             /* conformant array */
896             size_t element_size = type_memsize(type, 0, NULL);
897
898             WRITE_FCTYPE(file, FC_CARRAY, *typestring_offset);
899             /* alignment */
900             print_file(file, 2, "0x%x, /* 0 */\n", 0);
901             /* element size */
902             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
903             *typestring_offset += 4;
904
905             *typestring_offset += write_conf_or_var_desc(file, current_func,
906                                                          current_structure,
907                                                          size_is ? size_is : array);
908
909             if (has_pointer)
910             {
911                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
912                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
913                 *typestring_offset += 2;
914                 *typestring_offset += write_pointer_description(file, attrs,
915                     type, 0, array, 0, pointer_start_offset);
916                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
917                 *typestring_offset += 1;
918             }
919
920             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
921             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
922             *typestring_offset += 2;
923
924             return start_offset;
925         }
926         else
927         {
928             /* conformant varying array */
929             size_t element_size = type_memsize(type, 0, NULL);
930
931             WRITE_FCTYPE(file, FC_CVARRAY, *typestring_offset);
932             /* alignment */
933             print_file(file, 2, "0x%x, /* 0 */\n", 0);
934             /* element size */
935             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
936             *typestring_offset += 4;
937
938             *typestring_offset += write_conf_or_var_desc(file, current_func,
939                                                          current_structure,
940                                                          size_is ? size_is : array);
941             *typestring_offset += write_conf_or_var_desc(file, current_func,
942                                                          current_structure,
943                                                          length_is);
944
945             if (has_pointer)
946             {
947                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
948                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
949                 *typestring_offset += 2;
950                 *typestring_offset += write_pointer_description(file, attrs,
951                     type, 0, array, 0, pointer_start_offset);
952                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
953                 *typestring_offset += 1;
954             }
955
956             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
957             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
958             *typestring_offset += 2;
959
960             return start_offset;
961         }
962     }
963 }
964
965 static const var_t *find_array_or_string_in_struct(const type_t *type)
966 {
967     /* last field is the first in the fields linked list */
968     const var_t *last_field = type->fields;
969     if (is_array_type(last_field->attrs, last_field->ptr_level, last_field->array))
970         return last_field;
971
972     assert((last_field->type->type == RPC_FC_CSTRUCT) ||
973            (last_field->type->type == RPC_FC_CPSTRUCT) ||
974            (last_field->type->type == RPC_FC_CVSTRUCT));
975
976     return find_array_or_string_in_struct(last_field->type);
977 }
978
979 static size_t write_struct_tfs(FILE *file, const type_t *type,
980                                const char *name, size_t *typestring_offset)
981 {
982     size_t total_size;
983     const var_t *array;
984     size_t start_offset;
985     size_t array_offset;
986     size_t pointer_offset;
987
988     switch (type->type)
989     {
990     case RPC_FC_STRUCT:
991     case RPC_FC_PSTRUCT:
992         total_size = type_memsize(type, 0, NULL);
993
994         if (total_size > USHRT_MAX)
995             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
996                   name, USHRT_MAX, total_size - USHRT_MAX);
997
998         if (type->type == RPC_FC_PSTRUCT)
999         {
1000             pointer_offset = *typestring_offset;
1001             write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset);
1002         }
1003         else pointer_offset = 0; /* silence warning */
1004
1005         start_offset = *typestring_offset;
1006         if (type->type == RPC_FC_STRUCT)
1007             WRITE_FCTYPE(file, FC_STRUCT, *typestring_offset);
1008         else
1009             WRITE_FCTYPE(file, FC_PSTRUCT, *typestring_offset);
1010         /* alignment */
1011         print_file(file, 2, "0x0,\n");
1012         /* total size */
1013         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1014         *typestring_offset += 4;
1015
1016         if (type->type == RPC_FC_PSTRUCT)
1017         {
1018             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1019             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1020             *typestring_offset += 2;
1021             *typestring_offset += write_pointer_description(file, NULL,
1022                 type, 0, NULL, 0, pointer_offset);
1023             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1024             *typestring_offset += 1;
1025         }
1026
1027         /* member layout */
1028         print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
1029         print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1030
1031         *typestring_offset += 2;
1032         return start_offset;
1033     case RPC_FC_CSTRUCT:
1034     case RPC_FC_CPSTRUCT:
1035         total_size = type_memsize(type, 0, NULL);
1036
1037         if (total_size > USHRT_MAX)
1038             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
1039                   name, USHRT_MAX, total_size - USHRT_MAX);
1040
1041         array = find_array_or_string_in_struct(type);
1042         current_structure = type;
1043         array_offset = write_array_tfs(file, array->attrs, array->type,
1044                                        array->array, array->name,
1045                                        typestring_offset);
1046         current_structure = NULL;
1047
1048         if (type->type == RPC_FC_CPSTRUCT)
1049         {
1050             pointer_offset = *typestring_offset;
1051             write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset);
1052         }
1053         else pointer_offset = 0; /* silence warning */
1054
1055         start_offset = *typestring_offset;
1056         if (type->type == RPC_FC_CSTRUCT)
1057             WRITE_FCTYPE(file, FC_CSTRUCT, *typestring_offset);
1058         else
1059             WRITE_FCTYPE(file, FC_CPSTRUCT, *typestring_offset);
1060         /* alignment */
1061         print_file(file, 2, "0x0,\n");
1062         /* total size */
1063         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1064         *typestring_offset += 4;
1065         print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d (%u) */\n",
1066                    array_offset - *typestring_offset,
1067                    array_offset - *typestring_offset,
1068                    array_offset);
1069         *typestring_offset += 2;
1070
1071         if (type->type == RPC_FC_CPSTRUCT)
1072         {
1073             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1074             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1075             *typestring_offset += 2;
1076             *typestring_offset += write_pointer_description(file, NULL,
1077                 type, 0, NULL, 0, pointer_offset);
1078             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1079             *typestring_offset += 1;
1080         }
1081
1082         print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1083         *typestring_offset += 1;
1084
1085         return start_offset;
1086     case RPC_FC_CVSTRUCT:
1087         total_size = type_memsize(type, 0, NULL);
1088
1089         if (total_size > USHRT_MAX)
1090             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
1091                   name, USHRT_MAX, total_size - USHRT_MAX);
1092
1093         array = find_array_or_string_in_struct(type);
1094         current_structure = type;
1095         if (is_attr(array->attrs, ATTR_STRING))
1096             array_offset = write_string_tfs(file, array->attrs, array->type,
1097                                             array->array, array->name,
1098                                             typestring_offset);
1099         else
1100             array_offset = write_array_tfs(file, array->attrs, array->type,
1101                                            array->array, array->name,
1102                                            typestring_offset);
1103         current_structure = NULL;
1104
1105         pointer_offset = *typestring_offset;
1106         if (!write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset))
1107             pointer_offset = 0;
1108
1109         start_offset = *typestring_offset;
1110         WRITE_FCTYPE(file, FC_CVSTRUCT, *typestring_offset);
1111         /* alignment */
1112         print_file(file, 2, "0x0,\n");
1113         /* total size */
1114         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1115         *typestring_offset += 4;
1116         print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d (%u) */\n",
1117                    array_offset - *typestring_offset,
1118                    array_offset - *typestring_offset,
1119                    array_offset);
1120         *typestring_offset += 2;
1121
1122         if (pointer_offset != 0)
1123         {
1124             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1125             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1126             *typestring_offset += 2;
1127             *typestring_offset += write_pointer_description(file, NULL,
1128                 type, 0, NULL, 0, pointer_offset);
1129             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1130             *typestring_offset += 1;
1131         }
1132
1133         print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1134         *typestring_offset += 1;
1135
1136         return start_offset;
1137     default:
1138         error("write_struct_tfs: Unimplemented for type 0x%x\n", type->type);
1139         return *typestring_offset;
1140     }
1141 }
1142
1143 static void write_pointer_only_tfs(FILE *file, const attr_t *attrs, size_t offset, size_t *typeformat_offset)
1144 {
1145     int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
1146     if (!pointer_type) pointer_type = RPC_FC_RP;
1147
1148     print_file(file, 2, "0x%x, 0x00,    /* %s */\n",
1149                pointer_type,
1150                pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"));
1151     print_file(file, 2, "NdrFcShort(0x%x),    /* %d */\n", offset, offset);
1152     *typeformat_offset += 4;
1153 }
1154
1155 static size_t write_union_tfs(FILE *file, const attr_t *attrs,
1156                               const type_t *type, const char *name,
1157                               size_t *typeformat_offset)
1158 {
1159     error("write_union_tfs: Unimplemented\n");
1160     return *typeformat_offset;
1161 }
1162
1163 static size_t write_typeformatstring_var(FILE *file, int indent,
1164     const var_t *var, size_t *typeformat_offset)
1165 {
1166     const type_t *type = var->type;
1167     int ptr_level = var->ptr_level;
1168
1169     chat("write_typeformatstring_var: %s\n", var->name);
1170
1171     while (TRUE)
1172     {
1173         chat("write_typeformatstring: type->type = 0x%x, type->name = %s, ptr_level = %d\n", type->type, type->name, ptr_level);
1174
1175         if (is_string_type(var->attrs, ptr_level, var->array))
1176             return write_string_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
1177
1178         if (is_array_type(var->attrs, ptr_level, var->array))
1179             return write_array_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
1180
1181         if (ptr_level == 0)
1182         {
1183             /* follow reference if the type has one */
1184             if (type_has_ref(type))
1185             {
1186                 type = type->ref;
1187                 /* FIXME: get new ptr_level from type */
1188                 continue;
1189             }
1190
1191             /* basic types don't need a type format string */
1192             if (is_base_type(type->type))
1193                 return 0;
1194
1195             switch (type->type)
1196             {
1197             case RPC_FC_STRUCT:
1198             case RPC_FC_PSTRUCT:
1199             case RPC_FC_CSTRUCT:
1200             case RPC_FC_CPSTRUCT:
1201             case RPC_FC_CVSTRUCT:
1202             case RPC_FC_BOGUS_STRUCT:
1203                 return write_struct_tfs(file, type, var->name, typeformat_offset);
1204             case RPC_FC_ENCAPSULATED_UNION:
1205             case RPC_FC_NON_ENCAPSULATED_UNION:
1206                 return write_union_tfs(file, var->attrs, type, var->name, typeformat_offset);
1207             case RPC_FC_IGNORE:
1208             case RPC_FC_BIND_PRIMITIVE:
1209                 /* nothing to do */
1210                 return 0;
1211             default:
1212                 error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
1213             }
1214         }
1215         else if (ptr_level == 1 && !type_has_ref(type))
1216         {
1217             size_t start_offset = *typeformat_offset;
1218             int in_attr = is_attr(var->attrs, ATTR_IN);
1219             int out_attr = is_attr(var->attrs, ATTR_OUT);
1220             int pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
1221             if (!pointer_type) pointer_type = RPC_FC_RP;
1222
1223             /* special case for pointers to base types */
1224             switch (type->type)
1225             {
1226 #define CASE_BASETYPE(fctype) \
1227             case RPC_##fctype: \
1228                 print_file(file, indent, "0x%x, 0x%x,    /* %s %s[simple_pointer] */\n", \
1229                            pointer_type, \
1230                            (!in_attr && out_attr) ? 0x0C : 0x08, \
1231                            pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"), \
1232                            (!in_attr && out_attr) ? "[allocated_on_stack] " : ""); \
1233                 print_file(file, indent, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
1234                 print_file(file, indent, "0x5c,          /* FC_PAD */\n"); \
1235                 *typeformat_offset += 4; \
1236                 return start_offset
1237             CASE_BASETYPE(FC_BYTE);
1238             CASE_BASETYPE(FC_CHAR);
1239             CASE_BASETYPE(FC_SMALL);
1240             CASE_BASETYPE(FC_USMALL);
1241             CASE_BASETYPE(FC_WCHAR);
1242             CASE_BASETYPE(FC_SHORT);
1243             CASE_BASETYPE(FC_USHORT);
1244             CASE_BASETYPE(FC_LONG);
1245             CASE_BASETYPE(FC_ULONG);
1246             CASE_BASETYPE(FC_FLOAT);
1247             CASE_BASETYPE(FC_HYPER);
1248             CASE_BASETYPE(FC_DOUBLE);
1249             CASE_BASETYPE(FC_ENUM16);
1250             CASE_BASETYPE(FC_ENUM32);
1251             CASE_BASETYPE(FC_IGNORE);
1252             CASE_BASETYPE(FC_ERROR_STATUS_T);
1253             default:
1254                 break;
1255             }
1256         }
1257
1258         assert(ptr_level > 0);
1259
1260         if (file)
1261             fprintf(file, "/* %2u */\n", *typeformat_offset);
1262         write_pointer_only_tfs(file, var->attrs, 2, typeformat_offset);
1263
1264         ptr_level--;
1265     }
1266 }
1267
1268
1269 void write_typeformatstring(FILE *file, type_t *iface)
1270 {
1271     int indent = 0;
1272     var_t *var;
1273     size_t typeformat_offset;
1274
1275     print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
1276     print_file(file, indent, "{\n");
1277     indent++;
1278     print_file(file, indent, "0,\n");
1279     print_file(file, indent, "{\n");
1280     indent++;
1281     print_file(file, indent, "NdrFcShort(0x0),\n");
1282     typeformat_offset = 2;
1283
1284     if (iface->funcs)
1285     {
1286         func_t *func = iface->funcs;
1287         while (NEXT_LINK(func)) func = NEXT_LINK(func);
1288         for (; func; func = PREV_LINK(func))
1289         {
1290             current_func = func;
1291             if (func->args)
1292             {
1293                 var = func->args;
1294                 while (NEXT_LINK(var)) var = NEXT_LINK(var);
1295                 while (var)
1296                 {
1297                     write_typeformatstring_var(file, indent, var,
1298                                                &typeformat_offset);
1299                     var = PREV_LINK(var);
1300                 }
1301             }
1302         }
1303     }
1304
1305     print_file(file, indent, "0x0\n");
1306     indent--;
1307     print_file(file, indent, "}\n");
1308     indent--;
1309     print_file(file, indent, "};\n");
1310     print_file(file, indent, "\n");
1311 }
1312
1313 static unsigned int get_required_buffer_size_type(
1314     const type_t *type, int ptr_level, const expr_t *array,
1315     const char *name, unsigned int *alignment)
1316 {
1317     *alignment = 0;
1318     if (ptr_level == 0 && !array && !type_has_ref(type))
1319     {
1320         switch (type->type)
1321         {
1322         case RPC_FC_BYTE:
1323         case RPC_FC_CHAR:
1324         case RPC_FC_USMALL:
1325         case RPC_FC_SMALL:
1326             *alignment = 4;
1327             return 1;
1328
1329         case RPC_FC_WCHAR:
1330         case RPC_FC_USHORT:
1331         case RPC_FC_SHORT:
1332             *alignment = 4;
1333             return 2;
1334
1335         case RPC_FC_ULONG:
1336         case RPC_FC_LONG:
1337         case RPC_FC_FLOAT:
1338         case RPC_FC_ERROR_STATUS_T:
1339             *alignment = 4;
1340             return 4;
1341
1342         case RPC_FC_HYPER:
1343         case RPC_FC_DOUBLE:
1344             *alignment = 8;
1345             return 8;
1346
1347         case RPC_FC_IGNORE:
1348         case RPC_FC_BIND_PRIMITIVE:
1349             return 0;
1350
1351         case RPC_FC_STRUCT:
1352         {
1353             size_t size = 0;
1354             const var_t *field;
1355             for (field = type->fields; field; field = NEXT_LINK(field))
1356             {
1357                 unsigned int alignment;
1358                 size += get_required_buffer_size_type(
1359                     field->type, field->ptr_level, field->array, field->name,
1360                     &alignment);
1361             }
1362             return size;
1363         }
1364
1365         default:
1366             error("get_required_buffer_size: Unknown/unsupported type: %s (0x%02x)\n", name, type->type);
1367             return 0;
1368         }
1369     }
1370     if (ptr_level == 0 && type_has_ref(type))
1371         return get_required_buffer_size_type(type->ref, 0 /* FIXME */, array, name, alignment);
1372     return 0;
1373 }
1374
1375 unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment)
1376 {
1377     int in_attr = is_attr(var->attrs, ATTR_IN);
1378     int out_attr = is_attr(var->attrs, ATTR_OUT);
1379
1380     if (!in_attr && !out_attr)
1381         in_attr = 1;
1382
1383     if ((!out_attr || in_attr) && !is_attr(var->attrs, ATTR_STRING) && !var->array)
1384     {
1385         if (var->ptr_level > 0 || (var->ptr_level == 0 && type_has_ref(var->type)))
1386         {
1387             type_t *type = var->type;
1388             while (type->type == 0 && type->ref)
1389                 type = type->ref;
1390
1391             if (is_base_type(type->type))
1392                 return 25;
1393         }
1394     }
1395
1396     return get_required_buffer_size_type(var->type, var->ptr_level, var->array, var->name, alignment);
1397 }
1398
1399 static inline const char *function_from_phase(enum remoting_phase phase)
1400 {
1401     switch (phase)
1402     {
1403     case PHASE_BUFFERSIZE:
1404         return "BufferSize";
1405     case PHASE_MARSHAL:
1406         return "Marshall";
1407     case PHASE_UNMARSHAL:
1408         return "Unmarshall";
1409     case PHASE_FREE:
1410         return "Free";
1411     }
1412     return NULL;
1413 }
1414
1415 void write_remoting_arguments(FILE *file, int indent, const func_t *func,
1416                               unsigned int *type_offset, enum pass pass,
1417                               enum remoting_phase phase)
1418 {
1419     const expr_t *length_is;
1420     const expr_t *size_is;
1421     int in_attr, out_attr, has_length, has_size, pointer_type;
1422     var_t *var;
1423
1424     if (!func->args)
1425         return;
1426
1427     var = func->args;
1428     while (NEXT_LINK(var)) var = NEXT_LINK(var);
1429     for (; var; *type_offset += get_size_typeformatstring_var(var), var = PREV_LINK(var))
1430     {
1431         const type_t *type = var->type;
1432         length_is = get_attrp(var->attrs, ATTR_LENGTHIS);
1433         size_is = get_attrp(var->attrs, ATTR_SIZEIS);
1434         has_length = length_is && (length_is->type != EXPR_VOID);
1435         has_size = (size_is && (size_is->type != EXPR_VOID)) || (var->array && !var->array->is_const);
1436
1437         pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
1438         if (!pointer_type)
1439             pointer_type = RPC_FC_RP;
1440
1441         in_attr = is_attr(var->attrs, ATTR_IN);
1442         out_attr = is_attr(var->attrs, ATTR_OUT);
1443         if (!in_attr && !out_attr)
1444             in_attr = 1;
1445
1446         switch (pass)
1447         {
1448         case PASS_IN:
1449             if (!in_attr)
1450                 continue;
1451             break;
1452         case PASS_OUT:
1453             if (!out_attr)
1454                 continue;
1455             break;
1456         case PASS_RETURN:
1457             break;
1458         }
1459
1460         while (type_has_ref(type))
1461             type = type->ref;
1462
1463         if (is_string_type(var->attrs, var->ptr_level, var->array))
1464         {
1465             if (var->array && var->array->is_const)
1466                 print_file(file, indent,
1467                            "NdrNonConformantString%s(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1468                            function_from_phase(phase), var->name, *type_offset);
1469             else
1470             {
1471                 if (size_is && phase != PHASE_UNMARSHAL)
1472                 {
1473                     print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1474                     write_expr(file, size_is, 1);
1475                     fprintf(file, ";\n");
1476                 }
1477
1478                 if (phase == PHASE_FREE)
1479                 {
1480                     print_file(file, indent, "NdrPointerFree(\n");
1481                     indent++;
1482                     print_file(file, indent, "&_StubMsg,\n");
1483                     print_file(file, indent, "(unsigned char *)%s,\n", var->name);
1484                     print_file(file, indent, "&__MIDL_TypeFormatString.Format[%d]);\n",
1485                                *type_offset);
1486                     indent--;
1487                 }
1488                 else
1489                 {
1490                     print_file(file, indent, "NdrConformantString%s(\n", function_from_phase(phase));
1491                     indent++;
1492                     print_file(file, indent, "(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
1493                     print_file(file, indent, "(unsigned char *)%s,\n", var->name);
1494                     print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
1495                                *type_offset + (has_size ? 4 : 2),
1496                                (phase == PHASE_MARSHAL) ? ");" : ",");
1497                     if (phase == PHASE_UNMARSHAL)
1498                         print_file(file, indent, "(unsigned char)0);\n");
1499                     indent--;
1500                 }
1501             }
1502         }
1503         else if (is_array_type(var->attrs, var->ptr_level, var->array))
1504         {
1505             const char *array_type;
1506
1507             if (var->array && NEXT_LINK(var->array)) /* multi-dimensional array */
1508                 array_type = "ComplexArray";
1509             else
1510             {
1511                 if (!has_length && !has_size)
1512                     array_type = "FixedArray";
1513                 else if (has_length && !has_size)
1514                 {
1515                     if (phase == PHASE_MARSHAL)
1516                     {
1517                         print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
1518                         print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
1519                         write_expr(file, length_is, 1);
1520                         fprintf(file, ";\n\n");
1521                     }
1522                     array_type = "VaryingArray";
1523                 }
1524                 else if (!has_length && has_size)
1525                 {
1526                     if (phase == PHASE_MARSHAL)
1527                     {
1528                         print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1529                         write_expr(file, size_is ? size_is : var->array, 1);
1530                         fprintf(file, ";\n\n");
1531                     }
1532                     array_type = "ConformantArray";
1533                 }
1534                 else
1535                 {
1536                     if (phase == PHASE_MARSHAL)
1537                     {
1538                         print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1539                         write_expr(file, size_is ? size_is : var->array, 1);
1540                         fprintf(file, ";\n");
1541                         print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
1542                         print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
1543                         write_expr(file, length_is, 1);
1544                         fprintf(file, ";\n\n");
1545                     }
1546                     array_type = "ConformantVaryingArray";
1547                 }
1548             }
1549
1550             print_file(file, indent,
1551                        "Ndr%s%s(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1552                        array_type, function_from_phase(phase), var->name,
1553                        *type_offset);
1554         }
1555         else if (var->ptr_level == 0 && is_base_type(type->type))
1556         {
1557             unsigned int size;
1558             unsigned int alignment = 0;
1559             switch (type->type)
1560             {
1561             case RPC_FC_BYTE:
1562             case RPC_FC_CHAR:
1563             case RPC_FC_SMALL:
1564             case RPC_FC_USMALL:
1565                 size = 1;
1566                 alignment = 1;
1567                 break;
1568
1569             case RPC_FC_WCHAR:
1570             case RPC_FC_USHORT:
1571             case RPC_FC_SHORT:
1572                 size = 2;
1573                 alignment = 2;
1574                 break;
1575
1576             case RPC_FC_ULONG:
1577             case RPC_FC_LONG:
1578             case RPC_FC_FLOAT:
1579             case RPC_FC_ERROR_STATUS_T:
1580                 size = 4;
1581                 alignment = 4;
1582                 break;
1583
1584             case RPC_FC_HYPER:
1585             case RPC_FC_DOUBLE:
1586                 size = 8;
1587                 alignment = 8;
1588                 break;
1589
1590             case RPC_FC_IGNORE:
1591             case RPC_FC_BIND_PRIMITIVE:
1592                 /* no marshalling needed */
1593                 continue;
1594
1595             default:
1596                 error("write_remoting_arguments: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, type->type);
1597                 size = 0;
1598             }
1599
1600             if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
1601             {
1602                 print_file(file, indent, "_StubMsg.Buffer += (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
1603                            alignment - 1, alignment - 1);
1604
1605                 if (phase == PHASE_MARSHAL)
1606                 {
1607                     print_file(file, indent, "*(");
1608                     write_type(file, var->type, var, var->tname);
1609                     fprintf(file, " *)_StubMsg.Buffer = ");
1610                     write_name(file, var);
1611                     fprintf(file, ";\n");
1612                 }
1613                 else if (phase == PHASE_UNMARSHAL)
1614                 {
1615                     print_file(file, indent, "");
1616                     write_name(file, var);
1617                     fprintf(file, " = *(");
1618                     write_type(file, var->type, var, var->tname);
1619                     fprintf(file, " *)_StubMsg.Buffer;\n");
1620                 }
1621                 else
1622                     error("write_remoting_arguments: Unimplemented for base types for phase %d\n", phase);
1623
1624                 print_file(file, indent, "_StubMsg.Buffer += sizeof(");
1625                 write_type(file, var->type, var, var->tname);
1626                 fprintf(file, ");\n");
1627             }
1628         }
1629         else if (var->ptr_level == 0)
1630         {
1631             const char *ndrtype;
1632
1633             switch (type->type)
1634             {
1635             case RPC_FC_STRUCT:
1636                 ndrtype = "SimpleStruct";
1637                 break;
1638             case RPC_FC_CSTRUCT:
1639             case RPC_FC_CPSTRUCT:
1640                 ndrtype = "ConformantStruct";
1641                 break;
1642             case RPC_FC_CVSTRUCT:
1643                 ndrtype = "ConformantVaryingStruct";
1644                 break;
1645             case RPC_FC_BOGUS_STRUCT:
1646                 ndrtype = "ComplexStruct";
1647                 break;
1648             default:
1649                 error("write_remoting_arguments: Unsupported type: %s (0x%02x, ptr_level: %d)\n",
1650                     var->name, type->type, var->ptr_level);
1651                 ndrtype = NULL;
1652             }
1653
1654             print_file(file, indent,
1655                 "Ndr%s%s(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1656                 ndrtype, function_from_phase(phase), var->name, *type_offset);
1657         }
1658         else
1659         {
1660             if ((var->ptr_level == 1) && (pointer_type == RPC_FC_RP) && is_base_type(type->type))
1661             {
1662                 unsigned int size;
1663                 switch (type->type)
1664                 {
1665                 case RPC_FC_BYTE:
1666                 case RPC_FC_CHAR:
1667                 case RPC_FC_SMALL:
1668                 case RPC_FC_USMALL:
1669                     size = 1;
1670                     break;
1671
1672                 case RPC_FC_WCHAR:
1673                 case RPC_FC_USHORT:
1674                 case RPC_FC_SHORT:
1675                     size = 2;
1676                     break;
1677
1678                 case RPC_FC_ULONG:
1679                 case RPC_FC_LONG:
1680                 case RPC_FC_FLOAT:
1681                 case RPC_FC_ERROR_STATUS_T:
1682                     size = 4;
1683                     break;
1684
1685                 case RPC_FC_HYPER:
1686                 case RPC_FC_DOUBLE:
1687                     size = 8;
1688                     break;
1689
1690                 case RPC_FC_IGNORE:
1691                 case RPC_FC_BIND_PRIMITIVE:
1692                     /* no marshalling needed */
1693                     continue;
1694
1695                 default:
1696                     error("write_remoting_arguments: Unsupported type: %s (0x%02x, ptr_level: 1)\n", var->name, type->type);
1697                     size = 0;
1698                 }
1699
1700                 print_file(file, indent,
1701                            "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
1702                            size - 1, size - 1);
1703
1704                 if (phase == PHASE_MARSHAL)
1705                 {
1706                     print_file(file, indent, "*(");
1707                     write_type(file, var->type, NULL, var->tname);
1708                     fprintf(file, " *)_StubMsg.Buffer = *");
1709                     write_name(file, var);
1710                     fprintf(file, ";\n");
1711                 }
1712                 else if (phase == PHASE_UNMARSHAL)
1713                 {
1714                     print_file(file, indent, (pass == PASS_IN) ? "" : "*");
1715                     write_name(file, var);
1716                     fprintf(file, (pass == PASS_IN) ? " = (" : " = *(");
1717                     write_type(file, var->type, NULL, var->tname);
1718                     fprintf(file, " *)_StubMsg.Buffer;\n");
1719                 }
1720
1721                 print_file(file, indent, "_StubMsg.Buffer += sizeof(");
1722                 write_type(file, var->type, NULL, var->tname);
1723                 fprintf(file, ");\n");
1724             }
1725             else
1726             {
1727                 print_file(file, indent, "NdrPointer%s(\n", function_from_phase(phase));
1728                 indent++;
1729                 print_file(file, indent, "(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
1730                 print_file(file, indent, "(unsigned char *)%s,\n", var->name);
1731                 print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
1732                            *type_offset, (phase == PHASE_MARSHAL) ? ");" : ",");
1733                 if (phase == PHASE_UNMARSHAL)
1734                     print_file(file, indent, "(unsigned char *)0);\n");
1735                 indent--;
1736             }
1737         }
1738         fprintf(file, "\n");
1739     }
1740 }
1741
1742
1743 size_t get_size_procformatstring_var(const var_t *var)
1744 {
1745     unsigned int type_offset = 2;
1746     return write_procformatstring_var(NULL, 0, var, FALSE, &type_offset);
1747 }
1748
1749
1750 size_t get_size_typeformatstring_var(const var_t *var)
1751 {
1752     size_t type_offset = 0;
1753     write_typeformatstring_var(NULL, 0, var, &type_offset);
1754     return type_offset;
1755 }
1756
1757 size_t get_size_procformatstring(const type_t *iface)
1758 {
1759     size_t size = 1;
1760     func_t *func;
1761     var_t *var;
1762
1763     if (iface->funcs)
1764     {
1765         func = iface->funcs;
1766         while (NEXT_LINK(func)) func = NEXT_LINK(func);
1767         while (func)
1768         {
1769             /* argument list size */
1770             if (func->args)
1771             {
1772                 var = func->args;
1773                 while (NEXT_LINK(var)) var = NEXT_LINK(var);
1774                 while (var)
1775                 {
1776                     size += get_size_procformatstring_var(var);
1777                     var = PREV_LINK(var);
1778                 }
1779             }
1780
1781             /* return value size */
1782             size += 2; /* FIXME: determine real size */
1783             func = PREV_LINK(func);
1784         }
1785     }
1786     return size;
1787 }
1788
1789 size_t get_size_typeformatstring(const type_t *iface)
1790 {
1791     size_t size = 3;
1792     func_t *func;
1793     var_t *var;
1794
1795     if (iface->funcs)
1796     {
1797         func = iface->funcs;
1798         while (NEXT_LINK(func)) func = NEXT_LINK(func);
1799         while (func)
1800         {
1801             /* argument list size */
1802             if (func->args)
1803             {
1804                 var = func->args;
1805                 while (NEXT_LINK(var)) var = NEXT_LINK(var);
1806                 while (var)
1807                 {
1808                     size += get_size_typeformatstring_var(var);
1809                     var = PREV_LINK(var);
1810                 }
1811             }
1812
1813             func = PREV_LINK(func);
1814         }
1815     }
1816     return size;
1817 }
1818
1819 static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
1820                               const var_t *fields, const char *structvar)
1821 {
1822     switch (e->type) {
1823         case EXPR_VOID:
1824             break;
1825         case EXPR_NUM:
1826             fprintf(h, "%ld", e->u.lval);
1827             break;
1828         case EXPR_HEXNUM:
1829             fprintf(h, "0x%lx", e->u.lval);
1830             break;
1831         case EXPR_IDENTIFIER:
1832         {
1833             const var_t *field;
1834             for (field = fields; field; field = NEXT_LINK(field))
1835             {
1836                 if (!strcmp(e->u.sval, field->name))
1837                 {
1838                     fprintf(h, "%s->%s", structvar, e->u.sval);
1839                     break;
1840                 }
1841             }
1842             if (!field) error("no field found for identifier %s\n", e->u.sval);
1843             break;
1844         }
1845         case EXPR_NEG:
1846             fprintf(h, "-");
1847             write_struct_expr(h, e->ref, 1, fields, structvar);
1848             break;
1849         case EXPR_NOT:
1850             fprintf(h, "~");
1851             write_struct_expr(h, e->ref, 1, fields, structvar);
1852             break;
1853         case EXPR_PPTR:
1854             fprintf(h, "*");
1855             write_struct_expr(h, e->ref, 1, fields, structvar);
1856             break;
1857         case EXPR_CAST:
1858             fprintf(h, "(");
1859             write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
1860             fprintf(h, ")");
1861             write_struct_expr(h, e->ref, 1, fields, structvar);
1862             break;
1863         case EXPR_SIZEOF:
1864             fprintf(h, "sizeof(");
1865             write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
1866             fprintf(h, ")");
1867             break;
1868         case EXPR_SHL:
1869         case EXPR_SHR:
1870         case EXPR_MUL:
1871         case EXPR_DIV:
1872         case EXPR_ADD:
1873         case EXPR_SUB:
1874         case EXPR_AND:
1875         case EXPR_OR:
1876             if (brackets) fprintf(h, "(");
1877             write_struct_expr(h, e->ref, 1, fields, structvar);
1878             switch (e->type) {
1879                 case EXPR_SHL: fprintf(h, " << "); break;
1880                 case EXPR_SHR: fprintf(h, " >> "); break;
1881                 case EXPR_MUL: fprintf(h, " * "); break;
1882                 case EXPR_DIV: fprintf(h, " / "); break;
1883                 case EXPR_ADD: fprintf(h, " + "); break;
1884                 case EXPR_SUB: fprintf(h, " - "); break;
1885                 case EXPR_AND: fprintf(h, " & "); break;
1886                 case EXPR_OR:  fprintf(h, " | "); break;
1887                 default: break;
1888             }
1889             write_struct_expr(h, e->u.ext, 1, fields, structvar);
1890             if (brackets) fprintf(h, ")");
1891             break;
1892         case EXPR_COND:
1893             if (brackets) fprintf(h, "(");
1894             write_struct_expr(h, e->ref, 1, fields, structvar);
1895             fprintf(h, " ? ");
1896             write_struct_expr(h, e->u.ext, 1, fields, structvar);
1897             fprintf(h, " : ");
1898             write_struct_expr(h, e->ext2, 1, fields, structvar);
1899             if (brackets) fprintf(h, ")");
1900             break;
1901     }
1902 }
1903
1904 int write_expr_eval_routines(FILE *file, const char *iface)
1905 {
1906     int result = 0;
1907     struct expr_eval_routine *eval;
1908     unsigned short callback_offset = 0;
1909
1910     LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
1911     {
1912         int indent = 0;
1913         result = 1;
1914         print_file(file, indent, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
1915                   iface, eval->structure->name, callback_offset);
1916         print_file(file, indent, "{\n");
1917         indent++;
1918         print_file(file, indent, "struct %s *" STRUCT_EXPR_EVAL_VAR " = (struct %s *)(pStubMsg->StackTop - %u);\n",
1919                    eval->structure->name, eval->structure->name, eval->structure_size);
1920         fprintf(file, "\n");
1921         print_file(file, indent, "pStubMsg->Offset = 0;\n"); /* FIXME */
1922         print_file(file, indent, "pStubMsg->MaxCount = (unsigned long)");
1923         write_struct_expr(file, eval->expr, 1, eval->structure->fields, STRUCT_EXPR_EVAL_VAR);
1924         fprintf(file, ";\n");
1925         indent--;
1926         print_file(file, indent, "}\n\n");
1927         callback_offset++;
1928     }
1929     return result;
1930 }
1931
1932 void write_expr_eval_routine_list(FILE *file, const char *iface)
1933 {
1934     struct expr_eval_routine *eval;
1935     struct expr_eval_routine *cursor;
1936     unsigned short callback_offset = 0;
1937
1938     fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
1939     fprintf(file, "{\n");
1940
1941     LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
1942     {
1943         print_file(file, 1, "%s_%sExprEval_%04u,\n",
1944                    iface, eval->structure->name, callback_offset);
1945
1946         callback_offset++;
1947         list_remove(&eval->entry);
1948         free(eval);
1949     }
1950
1951     fprintf(file, "};\n\n");
1952 }