typegen.c 181 KB
Newer Older
1 2 3
/*
 * Format String Generator for IDL Compiler
 *
4
 * Copyright 2005-2006 Eric Kohl
5
 * Copyright 2005-2006 Robert Shearman
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 23 24 25 26 27 28 29 30 31 32
 */

#include "config.h"
#include "wine/port.h"

#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <string.h>
#include <assert.h>
#include <ctype.h>
Robert Shearman's avatar
Robert Shearman committed
33
#include <limits.h>
34 35 36 37 38

#include "widl.h"
#include "utils.h"
#include "parser.h"
#include "header.h"
39
#include "typetree.h"
40

41
#include "typegen.h"
42
#include "expr.h"
43

44 45 46 47 48
/* round size up to multiple of alignment */
#define ROUND_SIZE(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1))
/* value to add on to round size up to a multiple of alignment */
#define ROUNDING(size, alignment) (((alignment) - 1) - (((size) + ((alignment) - 1)) & ((alignment) - 1)))

49
static const type_t *current_structure;
50
static const var_t *current_func;
51
static const type_t *current_iface;
52 53 54 55

static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
struct expr_eval_routine
{
56 57 58 59 60
    struct list   entry;
    const type_t *iface;
    const type_t *cont_type;
    char         *name;
    unsigned int  baseoff;
61 62
    const expr_t *expr;
};
63

64 65 66 67 68 69
enum type_context
{
    TYPE_CONTEXT_TOPLEVELPARAM,
    TYPE_CONTEXT_PARAM,
    TYPE_CONTEXT_CONTAINER,
    TYPE_CONTEXT_CONTAINER_NO_POINTERS,
70
    TYPE_CONTEXT_RETVAL,
71 72
};

73 74 75 76 77 78 79 80 81 82 83 84 85
/* parameter flags in Oif mode */
static const unsigned short MustSize = 0x0001;
static const unsigned short MustFree = 0x0002;
static const unsigned short IsPipe = 0x0004;
static const unsigned short IsIn = 0x0008;
static const unsigned short IsOut = 0x0010;
static const unsigned short IsReturn = 0x0020;
static const unsigned short IsBasetype = 0x0040;
static const unsigned short IsByValue = 0x0080;
static const unsigned short IsSimpleRef = 0x0100;
/* static const unsigned short IsDontCallFreeInst = 0x0200; */
/* static const unsigned short SaveForAsyncFinish = 0x0400; */

86
static unsigned int field_memsize(const type_t *type, unsigned int *offset);
87
static unsigned int fields_memsize(const var_list_t *fields, unsigned int *align);
88 89
static unsigned int write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
                                    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 96
                                     type_t *type, enum type_context context,
                                     const char *name, unsigned int *typestring_offset);
97 98 99 100
static unsigned int get_required_buffer_size_type( const type_t *type, const char *name,
                                                   const attr_list_t *attrs, int toplevel_param,
                                                   unsigned int *alignment );
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 105
{
    switch (type)
    {
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    case FC_BYTE: return "FC_BYTE";
    case FC_CHAR: return "FC_CHAR";
    case FC_SMALL: return "FC_SMALL";
    case FC_USMALL: return "FC_USMALL";
    case FC_WCHAR: return "FC_WCHAR";
    case FC_SHORT: return "FC_SHORT";
    case FC_USHORT: return "FC_USHORT";
    case FC_LONG: return "FC_LONG";
    case FC_ULONG: return "FC_ULONG";
    case FC_FLOAT: return "FC_FLOAT";
    case FC_HYPER: return "FC_HYPER";
    case FC_DOUBLE: return "FC_DOUBLE";
    case FC_ENUM16: return "FC_ENUM16";
    case FC_ENUM32: return "FC_ENUM32";
    case FC_IGNORE: return "FC_IGNORE";
    case FC_ERROR_STATUS_T: return "FC_ERROR_STATUS_T";
    case FC_RP: return "FC_RP";
    case FC_UP: return "FC_UP";
    case FC_OP: return "FC_OP";
    case FC_FP: return "FC_FP";
    case FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION";
    case FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION";
    case FC_STRUCT: return "FC_STRUCT";
    case FC_PSTRUCT: return "FC_PSTRUCT";
    case FC_CSTRUCT: return "FC_CSTRUCT";
    case FC_CPSTRUCT: return "FC_CPSTRUCT";
    case FC_CVSTRUCT: return "FC_CVSTRUCT";
    case FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT";
    case FC_SMFARRAY: return "FC_SMFARRAY";
    case FC_LGFARRAY: return "FC_LGFARRAY";
    case FC_SMVARRAY: return "FC_SMVARRAY";
    case FC_LGVARRAY: return "FC_LGVARRAY";
    case FC_CARRAY: return "FC_CARRAY";
    case FC_CVARRAY: return "FC_CVARRAY";
    case FC_BOGUS_ARRAY: return "FC_BOGUS_ARRAY";
    case FC_ALIGNM2: return "FC_ALIGNM2";
    case FC_ALIGNM4: return "FC_ALIGNM4";
    case FC_ALIGNM8: return "FC_ALIGNM8";
    case FC_POINTER: return "FC_POINTER";
    case FC_C_CSTRING: return "FC_C_CSTRING";
    case FC_C_WSTRING: return "FC_C_WSTRING";
    case FC_CSTRING: return "FC_CSTRING";
    case FC_WSTRING: return "FC_WSTRING";
    case FC_BYTE_COUNT_POINTER: return "FC_BYTE_COUNT_POINTER";
    case FC_TRANSMIT_AS: return "FC_TRANSMIT_AS";
    case FC_REPRESENT_AS: return "FC_REPRESENT_AS";
    case FC_IP: return "FC_IP";
    case FC_BIND_CONTEXT: return "FC_BIND_CONTEXT";
    case FC_BIND_GENERIC: return "FC_BIND_GENERIC";
    case FC_BIND_PRIMITIVE: return "FC_BIND_PRIMITIVE";
    case FC_AUTO_HANDLE: return "FC_AUTO_HANDLE";
    case FC_CALLBACK_HANDLE: return "FC_CALLBACK_HANDLE";
    case FC_STRUCTPAD1: return "FC_STRUCTPAD1";
    case FC_STRUCTPAD2: return "FC_STRUCTPAD2";
    case FC_STRUCTPAD3: return "FC_STRUCTPAD3";
    case FC_STRUCTPAD4: return "FC_STRUCTPAD4";
    case FC_STRUCTPAD5: return "FC_STRUCTPAD5";
    case FC_STRUCTPAD6: return "FC_STRUCTPAD6";
    case FC_STRUCTPAD7: return "FC_STRUCTPAD7";
    case FC_STRING_SIZED: return "FC_STRING_SIZED";
    case FC_NO_REPEAT: return "FC_NO_REPEAT";
    case FC_FIXED_REPEAT: return "FC_FIXED_REPEAT";
    case FC_VARIABLE_REPEAT: return "FC_VARIABLE_REPEAT";
    case FC_FIXED_OFFSET: return "FC_FIXED_OFFSET";
    case FC_VARIABLE_OFFSET: return "FC_VARIABLE_OFFSET";
    case FC_PP: return "FC_PP";
    case FC_EMBEDDED_COMPLEX: return "FC_EMBEDDED_COMPLEX";
    case FC_DEREFERENCE: return "FC_DEREFERENCE";
    case FC_DIV_2: return "FC_DIV_2";
    case FC_MULT_2: return "FC_MULT_2";
    case FC_ADD_1: return "FC_ADD_1";
    case FC_SUB_1: return "FC_SUB_1";
    case FC_CALLBACK: return "FC_CALLBACK";
    case FC_CONSTANT_IID: return "FC_CONSTANT_IID";
    case FC_END: return "FC_END";
    case FC_PAD: return "FC_PAD";
    case FC_USER_MARSHAL: return "FC_USER_MARSHAL";
    case FC_RANGE: return "FC_RANGE";
    case FC_INT3264: return "FC_INT3264";
    case FC_UINT3264: return "FC_UINT3264";
186 187 188 189 190 191
    default:
        error("string_of_type: unknown type 0x%02x\n", type);
        return NULL;
    }
}

192 193 194 195 196 197 198 199
static void *get_aliaschain_attrp(const type_t *type, enum attr_type attr)
{
    const type_t *t = type;
    for (;;)
    {
        if (is_attr(t->attrs, attr))
            return get_attrp(t->attrs, attr);
        else if (type_is_alias(t))
200
            t = type_alias_get_aliasee_type(t);
201
        else return NULL;
202 203 204
    }
}

205 206 207 208 209
unsigned char get_basic_fc(const type_t *type)
{
    int sign = type_basic_get_sign(type);
    switch (type_basic_get_type(type))
    {
210 211
    case TYPE_BASIC_INT8: return (sign <= 0 ? FC_SMALL : FC_USMALL);
    case TYPE_BASIC_INT16: return (sign <= 0 ? FC_SHORT : FC_USHORT);
212 213
    case TYPE_BASIC_INT32:
    case TYPE_BASIC_LONG: return (sign <= 0 ? FC_LONG : FC_ULONG);
214 215 216 217 218 219 220 221 222 223 224
    case TYPE_BASIC_INT64: return FC_HYPER;
    case TYPE_BASIC_INT: return (sign <= 0 ? FC_LONG : FC_ULONG);
    case TYPE_BASIC_INT3264: return (sign <= 0 ? FC_INT3264 : FC_UINT3264);
    case TYPE_BASIC_BYTE: return FC_BYTE;
    case TYPE_BASIC_CHAR: return FC_CHAR;
    case TYPE_BASIC_WCHAR: return FC_WCHAR;
    case TYPE_BASIC_HYPER: return FC_HYPER;
    case TYPE_BASIC_FLOAT: return FC_FLOAT;
    case TYPE_BASIC_DOUBLE: return FC_DOUBLE;
    case TYPE_BASIC_ERROR_STATUS_T: return FC_ERROR_STATUS_T;
    case TYPE_BASIC_HANDLE: return FC_BIND_PRIMITIVE;
225
    }
226
    return 0;
227 228
}

229 230 231 232
static unsigned char get_basic_fc_signed(const type_t *type)
{
    switch (type_basic_get_type(type))
    {
233 234 235 236 237 238
    case TYPE_BASIC_INT8: return FC_SMALL;
    case TYPE_BASIC_INT16: return FC_SHORT;
    case TYPE_BASIC_INT32: return FC_LONG;
    case TYPE_BASIC_INT64: return FC_HYPER;
    case TYPE_BASIC_INT: return FC_LONG;
    case TYPE_BASIC_INT3264: return FC_INT3264;
239
    case TYPE_BASIC_LONG: return FC_LONG;
240 241 242 243 244 245 246 247
    case TYPE_BASIC_BYTE: return FC_BYTE;
    case TYPE_BASIC_CHAR: return FC_CHAR;
    case TYPE_BASIC_WCHAR: return FC_WCHAR;
    case TYPE_BASIC_HYPER: return FC_HYPER;
    case TYPE_BASIC_FLOAT: return FC_FLOAT;
    case TYPE_BASIC_DOUBLE: return FC_DOUBLE;
    case TYPE_BASIC_ERROR_STATUS_T: return FC_ERROR_STATUS_T;
    case TYPE_BASIC_HANDLE: return FC_BIND_PRIMITIVE;
248 249 250 251
    }
    return 0;
}

252 253 254 255 256 257 258
static inline unsigned int clamp_align(unsigned int align)
{
    unsigned int packing = (pointer_size == 4) ? win32_packing : win64_packing;
    if(align > packing) align = packing;
    return align;
}

259
unsigned char get_pointer_fc(const type_t *type, const attr_list_t *attrs, int toplevel_param)
260
{
261 262 263 264 265 266 267 268 269
    const type_t *t;
    int pointer_type;

    assert(is_ptr(type) || is_array(type));

    pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
    if (pointer_type)
        return pointer_type;

270
    for (t = type; type_is_alias(t); t = type_alias_get_aliasee_type(t))
271 272 273 274 275 276 277
    {
        pointer_type = get_attrv(t->attrs, ATTR_POINTERTYPE);
        if (pointer_type)
            return pointer_type;
    }

    if (toplevel_param)
278
        return FC_RP;
279 280 281 282 283

    if ((pointer_type = get_attrv(current_iface->attrs, ATTR_POINTERDEFAULT)))
        return pointer_type;

    return FC_UP;
284 285
}

286 287 288 289 290
static unsigned char get_pointer_fc_context( const type_t *type, const attr_list_t *attrs,
                                             enum type_context context )
{
    int pointer_fc = get_pointer_fc(type, attrs, context == TYPE_CONTEXT_TOPLEVELPARAM);

291
    if (pointer_fc == FC_UP && is_attr( attrs, ATTR_OUT ) &&
292
        (context == TYPE_CONTEXT_PARAM || context == TYPE_CONTEXT_RETVAL) && is_object( current_iface ))
293
        pointer_fc = FC_OP;
294 295 296 297

    return pointer_fc;
}

298 299 300 301
static unsigned char get_enum_fc(const type_t *type)
{
    assert(type_get_type(type) == TYPE_ENUM);
    if (is_aliaschain_attr(type, ATTR_V1ENUM))
302
        return FC_ENUM32;
303
    else
304
        return FC_ENUM16;
305 306
}

307 308 309 310 311 312 313 314 315 316 317 318 319
static type_t *get_user_type(const type_t *t, const char **pname)
{
    for (;;)
    {
        type_t *ut = get_attrp(t->attrs, ATTR_WIREMARSHAL);
        if (ut)
        {
            if (pname)
                *pname = t->name;
            return ut;
        }

        if (type_is_alias(t))
320
            t = type_alias_get_aliasee_type(t);
321 322 323 324 325 326 327 328 329 330
        else
            return NULL;
    }
}

static int is_user_type(const type_t *t)
{
    return get_user_type(t, NULL) != NULL;
}

331 332 333 334 335 336 337 338 339 340 341 342 343 344
enum typegen_type typegen_detect_type(const type_t *type, const attr_list_t *attrs, unsigned int flags)
{
    if (is_user_type(type))
        return TGT_USER_TYPE;

    if (is_aliaschain_attr(type, ATTR_CONTEXTHANDLE))
        return TGT_CTXT_HANDLE;

    if (!(flags & TDT_IGNORE_STRINGS) && is_string_type(attrs, type))
        return TGT_STRING;

    switch (type_get_type(type))
    {
    case TYPE_BASIC:
345 346
        if (!(flags & TDT_IGNORE_RANGES) &&
            (is_attr(attrs, ATTR_RANGE) || is_aliaschain_attr(type, ATTR_RANGE)))
347
            return TGT_RANGE;
348 349
        return TGT_BASIC;
    case TYPE_ENUM:
350 351
        if (!(flags & TDT_IGNORE_RANGES) &&
            (is_attr(attrs, ATTR_RANGE) || is_aliaschain_attr(type, ATTR_RANGE)))
352
            return TGT_RANGE;
353 354
        return TGT_ENUM;
    case TYPE_POINTER:
355
        if (type_get_type(type_pointer_get_ref_type(type)) == TYPE_INTERFACE ||
356
            type_get_type(type_pointer_get_ref_type(type)) == TYPE_RUNTIMECLASS ||
357
            type_get_type(type_pointer_get_ref_type(type)) == TYPE_DELEGATE ||
358
            (type_get_type(type_pointer_get_ref_type(type)) == TYPE_VOID && is_attr(attrs, ATTR_IIDIS)))
359
            return TGT_IFACE_POINTER;
360
        else if (is_aliaschain_attr(type_pointer_get_ref_type(type), ATTR_CONTEXTHANDLE))
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
            return TGT_CTXT_HANDLE_POINTER;
        else
            return TGT_POINTER;
    case TYPE_STRUCT:
        return TGT_STRUCT;
    case TYPE_ENCAPSULATED_UNION:
    case TYPE_UNION:
        return TGT_UNION;
    case TYPE_ARRAY:
        return TGT_ARRAY;
    case TYPE_FUNCTION:
    case TYPE_COCLASS:
    case TYPE_INTERFACE:
    case TYPE_MODULE:
    case TYPE_VOID:
    case TYPE_ALIAS:
377
    case TYPE_BITFIELD:
378
    case TYPE_RUNTIMECLASS:
379
    case TYPE_DELEGATE:
380
        break;
381
    case TYPE_APICONTRACT:
382 383
    case TYPE_PARAMETERIZED_TYPE:
    case TYPE_PARAMETER:
384 385 386
        /* not supposed to be here */
        assert(0);
        break;
387 388 389 390
    }
    return TGT_INVALID;
}

391 392
static int cant_be_null(const var_t *v)
{
393
    switch (typegen_detect_type(v->declspec.type, v->attrs, TDT_IGNORE_STRINGS))
394 395
    {
    case TGT_ARRAY:
396
        if (!type_array_is_decl_as_ptr( v->declspec.type )) return 0;
397 398
        /* fall through */
    case TGT_POINTER:
399
        return (get_pointer_fc(v->declspec.type, v->attrs, TRUE) == FC_RP);
400 401 402 403 404 405 406 407
    case TGT_CTXT_HANDLE_POINTER:
        return TRUE;
    default:
        return 0;
    }

}

408 409 410 411 412 413 414 415 416 417 418
static int get_padding(const var_list_t *fields)
{
    unsigned short offset = 0;
    unsigned int salign = 1;
    const var_t *f;

    if (!fields)
        return 0;

    LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry)
    {
419
        type_t *ft = f->declspec.type;
420
        unsigned int align = 0;
421
        unsigned int size = type_memsize_and_alignment(ft, &align);
422 423 424 425 426 427 428 429 430
        align = clamp_align(align);
        if (align > salign) salign = align;
        offset = ROUND_SIZE(offset, align);
        offset += size;
    }

    return ROUNDING(offset, salign);
}

431
static unsigned int get_stack_size( const var_t *var, int *by_value )
432 433 434 435
{
    unsigned int stack_size;
    int by_val;

436
    switch (typegen_detect_type( var->declspec.type, var->attrs, TDT_ALL_TYPES ))
437 438 439 440 441 442 443
    {
    case TGT_BASIC:
    case TGT_ENUM:
    case TGT_RANGE:
    case TGT_STRUCT:
    case TGT_UNION:
    case TGT_USER_TYPE:
444
        stack_size = type_memsize( var->declspec.type );
445 446 447 448 449 450 451 452 453 454 455
        by_val = (pointer_size < 8 || stack_size <= pointer_size); /* FIXME: should be platform-specific */
        break;
    default:
        by_val = 0;
        break;
    }
    if (!by_val) stack_size = pointer_size;
    if (by_value) *by_value = by_val;
    return ROUND_SIZE( stack_size, pointer_size );
}

456
static unsigned char get_contexthandle_flags( const type_t *iface, const attr_list_t *attrs,
457
                                              const type_t *type, int is_return )
458 459
{
    unsigned char flags = 0;
460
    int is_out;
461 462 463 464 465 466

    if (is_attr(iface->attrs, ATTR_STRICTCONTEXTHANDLE)) flags |= NDR_STRICT_CONTEXT_HANDLE;

    if (is_ptr(type) &&
        !is_attr( type->attrs, ATTR_CONTEXTHANDLE ) &&
        !is_attr( attrs, ATTR_CONTEXTHANDLE ))
467
        flags |= HANDLE_PARAM_IS_VIA_PTR;
468

469 470
    if (is_return) return flags | HANDLE_PARAM_IS_OUT | HANDLE_PARAM_IS_RETURN;

471 472
    is_out = is_attr(attrs, ATTR_OUT);
    if (is_attr(attrs, ATTR_IN) || !is_out)
473
    {
474
        flags |= HANDLE_PARAM_IS_IN;
475
        if (!is_out) flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
476
    }
477
    if (is_out) flags |= HANDLE_PARAM_IS_OUT;
478 479 480 481

    return flags;
}

482 483 484 485 486 487 488 489 490 491 492 493
static unsigned int get_rpc_flags( const attr_list_t *attrs )
{
    unsigned int flags = 0;

    if (is_attr( attrs, ATTR_IDEMPOTENT )) flags |= 0x0001;
    if (is_attr( attrs, ATTR_BROADCAST )) flags |= 0x0002;
    if (is_attr( attrs, ATTR_MAYBE )) flags |= 0x0004;
    if (is_attr( attrs, ATTR_MESSAGE )) flags |= 0x0100;
    if (is_attr( attrs, ATTR_ASYNC )) flags |= 0x4000;
    return flags;
}

494
unsigned char get_struct_fc(const type_t *type)
495 496 497 498 499
{
  int has_pointer = 0;
  int has_conformance = 0;
  int has_variance = 0;
  var_t *field;
500
  var_list_t *fields;
501

502 503 504
  fields = type_struct_get_fields(type);

  if (get_padding(fields))
505
    return FC_BOGUS_STRUCT;
506

507
  if (fields) LIST_FOR_EACH_ENTRY( field, fields, var_t, entry )
508
  {
509
    type_t *t = field->declspec.type;
510
    enum typegen_type typegen_type;
511

512
    typegen_type = typegen_detect_type(t, field->attrs, TDT_IGNORE_STRINGS);
513

514
    if (typegen_type == TGT_ARRAY && !type_array_is_decl_as_ptr(t))
515
    {
516
        if (is_string_type(field->attrs, field->declspec.type))
517
        {
518
            if (is_conformant_array(t))
519 520 521 522 523
                has_conformance = 1;
            has_variance = 1;
            continue;
        }

524
        if (is_array(type_array_get_element_type(field->declspec.type)))
525
            return FC_BOGUS_STRUCT;
526

527
        if (type_array_has_conformance(field->declspec.type))
528 529
        {
            has_conformance = 1;
530
            if (list_next(fields, &field->entry))
531 532 533
                error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
                        field->name);
        }
534
        if (type_array_has_variance(t))
535 536
            has_variance = 1;

537
        t = type_array_get_element_type(t);
538
        typegen_type = typegen_detect_type(t, field->attrs, TDT_IGNORE_STRINGS);
539
    }
540

541
    switch (typegen_type)
542
    {
543 544
    case TGT_USER_TYPE:
    case TGT_IFACE_POINTER:
545
        return FC_BOGUS_STRUCT;
546
    case TGT_BASIC:
547
        if (type_basic_get_type(t) == TYPE_BASIC_INT3264 && pointer_size != 4)
548
            return FC_BOGUS_STRUCT;
549
        break;
550
    case TGT_ENUM:
551 552
        if (get_enum_fc(t) == FC_ENUM16)
            return FC_BOGUS_STRUCT;
553
        break;
554
    case TGT_POINTER:
555
    case TGT_ARRAY:
556 557
        if (get_pointer_fc(t, field->attrs, FALSE) == FC_RP || pointer_size != 4)
            return FC_BOGUS_STRUCT;
558 559
        has_pointer = 1;
        break;
560
    case TGT_UNION:
561
        return FC_BOGUS_STRUCT;
562
    case TGT_STRUCT:
563 564 565 566
    {
        unsigned char fc = get_struct_fc(t);
        switch (fc)
        {
567
        case FC_STRUCT:
568
            break;
569
        case FC_CVSTRUCT:
570 571 572 573
            has_conformance = 1;
            has_variance = 1;
            has_pointer = 1;
            break;
574

575
        case FC_CPSTRUCT:
576 577 578 579 580 581
            has_conformance = 1;
            if (list_next( fields, &field->entry ))
                error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
                        field->name);
            has_pointer = 1;
            break;
582

583
        case FC_CSTRUCT:
584 585 586 587 588
            has_conformance = 1;
            if (list_next( fields, &field->entry ))
                error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
                      field->name);
            break;
589

590
        case FC_PSTRUCT:
591 592
            has_pointer = 1;
            break;
593

594 595 596
        default:
            error_loc("Unknown struct member %s with type (0x%02x)\n", field->name, fc);
            /* fallthru - treat it as complex */
597

598
        /* as soon as we see one of these these members, it's bogus... */
599 600
        case FC_BOGUS_STRUCT:
            return FC_BOGUS_STRUCT;
601 602 603
        }
        break;
    }
604
    case TGT_RANGE:
605
        return FC_BOGUS_STRUCT;
606 607 608 609 610 611 612 613
    case TGT_STRING:
        /* shouldn't get here because of TDT_IGNORE_STRINGS above. fall through */
    case TGT_INVALID:
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
        /* checking after parsing should mean that we don't get here. if we do,
         * it's a checker bug */
        assert(0);
614 615 616 617 618 619
    }
  }

  if( has_variance )
  {
    if ( has_conformance )
620
      return FC_CVSTRUCT;
621
    else
622
      return FC_BOGUS_STRUCT;
623 624
  }
  if( has_conformance && has_pointer )
625
    return FC_CPSTRUCT;
626
  if( has_conformance )
627
    return FC_CSTRUCT;
628
  if( has_pointer )
629 630
    return FC_PSTRUCT;
  return FC_STRUCT;
631 632
}

