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