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