633
static unsigned char get_array_fc(const type_t *type)
634
{
635 636 637 638
    unsigned char fc;
    const expr_t *size_is;
    const type_t *elem_type;

639
    elem_type = type_array_get_element_type(type);
640 641 642 643
    size_is = type_array_get_conformance(type);

    if (!size_is)
    {
644
        unsigned int size = type_memsize(elem_type);
645
        if (size * type_array_get_dim(type) > 0xffffuL)
646
            fc = FC_LGFARRAY;
647
        else
648
            fc = FC_SMFARRAY;
649 650
    }
    else
651
        fc = FC_CARRAY;
652 653

    if (type_array_has_variance(type))
654
    {
655 656 657 658 659 660
        if (fc == FC_SMFARRAY)
            fc = FC_SMVARRAY;
        else if (fc == FC_LGFARRAY)
            fc = FC_LGVARRAY;
        else if (fc == FC_CARRAY)
            fc = FC_CVARRAY;
661 662
    }

663
    switch (typegen_detect_type(elem_type, NULL, TDT_IGNORE_STRINGS))
664
    {
665
    case TGT_USER_TYPE:
666
        fc = FC_BOGUS_ARRAY;
667
        break;
668 669 670
    case TGT_BASIC:
        if (type_basic_get_type(elem_type) == TYPE_BASIC_INT3264 &&
            pointer_size != 4)
671
            fc = FC_BOGUS_ARRAY;
672
        break;
673
    case TGT_STRUCT:
674
        switch (get_struct_fc(elem_type))
675
        {
676 677
        case FC_BOGUS_STRUCT:
            fc = FC_BOGUS_ARRAY;
678 679
            break;
        }
680
        break;
681
    case TGT_ENUM:
682 683
        /* is 16-bit enum - if so, wire size differs from mem size and so
         * the array cannot be block copied, which means the array is complex */
684 685
        if (get_enum_fc(elem_type) == FC_ENUM16)
            fc = FC_BOGUS_ARRAY;
686
        break;
687 688
    case TGT_UNION:
    case TGT_IFACE_POINTER:
689
        fc = FC_BOGUS_ARRAY;
690
        break;
691
    case TGT_POINTER:
692 693 694
        /* ref pointers cannot just be block copied. unique pointers to
         * interfaces need special treatment. either case means the array is
         * complex */
695 696
        if (get_pointer_fc(elem_type, NULL, FALSE) == FC_RP || pointer_size != 4)
            fc = FC_BOGUS_ARRAY;
697
        break;
698
    case TGT_RANGE:
699
        fc = FC_BOGUS_ARRAY;
700
        break;
701 702 703 704 705
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
    case TGT_STRING:
    case TGT_INVALID:
    case TGT_ARRAY:
706 707
        /* nothing to do for everything else */
        break;
708 709 710
    }

    return fc;
711 712
}

713 714
static int is_non_complex_struct(const type_t *type)
{
715
    return (type_get_type(type) == TYPE_STRUCT &&
716
            get_struct_fc(type) != FC_BOGUS_STRUCT);
717 718
}

719 720
static int type_has_pointers(const type_t *type)
{
721
    switch (typegen_detect_type(type, NULL, TDT_IGNORE_STRINGS))
722
    {
723 724 725
    case TGT_USER_TYPE:
        return FALSE;
    case TGT_POINTER:
726
        return TRUE;
727
    case TGT_ARRAY:
728
        return type_array_is_decl_as_ptr(type) || type_has_pointers(type_array_get_element_type(type));
729
    case TGT_STRUCT:
730
    {
731
        var_list_t *fields = type_struct_get_fields(type);
732
        const var_t *field;
733
        if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
734
        {
735
            if (type_has_pointers(field->declspec.type))
736 737
                return TRUE;
        }
738
        break;
739
    }
740
    case TGT_UNION:
741 742 743
    {
        var_list_t *fields;
        const var_t *field;
744
        fields = type_union_get_cases(type);
745 746
        if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
        {
747
            if (field->declspec.type && type_has_pointers(field->declspec.type))
748 749
                return TRUE;
        }
750 751
        break;
    }
752 753 754 755 756 757
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
    case TGT_STRING:
    case TGT_IFACE_POINTER:
    case TGT_BASIC:
    case TGT_ENUM:
758
    case TGT_RANGE:
759
    case TGT_INVALID:
760
        break;
761 762 763 764 765
    }

    return FALSE;
}

766 767
static int type_has_full_pointer(const type_t *type, const attr_list_t *attrs,
                                 int toplevel_param)
768
{
769
    switch (typegen_detect_type(type, NULL, TDT_IGNORE_STRINGS))
770
    {
771 772 773
    case TGT_USER_TYPE:
        return FALSE;
    case TGT_POINTER:
774
        if (get_pointer_fc(type, attrs, toplevel_param) == FC_FP)
775 776 777
            return TRUE;
        else
            return FALSE;
778
    case TGT_ARRAY:
779
        if (get_pointer_fc(type, attrs, toplevel_param) == FC_FP)
780 781
            return TRUE;
        else
782
            return type_has_full_pointer(type_array_get_element_type(type), NULL, FALSE);
783
    case TGT_STRUCT:
784
    {
785
        var_list_t *fields = type_struct_get_fields(type);
786
        const var_t *field;
787
        if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
788
        {
789
            if (type_has_full_pointer(field->declspec.type, field->attrs, FALSE))
790 791
                return TRUE;
        }
792
        break;
793
    }
794
    case TGT_UNION:
795 796 797
    {
        var_list_t *fields;
        const var_t *field;
798
        fields = type_union_get_cases(type);
799 800
        if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
        {
801
            if (field->declspec.type && type_has_full_pointer(field->declspec.type, field->attrs, FALSE))
802 803
                return TRUE;
        }
804 805
        break;
    }
806 807 808 809 810 811
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
    case TGT_STRING:
    case TGT_IFACE_POINTER:
    case TGT_BASIC:
    case TGT_ENUM:
812
    case TGT_RANGE:
813
    case TGT_INVALID:
814
        break;
815 816 817 818 819
    }

    return FALSE;
}

820 821 822 823 824 825 826 827 828 829 830 831 832 833
static unsigned short user_type_offset(const char *name)
{
    user_type_t *ut;
    unsigned short off = 0;
    LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
    {
        if (strcmp(name, ut->name) == 0)
            return off;
        ++off;
    }
    error("user_type_offset: couldn't find type (%s)\n", name);
    return 0;
}

834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
static void update_tfsoff(type_t *type, unsigned int offset, FILE *file)
{
    type->typestring_offset = offset;
    if (file) type->tfswrite = FALSE;
}

static void guard_rec(type_t *type)
{
    /* types that contain references to themselves (like a linked list),
       need to be shielded from infinite recursion when writing embedded
       types  */
    if (type->typestring_offset)
        type->tfswrite = FALSE;
    else
        type->typestring_offset = 1;
}

851 852
static int is_embedded_complex(const type_t *type)
{
853
    switch (typegen_detect_type(type, NULL, TDT_ALL_TYPES))
854
    {
855 856 857 858 859
    case TGT_USER_TYPE:
    case TGT_STRUCT:
    case TGT_UNION:
    case TGT_ARRAY:
    case TGT_IFACE_POINTER:
860 861 862 863
        return TRUE;
    default:
        return FALSE;
    }
864 865
}

866 867 868
static const char *get_context_handle_type_name(const type_t *type)
{
    const type_t *t;
869 870
    for (t = type;
         is_ptr(t) || type_is_alias(t);
871
         t = type_is_alias(t) ? type_alias_get_aliasee_type(t) : type_pointer_get_ref_type(t))
872 873 874 875 876 877
        if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
            return t->name;
    assert(0);
    return NULL;
}

878 879 880 881
#define WRITE_FCTYPE(file, fctype, typestring_offset) \
    do { \
        if (file) \
            fprintf(file, "/* %2u */\n", typestring_offset); \
882
        print_file((file), 2, "0x%02x,\t/* " #fctype " */\n", fctype); \
883 884 885
    } \
    while (0)

886
static void print_file(FILE *file, int indent, const char *format, ...) __attribute__((format (printf, 3, 4)));
887
static void print_file(FILE *file, int indent, const char *format, ...)
888 889 890
{
    va_list va;
    va_start(va, format);
891
    print(file, indent, format, va);
892
    va_end(va);
893 894 895 896 897 898 899 900 901 902 903
}

void print(FILE *file, int indent, const char *format, va_list va)
{
    if (file)
    {
        if (format[0] != '\n')
            while (0 < indent--)
                fprintf(file, "    ");
        vfprintf(file, format, va);
    }
904 905
}

906

907
static void write_var_init(FILE *file, int indent, const type_t *t, const char *n, const char *local_var_prefix)
908 909
{
    if (decl_indirect(t))
910
    {
911 912
        print_file(file, indent, "MIDL_memset(&%s%s, 0, sizeof(%s%s));\n",
                   local_var_prefix, n, local_var_prefix, n);
913 914
        print_file(file, indent, "%s_p_%s = &%s%s;\n", local_var_prefix, n, local_var_prefix, n);
    }
915
    else if (is_ptr(t) || is_array(t))
916
        print_file(file, indent, "%s%s = 0;\n", local_var_prefix, n);
917 918
}

919
void write_parameters_init(FILE *file, int indent, const var_t *func, const char *local_var_prefix)
920
{
921
    const var_t *var = type_function_get_retval(func->declspec.type);
922

923 924
    if (!is_void(var->declspec.type))
        write_var_init(file, indent, var->declspec.type, var->name, local_var_prefix);
925

926
    if (!type_function_get_args(func->declspec.type))
927 928
        return;

929
    LIST_FOR_EACH_ENTRY( var, type_function_get_args(func->declspec.type), const var_t, entry )
930
        write_var_init(file, indent, var->declspec.type, var->name, local_var_prefix);
931 932 933 934

    fprintf(file, "\n");
}

935 936 937 938 939 940 941 942 943 944
static void write_formatdesc(FILE *f, int indent, const char *str)
{
    print_file(f, indent, "typedef struct _MIDL_%s_FORMAT_STRING\n", str);
    print_file(f, indent, "{\n");
    print_file(f, indent + 1, "short Pad;\n");
    print_file(f, indent + 1, "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str);
    print_file(f, indent, "} MIDL_%s_FORMAT_STRING;\n", str);
    print_file(f, indent, "\n");
}

945
void write_formatstringsdecl(FILE *f, int indent, const statement_list_t *stmts, type_pred_t pred)
946
{
947 948
    clear_all_offsets();

949
    print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n",
950
               get_size_typeformatstring(stmts, pred));
951 952

    print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n",
953
               get_size_procformatstring(stmts, pred));
954 955 956 957 958 959 960 961 962 963

    fprintf(f, "\n");
    write_formatdesc(f, indent, "TYPE");
    write_formatdesc(f, indent, "PROC");
    fprintf(f, "\n");
    print_file(f, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n");
    print_file(f, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n");
    print_file(f, indent, "\n");
}

964 965
int decl_indirect(const type_t *t)
{
966 967 968 969 970 971
    if (is_user_type(t))
        return TRUE;
    return (type_get_type(t) != TYPE_BASIC &&
            type_get_type(t) != TYPE_ENUM &&
            type_get_type(t) != TYPE_POINTER &&
            type_get_type(t) != TYPE_ARRAY);
972 973
}

974 975
static unsigned char get_parameter_fc( const var_t *var, int is_return, unsigned short *flags,
                                       unsigned int *stack_size, unsigned int *typestring_offset )
976 977 978 979
{
    unsigned int alignment, server_size = 0, buffer_size = 0;
    unsigned char fc = 0;
    int is_byval;
980 981
    int is_in = is_attr(var->attrs, ATTR_IN);
    int is_out = is_attr(var->attrs, ATTR_OUT);
982 983 984 985 986

    if (is_return) is_out = TRUE;
    else if (!is_in && !is_out) is_in = TRUE;

    *flags = 0;
987
    *stack_size = get_stack_size( var, &is_byval );
988
    *typestring_offset = var->typestring_offset;
989 990 991 992 993

    if (is_in)     *flags |= IsIn;
    if (is_out)    *flags |= IsOut;
    if (is_return) *flags |= IsReturn;

994 995
    if (!is_string_type( var->attrs, var->declspec.type ))
        buffer_size = get_required_buffer_size_type( var->declspec.type, NULL, var->attrs, TRUE, &alignment );
996

997
    switch (typegen_detect_type( var->declspec.type, var->attrs, TDT_ALL_TYPES ))
998 999 1000
    {
    case TGT_BASIC:
        *flags |= IsBasetype;
1001
        fc = get_basic_fc_signed( var->declspec.type );
1002
        if (fc == FC_BIND_PRIMITIVE)
1003 1004
        {
            buffer_size = 4;  /* actually 0 but avoids setting MustSize */
1005
            fc = FC_LONG;
1006 1007 1008 1009
        }
        break;
    case TGT_ENUM:
        *flags |= IsBasetype;
1010
        fc = get_enum_fc( var->declspec.type );
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
        break;
    case TGT_RANGE:
        *flags |= IsByValue;
        break;
    case TGT_STRUCT:
    case TGT_UNION:
    case TGT_USER_TYPE:
        *flags |= MustFree | (is_byval ? IsByValue : IsSimpleRef);
        break;
    case TGT_IFACE_POINTER:
        *flags |= MustFree;
        break;
    case TGT_ARRAY:
        *flags |= MustFree;
1025 1026 1027
        if (type_array_is_decl_as_ptr(var->declspec.type)
                && type_array_get_ptr_tfsoff(var->declspec.type)
                && get_pointer_fc(var->declspec.type, var->attrs, !is_return) == FC_RP)
1028
        {
1029
            *typestring_offset = var->declspec.type->typestring_offset;
1030
            *flags |= IsSimpleRef;
1031
        }
1032 1033 1034
        break;
    case TGT_STRING:
        *flags |= MustFree;
1035
        if (is_declptr( var->declspec.type ) && get_pointer_fc( var->declspec.type, var->attrs, !is_return ) == FC_RP)
1036 1037
        {
            /* skip over pointer description straight to string description */
1038
            if (is_conformant_array( var->declspec.type )) *typestring_offset += 4;
1039
            else *typestring_offset += 2;
1040 1041 1042 1043 1044
            *flags |= IsSimpleRef;
        }
        break;
    case TGT_CTXT_HANDLE_POINTER:
        *flags |= IsSimpleRef;
1045
        *typestring_offset += 4;
1046 1047 1048 1049 1050
        /* fall through */
    case TGT_CTXT_HANDLE:
        buffer_size = 20;
        break;
    case TGT_POINTER:
1051
        if (get_pointer_fc( var->declspec.type, var->attrs, !is_return ) == FC_RP)
1052
        {
1053
            const type_t *ref = type_pointer_get_ref_type( var->declspec.type );
1054

1055
            if (!is_string_type( var->attrs, ref ))
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
                buffer_size = get_required_buffer_size_type( ref, NULL, NULL, TRUE, &alignment );

            switch (typegen_detect_type( ref, NULL, TDT_ALL_TYPES ))
            {
            case TGT_BASIC:
                *flags |= IsSimpleRef | IsBasetype;
                fc = get_basic_fc( ref );
                if (!is_in && is_out) server_size = pointer_size;
                break;
            case TGT_ENUM:
1066
                if ((fc = get_enum_fc( ref )) == FC_ENUM32)
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
                {
                    *flags |= IsSimpleRef | IsBasetype;
                    if (!is_in && is_out) server_size = pointer_size;
                }
                else
                {
                    server_size = pointer_size;
                }
                break;
            case TGT_UNION:
            case TGT_USER_TYPE:
            case TGT_RANGE:
1079 1080
                *flags |= MustFree | IsSimpleRef;
                *typestring_offset = ref->typestring_offset;
1081 1082
                if (!is_in && is_out) server_size = type_memsize( ref );
                break;
1083
            case TGT_ARRAY:
1084 1085 1086 1087 1088 1089
                *flags |= MustFree;
                if (!type_array_is_decl_as_ptr(ref))
                {
                    *flags |= IsSimpleRef;
                    *typestring_offset = ref->typestring_offset;
                }
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
                if (!is_in && is_out) server_size = type_memsize( ref );
                break;
            case TGT_STRING:
            case TGT_POINTER:
            case TGT_CTXT_HANDLE:
            case TGT_CTXT_HANDLE_POINTER:
                *flags |= MustFree;
                server_size = pointer_size;
                break;
            case TGT_IFACE_POINTER:
                *flags |= MustFree;
                if (is_in && is_out) server_size = pointer_size;
                break;
            case TGT_STRUCT:
                *flags |= IsSimpleRef | MustFree;
                *typestring_offset = ref->typestring_offset;
                switch (get_struct_fc(ref))
                {
1108 1109 1110
                case FC_STRUCT:
                case FC_PSTRUCT:
                case FC_BOGUS_STRUCT:
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
                    if (!is_in && is_out) server_size = type_memsize( ref );
                    break;
                default:
                    break;
                }
                break;
            case TGT_INVALID:
                assert(0);
            }
        }
        else  /* not ref pointer */
        {
            *flags |= MustFree;
        }
        break;
    case TGT_INVALID:
        assert(0);
    }

    if (!buffer_size) *flags |= MustSize;

    if (server_size)
    {
        server_size = (server_size + 7) / 8;
        if (server_size < 8) *flags |= server_size << 13;
    }
    return fc;
}

static unsigned char get_func_oi2_flags( const var_t *func )
{
    const var_t *var;
1143
    var_list_t *args = type_function_get_args( func->declspec.type );
1144
    var_t *retval = type_function_get_retval( func->declspec.type );
1145 1146 1147 1148 1149 1150
    unsigned char oi2_flags = 0x40;  /* HasExtensions */
    unsigned short flags;
    unsigned int stack_size, typestring_offset;

    if (args) LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
    {
1151
        get_parameter_fc( var, 0, &flags, &stack_size, &typestring_offset );
1152 1153 1154 1155 1156 1157 1158
        if (flags & MustSize)
        {
            if (flags & IsIn) oi2_flags |= 0x02; /* ClientMustSize */
            if (flags & IsOut) oi2_flags |= 0x01;  /* ServerMustSize */
        }
    }

1159
    if (!is_void( retval->declspec.type ))
1160 1161
    {
        oi2_flags |= 0x04;  /* HasRet */
1162
        get_parameter_fc( retval, 1, &flags, &stack_size, &typestring_offset );
1163 1164 1165 1166 1167
        if (flags & MustSize) oi2_flags |= 0x01;  /* ServerMustSize */
    }
    return oi2_flags;
}

1168
static unsigned int write_new_procformatstring_type(FILE *file, int indent, const var_t *var,
1169 1170
                                                    int is_return, unsigned int *stack_offset)
{
1171
    char buffer[128];
1172 1173
    unsigned int stack_size, typestring_offset;
    unsigned short flags;
1174
    unsigned char fc = get_parameter_fc( var, is_return, &flags, &stack_size, &typestring_offset );
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188

    strcpy( buffer, "/* flags:" );
    if (flags & MustSize) strcat( buffer, " must size," );
    if (flags & MustFree) strcat( buffer, " must free," );
    if (flags & IsPipe) strcat( buffer, " pipe," );
    if (flags & IsIn) strcat( buffer, " in," );
    if (flags & IsOut) strcat( buffer, " out," );
    if (flags & IsReturn) strcat( buffer, " return," );
    if (flags & IsBasetype) strcat( buffer, " base type," );
    if (flags & IsByValue) strcat( buffer, " by value," );
    if (flags & IsSimpleRef) strcat( buffer, " simple ref," );
    if (flags >> 13) sprintf( buffer + strlen(buffer), " srv size=%u,", (flags >> 13) * 8 );
    strcpy( buffer + strlen( buffer ) - 1, " */" );
    print_file( file, indent, "NdrFcShort(0x%hx),\t%s\n", flags, buffer );
1189
    print_file( file, indent, "NdrFcShort(0x%x),	/* stack offset = %u */\n",
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202
                *stack_offset, *stack_offset );
    if (flags & IsBasetype)
    {
        print_file( file, indent, "0x%02x,	/* %s */\n", fc, string_of_type(fc) );
        print_file( file, indent, "0x0,\n" );
    }
    else
        print_file( file, indent, "NdrFcShort(0x%x),	/* type offset = %u */\n",
                    typestring_offset, typestring_offset );
    *stack_offset += max( stack_size, pointer_size );
    return 6;
}

1203
static unsigned int write_old_procformatstring_type(FILE *file, int indent, const var_t *var,
1204
                                                    int is_return, int is_interpreted)
1205
{
1206
    unsigned int size;
1207

1208 1209
    int is_in = is_attr(var->attrs, ATTR_IN);
    int is_out = is_attr(var->attrs, ATTR_OUT);
1210 1211

    if (!is_in && !is_out) is_in = TRUE;
1212

1213 1214
    if (type_get_type(var->declspec.type) == TYPE_BASIC ||
        type_get_type(var->declspec.type) == TYPE_ENUM)
1215
    {
1216 1217
        unsigned char fc;

1218 1219 1220 1221 1222
        if (is_return)
            print_file(file, indent, "0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
        else
            print_file(file, indent, "0x4e,    /* FC_IN_PARAM_BASETYPE */\n");

1223
        if (type_get_type(var->declspec.type) == TYPE_ENUM)
1224
        {
1225
            fc = get_enum_fc(var->declspec.type);
1226 1227 1228
        }
        else
        {
1229
            fc = get_basic_fc_signed(var->declspec.type);
1230

1231 1232
            if (fc == FC_BIND_PRIMITIVE)
                fc = FC_IGNORE;
1233
        }
1234 1235 1236 1237

        print_file(file, indent, "0x%02x,    /* %s */\n",
                   fc, string_of_type(fc));
        size = 2; /* includes param type prefix */
1238 1239 1240
    }
    else
    {
1241
        unsigned short offset = var->typestring_offset;
1242

1243 1244 1245
        if (!is_interpreted && is_array(var->declspec.type)
                && type_array_is_decl_as_ptr(var->declspec.type)
                && type_array_get_ptr_tfsoff(var->declspec.type))
1246
            offset = var->declspec.type->typestring_offset;
1247

1248 1249
        if (is_return)
            print_file(file, indent, "0x52,    /* FC_RETURN_PARAM */\n");
1250
        else if (is_in && is_out)
1251
            print_file(file, indent, "0x50,    /* FC_IN_OUT_PARAM */\n");
1252
        else if (is_out)
1253
            print_file(file, indent, "0x51,    /* FC_OUT_PARAM */\n");
1254 1255
        else
            print_file(file, indent, "0x4d,    /* FC_IN_PARAM */\n");
1256

1257
        size = get_stack_size( var, NULL );
1258
        print_file(file, indent, "0x%02x,\n", size / pointer_size );
1259
        print_file(file, indent, "NdrFcShort(0x%x),	/* type offset = %u */\n", offset, offset);
1260
        size = 4; /* includes param type prefix */
1261
    }
1262
    return size;
1263 1264
}

1265 1266 1267
int is_interpreted_func( const type_t *iface, const var_t *func )
{
    const char *str;
1268
    const var_t *var;
1269
    const var_list_t *args = type_function_get_args( func->declspec.type );
1270
    const type_t *ret_type = type_function_get_rettype( func->declspec.type );
1271

1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
    if (type_get_type( ret_type ) == TYPE_BASIC)
    {
        switch (type_basic_get_type( ret_type ))
        {
        case TYPE_BASIC_INT64:
        case TYPE_BASIC_HYPER:
            /* return value must fit in a long_ptr */
            if (pointer_size < 8) return 0;
            break;
        case TYPE_BASIC_FLOAT:
        case TYPE_BASIC_DOUBLE:
            /* floating point values can't be returned */
            return 0;
        default:
            break;
        }
    }
1289
    if (get_stub_mode() != MODE_Oif && args)
1290
    {
1291
        LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
1292
            switch (type_get_type( var->declspec.type ))
1293 1294
            {
            case TYPE_BASIC:
1295
                switch (type_basic_get_type( var->declspec.type ))
1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
                {
                /* floating point arguments are not supported in Oi mode */
                case TYPE_BASIC_FLOAT:  return 0;
                case TYPE_BASIC_DOUBLE: return 0;
                default: break;
                }
                break;
            /* unions passed by value are not supported in Oi mode */
            case TYPE_UNION: return 0;
            case TYPE_ENCAPSULATED_UNION: return 0;
            default: break;
            }
    }
1309

1310 1311
    if ((str = get_attrp( func->attrs, ATTR_OPTIMIZE ))) return !strcmp( str, "i" );
    if ((str = get_attrp( iface->attrs, ATTR_OPTIMIZE ))) return !strcmp( str, "i" );
1312
    return (get_stub_mode() != MODE_Os);
1313 1314
}

1315 1316 1317
static void write_proc_func_header( FILE *file, int indent, const type_t *iface,
                                    const var_t *func, unsigned int *offset,
                                    unsigned short num_proc )
1318
{
1319
    var_t *var;
1320
    var_list_t *args = type_function_get_args( func->declspec.type );
1321 1322 1323
    unsigned char explicit_fc, implicit_fc;
    unsigned char handle_flags;
    const var_t *handle_var = get_func_handle_var( iface, func, &explicit_fc, &implicit_fc );
1324
    unsigned char oi_flags = Oi_HAS_RPCFLAGS | Oi_USE_NEW_INIT_ROUTINES;
1325
    unsigned int rpc_flags = get_rpc_flags( func->attrs );
1326
    unsigned int nb_args = 0;
1327 1328 1329 1330 1331
    unsigned int stack_size = 0;
    unsigned short param_num = 0;
    unsigned short handle_stack_offset = 0;
    unsigned short handle_param_num = 0;

1332
    if (is_full_pointer_function( func )) oi_flags |= Oi_FULL_PTR_USED;
1333 1334
    if (is_object( iface ))
    {
1335 1336
        oi_flags |= Oi_OBJECT_PROC;
        if (get_stub_mode() == MODE_Oif) oi_flags |= Oi_OBJ_USE_V2_INTERPRETER;
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
        stack_size += pointer_size;
    }

    if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )
    {
        if (var == handle_var)
        {
            handle_stack_offset = stack_size;
            handle_param_num = param_num;
        }
1347
        stack_size += get_stack_size( var, NULL );
1348
        param_num++;
1349 1350
        nb_args++;
    }
1351
    if (!is_void( type_function_get_rettype( func->declspec.type )))
1352 1353 1354
    {
        stack_size += pointer_size;
        nb_args++;
1355 1356 1357 1358 1359 1360 1361 1362
    }

    print_file( file, 0, "/* %u (procedure %s::%s) */\n", *offset, iface->name, func->name );
    print_file( file, indent, "0x%02x,\t/* %s */\n", implicit_fc,
                implicit_fc ? string_of_type(implicit_fc) : "explicit handle" );
    print_file( file, indent, "0x%02x,\n", oi_flags );
    print_file( file, indent, "NdrFcLong(0x%x),\n", rpc_flags );
    print_file( file, indent, "NdrFcShort(0x%hx),\t/* method %hu */\n", num_proc, num_proc );
1363
    print_file( file, indent, "NdrFcShort(0x%x),\t/* stack size = %u */\n", stack_size, stack_size );
1364 1365
    *offset += 10;

1366 1367 1368 1369
    if (!implicit_fc)
    {
        switch (explicit_fc)
        {
1370
        case FC_BIND_PRIMITIVE:
1371 1372 1373 1374 1375 1376 1377
            handle_flags = 0;
            print_file( file, indent, "0x%02x,\t/* %s */\n", explicit_fc, string_of_type(explicit_fc) );
            print_file( file, indent, "0x%02x,\n", handle_flags );
            print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack offset = %hu */\n",
                        handle_stack_offset, handle_stack_offset );
            *offset += 4;
            break;
1378
        case FC_BIND_GENERIC:
1379
            handle_flags = type_memsize( handle_var->declspec.type );
1380 1381 1382 1383
            print_file( file, indent, "0x%02x,\t/* %s */\n", explicit_fc, string_of_type(explicit_fc) );
            print_file( file, indent, "0x%02x,\n", handle_flags );
            print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack offset = %hu */\n",
                        handle_stack_offset, handle_stack_offset );
1384
            print_file( file, indent, "0x%02x,\n", get_generic_handle_offset( handle_var->declspec.type ) );
1385
            print_file( file, indent, "0x%x,\t/* FC_PAD */\n", FC_PAD);
1386 1387
            *offset += 6;
            break;
1388
        case FC_BIND_CONTEXT:
1389
            handle_flags = get_contexthandle_flags( iface, handle_var->attrs, handle_var->declspec.type, 0 );
1390 1391 1392 1393
            print_file( file, indent, "0x%02x,\t/* %s */\n", explicit_fc, string_of_type(explicit_fc) );
            print_file( file, indent, "0x%02x,\n", handle_flags );
            print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack offset = %hu */\n",
                        handle_stack_offset, handle_stack_offset );
1394
            print_file( file, indent, "0x%02x,\n", get_context_handle_offset( handle_var->declspec.type ) );
1395 1396 1397 1398 1399
            print_file( file, indent, "0x%02x,\t/* param %hu */\n", handle_param_num, handle_param_num );
            *offset += 6;
            break;
        }
    }
