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