widl: Only write the buffer incrementing code for the marshaling and unmarshaling...
[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 /* returns whether the MaxCount, Offset or ActualCount members need to be
1416  * filled in for the specified phase */
1417 static inline int is_size_needed_for_phase(enum remoting_phase phase)
1418 {
1419     return (phase != PHASE_UNMARSHAL);
1420 }
1421
1422 void write_remoting_arguments(FILE *file, int indent, const func_t *func,
1423                               unsigned int *type_offset, enum pass pass,
1424                               enum remoting_phase phase)
1425 {
1426     const expr_t *length_is;
1427     const expr_t *size_is;
1428     int in_attr, out_attr, has_length, has_size, pointer_type;
1429     var_t *var;
1430
1431     if (!func->args)
1432         return;
1433
1434     var = func->args;
1435     while (NEXT_LINK(var)) var = NEXT_LINK(var);
1436     for (; var; *type_offset += get_size_typeformatstring_var(var), var = PREV_LINK(var))
1437     {
1438         const type_t *type = var->type;
1439         length_is = get_attrp(var->attrs, ATTR_LENGTHIS);
1440         size_is = get_attrp(var->attrs, ATTR_SIZEIS);
1441         has_length = length_is && (length_is->type != EXPR_VOID);
1442         has_size = (size_is && (size_is->type != EXPR_VOID)) || (var->array && !var->array->is_const);
1443
1444         pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
1445         if (!pointer_type)
1446             pointer_type = RPC_FC_RP;
1447
1448         in_attr = is_attr(var->attrs, ATTR_IN);
1449         out_attr = is_attr(var->attrs, ATTR_OUT);
1450         if (!in_attr && !out_attr)
1451             in_attr = 1;
1452
1453         switch (pass)
1454         {
1455         case PASS_IN:
1456             if (!in_attr)
1457                 continue;
1458             break;
1459         case PASS_OUT:
1460             if (!out_attr)
1461                 continue;
1462             break;
1463         case PASS_RETURN:
1464             break;
1465         }
1466
1467         while (type_has_ref(type))
1468             type = type->ref;
1469
1470         if (is_string_type(var->attrs, var->ptr_level, var->array))
1471         {
1472             if (var->array && var->array->is_const)
1473                 print_file(file, indent,
1474                            "NdrNonConformantString%s(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1475                            function_from_phase(phase), var->name, *type_offset);
1476             else
1477             {
1478                 if (size_is && is_size_needed_for_phase(phase))
1479                 {
1480                     print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1481                     write_expr(file, size_is, 1);
1482                     fprintf(file, ";\n");
1483                 }
1484
1485                 if (phase == PHASE_FREE)
1486                 {
1487                     print_file(file, indent, "NdrPointerFree(\n");
1488                     indent++;
1489                     print_file(file, indent, "&_StubMsg,\n");
1490                     print_file(file, indent, "(unsigned char *)%s,\n", var->name);
1491                     print_file(file, indent, "&__MIDL_TypeFormatString.Format[%d]);\n",
1492                                *type_offset);
1493                     indent--;
1494                 }
1495                 else
1496                 {
1497                     print_file(file, indent, "NdrConformantString%s(\n", function_from_phase(phase));
1498                     indent++;
1499                     print_file(file, indent, "(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
1500                     print_file(file, indent, "(unsigned char *)%s,\n", var->name);
1501                     print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
1502                                *type_offset + (has_size ? 4 : 2),
1503                                (phase == PHASE_MARSHAL) ? ");" : ",");
1504                     if (phase == PHASE_UNMARSHAL)
1505                         print_file(file, indent, "(unsigned char)0);\n");
1506                     indent--;
1507                 }
1508             }
1509         }
1510         else if (is_array_type(var->attrs, var->ptr_level, var->array))
1511         {
1512             const char *array_type;
1513
1514             if (var->array && NEXT_LINK(var->array)) /* multi-dimensional array */
1515                 array_type = "ComplexArray";
1516             else
1517             {
1518                 if (!has_length && !has_size)
1519                     array_type = "FixedArray";
1520                 else if (has_length && !has_size)
1521                 {
1522                     if (is_size_needed_for_phase(phase))
1523                     {
1524                         print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
1525                         print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
1526                         write_expr(file, length_is, 1);
1527                         fprintf(file, ";\n\n");
1528                     }
1529                     array_type = "VaryingArray";
1530                 }
1531                 else if (!has_length && has_size)
1532                 {
1533                     if (is_size_needed_for_phase(phase))
1534                     {
1535                         print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1536                         write_expr(file, size_is ? size_is : var->array, 1);
1537                         fprintf(file, ";\n\n");
1538                     }
1539                     array_type = "ConformantArray";
1540                 }
1541                 else
1542                 {
1543                     if (is_size_needed_for_phase(phase))
1544                     {
1545                         print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1546                         write_expr(file, size_is ? size_is : var->array, 1);
1547                         fprintf(file, ";\n");
1548                         print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
1549                         print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
1550                         write_expr(file, length_is, 1);
1551                         fprintf(file, ";\n\n");
1552                     }
1553                     array_type = "ConformantVaryingArray";
1554                 }
1555             }
1556
1557             print_file(file, indent,
1558                        "Ndr%s%s(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1559                        array_type, function_from_phase(phase), var->name,
1560                        *type_offset);
1561         }
1562         else if (var->ptr_level == 0 && is_base_type(type->type))
1563         {
1564             unsigned int size;
1565             unsigned int alignment = 0;
1566             switch (type->type)
1567             {
1568             case RPC_FC_BYTE:
1569             case RPC_FC_CHAR:
1570             case RPC_FC_SMALL:
1571             case RPC_FC_USMALL:
1572                 size = 1;
1573                 alignment = 1;
1574                 break;
1575
1576             case RPC_FC_WCHAR:
1577             case RPC_FC_USHORT:
1578             case RPC_FC_SHORT:
1579                 size = 2;
1580                 alignment = 2;
1581                 break;
1582
1583             case RPC_FC_ULONG:
1584             case RPC_FC_LONG:
1585             case RPC_FC_FLOAT:
1586             case RPC_FC_ERROR_STATUS_T:
1587                 size = 4;
1588                 alignment = 4;
1589                 break;
1590
1591             case RPC_FC_HYPER:
1592             case RPC_FC_DOUBLE:
1593                 size = 8;
1594                 alignment = 8;
1595                 break;
1596
1597             case RPC_FC_IGNORE:
1598             case RPC_FC_BIND_PRIMITIVE:
1599                 /* no marshalling needed */
1600                 continue;
1601
1602             default:
1603                 error("write_remoting_arguments: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, type->type);
1604                 size = 0;
1605             }
1606
1607             if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
1608             {
1609                 print_file(file, indent, "_StubMsg.Buffer += (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
1610                            alignment - 1, alignment - 1);
1611
1612                 if (phase == PHASE_MARSHAL)
1613                 {
1614                     print_file(file, indent, "*(");
1615                     write_type(file, var->type, var, var->tname);
1616                     fprintf(file, " *)_StubMsg.Buffer = ");
1617                     write_name(file, var);
1618                     fprintf(file, ";\n");
1619                 }
1620                 else if (phase == PHASE_UNMARSHAL)
1621                 {
1622                     print_file(file, indent, "");
1623                     write_name(file, var);
1624                     fprintf(file, " = *(");
1625                     write_type(file, var->type, var, var->tname);
1626                     fprintf(file, " *)_StubMsg.Buffer;\n");
1627                 }
1628                 else
1629                     error("write_remoting_arguments: Unimplemented for base types for phase %d\n", phase);
1630
1631                 print_file(file, indent, "_StubMsg.Buffer += sizeof(");
1632                 write_type(file, var->type, var, var->tname);
1633                 fprintf(file, ");\n");
1634             }
1635         }
1636         else if (var->ptr_level == 0)
1637         {
1638             const char *ndrtype;
1639
1640             switch (type->type)
1641             {
1642             case RPC_FC_STRUCT:
1643                 ndrtype = "SimpleStruct";
1644                 break;
1645             case RPC_FC_CSTRUCT:
1646             case RPC_FC_CPSTRUCT:
1647                 ndrtype = "ConformantStruct";
1648                 break;
1649             case RPC_FC_CVSTRUCT:
1650                 ndrtype = "ConformantVaryingStruct";
1651                 break;
1652             case RPC_FC_BOGUS_STRUCT:
1653                 ndrtype = "ComplexStruct";
1654                 break;
1655             default:
1656                 error("write_remoting_arguments: Unsupported type: %s (0x%02x, ptr_level: %d)\n",
1657                     var->name, type->type, var->ptr_level);
1658                 ndrtype = NULL;
1659             }
1660
1661             print_file(file, indent,
1662                 "Ndr%s%s(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n",
1663                 ndrtype, function_from_phase(phase), var->name, *type_offset);
1664         }
1665         else
1666         {
1667             if ((var->ptr_level == 1) && (pointer_type == RPC_FC_RP) && is_base_type(type->type))
1668             {
1669                 unsigned int size;
1670                 switch (type->type)
1671                 {
1672                 case RPC_FC_BYTE:
1673                 case RPC_FC_CHAR:
1674                 case RPC_FC_SMALL:
1675                 case RPC_FC_USMALL:
1676                     size = 1;
1677                     break;
1678
1679                 case RPC_FC_WCHAR:
1680                 case RPC_FC_USHORT:
1681                 case RPC_FC_SHORT:
1682                     size = 2;
1683                     break;
1684
1685                 case RPC_FC_ULONG:
1686                 case RPC_FC_LONG:
1687                 case RPC_FC_FLOAT:
1688                 case RPC_FC_ERROR_STATUS_T:
1689                     size = 4;
1690                     break;
1691
1692                 case RPC_FC_HYPER:
1693                 case RPC_FC_DOUBLE:
1694                     size = 8;
1695                     break;
1696
1697                 case RPC_FC_IGNORE:
1698                 case RPC_FC_BIND_PRIMITIVE:
1699                     /* no marshalling needed */
1700                     continue;
1701
1702                 default:
1703                     error("write_remoting_arguments: Unsupported type: %s (0x%02x, ptr_level: 1)\n", var->name, type->type);
1704                     size = 0;
1705                 }
1706
1707                 if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
1708                 {
1709                     print_file(file, indent,
1710                             "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
1711                             size - 1, size - 1);
1712
1713                     if (phase == PHASE_MARSHAL)
1714                     {
1715                         print_file(file, indent, "*(");
1716                         write_type(file, var->type, NULL, var->tname);
1717                         fprintf(file, " *)_StubMsg.Buffer = *");
1718                         write_name(file, var);
1719                         fprintf(file, ";\n");
1720                     }
1721                     else if (phase == PHASE_UNMARSHAL)
1722                     {
1723                         print_file(file, indent, (pass == PASS_IN) ? "" : "*");
1724                         write_name(file, var);
1725                         fprintf(file, (pass == PASS_IN) ? " = (" : " = *(");
1726                         write_type(file, var->type, NULL, var->tname);
1727                         fprintf(file, " *)_StubMsg.Buffer;\n");
1728                     }
1729
1730                     print_file(file, indent, "_StubMsg.Buffer += sizeof(");
1731                     write_type(file, var->type, NULL, var->tname);
1732                     fprintf(file, ");\n");
1733                 }
1734             }
1735             else
1736             {
1737                 print_file(file, indent, "NdrPointer%s(\n", function_from_phase(phase));
1738                 indent++;
1739                 print_file(file, indent, "(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
1740                 print_file(file, indent, "(unsigned char *)%s,\n", var->name);
1741                 print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
1742                            *type_offset, (phase == PHASE_MARSHAL) ? ");" : ",");
1743                 if (phase == PHASE_UNMARSHAL)
1744                     print_file(file, indent, "(unsigned char *)0);\n");
1745                 indent--;
1746             }
1747         }
1748         fprintf(file, "\n");
1749     }
1750 }
1751
1752
1753 size_t get_size_procformatstring_var(const var_t *var)
1754 {
1755     unsigned int type_offset = 2;
1756     return write_procformatstring_var(NULL, 0, var, FALSE, &type_offset);
1757 }
1758
1759
1760 size_t get_size_typeformatstring_var(const var_t *var)
1761 {
1762     size_t type_offset = 0;
1763     write_typeformatstring_var(NULL, 0, var, &type_offset);
1764     return type_offset;
1765 }
1766
1767 size_t get_size_procformatstring(const type_t *iface)
1768 {
1769     size_t size = 1;
1770     func_t *func;
1771     var_t *var;
1772
1773     if (iface->funcs)
1774     {
1775         func = iface->funcs;
1776         while (NEXT_LINK(func)) func = NEXT_LINK(func);
1777         while (func)
1778         {
1779             /* argument list size */
1780             if (func->args)
1781             {
1782                 var = func->args;
1783                 while (NEXT_LINK(var)) var = NEXT_LINK(var);
1784                 while (var)
1785                 {
1786                     size += get_size_procformatstring_var(var);
1787                     var = PREV_LINK(var);
1788                 }
1789             }
1790
1791             /* return value size */
1792             size += 2; /* FIXME: determine real size */
1793             func = PREV_LINK(func);
1794         }
1795     }
1796     return size;
1797 }
1798
1799 size_t get_size_typeformatstring(const type_t *iface)
1800 {
1801     size_t size = 3;
1802     func_t *func;
1803     var_t *var;
1804
1805     if (iface->funcs)
1806     {
1807         func = iface->funcs;
1808         while (NEXT_LINK(func)) func = NEXT_LINK(func);
1809         while (func)
1810         {
1811             /* argument list size */
1812             if (func->args)
1813             {
1814                 var = func->args;
1815                 while (NEXT_LINK(var)) var = NEXT_LINK(var);
1816                 while (var)
1817                 {
1818                     size += get_size_typeformatstring_var(var);
1819                     var = PREV_LINK(var);
1820                 }
1821             }
1822
1823             func = PREV_LINK(func);
1824         }
1825     }
1826     return size;
1827 }
1828
1829 static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
1830                               const var_t *fields, const char *structvar)
1831 {
1832     switch (e->type) {
1833         case EXPR_VOID:
1834             break;
1835         case EXPR_NUM:
1836             fprintf(h, "%ld", e->u.lval);
1837             break;
1838         case EXPR_HEXNUM:
1839             fprintf(h, "0x%lx", e->u.lval);
1840             break;
1841         case EXPR_IDENTIFIER:
1842         {
1843             const var_t *field;
1844             for (field = fields; field; field = NEXT_LINK(field))
1845             {
1846                 if (!strcmp(e->u.sval, field->name))
1847                 {
1848                     fprintf(h, "%s->%s", structvar, e->u.sval);
1849                     break;
1850                 }
1851             }
1852             if (!field) error("no field found for identifier %s\n", e->u.sval);
1853             break;
1854         }
1855         case EXPR_NEG:
1856             fprintf(h, "-");
1857             write_struct_expr(h, e->ref, 1, fields, structvar);
1858             break;
1859         case EXPR_NOT:
1860             fprintf(h, "~");
1861             write_struct_expr(h, e->ref, 1, fields, structvar);
1862             break;
1863         case EXPR_PPTR:
1864             fprintf(h, "*");
1865             write_struct_expr(h, e->ref, 1, fields, structvar);
1866             break;
1867         case EXPR_CAST:
1868             fprintf(h, "(");
1869             write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
1870             fprintf(h, ")");
1871             write_struct_expr(h, e->ref, 1, fields, structvar);
1872             break;
1873         case EXPR_SIZEOF:
1874             fprintf(h, "sizeof(");
1875             write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
1876             fprintf(h, ")");
1877             break;
1878         case EXPR_SHL:
1879         case EXPR_SHR:
1880         case EXPR_MUL:
1881         case EXPR_DIV:
1882         case EXPR_ADD:
1883         case EXPR_SUB:
1884         case EXPR_AND:
1885         case EXPR_OR:
1886             if (brackets) fprintf(h, "(");
1887             write_struct_expr(h, e->ref, 1, fields, structvar);
1888             switch (e->type) {
1889                 case EXPR_SHL: fprintf(h, " << "); break;
1890                 case EXPR_SHR: fprintf(h, " >> "); break;
1891                 case EXPR_MUL: fprintf(h, " * "); break;
1892                 case EXPR_DIV: fprintf(h, " / "); break;
1893                 case EXPR_ADD: fprintf(h, " + "); break;
1894                 case EXPR_SUB: fprintf(h, " - "); break;
1895                 case EXPR_AND: fprintf(h, " & "); break;
1896                 case EXPR_OR:  fprintf(h, " | "); break;
1897                 default: break;
1898             }
1899             write_struct_expr(h, e->u.ext, 1, fields, structvar);
1900             if (brackets) fprintf(h, ")");
1901             break;
1902         case EXPR_COND:
1903             if (brackets) fprintf(h, "(");
1904             write_struct_expr(h, e->ref, 1, fields, structvar);
1905             fprintf(h, " ? ");
1906             write_struct_expr(h, e->u.ext, 1, fields, structvar);
1907             fprintf(h, " : ");
1908             write_struct_expr(h, e->ext2, 1, fields, structvar);
1909             if (brackets) fprintf(h, ")");
1910             break;
1911     }
1912 }
1913
1914 int write_expr_eval_routines(FILE *file, const char *iface)
1915 {
1916     int result = 0;
1917     struct expr_eval_routine *eval;
1918     unsigned short callback_offset = 0;
1919
1920     LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
1921     {
1922         int indent = 0;
1923         result = 1;
1924         print_file(file, indent, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
1925                   iface, eval->structure->name, callback_offset);
1926         print_file(file, indent, "{\n");
1927         indent++;
1928         print_file(file, indent, "struct %s *" STRUCT_EXPR_EVAL_VAR " = (struct %s *)(pStubMsg->StackTop - %u);\n",
1929                    eval->structure->name, eval->structure->name, eval->structure_size);
1930         fprintf(file, "\n");
1931         print_file(file, indent, "pStubMsg->Offset = 0;\n"); /* FIXME */
1932         print_file(file, indent, "pStubMsg->MaxCount = (unsigned long)");
1933         write_struct_expr(file, eval->expr, 1, eval->structure->fields, STRUCT_EXPR_EVAL_VAR);
1934         fprintf(file, ";\n");
1935         indent--;
1936         print_file(file, indent, "}\n\n");
1937         callback_offset++;
1938     }
1939     return result;
1940 }
1941
1942 void write_expr_eval_routine_list(FILE *file, const char *iface)
1943 {
1944     struct expr_eval_routine *eval;
1945     struct expr_eval_routine *cursor;
1946     unsigned short callback_offset = 0;
1947
1948     fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
1949     fprintf(file, "{\n");
1950
1951     LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
1952     {
1953         print_file(file, 1, "%s_%sExprEval_%04u,\n",
1954                    iface, eval->structure->name, callback_offset);
1955
1956         callback_offset++;
1957         list_remove(&eval->entry);
1958         free(eval);
1959     }
1960
1961     fprintf(file, "};\n\n");
1962 }