1400

1401
    if (get_stub_mode() == MODE_Oif)
1402
    {
1403 1404 1405 1406 1407 1408
        unsigned char oi2_flags = get_func_oi2_flags( func );
        unsigned char ext_flags = 0;
        unsigned int size;

        if (is_attr( func->attrs, ATTR_NOTIFY )) ext_flags |= 0x08;  /* HasNotify */
        if (is_attr( func->attrs, ATTR_NOTIFYFLAG )) ext_flags |= 0x10;  /* HasNotify2 */
1409
        if (iface == type_iface_get_async_iface(iface)) oi2_flags |= 0x20;
1410 1411

        size = get_function_buffer_size( func, PASS_IN );
1412
        print_file( file, indent, "NdrFcShort(0x%x),\t/* client buffer = %u */\n", size, size );
1413
        size = get_function_buffer_size( func, PASS_OUT );
1414
        print_file( file, indent, "NdrFcShort(0x%x),\t/* server buffer = %u */\n", size, size );
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424
        print_file( file, indent, "0x%02x,\n", oi2_flags );
        print_file( file, indent, "0x%02x,\t/* %u params */\n", nb_args, nb_args );
        print_file( file, indent, "0x%02x,\n", pointer_size == 8 ? 10 : 8 );
        print_file( file, indent, "0x%02x,\n", ext_flags );
        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* server corr hint */
        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* client corr hint */
        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* FIXME: notify index */
        *offset += 14;
        if (pointer_size == 8)
        {
1425 1426 1427 1428 1429
            unsigned short pos = 0, fpu_mask = 0;

            if (is_object( iface )) pos += 2;
            if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )
            {
1430
                if (type_get_type( var->declspec.type ) == TYPE_BASIC)
1431
                {
1432
                    switch (type_basic_get_type( var->declspec.type ))
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442
                    {
                    case TYPE_BASIC_FLOAT:  fpu_mask |= 1 << pos; break;
                    case TYPE_BASIC_DOUBLE: fpu_mask |= 2 << pos; break;
                    default: break;
                    }
                }
                pos += 2;
                if (pos >= 16) break;
            }
            print_file( file, indent, "NdrFcShort(0x%x),\n", fpu_mask );  /* floating point mask */
1443 1444
            *offset += 2;
        }
1445 1446 1447 1448 1449 1450 1451
    }
}

static void write_procformatstring_func( FILE *file, int indent, const type_t *iface,
                                         const var_t *func, unsigned int *offset,
                                         unsigned short num_proc )
{
1452
    unsigned int stack_offset = is_object( iface ) ? pointer_size : 0;
1453
    int is_interpreted = is_interpreted_func( iface, func );
1454
    int is_new_style = is_interpreted && (get_stub_mode() == MODE_Oif);
1455
    var_t *retval = type_function_get_retval( func->declspec.type );
1456 1457

    if (is_interpreted) write_proc_func_header( file, indent, iface, func, offset, num_proc );
1458

1459
    /* emit argument data */
1460
    if (type_function_get_args(func->declspec.type))
1461 1462
    {
        const var_t *var;
1463
        LIST_FOR_EACH_ENTRY( var, type_function_get_args(func->declspec.type), const var_t, entry )
1464 1465
        {
            print_file( file, 0, "/* %u (parameter %s) */\n", *offset, var->name );
1466
            if (is_new_style)
1467
                *offset += write_new_procformatstring_type(file, indent, var, FALSE, &stack_offset);
1468
            else
1469
                *offset += write_old_procformatstring_type(file, indent, var, FALSE, is_interpreted);
1470 1471 1472 1473
        }
    }

    /* emit return value data */
1474
    if (is_void(retval->declspec.type))
1475
    {
1476 1477 1478
        if (!is_new_style)
        {
            print_file(file, 0, "/* %u (void) */\n", *offset);
1479 1480
            print_file(file, indent, "0x5b,\t/* FC_END */\n");
            print_file(file, indent, "0x5c,\t/* FC_PAD */\n");
1481 1482
            *offset += 2;
        }
1483 1484 1485 1486
    }
    else
    {
        print_file( file, 0, "/* %u (return value) */\n", *offset );
1487
        if (is_new_style)
1488
            *offset += write_new_procformatstring_type(file, indent, retval, TRUE, &stack_offset);
1489
        else
1490
            *offset += write_old_procformatstring_type(file, indent, retval, TRUE, is_interpreted);
1491 1492 1493
    }
}

1494 1495 1496
static void for_each_iface(const statement_list_t *stmts,
                           void (*proc)(type_t *iface, FILE *file, int indent, unsigned int *offset),
                           type_pred_t pred, FILE *file, int indent, unsigned int *offset)
1497
{
1498
    const statement_t *stmt;
1499 1500
    type_t *iface;

1501
    if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
1502
    {
1503 1504 1505 1506 1507
        if (stmt->type != STMT_TYPE || type_get_type(stmt->u.type) != TYPE_INTERFACE)
            continue;
        iface = stmt->u.type;
        if (!pred(iface)) continue;
        proc(iface, file, indent, offset);
1508 1509
        if (type_iface_get_async_iface(iface))
            proc(type_iface_get_async_iface(iface), file, indent, offset);
1510 1511
    }
}
1512

1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523
static void write_iface_procformatstring(type_t *iface, FILE *file, int indent, unsigned int *offset)
{
    const statement_t *stmt;
    const type_t *parent = type_iface_get_inherit( iface );
    int count = parent ? count_methods( parent ) : 0;

    STATEMENTS_FOR_EACH_FUNC(stmt, type_iface_get_stmts(iface))
    {
        var_t *func = stmt->u.var;
        if (is_local(func->attrs)) continue;
        write_procformatstring_func( file, indent, iface, func, offset, count++ );
1524
    }
1525 1526 1527 1528 1529
}

void write_procformatstring(FILE *file, const statement_list_t *stmts, type_pred_t pred)
{
    int indent = 0;
1530
    unsigned int offset = 0;
1531 1532 1533 1534 1535 1536 1537 1538

    print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
    print_file(file, indent, "{\n");
    indent++;
    print_file(file, indent, "0,\n");
    print_file(file, indent, "{\n");
    indent++;

1539
    for_each_iface(stmts, write_iface_procformatstring, pred, file, indent, &offset);
1540 1541 1542 1543 1544 1545 1546 1547 1548

    print_file(file, indent, "0x0\n");
    indent--;
    print_file(file, indent, "}\n");
    indent--;
    print_file(file, indent, "};\n");
    print_file(file, indent, "\n");
}

1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
void write_procformatstring_offsets( FILE *file, const type_t *iface )
{
    const statement_t *stmt;
    int indent = 0;

    print_file( file, indent,  "static const unsigned short %s_FormatStringOffsetTable[] =\n",
                iface->name );
    print_file( file, indent,  "{\n" );
    indent++;
    STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
    {
        var_t *func = stmt->u.var;
        if (is_local( func->attrs )) continue;
        print_file( file, indent,  "%u,  /* %s */\n", func->procstring_offset, func->name );
    }
    indent--;
    print_file( file, indent,  "};\n\n" );
}

1568
static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
1569
{
1570 1571 1572
    unsigned char fc;

    if (type_get_type(type) == TYPE_BASIC)
1573
        fc = get_basic_fc_signed(type);
1574 1575 1576 1577 1578 1579 1580 1581
    else if (type_get_type(type) == TYPE_ENUM)
        fc = get_enum_fc(type);
    else
        return 0;

    print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
    *typestring_offset += 1;
    return 1;
1582 1583
}

1584
/* write conformance / variance descriptor */
1585
static unsigned int write_conf_or_var_desc(FILE *file, const type_t *cont_type,
1586 1587
                                           unsigned int baseoff, const type_t *type,
                                           const expr_t *expr)
1588
{
1589
    unsigned char operator_type = 0;
1590
    unsigned char conftype = FC_NORMAL_CONFORMANCE;
1591
    const char *conftype_string = "field";
1592
    const expr_t *subexpr;
1593 1594
    const type_t *iface = NULL;
    const char *name;
1595

1596 1597 1598 1599 1600 1601
    if (!expr)
    {
        print_file(file, 2, "NdrFcLong(0xffffffff),\t/* -1 */\n");
        return 4;
    }

1602 1603 1604
    if (expr->is_const)
    {
        if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
1605
            error("write_conf_or_var_desc: constant value %d is greater than "
1606 1607 1608
                  "the maximum constant size of %d\n", expr->cval,
                  UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);

1609
        print_file(file, 2, "0x%x, /* Corr desc: constant, val = %d */\n",
1610
                   FC_CONSTANT_CONFORMANCE, expr->cval);
1611
        print_file(file, 2, "0x%x,\n", expr->cval >> 16);
1612
        print_file(file, 2, "NdrFcShort(0x%hx),\n", (unsigned short)expr->cval);
1613 1614 1615 1616

        return 4;
    }

1617
    if (!cont_type)  /* top-level conformance */
1618
    {
1619
        conftype = FC_TOP_LEVEL_CONFORMANCE;
1620
        conftype_string = "parameter";
1621
        cont_type = current_func->declspec.type;
1622 1623
        name = current_func->name;
        iface = current_iface;
1624
    }
1625
    else
1626
    {
1627 1628 1629
        name = cont_type->name;
        if (is_ptr(type) || (is_array(type) && type_array_is_decl_as_ptr(type)))
        {
1630
            conftype = FC_POINTER_CONFORMANCE;
1631 1632
            conftype_string = "field pointer";
        }
1633 1634
    }

1635
    subexpr = expr;
1636 1637 1638 1639
    switch (subexpr->type)
    {
    case EXPR_PPTR:
        subexpr = subexpr->ref;
1640
        operator_type = FC_DEREFERENCE;
1641 1642 1643 1644 1645
        break;
    case EXPR_DIV:
        if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
        {
            subexpr = subexpr->ref;
1646
            operator_type = FC_DIV_2;
1647 1648 1649 1650 1651 1652
        }
        break;
    case EXPR_MUL:
        if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
        {
            subexpr = subexpr->ref;
1653
            operator_type = FC_MULT_2;
1654 1655 1656 1657 1658 1659
        }
        break;
    case EXPR_SUB:
        if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
        {
            subexpr = subexpr->ref;
1660
            operator_type = FC_SUB_1;
1661 1662 1663 1664 1665 1666
        }
        break;
    case EXPR_ADD:
        if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
        {
            subexpr = subexpr->ref;
1667
            operator_type = FC_ADD_1;
1668 1669 1670 1671 1672 1673 1674
        }
        break;
    default:
        break;
    }

    if (subexpr->type == EXPR_IDENTIFIER)
1675
    {
1676 1677
        const type_t *correlation_variable = NULL;
        unsigned char param_type = 0;
1678
        unsigned int offset = 0;
1679
        const var_t *var;
1680
        struct expr_loc expr_loc;
1681

1682
        if (type_get_type(cont_type) == TYPE_FUNCTION)
1683
        {
1684
            var_list_t *args = type_function_get_args( cont_type );
1685 1686 1687

            if (is_object( iface )) offset += pointer_size;
            if (args) LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
1688
            {
1689 1690 1691
                if (var->name && !strcmp(var->name, subexpr->u.sval))
                {
                    expr_loc.v = var;
1692
                    correlation_variable = var->declspec.type;
1693 1694
                    break;
                }
1695
                offset += get_stack_size( var, NULL );
1696 1697 1698 1699 1700 1701 1702 1703
            }
        }
        else
        {
            var_list_t *fields = type_struct_get_fields( cont_type );

            if (fields) LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
            {
1704
                unsigned int size = field_memsize( var->declspec.type, &offset );
1705 1706 1707
                if (var->name && !strcmp(var->name, subexpr->u.sval))
                {
                    expr_loc.v = var;
1708
                    correlation_variable = var->declspec.type;
1709 1710 1711
                    break;
                }
                offset += size;
1712
            }
1713
        }
1714

1715 1716 1717 1718
        if (!correlation_variable)
            error("write_conf_or_var_desc: couldn't find variable %s in %s\n", subexpr->u.sval, name);
        expr_loc.attr = NULL;
        correlation_variable = expr_resolve_type(&expr_loc, cont_type, expr);
1719

1720
        offset -= baseoff;
1721

1722
        if (type_get_type(correlation_variable) == TYPE_BASIC)
1723
        {
1724
            switch (get_basic_fc(correlation_variable))
1725
            {
1726 1727 1728
            case FC_CHAR:
            case FC_SMALL:
                param_type = FC_SMALL;
1729
                break;
1730 1731 1732
            case FC_BYTE:
            case FC_USMALL:
                param_type = FC_USMALL;
1733
                break;
1734 1735 1736
            case FC_WCHAR:
            case FC_SHORT:
                param_type = FC_SHORT;
1737
                break;
1738 1739
            case FC_USHORT:
                param_type = FC_USHORT;
1740
                break;
1741 1742
            case FC_LONG:
                param_type = FC_LONG;
1743
                break;
1744 1745
            case FC_ULONG:
                param_type = FC_ULONG;
1746 1747 1748
                break;
            default:
                error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
1749
                      get_basic_fc(correlation_variable));
1750 1751 1752 1753
            }
        }
        else if (type_get_type(correlation_variable) == TYPE_ENUM)
        {
1754 1755
            if (get_enum_fc(correlation_variable) == FC_ENUM32)
                param_type = FC_LONG;
1756
            else
1757
                param_type = FC_SHORT;
1758
        }
1759 1760 1761
        else if (type_get_type(correlation_variable) == TYPE_POINTER)
        {
            if (pointer_size == 8)
1762
                param_type = FC_HYPER;
1763
            else
1764
                param_type = FC_LONG;
1765
        }
1766 1767 1768 1769 1770
        else
        {
            error("write_conf_or_var_desc: non-arithmetic type used as correlation variable %s\n",
                  subexpr->u.sval);
            return 0;
1771
        }
1772

1773 1774 1775
        print_file(file, 2, "0x%x,\t/* Corr desc: %s %s, %s */\n",
                   conftype | param_type, conftype_string, subexpr->u.sval, string_of_type(param_type));
        print_file(file, 2, "0x%x,\t/* %s */\n", operator_type,
1776
                   operator_type ? string_of_type(operator_type) : "no operators");
1777
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* offset = %d */\n",
1778
                   (unsigned short)offset, offset);
1779
    }
1780
    else if (!iface || is_interpreted_func( iface, current_func ))
1781 1782
    {
        unsigned int callback_offset = 0;
1783 1784
        struct expr_eval_routine *eval;
        int found = 0;
1785

1786
        LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
1787
        {
1788 1789 1790 1791
            if (eval->cont_type == cont_type ||
                (type_get_type( eval->cont_type ) == type_get_type( cont_type ) &&
                 eval->iface == iface &&
                 eval->name && name && !strcmp(eval->name, name) &&
1792
                 !compare_expr(eval->expr, expr)))
1793
            {
1794 1795
                found = 1;
                break;
1796
            }
1797
            callback_offset++;
1798
        }
1799 1800

        if (!found)
1801
        {
1802
            eval = xmalloc (sizeof(*eval));
1803 1804 1805
            eval->iface = iface;
            eval->cont_type = cont_type;
            eval->name = xstrdup( name );
1806
            eval->baseoff = baseoff;
1807 1808
            eval->expr = expr;
            list_add_tail (&expr_eval_routines, &eval->entry);
1809 1810
        }

1811 1812 1813
        if (callback_offset > USHRT_MAX)
            error("Maximum number of callback routines reached\n");

1814
        print_file(file, 2, "0x%x,\t/* Corr desc: %s in %s */\n", conftype, conftype_string, name);
1815
        print_file(file, 2, "0x%x,\t/* %s */\n", FC_CALLBACK, "FC_CALLBACK");
1816
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)callback_offset, callback_offset);
1817
    }
1818 1819 1820 1821 1822 1823
    else  /* output a dummy corr desc that isn't used */
    {
        print_file(file, 2, "0x%x,\t/* Corr desc: unused for %s */\n", conftype, name);
        print_file(file, 2, "0x0,\n" );
        print_file(file, 2, "NdrFcShort(0x0),\n" );
    }
1824 1825 1826
    return 4;
}

1827 1828 1829 1830
/* return size and start offset of a data field based on current offset */
static unsigned int field_memsize(const type_t *type, unsigned int *offset)
{
    unsigned int align = 0;
1831
    unsigned int size = type_memsize_and_alignment( type, &align );
1832 1833 1834 1835 1836

    *offset = ROUND_SIZE( *offset, align );
    return size;
}

1837
static unsigned int fields_memsize(const var_list_t *fields, unsigned int *align)
Robert Shearman's avatar
Robert Shearman committed
1838
{
1839
    unsigned int size = 0;
1840
    unsigned int max_align;
1841 1842 1843 1844
    const var_t *v;

    if (!fields) return 0;
    LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
1845 1846
    {
        unsigned int falign = 0;
1847
        unsigned int fsize = type_memsize_and_alignment(v->declspec.type, &falign);
1848
        if (*align < falign) *align = falign;
1849
        falign = clamp_align(falign);
1850
        size = ROUND_SIZE(size, falign);
1851 1852
        size += fsize;
    }
1853

1854
    max_align = clamp_align(*align);
1855 1856
    size = ROUND_SIZE(size, max_align);

Robert Shearman's avatar
Robert Shearman committed
1857 1858 1859
    return size;
}

1860
static unsigned int union_memsize(const var_list_t *fields, unsigned int *pmaxa)
1861
{
1862
    unsigned int size, maxs = 0;
1863 1864 1865 1866 1867 1868
    unsigned int align = *pmaxa;
    const var_t *v;

    if (fields) LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
    {
        /* we could have an empty default field with NULL type */
1869
        if (v->declspec.type)
1870
        {
1871
            size = type_memsize_and_alignment(v->declspec.type, &align);
1872 1873 1874 1875 1876 1877 1878 1879
            if (maxs < size) maxs = size;
            if (*pmaxa < align) *pmaxa = align;
        }
    }

    return maxs;
}

1880
unsigned int type_memsize_and_alignment(const type_t *t, unsigned int *align)
Robert Shearman's avatar
Robert Shearman committed
1881
{
1882
    unsigned int size = 0;
Robert Shearman's avatar
Robert Shearman committed
1883

1884
    switch (type_get_type(t))
1885
    {
1886
    case TYPE_BASIC:
1887
        switch (get_basic_fc(t))
1888
        {
1889 1890 1891 1892
        case FC_BYTE:
        case FC_CHAR:
        case FC_USMALL:
        case FC_SMALL:
1893 1894 1895
            size = 1;
            if (size > *align) *align = size;
            break;
1896 1897 1898
        case FC_WCHAR:
        case FC_USHORT:
        case FC_SHORT:
1899 1900 1901
            size = 2;
            if (size > *align) *align = size;
            break;
1902 1903 1904 1905
        case FC_ULONG:
        case FC_LONG:
        case FC_ERROR_STATUS_T:
        case FC_FLOAT:
1906 1907 1908
            size = 4;
            if (size > *align) *align = size;
            break;
1909 1910
        case FC_HYPER:
        case FC_DOUBLE:
1911 1912 1913
            size = 8;
            if (size > *align) *align = size;
            break;
1914 1915 1916
        case FC_INT3264:
        case FC_UINT3264:
        case FC_BIND_PRIMITIVE:
1917 1918 1919 1920
            assert( pointer_size );
            size = pointer_size;
            if (size > *align) *align = size;
            break;
1921
        default:
1922
            error("type_memsize: Unknown type 0x%x\n", get_basic_fc(t));
1923 1924
            size = 0;
        }
Robert Shearman's avatar
Robert Shearman committed
1925
        break;
1926 1927 1928
    case TYPE_ENUM:
        switch (get_enum_fc(t))
        {
1929 1930
        case FC_ENUM16:
        case FC_ENUM32:
1931 1932 1933 1934 1935 1936 1937
            size = 4;
            if (size > *align) *align = size;
            break;
        default:
            error("type_memsize: Unknown enum type\n");
            size = 0;
        }
Robert Shearman's avatar
Robert Shearman committed
1938
        break;
1939
    case TYPE_STRUCT:
1940
        size = fields_memsize(type_struct_get_fields(t), align);
1941
        break;
1942
    case TYPE_ENCAPSULATED_UNION:
1943 1944
        size = fields_memsize(type_encapsulated_union_get_fields(t), align);
        break;
1945
    case TYPE_UNION:
1946
        size = union_memsize(type_union_get_cases(t), align);
Robert Shearman's avatar
Robert Shearman committed
1947
        break;
1948
    case TYPE_POINTER:
1949
    case TYPE_INTERFACE:
1950 1951 1952
        assert( pointer_size );
        size = pointer_size;
        if (size > *align) *align = size;
1953
        break;
1954
    case TYPE_ARRAY:
1955
        if (!type_array_is_decl_as_ptr(t))
1956 1957 1958
        {
            if (is_conformant_array(t))
            {
1959
                type_memsize_and_alignment(type_array_get_element_type(t), align);
1960 1961 1962 1963
                size = 0;
            }
            else
                size = type_array_get_dim(t) *
1964
                    type_memsize_and_alignment(type_array_get_element_type(t), align);
1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977
        }
        else /* declared as a pointer */
        {
            assert( pointer_size );
            size = pointer_size;
            if (size > *align) *align = size;
        }
        break;
    case TYPE_ALIAS:
    case TYPE_VOID:
    case TYPE_COCLASS:
    case TYPE_MODULE:
    case TYPE_FUNCTION:
1978
    case TYPE_BITFIELD:
1979
    case TYPE_APICONTRACT:
1980
    case TYPE_RUNTIMECLASS:
1981 1982
    case TYPE_PARAMETERIZED_TYPE:
    case TYPE_PARAMETER:
1983
    case TYPE_DELEGATE:
1984 1985 1986
        /* these types should not be encountered here due to language
         * restrictions (interface, void, coclass, module), logical
         * restrictions (alias - due to type_get_type call above) or
1987
         * checking restrictions (function, bitfield). */
1988
        assert(0);
Robert Shearman's avatar
Robert Shearman committed
1989 1990 1991 1992 1993
    }

    return size;
}

1994 1995 1996 1997 1998 1999
unsigned int type_memsize(const type_t *t)
{
    unsigned int align = 0;
    return type_memsize_and_alignment( t, &align );
}

2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
static unsigned int type_buffer_alignment(const type_t *t)
{
    const var_list_t *fields;
    const var_t *var;
    unsigned int max = 0, align;

    switch (type_get_type(t))
    {
    case TYPE_BASIC:
        switch (get_basic_fc(t))
        {
2011 2012 2013 2014
        case FC_BYTE:
        case FC_CHAR:
        case FC_USMALL:
        case FC_SMALL:
2015
            return 1;
2016 2017 2018
        case FC_WCHAR:
        case FC_USHORT:
        case FC_SHORT:
2019
            return 2;
2020 2021 2022 2023 2024 2025
        case FC_ULONG:
        case FC_LONG:
        case FC_ERROR_STATUS_T:
        case FC_FLOAT:
        case FC_INT3264:
        case FC_UINT3264:
2026
            return 4;
2027 2028
        case FC_HYPER:
        case FC_DOUBLE:
2029 2030 2031 2032 2033 2034 2035 2036
            return 8;
        default:
            error("type_buffer_alignment: Unknown type 0x%x\n", get_basic_fc(t));
        }
        break;
    case TYPE_ENUM:
        switch (get_enum_fc(t))
        {
2037
        case FC_ENUM16:
2038
            return 2;
2039
        case FC_ENUM32:
2040 2041 2042 2043 2044 2045 2046 2047 2048
            return 4;
        default:
            error("type_buffer_alignment: Unknown enum type\n");
        }
        break;
    case TYPE_STRUCT:
        if (!(fields = type_struct_get_fields(t))) break;
        LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
        {
2049 2050
            if (!var->declspec.type) continue;
            align = type_buffer_alignment( var->declspec.type );
2051 2052 2053 2054 2055 2056 2057
            if (max < align) max = align;
        }
        break;
    case TYPE_ENCAPSULATED_UNION:
        if (!(fields = type_encapsulated_union_get_fields(t))) break;
        LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
        {
2058 2059
            if (!var->declspec.type) continue;
            align = type_buffer_alignment( var->declspec.type );
2060 2061 2062 2063 2064 2065 2066
            if (max < align) max = align;
        }
        break;
    case TYPE_UNION:
        if (!(fields = type_union_get_cases(t))) break;
        LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
        {
2067 2068
            if (!var->declspec.type) continue;
            align = type_buffer_alignment( var->declspec.type );
2069 2070 2071 2072 2073
            if (max < align) max = align;
        }
        break;
    case TYPE_ARRAY:
        if (!type_array_is_decl_as_ptr(t))
2074
            return type_buffer_alignment( type_array_get_element_type(t) );
2075 2076 2077 2078 2079 2080 2081 2082 2083 2084
        /* else fall through */
    case TYPE_POINTER:
        return 4;
    case TYPE_INTERFACE:
    case TYPE_ALIAS:
    case TYPE_VOID:
    case TYPE_COCLASS:
    case TYPE_MODULE:
    case TYPE_FUNCTION:
    case TYPE_BITFIELD:
2085
    case TYPE_APICONTRACT:
2086
    case TYPE_RUNTIMECLASS:
2087 2088
    case TYPE_PARAMETERIZED_TYPE:
    case TYPE_PARAMETER:
2089
    case TYPE_DELEGATE:
2090 2091 2092 2093 2094 2095 2096 2097 2098
        /* these types should not be encountered here due to language
         * restrictions (interface, void, coclass, module), logical
         * restrictions (alias - due to type_get_type call above) or
         * checking restrictions (function, bitfield). */
        assert(0);
    }
    return max;
}

2099
int is_full_pointer_function(const var_t *func)
2100 2101
{
    const var_t *var;
2102
    if (type_has_full_pointer(type_function_get_rettype(func->declspec.type), func->attrs, TRUE))
2103
        return TRUE;
2104
    if (!type_function_get_args(func->declspec.type))
2105
        return FALSE;
2106
    LIST_FOR_EACH_ENTRY( var, type_function_get_args(func->declspec.type), const var_t, entry )
2107
        if (type_has_full_pointer( var->declspec.type, var->attrs, TRUE ))
2108 2109 2110 2111
            return TRUE;
    return FALSE;
}

2112
void write_full_pointer_init(FILE *file, int indent, const var_t *func, int is_server)
2113
{
2114
    print_file(file, indent, "__frame->_StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,%s);\n",
2115 2116 2117 2118
                   is_server ? "XLAT_SERVER" : "XLAT_CLIENT");
    fprintf(file, "\n");
}

2119
void write_full_pointer_free(FILE *file, int indent, const var_t *func)
2120
{
2121
    print_file(file, indent, "NdrFullPointerXlatFree(__frame->_StubMsg.FullPtrXlatTables);\n");
2122 2123 2124
    fprintf(file, "\n");
}

2125 2126
static unsigned int write_nonsimple_pointer(FILE *file, const attr_list_t *attrs,
                                            const type_t *type,
2127
                                            enum type_context context,
2128 2129
                                            unsigned int offset,
                                            unsigned int *typeformat_offset)
2130
{
2131 2132 2133 2134 2135
    unsigned int start_offset = *typeformat_offset;
    short reloff = offset - (*typeformat_offset + 2);
    int in_attr, out_attr;
    int pointer_type;
    unsigned char flags = 0;
2136

2137
    pointer_type = get_pointer_fc_context(type, attrs, context);
2138 2139 2140 2141 2142

    in_attr = is_attr(attrs, ATTR_IN);
    out_attr = is_attr(attrs, ATTR_OUT);
    if (!in_attr && !out_attr) in_attr = 1;

2143 2144 2145 2146 2147 2148 2149 2150 2151
    if (!is_interpreted_func(current_iface, current_func))
    {
        if (out_attr && !in_attr && pointer_type == FC_RP)
            flags |= FC_ALLOCED_ON_STACK;
    }
    else if (get_stub_mode() == MODE_Oif)
    {
        if (context == TYPE_CONTEXT_TOPLEVELPARAM && is_ptr(type) && pointer_type == FC_RP)
        {
2152
            switch (typegen_detect_type(type_pointer_get_ref_type(type), NULL, TDT_ALL_TYPES))
2153 2154 2155 2156 2157
            {
            case TGT_STRING:
            case TGT_POINTER:
            case TGT_CTXT_HANDLE:
            case TGT_CTXT_HANDLE_POINTER:
2158
            case TGT_ARRAY:
2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169
                flags |= FC_ALLOCED_ON_STACK;
                break;
            case TGT_IFACE_POINTER:
                if (in_attr && out_attr)
                    flags |= FC_ALLOCED_ON_STACK;
                break;
            default:
                break;
            }
        }
    }
2170

2171 2172
    if (is_ptr(type))
    {
2173
        type_t *ref = type_pointer_get_ref_type(type);
2174
        if(is_declptr(ref) && !is_user_type(ref))
2175
            flags |= FC_POINTER_DEREF;
2176 2177 2178
        if (pointer_type != FC_RP) {
            flags |= get_attrv(type->attrs, ATTR_ALLOCATE);
        }
2179
    }
2180 2181 2182 2183 2184 2185 2186

    print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
               pointer_type,
               flags,
               string_of_type(pointer_type));
    if (file)
    {
2187
        if (flags & FC_ALLOCED_ON_STACK)
2188
            fprintf(file, " [allocated_on_stack]");
2189
        if (flags & FC_POINTER_DEREF)
2190
            fprintf(file, " [pointer_deref]");
2191 2192 2193 2194
        if (flags & FC_DONT_FREE)
            fprintf(file, " [dont_free]");
        if (flags & FC_ALLOCATE_ALL_NODES)
            fprintf(file, " [all_nodes]");
2195 2196 2197 2198 2199 2200 2201
        fprintf(file, " */\n");
    }

    print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n", reloff, reloff, offset);
    *typeformat_offset += 4;

    return start_offset;
2202 2203
}

2204 2205
static unsigned int write_simple_pointer(FILE *file, const attr_list_t *attrs,
                                         const type_t *type, enum type_context context)
2206
{
2207 2208 2209
    unsigned char fc;
    unsigned char pointer_fc;
    const type_t *ref;
2210 2211
    int in_attr = is_attr(attrs, ATTR_IN);
    int out_attr = is_attr(attrs, ATTR_OUT);
2212
    unsigned char flags = FC_SIMPLE_POINTER;
2213

2214 2215
    /* for historical reasons, write_simple_pointer also handled string types,
     * but no longer does. catch bad uses of the function with this check */
2216
    if (is_string_type(attrs, type))
2217
        error("write_simple_pointer: can't handle type %s which is a string type\n", type->name);
2218

2219
    pointer_fc = get_pointer_fc_context(type, attrs, context);
2220

2221
    ref = type_pointer_get_ref_type(type);
2222 2223 2224
    if (type_get_type(ref) == TYPE_ENUM)
        fc = get_enum_fc(ref);
    else
2225
        fc = get_basic_fc(ref);
2226

2227 2228 2229 2230 2231 2232 2233 2234 2235 2236
    if (!is_interpreted_func(current_iface, current_func))
    {
        if (out_attr && !in_attr && pointer_fc == FC_RP)
            flags |= FC_ALLOCED_ON_STACK;
    }
    else if (get_stub_mode() == MODE_Oif)
    {
        if (context == TYPE_CONTEXT_TOPLEVELPARAM && fc == FC_ENUM16 && pointer_fc == FC_RP)
            flags |= FC_ALLOCED_ON_STACK;
    }
2237 2238 2239

    print_file(file, 2, "0x%02x, 0x%x,\t/* %s %s[simple_pointer] */\n",
               pointer_fc, flags, string_of_type(pointer_fc),
2240
               flags & FC_ALLOCED_ON_STACK ? "[allocated_on_stack] " : "");
2241
    print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
2242 2243 2244 2245
    print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
    return 4;
}

2246 2247
static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff)
{
2248
    const decl_spec_t ds = {.type = t};
2249
    print_file(file, 0, "/* %u (", tfsoff);
2250
    write_type_decl(file, &ds, NULL);
2251 2252 2253
    print_file(file, 0, ") */\n");
}

2254
static unsigned int write_pointer_tfs(FILE *file, const attr_list_t *attrs,
2255
                                      type_t *type, unsigned int ref_offset,
2256
                                      enum type_context context,
2257
                                      unsigned int *typestring_offset)
2258
{
2259
    unsigned int offset = *typestring_offset;
2260
    type_t *ref = type_pointer_get_ref_type(type);
2261

2262
    print_start_tfs_comment(file, type, offset);
2263
    update_tfsoff(type, offset, file);
2264

2265 2266 2267 2268
    switch (typegen_detect_type(ref, attrs, TDT_ALL_TYPES))
    {
    case TGT_BASIC:
    case TGT_ENUM:
2269
        *typestring_offset += write_simple_pointer(file, attrs, type, context);
2270 2271
        break;
    default:
2272
        if (ref_offset)
2273
            write_nonsimple_pointer(file, attrs, type, context, ref_offset, typestring_offset);
2274 2275
        break;
    }
2276 2277 2278 2279

    return offset;
}

2280
static int processed(const type_t *type)
2281
{
2282
    return type->typestring_offset && !type->tfswrite;
2283 2284
}

2285 2286 2287 2288
static int user_type_has_variable_size(const type_t *t)
{
    if (is_ptr(t))
        return TRUE;
2289 2290 2291
    else if (type_get_type(t) == TYPE_STRUCT)
    {
        switch (get_struct_fc(t))
2292
        {
2293 2294 2295 2296
        case FC_PSTRUCT:
        case FC_CSTRUCT:
        case FC_CPSTRUCT:
        case FC_CVSTRUCT:
2297 2298
            return TRUE;
        }
2299
    }
2300 2301 2302 2303 2304
    /* Note: Since this only applies to user types, we can't have a conformant
       array here, and strings should get filed under pointer in this case.  */
    return FALSE;
}

2305
static unsigned int write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
2306
{
2307
    unsigned int start, absoff, flags;
2308
    const char *name = NULL;
2309
    type_t *utype = get_user_type(type, &name);
2310 2311
    unsigned int usize = type_memsize(utype);
    unsigned int ualign = type_buffer_alignment(utype);
2312
    unsigned int size = type_memsize(type);
2313 2314 2315
    unsigned short funoff = user_type_offset(name);
    short reloff;

2316 2317
    if (processed(type)) return type->typestring_offset;

2318 2319
    guard_rec(type);

2320 2321
    if(user_type_has_variable_size(utype)) usize = 0;

2322 2323
    if (type_get_type(utype) == TYPE_BASIC ||
        type_get_type(utype) == TYPE_ENUM)
2324
    {
2325 2326 2327 2328 2329
        unsigned char fc;

        if (type_get_type(utype) == TYPE_ENUM)
            fc = get_enum_fc(utype);
        else
2330
            fc = get_basic_fc(utype);
2331

2332
        absoff = *tfsoff;
2333
        print_start_tfs_comment(file, utype, absoff);
2334
        print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344
        print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
        *tfsoff += 2;
    }
    else
    {
        if (!processed(utype))
            write_embedded_types(file, NULL, utype, utype->name, TRUE, tfsoff);
        absoff = utype->typestring_offset;
    }

2345
    if (type_get_type(utype) == TYPE_POINTER && get_pointer_fc(utype, NULL, FALSE) == FC_RP)
2346
        flags = 0x40;
2347
    else if (type_get_type(utype) == TYPE_POINTER && get_pointer_fc(utype, NULL, FALSE) == FC_UP)
2348 2349 2350 2351
        flags = 0x80;
    else
        flags = 0;

2352 2353
    start = *tfsoff;
    update_tfsoff(type, start, file);
2354
    print_start_tfs_comment(file, type, start);
2355
    print_file(file, 2, "0x%x,\t/* FC_USER_MARSHAL */\n", FC_USER_MARSHAL);
2356
    print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
2357
               flags | (ualign - 1), ualign - 1, flags);
2358
    print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
2359 2360
    print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)size, size);
    print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)usize, usize);
2361 2362
    *tfsoff += 8;
    reloff = absoff - *tfsoff;
2363
    print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n", reloff, reloff, absoff);
2364
    *tfsoff += 2;
2365
    return start;
2366 2367
}

2368
static void write_member_type(FILE *file, const type_t *cont,
2369 2370 2371
                              int cont_is_complex, const attr_list_t *attrs,
                              const type_t *type, unsigned int *corroff,
                              unsigned int *tfsoff)
2372
{
2373
    if (is_embedded_complex(type) && !is_conformant_array(type))
2374
    {
2375
        unsigned int absoff;
2376 2377
        short reloff;

2378
        if (type_get_type(type) == TYPE_UNION && is_attr(attrs, ATTR_SWITCHIS))
2379 2380 2381 2382 2383 2384 2385 2386 2387
        {
            absoff = *corroff;
            *corroff += 8;
        }
        else
        {
            absoff = type->typestring_offset;
        }
        reloff = absoff - (*tfsoff + 2);
2388 2389

        print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
2390 2391 2392 2393
        /* padding is represented using FC_STRUCTPAD* types, so presumably
         * this is left over in the format for historical purposes in MIDL
         * or rpcrt4. */
        print_file(file, 2, "0x0,\n");
2394
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
2395 2396 2397
                   reloff, reloff, absoff);
        *tfsoff += 4;
    }
2398
    else if (is_ptr(type) || is_conformant_array(type))
2399
    {
2400
        unsigned char fc = cont_is_complex ? FC_POINTER : FC_LONG;
2401
        print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
2402 2403
        *tfsoff += 1;
    }
2404
    else if (!write_base_type(file, type, tfsoff))
2405
        error("Unsupported member type %d\n", type_get_type(type));
2406 2407
}

2408
static void write_array_element_type(FILE *file, const attr_list_t *attrs, const type_t *type,
2409 2410
                                     int cont_is_complex, unsigned int *tfsoff)
{
2411
    type_t *elem = type_array_get_element_type(type);
2412 2413 2414

    if (!is_embedded_complex(elem) && is_ptr(elem))
    {
2415
        type_t *ref = type_pointer_get_ref_type(elem);
2416 2417 2418

        if (processed(ref))
        {
2419 2420
            write_nonsimple_pointer(file, NULL, elem, TYPE_CONTEXT_CONTAINER,
                                    ref->typestring_offset, tfsoff);
2421 2422
            return;
        }
2423
        if (cont_is_complex && is_string_type(attrs, elem))
2424 2425 2426 2427
        {
            write_string_tfs(file, NULL, elem, TYPE_CONTEXT_CONTAINER, NULL, tfsoff);
            return;
        }
2428 2429 2430
        if (!is_string_type(NULL, elem) &&
            (type_get_type(ref) == TYPE_BASIC || type_get_type(ref) == TYPE_ENUM))
        {
2431
            *tfsoff += write_simple_pointer(file, NULL, elem, TYPE_CONTEXT_CONTAINER);
2432 2433 2434
            return;
        }
    }
2435
    write_member_type(file, type, cont_is_complex, NULL, elem, NULL, tfsoff);
2436 2437
}

2438 2439 2440 2441
static void write_end(FILE *file, unsigned int *tfsoff)
{
    if (*tfsoff % 2 == 0)
    {
2442
        print_file(file, 2, "0x%x,\t/* FC_PAD */\n", FC_PAD);
2443 2444
        *tfsoff += 1;
    }
2445
    print_file(file, 2, "0x%x,\t/* FC_END */\n", FC_END);
2446 2447 2448
    *tfsoff += 1;
}

2449 2450 2451
static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
{
    unsigned int offset = 0;
2452
    var_list_t *fs = type_struct_get_fields(type);
2453 2454 2455 2456
    var_t *f;

    if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
    {
2457
        type_t *ft = f->declspec.type;
2458
        unsigned int size = field_memsize( ft, &offset );
2459
        if (type_get_type(ft) == TYPE_UNION && is_attr(f->attrs, ATTR_SWITCHIS))
2460
        {
2461
            short reloff;
2462
            unsigned int absoff = ft->typestring_offset;
2463 2464 2465
            if (is_attr(ft->attrs, ATTR_SWITCHTYPE))
                absoff += 8; /* we already have a corr descr, skip it */
            reloff = absoff - (*tfsoff + 6);
2466
            print_file(file, 0, "/* %d */\n", *tfsoff);
2467 2468
            print_file(file, 2, "0x%x,\t/* FC_NON_ENCAPSULATED_UNION */\n", FC_NON_ENCAPSULATED_UNION);
            print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", FC_LONG);
2469
            write_conf_or_var_desc(file, current_structure, offset, ft,
2470
                                   get_attrp(f->attrs, ATTR_SWITCHIS));
2471 2472
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
                       (unsigned short)reloff, reloff, absoff);
2473 2474
            *tfsoff += 8;
        }
2475
        offset += size;
2476 2477 2478
    }
}

2479 2480
static int write_pointer_description_offsets(
    FILE *file, const attr_list_t *attrs, type_t *type,
2481
    unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
2482 2483 2484 2485
    unsigned int *typestring_offset)
{
    int written = 0;

2486
    if ((is_ptr(type) && type_get_type(type_pointer_get_ref_type(type)) != TYPE_INTERFACE) ||
2487
        (is_array(type) && type_array_is_decl_as_ptr(type)))
2488 2489 2490
    {
        if (offset_in_memory && offset_in_buffer)
        {
2491
            unsigned int memsize;
2492

2493 2494 2495 2496 2497
            /* pointer instance
             *
             * note that MSDN states that for pointer layouts in structures,
             * this is a negative offset from the end of the structure, but
             * this statement is incorrect. all offsets are positive */
2498 2499
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Memory offset = %d */\n", (unsigned short)*offset_in_memory, *offset_in_memory);
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Buffer offset = %d */\n", (unsigned short)*offset_in_buffer, *offset_in_buffer);
2500

2501
            memsize = type_memsize(type);
2502 2503 2504 2505
            *offset_in_memory += memsize;
            /* increment these separately as in the case of conformant (varying)
             * structures these start at different values */
            *offset_in_buffer += memsize;
2506 2507 2508
        }
        *typestring_offset += 4;

2509 2510
        if (is_ptr(type))
        {
2511
            type_t *ref = type_pointer_get_ref_type(type);
2512 2513

            if (is_string_type(attrs, type))
2514
                write_string_tfs(file, attrs, type, TYPE_CONTEXT_CONTAINER, NULL, typestring_offset);
2515
            else if (processed(ref))
2516 2517
                write_nonsimple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER,
                                        ref->typestring_offset, typestring_offset);
2518
            else if (type_get_type(ref) == TYPE_BASIC || type_get_type(ref) == TYPE_ENUM)
2519
                *typestring_offset += write_simple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER);
2520 2521 2522
            else
                error("write_pointer_description_offsets: type format string unknown\n");
        }
2523
        else
2524 2525 2526 2527 2528 2529
        {
            unsigned int offset = type->typestring_offset;
            /* skip over the pointer that is written for strings, since a
             * pointer has to be written in-place here */
            if (is_string_type(attrs, type))
                offset += 4;
2530
            write_nonsimple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER, offset, typestring_offset);
2531
        }
2532 2533 2534 2535 2536

        return 1;
    }

    if (is_array(type))
2537
    {
2538
        return write_pointer_description_offsets(
2539
            file, attrs, type_array_get_element_type(type), offset_in_memory,
2540
            offset_in_buffer, typestring_offset);
2541 2542 2543 2544 2545
    }
    else if (is_non_complex_struct(type))
    {
        /* otherwise search for interesting fields to parse */
        const var_t *v;
2546
        LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
2547
        {
2548 2549
            if (offset_in_memory && offset_in_buffer)
            {
2550
                unsigned int padding;
2551
                unsigned int align = 0;
2552
                type_memsize_and_alignment(v->declspec.type, &align);
2553 2554 2555 2556
                padding = ROUNDING(*offset_in_memory, align);
                *offset_in_memory += padding;
                *offset_in_buffer += padding;
            }
2557
            written += write_pointer_description_offsets(
2558
                file, v->attrs, v->declspec.type, offset_in_memory, offset_in_buffer,
2559
                typestring_offset);
2560
        }
2561
    }
2562 2563
    else
    {
2564 2565
        if (offset_in_memory && offset_in_buffer)
        {
2566
            unsigned int memsize = type_memsize(type);
2567 2568 2569 2570 2571
            *offset_in_memory += memsize;
            /* increment these separately as in the case of conformant (varying)
             * structures these start at different values */
            *offset_in_buffer += memsize;
        }
2572
    }
2573

2574 2575 2576
    return written;
}

2577 2578 2579 2580 2581 2582 2583 2584 2585 2586
static int write_no_repeat_pointer_descriptions(
    FILE *file, const attr_list_t *attrs, type_t *type,
    unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
    unsigned int *typestring_offset)
{
    int written = 0;

    if (is_ptr(type) ||
        (is_conformant_array(type) && type_array_is_decl_as_ptr(type)))
    {
2587 2588
        print_file(file, 2, "0x%02x, /* FC_NO_REPEAT */\n", FC_NO_REPEAT);
        print_file(file, 2, "0x%02x, /* FC_PAD */\n", FC_PAD);
2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602
        *typestring_offset += 2;

        return write_pointer_description_offsets(file, attrs, type,
                       offset_in_memory, offset_in_buffer, typestring_offset);
    }

    if (is_non_complex_struct(type))
    {
        const var_t *v;
        LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
        {
            if (offset_in_memory && offset_in_buffer)
            {
                unsigned int padding;
2603
                unsigned int align = 0;
2604
                type_memsize_and_alignment(v->declspec.type, &align);
2605 2606 2607 2608 2609
                padding = ROUNDING(*offset_in_memory, align);
                *offset_in_memory += padding;
                *offset_in_buffer += padding;
            }
            written += write_no_repeat_pointer_descriptions(
2610
                file, v->attrs, v->declspec.type,
2611 2612 2613 2614 2615
                offset_in_memory, offset_in_buffer, typestring_offset);
        }
    }
    else
    {
2616
        unsigned int memsize = type_memsize(type);
2617 2618 2619 2620 2621 2622 2623 2624 2625
        *offset_in_memory += memsize;
        /* increment these separately as in the case of conformant (varying)
         * structures these start at different values */
        *offset_in_buffer += memsize;
    }

    return written;
}

2626 2627 2628 2629
/* Note: if file is NULL return value is number of pointers to write, else
 * it is the number of type format characters written */
static int write_fixed_array_pointer_descriptions(
    FILE *file, const attr_list_t *attrs, type_t *type,
2630
    unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
2631 2632 2633 2634
    unsigned int *typestring_offset)
{
    int pointer_count = 0;

2635 2636
    if (type_get_type(type) == TYPE_ARRAY &&
        !type_array_has_conformance(type) && !type_array_has_variance(type))
2637 2638 2639 2640 2641
    {
        unsigned int temp = 0;
        /* unfortunately, this needs to be done in two passes to avoid
         * writing out redundant FC_FIXED_REPEAT descriptions */
        pointer_count = write_pointer_description_offsets(
2642
            NULL, attrs, type_array_get_element_type(type), NULL, NULL, &temp);
2643 2644 2645
        if (pointer_count > 0)
        {
            unsigned int increment_size;
2646 2647
            unsigned int offset_of_array_pointer_mem = 0;
            unsigned int offset_of_array_pointer_buf = 0;
2648

2649
            increment_size = type_memsize(type_array_get_element_type(type));
2650

2651 2652
            print_file(file, 2, "0x%02x, /* FC_FIXED_REPEAT */\n", FC_FIXED_REPEAT);
            print_file(file, 2, "0x%02x, /* FC_PAD */\n", FC_PAD);
2653 2654 2655 2656
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Iterations = %d */\n", (unsigned short)type_array_get_dim(type), type_array_get_dim(type));
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Increment = %d */\n", (unsigned short)increment_size, increment_size);
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset to array = %d */\n", (unsigned short)*offset_in_memory, *offset_in_memory);
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Number of pointers = %d */\n", (unsigned short)pointer_count, pointer_count);
2657 2658 2659 2660 2661 2662 2663
            *typestring_offset += 10;

            pointer_count = write_pointer_description_offsets(
                file, attrs, type, &offset_of_array_pointer_mem,
                &offset_of_array_pointer_buf, typestring_offset);
        }
    }
2664
    else if (type_get_type(type) == TYPE_STRUCT)
2665 2666
    {
        const var_t *v;
2667
        LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
2668
        {
2669 2670
            if (offset_in_memory && offset_in_buffer)
            {
2671
                unsigned int padding;
2672
                unsigned int align = 0;
2673
                type_memsize_and_alignment(v->declspec.type, &align);
2674 2675 2676 2677
                padding = ROUNDING(*offset_in_memory, align);
                *offset_in_memory += padding;
                *offset_in_buffer += padding;
            }
2678
            pointer_count += write_fixed_array_pointer_descriptions(
2679
                file, v->attrs, v->declspec.type, offset_in_memory, offset_in_buffer,
2680 2681 2682 2683 2684
                typestring_offset);
        }
    }
    else
    {
2685 2686
        if (offset_in_memory && offset_in_buffer)
        {
2687
            unsigned int memsize;
2688
            memsize = type_memsize(type);
2689 2690 2691 2692 2693
            *offset_in_memory += memsize;
            /* increment these separately as in the case of conformant (varying)
             * structures these start at different values */
            *offset_in_buffer += memsize;
        }
2694 2695 2696 2697 2698 2699 2700 2701 2702
    }

    return pointer_count;
}

/* Note: if file is NULL return value is number of pointers to write, else
 * it is the number of type format characters written */
static int write_conformant_array_pointer_descriptions(
    FILE *file, const attr_list_t *attrs, type_t *type,
2703
    unsigned int offset_in_memory, unsigned int *typestring_offset)
2704 2705 2706
{
    int pointer_count = 0;

2707
    if (is_conformant_array(type) && !type_array_has_variance(type))
2708 2709 2710 2711 2712
    {
        unsigned int temp = 0;
        /* unfortunately, this needs to be done in two passes to avoid
         * writing out redundant FC_VARIABLE_REPEAT descriptions */
        pointer_count = write_pointer_description_offsets(
2713
            NULL, attrs, type_array_get_element_type(type), NULL, NULL, &temp);
2714 2715 2716
        if (pointer_count > 0)
        {
            unsigned int increment_size;
2717 2718
            unsigned int offset_of_array_pointer_mem = offset_in_memory;
            unsigned int offset_of_array_pointer_buf = offset_in_memory;
2719

2720
            increment_size = type_memsize(type_array_get_element_type(type));
2721 2722 2723 2724

            if (increment_size > USHRT_MAX)
                error("array size of %u bytes is too large\n", increment_size);

2725 2726
            print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", FC_VARIABLE_REPEAT);
            print_file(file, 2, "0x%02x, /* FC_FIXED_OFFSET */\n", FC_FIXED_OFFSET);
2727 2728 2729
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Increment = %d */\n", (unsigned short)increment_size, increment_size);
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset to array = %d */\n", (unsigned short)offset_in_memory, offset_in_memory);
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Number of pointers = %d */\n", (unsigned short)pointer_count, pointer_count);
2730 2731 2732
            *typestring_offset += 8;

            pointer_count = write_pointer_description_offsets(
2733
                file, attrs, type_array_get_element_type(type),
2734 2735
                &offset_of_array_pointer_mem, &offset_of_array_pointer_buf,
                typestring_offset);
2736 2737 2738 2739 2740 2741 2742 2743 2744 2745
        }
    }

    return pointer_count;
}

/* Note: if file is NULL return value is number of pointers to write, else
 * it is the number of type format characters written */
static int write_varying_array_pointer_descriptions(
    FILE *file, const attr_list_t *attrs, type_t *type,
2746
    unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
2747 2748 2749 2750
    unsigned int *typestring_offset)
{
    int pointer_count = 0;

2751
    if (is_array(type) && type_array_has_variance(type))
2752 2753 2754 2755 2756
    {
        unsigned int temp = 0;
        /* unfortunately, this needs to be done in two passes to avoid
         * writing out redundant FC_VARIABLE_REPEAT descriptions */
        pointer_count = write_pointer_description_offsets(
2757
            NULL, attrs, type_array_get_element_type(type), NULL, NULL, &temp);
2758 2759 2760 2761
        if (pointer_count > 0)
        {
            unsigned int increment_size;

2762
            increment_size = type_memsize(type_array_get_element_type(type));
2763 2764 2765 2766

            if (increment_size > USHRT_MAX)
                error("array size of %u bytes is too large\n", increment_size);

2767 2768
            print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", FC_VARIABLE_REPEAT);
            print_file(file, 2, "0x%02x, /* FC_VARIABLE_OFFSET */\n", FC_VARIABLE_OFFSET);
2769 2770 2771
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Increment = %d */\n", (unsigned short)increment_size, increment_size);
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset to array = %d */\n", (unsigned short)*offset_in_memory, *offset_in_memory);
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Number of pointers = %d */\n", (unsigned short)pointer_count, pointer_count);
2772 2773 2774
            *typestring_offset += 8;

            pointer_count = write_pointer_description_offsets(
2775
                file, attrs, type_array_get_element_type(type), offset_in_memory,
2776
                offset_in_buffer, typestring_offset);
2777 2778
        }
    }
2779
    else if (type_get_type(type) == TYPE_STRUCT)
2780 2781
    {
        const var_t *v;
2782
        LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
2783
        {
2784 2785
            if (offset_in_memory && offset_in_buffer)
            {
2786
                unsigned int align = 0, padding;
2787

2788
                if (is_array(v->declspec.type) && type_array_has_variance(v->declspec.type))
2789 2790 2791 2792 2793 2794
                {
                    *offset_in_buffer = ROUND_SIZE(*offset_in_buffer, 4);
                    /* skip over variance and offset in buffer */
                    *offset_in_buffer += 8;
                }

2795
                type_memsize_and_alignment(v->declspec.type, &align);
2796 2797 2798 2799
                padding = ROUNDING(*offset_in_memory, align);
                *offset_in_memory += padding;
                *offset_in_buffer += padding;
            }
2800
            pointer_count += write_varying_array_pointer_descriptions(
2801
                file, v->attrs, v->declspec.type, offset_in_memory, offset_in_buffer,
2802 2803 2804 2805 2806
                typestring_offset);
        }
    }
    else
    {
2807 2808
        if (offset_in_memory && offset_in_buffer)
        {
2809
            unsigned int memsize = type_memsize(type);
2810 2811 2812 2813 2814
            *offset_in_memory += memsize;
            /* increment these separately as in the case of conformant (varying)
             * structures these start at different values */
            *offset_in_buffer += memsize;
        }
2815 2816 2817 2818 2819
    }

    return pointer_count;
}

2820
static void write_pointer_description(FILE *file, const attr_list_t *attrs, type_t *type,
2821 2822
                                      unsigned int *typestring_offset)
{
2823 2824
    unsigned int offset_in_buffer;
    unsigned int offset_in_memory;
2825 2826 2827

    /* pass 1: search for single instance of a pointer (i.e. don't descend
     * into arrays) */
2828 2829 2830
    if (!is_array(type))
    {
        offset_in_memory = 0;
2831
        offset_in_buffer = 0;
2832
        write_no_repeat_pointer_descriptions(
2833
            file, NULL, type,
2834 2835
            &offset_in_memory, &offset_in_buffer, typestring_offset);
    }
2836 2837 2838

    /* pass 2: search for pointers in fixed arrays */
    offset_in_memory = 0;
2839
    offset_in_buffer = 0;
2840 2841 2842 2843 2844 2845
    write_fixed_array_pointer_descriptions(
        file, NULL, type,
        &offset_in_memory, &offset_in_buffer, typestring_offset);

    /* pass 3: search for pointers in conformant only arrays (but don't descend
     * into conformant varying or varying arrays) */
2846 2847
    if (is_conformant_array(type) &&
        (type_array_is_decl_as_ptr(type) || !current_structure))
2848
        write_conformant_array_pointer_descriptions(
2849
            file, attrs, type, 0, typestring_offset);
2850
    else if (type_get_type(type) == TYPE_STRUCT &&
2851
             get_struct_fc(type) == FC_CPSTRUCT)
2852
    {
2853
        type_t *carray = find_array_or_string_in_struct(type)->declspec.type;
2854 2855
        write_conformant_array_pointer_descriptions( file, NULL, carray,
                                                     type_memsize(type), typestring_offset);
2856
    }
2857

2858
    /* pass 4: search for pointers in varying arrays */
2859
    offset_in_memory = 0;
2860
    offset_in_buffer = 0;
2861 2862 2863
    write_varying_array_pointer_descriptions(
            file, NULL, type,
            &offset_in_memory, &offset_in_buffer, typestring_offset);
2864 2865
}

2866
static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
2867
                                     type_t *type, enum type_context context,
2868
                                     const char *name, unsigned int *typestring_offset)
2869
{
2870
    unsigned int start_offset;
2871
    unsigned char rtype;
2872
    type_t *elem_type;
2873
    int is_processed = processed(type);
2874

2875 2876
    start_offset = *typestring_offset;

2877
    if (is_declptr(type))
2878
    {
2879
        unsigned char flag = is_conformant_array(type) ? 0 : FC_SIMPLE_POINTER;
2880
        int pointer_type = get_pointer_fc_context(type, attrs, context);
2881
        if (!pointer_type)
2882
            pointer_type = FC_RP;
2883
        print_start_tfs_comment(file, type, *typestring_offset);
2884 2885 2886 2887 2888 2889 2890 2891 2892
        print_file(file, 2,"0x%x, 0x%x,\t/* %s%s */\n",
                   pointer_type, flag, string_of_type(pointer_type),
                   flag ? " [simple_pointer]" : "");
        *typestring_offset += 2;
        if (!flag)
        {
            print_file(file, 2, "NdrFcShort(0x2),\n");
            *typestring_offset += 2;
        }
2893
        is_processed = FALSE;
2894
    }
2895

2896
    if (is_array(type))
2897
        elem_type = type_array_get_element_type(type);
2898
    else
2899
        elem_type = type_pointer_get_ref_type(type);
2900

2901 2902 2903
    if (type_get_type(elem_type) == TYPE_POINTER && is_array(type))
        return write_array_tfs(file, attrs, type, name, typestring_offset);

2904 2905 2906 2907 2908 2909
    if (type_get_type(elem_type) != TYPE_BASIC)
    {
        error("write_string_tfs: Unimplemented for non-basic type %s\n", name);
        return start_offset;
    }

2910
    rtype = get_basic_fc(elem_type);
2911
    if ((rtype != FC_BYTE) && (rtype != FC_CHAR) && (rtype != FC_WCHAR))
Robert Shearman's avatar
Robert Shearman committed
2912
    {
2913
        error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
2914
        return start_offset;
Robert Shearman's avatar
Robert Shearman committed
2915 2916
    }

2917
    if (type_get_type(type) == TYPE_ARRAY && !type_array_has_conformance(type))
Robert Shearman's avatar
Robert Shearman committed
2918
    {
2919
        unsigned int dim = type_array_get_dim(type);
2920

2921 2922
        if (is_processed) return start_offset;

2923
        /* FIXME: multi-dimensional array */
2924 2925
        if (0xffffu < dim)
            error("array size for parameter %s exceeds %u bytes by %u bytes\n",
2926
                  name, 0xffffu, dim - 0xffffu);
Robert Shearman's avatar
Robert Shearman committed
2927

2928
        if (rtype == FC_WCHAR)
2929
            WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
2930 2931
        else
            WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
2932
        print_file(file, 2, "0x%x,\t/* FC_PAD */\n", FC_PAD);
2933
        *typestring_offset += 2;
Robert Shearman's avatar
Robert Shearman committed
2934

2935
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* %d */\n", (unsigned short)dim, dim);
2936
        *typestring_offset += 2;
Robert Shearman's avatar
Robert Shearman committed
2937

2938
        update_tfsoff(type, start_offset, file);
2939
        return start_offset;
Robert Shearman's avatar
Robert Shearman committed
2940
    }
2941
    else if (is_conformant_array(type))
Robert Shearman's avatar
Robert Shearman committed
2942
    {
2943
        if (rtype == FC_WCHAR)
2944
            WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
2945 2946
        else
            WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
2947
        print_file(file, 2, "0x%x,\t/* FC_STRING_SIZED */\n", FC_STRING_SIZED);
2948
        *typestring_offset += 2;
Robert Shearman's avatar
Robert Shearman committed
2949

2950
        *typestring_offset += write_conf_or_var_desc(
2951
            file, current_structure,
2952
            (!type_array_is_decl_as_ptr(type) && current_structure
2953
             ? type_memsize(current_structure)
2954
             : 0),
2955
            type, type_array_get_conformance(type));
2956

2957
        update_tfsoff(type, start_offset, file);
2958
        return start_offset;
Robert Shearman's avatar
Robert Shearman committed
2959 2960 2961
    }
    else
    {
2962 2963
        if (is_processed) return start_offset;

2964
        if (rtype == FC_WCHAR)
2965
            WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
2966 2967
        else
            WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
2968
        print_file(file, 2, "0x%x,\t/* FC_PAD */\n", FC_PAD);
2969
        *typestring_offset += 2;
Robert Shearman's avatar
Robert Shearman committed
2970

2971
        update_tfsoff(type, start_offset, file);
2972
        return start_offset;
Robert Shearman's avatar
Robert Shearman committed
2973
    }
2974 2975
}

2976 2977
static unsigned int write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
                                    const char *name, unsigned int *typestring_offset)
2978
{
2979 2980
    const expr_t *length_is = type_array_get_variance(type);
    const expr_t *size_is = type_array_get_conformance(type);
2981
    unsigned int align;
2982 2983
    unsigned int size;
    unsigned int start_offset;
2984
    unsigned char fc;
2985
    unsigned int baseoff
2986
        = !type_array_is_decl_as_ptr(type) && current_structure
2987
        ? type_memsize(current_structure)
2988 2989
        : 0;

2990 2991
    if (!is_string_type(attrs, type_array_get_element_type(type)))
        write_embedded_types(file, attrs, type_array_get_element_type(type), name, FALSE, typestring_offset);
Robert Shearman's avatar
Robert Shearman committed
2992

2993 2994
    size = type_memsize(is_conformant_array(type) ? type_array_get_element_type(type) : type);
    align = type_buffer_alignment(is_conformant_array(type) ? type_array_get_element_type(type) : type);
2995
    fc = get_array_fc(type);
2996

2997 2998
    start_offset = *typestring_offset;
    update_tfsoff(type, start_offset, file);
2999
    print_start_tfs_comment(file, type, start_offset);
3000
    print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
3001 3002
    print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
    *typestring_offset += 2;
3003

3004
    align = 0;
3005
    if (fc != FC_BOGUS_ARRAY)
3006
    {
3007
        if (fc == FC_LGFARRAY || fc == FC_LGVARRAY)
Robert Shearman's avatar
Robert Shearman committed
3008
        {
3009
            print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", size, size);
3010
            *typestring_offset += 4;
Robert Shearman's avatar
Robert Shearman committed
3011
        }
3012
        else
Robert Shearman's avatar
Robert Shearman committed
3013
        {
3014
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)size, size);
3015
            *typestring_offset += 2;
3016
        }
Robert Shearman's avatar
Robert Shearman committed
3017

3018 3019
        if (is_conformant_array(type))
            *typestring_offset
3020
                += write_conf_or_var_desc(file, current_structure, baseoff,
3021
                                          type, size_is);
Robert Shearman's avatar
Robert Shearman committed
3022

3023
        if (fc == FC_SMVARRAY || fc == FC_LGVARRAY)
Robert Shearman's avatar
Robert Shearman committed
3024
        {
3025
            unsigned int elsize = type_memsize(type_array_get_element_type(type));
3026
            unsigned int dim = type_array_get_dim(type);
3027

3028
            if (fc == FC_LGVARRAY)
3029
            {
3030
                print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", dim, dim);
3031
                *typestring_offset += 4;
3032
            }
3033
            else
3034
            {
3035
                print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)dim, dim);
3036
                *typestring_offset += 2;
3037
            }
Robert Shearman's avatar
Robert Shearman committed
3038

3039
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)elsize, elsize);
3040
            *typestring_offset += 2;
Robert Shearman's avatar
Robert Shearman committed
3041 3042
        }

3043 3044
        if (length_is)
            *typestring_offset
3045
                += write_conf_or_var_desc(file, current_structure, baseoff,
3046
                                          type, length_is);
3047

3048
        if (type_has_pointers(type_array_get_element_type(type)) &&
3049
            (type_array_is_decl_as_ptr(type) || !current_structure))
3050
        {
3051 3052
            print_file(file, 2, "0x%x,\t/* FC_PP */\n", FC_PP);
            print_file(file, 2, "0x%x,\t/* FC_PAD */\n", FC_PAD);
3053
            *typestring_offset += 2;
3054
            write_pointer_description(file, is_string_type(attrs, type) ? attrs : NULL, type, typestring_offset);
3055
            print_file(file, 2, "0x%x,\t/* FC_END */\n", FC_END);
3056
            *typestring_offset += 1;
Robert Shearman's avatar
Robert Shearman committed
3057
        }
3058

3059
        write_array_element_type(file, is_string_type(attrs, type) ? attrs : NULL, type, FALSE, typestring_offset);
3060
        write_end(file, typestring_offset);
Robert Shearman's avatar
Robert Shearman committed
3061
    }
3062
    else
3063
    {
3064
        unsigned int dim = size_is ? 0 : type_array_get_dim(type);
3065
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)dim, dim);
3066 3067 3068
        *typestring_offset += 2;
        *typestring_offset
            += write_conf_or_var_desc(file, current_structure, baseoff,
3069
                                      type, size_is);
3070 3071
        *typestring_offset
            += write_conf_or_var_desc(file, current_structure, baseoff,
3072
                                      type, length_is);
3073

3074
        write_array_element_type(file, is_string_type(attrs, type) ? attrs : NULL, type, TRUE, typestring_offset);
3075 3076
        write_end(file, typestring_offset);
    }
3077 3078

    return start_offset;
3079
}
3080

3081
static const var_t *find_array_or_string_in_struct(const type_t *type)
3082
{
3083
    const var_list_t *fields = type_struct_get_fields(type);
3084 3085 3086
    const var_t *last_field;
    const type_t *ft;

3087
    if (!fields || list_empty(fields))
3088 3089
        return NULL;

3090
    last_field = LIST_ENTRY( list_tail(fields), const var_t, entry );
3091
    ft = last_field->declspec.type;
3092

3093
    if (is_conformant_array(ft) && !type_array_is_decl_as_ptr(ft))
3094 3095
        return last_field;

3096
    if (type_get_type(ft) == TYPE_STRUCT)
3097
        return find_array_or_string_in_struct(ft);
3098 3099
    else
        return NULL;
3100 3101
}

3102
static void write_struct_members(FILE *file, const type_t *type,
3103 3104
                                 int is_complex, unsigned int *corroff,
                                 unsigned int *typestring_offset)
3105
{
3106
    const var_t *field;
3107
    unsigned short offset = 0;
3108
    unsigned int salign = 1;
3109
    int padding;
3110
    var_list_t *fields = type_struct_get_fields(type);
3111

3112
    if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
3113
    {
3114
        type_t *ft = field->declspec.type;
3115
        unsigned int align = 0;
3116
        unsigned int size = type_memsize_and_alignment(ft, &align);
3117
        align = clamp_align(align);
3118 3119
        if (salign < align) salign = align;

3120
        if (!is_conformant_array(ft) || type_array_is_decl_as_ptr(ft))
3121 3122 3123 3124 3125 3126
        {
            if ((align - 1) & offset)
            {
                unsigned char fc = 0;
                switch (align)
                {
3127
                case 2:
3128
                    fc = FC_ALIGNM2;
3129
                    break;
3130
                case 4:
3131
                    fc = FC_ALIGNM4;
3132 3133
                    break;
                case 8:
3134
                    fc = FC_ALIGNM8;
3135 3136
                    break;
                default:
3137
                    error("write_struct_members: cannot align type %d\n", type_get_type(ft));
3138 3139
                }
                print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
3140
                offset = ROUND_SIZE(offset, align);
3141 3142
                *typestring_offset += 1;
            }
3143
            write_member_type(file, type, is_complex, field->attrs, field->declspec.type, corroff,
3144
                              typestring_offset);
3145 3146
            offset += size;
        }
3147
    }
3148

3149
    padding = ROUNDING(offset, salign);
3150 3151 3152
    if (padding)
    {
        print_file(file, 2, "0x%x,\t/* FC_STRUCTPAD%d */\n",
3153
                   FC_STRUCTPAD1 + padding - 1,
3154 3155 3156 3157
                   padding);
        *typestring_offset += 1;
    }

3158
    write_end(file, typestring_offset);
3159 3160
}

3161 3162
static unsigned int write_struct_tfs(FILE *file, type_t *type,
                                     const char *name, unsigned int *tfsoff)
3163
{
3164
    const type_t *save_current_structure = current_structure;
3165
    unsigned int total_size;
3166
    const var_t *array;
3167
    unsigned int start_offset;
3168
    unsigned int align;
3169 3170
    unsigned int corroff;
    var_t *f;
3171
    unsigned char fc = get_struct_fc(type);
3172
    var_list_t *fields = type_struct_get_fields(type);
3173

3174 3175
    if (processed(type)) return type->typestring_offset;

3176
    guard_rec(type);
3177
    current_structure = type;
3178

3179 3180
    total_size = type_memsize(type);
    align = type_buffer_alignment(type);
3181 3182 3183
    if (total_size > USHRT_MAX)
        error("structure size for %s exceeds %d bytes by %d bytes\n",
              name, USHRT_MAX, total_size - USHRT_MAX);
3184

3185
    if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
3186
        write_embedded_types(file, f->attrs, f->declspec.type, f->name, FALSE, tfsoff);
3187

3188
    array = find_array_or_string_in_struct(type);
3189
    if (array && !processed(array->declspec.type))
3190
    {
3191 3192
        if(is_string_type(array->attrs, array->declspec.type))
            write_string_tfs(file, array->attrs, array->declspec.type, TYPE_CONTEXT_CONTAINER, array->name, tfsoff);
3193
        else
3194
            write_array_tfs(file, array->attrs, array->declspec.type, array->name, tfsoff);
3195
    }
3196 3197 3198

    corroff = *tfsoff;
    write_descriptors(file, type, tfsoff);
3199

3200 3201
    start_offset = *tfsoff;
    update_tfsoff(type, start_offset, file);
3202
    print_start_tfs_comment(file, type, start_offset);
3203
    print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
3204
    print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
3205
    print_file(file, 2, "NdrFcShort(0x%hx),\t/* %d */\n", (unsigned short)total_size, total_size);
3206
    *tfsoff += 4;
3207

3208 3209
    if (array)
    {
3210
        unsigned int absoff = array->declspec.type->typestring_offset;
3211
        short reloff = absoff - *tfsoff;
3212
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
3213 3214 3215
                   reloff, reloff, absoff);
        *tfsoff += 2;
    }
3216
    else if (fc == FC_BOGUS_STRUCT)
3217 3218 3219 3220
    {
        print_file(file, 2, "NdrFcShort(0x0),\n");
        *tfsoff += 2;
    }
3221

3222
    if (fc == FC_BOGUS_STRUCT)
3223
    {
3224 3225 3226
        /* On the sizing pass, type->ptrdesc may be zero, but it's ok as
           nothing is written to file yet.  On the actual writing pass,
           this will have been updated.  */
3227
        unsigned int absoff = type->ptrdesc ? type->ptrdesc : *tfsoff;
3228 3229
        int reloff = absoff - *tfsoff;
        assert( reloff >= 0 );
3230
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %d (%u) */\n",
3231
                   (unsigned short)reloff, reloff, absoff);
3232 3233
        *tfsoff += 2;
    }
3234 3235 3236
    else if ((fc == FC_PSTRUCT) ||
             (fc == FC_CPSTRUCT) ||
             (fc == FC_CVSTRUCT && type_has_pointers(type)))
3237
    {
3238 3239
        print_file(file, 2, "0x%x,\t/* FC_PP */\n", FC_PP);
        print_file(file, 2, "0x%x,\t/* FC_PAD */\n", FC_PAD);
3240
        *tfsoff += 2;
3241
        write_pointer_description(file, NULL, type, tfsoff);
3242
        print_file(file, 2, "0x%x,\t/* FC_END */\n", FC_END);
3243 3244
        *tfsoff += 1;
    }
3245

3246
    write_struct_members(file, type, fc == FC_BOGUS_STRUCT, &corroff,
3247
                         tfsoff);
3248

3249
    if (fc == FC_BOGUS_STRUCT)
3250 3251 3252
    {
        const var_t *f;

3253
        type->ptrdesc = *tfsoff;
3254
        if (fields) LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry)
3255
        {
3256
            type_t *ft = f->declspec.type;
3257
            switch (typegen_detect_type(ft, f->attrs, TDT_IGNORE_STRINGS))
3258
            {
3259
            case TGT_POINTER:
3260
                if (is_string_type(f->attrs, ft))
3261
                    write_string_tfs(file, f->attrs, ft, TYPE_CONTEXT_CONTAINER, f->name, tfsoff);
3262
                else
3263
                    write_pointer_tfs(file, f->attrs, ft,
3264
                                      type_pointer_get_ref_type(ft)->typestring_offset,
3265
                                      TYPE_CONTEXT_CONTAINER, tfsoff);
3266 3267 3268 3269 3270
                break;
            case TGT_ARRAY:
                if (type_array_is_decl_as_ptr(ft))
                {
                    unsigned int offset;
3271

3272
                    print_file(file, 0, "/* %d */\n", *tfsoff);
3273

3274 3275 3276 3277 3278
                    offset = ft->typestring_offset;
                    /* skip over the pointer that is written for strings, since a
                     * pointer has to be written in-place here */
                    if (is_string_type(f->attrs, ft))
                        offset += 4;
3279
                    write_nonsimple_pointer(file, f->attrs, ft, TYPE_CONTEXT_CONTAINER, offset, tfsoff);
3280 3281 3282 3283
                }
                break;
            default:
                break;
3284
            }
3285
        }
3286 3287
        if (type->ptrdesc == *tfsoff)
            type->ptrdesc = 0;
3288 3289
    }

3290
    current_structure = save_current_structure;
3291
    return start_offset;
3292 3293
}

3294
static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
3295
{
3296 3297 3298 3299
    if (t == NULL)
    {
        print_file(file, 2, "NdrFcShort(0x0),\t/* No type */\n");
    }
3300
    else
3301
    {
3302 3303 3304 3305
        if (type_get_type(t) == TYPE_BASIC || type_get_type(t) == TYPE_ENUM)
        {
            unsigned char fc;
            if (type_get_type(t) == TYPE_BASIC)
3306
                fc = get_basic_fc(t);
3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319
            else
                fc = get_enum_fc(t);
            print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n",
                       fc, string_of_type(fc));
        }
        else if (t->typestring_offset)
        {
            short reloff = t->typestring_offset - *tfsoff;
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %d (%d) */\n",
                       reloff, reloff, t->typestring_offset);
        }
        else
            error("write_branch_type: type unimplemented %d\n", type_get_type(t));
3320 3321 3322 3323 3324
    }

    *tfsoff += 2;
}

3325 3326
static unsigned int write_union_tfs(FILE *file, const attr_list_t *attrs,
                                    type_t *type, unsigned int *tfsoff)
3327
{
3328
    unsigned int start_offset;
3329
    unsigned int size;
3330
    var_list_t *fields;
3331
    unsigned int nbranch = 0;
3332 3333
    type_t *deftype = NULL;
    short nodeftype = 0xffff;
3334
    unsigned int dummy;
3335 3336
    var_t *f;

3337 3338 3339 3340
    if (processed(type) &&
        (type_get_type(type) == TYPE_ENCAPSULATED_UNION || !is_attr(type->attrs, ATTR_SWITCHTYPE)))
        return type->typestring_offset;

3341 3342
    guard_rec(type);

3343
    fields = type_union_get_cases(type);
3344

3345 3346
    size = union_memsize(fields, &dummy);

3347 3348 3349 3350 3351
    if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
    {
        expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
        if (cases)
            nbranch += list_count(cases);
3352 3353
        if (f->declspec.type)
            write_embedded_types(file, f->attrs, f->declspec.type, f->name, TRUE, tfsoff);
3354 3355 3356
    }

    start_offset = *tfsoff;
3357
    update_tfsoff(type, start_offset, file);
3358
    print_start_tfs_comment(file, type, start_offset);
3359
    if (type_get_type(type) == TYPE_ENCAPSULATED_UNION)
3360
    {
3361
        const var_t *sv = type_union_get_switch_value(type);
3362
        const type_t *st = sv->declspec.type;
3363
        unsigned int align = 0;
3364
        unsigned char fc;
3365

3366
        if (type_get_type(st) == TYPE_BASIC)
3367
        {
3368 3369
            fc = get_basic_fc(st);
            switch (fc)
3370
            {
3371 3372 3373 3374 3375 3376 3377 3378 3379
            case FC_CHAR:
            case FC_SMALL:
            case FC_BYTE:
            case FC_USMALL:
            case FC_WCHAR:
            case FC_SHORT:
            case FC_USHORT:
            case FC_LONG:
            case FC_ULONG:
3380 3381 3382 3383 3384
                break;
            default:
                fc = 0;
                error("union switch type must be an integer, char, or enum\n");
            }
3385
        }
3386 3387 3388 3389 3390
        else if (type_get_type(st) == TYPE_ENUM)
            fc = get_enum_fc(st);
        else
            error("union switch type must be an integer, char, or enum\n");

3391 3392 3393
        type_memsize_and_alignment(st, &align);
        if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
        {
3394 3395
            if (f->declspec.type)
                type_memsize_and_alignment(f->declspec.type, &align);
3396 3397
        }

3398
        print_file(file, 2, "0x%x,\t/* FC_ENCAPSULATED_UNION */\n", FC_ENCAPSULATED_UNION);
3399
        print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
3400
                   (align << 4) | fc, string_of_type(fc));
3401
        *tfsoff += 2;
3402
    }
3403 3404
    else if (is_attr(type->attrs, ATTR_SWITCHTYPE))
    {
3405
        const expr_t *switch_is = get_attrp(attrs, ATTR_SWITCHIS);
3406
        const type_t *st = get_attrp(type->attrs, ATTR_SWITCHTYPE);
3407
        unsigned char fc;
3408

3409
        if (type_get_type(st) == TYPE_BASIC)
3410
        {
3411 3412
            fc = get_basic_fc(st);
            switch (fc)
3413
            {
3414 3415 3416 3417 3418 3419 3420 3421 3422
            case FC_CHAR:
            case FC_SMALL:
            case FC_USMALL:
            case FC_SHORT:
            case FC_USHORT:
            case FC_LONG:
            case FC_ULONG:
            case FC_ENUM16:
            case FC_ENUM32:
3423 3424 3425 3426 3427
                break;
            default:
                fc = 0;
                error("union switch type must be an integer, char, or enum\n");
            }
3428
        }
3429 3430 3431 3432 3433
        else if (type_get_type(st) == TYPE_ENUM)
            fc = get_enum_fc(st);
        else
            error("union switch type must be an integer, char, or enum\n");

3434
        print_file(file, 2, "0x%x,\t/* FC_NON_ENCAPSULATED_UNION */\n", FC_NON_ENCAPSULATED_UNION);
3435 3436 3437
        print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
                   fc, string_of_type(fc));
        *tfsoff += 2;
3438
        *tfsoff += write_conf_or_var_desc(file, current_structure, 0, st, switch_is );
3439 3440
        print_file(file, 2, "NdrFcShort(0x2),\t/* Offset= 2 (%u) */\n", *tfsoff + 2);
        *tfsoff += 2;
3441
        print_file(file, 0, "/* %u */\n", *tfsoff);
3442 3443
    }

3444 3445
    print_file(file, 2, "NdrFcShort(0x%hx),\t/* %d */\n", (unsigned short)size, size);
    print_file(file, 2, "NdrFcShort(0x%hx),\t/* %d */\n", (unsigned short)nbranch, nbranch);
3446 3447 3448 3449
    *tfsoff += 4;

    if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
    {
3450
        type_t *ft = f->declspec.type;
3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462
        expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
        int deflt = is_attr(f->attrs, ATTR_DEFAULT);
        expr_t *c;

        if (cases == NULL && !deflt)
            error("union field %s with neither case nor default attribute\n", f->name);

        if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry)
        {
            /* MIDL doesn't check for duplicate cases, even though that seems
               like a reasonable thing to do, it just dumps them to the TFS
               like we're going to do here.  */
3463
            print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483
            *tfsoff += 4;
            write_branch_type(file, ft, tfsoff);
        }

        /* MIDL allows multiple default branches, even though that seems
           illogical, it just chooses the last one, which is what we will
           do.  */
        if (deflt)
        {
            deftype = ft;
            nodeftype = 0;
        }
    }

    if (deftype)
    {
        write_branch_type(file, deftype, tfsoff);
    }
    else
    {
3484
        print_file(file, 2, "NdrFcShort(0x%hx),\n", nodeftype);
3485 3486 3487 3488
        *tfsoff += 2;
    }

    return start_offset;
3489 3490
}

3491 3492
static unsigned int write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
                                 unsigned int *typeformat_offset)
3493
{
3494 3495
    unsigned int i;
    unsigned int start_offset = *typeformat_offset;
3496
    expr_t *iid = get_attrp(attrs, ATTR_IIDIS);
3497

3498 3499
    if (!iid && processed(type)) return type->typestring_offset;

3500
    print_start_tfs_comment(file, type, start_offset);
3501
    update_tfsoff(type, start_offset, file);
3502

3503 3504 3505 3506
    if (iid)
    {
        print_file(file, 2, "0x2f,  /* FC_IP */\n");
        print_file(file, 2, "0x5c,  /* FC_PAD */\n");
3507
        *typeformat_offset
3508
            += write_conf_or_var_desc(file, current_structure, 0, type, iid) + 2;
3509 3510 3511
    }
    else
    {
3512
        const type_t *base = is_ptr(type) ? type_pointer_get_ref_type(type) : type;
3513
        const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
3514

3515 3516
        if (! uuid)
            error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
3517

3518 3519
        print_file(file, 2, "0x2f,\t/* FC_IP */\n");
        print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
3520
        print_file(file, 2, "NdrFcLong(0x%08x),\n", uuid->Data1);
3521 3522 3523 3524 3525 3526 3527
        print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2);
        print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3);
        for (i = 0; i < 8; ++i)
            print_file(file, 2, "0x%02x,\n", uuid->Data4[i]);

        if (file)
            fprintf(file, "\n");
3528

3529 3530
        *typeformat_offset += 18;
    }
3531 3532 3533
    return start_offset;
}

3534 3535
static unsigned int write_contexthandle_tfs(FILE *file,
                                            const attr_list_t *attrs,
3536
                                            type_t *type,
3537
                                            enum type_context context,
3538
                                            unsigned int *typeformat_offset)
3539
{
3540
    unsigned int start_offset = *typeformat_offset;
3541
    unsigned char flags = get_contexthandle_flags( current_iface, attrs, type, context == TYPE_CONTEXT_RETVAL );
3542

3543
    print_start_tfs_comment(file, type, start_offset);
3544

3545
    if (flags & 0x80)  /* via ptr */
3546
    {
3547
        int pointer_type = get_pointer_fc( type, attrs, context == TYPE_CONTEXT_TOPLEVELPARAM );
3548
        if (!pointer_type) pointer_type = FC_RP;
3549 3550 3551 3552
        *typeformat_offset += 4;
        print_file(file, 2,"0x%x, 0x0,\t/* %s */\n", pointer_type, string_of_type(pointer_type) );
        print_file(file, 2, "NdrFcShort(0x2),\t /* Offset= 2 (%u) */\n", *typeformat_offset);
        print_file(file, 0, "/* %2u */\n", *typeformat_offset);
3553
    }
3554

3555
    print_file(file, 2, "0x%02x,\t/* FC_BIND_CONTEXT */\n", FC_BIND_CONTEXT);
3556
    print_file(file, 2, "0x%x,\t/* Context flags: ", flags);
3557
    if (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL)
3558
        print_file(file, 0, "can't be null, ");
3559
    if (flags & NDR_CONTEXT_HANDLE_SERIALIZE)
3560
        print_file(file, 0, "serialize, ");
3561
    if (flags & NDR_CONTEXT_HANDLE_NOSERIALIZE)
3562
        print_file(file, 0, "no serialize, ");
3563
    if (flags & NDR_STRICT_CONTEXT_HANDLE)
3564
        print_file(file, 0, "strict, ");
3565
    if (flags & HANDLE_PARAM_IS_RETURN)
3566
        print_file(file, 0, "return, ");
3567
    if (flags & HANDLE_PARAM_IS_OUT)
3568
        print_file(file, 0, "out, ");
3569
    if (flags & HANDLE_PARAM_IS_IN)
3570
        print_file(file, 0, "in, ");
3571
    if (flags & HANDLE_PARAM_IS_VIA_PTR)
3572 3573
        print_file(file, 0, "via ptr, ");
    print_file(file, 0, "*/\n");
3574
    print_file(file, 2, "0x%x,\t/* rundown routine */\n", get_context_handle_offset( type ));
3575 3576 3577
    print_file(file, 2, "0, /* FIXME: param num */\n");
    *typeformat_offset += 4;

3578
    update_tfsoff( type, start_offset, file );
3579 3580 3581
    return start_offset;
}

3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599
static unsigned int write_range_tfs(FILE *file, const attr_list_t *attrs,
                                    type_t *type, expr_list_t *range_list,
                                    unsigned int *typeformat_offset)
{
    unsigned char fc;
    unsigned int start_offset = *typeformat_offset;
    const expr_t *range_min = LIST_ENTRY(list_head(range_list), const expr_t, entry);
    const expr_t *range_max = LIST_ENTRY(list_next(range_list, list_head(range_list)), const expr_t, entry);

    if (type_get_type(type) == TYPE_BASIC)
        fc = get_basic_fc(type);
    else
        fc = get_enum_fc(type);

    /* fc must fit in lower 4-bits of 8-bit field below */
    assert(fc <= 0xf);

    print_file(file, 0, "/* %u */\n", *typeformat_offset);
3600
    print_file(file, 2, "0x%x,\t/* FC_RANGE */\n", FC_RANGE);
3601
    print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
3602 3603
    print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", range_min->cval, range_min->cval);
    print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", range_max->cval, range_max->cval);
3604
    update_tfsoff( type, start_offset, file );
3605 3606 3607 3608 3609
    *typeformat_offset += 10;

    return start_offset;
}

3610 3611
static unsigned int write_type_tfs(FILE *file, const attr_list_t *attrs,
                                   type_t *type, const char *name,
3612 3613
                                   enum type_context context,
                                   unsigned int *typeformat_offset)
3614
{
3615
    unsigned int offset;
3616

3617
    switch (typegen_detect_type(type, attrs, TDT_ALL_TYPES))
3618
    {
3619 3620
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
3621
        return write_contexthandle_tfs(file, attrs, type, context, typeformat_offset);
3622
    case TGT_USER_TYPE:
3623
        return write_user_tfs(file, type, typeformat_offset);
3624
    case TGT_STRING:
3625
        return write_string_tfs(file, attrs, type, context, name, typeformat_offset);
3626
    case TGT_ARRAY:
3627
    {
3628
        unsigned int off;
3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639
        /* conformant and pointer arrays are handled specially */
        if ((context != TYPE_CONTEXT_CONTAINER &&
             context != TYPE_CONTEXT_CONTAINER_NO_POINTERS) ||
            !is_conformant_array(type) || type_array_is_decl_as_ptr(type))
            off = write_array_tfs(file, attrs, type, name, typeformat_offset);
        else
            off = 0;
        if (context != TYPE_CONTEXT_CONTAINER &&
            context != TYPE_CONTEXT_CONTAINER_NO_POINTERS)
        {
            int ptr_type;
3640
            ptr_type = get_pointer_fc_context(type, attrs, context);
3641 3642
            if (type_array_is_decl_as_ptr(type)
                    || (ptr_type != FC_RP && context == TYPE_CONTEXT_TOPLEVELPARAM))
3643 3644 3645 3646 3647 3648 3649 3650 3651
            {
                unsigned int absoff = type->typestring_offset;
                short reloff = absoff - (*typeformat_offset + 2);
                off = *typeformat_offset;
                print_file(file, 0, "/* %d */\n", off);
                print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
                           string_of_type(ptr_type));
                print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
                           reloff, reloff, absoff);
3652
                if (ptr_type != FC_RP) update_tfsoff( type, off, file );
3653 3654
                *typeformat_offset += 4;
            }
3655
            type_array_set_ptr_tfsoff(type, off);
3656 3657 3658
        }
        return off;
    }
3659
    case TGT_STRUCT:
3660
        return write_struct_tfs(file, type, name, typeformat_offset);
3661
    case TGT_UNION:
3662
        return write_union_tfs(file, attrs, type, typeformat_offset);
3663 3664 3665 3666
    case TGT_ENUM:
    case TGT_BASIC:
        /* nothing to do */
        return 0;
3667 3668
    case TGT_RANGE:
    {
3669
        expr_list_t *range_list = get_attrp(attrs, ATTR_RANGE);
3670 3671
        if (!range_list)
            range_list = get_aliaschain_attrp(type, ATTR_RANGE);
3672
        return write_range_tfs(file, attrs, type, range_list, typeformat_offset);
3673
    }
3674
    case TGT_IFACE_POINTER:
3675
        return write_ip_tfs(file, attrs, type, typeformat_offset);
3676
    case TGT_POINTER:
3677 3678
    {
        enum type_context ref_context;
3679
        type_t *ref = type_pointer_get_ref_type(type);
3680

3681 3682 3683 3684
        if (context == TYPE_CONTEXT_TOPLEVELPARAM)
            ref_context = TYPE_CONTEXT_PARAM;
        else if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
            ref_context = TYPE_CONTEXT_CONTAINER;
3685
        else
3686
            ref_context = context;
3687

3688
        if (is_string_type(attrs, ref))
3689 3690 3691 3692
        {
            if (context != TYPE_CONTEXT_CONTAINER_NO_POINTERS)
                write_pointer_tfs(file, attrs, type, *typeformat_offset + 4, context, typeformat_offset);

3693
            offset = write_type_tfs(file, attrs, ref, name, ref_context, typeformat_offset);
3694 3695 3696 3697 3698
            if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
                return 0;
            return offset;
        }

3699
        offset = write_type_tfs( file, attrs, type_pointer_get_ref_type(type), name,
3700
                                 ref_context, typeformat_offset);
3701 3702
        if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
            return 0;
3703
        return write_pointer_tfs(file, attrs, type, offset, context, typeformat_offset);
3704
    }
3705 3706 3707
    case TGT_INVALID:
        break;
    }
3708
    error("invalid type %s for var %s\n", type->name, name);
3709
    return 0;
3710 3711
}

3712
static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
3713
                                const char *name, int write_ptr, unsigned int *tfsoff)
3714
{
3715
    return write_type_tfs(file, attrs, type, name, write_ptr ? TYPE_CONTEXT_CONTAINER : TYPE_CONTEXT_CONTAINER_NO_POINTERS, tfsoff);
3716 3717
}

3718
static void process_tfs_iface(type_t *iface, FILE *file, int indent, unsigned int *offset)
3719
{
3720 3721
    const statement_list_t *stmts = type_iface_get_stmts(iface);
    const statement_t *stmt;
3722
    var_t *var;
3723

3724
    current_iface = iface;
3725
    if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, statement_t, entry )
3726
    {
3727 3728 3729 3730 3731 3732
        switch(stmt->type)
        {
        case STMT_DECLARATION:
        {
            const var_t *func = stmt->u.var;

3733 3734
            if(stmt->u.var->declspec.stgclass != STG_NONE
               || type_get_type_detect_alias(stmt->u.var->declspec.type) != TYPE_FUNCTION)
3735
                continue;
3736

3737 3738
            current_func = func;
            if (is_local(func->attrs)) continue;
3739

3740 3741 3742
            var = type_function_get_retval(func->declspec.type);
            if (!is_void(var->declspec.type))
                var->typestring_offset = write_type_tfs( file, var->attrs, var->declspec.type, func->name,
3743
                                                         TYPE_CONTEXT_RETVAL, offset);
3744

3745 3746
            if (type_function_get_args(func->declspec.type))
                LIST_FOR_EACH_ENTRY( var, type_function_get_args(func->declspec.type), var_t, entry )
3747
                    var->typestring_offset = write_type_tfs( file, var->attrs, var->declspec.type, var->name,
3748 3749 3750 3751 3752 3753
                                                             TYPE_CONTEXT_TOPLEVELPARAM, offset );
            break;

        }
        case STMT_TYPEDEF:
        {
3754 3755
            typeref_t *ref;
            if (stmt->u.type_list) LIST_FOR_EACH_ENTRY(ref, stmt->u.type_list, typeref_t, entry)
3756
            {
3757 3758 3759 3760
                if (is_attr(ref->type->attrs, ATTR_ENCODE)
                    || is_attr(ref->type->attrs, ATTR_DECODE))
                    ref->type->typestring_offset = write_type_tfs( file,
                            ref->type->attrs, ref->type, ref->type->name,
3761 3762 3763 3764 3765 3766 3767
                            TYPE_CONTEXT_CONTAINER, offset);
            }
            break;
        }
        default:
            break;
        }
3768
    }
3769 3770
}

3771
static unsigned int process_tfs(FILE *file, const statement_list_t *stmts, type_pred_t pred)
3772 3773
{
    unsigned int typeformat_offset = 2;
3774 3775
    for_each_iface(stmts, process_tfs_iface, pred, file, 0, &typeformat_offset);
    return typeformat_offset + 1;
3776 3777 3778
}


3779
void write_typeformatstring(FILE *file, const statement_list_t *stmts, type_pred_t pred)
3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790
{
    int indent = 0;

    print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
    print_file(file, indent, "{\n");
    indent++;
    print_file(file, indent, "0,\n");
    print_file(file, indent, "{\n");
    indent++;
    print_file(file, indent, "NdrFcShort(0x0),\n");

3791
    set_all_tfswrite(TRUE);
3792
    process_tfs(file, stmts, pred);
3793

3794 3795 3796 3797 3798 3799 3800 3801
    print_file(file, indent, "0x0\n");
    indent--;
    print_file(file, indent, "}\n");
    indent--;
    print_file(file, indent, "};\n");
    print_file(file, indent, "\n");
}

3802
static unsigned int get_required_buffer_size_type(
3803
    const type_t *type, const char *name, const attr_list_t *attrs, int toplevel_param, unsigned int *alignment)
3804
{
3805
    *alignment = 0;
3806
    switch (typegen_detect_type(type, NULL, TDT_IGNORE_RANGES))
3807 3808
    {
    case TGT_USER_TYPE:
3809
    {
3810
        const char *uname = NULL;
3811
        const type_t *utype = get_user_type(type, &uname);
3812
        return get_required_buffer_size_type(utype, uname, NULL, FALSE, alignment);
3813
    }
3814
    case TGT_BASIC:
3815
        switch (get_basic_fc(type))
3816
        {
3817 3818 3819 3820
        case FC_BYTE:
        case FC_CHAR:
        case FC_USMALL:
        case FC_SMALL:
3821 3822
            *alignment = 4;
            return 1;
3823

3824 3825 3826
        case FC_WCHAR:
        case FC_USHORT:
        case FC_SHORT:
3827 3828
            *alignment = 4;
            return 2;
3829

3830 3831 3832 3833
        case FC_ULONG:
        case FC_LONG:
        case FC_FLOAT:
        case FC_ERROR_STATUS_T:
3834 3835
            *alignment = 4;
            return 4;
3836

3837 3838
        case FC_HYPER:
        case FC_DOUBLE:
3839 3840
            *alignment = 8;
            return 8;
3841

3842 3843
        case FC_INT3264:
        case FC_UINT3264:
3844 3845 3846 3847
            assert( pointer_size );
            *alignment = pointer_size;
            return pointer_size;

3848 3849
        case FC_IGNORE:
        case FC_BIND_PRIMITIVE:
3850
            return 0;
3851

3852 3853
        default:
            error("get_required_buffer_size: unknown basic type 0x%02x\n",
3854
                  get_basic_fc(type));
3855 3856 3857
            return 0;
        }
        break;
3858

3859 3860 3861
    case TGT_ENUM:
        switch (get_enum_fc(type))
        {
3862
        case FC_ENUM32:
3863 3864
            *alignment = 4;
            return 4;
3865
        case FC_ENUM16:
3866 3867 3868 3869
            *alignment = 4;
            return 2;
        }
        break;
3870

3871
    case TGT_STRUCT:
3872
        if (get_struct_fc(type) == FC_STRUCT)
3873 3874 3875 3876 3877
        {
            if (!type_struct_get_fields(type)) return 0;
            return fields_memsize(type_struct_get_fields(type), alignment);
        }
        break;
3878

3879 3880
    case TGT_POINTER:
        {
3881
            unsigned int size, align;
3882
            const type_t *ref = type_pointer_get_ref_type(type);
3883
            if (is_string_type( attrs, ref )) break;
3884
            if (!(size = get_required_buffer_size_type( ref, name, NULL, FALSE, &align ))) break;
3885
            if (get_pointer_fc(type, attrs, toplevel_param) != FC_RP)
3886 3887 3888 3889 3890 3891
            {
                size += 4 + align;
                align = 4;
            }
            *alignment = align;
            return size;
3892
        }
3893

3894
    case TGT_ARRAY:
3895
        switch (get_array_fc(type))
3896
        {
3897 3898 3899 3900 3901
        case FC_SMFARRAY:
        case FC_LGFARRAY:
            return type_array_get_dim(type) *
                get_required_buffer_size_type(type_array_get_element_type(type), name,
                                              NULL, FALSE, alignment);
3902 3903
        }
        break;
3904

3905 3906
    default:
        break;
3907
    }
3908
    return 0;
3909 3910
}

3911
static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
3912
{
3913 3914 3915 3916 3917 3918
    int in_attr = is_attr(var->attrs, ATTR_IN);
    int out_attr = is_attr(var->attrs, ATTR_OUT);

    if (!in_attr && !out_attr)
        in_attr = 1;

3919 3920
    *alignment = 0;

3921 3922 3923 3924
    if ((pass == PASS_IN && in_attr) || (pass == PASS_OUT && out_attr) ||
        pass == PASS_RETURN)
    {
        if (is_ptrchain_attr(var, ATTR_CONTEXTHANDLE))
3925 3926 3927 3928 3929
        {
            *alignment = 4;
            return 20;
        }

3930 3931
        if (!is_string_type(var->attrs, var->declspec.type))
            return get_required_buffer_size_type(var->declspec.type, var->name,
3932
                                                 var->attrs, TRUE, alignment);
3933
    }
3934
    return 0;
3935 3936
}

3937
static unsigned int get_function_buffer_size( const var_t *func, enum pass pass )
3938 3939 3940 3941
{
    const var_t *var;
    unsigned int total_size = 0, alignment;

3942
    if (type_function_get_args(func->declspec.type))
3943
    {
3944
        LIST_FOR_EACH_ENTRY( var, type_function_get_args(func->declspec.type), const var_t, entry )
3945 3946 3947 3948 3949 3950
        {
            total_size += get_required_buffer_size(var, &alignment, pass);
            total_size += alignment;
        }
    }

3951
    if (pass == PASS_OUT && !is_void(type_function_get_rettype(func->declspec.type)))
3952
    {
3953
        var_t v = *func;
3954
        v.declspec.type = type_function_get_rettype(func->declspec.type);
3955
        total_size += get_required_buffer_size(&v, &alignment, PASS_RETURN);
3956 3957 3958 3959 3960
        total_size += alignment;
    }
    return total_size;
}

3961
static void print_phase_function(FILE *file, int indent, const char *type,
3962
                                 const char *local_var_prefix, enum remoting_phase phase,
3963
                                 const var_t *var, unsigned int type_offset)
3964
{
3965
    const char *function;
3966 3967 3968
    switch (phase)
    {
    case PHASE_BUFFERSIZE:
3969 3970
        function = "BufferSize";
        break;
3971
    case PHASE_MARSHAL:
3972 3973
        function = "Marshall";
        break;
3974
    case PHASE_UNMARSHAL:
3975 3976
        function = "Unmarshall";
        break;
3977
    case PHASE_FREE:
3978 3979 3980 3981 3982
        function = "Free";
        break;
    default:
        assert(0);
        return;
3983
    }
3984 3985 3986

    print_file(file, indent, "Ndr%s%s(\n", type, function);
    indent++;
3987
    print_file(file, indent, "&__frame->_StubMsg,\n");
3988
    print_file(file, indent, "%s%s%s%s%s,\n",
3989
               (phase == PHASE_UNMARSHAL) ? "(unsigned char **)" : "(unsigned char *)",
3990
               (phase == PHASE_UNMARSHAL || decl_indirect(var->declspec.type)) ? "&" : "",
3991
               local_var_prefix,
3992
               (phase == PHASE_UNMARSHAL && decl_indirect(var->declspec.type)) ? "_p_" : "",
3993
               var->name);
3994 3995 3996 3997 3998
    print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
               type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
    if (phase == PHASE_UNMARSHAL)
        print_file(file, indent, "0);\n");
    indent--;
3999 4000
}

4001 4002
void print_phase_basetype(FILE *file, int indent, const char *local_var_prefix,
                          enum remoting_phase phase, enum pass pass, const var_t *var,
4003 4004
                          const char *varname)
{
4005
    type_t *type = var->declspec.type;
4006 4007 4008 4009 4010 4011
    unsigned int alignment = 0;

    /* no work to do for other phases, buffer sizing is done elsewhere */
    if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
        return;

4012 4013 4014 4015
    if (type_get_type(type) == TYPE_ENUM ||
        (type_get_type(type) == TYPE_BASIC &&
         type_basic_get_type(type) == TYPE_BASIC_INT3264 &&
         pointer_size != 4))
4016
    {
4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032
        unsigned char fc;

        if (type_get_type(type) == TYPE_ENUM)
            fc = get_enum_fc(type);
        else
            fc = get_basic_fc(type);

        if (phase == PHASE_MARSHAL)
            print_file(file, indent, "NdrSimpleTypeMarshall(\n");
        else
            print_file(file, indent, "NdrSimpleTypeUnmarshall(\n");
        print_file(file, indent+1, "&__frame->_StubMsg,\n");
        print_file(file, indent+1, "(unsigned char *)&%s%s,\n",
                   local_var_prefix,
                   var->name);
        print_file(file, indent+1, "0x%02x /* %s */);\n", fc, string_of_type(fc));
4033 4034 4035
    }
    else
    {
4036 4037 4038
        const decl_spec_t *ref = is_ptr(type) ? type_pointer_get_ref(type) : &var->declspec;

        switch (get_basic_fc(ref->type))
4039
        {
4040 4041 4042 4043
        case FC_BYTE:
        case FC_CHAR:
        case FC_SMALL:
        case FC_USMALL:
4044 4045 4046
            alignment = 1;
            break;

4047 4048 4049
        case FC_WCHAR:
        case FC_USHORT:
        case FC_SHORT:
4050 4051 4052
            alignment = 2;
            break;

4053 4054 4055 4056
        case FC_ULONG:
        case FC_LONG:
        case FC_FLOAT:
        case FC_ERROR_STATUS_T:
4057
        /* pointer_size must be 4 if we got here in these two cases */
4058 4059
        case FC_INT3264:
        case FC_UINT3264:
4060 4061 4062
            alignment = 4;
            break;

4063 4064
        case FC_HYPER:
        case FC_DOUBLE:
4065 4066 4067
            alignment = 8;
            break;

4068 4069
        case FC_IGNORE:
        case FC_BIND_PRIMITIVE:
4070 4071 4072 4073
            /* no marshalling needed */
            return;

        default:
4074
            error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n",
4075
                  var->name, get_basic_fc(ref->type));
4076
        }
4077

4078
        if (phase == PHASE_MARSHAL && alignment > 1)
4079 4080 4081
            print_file(file, indent, "MIDL_memset(__frame->_StubMsg.Buffer, 0, (0x%x - (ULONG_PTR)__frame->_StubMsg.Buffer) & 0x%x);\n", alignment, alignment - 1);
        print_file(file, indent, "__frame->_StubMsg.Buffer = (unsigned char *)(((ULONG_PTR)__frame->_StubMsg.Buffer + %u) & ~0x%x);\n",
                    alignment - 1, alignment - 1);
4082

4083 4084 4085
        if (phase == PHASE_MARSHAL)
        {
            print_file(file, indent, "*(");
4086
            write_type_decl(file, ref, NULL);
4087 4088 4089 4090 4091 4092 4093 4094 4095 4096
            if (is_ptr(type))
                fprintf(file, " *)__frame->_StubMsg.Buffer = *");
            else
                fprintf(file, " *)__frame->_StubMsg.Buffer = ");
            fprintf(file, "%s%s", local_var_prefix, varname);
            fprintf(file, ";\n");
        }
        else if (phase == PHASE_UNMARSHAL)
        {
            print_file(file, indent, "if (__frame->_StubMsg.Buffer + sizeof(");
4097
            write_type_decl(file, ref, NULL);
4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108
            fprintf(file, ") > __frame->_StubMsg.BufferEnd)\n");
            print_file(file, indent, "{\n");
            print_file(file, indent + 1, "RpcRaiseException(RPC_X_BAD_STUB_DATA);\n");
            print_file(file, indent, "}\n");
            print_file(file, indent, "%s%s%s",
                       (pass == PASS_IN || pass == PASS_RETURN) ? "" : "*",
                       local_var_prefix, varname);
            if (pass == PASS_IN && is_ptr(type))
                fprintf(file, " = (");
            else
                fprintf(file, " = *(");
4109
            write_type_decl(file, ref, NULL);
4110 4111 4112 4113
            fprintf(file, " *)__frame->_StubMsg.Buffer;\n");
        }

        print_file(file, indent, "__frame->_StubMsg.Buffer += sizeof(");
4114
        write_type_decl(file, ref, NULL);
4115
        fprintf(file, ");\n");
4116 4117 4118
    }
}

4119 4120
/* returns whether the MaxCount, Offset or ActualCount members need to be
 * filled in for the specified phase */
4121
static inline int is_conformance_needed_for_phase(enum remoting_phase phase)
4122 4123 4124 4125
{
    return (phase != PHASE_UNMARSHAL);
}

4126 4127 4128 4129
expr_t *get_size_is_expr(const type_t *t, const char *name)
{
    expr_t *x = NULL;

4130
    for ( ; is_array(t); t = type_array_get_element_type(t))
4131 4132
        if (type_array_has_conformance(t) &&
            type_array_get_conformance(t)->type != EXPR_VOID)
4133 4134
        {
            if (!x)
4135
                x = type_array_get_conformance(t);
4136 4137 4138 4139 4140 4141 4142 4143 4144
            else
                error("%s: multidimensional conformant"
                      " arrays not supported at the top level\n",
                      name);
        }

    return x;
}

4145 4146
void write_parameter_conf_or_var_exprs(FILE *file, int indent, const char *local_var_prefix,
                                       enum remoting_phase phase, const var_t *var, int valid_variance)
4147
{
4148
    const type_t *type = var->declspec.type;
4149 4150 4151
    /* get fundamental type for the argument */
    for (;;)
    {
4152
        switch (typegen_detect_type(type, var->attrs, TDT_IGNORE_STRINGS|TDT_IGNORE_RANGES))
4153
        {
4154 4155
        case TGT_ARRAY:
            if (is_conformance_needed_for_phase(phase))
4156
            {
4157 4158
                if (type_array_has_conformance(type) &&
                    type_array_get_conformance(type)->type != EXPR_VOID)
4159
                {
4160
                    print_file(file, indent, "__frame->_StubMsg.MaxCount = (ULONG_PTR)");
4161
                    write_expr(file, type_array_get_conformance(type), 1, 1, NULL, NULL, local_var_prefix);
4162 4163
                    fprintf(file, ";\n\n");
                }
4164
                if (type_array_has_variance(type))
4165
                {
4166
                    print_file(file, indent, "__frame->_StubMsg.Offset = 0;\n"); /* FIXME */
4167 4168 4169 4170 4171 4172 4173 4174
                    if (valid_variance)
                    {
                        print_file(file, indent, "__frame->_StubMsg.ActualCount = (ULONG_PTR)");
                        write_expr(file, type_array_get_variance(type), 1, 1, NULL, NULL, local_var_prefix);
                        fprintf(file, ";\n\n");
                    }
                    else
                        print_file(file, indent, "__frame->_StubMsg.ActualCount = __frame->_StubMsg.MaxCount;\n\n");
4175 4176 4177
                }
            }
            break;
4178 4179 4180
        case TGT_UNION:
            if (type_get_type(type) == TYPE_UNION &&
                is_conformance_needed_for_phase(phase))
4181
            {
4182
                print_file(file, indent, "__frame->_StubMsg.MaxCount = (ULONG_PTR)");
4183
                write_expr(file, get_attrp(var->attrs, ATTR_SWITCHIS), 1, 1, NULL, NULL, local_var_prefix);
4184 4185 4186
                fprintf(file, ";\n\n");
            }
            break;
4187
        case TGT_IFACE_POINTER:
4188 4189 4190 4191 4192
        {
            expr_t *iid;

            if (is_conformance_needed_for_phase(phase) && (iid = get_attrp( var->attrs, ATTR_IIDIS )))
            {
4193
                print_file( file, indent, "__frame->_StubMsg.MaxCount = (ULONG_PTR) " );
4194
                write_expr( file, iid, 1, 1, NULL, NULL, local_var_prefix );
4195 4196 4197 4198
                fprintf( file, ";\n\n" );
            }
            break;
        }
4199
        case TGT_POINTER:
4200
            type = type_pointer_get_ref_type(type);
4201 4202 4203 4204 4205 4206 4207 4208 4209 4210
            continue;
        case TGT_INVALID:
        case TGT_USER_TYPE:
        case TGT_CTXT_HANDLE:
        case TGT_CTXT_HANDLE_POINTER:
        case TGT_STRING:
        case TGT_BASIC:
        case TGT_ENUM:
        case TGT_STRUCT:
        case TGT_RANGE:
4211
            break;
4212 4213
        }
        break;
4214 4215 4216
    }
}

4217
static void write_remoting_arg(FILE *file, int indent, const var_t *func, const char *local_var_prefix,
4218
                               enum pass pass, enum remoting_phase phase, const var_t *var)
4219
{
4220
    int in_attr, out_attr, pointer_type;
4221
    const char *type_str = NULL;
4222
    const type_t *type = var->declspec.type;
4223
    unsigned int alignment, start_offset = type->typestring_offset;
4224

4225 4226 4227 4228
    if (is_ptr(type) || is_array(type))
        pointer_type = get_pointer_fc(type, var->attrs, pass != PASS_RETURN);
    else
        pointer_type = 0;
4229

4230 4231 4232 4233
    in_attr = is_attr(var->attrs, ATTR_IN);
    out_attr = is_attr(var->attrs, ATTR_OUT);
    if (!in_attr && !out_attr)
        in_attr = 1;
4234

4235
    if (phase != PHASE_FREE)
4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246
        switch (pass)
        {
        case PASS_IN:
            if (!in_attr) return;
            break;
        case PASS_OUT:
            if (!out_attr) return;
            break;
        case PASS_RETURN:
            break;
        }
4247

4248 4249
    if (phase == PHASE_BUFFERSIZE && get_required_buffer_size( var, &alignment, pass )) return;

4250
    write_parameter_conf_or_var_exprs(file, indent, local_var_prefix, phase, var, TRUE);
4251

4252
    switch (typegen_detect_type(type, var->attrs, TDT_ALL_TYPES))
4253
    {
4254 4255
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
4256
        if (phase == PHASE_MARSHAL)
4257
        {
4258 4259
            if (pass == PASS_IN)
            {
4260 4261 4262
                /* if the context_handle attribute appears in the chain of types
                 * without pointers being followed, then the context handle must
                 * be direct, otherwise it is a pointer */
4263
                const char *ch_ptr = is_aliaschain_attr(type, ATTR_CONTEXTHANDLE) ? "" : "*";
4264
                print_file(file, indent, "NdrClientContextMarshall(\n");
4265
                print_file(file, indent + 1, "&__frame->_StubMsg,\n");
4266 4267
                print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s%s,\n", ch_ptr, local_var_prefix,
                           var->name);
4268 4269 4270 4271
                print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
            }
            else
            {
4272
                print_file(file, indent, "NdrServerContextNewMarshall(\n");
4273
                print_file(file, indent + 1, "&__frame->_StubMsg,\n");
4274
                print_file(file, indent + 1, "(NDR_SCONTEXT)%s%s,\n", local_var_prefix, var->name);
4275
                print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown,\n", get_context_handle_type_name(var->declspec.type));
4276
                print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
4277 4278 4279 4280
            }
        }
        else if (phase == PHASE_UNMARSHAL)
        {
4281
            if (pass == PASS_OUT || pass == PASS_RETURN)
4282
            {
4283
                if (!in_attr)
4284
                    print_file(file, indent, "*%s%s = 0;\n", local_var_prefix, var->name);
4285
                print_file(file, indent, "NdrClientContextUnmarshall(\n");
4286
                print_file(file, indent + 1, "&__frame->_StubMsg,\n");
4287 4288
                print_file(file, indent + 1, "(NDR_CCONTEXT *)%s%s%s,\n",
                           pass == PASS_RETURN ? "&" : "", local_var_prefix, var->name);
4289
                print_file(file, indent + 1, "__frame->_Handle);\n");
4290 4291
            }
            else
4292
            {
4293
                print_file(file, indent, "%s%s = NdrServerContextNewUnmarshall(\n", local_var_prefix, var->name);
4294
                print_file(file, indent + 1, "&__frame->_StubMsg,\n");
4295 4296
                print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
            }
4297
        }
4298 4299
        break;
    case TGT_USER_TYPE:
4300
        print_phase_function(file, indent, "UserMarshal", local_var_prefix, phase, var, start_offset);
4301 4302
        break;
    case TGT_STRING:
4303
        if (phase == PHASE_FREE || pass == PASS_RETURN ||
4304
            pointer_type != FC_RP)
4305
        {
4306 4307 4308 4309 4310
            /* strings returned are assumed to be global and hence don't
             * need freeing */
            if (is_declptr(type) && !(phase == PHASE_FREE && pass == PASS_RETURN))
                print_phase_function(file, indent, "Pointer", local_var_prefix,
                                     phase, var, start_offset);
4311
            else if (pointer_type == FC_RP && phase == PHASE_FREE &&
4312 4313 4314 4315
                !in_attr && is_conformant_array(type))
            {
                print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
                indent++;
4316
                print_file(file, indent, "__frame->_StubMsg.pfnFree((void*)%s%s);\n", local_var_prefix, var->name);
4317
            }
4318
        }
4319
        else
4320
        {
4321 4322 4323 4324 4325 4326 4327 4328 4329
            unsigned int real_start_offset = start_offset;
            /* skip over pointer description straight to string description */
            if (is_declptr(type))
            {
                if (is_conformant_array(type))
                    real_start_offset += 4;
                else
                    real_start_offset += 2;
            }
4330 4331 4332
            if (is_array(type) && !is_conformant_array(type))
                print_phase_function(file, indent, "NonConformantString",
                                     local_var_prefix, phase, var,
4333
                                     real_start_offset);
4334
            else
4335
                print_phase_function(file, indent, "ConformantString", local_var_prefix,
4336
                                     phase, var, real_start_offset);
4337
        }
4338 4339
        break;
    case TGT_ARRAY:
4340 4341
    {
        unsigned char tc = get_array_fc(type);
4342
        const char *array_type = NULL;
4343

4344 4345 4346 4347 4348 4349 4350
        /* We already have the size_is expression since it's at the
           top level, but do checks for multidimensional conformant
           arrays.  When we handle them, we'll need to extend this
           function to return a list, and then we'll actually use
           the return value.  */
        get_size_is_expr(type, var->name);

4351
        switch (tc)
4352
        {
4353 4354
        case FC_SMFARRAY:
        case FC_LGFARRAY:
4355 4356
            array_type = "FixedArray";
            break;
4357 4358
        case FC_SMVARRAY:
        case FC_LGVARRAY:
4359
            array_type = "VaryingArray";
4360
            break;
4361
        case FC_CARRAY:
4362
            array_type = "ConformantArray";
4363
            break;
4364
        case FC_CVARRAY:
4365 4366
            array_type = "ConformantVaryingArray";
            break;
4367
        case FC_BOGUS_ARRAY:
4368 4369
            array_type = "ComplexArray";
            break;
4370
        }
4371

4372
        if (pointer_type != FC_RP) array_type = "Pointer";
4373

4374
        if (phase == PHASE_FREE && pointer_type == FC_RP)
4375
        {
4376
            /* these are all unmarshalled by allocating memory */
4377 4378 4379 4380
            if (tc == FC_BOGUS_ARRAY ||
                tc == FC_CVARRAY ||
                ((tc == FC_SMVARRAY || tc == FC_LGVARRAY) && in_attr) ||
                (tc == FC_CARRAY && !in_attr))
4381
            {
4382
                if (type_array_is_decl_as_ptr(type) && type_array_get_ptr_tfsoff(type))
4383 4384
                {
                    print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var,
4385
                                         type_array_get_ptr_tfsoff(type));
4386 4387 4388
                    break;
                }
                print_phase_function(file, indent, array_type, local_var_prefix, phase, var, start_offset);
4389
                print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
4390
                indent++;
4391
                print_file(file, indent, "__frame->_StubMsg.pfnFree((void*)%s%s);\n", local_var_prefix, var->name);
4392
                break;
4393 4394
            }
        }
4395
        print_phase_function(file, indent, array_type, local_var_prefix, phase, var, start_offset);
4396
        break;
4397
    }
4398
    case TGT_BASIC:
4399
        print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
4400
        break;
4401
    case TGT_ENUM:
4402
        print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
4403
        break;
4404
    case TGT_RANGE:
4405
        print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418
        /* Note: this goes beyond what MIDL does - it only supports arguments
         * with the [range] attribute in Oicf mode */
        if (phase == PHASE_UNMARSHAL)
        {
            const expr_t *range_min;
            const expr_t *range_max;
            expr_list_t *range_list = get_attrp(var->attrs, ATTR_RANGE);
            if (!range_list)
                range_list = get_aliaschain_attrp(type, ATTR_RANGE);
            range_min = LIST_ENTRY(list_head(range_list), const expr_t, entry);
            range_max = LIST_ENTRY(list_next(range_list, list_head(range_list)), const expr_t, entry);

            print_file(file, indent, "if ((%s%s < (", local_var_prefix, var->name);
4419
            write_type_decl(file, &var->declspec, NULL);
4420
            fprintf(file, ")0x%x) || (%s%s > (", range_min->cval, local_var_prefix, var->name);
4421
            write_type_decl(file, &var->declspec, NULL);
4422
            fprintf(file, ")0x%x))\n", range_max->cval);
4423 4424 4425 4426 4427
            print_file(file, indent, "{\n");
            print_file(file, indent+1, "RpcRaiseException(RPC_S_INVALID_BOUND);\n");
            print_file(file, indent, "}\n");
        }
        break;
4428
    case TGT_STRUCT:
4429
        switch (get_struct_fc(type))
4430
        {
4431
        case FC_STRUCT:
4432 4433 4434
            if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
                print_phase_function(file, indent, "SimpleStruct", local_var_prefix, phase, var, start_offset);
            break;
4435
        case FC_PSTRUCT:
4436
            print_phase_function(file, indent, "SimpleStruct", local_var_prefix, phase, var, start_offset);
4437
            break;
4438 4439
        case FC_CSTRUCT:
        case FC_CPSTRUCT:
4440
            print_phase_function(file, indent, "ConformantStruct", local_var_prefix, phase, var, start_offset);
4441
            break;
4442
        case FC_CVSTRUCT:
4443
            print_phase_function(file, indent, "ConformantVaryingStruct", local_var_prefix, phase, var, start_offset);
4444
            break;
4445
        case FC_BOGUS_STRUCT:
4446
            print_phase_function(file, indent, "ComplexStruct", local_var_prefix, phase, var, start_offset);
4447 4448
            break;
        default:
4449
            error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, get_struct_fc(type));
4450
        }
4451
        break;
4452
    case TGT_UNION:
4453 4454 4455
    {
        const char *union_type = NULL;

4456
        if (type_get_type(type) == TYPE_UNION)
4457
            union_type = "NonEncapsulatedUnion";
4458
        else if (type_get_type(type) == TYPE_ENCAPSULATED_UNION)
4459 4460 4461 4462
            union_type = "EncapsulatedUnion";

        print_phase_function(file, indent, union_type, local_var_prefix,
                             phase, var, start_offset);
4463
        break;
4464
    }
4465
    case TGT_POINTER:
4466
    {
4467
        const type_t *ref = type_pointer_get_ref_type(type);
4468
        if (pointer_type == FC_RP) switch (typegen_detect_type(ref, NULL, TDT_ALL_TYPES))
4469
        {
4470
        case TGT_BASIC:
4471
            print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
4472
            break;
4473
        case TGT_ENUM:
4474 4475 4476 4477 4478 4479
            /* base types have known sizes, so don't need a sizing pass
             * and don't have any memory to free and so don't need a
             * freeing pass */
            if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
                print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
            break;
4480
        case TGT_STRUCT:
4481
            switch (get_struct_fc(ref))
4482
            {
4483
            case FC_STRUCT:
4484 4485 4486 4487
                /* simple structs have known sizes, so don't need a sizing
                 * pass and don't have any memory to free and so don't
                 * need a freeing pass */
                if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
4488
                    type_str = "SimpleStruct";
4489 4490 4491 4492
                else if (phase == PHASE_FREE && pass == PASS_RETURN)
                {
                    print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
                    indent++;
4493
                    print_file(file, indent, "__frame->_StubMsg.pfnFree((void*)%s%s);\n", local_var_prefix, var->name);
4494 4495
                    indent--;
                }
4496
                break;
4497
            case FC_PSTRUCT:
4498
                type_str = "SimpleStruct";
4499
                break;
4500 4501
            case FC_CSTRUCT:
            case FC_CPSTRUCT:
4502
                type_str = "ConformantStruct";
4503
                break;
4504
            case FC_CVSTRUCT:
4505
                type_str = "ConformantVaryingStruct";
4506
                break;
4507
            case FC_BOGUS_STRUCT:
4508
                type_str = "ComplexStruct";
4509 4510
                break;
            default:
4511
                error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, get_struct_fc(ref));
4512 4513
            }

4514
            if (type_str)
4515 4516
            {
                if (phase == PHASE_FREE)
4517
                    type_str = "Pointer";
4518 4519
                else
                    start_offset = ref->typestring_offset;
4520
                print_phase_function(file, indent, type_str, local_var_prefix, phase, var, start_offset);
4521
            }
4522
            break;
4523
        case TGT_UNION:
4524
            if (phase == PHASE_FREE)
4525
                type_str = "Pointer";
4526 4527
            else
            {
4528
                if (type_get_type(ref) == TYPE_UNION)
4529
                    type_str = "NonEncapsulatedUnion";
4530
                else if (type_get_type(ref) == TYPE_ENCAPSULATED_UNION)
4531
                    type_str = "EncapsulatedUnion";
4532 4533 4534 4535

                start_offset = ref->typestring_offset;
            }

4536
            print_phase_function(file, indent, type_str, local_var_prefix,
4537
                                 phase, var, start_offset);
4538
            break;
4539 4540 4541 4542 4543 4544 4545 4546 4547 4548
        case TGT_USER_TYPE:
            if (phase != PHASE_FREE)
            {
                type_str = "UserMarshal";
                start_offset = ref->typestring_offset;
            }
            else type_str = "Pointer";

            print_phase_function(file, indent, type_str, local_var_prefix, phase, var, start_offset);
            break;
4549 4550 4551 4552 4553 4554 4555
        case TGT_STRING:
        case TGT_POINTER:
        case TGT_ARRAY:
        case TGT_RANGE:
        case TGT_IFACE_POINTER:
        case TGT_CTXT_HANDLE:
        case TGT_CTXT_HANDLE_POINTER:
4556 4557
            print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
            break;
4558
        case TGT_INVALID:
4559 4560
            assert(0);
            break;
4561
        }
4562 4563 4564 4565
        else
            print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
        break;
    }
4566 4567 4568 4569
    case TGT_IFACE_POINTER:
        print_phase_function(file, indent, "InterfacePointer", local_var_prefix, phase, var, start_offset);
        break;
    case TGT_INVALID:
4570 4571
        assert(0);
        break;
4572 4573 4574 4575
    }
    fprintf(file, "\n");
}

4576
void write_remoting_arguments(FILE *file, int indent, const var_t *func, const char *local_var_prefix,
4577 4578 4579 4580 4581
                              enum pass pass, enum remoting_phase phase)
{
    if (phase == PHASE_BUFFERSIZE && pass != PASS_RETURN)
    {
        unsigned int size = get_function_buffer_size( func, pass );
4582
        print_file(file, indent, "__frame->_StubMsg.BufferLength = %u;\n", size);
4583 4584 4585 4586
    }

    if (pass == PASS_RETURN)
    {
4587
        write_remoting_arg( file, indent, func, local_var_prefix, pass, phase,
4588
                            type_function_get_retval(func->declspec.type) );
4589 4590 4591 4592
    }
    else
    {
        const var_t *var;
4593
        if (!type_function_get_args(func->declspec.type))
4594
            return;
4595
        LIST_FOR_EACH_ENTRY( var, type_function_get_args(func->declspec.type), const var_t, entry )
4596
            write_remoting_arg( file, indent, func, local_var_prefix, pass, phase, var );
4597 4598
    }
}
4599 4600


4601
unsigned int get_size_procformatstring_func(const type_t *iface, const var_t *func)
4602
{
4603
    unsigned int offset = 0;
4604
    write_procformatstring_func( NULL, 0, iface, func, &offset, 0 );
4605
    return offset;
4606 4607
}

4608
static void get_size_procformatstring_iface(type_t *iface, FILE *file, int indent, unsigned int *size)
4609
{
4610
    const statement_t *stmt;
4611
    STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
4612
    {
4613 4614 4615
        const var_t *func = stmt->u.var;
        if (!is_local(func->attrs))
            *size += get_size_procformatstring_func( iface, func );
4616
    }
4617 4618 4619 4620 4621 4622
}

unsigned int get_size_procformatstring(const statement_list_t *stmts, type_pred_t pred)
{
    unsigned int size = 1;
    for_each_iface(stmts, get_size_procformatstring_iface, pred, NULL, 0, &size);
4623 4624 4625
    return size;
}

4626
unsigned int get_size_typeformatstring(const statement_list_t *stmts, type_pred_t pred)
4627
{
4628
    set_all_tfswrite(FALSE);
4629
    return process_tfs(NULL, stmts, pred);
4630 4631
}

4632
void declare_stub_args( FILE *file, int indent, const var_t *func )
4633 4634 4635
{
    int in_attr, out_attr;
    int i = 0;
4636
    var_t *var = type_function_get_retval(func->declspec.type);
4637

4638
    /* declare return value */
4639
    if (!is_void(var->declspec.type))
4640
    {
4641
        if (is_context_handle(var->declspec.type))
4642 4643 4644 4645
            print_file(file, indent, "NDR_SCONTEXT %s;\n", var->name);
        else
        {
            print_file(file, indent, "%s", "");
4646
            write_type_decl(file, &var->declspec, var->name);
4647 4648
            fprintf(file, ";\n");
        }
4649 4650
    }

4651
    if (!type_function_get_args(func->declspec.type))
4652 4653
        return;

4654
    LIST_FOR_EACH_ENTRY( var, type_function_get_args(func->declspec.type), var_t, entry )
4655 4656 4657 4658 4659 4660
    {
        in_attr = is_attr(var->attrs, ATTR_IN);
        out_attr = is_attr(var->attrs, ATTR_OUT);
        if (!out_attr && !in_attr)
            in_attr = 1;

4661
        if (is_context_handle(var->declspec.type))
4662 4663
            print_file(file, indent, "NDR_SCONTEXT %s;\n", var->name);
        else
4664
        {
4665
            if (!in_attr && !is_conformant_array(var->declspec.type))
4666
            {
4667
                const decl_spec_t *type_to_print;
4668
                char name[16];
4669
                print_file(file, indent, "%s", "");
4670 4671
                if (type_get_type(var->declspec.type) == TYPE_ARRAY &&
                    !type_array_is_decl_as_ptr(var->declspec.type))
4672
                    type_to_print = &var->declspec;
4673
                else
4674
                    type_to_print = type_pointer_get_ref(var->declspec.type);
4675 4676
                sprintf(name, "_W%u", i++);
                write_type_decl(file, type_to_print, name);
4677 4678 4679
                fprintf(file, ";\n");
            }

4680
            print_file(file, indent, "%s", "");
4681
            write_type_decl_left(file, &var->declspec);
4682
            fprintf(file, " ");
4683 4684
            if (type_get_type(var->declspec.type) == TYPE_ARRAY &&
                !type_array_is_decl_as_ptr(var->declspec.type)) {
4685
                fprintf(file, "(*%s)", var->name);
4686
            } else
4687
                fprintf(file, "%s", var->name);
4688
            write_type_right(file, var->declspec.type, FALSE);
4689
            fprintf(file, ";\n");
4690

4691
            if (decl_indirect(var->declspec.type))
4692
                print_file(file, indent, "void *_p_%s;\n", var->name);
4693
        }
4694 4695 4696 4697
    }
}


4698
void assign_stub_out_args( FILE *file, int indent, const var_t *func, const char *local_var_prefix )
4699 4700 4701 4702
{
    int in_attr, out_attr;
    int i = 0, sep = 0;
    const var_t *var;
4703
    type_t *ref;
4704

4705
    if (!type_function_get_args(func->declspec.type))
4706 4707
        return;

4708
    LIST_FOR_EACH_ENTRY( var, type_function_get_args(func->declspec.type), const var_t, entry )
4709 4710 4711 4712 4713 4714 4715 4716
    {
        in_attr = is_attr(var->attrs, ATTR_IN);
        out_attr = is_attr(var->attrs, ATTR_OUT);
        if (!out_attr && !in_attr)
            in_attr = 1;

        if (!in_attr)
        {
4717
            print_file(file, indent, "%s%s", local_var_prefix, var->name);
4718

4719
            switch (typegen_detect_type(var->declspec.type, var->attrs, TDT_IGNORE_STRINGS))
4720
            {
4721
            case TGT_CTXT_HANDLE_POINTER:
4722
                fprintf(file, " = NdrContextHandleInitialize(\n");
4723
                print_file(file, indent + 1, "&__frame->_StubMsg,\n");
4724
                print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n",
4725
                           var->typestring_offset);
4726 4727
                break;
            case TGT_ARRAY:
4728
                if (type_array_has_conformance(var->declspec.type))
4729
                {
4730
                    unsigned int size;
4731
                    type_t *type;
4732 4733

                    fprintf(file, " = NdrAllocate(&__frame->_StubMsg, ");
4734
                    for (type = var->declspec.type;
4735
                         is_array(type) && type_array_has_conformance(type);
4736
                         type = type_array_get_element_type(type))
4737 4738 4739 4740 4741 4742 4743 4744 4745
                    {
                        write_expr(file, type_array_get_conformance(type), TRUE,
                                   TRUE, NULL, NULL, local_var_prefix);
                        fprintf(file, " * ");
                    }
                    size = type_memsize(type);
                    fprintf(file, "%u);\n", size);

                    print_file(file, indent, "memset(%s%s, 0, ", local_var_prefix, var->name);
4746
                    for (type = var->declspec.type;
4747
                         is_array(type) && type_array_has_conformance(type);
4748
                         type = type_array_get_element_type(type))
4749 4750 4751 4752 4753
                    {
                        write_expr(file, type_array_get_conformance(type), TRUE,
                                   TRUE, NULL, NULL, local_var_prefix);
                        fprintf(file, " * ");
                    }
4754
                    size = type_memsize(type);
4755
                    fprintf(file, "%u);\n", size);
4756
                }
4757 4758 4759 4760
                else
                    fprintf(file, " = &%s_W%u;\n", local_var_prefix, i++);
                break;
            case TGT_POINTER:
4761
                fprintf(file, " = &%s_W%u;\n", local_var_prefix, i);
4762
                ref = type_pointer_get_ref_type(var->declspec.type);
4763
                switch (typegen_detect_type(ref, var->attrs, TDT_IGNORE_STRINGS))
4764 4765 4766 4767
                {
                case TGT_BASIC:
                case TGT_ENUM:
                case TGT_POINTER:
4768
                case TGT_RANGE:
4769
                case TGT_IFACE_POINTER:
4770
                    print_file(file, indent, "%s_W%u = 0;\n", local_var_prefix, i);
4771
                    break;
4772 4773 4774 4775
                case TGT_USER_TYPE:
                    print_file(file, indent, "memset(&%s_W%u, 0, sizeof(%s_W%u));\n",
                               local_var_prefix, i, local_var_prefix, i);
                    break;
4776 4777 4778 4779 4780 4781
                case TGT_ARRAY:
                    if (type_array_is_decl_as_ptr(ref))
                    {
                        print_file(file, indent, "%s_W%u = 0;\n", local_var_prefix, i);
                        break;
                    }
4782
                    ref = type_array_get_element_type(ref);
4783
                    /* fall through */
4784 4785
                case TGT_STRUCT:
                case TGT_UNION:
4786 4787 4788 4789
                    if (type_has_pointers(ref))
                        print_file(file, indent, "memset(&%s_W%u, 0, sizeof(%s_W%u));\n",
                                   local_var_prefix, i, local_var_prefix, i);
                    break;
4790 4791 4792 4793 4794 4795 4796
                case TGT_CTXT_HANDLE:
                case TGT_CTXT_HANDLE_POINTER:
                case TGT_INVALID:
                case TGT_STRING:
                    /* not initialised */
                    break;
                }
4797
                i++;
4798 4799 4800
                break;
            default:
                break;
4801 4802 4803 4804 4805 4806 4807 4808 4809 4810
            }

            sep = 1;
        }
    }
    if (sep)
        fprintf(file, "\n");
}


4811 4812
void write_func_param_struct( FILE *file, const type_t *iface, const type_t *func,
                              const char *var_decl, int add_retval )
4813
{
4814
    var_t *retval = type_function_get_retval( func );
4815
    const var_list_t *args = type_function_get_args( func );
4816
    const var_t *arg;
4817 4818 4819 4820 4821
    int needs_packing;
    unsigned int align = 0;

    if (args)
        LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
4822
            if (!is_array( arg->declspec.type )) type_memsize_and_alignment( arg->declspec.type, &align );
4823 4824

    needs_packing = (align > pointer_size);
4825

4826
    if (needs_packing) print_file( file, 0, "#include <pshpack%u.h>\n", pointer_size );
4827 4828 4829 4830 4831 4832 4833
    print_file(file, 1, "struct _PARAM_STRUCT\n" );
    print_file(file, 1, "{\n" );
    if (is_object( iface )) print_file(file, 2, "%s *This;\n", iface->name );

    if (args) LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
    {
        print_file(file, 2, "%s", "");
4834
        write_type_left( file, &arg->declspec, NAME_DEFAULT, TRUE, TRUE );
4835 4836
        if (needs_space_after( arg->declspec.type )) fputc( ' ', file );
        if (is_array( arg->declspec.type ) && !type_array_is_decl_as_ptr( arg->declspec.type )) fputc( '*', file );
4837

4838
        /* FIXME: should check for large args being passed by pointer */
4839
        align = 0;
4840 4841
        if (is_array( arg->declspec.type ) || is_ptr( arg->declspec.type )) align = pointer_size;
        else type_memsize_and_alignment( arg->declspec.type, &align );
4842

4843 4844 4845
        if (align < pointer_size)
            fprintf( file, "DECLSPEC_ALIGN(%u) ", pointer_size );
        fprintf( file, "%s;\n", arg->name );
4846
    }
4847
    if (add_retval && !is_void( retval->declspec.type ))
4848 4849
    {
        print_file(file, 2, "%s", "");
4850 4851 4852 4853 4854 4855 4856 4857
        write_type_left( file, &retval->declspec, NAME_DEFAULT, TRUE, TRUE );
        if (needs_space_after( retval->declspec.type )) fputc( ' ', file );
        if (!is_array( retval->declspec.type ) && !is_ptr( retval->declspec.type ) &&
            type_memsize( retval->declspec.type ) != pointer_size)
        {
            fprintf( file, "DECLSPEC_ALIGN(%u) ", pointer_size );
        }
        fprintf( file, "%s;\n", retval->name );
4858
    }
4859 4860 4861
    print_file(file, 1, "} %s;\n", var_decl );
    if (needs_packing) print_file( file, 0, "#include <poppack.h>\n" );
    print_file( file, 0, "\n" );
4862 4863
}

4864 4865
void write_pointer_checks( FILE *file, int indent, const var_t *func )
{
4866
    const var_list_t *args = type_function_get_args( func->declspec.type );
4867 4868 4869 4870 4871 4872 4873 4874 4875
    const var_t *var;

    if (!args) return;

    LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
        if (cant_be_null( var ))
            print_file( file, indent, "if (!%s) RpcRaiseException(RPC_X_NULL_REF_POINTER);\n", var->name );
}

4876 4877
int write_expr_eval_routines(FILE *file, const char *iface)
{
4878
    static const char *var_name = "pS";
4879
    static const char *var_name_expr = "pS->";
4880 4881 4882 4883 4884 4885
    int result = 0;
    struct expr_eval_routine *eval;
    unsigned short callback_offset = 0;

    LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
    {
4886
        const char *name = eval->name;
4887
        result = 1;
4888 4889

        print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
4890
                   eval->iface ? eval->iface->name : iface, name, callback_offset);
4891
        print_file(file, 0, "{\n");
4892 4893
        if (type_get_type( eval->cont_type ) == TYPE_FUNCTION)
        {
4894 4895
            write_func_param_struct( file, eval->iface, eval->cont_type,
                                     "*pS = (struct _PARAM_STRUCT *)pStubMsg->StackTop", FALSE );
4896 4897 4898
        }
        else
        {
4899
            decl_spec_t ds = {.type = (type_t *)eval->cont_type};
4900
            print_file(file, 1, "%s", "");
4901
            write_type_left(file, &ds, NAME_DEFAULT, TRUE, TRUE);
4902
            fprintf(file, " *%s = (", var_name);
4903
            write_type_left(file, &ds, NAME_DEFAULT, TRUE, TRUE);
4904 4905
            fprintf(file, " *)(pStubMsg->StackTop - %u);\n", eval->baseoff);
        }
4906
        print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */
4907
        print_file(file, 1, "pStubMsg->MaxCount = (ULONG_PTR)");
4908
        write_expr(file, eval->expr, 1, 1, var_name_expr, eval->cont_type, "");
4909
        fprintf(file, ";\n");
4910
        print_file(file, 0, "}\n\n");
4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926
        callback_offset++;
    }
    return result;
}

void write_expr_eval_routine_list(FILE *file, const char *iface)
{
    struct expr_eval_routine *eval;
    struct expr_eval_routine *cursor;
    unsigned short callback_offset = 0;

    fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
    fprintf(file, "{\n");

    LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
    {
4927 4928
        print_file(file, 1, "%s_%sExprEval_%04u,\n",
                   eval->iface ? eval->iface->name : iface, eval->name, callback_offset);
4929 4930
        callback_offset++;
        list_remove(&eval->entry);
4931
        free(eval->name);
4932 4933 4934 4935 4936
        free(eval);
    }

    fprintf(file, "};\n\n");
}
4937

4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950
void write_user_quad_list(FILE *file)
{
    user_type_t *ut;

    if (list_empty(&user_type_list))
        return;

    fprintf(file, "static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[] =\n");
    fprintf(file, "{\n");
    LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
    {
        const char *sep = &ut->entry == list_tail(&user_type_list) ? "" : ",";
        print_file(file, 1, "{\n");
4951 4952 4953 4954
        print_file(file, 2, "(USER_MARSHAL_SIZING_ROUTINE)%s_UserSize,\n", ut->name);
        print_file(file, 2, "(USER_MARSHAL_MARSHALLING_ROUTINE)%s_UserMarshal,\n", ut->name);
        print_file(file, 2, "(USER_MARSHAL_UNMARSHALLING_ROUTINE)%s_UserUnmarshal,\n", ut->name);
        print_file(file, 2, "(USER_MARSHAL_FREEING_ROUTINE)%s_UserFree\n", ut->name);
4955 4956 4957 4958
        print_file(file, 1, "}%s\n", sep);
    }
    fprintf(file, "};\n\n");
}
4959 4960 4961 4962 4963 4964 4965

void write_endpoints( FILE *f, const char *prefix, const str_list_t *list )
{
    const struct str_list_entry_t *endpoint;
    const char *p;

    /* this should be an array of RPC_PROTSEQ_ENDPOINT but we want const strings */
4966
    print_file( f, 0, "static const unsigned char * const %s__RpcProtseqEndpoint[][2] =\n{\n", prefix );
4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992
    LIST_FOR_EACH_ENTRY( endpoint, list, const struct str_list_entry_t, entry )
    {
        print_file( f, 1, "{ (const unsigned char *)\"" );
        for (p = endpoint->str; *p && *p != ':'; p++)
        {
            if (*p == '"' || *p == '\\') fputc( '\\', f );
            fputc( *p, f );
        }
        if (!*p) goto error;
        if (p[1] != '[') goto error;

        fprintf( f, "\", (const unsigned char *)\"" );
        for (p += 2; *p && *p != ']'; p++)
        {
            if (*p == '"' || *p == '\\') fputc( '\\', f );
            fputc( *p, f );
        }
        if (*p != ']') goto error;
        fprintf( f, "\" },\n" );
    }
    print_file( f, 0, "};\n\n" );
    return;

error:
    error("Invalid endpoint syntax '%s'\n", endpoint->str);
}
4993

4994 4995 4996
void write_client_call_routine( FILE *file, const type_t *iface, const var_t *func,
                                const char *prefix, unsigned int proc_offset )
{
4997 4998
    const decl_spec_t *rettype = type_function_get_ret( func->declspec.type );
    int has_ret = !is_void( rettype->type );
4999
    const var_list_t *args = type_function_get_args( func->declspec.type );
5000
    const var_t *arg;
5001 5002 5003 5004
    int len, needs_params = 0;

    /* we need a param structure if we have more than one arg */
    if (pointer_size == 4 && args) needs_params = is_object( iface ) || list_count( args ) > 1;
5005 5006

    print_file( file, 0, "{\n");
5007 5008 5009
    if (needs_params)
    {
        if (has_ret) print_file( file, 1, "%s", "CLIENT_CALL_RETURN _RetVal;\n" );
5010
        write_func_param_struct( file, iface, func->declspec.type, "__params", FALSE );
5011 5012 5013 5014 5015 5016 5017
        if (is_object( iface )) print_file( file, 1, "__params.This = This;\n" );
        if (args)
            LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
                print_file( file, 1, "__params.%s = %s;\n", arg->name, arg->name );
    }
    else if (has_ret) print_file( file, 1, "%s", "CLIENT_CALL_RETURN _RetVal;\n\n" );

5018 5019 5020 5021 5022
    len = fprintf( file, "    %s%s( ",
                   has_ret ? "_RetVal = " : "",
                   get_stub_mode() == MODE_Oif ? "NdrClientCall2" : "NdrClientCall" );
    fprintf( file, "&%s_StubDesc,", prefix );
    fprintf( file, "\n%*s&__MIDL_ProcFormatString.Format[%u]", len, "", proc_offset );
5023 5024 5025 5026 5027
    if (needs_params)
    {
        fprintf( file, ",\n%*s&__params", len, "" );
    }
    else if (pointer_size == 8)
5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052
    {
        if (is_object( iface )) fprintf( file, ",\n%*sThis", len, "" );
        if (args)
            LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
                fprintf( file, ",\n%*s%s", len, "", arg->name );
    }
    else
    {
        if (is_object( iface )) fprintf( file, ",\n%*s&This", len, "" );
        else if (args)
        {
            arg = LIST_ENTRY( list_head(args), const var_t, entry );
            fprintf( file, ",\n%*s&%s", len, "", arg->name );
        }
    }
    fprintf( file, " );\n" );
    if (has_ret)
    {
        print_file( file, 1, "return (" );
        write_type_decl_left(file, rettype);
        fprintf( file, ")%s;\n", pointer_size == 8 ? "_RetVal.Simple" : "*(LONG_PTR *)&_RetVal" );
    }
    print_file( file, 0, "}\n\n");
}

5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064
void write_exceptions( FILE *file )
{
    fprintf( file, "#ifndef USE_COMPILER_EXCEPTIONS\n");
    fprintf( file, "\n");
    fprintf( file, "#include \"wine/exception.h\"\n");
    fprintf( file, "#undef RpcTryExcept\n");
    fprintf( file, "#undef RpcExcept\n");
    fprintf( file, "#undef RpcEndExcept\n");
    fprintf( file, "#undef RpcTryFinally\n");
    fprintf( file, "#undef RpcFinally\n");
    fprintf( file, "#undef RpcEndFinally\n");
    fprintf( file, "#undef RpcExceptionCode\n");
5065
    fprintf( file, "#undef RpcAbnormalTermination\n");
5066 5067
    fprintf( file, "\n");
    fprintf( file, "struct __exception_frame;\n");
5068
    fprintf( file, "typedef int (*__filter_func)(struct __exception_frame *);\n");
5069 5070 5071 5072 5073 5074
    fprintf( file, "typedef void (*__finally_func)(struct __exception_frame *);\n");
    fprintf( file, "\n");
    fprintf( file, "#define __DECL_EXCEPTION_FRAME \\\n");
    fprintf( file, "    EXCEPTION_REGISTRATION_RECORD frame; \\\n");
    fprintf( file, "    __filter_func                 filter; \\\n");
    fprintf( file, "    __finally_func                finally; \\\n");
5075
    fprintf( file, "    __wine_jmp_buf                jmp; \\\n");
5076
    fprintf( file, "    DWORD                         code; \\\n");
5077
    fprintf( file, "    unsigned char                 abnormal_termination; \\\n");
5078 5079 5080 5081
    fprintf( file, "    unsigned char                 filter_level; \\\n");
    fprintf( file, "    unsigned char                 finally_level;\n");
    fprintf( file, "\n");
    fprintf( file, "struct __exception_frame\n{\n");
5082
    fprintf( file, "    __DECL_EXCEPTION_FRAME\n");
5083 5084
    fprintf( file, "};\n");
    fprintf( file, "\n");
5085 5086 5087 5088 5089 5090 5091 5092 5093 5094
    fprintf( file, "static inline void __widl_unwind_target(void)\n" );
    fprintf( file, "{\n");
    fprintf( file, "    struct __exception_frame *exc_frame = (struct __exception_frame *)__wine_get_frame();\n" );
    fprintf( file, "    if (exc_frame->finally_level > exc_frame->filter_level)\n" );
    fprintf( file, "    {\n");
    fprintf( file, "        exc_frame->abnormal_termination = 1;\n");
    fprintf( file, "        exc_frame->finally( exc_frame );\n");
    fprintf( file, "        __wine_pop_frame( &exc_frame->frame );\n");
    fprintf( file, "    }\n");
    fprintf( file, "    exc_frame->filter_level = 0;\n");
5095
    fprintf( file, "    __wine_longjmp( &exc_frame->jmp, 1 );\n");
5096 5097
    fprintf( file, "}\n");
    fprintf( file, "\n");
5098 5099 5100 5101
    fprintf( file, "static DWORD __cdecl __widl_exception_handler( EXCEPTION_RECORD *record,\n");
    fprintf( file, "                                               EXCEPTION_REGISTRATION_RECORD *frame,\n");
    fprintf( file, "                                               CONTEXT *context,\n");
    fprintf( file, "                                               EXCEPTION_REGISTRATION_RECORD **pdispatcher )\n");
5102 5103 5104 5105 5106 5107
    fprintf( file, "{\n");
    fprintf( file, "    struct __exception_frame *exc_frame = (struct __exception_frame *)frame;\n");
    fprintf( file, "\n");
    fprintf( file, "    if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))\n");
    fprintf( file, "    {\n" );
    fprintf( file, "        if (exc_frame->finally_level && (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))\n");
5108 5109
    fprintf( file, "        {\n" );
    fprintf( file, "            exc_frame->abnormal_termination = 1;\n");
5110
    fprintf( file, "            exc_frame->finally( exc_frame );\n");
5111
    fprintf( file, "        }\n" );
5112 5113 5114
    fprintf( file, "        return ExceptionContinueSearch;\n");
    fprintf( file, "    }\n" );
    fprintf( file, "    exc_frame->code = record->ExceptionCode;\n");
5115
    fprintf( file, "    if (exc_frame->filter_level && exc_frame->filter( exc_frame ) == EXCEPTION_EXECUTE_HANDLER)\n" );
5116
    fprintf( file, "        __wine_rtl_unwind( frame, record, __widl_unwind_target );\n");
5117 5118 5119 5120
    fprintf( file, "    return ExceptionContinueSearch;\n");
    fprintf( file, "}\n");
    fprintf( file, "\n");
    fprintf( file, "#define RpcTryExcept \\\n");
5121
    fprintf( file, "    if (!__wine_setjmpex( &__frame->jmp, &__frame->frame )) \\\n");
5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149
    fprintf( file, "    { \\\n");
    fprintf( file, "        if (!__frame->finally_level) \\\n" );
    fprintf( file, "            __wine_push_frame( &__frame->frame ); \\\n");
    fprintf( file, "        __frame->filter_level = __frame->finally_level + 1;\n" );
    fprintf( file, "\n");
    fprintf( file, "#define RpcExcept(expr) \\\n");
    fprintf( file, "        if (!__frame->finally_level) \\\n" );
    fprintf( file, "            __wine_pop_frame( &__frame->frame ); \\\n");
    fprintf( file, "        __frame->filter_level = 0; \\\n" );
    fprintf( file, "    } \\\n");
    fprintf( file, "    else \\\n");
    fprintf( file, "\n");
    fprintf( file, "#define RpcEndExcept\n");
    fprintf( file, "\n");
    fprintf( file, "#define RpcExceptionCode() (__frame->code)\n");
    fprintf( file, "\n");
    fprintf( file, "#define RpcTryFinally \\\n");
    fprintf( file, "    if (!__frame->filter_level) \\\n");
    fprintf( file, "        __wine_push_frame( &__frame->frame ); \\\n");
    fprintf( file, "    __frame->finally_level = __frame->filter_level + 1;\n");
    fprintf( file, "\n");
    fprintf( file, "#define RpcFinally \\\n");
    fprintf( file, "    if (!__frame->filter_level) \\\n");
    fprintf( file, "        __wine_pop_frame( &__frame->frame ); \\\n");
    fprintf( file, "    __frame->finally_level = 0;\n");
    fprintf( file, "\n");
    fprintf( file, "#define RpcEndFinally\n");
    fprintf( file, "\n");
5150 5151
    fprintf( file, "#define RpcAbnormalTermination() (__frame->abnormal_termination)\n");
    fprintf( file, "\n");
5152 5153 5154 5155 5156
    fprintf( file, "#define RpcExceptionInit(filter_func,finally_func) \\\n");
    fprintf( file, "    do { \\\n");
    fprintf( file, "        __frame->frame.Handler = __widl_exception_handler; \\\n");
    fprintf( file, "        __frame->filter = (__filter_func)(filter_func); \\\n" );
    fprintf( file, "        __frame->finally = (__finally_func)(finally_func); \\\n");
5157
    fprintf( file, "        __frame->abnormal_termination = 0; \\\n");
5158 5159 5160 5161 5162 5163
    fprintf( file, "        __frame->filter_level = 0; \\\n");
    fprintf( file, "        __frame->finally_level = 0; \\\n");
    fprintf( file, "    } while (0)\n");
    fprintf( file, "\n");
    fprintf( file, "#else /* USE_COMPILER_EXCEPTIONS */\n");
    fprintf( file, "\n");
5164 5165 5166
    fprintf( file, "#define RpcExceptionInit(filter_func,finally_func) \\\n");
    fprintf( file, "    do { (void)(filter_func); } while(0)\n");
    fprintf( file, "\n");
5167 5168
    fprintf( file, "#define __DECL_EXCEPTION_FRAME \\\n");
    fprintf( file, "    DWORD code;\n");
5169 5170 5171
    fprintf( file, "\n");
    fprintf( file, "#endif /* USE_COMPILER_EXCEPTIONS */\n");
}