typegen.c 178 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 70 71
enum type_context
{
    TYPE_CONTEXT_TOPLEVELPARAM,
    TYPE_CONTEXT_PARAM,
    TYPE_CONTEXT_CONTAINER,
    TYPE_CONTEXT_CONTAINER_NO_POINTERS,
};

72 73 74 75 76 77 78 79 80 81 82 83 84
/* 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; */

85
static unsigned int field_memsize(const type_t *type, unsigned int *offset);
86
static unsigned int fields_memsize(const var_list_t *fields, unsigned int *align);
87
static unsigned int type_memsize_and_alignment(const type_t *t, unsigned int *align);
88 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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
{
    switch (type)
    {
    case RPC_FC_BYTE: return "FC_BYTE";
    case RPC_FC_CHAR: return "FC_CHAR";
    case RPC_FC_SMALL: return "FC_SMALL";
    case RPC_FC_USMALL: return "FC_USMALL";
    case RPC_FC_WCHAR: return "FC_WCHAR";
    case RPC_FC_SHORT: return "FC_SHORT";
    case RPC_FC_USHORT: return "FC_USHORT";
    case RPC_FC_LONG: return "FC_LONG";
    case RPC_FC_ULONG: return "FC_ULONG";
    case RPC_FC_FLOAT: return "FC_FLOAT";
    case RPC_FC_HYPER: return "FC_HYPER";
    case RPC_FC_DOUBLE: return "FC_DOUBLE";
    case RPC_FC_ENUM16: return "FC_ENUM16";
    case RPC_FC_ENUM32: return "FC_ENUM32";
    case RPC_FC_IGNORE: return "FC_IGNORE";
    case RPC_FC_ERROR_STATUS_T: return "FC_ERROR_STATUS_T";
    case RPC_FC_RP: return "FC_RP";
    case RPC_FC_UP: return "FC_UP";
    case RPC_FC_OP: return "FC_OP";
    case RPC_FC_FP: return "FC_FP";
126 127 128 129 130 131 132 133
    case RPC_FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION";
    case RPC_FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION";
    case RPC_FC_STRUCT: return "FC_STRUCT";
    case RPC_FC_PSTRUCT: return "FC_PSTRUCT";
    case RPC_FC_CSTRUCT: return "FC_CSTRUCT";
    case RPC_FC_CPSTRUCT: return "FC_CPSTRUCT";
    case RPC_FC_CVSTRUCT: return "FC_CVSTRUCT";
    case RPC_FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT";
134 135 136 137 138 139 140
    case RPC_FC_SMFARRAY: return "FC_SMFARRAY";
    case RPC_FC_LGFARRAY: return "FC_LGFARRAY";
    case RPC_FC_SMVARRAY: return "FC_SMVARRAY";
    case RPC_FC_LGVARRAY: return "FC_LGVARRAY";
    case RPC_FC_CARRAY: return "FC_CARRAY";
    case RPC_FC_CVARRAY: return "FC_CVARRAY";
    case RPC_FC_BOGUS_ARRAY: return "FC_BOGUS_ARRAY";
141
    case RPC_FC_ALIGNM2: return "FC_ALIGNM2";
142 143
    case RPC_FC_ALIGNM4: return "FC_ALIGNM4";
    case RPC_FC_ALIGNM8: return "FC_ALIGNM8";
144
    case RPC_FC_POINTER: return "FC_POINTER";
145 146 147 148
    case RPC_FC_C_CSTRING: return "FC_C_CSTRING";
    case RPC_FC_C_WSTRING: return "FC_C_WSTRING";
    case RPC_FC_CSTRING: return "FC_CSTRING";
    case RPC_FC_WSTRING: return "FC_WSTRING";
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
    case RPC_FC_BYTE_COUNT_POINTER: return "FC_BYTE_COUNT_POINTER";
    case RPC_FC_TRANSMIT_AS: return "FC_TRANSMIT_AS";
    case RPC_FC_REPRESENT_AS: return "FC_REPRESENT_AS";
    case RPC_FC_IP: return "FC_IP";
    case RPC_FC_BIND_CONTEXT: return "FC_BIND_CONTEXT";
    case RPC_FC_BIND_GENERIC: return "FC_BIND_GENERIC";
    case RPC_FC_BIND_PRIMITIVE: return "FC_BIND_PRIMITIVE";
    case RPC_FC_AUTO_HANDLE: return "FC_AUTO_HANDLE";
    case RPC_FC_CALLBACK_HANDLE: return "FC_CALLBACK_HANDLE";
    case RPC_FC_STRUCTPAD1: return "FC_STRUCTPAD1";
    case RPC_FC_STRUCTPAD2: return "FC_STRUCTPAD2";
    case RPC_FC_STRUCTPAD3: return "FC_STRUCTPAD3";
    case RPC_FC_STRUCTPAD4: return "FC_STRUCTPAD4";
    case RPC_FC_STRUCTPAD5: return "FC_STRUCTPAD5";
    case RPC_FC_STRUCTPAD6: return "FC_STRUCTPAD6";
    case RPC_FC_STRUCTPAD7: return "FC_STRUCTPAD7";
    case RPC_FC_STRING_SIZED: return "FC_STRING_SIZED";
    case RPC_FC_NO_REPEAT: return "FC_NO_REPEAT";
    case RPC_FC_FIXED_REPEAT: return "FC_FIXED_REPEAT";
    case RPC_FC_VARIABLE_REPEAT: return "FC_VARIABLE_REPEAT";
    case RPC_FC_FIXED_OFFSET: return "FC_FIXED_OFFSET";
    case RPC_FC_VARIABLE_OFFSET: return "FC_VARIABLE_OFFSET";
    case RPC_FC_PP: return "FC_PP";
    case RPC_FC_EMBEDDED_COMPLEX: return "FC_EMBEDDED_COMPLEX";
    case RPC_FC_DEREFERENCE: return "FC_DEREFERENCE";
    case RPC_FC_DIV_2: return "FC_DIV_2";
    case RPC_FC_MULT_2: return "FC_MULT_2";
    case RPC_FC_ADD_1: return "FC_ADD_1";
    case RPC_FC_SUB_1: return "FC_SUB_1";
    case RPC_FC_CALLBACK: return "FC_CALLBACK";
    case RPC_FC_CONSTANT_IID: return "FC_CONSTANT_IID";
    case RPC_FC_END: return "FC_END";
    case RPC_FC_PAD: return "FC_PAD";
    case RPC_FC_USER_MARSHAL: return "FC_USER_MARSHAL";
    case RPC_FC_RANGE: return "FC_RANGE";
184 185
    case RPC_FC_INT3264: return "FC_INT3264";
    case RPC_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 200
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))
            t = type_alias_get_aliasee(t);
201
        else return NULL;
202 203 204
    }
}

205 206 207 208 209 210 211 212 213 214
unsigned char get_basic_fc(const type_t *type)
{
    int sign = type_basic_get_sign(type);
    switch (type_basic_get_type(type))
    {
    case TYPE_BASIC_INT8: return (sign <= 0 ? RPC_FC_SMALL : RPC_FC_USMALL);
    case TYPE_BASIC_INT16: return (sign <= 0 ? RPC_FC_SHORT : RPC_FC_USHORT);
    case TYPE_BASIC_INT32: return (sign <= 0 ? RPC_FC_LONG : RPC_FC_ULONG);
    case TYPE_BASIC_INT64: return RPC_FC_HYPER;
    case TYPE_BASIC_INT: return (sign <= 0 ? RPC_FC_LONG : RPC_FC_ULONG);
215
    case TYPE_BASIC_INT3264: return (sign <= 0 ? RPC_FC_INT3264 : RPC_FC_UINT3264);
216 217 218 219 220 221 222 223 224
    case TYPE_BASIC_BYTE: return RPC_FC_BYTE;
    case TYPE_BASIC_CHAR: return RPC_FC_CHAR;
    case TYPE_BASIC_WCHAR: return RPC_FC_WCHAR;
    case TYPE_BASIC_HYPER: return RPC_FC_HYPER;
    case TYPE_BASIC_FLOAT: return RPC_FC_FLOAT;
    case TYPE_BASIC_DOUBLE: return RPC_FC_DOUBLE;
    case TYPE_BASIC_ERROR_STATUS_T: return RPC_FC_ERROR_STATUS_T;
    case TYPE_BASIC_HANDLE: return RPC_FC_BIND_PRIMITIVE;
    }
225
    return 0;
226 227
}

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
static unsigned char get_basic_fc_signed(const type_t *type)
{
    switch (type_basic_get_type(type))
    {
    case TYPE_BASIC_INT8: return RPC_FC_SMALL;
    case TYPE_BASIC_INT16: return RPC_FC_SHORT;
    case TYPE_BASIC_INT32: return RPC_FC_LONG;
    case TYPE_BASIC_INT64: return RPC_FC_HYPER;
    case TYPE_BASIC_INT: return RPC_FC_LONG;
    case TYPE_BASIC_INT3264: return RPC_FC_INT3264;
    case TYPE_BASIC_BYTE: return RPC_FC_BYTE;
    case TYPE_BASIC_CHAR: return RPC_FC_CHAR;
    case TYPE_BASIC_WCHAR: return RPC_FC_WCHAR;
    case TYPE_BASIC_HYPER: return RPC_FC_HYPER;
    case TYPE_BASIC_FLOAT: return RPC_FC_FLOAT;
    case TYPE_BASIC_DOUBLE: return RPC_FC_DOUBLE;
    case TYPE_BASIC_ERROR_STATUS_T: return RPC_FC_ERROR_STATUS_T;
    case TYPE_BASIC_HANDLE: return RPC_FC_BIND_PRIMITIVE;
    }
    return 0;
}

250 251 252 253 254 255 256
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;
}

257
unsigned char get_pointer_fc(const type_t *type, const attr_list_t *attrs, int toplevel_param)
258
{
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
    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;

    for (t = type; type_is_alias(t); t = type_alias_get_aliasee(t))
    {
        pointer_type = get_attrv(t->attrs, ATTR_POINTERTYPE);
        if (pointer_type)
            return pointer_type;
    }

    if (toplevel_param)
        return RPC_FC_RP;
    else if (is_ptr(type))
        return type_pointer_get_default_fc(type);
    else
        return type_array_get_ptr_default_fc(type);
281 282
}

283 284 285 286 287 288 289 290 291 292 293 294
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);

    if (pointer_fc == RPC_FC_UP && is_attr( attrs, ATTR_OUT ) &&
        context == TYPE_CONTEXT_PARAM && is_object( current_iface ))
        pointer_fc = RPC_FC_OP;

    return pointer_fc;
}

295 296 297 298 299 300 301 302 303
static unsigned char get_enum_fc(const type_t *type)
{
    assert(type_get_type(type) == TYPE_ENUM);
    if (is_aliaschain_attr(type, ATTR_V1ENUM))
        return RPC_FC_ENUM32;
    else
        return RPC_FC_ENUM16;
}

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
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))
            t = type_alias_get_aliasee(t);
        else
            return NULL;
    }
}

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

328 329 330 331 332 333 334 335 336 337 338 339 340 341
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:
342 343
        if (!(flags & TDT_IGNORE_RANGES) &&
            (is_attr(attrs, ATTR_RANGE) || is_aliaschain_attr(type, ATTR_RANGE)))
344
            return TGT_RANGE;
345 346
        return TGT_BASIC;
    case TYPE_ENUM:
347 348
        if (!(flags & TDT_IGNORE_RANGES) &&
            (is_attr(attrs, ATTR_RANGE) || is_aliaschain_attr(type, ATTR_RANGE)))
349
            return TGT_RANGE;
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
        return TGT_ENUM;
    case TYPE_POINTER:
        if (type_get_type(type_pointer_get_ref(type)) == TYPE_INTERFACE ||
            (type_get_type(type_pointer_get_ref(type)) == TYPE_VOID && is_attr(attrs, ATTR_IIDIS)))
            return TGT_IFACE_POINTER;
        else if (is_aliaschain_attr(type_pointer_get_ref(type), ATTR_CONTEXTHANDLE))
            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:
372
    case TYPE_BITFIELD:
373 374 375 376 377
        break;
    }
    return TGT_INVALID;
}

378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
static int cant_be_null(const var_t *v)
{
    switch (typegen_detect_type(v->type, v->attrs, TDT_IGNORE_STRINGS))
    {
    case TGT_ARRAY:
        if (!type_array_is_decl_as_ptr( v->type )) return 0;
        /* fall through */
    case TGT_POINTER:
        return (get_pointer_fc(v->type, v->attrs, TRUE) == RPC_FC_RP);
    case TGT_CTXT_HANDLE_POINTER:
        return TRUE;
    default:
        return 0;
    }

}

395 396 397 398 399 400 401 402 403 404 405 406 407
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)
    {
        type_t *ft = f->type;
        unsigned int align = 0;
408
        unsigned int size = type_memsize_and_alignment(ft, &align);
409 410 411 412 413 414 415 416 417
        align = clamp_align(align);
        if (align > salign) salign = align;
        offset = ROUND_SIZE(offset, align);
        offset += size;
    }

    return ROUNDING(offset, salign);
}

418
static unsigned int get_stack_size( const var_t *var, int *by_value )
419 420 421 422
{
    unsigned int stack_size;
    int by_val;

423
    switch (typegen_detect_type( var->type, var->attrs, TDT_ALL_TYPES ))
424 425 426 427 428 429 430
    {
    case TGT_BASIC:
    case TGT_ENUM:
    case TGT_RANGE:
    case TGT_STRUCT:
    case TGT_UNION:
    case TGT_USER_TYPE:
431
        stack_size = type_memsize( var->type );
432 433 434 435 436 437 438 439 440 441 442
        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 );
}

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
static unsigned char get_contexthandle_flags( const type_t *iface, const attr_list_t *attrs,
                                              const type_t *type )
{
    unsigned char flags = 0;

    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 ))
        flags |= 0x80;

    if (is_attr(attrs, ATTR_IN))
    {
        flags |= 0x40;
        if (!is_attr(attrs, ATTR_OUT)) flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
    }
    if (is_attr(attrs, ATTR_OUT)) flags |= 0x20;

    return flags;
}

465 466 467 468 469 470 471 472 473 474 475 476
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;
}

477
unsigned char get_struct_fc(const type_t *type)
478 479 480 481 482
{
  int has_pointer = 0;
  int has_conformance = 0;
  int has_variance = 0;
  var_t *field;
483
  var_list_t *fields;
484

485 486 487
  fields = type_struct_get_fields(type);

  if (get_padding(fields))
488 489
    return RPC_FC_BOGUS_STRUCT;

490
  if (fields) LIST_FOR_EACH_ENTRY( field, fields, var_t, entry )
491 492
  {
    type_t *t = field->type;
493
    enum typegen_type typegen_type;
494

495
    typegen_type = typegen_detect_type(t, field->attrs, TDT_IGNORE_STRINGS);
496

497
    if (typegen_type == TGT_ARRAY && !type_array_is_decl_as_ptr(t))
498 499 500
    {
        if (is_string_type(field->attrs, field->type))
        {
501
            if (is_conformant_array(t))
502 503 504 505 506
                has_conformance = 1;
            has_variance = 1;
            continue;
        }

507
        if (is_array(type_array_get_element(field->type)))
508 509
            return RPC_FC_BOGUS_STRUCT;

510
        if (type_array_has_conformance(field->type))
511 512
        {
            has_conformance = 1;
513
            if (list_next(fields, &field->entry))
514 515 516
                error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
                        field->name);
        }
517
        if (type_array_has_variance(t))
518 519
            has_variance = 1;

520
        t = type_array_get_element(t);
521
        typegen_type = typegen_detect_type(t, field->attrs, TDT_IGNORE_STRINGS);
522
    }
523

524
    switch (typegen_type)
525
    {
526 527 528 529
    case TGT_USER_TYPE:
    case TGT_IFACE_POINTER:
        return RPC_FC_BOGUS_STRUCT;
    case TGT_BASIC:
530 531
        if (type_basic_get_type(t) == TYPE_BASIC_INT3264 && pointer_size != 4)
            return RPC_FC_BOGUS_STRUCT;
532
        break;
533
    case TGT_ENUM:
534 535 536
        if (get_enum_fc(t) == RPC_FC_ENUM16)
            return RPC_FC_BOGUS_STRUCT;
        break;
537
    case TGT_POINTER:
538
    case TGT_ARRAY:
539
        if (get_pointer_fc(t, field->attrs, FALSE) == RPC_FC_RP || pointer_size != 4)
540 541 542
            return RPC_FC_BOGUS_STRUCT;
        has_pointer = 1;
        break;
543
    case TGT_UNION:
544
        return RPC_FC_BOGUS_STRUCT;
545
    case TGT_STRUCT:
546 547 548 549 550 551 552 553 554 555 556
    {
        unsigned char fc = get_struct_fc(t);
        switch (fc)
        {
        case RPC_FC_STRUCT:
            break;
        case RPC_FC_CVSTRUCT:
            has_conformance = 1;
            has_variance = 1;
            has_pointer = 1;
            break;
557

558 559 560 561 562 563 564
        case RPC_FC_CPSTRUCT:
            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;
565

566 567 568 569 570 571
        case RPC_FC_CSTRUCT:
            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;
572

573 574 575
        case RPC_FC_PSTRUCT:
            has_pointer = 1;
            break;
576

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

581 582 583 584 585 586
        /* as soon as we see one of these these members, it's bogus... */
        case RPC_FC_BOGUS_STRUCT:
            return RPC_FC_BOGUS_STRUCT;
        }
        break;
    }
587 588
    case TGT_RANGE:
        return RPC_FC_BOGUS_STRUCT;
589 590 591 592 593 594 595 596
    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);
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
    }
  }

  if( has_variance )
  {
    if ( has_conformance )
      return RPC_FC_CVSTRUCT;
    else
      return RPC_FC_BOGUS_STRUCT;
  }
  if( has_conformance && has_pointer )
    return RPC_FC_CPSTRUCT;
  if( has_conformance )
    return RPC_FC_CSTRUCT;
  if( has_pointer )
    return RPC_FC_PSTRUCT;
  return RPC_FC_STRUCT;
}

616
static unsigned char get_array_fc(const type_t *type)
617
{
618 619 620 621 622 623 624 625 626
    unsigned char fc;
    const expr_t *size_is;
    const type_t *elem_type;

    elem_type = type_array_get_element(type);
    size_is = type_array_get_conformance(type);

    if (!size_is)
    {
627
        unsigned int size = type_memsize(elem_type);
628 629 630 631 632 633 634 635 636
        if (size * type_array_get_dim(type) > 0xffffuL)
            fc = RPC_FC_LGFARRAY;
        else
            fc = RPC_FC_SMFARRAY;
    }
    else
        fc = RPC_FC_CARRAY;

    if (type_array_has_variance(type))
637
    {
638 639 640 641 642 643 644 645
        if (fc == RPC_FC_SMFARRAY)
            fc = RPC_FC_SMVARRAY;
        else if (fc == RPC_FC_LGFARRAY)
            fc = RPC_FC_LGVARRAY;
        else if (fc == RPC_FC_CARRAY)
            fc = RPC_FC_CVARRAY;
    }

646
    switch (typegen_detect_type(elem_type, NULL, TDT_IGNORE_STRINGS))
647
    {
648 649 650
    case TGT_USER_TYPE:
        fc = RPC_FC_BOGUS_ARRAY;
        break;
651 652 653 654 655
    case TGT_BASIC:
        if (type_basic_get_type(elem_type) == TYPE_BASIC_INT3264 &&
            pointer_size != 4)
            fc = RPC_FC_BOGUS_ARRAY;
        break;
656
    case TGT_STRUCT:
657
        switch (get_struct_fc(elem_type))
658 659
        {
        case RPC_FC_BOGUS_STRUCT:
660
            fc = RPC_FC_BOGUS_ARRAY;
661 662
            break;
        }
663
        break;
664
    case TGT_ENUM:
665 666
        /* 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 */
667 668 669
        if (get_enum_fc(elem_type) == RPC_FC_ENUM16)
            fc = RPC_FC_BOGUS_ARRAY;
        break;
670 671
    case TGT_UNION:
    case TGT_IFACE_POINTER:
672
        fc = RPC_FC_BOGUS_ARRAY;
673
        break;
674
    case TGT_POINTER:
675 676 677
        /* ref pointers cannot just be block copied. unique pointers to
         * interfaces need special treatment. either case means the array is
         * complex */
678
        if (get_pointer_fc(elem_type, NULL, FALSE) == RPC_FC_RP || pointer_size != 4)
679
            fc = RPC_FC_BOGUS_ARRAY;
680
        break;
681 682 683
    case TGT_RANGE:
        fc = RPC_FC_BOGUS_ARRAY;
        break;
684 685 686 687 688
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
    case TGT_STRING:
    case TGT_INVALID:
    case TGT_ARRAY:
689 690
        /* nothing to do for everything else */
        break;
691 692 693
    }

    return fc;
694 695
}

696 697
static int is_non_complex_struct(const type_t *type)
{
698 699
    return (type_get_type(type) == TYPE_STRUCT &&
            get_struct_fc(type) != RPC_FC_BOGUS_STRUCT);
700 701
}

702 703
static int type_has_pointers(const type_t *type)
{
704
    switch (typegen_detect_type(type, NULL, TDT_IGNORE_STRINGS))
705
    {
706 707 708
    case TGT_USER_TYPE:
        return FALSE;
    case TGT_POINTER:
709
        return TRUE;
710
    case TGT_ARRAY:
711
        return type_array_is_decl_as_ptr(type) || type_has_pointers(type_array_get_element(type));
712
    case TGT_STRUCT:
713
    {
714
        var_list_t *fields = type_struct_get_fields(type);
715
        const var_t *field;
716
        if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
717 718 719 720
        {
            if (type_has_pointers(field->type))
                return TRUE;
        }
721
        break;
722
    }
723
    case TGT_UNION:
724 725 726
    {
        var_list_t *fields;
        const var_t *field;
727
        fields = type_union_get_cases(type);
728 729 730 731 732
        if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
        {
            if (field->type && type_has_pointers(field->type))
                return TRUE;
        }
733 734
        break;
    }
735 736 737 738 739 740
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
    case TGT_STRING:
    case TGT_IFACE_POINTER:
    case TGT_BASIC:
    case TGT_ENUM:
741
    case TGT_RANGE:
742
    case TGT_INVALID:
743
        break;
744 745 746 747 748
    }

    return FALSE;
}

749 750
static int type_has_full_pointer(const type_t *type, const attr_list_t *attrs,
                                 int toplevel_param)
751
{
752
    switch (typegen_detect_type(type, NULL, TDT_IGNORE_STRINGS))
753
    {
754 755 756
    case TGT_USER_TYPE:
        return FALSE;
    case TGT_POINTER:
757
        if (get_pointer_fc(type, attrs, toplevel_param) == RPC_FC_FP)
758 759 760
            return TRUE;
        else
            return FALSE;
761
    case TGT_ARRAY:
762 763 764 765
        if (get_pointer_fc(type, attrs, toplevel_param) == RPC_FC_FP)
            return TRUE;
        else
            return type_has_full_pointer(type_array_get_element(type), NULL, FALSE);
766
    case TGT_STRUCT:
767
    {
768
        var_list_t *fields = type_struct_get_fields(type);
769
        const var_t *field;
770
        if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
771
        {
772
            if (type_has_full_pointer(field->type, field->attrs, FALSE))
773 774
                return TRUE;
        }
775
        break;
776
    }
777
    case TGT_UNION:
778 779 780
    {
        var_list_t *fields;
        const var_t *field;
781
        fields = type_union_get_cases(type);
782 783
        if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
        {
784
            if (field->type && type_has_full_pointer(field->type, field->attrs, FALSE))
785 786
                return TRUE;
        }
787 788
        break;
    }
789 790 791 792 793 794
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
    case TGT_STRING:
    case TGT_IFACE_POINTER:
    case TGT_BASIC:
    case TGT_ENUM:
795
    case TGT_RANGE:
796
    case TGT_INVALID:
797
        break;
798 799 800 801 802
    }

    return FALSE;
}

803 804 805 806 807 808 809 810 811 812 813 814 815 816
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;
}

817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
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;
}

834 835
static int is_embedded_complex(const type_t *type)
{
836
    switch (typegen_detect_type(type, NULL, TDT_ALL_TYPES))
837
    {
838 839 840 841 842
    case TGT_USER_TYPE:
    case TGT_STRUCT:
    case TGT_UNION:
    case TGT_ARRAY:
    case TGT_IFACE_POINTER:
843 844 845 846
        return TRUE;
    default:
        return FALSE;
    }
847 848
}

849 850 851
static const char *get_context_handle_type_name(const type_t *type)
{
    const type_t *t;
852 853 854
    for (t = type;
         is_ptr(t) || type_is_alias(t);
         t = type_is_alias(t) ? type_alias_get_aliasee(t) : type_pointer_get_ref(t))
855 856 857 858 859 860
        if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
            return t->name;
    assert(0);
    return NULL;
}

861 862 863 864
#define WRITE_FCTYPE(file, fctype, typestring_offset) \
    do { \
        if (file) \
            fprintf(file, "/* %2u */\n", typestring_offset); \
865
        print_file((file), 2, "0x%02x,\t/* " #fctype " */\n", RPC_##fctype); \
866 867 868
    } \
    while (0)

869
static void print_file(FILE *file, int indent, const char *format, ...) __attribute__((format (printf, 3, 4)));
870
static void print_file(FILE *file, int indent, const char *format, ...)
871 872 873
{
    va_list va;
    va_start(va, format);
874
    print(file, indent, format, va);
875
    va_end(va);
876 877 878 879 880 881 882 883 884 885 886
}

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);
    }
887 888
}

889

890
static void write_var_init(FILE *file, int indent, const type_t *t, const char *n, const char *local_var_prefix)
891 892
{
    if (decl_indirect(t))
893
    {
894 895
        print_file(file, indent, "MIDL_memset(&%s%s, 0, sizeof(%s%s));\n",
                   local_var_prefix, n, local_var_prefix, n);
896 897
        print_file(file, indent, "%s_p_%s = &%s%s;\n", local_var_prefix, n, local_var_prefix, n);
    }
898
    else if (is_ptr(t) || is_array(t))
899
        print_file(file, indent, "%s%s = 0;\n", local_var_prefix, n);
900 901
}

902
void write_parameters_init(FILE *file, int indent, const var_t *func, const char *local_var_prefix)
903
{
904
    const var_t *var = type_function_get_retval(func->type);
905

906 907
    if (!is_void(var->type))
        write_var_init(file, indent, var->type, var->name, local_var_prefix);
908

909
    if (!type_get_function_args(func->type))
910 911
        return;

912
    LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
913
        write_var_init(file, indent, var->type, var->name, local_var_prefix);
914 915 916 917

    fprintf(file, "\n");
}

918 919 920 921 922 923 924 925 926 927
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");
}

928
void write_formatstringsdecl(FILE *f, int indent, const statement_list_t *stmts, type_pred_t pred)
929
{
930 931
    clear_all_offsets();

932
    print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n",
933
               get_size_typeformatstring(stmts, pred));
934 935

    print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n",
936
               get_size_procformatstring(stmts, pred));
937 938 939 940 941 942 943 944 945 946

    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");
}

947 948
int decl_indirect(const type_t *t)
{
949 950 951 952 953 954
    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);
955 956
}

957 958
static unsigned char get_parameter_fc( const var_t *var, int is_return, unsigned short *flags,
                                       unsigned int *stack_size, unsigned int *typestring_offset )
959 960 961 962
{
    unsigned int alignment, server_size = 0, buffer_size = 0;
    unsigned char fc = 0;
    int is_byval;
963 964
    int is_in = is_attr(var->attrs, ATTR_IN);
    int is_out = is_attr(var->attrs, ATTR_OUT);
965 966 967 968 969

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

    *flags = 0;
970
    *stack_size = get_stack_size( var, &is_byval );
971
    *typestring_offset = var->typestring_offset;
972 973 974 975 976

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

977 978
    if (!is_string_type( var->attrs, var->type ))
        buffer_size = get_required_buffer_size_type( var->type, NULL, var->attrs, TRUE, &alignment );
979

980
    switch (typegen_detect_type( var->type, var->attrs, TDT_ALL_TYPES ))
981 982 983
    {
    case TGT_BASIC:
        *flags |= IsBasetype;
984
        fc = get_basic_fc_signed( var->type );
985 986 987 988 989 990 991 992
        if (fc == RPC_FC_BIND_PRIMITIVE)
        {
            buffer_size = 4;  /* actually 0 but avoids setting MustSize */
            fc = RPC_FC_LONG;
        }
        break;
    case TGT_ENUM:
        *flags |= IsBasetype;
993
        fc = get_enum_fc( var->type );
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
        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;
1008 1009
        if (type_array_is_decl_as_ptr(var->type) && var->type->details.array.ptr_tfsoff &&
            get_pointer_fc( var->type, var->attrs, !is_return ) == RPC_FC_RP)
1010 1011
        {
            *typestring_offset = var->type->typestring_offset;
1012
            *flags |= IsSimpleRef;
1013
        }
1014 1015 1016
        break;
    case TGT_STRING:
        *flags |= MustFree;
1017
        if (is_declptr( var->type ) && get_pointer_fc( var->type, var->attrs, !is_return ) == RPC_FC_RP)
1018 1019
        {
            /* skip over pointer description straight to string description */
1020
            if (is_conformant_array( var->type )) *typestring_offset += 4;
1021
            else *typestring_offset += 2;
1022 1023 1024 1025 1026
            *flags |= IsSimpleRef;
        }
        break;
    case TGT_CTXT_HANDLE_POINTER:
        *flags |= IsSimpleRef;
1027
        *typestring_offset += 4;
1028 1029 1030 1031 1032
        /* fall through */
    case TGT_CTXT_HANDLE:
        buffer_size = 20;
        break;
    case TGT_POINTER:
1033
        if (get_pointer_fc( var->type, var->attrs, !is_return ) == RPC_FC_RP)
1034
        {
1035
            const type_t *ref = type_pointer_get_ref( var->type );
1036

1037
            if (!is_string_type( var->attrs, ref ))
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
                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:
                if ((fc = get_enum_fc( ref )) == RPC_FC_ENUM32)
                {
                    *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:
                *flags |= IsSimpleRef | MustFree;
                *typestring_offset = ref->typestring_offset;
                if (!is_in && is_out) server_size = type_memsize( ref );
                break;
            case TGT_STRING:
            case TGT_POINTER:
            case TGT_ARRAY:
            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))
                {
                case RPC_FC_STRUCT:
                case RPC_FC_PSTRUCT:
                case RPC_FC_BOGUS_STRUCT:
                    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;
    var_list_t *args = type_get_function_args( func->type );
1118
    var_t *retval = type_function_get_retval( func->type );
1119 1120 1121 1122 1123 1124
    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 )
    {
1125
        get_parameter_fc( var, 0, &flags, &stack_size, &typestring_offset );
1126 1127 1128 1129 1130 1131 1132
        if (flags & MustSize)
        {
            if (flags & IsIn) oi2_flags |= 0x02; /* ClientMustSize */
            if (flags & IsOut) oi2_flags |= 0x01;  /* ServerMustSize */
        }
    }

1133
    if (!is_void( retval->type ))
1134 1135
    {
        oi2_flags |= 0x04;  /* HasRet */
1136
        get_parameter_fc( retval, 1, &flags, &stack_size, &typestring_offset );
1137 1138 1139 1140 1141
        if (flags & MustSize) oi2_flags |= 0x01;  /* ServerMustSize */
    }
    return oi2_flags;
}

1142
static unsigned int write_new_procformatstring_type(FILE *file, int indent, const var_t *var,
1143 1144
                                                    int is_return, unsigned int *stack_offset)
{
1145
    char buffer[128];
1146 1147
    unsigned int stack_size, typestring_offset;
    unsigned short flags;
1148
    unsigned char fc = get_parameter_fc( var, is_return, &flags, &stack_size, &typestring_offset );
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162

    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 );
1163
    print_file( file, indent, "NdrFcShort(0x%x),	/* stack offset = %u */\n",
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
                *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;
}

1177
static unsigned int write_old_procformatstring_type(FILE *file, int indent, const var_t *var,
1178
                                                    int is_return, int is_interpreted)
1179
{
1180
    unsigned int size;
1181

1182 1183
    int is_in = is_attr(var->attrs, ATTR_IN);
    int is_out = is_attr(var->attrs, ATTR_OUT);
1184 1185

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

1187 1188
    if (type_get_type(var->type) == TYPE_BASIC ||
        type_get_type(var->type) == TYPE_ENUM)
1189
    {
1190 1191
        unsigned char fc;

1192 1193 1194 1195 1196
        if (is_return)
            print_file(file, indent, "0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
        else
            print_file(file, indent, "0x4e,    /* FC_IN_PARAM_BASETYPE */\n");

1197
        if (type_get_type(var->type) == TYPE_ENUM)
1198
        {
1199
            fc = get_enum_fc(var->type);
1200 1201 1202
        }
        else
        {
1203
            fc = get_basic_fc_signed(var->type);
1204 1205 1206

            if (fc == RPC_FC_BIND_PRIMITIVE)
                fc = RPC_FC_IGNORE;
1207
        }
1208 1209 1210 1211

        print_file(file, indent, "0x%02x,    /* %s */\n",
                   fc, string_of_type(fc));
        size = 2; /* includes param type prefix */
1212 1213 1214
    }
    else
    {
1215
        unsigned short offset = var->typestring_offset;
1216

1217
        if (!is_interpreted && is_array(var->type) &&
1218 1219
            type_array_is_decl_as_ptr(var->type) &&
            var->type->details.array.ptr_tfsoff)
1220
            offset = var->type->typestring_offset;
1221

1222 1223
        if (is_return)
            print_file(file, indent, "0x52,    /* FC_RETURN_PARAM */\n");
1224
        else if (is_in && is_out)
1225
            print_file(file, indent, "0x50,    /* FC_IN_OUT_PARAM */\n");
1226
        else if (is_out)
1227
            print_file(file, indent, "0x51,    /* FC_OUT_PARAM */\n");
1228 1229
        else
            print_file(file, indent, "0x4d,    /* FC_IN_PARAM */\n");
1230

1231
        size = get_stack_size( var, NULL );
1232
        print_file(file, indent, "0x%02x,\n", size / pointer_size );
1233
        print_file(file, indent, "NdrFcShort(0x%x),	/* type offset = %u */\n", offset, offset);
1234
        size = 4; /* includes param type prefix */
1235
    }
1236
    return size;
1237 1238
}

1239 1240 1241
int is_interpreted_func( const type_t *iface, const var_t *func )
{
    const char *str;
1242 1243
    const var_t *var;
    const var_list_t *args = type_get_function_args( func->type );
1244 1245
    const type_t *ret_type = type_function_get_rettype( func->type );

1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
    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;
        }
    }
1263
    if (get_stub_mode() != MODE_Oif && args)
1264
    {
1265
        LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
            switch (type_get_type( var->type ))
            {
            case TYPE_BASIC:
                switch (type_basic_get_type( var->type ))
                {
                /* 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;
            }
    }
1283

1284 1285
    if ((str = get_attrp( func->attrs, ATTR_OPTIMIZE ))) return !strcmp( str, "i" );
    if ((str = get_attrp( iface->attrs, ATTR_OPTIMIZE ))) return !strcmp( str, "i" );
1286
    return (get_stub_mode() != MODE_Os);
1287 1288
}

1289 1290 1291
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 )
1292
{
1293 1294 1295 1296 1297 1298 1299
    var_t *var;
    var_list_t *args = type_get_function_args( func->type );
    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 );
    unsigned char oi_flags = RPC_FC_PROC_OIF_RPCFLAGS | RPC_FC_PROC_OIF_NEWINIT;
    unsigned int rpc_flags = get_rpc_flags( func->attrs );
1300
    unsigned int nb_args = 0;
1301 1302 1303 1304 1305 1306 1307 1308 1309
    unsigned int stack_size = 0;
    unsigned short param_num = 0;
    unsigned short handle_stack_offset = 0;
    unsigned short handle_param_num = 0;

    if (is_full_pointer_function( func )) oi_flags |= RPC_FC_PROC_OIF_FULLPTR;
    if (is_object( iface ))
    {
        oi_flags |= RPC_FC_PROC_OIF_OBJECT;
1310
        if (get_stub_mode() == MODE_Oif) oi_flags |= RPC_FC_PROC_OIF_OBJ_V2;
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320
        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;
        }
1321
        stack_size += get_stack_size( var, NULL );
1322
        param_num++;
1323 1324 1325 1326 1327 1328
        nb_args++;
    }
    if (!is_void( type_function_get_rettype( func->type )))
    {
        stack_size += pointer_size;
        nb_args++;
1329 1330 1331 1332 1333 1334 1335 1336
    }

    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 );
1337
    print_file( file, indent, "NdrFcShort(0x%x),\t/* stack size = %u */\n", stack_size, stack_size );
1338 1339
    *offset += 10;

1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373
    if (!implicit_fc)
    {
        switch (explicit_fc)
        {
        case RPC_FC_BIND_PRIMITIVE:
            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;
        case RPC_FC_BIND_GENERIC:
            handle_flags = type_memsize( handle_var->type );
            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 );
            print_file( file, indent, "0x%02x,\n", get_generic_handle_offset( handle_var->type ) );
            print_file( file, indent, "0x%x,\t/* FC_PAD */\n", RPC_FC_PAD);
            *offset += 6;
            break;
        case RPC_FC_BIND_CONTEXT:
            handle_flags = get_contexthandle_flags( iface, handle_var->attrs, handle_var->type );
            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 );
            print_file( file, indent, "0x%02x,\n", get_context_handle_offset( handle_var->type ) );
            print_file( file, indent, "0x%02x,\t/* param %hu */\n", handle_param_num, handle_param_num );
            *offset += 6;
            break;
        }
    }
1374

1375
    if (get_stub_mode() == MODE_Oif)
1376
    {
1377 1378 1379 1380 1381 1382 1383 1384
        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 */

        size = get_function_buffer_size( func, PASS_IN );
1385
        print_file( file, indent, "NdrFcShort(0x%x),\t/* client buffer = %u */\n", size, size );
1386
        size = get_function_buffer_size( func, PASS_OUT );
1387
        print_file( file, indent, "NdrFcShort(0x%x),\t/* server buffer = %u */\n", size, size );
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
        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)
        {
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415
            unsigned short pos = 0, fpu_mask = 0;

            if (is_object( iface )) pos += 2;
            if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )
            {
                if (type_get_type( var->type ) == TYPE_BASIC)
                {
                    switch (type_basic_get_type( var->type ))
                    {
                    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 */
1416 1417
            *offset += 2;
        }
1418 1419 1420 1421 1422 1423 1424
    }
}

static void write_procformatstring_func( FILE *file, int indent, const type_t *iface,
                                         const var_t *func, unsigned int *offset,
                                         unsigned short num_proc )
{
1425
    unsigned int stack_offset = is_object( iface ) ? pointer_size : 0;
1426
    int is_interpreted = is_interpreted_func( iface, func );
1427
    int is_new_style = is_interpreted && (get_stub_mode() == MODE_Oif);
1428
    var_t *retval = type_function_get_retval( func->type );
1429 1430

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

1432 1433 1434 1435 1436 1437 1438
    /* emit argument data */
    if (type_get_function_args(func->type))
    {
        const var_t *var;
        LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
        {
            print_file( file, 0, "/* %u (parameter %s) */\n", *offset, var->name );
1439
            if (is_new_style)
1440
                *offset += write_new_procformatstring_type(file, indent, var, FALSE, &stack_offset);
1441
            else
1442
                *offset += write_old_procformatstring_type(file, indent, var, FALSE, is_interpreted);
1443 1444 1445 1446
        }
    }

    /* emit return value data */
1447
    if (is_void(retval->type))
1448
    {
1449 1450 1451
        if (!is_new_style)
        {
            print_file(file, 0, "/* %u (void) */\n", *offset);
1452 1453
            print_file(file, indent, "0x5b,\t/* FC_END */\n");
            print_file(file, indent, "0x5c,\t/* FC_PAD */\n");
1454 1455
            *offset += 2;
        }
1456 1457 1458 1459
    }
    else
    {
        print_file( file, 0, "/* %u (return value) */\n", *offset );
1460
        if (is_new_style)
1461
            *offset += write_new_procformatstring_type(file, indent, retval, TRUE, &stack_offset);
1462
        else
1463
            *offset += write_old_procformatstring_type(file, indent, retval, TRUE, is_interpreted);
1464 1465 1466
    }
}

1467 1468
static void write_procformatstring_stmts(FILE *file, int indent, const statement_list_t *stmts,
                                         type_pred_t pred, unsigned int *offset)
1469
{
1470 1471
    const statement_t *stmt;
    if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
1472
    {
1473
        if (stmt->type == STMT_TYPE && type_get_type(stmt->u.type) == TYPE_INTERFACE)
1474
        {
1475
            const statement_t *stmt_func;
1476 1477 1478 1479 1480 1481
            const type_t *iface = stmt->u.type;
            const type_t *parent = type_iface_get_inherit( iface );
            int count = parent ? count_methods( parent ) : 0;

            if (!pred(iface)) continue;
            STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(iface))
1482
            {
1483
                var_t *func = stmt_func->u.var;
1484
                if (is_local(func->attrs)) continue;
1485
                write_procformatstring_func( file, indent, iface, func, offset, count++ );
1486
            }
1487 1488
        }
    }
1489 1490 1491 1492 1493
}

void write_procformatstring(FILE *file, const statement_list_t *stmts, type_pred_t pred)
{
    int indent = 0;
1494
    unsigned int offset = 0;
1495 1496 1497 1498 1499 1500 1501 1502

    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++;

1503
    write_procformatstring_stmts(file, indent, stmts, pred, &offset);
1504 1505 1506 1507 1508 1509 1510 1511 1512

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

1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
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" );
}

1532
static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
1533
{
1534 1535 1536
    unsigned char fc;

    if (type_get_type(type) == TYPE_BASIC)
1537
        fc = get_basic_fc_signed(type);
1538 1539 1540 1541 1542 1543 1544 1545
    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;
1546 1547
}

1548
/* write conformance / variance descriptor */
1549
static unsigned int write_conf_or_var_desc(FILE *file, const type_t *cont_type,
1550 1551
                                           unsigned int baseoff, const type_t *type,
                                           const expr_t *expr)
1552
{
1553
    unsigned char operator_type = 0;
1554
    unsigned char conftype = RPC_FC_NORMAL_CONFORMANCE;
1555
    const char *conftype_string = "field";
1556
    const expr_t *subexpr;
1557 1558
    const type_t *iface = NULL;
    const char *name;
1559

1560 1561 1562 1563 1564 1565
    if (!expr)
    {
        print_file(file, 2, "NdrFcLong(0xffffffff),\t/* -1 */\n");
        return 4;
    }

1566 1567 1568
    if (expr->is_const)
    {
        if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
1569
            error("write_conf_or_var_desc: constant value %d is greater than "
1570 1571 1572
                  "the maximum constant size of %d\n", expr->cval,
                  UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);

1573
        print_file(file, 2, "0x%x, /* Corr desc: constant, val = %d */\n",
1574
                   RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
1575
        print_file(file, 2, "0x%x,\n", expr->cval >> 16);
1576
        print_file(file, 2, "NdrFcShort(0x%hx),\n", (unsigned short)expr->cval);
1577 1578 1579 1580

        return 4;
    }

1581
    if (!cont_type)  /* top-level conformance */
1582
    {
1583 1584 1585 1586 1587
        conftype = RPC_FC_TOP_LEVEL_CONFORMANCE;
        conftype_string = "parameter";
        cont_type = current_func->type;
        name = current_func->name;
        iface = current_iface;
1588
    }
1589
    else
1590
    {
1591 1592 1593 1594 1595 1596
        name = cont_type->name;
        if (is_ptr(type) || (is_array(type) && type_array_is_decl_as_ptr(type)))
        {
            conftype = RPC_FC_POINTER_CONFORMANCE;
            conftype_string = "field pointer";
        }
1597 1598
    }

1599
    subexpr = expr;
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
    switch (subexpr->type)
    {
    case EXPR_PPTR:
        subexpr = subexpr->ref;
        operator_type = RPC_FC_DEREFERENCE;
        break;
    case EXPR_DIV:
        if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
        {
            subexpr = subexpr->ref;
            operator_type = RPC_FC_DIV_2;
        }
        break;
    case EXPR_MUL:
        if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
        {
            subexpr = subexpr->ref;
            operator_type = RPC_FC_MULT_2;
        }
        break;
    case EXPR_SUB:
        if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
        {
            subexpr = subexpr->ref;
            operator_type = RPC_FC_SUB_1;
        }
        break;
    case EXPR_ADD:
        if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
        {
            subexpr = subexpr->ref;
            operator_type = RPC_FC_ADD_1;
        }
        break;
    default:
        break;
    }

    if (subexpr->type == EXPR_IDENTIFIER)
1639
    {
1640 1641
        const type_t *correlation_variable = NULL;
        unsigned char param_type = 0;
1642
        unsigned int offset = 0;
1643
        const var_t *var;
1644
        struct expr_loc expr_loc;
1645

1646
        if (type_get_type(cont_type) == TYPE_FUNCTION)
1647
        {
1648 1649 1650 1651
            var_list_t *args = type_get_function_args( cont_type );

            if (is_object( iface )) offset += pointer_size;
            if (args) LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
1652
            {
1653 1654 1655 1656 1657 1658
                if (var->name && !strcmp(var->name, subexpr->u.sval))
                {
                    expr_loc.v = var;
                    correlation_variable = var->type;
                    break;
                }
1659
                offset += get_stack_size( var, NULL );
1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675
            }
        }
        else
        {
            var_list_t *fields = type_struct_get_fields( cont_type );

            if (fields) LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
            {
                unsigned int size = field_memsize( var->type, &offset );
                if (var->name && !strcmp(var->name, subexpr->u.sval))
                {
                    expr_loc.v = var;
                    correlation_variable = var->type;
                    break;
                }
                offset += size;
1676
            }
1677
        }
1678

1679 1680 1681 1682
        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);
1683

1684
        offset -= baseoff;
1685

1686
        if (type_get_type(correlation_variable) == TYPE_BASIC)
1687
        {
1688
            switch (get_basic_fc(correlation_variable))
1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712
            {
            case RPC_FC_CHAR:
            case RPC_FC_SMALL:
                param_type = RPC_FC_SMALL;
                break;
            case RPC_FC_BYTE:
            case RPC_FC_USMALL:
                param_type = RPC_FC_USMALL;
                break;
            case RPC_FC_WCHAR:
            case RPC_FC_SHORT:
                param_type = RPC_FC_SHORT;
                break;
            case RPC_FC_USHORT:
                param_type = RPC_FC_USHORT;
                break;
            case RPC_FC_LONG:
                param_type = RPC_FC_LONG;
                break;
            case RPC_FC_ULONG:
                param_type = RPC_FC_ULONG;
                break;
            default:
                error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
1713
                      get_basic_fc(correlation_variable));
1714 1715 1716 1717 1718 1719 1720 1721 1722
            }
        }
        else if (type_get_type(correlation_variable) == TYPE_ENUM)
        {
            if (get_enum_fc(correlation_variable) == RPC_FC_ENUM32)
                param_type = RPC_FC_LONG;
            else
                param_type = RPC_FC_SHORT;
        }
1723 1724 1725 1726 1727 1728 1729
        else if (type_get_type(correlation_variable) == TYPE_POINTER)
        {
            if (pointer_size == 8)
                param_type = RPC_FC_HYPER;
            else
                param_type = RPC_FC_LONG;
        }
1730 1731 1732 1733 1734
        else
        {
            error("write_conf_or_var_desc: non-arithmetic type used as correlation variable %s\n",
                  subexpr->u.sval);
            return 0;
1735
        }
1736

1737 1738 1739
        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,
1740
                   operator_type ? string_of_type(operator_type) : "no operators");
1741
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* offset = %d */\n",
1742
                   (unsigned short)offset, offset);
1743
    }
1744
    else if (!iface || is_interpreted_func( iface, current_func ))
1745 1746
    {
        unsigned int callback_offset = 0;
1747 1748
        struct expr_eval_routine *eval;
        int found = 0;
1749

1750
        LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
1751
        {
1752 1753 1754 1755
            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) &&
1756
                 !compare_expr(eval->expr, expr)))
1757
            {
1758 1759
                found = 1;
                break;
1760
            }
1761
            callback_offset++;
1762
        }
1763 1764

        if (!found)
1765
        {
1766
            eval = xmalloc (sizeof(*eval));
1767 1768 1769
            eval->iface = iface;
            eval->cont_type = cont_type;
            eval->name = xstrdup( name );
1770
            eval->baseoff = baseoff;
1771 1772
            eval->expr = expr;
            list_add_tail (&expr_eval_routines, &eval->entry);
1773 1774
        }

1775 1776 1777
        if (callback_offset > USHRT_MAX)
            error("Maximum number of callback routines reached\n");

1778 1779
        print_file(file, 2, "0x%x,\t/* Corr desc: %s in %s */\n", conftype, conftype_string, name);
        print_file(file, 2, "0x%x,\t/* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
1780
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)callback_offset, callback_offset);
1781
    }
1782 1783 1784 1785 1786 1787
    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" );
    }
1788 1789 1790
    return 4;
}

1791 1792 1793 1794
/* 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;
1795
    unsigned int size = type_memsize_and_alignment( type, &align );
1796 1797 1798 1799 1800

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

1801
static unsigned int fields_memsize(const var_list_t *fields, unsigned int *align)
Robert Shearman's avatar
Robert Shearman committed
1802
{
1803
    unsigned int size = 0;
1804
    unsigned int max_align;
1805 1806 1807 1808
    const var_t *v;

    if (!fields) return 0;
    LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
1809 1810
    {
        unsigned int falign = 0;
1811
        unsigned int fsize = type_memsize_and_alignment(v->type, &falign);
1812
        if (*align < falign) *align = falign;
1813
        falign = clamp_align(falign);
1814
        size = ROUND_SIZE(size, falign);
1815 1816
        size += fsize;
    }
1817

1818
    max_align = clamp_align(*align);
1819 1820
    size = ROUND_SIZE(size, max_align);

Robert Shearman's avatar
Robert Shearman committed
1821 1822 1823
    return size;
}

1824
static unsigned int union_memsize(const var_list_t *fields, unsigned int *pmaxa)
1825
{
1826
    unsigned int size, maxs = 0;
1827 1828 1829 1830 1831 1832 1833 1834
    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 */
        if (v->type)
        {
1835
            size = type_memsize_and_alignment(v->type, &align);
1836 1837 1838 1839 1840 1841 1842 1843
            if (maxs < size) maxs = size;
            if (*pmaxa < align) *pmaxa = align;
        }
    }

    return maxs;
}

1844
static unsigned int type_memsize_and_alignment(const type_t *t, unsigned int *align)
Robert Shearman's avatar
Robert Shearman committed
1845
{
1846
    unsigned int size = 0;
Robert Shearman's avatar
Robert Shearman committed
1847

1848
    switch (type_get_type(t))
1849
    {
1850
    case TYPE_BASIC:
1851
        switch (get_basic_fc(t))
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877
        {
        case RPC_FC_BYTE:
        case RPC_FC_CHAR:
        case RPC_FC_USMALL:
        case RPC_FC_SMALL:
            size = 1;
            if (size > *align) *align = size;
            break;
        case RPC_FC_WCHAR:
        case RPC_FC_USHORT:
        case RPC_FC_SHORT:
            size = 2;
            if (size > *align) *align = size;
            break;
        case RPC_FC_ULONG:
        case RPC_FC_LONG:
        case RPC_FC_ERROR_STATUS_T:
        case RPC_FC_FLOAT:
            size = 4;
            if (size > *align) *align = size;
            break;
        case RPC_FC_HYPER:
        case RPC_FC_DOUBLE:
            size = 8;
            if (size > *align) *align = size;
            break;
1878 1879
        case RPC_FC_INT3264:
        case RPC_FC_UINT3264:
1880
        case RPC_FC_BIND_PRIMITIVE:
1881 1882 1883 1884
            assert( pointer_size );
            size = pointer_size;
            if (size > *align) *align = size;
            break;
1885
        default:
1886
            error("type_memsize: Unknown type 0x%x\n", get_basic_fc(t));
1887 1888
            size = 0;
        }
Robert Shearman's avatar
Robert Shearman committed
1889
        break;
1890 1891 1892
    case TYPE_ENUM:
        switch (get_enum_fc(t))
        {
1893
        case RPC_FC_ENUM16:
1894 1895 1896 1897 1898 1899 1900 1901
        case RPC_FC_ENUM32:
            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
1902
        break;
1903
    case TYPE_STRUCT:
1904
        size = fields_memsize(type_struct_get_fields(t), align);
1905
        break;
1906
    case TYPE_ENCAPSULATED_UNION:
1907 1908
        size = fields_memsize(type_encapsulated_union_get_fields(t), align);
        break;
1909
    case TYPE_UNION:
1910
        size = union_memsize(type_union_get_cases(t), align);
Robert Shearman's avatar
Robert Shearman committed
1911
        break;
1912 1913 1914 1915
    case TYPE_POINTER:
        assert( pointer_size );
        size = pointer_size;
        if (size > *align) *align = size;
1916
        break;
1917
    case TYPE_ARRAY:
1918
        if (!type_array_is_decl_as_ptr(t))
1919 1920 1921
        {
            if (is_conformant_array(t))
            {
1922
                type_memsize_and_alignment(type_array_get_element(t), align);
1923 1924 1925 1926
                size = 0;
            }
            else
                size = type_array_get_dim(t) *
1927
                    type_memsize_and_alignment(type_array_get_element(t), align);
1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941
        }
        else /* declared as a pointer */
        {
            assert( pointer_size );
            size = pointer_size;
            if (size > *align) *align = size;
        }
        break;
    case TYPE_INTERFACE:
    case TYPE_ALIAS:
    case TYPE_VOID:
    case TYPE_COCLASS:
    case TYPE_MODULE:
    case TYPE_FUNCTION:
1942
    case TYPE_BITFIELD:
1943 1944 1945
        /* 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
1946
         * checking restrictions (function, bitfield). */
1947
        assert(0);
Robert Shearman's avatar
Robert Shearman committed
1948 1949 1950 1951 1952
    }

    return size;
}

1953 1954 1955 1956 1957 1958
unsigned int type_memsize(const type_t *t)
{
    unsigned int align = 0;
    return type_memsize_and_alignment( t, &align );
}

1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052
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))
        {
        case RPC_FC_BYTE:
        case RPC_FC_CHAR:
        case RPC_FC_USMALL:
        case RPC_FC_SMALL:
            return 1;
        case RPC_FC_WCHAR:
        case RPC_FC_USHORT:
        case RPC_FC_SHORT:
            return 2;
        case RPC_FC_ULONG:
        case RPC_FC_LONG:
        case RPC_FC_ERROR_STATUS_T:
        case RPC_FC_FLOAT:
        case RPC_FC_INT3264:
        case RPC_FC_UINT3264:
            return 4;
        case RPC_FC_HYPER:
        case RPC_FC_DOUBLE:
            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))
        {
        case RPC_FC_ENUM16:
            return 2;
        case RPC_FC_ENUM32:
            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 )
        {
            if (!var->type) continue;
            align = type_buffer_alignment( var->type );
            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 )
        {
            if (!var->type) continue;
            align = type_buffer_alignment( var->type );
            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 )
        {
            if (!var->type) continue;
            align = type_buffer_alignment( var->type );
            if (max < align) max = align;
        }
        break;
    case TYPE_ARRAY:
        if (!type_array_is_decl_as_ptr(t))
            return type_buffer_alignment( type_array_get_element(t) );
        /* 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:
        /* 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;
}

2053
int is_full_pointer_function(const var_t *func)
2054 2055
{
    const var_t *var;
2056
    if (type_has_full_pointer(type_function_get_rettype(func->type), func->attrs, TRUE))
2057
        return TRUE;
2058
    if (!type_get_function_args(func->type))
2059
        return FALSE;
2060
    LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
2061
        if (type_has_full_pointer( var->type, var->attrs, TRUE ))
2062 2063 2064 2065
            return TRUE;
    return FALSE;
}

2066
void write_full_pointer_init(FILE *file, int indent, const var_t *func, int is_server)
2067
{
2068
    print_file(file, indent, "__frame->_StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,%s);\n",
2069 2070 2071 2072
                   is_server ? "XLAT_SERVER" : "XLAT_CLIENT");
    fprintf(file, "\n");
}

2073
void write_full_pointer_free(FILE *file, int indent, const var_t *func)
2074
{
2075
    print_file(file, indent, "NdrFullPointerXlatFree(__frame->_StubMsg.FullPtrXlatTables);\n");
2076 2077 2078
    fprintf(file, "\n");
}

2079 2080
static unsigned int write_nonsimple_pointer(FILE *file, const attr_list_t *attrs,
                                            const type_t *type,
2081
                                            enum type_context context,
2082 2083
                                            unsigned int offset,
                                            unsigned int *typeformat_offset)
2084
{
2085 2086 2087 2088 2089
    unsigned int start_offset = *typeformat_offset;
    short reloff = offset - (*typeformat_offset + 2);
    int in_attr, out_attr;
    int pointer_type;
    unsigned char flags = 0;
2090

2091
    pointer_type = get_pointer_fc_context(type, attrs, context);
2092 2093 2094 2095 2096 2097 2098 2099

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

    if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
        flags |= RPC_FC_P_ONSTACK;

2100 2101 2102 2103 2104 2105
    if (is_ptr(type))
    {
        type_t *ref = type_pointer_get_ref(type);
        if(is_declptr(ref) && !is_user_type(ref))
            flags |= RPC_FC_P_DEREF;
    }
2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123

    print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
               pointer_type,
               flags,
               string_of_type(pointer_type));
    if (file)
    {
        if (flags & RPC_FC_P_ONSTACK)
            fprintf(file, " [allocated_on_stack]");
        if (flags & RPC_FC_P_DEREF)
            fprintf(file, " [pointer_deref]");
        fprintf(file, " */\n");
    }

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

    return start_offset;
2124 2125
}

2126 2127
static unsigned int write_simple_pointer(FILE *file, const attr_list_t *attrs,
                                         const type_t *type, enum type_context context)
2128
{
2129 2130 2131
    unsigned char fc;
    unsigned char pointer_fc;
    const type_t *ref;
2132 2133 2134
    int in_attr = is_attr(attrs, ATTR_IN);
    int out_attr = is_attr(attrs, ATTR_OUT);
    unsigned char flags = RPC_FC_P_SIMPLEPOINTER;
2135

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

2141
    pointer_fc = get_pointer_fc_context(type, attrs, context);
2142 2143 2144 2145 2146

    ref = type_pointer_get_ref(type);
    if (type_get_type(ref) == TYPE_ENUM)
        fc = get_enum_fc(ref);
    else
2147
        fc = get_basic_fc(ref);
2148

2149 2150 2151 2152 2153 2154
    if (out_attr && !in_attr)
        flags |= RPC_FC_P_ONSTACK;

    print_file(file, 2, "0x%02x, 0x%x,\t/* %s %s[simple_pointer] */\n",
               pointer_fc, flags, string_of_type(pointer_fc),
               flags & RPC_FC_P_ONSTACK ? "[allocated_on_stack] " : "");
2155
    print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
2156 2157 2158 2159
    print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
    return 4;
}

2160 2161 2162 2163 2164 2165 2166
static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff)
{
    print_file(file, 0, "/* %u (", tfsoff);
    write_type_decl(file, t, NULL);
    print_file(file, 0, ") */\n");
}

2167
static unsigned int write_pointer_tfs(FILE *file, const attr_list_t *attrs,
2168
                                      type_t *type, unsigned int ref_offset,
2169
                                      enum type_context context,
2170
                                      unsigned int *typestring_offset)
2171
{
2172
    unsigned int offset = *typestring_offset;
2173
    type_t *ref = type_pointer_get_ref(type);
2174

2175
    print_start_tfs_comment(file, type, offset);
2176
    update_tfsoff(type, offset, file);
2177

2178 2179 2180 2181
    switch (typegen_detect_type(ref, attrs, TDT_ALL_TYPES))
    {
    case TGT_BASIC:
    case TGT_ENUM:
2182
        *typestring_offset += write_simple_pointer(file, attrs, type, context);
2183 2184
        break;
    default:
2185
        if (ref_offset)
2186
            write_nonsimple_pointer(file, attrs, type, context, ref_offset, typestring_offset);
2187 2188
        break;
    }
2189 2190 2191 2192

    return offset;
}

2193
static int processed(const type_t *type)
2194
{
2195
    return type->typestring_offset && !type->tfswrite;
2196 2197
}

2198 2199 2200 2201
static int user_type_has_variable_size(const type_t *t)
{
    if (is_ptr(t))
        return TRUE;
2202 2203 2204
    else if (type_get_type(t) == TYPE_STRUCT)
    {
        switch (get_struct_fc(t))
2205 2206 2207 2208 2209 2210 2211
        {
        case RPC_FC_PSTRUCT:
        case RPC_FC_CSTRUCT:
        case RPC_FC_CPSTRUCT:
        case RPC_FC_CVSTRUCT:
            return TRUE;
        }
2212
    }
2213 2214 2215 2216 2217
    /* 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;
}

2218
static unsigned int write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
2219
{
2220
    unsigned int start, absoff, flags;
2221
    const char *name = NULL;
2222
    type_t *utype = get_user_type(type, &name);
2223 2224
    unsigned int usize = type_memsize(utype);
    unsigned int ualign = type_buffer_alignment(utype);
2225
    unsigned int size = type_memsize(type);
2226 2227 2228
    unsigned short funoff = user_type_offset(name);
    short reloff;

2229 2230
    if (processed(type)) return type->typestring_offset;

2231 2232
    guard_rec(type);

2233 2234
    if(user_type_has_variable_size(utype)) usize = 0;

2235 2236
    if (type_get_type(utype) == TYPE_BASIC ||
        type_get_type(utype) == TYPE_ENUM)
2237
    {
2238 2239 2240 2241 2242
        unsigned char fc;

        if (type_get_type(utype) == TYPE_ENUM)
            fc = get_enum_fc(utype);
        else
2243
            fc = get_basic_fc(utype);
2244

2245
        absoff = *tfsoff;
2246
        print_start_tfs_comment(file, utype, absoff);
2247
        print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
2248 2249 2250 2251 2252 2253 2254 2255 2256 2257
        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;
    }

2258
    if (type_get_type(utype) == TYPE_POINTER && get_pointer_fc(utype, NULL, FALSE) == RPC_FC_RP)
2259
        flags = 0x40;
2260
    else if (type_get_type(utype) == TYPE_POINTER && get_pointer_fc(utype, NULL, FALSE) == RPC_FC_UP)
2261 2262 2263 2264
        flags = 0x80;
    else
        flags = 0;

2265 2266
    start = *tfsoff;
    update_tfsoff(type, start, file);
2267
    print_start_tfs_comment(file, type, start);
2268
    print_file(file, 2, "0x%x,\t/* FC_USER_MARSHAL */\n", RPC_FC_USER_MARSHAL);
2269
    print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
2270
               flags | (ualign - 1), ualign - 1, flags);
2271
    print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
2272 2273
    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);
2274 2275
    *tfsoff += 8;
    reloff = absoff - *tfsoff;
2276
    print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n", reloff, reloff, absoff);
2277
    *tfsoff += 2;
2278
    return start;
2279 2280
}

2281
static void write_member_type(FILE *file, const type_t *cont,
2282 2283 2284
                              int cont_is_complex, const attr_list_t *attrs,
                              const type_t *type, unsigned int *corroff,
                              unsigned int *tfsoff)
2285
{
2286
    if (is_embedded_complex(type) && !is_conformant_array(type))
2287
    {
2288
        unsigned int absoff;
2289 2290
        short reloff;

2291
        if (type_get_type(type) == TYPE_UNION && is_attr(attrs, ATTR_SWITCHIS))
2292 2293 2294 2295 2296 2297 2298 2299 2300
        {
            absoff = *corroff;
            *corroff += 8;
        }
        else
        {
            absoff = type->typestring_offset;
        }
        reloff = absoff - (*tfsoff + 2);
2301 2302

        print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
2303 2304 2305 2306
        /* 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");
2307
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
2308 2309 2310
                   reloff, reloff, absoff);
        *tfsoff += 4;
    }
2311
    else if (is_ptr(type) || is_conformant_array(type))
2312
    {
2313
        unsigned char fc = cont_is_complex ? RPC_FC_POINTER : RPC_FC_LONG;
2314
        print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
2315 2316
        *tfsoff += 1;
    }
2317
    else if (!write_base_type(file, type, tfsoff))
2318
        error("Unsupported member type %d\n", type_get_type(type));
2319 2320
}

2321
static void write_array_element_type(FILE *file, const attr_list_t *attrs, const type_t *type,
2322 2323 2324 2325 2326 2327 2328 2329 2330 2331
                                     int cont_is_complex, unsigned int *tfsoff)
{
    type_t *elem = type_array_get_element(type);

    if (!is_embedded_complex(elem) && is_ptr(elem))
    {
        type_t *ref = type_pointer_get_ref(elem);

        if (processed(ref))
        {
2332 2333
            write_nonsimple_pointer(file, NULL, elem, TYPE_CONTEXT_CONTAINER,
                                    ref->typestring_offset, tfsoff);
2334 2335
            return;
        }
2336
        if (cont_is_complex && is_string_type(attrs, elem))
2337 2338 2339 2340
        {
            write_string_tfs(file, NULL, elem, TYPE_CONTEXT_CONTAINER, NULL, tfsoff);
            return;
        }
2341 2342 2343
        if (!is_string_type(NULL, elem) &&
            (type_get_type(ref) == TYPE_BASIC || type_get_type(ref) == TYPE_ENUM))
        {
2344
            *tfsoff += write_simple_pointer(file, NULL, elem, TYPE_CONTEXT_CONTAINER);
2345 2346 2347
            return;
        }
    }
2348
    write_member_type(file, type, cont_is_complex, NULL, elem, NULL, tfsoff);
2349 2350
}

2351 2352 2353 2354
static void write_end(FILE *file, unsigned int *tfsoff)
{
    if (*tfsoff % 2 == 0)
    {
2355
        print_file(file, 2, "0x%x,\t/* FC_PAD */\n", RPC_FC_PAD);
2356 2357
        *tfsoff += 1;
    }
2358
    print_file(file, 2, "0x%x,\t/* FC_END */\n", RPC_FC_END);
2359 2360 2361
    *tfsoff += 1;
}

2362 2363 2364
static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
{
    unsigned int offset = 0;
2365
    var_list_t *fs = type_struct_get_fields(type);
2366 2367 2368 2369 2370
    var_t *f;

    if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
    {
        type_t *ft = f->type;
2371
        unsigned int size = field_memsize( ft, &offset );
2372
        if (type_get_type(ft) == TYPE_UNION && is_attr(f->attrs, ATTR_SWITCHIS))
2373
        {
2374
            short reloff;
2375
            unsigned int absoff = ft->typestring_offset;
2376 2377 2378
            if (is_attr(ft->attrs, ATTR_SWITCHTYPE))
                absoff += 8; /* we already have a corr descr, skip it */
            reloff = absoff - (*tfsoff + 6);
2379
            print_file(file, 0, "/* %d */\n", *tfsoff);
2380
            print_file(file, 2, "0x%x,\t/* FC_NON_ENCAPSULATED_UNION */\n", RPC_FC_NON_ENCAPSULATED_UNION);
2381
            print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", RPC_FC_LONG);
2382
            write_conf_or_var_desc(file, current_structure, offset, ft,
2383
                                   get_attrp(f->attrs, ATTR_SWITCHIS));
2384 2385
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
                       (unsigned short)reloff, reloff, absoff);
2386 2387
            *tfsoff += 8;
        }
2388
        offset += size;
2389 2390 2391
    }
}

2392 2393
static int write_pointer_description_offsets(
    FILE *file, const attr_list_t *attrs, type_t *type,
2394
    unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
2395 2396 2397 2398
    unsigned int *typestring_offset)
{
    int written = 0;

2399 2400
    if ((is_ptr(type) && type_get_type(type_pointer_get_ref(type)) != TYPE_INTERFACE) ||
        (is_array(type) && type_array_is_decl_as_ptr(type)))
2401 2402 2403
    {
        if (offset_in_memory && offset_in_buffer)
        {
2404
            unsigned int memsize;
2405

2406 2407 2408 2409 2410
            /* 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 */
2411 2412
            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);
2413

2414
            memsize = type_memsize(type);
2415 2416 2417 2418
            *offset_in_memory += memsize;
            /* increment these separately as in the case of conformant (varying)
             * structures these start at different values */
            *offset_in_buffer += memsize;
2419 2420 2421
        }
        *typestring_offset += 4;

2422 2423 2424 2425 2426
        if (is_ptr(type))
        {
            type_t *ref = type_pointer_get_ref(type);

            if (is_string_type(attrs, type))
2427
                write_string_tfs(file, attrs, type, TYPE_CONTEXT_CONTAINER, NULL, typestring_offset);
2428
            else if (processed(ref))
2429 2430
                write_nonsimple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER,
                                        ref->typestring_offset, typestring_offset);
2431
            else if (type_get_type(ref) == TYPE_BASIC || type_get_type(ref) == TYPE_ENUM)
2432
                *typestring_offset += write_simple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER);
2433 2434 2435
            else
                error("write_pointer_description_offsets: type format string unknown\n");
        }
2436
        else
2437 2438 2439 2440 2441 2442
        {
            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;
2443
            write_nonsimple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER, offset, typestring_offset);
2444
        }
2445 2446 2447 2448 2449

        return 1;
    }

    if (is_array(type))
2450
    {
2451
        return write_pointer_description_offsets(
2452 2453
            file, attrs, type_array_get_element(type), offset_in_memory,
            offset_in_buffer, typestring_offset);
2454 2455 2456 2457 2458
    }
    else if (is_non_complex_struct(type))
    {
        /* otherwise search for interesting fields to parse */
        const var_t *v;
2459
        LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
2460
        {
2461 2462
            if (offset_in_memory && offset_in_buffer)
            {
2463
                unsigned int padding;
2464 2465
                unsigned int align = 0;
                type_memsize_and_alignment(v->type, &align);
2466 2467 2468 2469
                padding = ROUNDING(*offset_in_memory, align);
                *offset_in_memory += padding;
                *offset_in_buffer += padding;
            }
2470 2471 2472
            written += write_pointer_description_offsets(
                file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
                typestring_offset);
2473
        }
2474
    }
2475 2476
    else
    {
2477 2478
        if (offset_in_memory && offset_in_buffer)
        {
2479
            unsigned int memsize = type_memsize(type);
2480 2481 2482 2483 2484
            *offset_in_memory += memsize;
            /* increment these separately as in the case of conformant (varying)
             * structures these start at different values */
            *offset_in_buffer += memsize;
        }
2485
    }
2486

2487 2488 2489
    return written;
}

2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515
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)))
    {
        print_file(file, 2, "0x%02x, /* FC_NO_REPEAT */\n", RPC_FC_NO_REPEAT);
        print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
        *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;
2516 2517
                unsigned int align = 0;
                type_memsize_and_alignment(v->type, &align);
2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528
                padding = ROUNDING(*offset_in_memory, align);
                *offset_in_memory += padding;
                *offset_in_buffer += padding;
            }
            written += write_no_repeat_pointer_descriptions(
                file, v->attrs, v->type,
                offset_in_memory, offset_in_buffer, typestring_offset);
        }
    }
    else
    {
2529
        unsigned int memsize = type_memsize(type);
2530 2531 2532 2533 2534 2535 2536 2537 2538
        *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;
}

2539 2540 2541 2542
/* 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,
2543
    unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
2544 2545 2546 2547
    unsigned int *typestring_offset)
{
    int pointer_count = 0;

2548 2549
    if (type_get_type(type) == TYPE_ARRAY &&
        !type_array_has_conformance(type) && !type_array_has_variance(type))
2550 2551 2552 2553 2554
    {
        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(
2555
            NULL, attrs, type_array_get_element(type), NULL, NULL, &temp);
2556 2557 2558
        if (pointer_count > 0)
        {
            unsigned int increment_size;
2559 2560
            unsigned int offset_of_array_pointer_mem = 0;
            unsigned int offset_of_array_pointer_buf = 0;
2561

2562
            increment_size = type_memsize(type_array_get_element(type));
2563 2564 2565

            print_file(file, 2, "0x%02x, /* FC_FIXED_REPEAT */\n", RPC_FC_FIXED_REPEAT);
            print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
2566 2567 2568 2569
            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);
2570 2571 2572 2573 2574 2575 2576
            *typestring_offset += 10;

            pointer_count = write_pointer_description_offsets(
                file, attrs, type, &offset_of_array_pointer_mem,
                &offset_of_array_pointer_buf, typestring_offset);
        }
    }
2577
    else if (type_get_type(type) == TYPE_STRUCT)
2578 2579
    {
        const var_t *v;
2580
        LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
2581
        {
2582 2583
            if (offset_in_memory && offset_in_buffer)
            {
2584
                unsigned int padding;
2585 2586
                unsigned int align = 0;
                type_memsize_and_alignment(v->type, &align);
2587 2588 2589 2590
                padding = ROUNDING(*offset_in_memory, align);
                *offset_in_memory += padding;
                *offset_in_buffer += padding;
            }
2591 2592 2593 2594 2595 2596 2597
            pointer_count += write_fixed_array_pointer_descriptions(
                file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
                typestring_offset);
        }
    }
    else
    {
2598 2599
        if (offset_in_memory && offset_in_buffer)
        {
2600
            unsigned int memsize;
2601
            memsize = type_memsize(type);
2602 2603 2604 2605 2606
            *offset_in_memory += memsize;
            /* increment these separately as in the case of conformant (varying)
             * structures these start at different values */
            *offset_in_buffer += memsize;
        }
2607 2608 2609 2610 2611 2612 2613 2614 2615
    }

    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,
2616
    unsigned int offset_in_memory, unsigned int *typestring_offset)
2617 2618 2619
{
    int pointer_count = 0;

2620
    if (is_conformant_array(type) && !type_array_has_variance(type))
2621 2622 2623 2624 2625
    {
        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(
2626
            NULL, attrs, type_array_get_element(type), NULL, NULL, &temp);
2627 2628 2629
        if (pointer_count > 0)
        {
            unsigned int increment_size;
2630 2631
            unsigned int offset_of_array_pointer_mem = offset_in_memory;
            unsigned int offset_of_array_pointer_buf = offset_in_memory;
2632

2633
            increment_size = type_memsize(type_array_get_element(type));
2634 2635 2636 2637 2638 2639

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

            print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
            print_file(file, 2, "0x%02x, /* FC_FIXED_OFFSET */\n", RPC_FC_FIXED_OFFSET);
2640 2641 2642
            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);
2643 2644 2645
            *typestring_offset += 8;

            pointer_count = write_pointer_description_offsets(
2646 2647 2648
                file, attrs, type_array_get_element(type),
                &offset_of_array_pointer_mem, &offset_of_array_pointer_buf,
                typestring_offset);
2649 2650 2651 2652 2653 2654 2655 2656 2657 2658
        }
    }

    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,
2659
    unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
2660 2661 2662 2663
    unsigned int *typestring_offset)
{
    int pointer_count = 0;

2664
    if (is_array(type) && type_array_has_variance(type))
2665 2666 2667 2668 2669
    {
        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(
2670
            NULL, attrs, type_array_get_element(type), NULL, NULL, &temp);
2671 2672 2673 2674
        if (pointer_count > 0)
        {
            unsigned int increment_size;

2675
            increment_size = type_memsize(type_array_get_element(type));
2676 2677 2678 2679 2680 2681

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

            print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
            print_file(file, 2, "0x%02x, /* FC_VARIABLE_OFFSET */\n", RPC_FC_VARIABLE_OFFSET);
2682 2683 2684
            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);
2685 2686 2687
            *typestring_offset += 8;

            pointer_count = write_pointer_description_offsets(
2688
                file, attrs, type_array_get_element(type), offset_in_memory,
2689
                offset_in_buffer, typestring_offset);
2690 2691
        }
    }
2692
    else if (type_get_type(type) == TYPE_STRUCT)
2693 2694
    {
        const var_t *v;
2695
        LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
2696
        {
2697 2698
            if (offset_in_memory && offset_in_buffer)
            {
2699
                unsigned int align = 0, padding;
2700

2701
                if (is_array(v->type) && type_array_has_variance(v->type))
2702 2703 2704 2705 2706 2707
                {
                    *offset_in_buffer = ROUND_SIZE(*offset_in_buffer, 4);
                    /* skip over variance and offset in buffer */
                    *offset_in_buffer += 8;
                }

2708
                type_memsize_and_alignment(v->type, &align);
2709 2710 2711 2712
                padding = ROUNDING(*offset_in_memory, align);
                *offset_in_memory += padding;
                *offset_in_buffer += padding;
            }
2713 2714 2715 2716 2717 2718 2719
            pointer_count += write_varying_array_pointer_descriptions(
                file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
                typestring_offset);
        }
    }
    else
    {
2720 2721
        if (offset_in_memory && offset_in_buffer)
        {
2722
            unsigned int memsize = type_memsize(type);
2723 2724 2725 2726 2727
            *offset_in_memory += memsize;
            /* increment these separately as in the case of conformant (varying)
             * structures these start at different values */
            *offset_in_buffer += memsize;
        }
2728 2729 2730 2731 2732
    }

    return pointer_count;
}

2733
static void write_pointer_description(FILE *file, const attr_list_t *attrs, type_t *type,
2734 2735
                                      unsigned int *typestring_offset)
{
2736 2737
    unsigned int offset_in_buffer;
    unsigned int offset_in_memory;
2738 2739 2740

    /* pass 1: search for single instance of a pointer (i.e. don't descend
     * into arrays) */
2741 2742 2743
    if (!is_array(type))
    {
        offset_in_memory = 0;
2744
        offset_in_buffer = 0;
2745
        write_no_repeat_pointer_descriptions(
2746
            file, NULL, type,
2747 2748
            &offset_in_memory, &offset_in_buffer, typestring_offset);
    }
2749 2750 2751

    /* pass 2: search for pointers in fixed arrays */
    offset_in_memory = 0;
2752
    offset_in_buffer = 0;
2753 2754 2755 2756 2757 2758
    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) */
2759 2760
    if (is_conformant_array(type) &&
        (type_array_is_decl_as_ptr(type) || !current_structure))
2761
        write_conformant_array_pointer_descriptions(
2762
            file, attrs, type, 0, typestring_offset);
2763 2764
    else if (type_get_type(type) == TYPE_STRUCT &&
             get_struct_fc(type) == RPC_FC_CPSTRUCT)
2765 2766
    {
        type_t *carray = find_array_or_string_in_struct(type)->type;
2767 2768
        write_conformant_array_pointer_descriptions( file, NULL, carray,
                                                     type_memsize(type), typestring_offset);
2769
    }
2770

2771
    /* pass 4: search for pointers in varying arrays */
2772
    offset_in_memory = 0;
2773
    offset_in_buffer = 0;
2774 2775 2776
    write_varying_array_pointer_descriptions(
            file, NULL, type,
            &offset_in_memory, &offset_in_buffer, typestring_offset);
2777 2778
}

2779
static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
2780
                                     type_t *type, enum type_context context,
2781
                                     const char *name, unsigned int *typestring_offset)
2782
{
2783
    unsigned int start_offset;
2784
    unsigned char rtype;
2785
    type_t *elem_type;
2786
    int is_processed = processed(type);
2787

2788 2789
    start_offset = *typestring_offset;

2790
    if (is_declptr(type))
2791
    {
2792
        unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER;
2793
        int pointer_type = get_pointer_fc_context(type, attrs, context);
2794 2795
        if (!pointer_type)
            pointer_type = RPC_FC_RP;
2796
        print_start_tfs_comment(file, type, *typestring_offset);
2797 2798 2799 2800 2801 2802 2803 2804 2805
        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;
        }
2806
        is_processed = FALSE;
2807
    }
2808

2809
    if (is_array(type))
2810
        elem_type = type_array_get_element(type);
2811
    else
2812
        elem_type = type_pointer_get_ref(type);
2813

2814 2815 2816
    if (type_get_type(elem_type) == TYPE_POINTER && is_array(type))
        return write_array_tfs(file, attrs, type, name, typestring_offset);

2817 2818 2819 2820 2821 2822
    if (type_get_type(elem_type) != TYPE_BASIC)
    {
        error("write_string_tfs: Unimplemented for non-basic type %s\n", name);
        return start_offset;
    }

2823
    rtype = get_basic_fc(elem_type);
2824
    if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR))
Robert Shearman's avatar
Robert Shearman committed
2825
    {
2826
        error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
2827
        return start_offset;
Robert Shearman's avatar
Robert Shearman committed
2828 2829
    }

2830
    if (type_get_type(type) == TYPE_ARRAY && !type_array_has_conformance(type))
Robert Shearman's avatar
Robert Shearman committed
2831
    {
2832
        unsigned int dim = type_array_get_dim(type);
2833

2834 2835
        if (is_processed) return start_offset;

2836
        /* FIXME: multi-dimensional array */
2837 2838
        if (0xffffu < dim)
            error("array size for parameter %s exceeds %u bytes by %u bytes\n",
2839
                  name, 0xffffu, dim - 0xffffu);
Robert Shearman's avatar
Robert Shearman committed
2840

2841
        if (rtype == RPC_FC_WCHAR)
2842
            WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
2843 2844
        else
            WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
2845
        print_file(file, 2, "0x%x,\t/* FC_PAD */\n", RPC_FC_PAD);
2846
        *typestring_offset += 2;
Robert Shearman's avatar
Robert Shearman committed
2847

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

2851
        update_tfsoff(type, start_offset, file);
2852
        return start_offset;
Robert Shearman's avatar
Robert Shearman committed
2853
    }
2854
    else if (is_conformant_array(type))
Robert Shearman's avatar
Robert Shearman committed
2855
    {
2856
        if (rtype == RPC_FC_WCHAR)
2857
            WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
2858 2859
        else
            WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
2860
        print_file(file, 2, "0x%x,\t/* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
2861
        *typestring_offset += 2;
Robert Shearman's avatar
Robert Shearman committed
2862

2863
        *typestring_offset += write_conf_or_var_desc(
2864
            file, current_structure,
2865
            (!type_array_is_decl_as_ptr(type) && current_structure
2866
             ? type_memsize(current_structure)
2867
             : 0),
2868
            type, type_array_get_conformance(type));
2869

2870
        update_tfsoff(type, start_offset, file);
2871
        return start_offset;
Robert Shearman's avatar
Robert Shearman committed
2872 2873 2874
    }
    else
    {
2875 2876
        if (is_processed) return start_offset;

2877
        if (rtype == RPC_FC_WCHAR)
2878
            WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
2879 2880
        else
            WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
2881
        print_file(file, 2, "0x%x,\t/* FC_PAD */\n", RPC_FC_PAD);
2882
        *typestring_offset += 2;
Robert Shearman's avatar
Robert Shearman committed
2883

2884
        update_tfsoff(type, start_offset, file);
2885
        return start_offset;
Robert Shearman's avatar
Robert Shearman committed
2886
    }
2887 2888
}

2889 2890
static unsigned int write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
                                    const char *name, unsigned int *typestring_offset)
2891
{
2892 2893
    const expr_t *length_is = type_array_get_variance(type);
    const expr_t *size_is = type_array_get_conformance(type);
2894
    unsigned int align;
2895 2896
    unsigned int size;
    unsigned int start_offset;
2897
    unsigned char fc;
2898
    int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
2899
    unsigned int baseoff
2900
        = !type_array_is_decl_as_ptr(type) && current_structure
2901
        ? type_memsize(current_structure)
2902 2903
        : 0;

2904 2905 2906
    if (!pointer_type)
        pointer_type = RPC_FC_RP;

2907 2908
    if (!is_string_type(attrs, type_array_get_element(type)))
        write_embedded_types(file, attrs, type_array_get_element(type), name, FALSE, typestring_offset);
Robert Shearman's avatar
Robert Shearman committed
2909

2910 2911
    size = type_memsize(is_conformant_array(type) ? type_array_get_element(type) : type);
    align = type_buffer_alignment(is_conformant_array(type) ? type_array_get_element(type) : type);
2912
    fc = get_array_fc(type);
2913

2914 2915
    start_offset = *typestring_offset;
    update_tfsoff(type, start_offset, file);
2916
    print_start_tfs_comment(file, type, start_offset);
2917
    print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
2918 2919
    print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
    *typestring_offset += 2;
2920

2921
    align = 0;
2922
    if (fc != RPC_FC_BOGUS_ARRAY)
2923
    {
2924
        if (fc == RPC_FC_LGFARRAY || fc == RPC_FC_LGVARRAY)
Robert Shearman's avatar
Robert Shearman committed
2925
        {
2926
            print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", size, size);
2927
            *typestring_offset += 4;
Robert Shearman's avatar
Robert Shearman committed
2928
        }
2929
        else
Robert Shearman's avatar
Robert Shearman committed
2930
        {
2931
            print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)size, size);
2932
            *typestring_offset += 2;
2933
        }
Robert Shearman's avatar
Robert Shearman committed
2934

2935 2936
        if (is_conformant_array(type))
            *typestring_offset
2937
                += write_conf_or_var_desc(file, current_structure, baseoff,
2938
                                          type, size_is);
Robert Shearman's avatar
Robert Shearman committed
2939

2940
        if (fc == RPC_FC_SMVARRAY || fc == RPC_FC_LGVARRAY)
Robert Shearman's avatar
Robert Shearman committed
2941
        {
2942
            unsigned int elsize = type_memsize(type_array_get_element(type));
2943
            unsigned int dim = type_array_get_dim(type);
2944

2945
            if (fc == RPC_FC_LGVARRAY)
2946
            {
2947
                print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", dim, dim);
2948
                *typestring_offset += 4;
2949
            }
2950
            else
2951
            {
2952
                print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)dim, dim);
2953
                *typestring_offset += 2;
2954
            }
Robert Shearman's avatar
Robert Shearman committed
2955

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

2960 2961
        if (length_is)
            *typestring_offset
2962
                += write_conf_or_var_desc(file, current_structure, baseoff,
2963
                                          type, length_is);
2964

2965 2966
        if (type_has_pointers(type_array_get_element(type)) &&
            (type_array_is_decl_as_ptr(type) || !current_structure))
2967
        {
2968 2969
            print_file(file, 2, "0x%x,\t/* FC_PP */\n", RPC_FC_PP);
            print_file(file, 2, "0x%x,\t/* FC_PAD */\n", RPC_FC_PAD);
2970
            *typestring_offset += 2;
2971
            write_pointer_description(file, is_string_type(attrs, type) ? attrs : NULL, type, typestring_offset);
2972
            print_file(file, 2, "0x%x,\t/* FC_END */\n", RPC_FC_END);
2973
            *typestring_offset += 1;
Robert Shearman's avatar
Robert Shearman committed
2974
        }
2975

2976
        write_array_element_type(file, is_string_type(attrs, type) ? attrs : NULL, type, FALSE, typestring_offset);
2977
        write_end(file, typestring_offset);
Robert Shearman's avatar
Robert Shearman committed
2978
    }
2979
    else
2980
    {
2981
        unsigned int dim = size_is ? 0 : type_array_get_dim(type);
2982
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)dim, dim);
2983 2984 2985
        *typestring_offset += 2;
        *typestring_offset
            += write_conf_or_var_desc(file, current_structure, baseoff,
2986
                                      type, size_is);
2987 2988
        *typestring_offset
            += write_conf_or_var_desc(file, current_structure, baseoff,
2989
                                      type, length_is);
2990

2991
        write_array_element_type(file, is_string_type(attrs, type) ? attrs : NULL, type, TRUE, typestring_offset);
2992 2993
        write_end(file, typestring_offset);
    }
2994 2995

    return start_offset;
2996
}
2997

2998
static const var_t *find_array_or_string_in_struct(const type_t *type)
2999
{
3000
    const var_list_t *fields = type_struct_get_fields(type);
3001 3002 3003
    const var_t *last_field;
    const type_t *ft;

3004
    if (!fields || list_empty(fields))
3005 3006
        return NULL;

3007
    last_field = LIST_ENTRY( list_tail(fields), const var_t, entry );
3008
    ft = last_field->type;
3009

3010
    if (is_conformant_array(ft) && !type_array_is_decl_as_ptr(ft))
3011 3012
        return last_field;

3013
    if (type_get_type(ft) == TYPE_STRUCT)
3014
        return find_array_or_string_in_struct(ft);
3015 3016
    else
        return NULL;
3017 3018
}

3019
static void write_struct_members(FILE *file, const type_t *type,
3020 3021
                                 int is_complex, unsigned int *corroff,
                                 unsigned int *typestring_offset)
3022
{
3023
    const var_t *field;
3024
    unsigned short offset = 0;
3025
    unsigned int salign = 1;
3026
    int padding;
3027
    var_list_t *fields = type_struct_get_fields(type);
3028

3029
    if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
3030 3031
    {
        type_t *ft = field->type;
3032
        unsigned int align = 0;
3033
        unsigned int size = type_memsize_and_alignment(ft, &align);
3034
        align = clamp_align(align);
3035 3036
        if (salign < align) salign = align;

3037
        if (!is_conformant_array(ft) || type_array_is_decl_as_ptr(ft))
3038 3039 3040 3041 3042 3043
        {
            if ((align - 1) & offset)
            {
                unsigned char fc = 0;
                switch (align)
                {
3044 3045 3046
                case 2:
                    fc = RPC_FC_ALIGNM2;
                    break;
3047 3048 3049 3050 3051 3052 3053
                case 4:
                    fc = RPC_FC_ALIGNM4;
                    break;
                case 8:
                    fc = RPC_FC_ALIGNM8;
                    break;
                default:
3054
                    error("write_struct_members: cannot align type %d\n", type_get_type(ft));
3055 3056
                }
                print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
3057
                offset = ROUND_SIZE(offset, align);
3058 3059
                *typestring_offset += 1;
            }
3060
            write_member_type(file, type, is_complex, field->attrs, field->type, corroff,
3061
                              typestring_offset);
3062 3063
            offset += size;
        }
3064
    }
3065

3066
    padding = ROUNDING(offset, salign);
3067 3068 3069 3070 3071 3072 3073 3074
    if (padding)
    {
        print_file(file, 2, "0x%x,\t/* FC_STRUCTPAD%d */\n",
                   RPC_FC_STRUCTPAD1 + padding - 1,
                   padding);
        *typestring_offset += 1;
    }

3075
    write_end(file, typestring_offset);
3076 3077
}

3078 3079
static unsigned int write_struct_tfs(FILE *file, type_t *type,
                                     const char *name, unsigned int *tfsoff)
3080
{
3081
    const type_t *save_current_structure = current_structure;
3082
    unsigned int total_size;
3083
    const var_t *array;
3084
    unsigned int start_offset;
3085
    unsigned int align;
3086 3087
    unsigned int corroff;
    var_t *f;
3088
    unsigned char fc = get_struct_fc(type);
3089
    var_list_t *fields = type_struct_get_fields(type);
3090

3091 3092
    if (processed(type)) return type->typestring_offset;

3093
    guard_rec(type);
3094
    current_structure = type;
3095

3096 3097
    total_size = type_memsize(type);
    align = type_buffer_alignment(type);
3098 3099 3100
    if (total_size > USHRT_MAX)
        error("structure size for %s exceeds %d bytes by %d bytes\n",
              name, USHRT_MAX, total_size - USHRT_MAX);
3101

3102
    if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
3103
        write_embedded_types(file, f->attrs, f->type, f->name, FALSE, tfsoff);
3104

3105 3106
    array = find_array_or_string_in_struct(type);
    if (array && !processed(array->type))
3107 3108
    {
        if(is_string_type(array->attrs, array->type))
3109
            write_string_tfs(file, array->attrs, array->type, TYPE_CONTEXT_CONTAINER, array->name, tfsoff);
3110 3111 3112
        else
            write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
    }
3113 3114 3115

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

3117 3118
    start_offset = *tfsoff;
    update_tfsoff(type, start_offset, file);
3119
    print_start_tfs_comment(file, type, start_offset);
3120
    print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
3121
    print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
3122
    print_file(file, 2, "NdrFcShort(0x%hx),\t/* %d */\n", (unsigned short)total_size, total_size);
3123
    *tfsoff += 4;
3124

3125 3126 3127 3128
    if (array)
    {
        unsigned int absoff = array->type->typestring_offset;
        short reloff = absoff - *tfsoff;
3129
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
3130 3131 3132
                   reloff, reloff, absoff);
        *tfsoff += 2;
    }
3133
    else if (fc == RPC_FC_BOGUS_STRUCT)
3134 3135 3136 3137
    {
        print_file(file, 2, "NdrFcShort(0x0),\n");
        *tfsoff += 2;
    }
3138

3139
    if (fc == RPC_FC_BOGUS_STRUCT)
3140
    {
3141 3142 3143
        /* 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.  */
3144
        unsigned int absoff = type->ptrdesc ? type->ptrdesc : *tfsoff;
3145 3146
        int reloff = absoff - *tfsoff;
        assert( reloff >= 0 );
3147
        print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %d (%u) */\n",
3148
                   (unsigned short)reloff, reloff, absoff);
3149 3150
        *tfsoff += 2;
    }
3151 3152
    else if ((fc == RPC_FC_PSTRUCT) ||
             (fc == RPC_FC_CPSTRUCT) ||
3153
             (fc == RPC_FC_CVSTRUCT && type_has_pointers(type)))
3154
    {
3155 3156
        print_file(file, 2, "0x%x,\t/* FC_PP */\n", RPC_FC_PP);
        print_file(file, 2, "0x%x,\t/* FC_PAD */\n", RPC_FC_PAD);
3157
        *tfsoff += 2;
3158
        write_pointer_description(file, NULL, type, tfsoff);
3159
        print_file(file, 2, "0x%x,\t/* FC_END */\n", RPC_FC_END);
3160 3161
        *tfsoff += 1;
    }
3162

3163 3164
    write_struct_members(file, type, fc == RPC_FC_BOGUS_STRUCT, &corroff,
                         tfsoff);
3165

3166
    if (fc == RPC_FC_BOGUS_STRUCT)
3167 3168 3169
    {
        const var_t *f;

3170
        type->ptrdesc = *tfsoff;
3171
        if (fields) LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry)
3172 3173
        {
            type_t *ft = f->type;
3174
            switch (typegen_detect_type(ft, f->attrs, TDT_IGNORE_STRINGS))
3175
            {
3176
            case TGT_POINTER:
3177
                if (is_string_type(f->attrs, ft))
3178
                    write_string_tfs(file, f->attrs, ft, TYPE_CONTEXT_CONTAINER, f->name, tfsoff);
3179
                else
3180 3181
                    write_pointer_tfs(file, f->attrs, ft,
                                      type_pointer_get_ref(ft)->typestring_offset,
3182
                                      TYPE_CONTEXT_CONTAINER, tfsoff);
3183 3184 3185 3186 3187
                break;
            case TGT_ARRAY:
                if (type_array_is_decl_as_ptr(ft))
                {
                    unsigned int offset;
3188

3189
                    print_file(file, 0, "/* %d */\n", *tfsoff);
3190

3191 3192 3193 3194 3195
                    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;
3196
                    write_nonsimple_pointer(file, f->attrs, ft, TYPE_CONTEXT_CONTAINER, offset, tfsoff);
3197 3198 3199 3200
                }
                break;
            default:
                break;
3201
            }
3202
        }
3203 3204
        if (type->ptrdesc == *tfsoff)
            type->ptrdesc = 0;
3205 3206
    }

3207
    current_structure = save_current_structure;
3208
    return start_offset;
3209 3210
}

3211
static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
3212
{
3213 3214 3215 3216
    if (t == NULL)
    {
        print_file(file, 2, "NdrFcShort(0x0),\t/* No type */\n");
    }
3217
    else
3218
    {
3219 3220 3221 3222
        if (type_get_type(t) == TYPE_BASIC || type_get_type(t) == TYPE_ENUM)
        {
            unsigned char fc;
            if (type_get_type(t) == TYPE_BASIC)
3223
                fc = get_basic_fc(t);
3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236
            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));
3237 3238 3239 3240 3241
    }

    *tfsoff += 2;
}

3242 3243
static unsigned int write_union_tfs(FILE *file, const attr_list_t *attrs,
                                    type_t *type, unsigned int *tfsoff)
3244
{
3245
    unsigned int start_offset;
3246
    unsigned int size;
3247
    var_list_t *fields;
3248
    unsigned int nbranch = 0;
3249 3250 3251 3252
    type_t *deftype = NULL;
    short nodeftype = 0xffff;
    var_t *f;

3253 3254 3255 3256
    if (processed(type) &&
        (type_get_type(type) == TYPE_ENCAPSULATED_UNION || !is_attr(type->attrs, ATTR_SWITCHTYPE)))
        return type->typestring_offset;

3257 3258
    guard_rec(type);

3259
    size = type_memsize(type);
3260

3261
    fields = type_union_get_cases(type);
3262

3263 3264 3265 3266 3267
    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);
3268 3269
        if (f->type)
            write_embedded_types(file, f->attrs, f->type, f->name, TRUE, tfsoff);
3270 3271 3272
    }

    start_offset = *tfsoff;
3273
    update_tfsoff(type, start_offset, file);
3274
    print_start_tfs_comment(file, type, start_offset);
3275
    if (type_get_type(type) == TYPE_ENCAPSULATED_UNION)
3276
    {
3277
        const var_t *sv = type_union_get_switch_value(type);
3278
        const type_t *st = sv->type;
3279
        unsigned char fc;
3280

3281
        if (type_get_type(st) == TYPE_BASIC)
3282
        {
3283 3284
            fc = get_basic_fc(st);
            switch (fc)
3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299
            {
            case RPC_FC_CHAR:
            case RPC_FC_SMALL:
            case RPC_FC_BYTE:
            case RPC_FC_USMALL:
            case RPC_FC_WCHAR:
            case RPC_FC_SHORT:
            case RPC_FC_USHORT:
            case RPC_FC_LONG:
            case RPC_FC_ULONG:
                break;
            default:
                fc = 0;
                error("union switch type must be an integer, char, or enum\n");
            }
3300
        }
3301 3302 3303 3304 3305 3306 3307 3308 3309
        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");

        print_file(file, 2, "0x%x,\t/* FC_ENCAPSULATED_UNION */\n", RPC_FC_ENCAPSULATED_UNION);
        print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
                   0x40 | fc, string_of_type(fc));
        *tfsoff += 2;
3310
    }
3311 3312
    else if (is_attr(type->attrs, ATTR_SWITCHTYPE))
    {
3313
        const expr_t *switch_is = get_attrp(attrs, ATTR_SWITCHIS);
3314
        const type_t *st = get_attrp(type->attrs, ATTR_SWITCHTYPE);
3315
        unsigned char fc;
3316

3317
        if (type_get_type(st) == TYPE_BASIC)
3318
        {
3319 3320
            fc = get_basic_fc(st);
            switch (fc)
3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335
            {
            case RPC_FC_CHAR:
            case RPC_FC_SMALL:
            case RPC_FC_USMALL:
            case RPC_FC_SHORT:
            case RPC_FC_USHORT:
            case RPC_FC_LONG:
            case RPC_FC_ULONG:
            case RPC_FC_ENUM16:
            case RPC_FC_ENUM32:
                break;
            default:
                fc = 0;
                error("union switch type must be an integer, char, or enum\n");
            }
3336
        }
3337 3338 3339 3340 3341 3342 3343 3344 3345
        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");

        print_file(file, 2, "0x%x,\t/* FC_NON_ENCAPSULATED_UNION */\n", RPC_FC_NON_ENCAPSULATED_UNION);
        print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
                   fc, string_of_type(fc));
        *tfsoff += 2;
3346
        *tfsoff += write_conf_or_var_desc(file, current_structure, 0, st, switch_is );
3347 3348
        print_file(file, 2, "NdrFcShort(0x2),\t/* Offset= 2 (%u) */\n", *tfsoff + 2);
        *tfsoff += 2;
3349
        print_file(file, 0, "/* %u */\n", *tfsoff);
3350 3351
    }

3352 3353
    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);
3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370
    *tfsoff += 4;

    if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
    {
        type_t *ft = f->type;
        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.  */
3371
            print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391
            *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
    {
3392
        print_file(file, 2, "NdrFcShort(0x%hx),\n", nodeftype);
3393 3394 3395 3396
        *tfsoff += 2;
    }

    return start_offset;
3397 3398
}

3399 3400
static unsigned int write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
                                 unsigned int *typeformat_offset)
3401
{
3402 3403
    unsigned int i;
    unsigned int start_offset = *typeformat_offset;
3404
    expr_t *iid = get_attrp(attrs, ATTR_IIDIS);
3405

3406 3407
    if (!iid && processed(type)) return type->typestring_offset;

3408
    print_start_tfs_comment(file, type, start_offset);
3409
    update_tfsoff(type, start_offset, file);
3410

3411 3412 3413 3414
    if (iid)
    {
        print_file(file, 2, "0x2f,  /* FC_IP */\n");
        print_file(file, 2, "0x5c,  /* FC_PAD */\n");
3415
        *typeformat_offset
3416
            += write_conf_or_var_desc(file, current_structure, 0, type, iid) + 2;
3417 3418 3419
    }
    else
    {
3420
        const type_t *base = is_ptr(type) ? type_pointer_get_ref(type) : type;
3421
        const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
3422

3423 3424
        if (! uuid)
            error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
3425

3426 3427
        print_file(file, 2, "0x2f,\t/* FC_IP */\n");
        print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
3428
        print_file(file, 2, "NdrFcLong(0x%08x),\n", uuid->Data1);
3429 3430 3431 3432 3433 3434 3435
        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");
3436

3437 3438
        *typeformat_offset += 18;
    }
3439 3440 3441
    return start_offset;
}

3442 3443
static unsigned int write_contexthandle_tfs(FILE *file,
                                            const attr_list_t *attrs,
3444 3445
                                            type_t *type,
                                            int toplevel_param,
3446
                                            unsigned int *typeformat_offset)
3447
{
3448
    unsigned int start_offset = *typeformat_offset;
3449
    unsigned char flags = get_contexthandle_flags( current_iface, attrs, type );
3450

3451
    print_start_tfs_comment(file, type, start_offset);
3452

3453
    if (flags & 0x80)  /* via ptr */
3454
    {
3455 3456 3457 3458 3459 3460
        int pointer_type = get_pointer_fc( type, attrs, toplevel_param );
        if (!pointer_type) pointer_type = RPC_FC_RP;
        *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);
3461
    }
3462

3463
    print_file(file, 2, "0x%02x,\t/* FC_BIND_CONTEXT */\n", RPC_FC_BIND_CONTEXT);
3464
    print_file(file, 2, "0x%x,\t/* Context flags: ", flags);
3465 3466
    /* return and can't be null values overlap */
    if (((flags & 0x21) != 0x21) && (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL))
3467
        print_file(file, 0, "can't be null, ");
3468
    if (flags & NDR_CONTEXT_HANDLE_SERIALIZE)
3469
        print_file(file, 0, "serialize, ");
3470
    if (flags & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
3471
        print_file(file, 0, "no serialize, ");
3472
    if (flags & NDR_STRICT_CONTEXT_HANDLE)
3473 3474 3475 3476 3477 3478 3479 3480 3481 3482
        print_file(file, 0, "strict, ");
    if ((flags & 0x21) == 0x20)
        print_file(file, 0, "out, ");
    if ((flags & 0x21) == 0x21)
        print_file(file, 0, "return, ");
    if (flags & 0x40)
        print_file(file, 0, "in, ");
    if (flags & 0x80)
        print_file(file, 0, "via ptr, ");
    print_file(file, 0, "*/\n");
3483
    print_file(file, 2, "0x%x,\t/* rundown routine */\n", get_context_handle_offset( type ));
3484 3485 3486
    print_file(file, 2, "0, /* FIXME: param num */\n");
    *typeformat_offset += 4;

3487
    update_tfsoff( type, start_offset, file );
3488 3489 3490
    return start_offset;
}

3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510
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);
    print_file(file, 2, "0x%x,\t/* FC_RANGE */\n", RPC_FC_RANGE);
    print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
3511 3512
    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);
3513
    update_tfsoff( type, start_offset, file );
3514 3515 3516 3517 3518
    *typeformat_offset += 10;

    return start_offset;
}

3519 3520 3521 3522 3523
static unsigned int write_type_tfs(FILE *file, int indent,
                                   const attr_list_t *attrs, type_t *type,
                                   const char *name,
                                   enum type_context context,
                                   unsigned int *typeformat_offset)
3524
{
3525
    unsigned int offset;
3526

3527
    switch (typegen_detect_type(type, attrs, TDT_ALL_TYPES))
3528
    {
3529 3530
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
3531 3532
        return write_contexthandle_tfs(file, attrs, type,
                                       context == TYPE_CONTEXT_TOPLEVELPARAM, typeformat_offset);
3533
    case TGT_USER_TYPE:
3534
        return write_user_tfs(file, type, typeformat_offset);
3535
    case TGT_STRING:
3536
        return write_string_tfs(file, attrs, type, context, name, typeformat_offset);
3537
    case TGT_ARRAY:
3538
    {
3539
        unsigned int off;
3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552
        /* 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;
            ptr_type = get_pointer_fc(type, attrs,
                                      context == TYPE_CONTEXT_TOPLEVELPARAM);
3553
            if (ptr_type != RPC_FC_RP || type_array_is_decl_as_ptr(type))
3554 3555 3556 3557 3558 3559 3560 3561 3562
            {
                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);
3563
                if (ptr_type != RPC_FC_RP) update_tfsoff( type, off, file );
3564 3565
                *typeformat_offset += 4;
            }
3566
            type->details.array.ptr_tfsoff = off;
3567 3568 3569
        }
        return off;
    }
3570
    case TGT_STRUCT:
3571
        return write_struct_tfs(file, type, name, typeformat_offset);
3572
    case TGT_UNION:
3573
        return write_union_tfs(file, attrs, type, typeformat_offset);
3574 3575 3576 3577
    case TGT_ENUM:
    case TGT_BASIC:
        /* nothing to do */
        return 0;
3578 3579
    case TGT_RANGE:
    {
3580
        expr_list_t *range_list = get_attrp(attrs, ATTR_RANGE);
3581 3582
        if (!range_list)
            range_list = get_aliaschain_attrp(type, ATTR_RANGE);
3583
        return write_range_tfs(file, attrs, type, range_list, typeformat_offset);
3584
    }
3585
    case TGT_IFACE_POINTER:
3586
        return write_ip_tfs(file, attrs, type, typeformat_offset);
3587
    case TGT_POINTER:
3588 3589
    {
        enum type_context ref_context;
3590 3591
        type_t *ref = type_pointer_get_ref(type);

3592 3593 3594 3595
        if (context == TYPE_CONTEXT_TOPLEVELPARAM)
            ref_context = TYPE_CONTEXT_PARAM;
        else if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
            ref_context = TYPE_CONTEXT_CONTAINER;
3596
        else
3597
            ref_context = context;
3598

3599
        if (is_string_type(attrs, ref))
3600 3601 3602 3603 3604 3605 3606 3607 3608 3609
        {
            if (context != TYPE_CONTEXT_CONTAINER_NO_POINTERS)
                write_pointer_tfs(file, attrs, type, *typeformat_offset + 4, context, typeformat_offset);

            offset = write_type_tfs(file, indent, attrs, ref, name, ref_context, typeformat_offset);
            if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
                return 0;
            return offset;
        }

3610 3611
        offset = write_type_tfs( file, indent, attrs, type_pointer_get_ref(type), name,
                                 ref_context, typeformat_offset);
3612 3613
        if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
            return 0;
3614
        return write_pointer_tfs(file, attrs, type, offset, context, typeformat_offset);
3615
    }
3616 3617 3618
    case TGT_INVALID:
        break;
    }
3619
    error("invalid type %s for var %s\n", type->name, name);
3620
    return 0;
3621 3622
}

3623
static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
3624
                                const char *name, int write_ptr, unsigned int *tfsoff)
3625
{
3626
    return write_type_tfs(file, 2, attrs, type, name, write_ptr ? TYPE_CONTEXT_CONTAINER : TYPE_CONTEXT_CONTAINER_NO_POINTERS, tfsoff);
3627 3628
}

3629 3630
static unsigned int process_tfs_stmts(FILE *file, const statement_list_t *stmts,
                                      type_pred_t pred, unsigned int *typeformat_offset)
3631
{
3632
    var_t *var;
3633
    const statement_t *stmt;
3634

3635
    if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
3636
    {
3637
        const type_t *iface;
3638 3639
        const statement_t *stmt_func;

3640
        if (stmt->type != STMT_TYPE || type_get_type(stmt->u.type) != TYPE_INTERFACE)
3641 3642 3643 3644
            continue;

        iface = stmt->u.type;
        if (!pred(iface))
3645 3646
            continue;

3647
        current_iface = iface;
3648
        STATEMENTS_FOR_EACH_FUNC( stmt_func, type_iface_get_stmts(iface) )
3649
        {
3650
            const var_t *func = stmt_func->u.var;
3651 3652
            current_func = func;
            if (is_local(func->attrs)) continue;
3653

3654 3655 3656 3657
            var = type_function_get_retval(func->type);
            if (!is_void(var->type))
                var->typestring_offset = write_type_tfs( file, 2, func->attrs, var->type, func->name,
                                                         TYPE_CONTEXT_PARAM, typeformat_offset);
3658

3659
            if (type_get_function_args(func->type))
3660 3661 3662 3663
                LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), var_t, entry )
                    var->typestring_offset = write_type_tfs( file, 2, var->attrs, var->type, var->name,
                                                             TYPE_CONTEXT_TOPLEVELPARAM,
                                                             typeformat_offset );
3664 3665 3666
        }
    }

3667 3668 3669
    return *typeformat_offset + 1;
}

3670
static unsigned int process_tfs(FILE *file, const statement_list_t *stmts, type_pred_t pred)
3671 3672 3673 3674
{
    unsigned int typeformat_offset = 2;

    return process_tfs_stmts(file, stmts, pred, &typeformat_offset);
3675 3676 3677
}


3678
void write_typeformatstring(FILE *file, const statement_list_t *stmts, type_pred_t pred)
3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689
{
    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");

3690
    set_all_tfswrite(TRUE);
3691
    process_tfs(file, stmts, pred);
3692

3693 3694 3695 3696 3697 3698 3699 3700
    print_file(file, indent, "0x0\n");
    indent--;
    print_file(file, indent, "}\n");
    indent--;
    print_file(file, indent, "};\n");
    print_file(file, indent, "\n");
}

3701
static unsigned int get_required_buffer_size_type(
3702
    const type_t *type, const char *name, const attr_list_t *attrs, int toplevel_param, unsigned int *alignment)
3703
{
3704
    *alignment = 0;
3705
    switch (typegen_detect_type(type, NULL, TDT_IGNORE_RANGES))
3706 3707
    {
    case TGT_USER_TYPE:
3708
    {
3709 3710
        const char *uname;
        const type_t *utype = get_user_type(type, &uname);
3711
        return get_required_buffer_size_type(utype, uname, NULL, FALSE, alignment);
3712
    }
3713
    case TGT_BASIC:
3714
        switch (get_basic_fc(type))
3715
        {
3716 3717 3718 3719 3720 3721
        case RPC_FC_BYTE:
        case RPC_FC_CHAR:
        case RPC_FC_USMALL:
        case RPC_FC_SMALL:
            *alignment = 4;
            return 1;
3722

3723 3724 3725 3726 3727
        case RPC_FC_WCHAR:
        case RPC_FC_USHORT:
        case RPC_FC_SHORT:
            *alignment = 4;
            return 2;
3728

3729 3730 3731 3732 3733 3734
        case RPC_FC_ULONG:
        case RPC_FC_LONG:
        case RPC_FC_FLOAT:
        case RPC_FC_ERROR_STATUS_T:
            *alignment = 4;
            return 4;
3735

3736 3737 3738 3739
        case RPC_FC_HYPER:
        case RPC_FC_DOUBLE:
            *alignment = 8;
            return 8;
3740

3741 3742 3743 3744 3745 3746
        case RPC_FC_INT3264:
        case RPC_FC_UINT3264:
            assert( pointer_size );
            *alignment = pointer_size;
            return pointer_size;

3747 3748 3749
        case RPC_FC_IGNORE:
        case RPC_FC_BIND_PRIMITIVE:
            return 0;
3750

3751 3752
        default:
            error("get_required_buffer_size: unknown basic type 0x%02x\n",
3753
                  get_basic_fc(type));
3754 3755 3756
            return 0;
        }
        break;
3757

3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768
    case TGT_ENUM:
        switch (get_enum_fc(type))
        {
        case RPC_FC_ENUM32:
            *alignment = 4;
            return 4;
        case RPC_FC_ENUM16:
            *alignment = 4;
            return 2;
        }
        break;
3769

3770 3771 3772 3773 3774 3775 3776
    case TGT_STRUCT:
        if (get_struct_fc(type) == RPC_FC_STRUCT)
        {
            if (!type_struct_get_fields(type)) return 0;
            return fields_memsize(type_struct_get_fields(type), alignment);
        }
        break;
3777

3778 3779
    case TGT_POINTER:
        {
3780
            unsigned int size, align;
3781
            const type_t *ref = type_pointer_get_ref(type);
3782
            if (is_string_type( attrs, ref )) break;
3783 3784 3785 3786 3787 3788 3789 3790
            if (!(size = get_required_buffer_size_type( ref, name, NULL, FALSE, &align ))) break;
            if (get_pointer_fc(type, attrs, toplevel_param) != RPC_FC_RP)
            {
                size += 4 + align;
                align = 4;
            }
            *alignment = align;
            return size;
3791
        }
3792

3793
    case TGT_ARRAY:
3794
        if (get_pointer_fc(type, attrs, toplevel_param) == RPC_FC_RP)
3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805
        {
            switch (get_array_fc(type))
            {
            case RPC_FC_SMFARRAY:
            case RPC_FC_LGFARRAY:
                return type_array_get_dim(type) *
                    get_required_buffer_size_type(type_array_get_element(type), name,
                                                  NULL, FALSE, alignment);
            }
        }
        break;
3806

3807 3808
    default:
        break;
3809
    }
3810
    return 0;
3811 3812
}

3813
static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
3814
{
3815 3816 3817 3818 3819 3820
    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;

3821 3822
    *alignment = 0;

3823 3824 3825 3826
    if ((pass == PASS_IN && in_attr) || (pass == PASS_OUT && out_attr) ||
        pass == PASS_RETURN)
    {
        if (is_ptrchain_attr(var, ATTR_CONTEXTHANDLE))
3827 3828 3829 3830 3831
        {
            *alignment = 4;
            return 20;
        }

3832 3833
        if (!is_string_type(var->attrs, var->type))
            return get_required_buffer_size_type(var->type, var->name,
3834
                                                 var->attrs, TRUE, alignment);
3835
    }
3836
    return 0;
3837 3838
}

3839
static unsigned int get_function_buffer_size( const var_t *func, enum pass pass )
3840 3841 3842 3843
{
    const var_t *var;
    unsigned int total_size = 0, alignment;

3844
    if (type_get_function_args(func->type))
3845
    {
3846
        LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
3847 3848 3849 3850 3851 3852
        {
            total_size += get_required_buffer_size(var, &alignment, pass);
            total_size += alignment;
        }
    }

3853
    if (pass == PASS_OUT && !is_void(type_function_get_rettype(func->type)))
3854
    {
3855
        var_t v = *func;
3856
        v.type = type_function_get_rettype(func->type);
3857
        total_size += get_required_buffer_size(&v, &alignment, PASS_RETURN);
3858 3859 3860 3861 3862
        total_size += alignment;
    }
    return total_size;
}

3863
static void print_phase_function(FILE *file, int indent, const char *type,
3864
                                 const char *local_var_prefix, enum remoting_phase phase,
3865
                                 const var_t *var, unsigned int type_offset)
3866
{
3867
    const char *function;
3868 3869 3870
    switch (phase)
    {
    case PHASE_BUFFERSIZE:
3871 3872
        function = "BufferSize";
        break;
3873
    case PHASE_MARSHAL:
3874 3875
        function = "Marshall";
        break;
3876
    case PHASE_UNMARSHAL:
3877 3878
        function = "Unmarshall";
        break;
3879
    case PHASE_FREE:
3880 3881 3882 3883 3884
        function = "Free";
        break;
    default:
        assert(0);
        return;
3885
    }
3886 3887 3888

    print_file(file, indent, "Ndr%s%s(\n", type, function);
    indent++;
3889
    print_file(file, indent, "&__frame->_StubMsg,\n");
3890
    print_file(file, indent, "%s%s%s%s%s,\n",
3891 3892
               (phase == PHASE_UNMARSHAL) ? "(unsigned char **)" : "(unsigned char *)",
               (phase == PHASE_UNMARSHAL || decl_indirect(var->type)) ? "&" : "",
3893
               local_var_prefix,
3894 3895
               (phase == PHASE_UNMARSHAL && decl_indirect(var->type)) ? "_p_" : "",
               var->name);
3896 3897 3898 3899 3900
    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--;
3901 3902
}

3903 3904
void print_phase_basetype(FILE *file, int indent, const char *local_var_prefix,
                          enum remoting_phase phase, enum pass pass, const var_t *var,
3905 3906
                          const char *varname)
{
3907
    type_t *type = var->type;
3908 3909 3910 3911 3912 3913
    unsigned int alignment = 0;

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

3914 3915 3916 3917
    if (type_get_type(type) == TYPE_ENUM ||
        (type_get_type(type) == TYPE_BASIC &&
         type_basic_get_type(type) == TYPE_BASIC_INT3264 &&
         pointer_size != 4))
3918
    {
3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934
        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));
3935 3936 3937
    }
    else
    {
3938
        const type_t *ref = is_ptr(type) ? type_pointer_get_ref(type) : type;
3939
        switch (get_basic_fc(ref))
3940
        {
3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957
        case RPC_FC_BYTE:
        case RPC_FC_CHAR:
        case RPC_FC_SMALL:
        case RPC_FC_USMALL:
            alignment = 1;
            break;

        case RPC_FC_WCHAR:
        case RPC_FC_USHORT:
        case RPC_FC_SHORT:
            alignment = 2;
            break;

        case RPC_FC_ULONG:
        case RPC_FC_LONG:
        case RPC_FC_FLOAT:
        case RPC_FC_ERROR_STATUS_T:
3958 3959 3960
        /* pointer_size must be 4 if we got here in these two cases */
        case RPC_FC_INT3264:
        case RPC_FC_UINT3264:
3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974
            alignment = 4;
            break;

        case RPC_FC_HYPER:
        case RPC_FC_DOUBLE:
            alignment = 8;
            break;

        case RPC_FC_IGNORE:
        case RPC_FC_BIND_PRIMITIVE:
            /* no marshalling needed */
            return;

        default:
3975
            error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n",
3976
                  var->name, get_basic_fc(ref));
3977
        }
3978

3979
        if (phase == PHASE_MARSHAL && alignment > 1)
3980 3981 3982
            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);
3983

3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014
        if (phase == PHASE_MARSHAL)
        {
            print_file(file, indent, "*(");
            write_type_decl(file, is_ptr(type) ? type_pointer_get_ref(type) : type, NULL);
            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(");
            write_type_decl(file, is_ptr(type) ? type_pointer_get_ref(type) : type, NULL);
            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, " = *(");
            write_type_decl(file, is_ptr(type) ? type_pointer_get_ref(type) : type, NULL);
            fprintf(file, " *)__frame->_StubMsg.Buffer;\n");
        }

        print_file(file, indent, "__frame->_StubMsg.Buffer += sizeof(");
4015
        write_type_decl(file, is_ptr(type) ? type_pointer_get_ref(type) : type, NULL);
4016
        fprintf(file, ");\n");
4017 4018 4019
    }
}

4020 4021
/* returns whether the MaxCount, Offset or ActualCount members need to be
 * filled in for the specified phase */
4022
static inline int is_conformance_needed_for_phase(enum remoting_phase phase)
4023 4024 4025 4026
{
    return (phase != PHASE_UNMARSHAL);
}

4027 4028 4029 4030
expr_t *get_size_is_expr(const type_t *t, const char *name)
{
    expr_t *x = NULL;

4031
    for ( ; is_array(t); t = type_array_get_element(t))
4032 4033
        if (type_array_has_conformance(t) &&
            type_array_get_conformance(t)->type != EXPR_VOID)
4034 4035
        {
            if (!x)
4036
                x = type_array_get_conformance(t);
4037 4038 4039 4040 4041 4042 4043 4044 4045
            else
                error("%s: multidimensional conformant"
                      " arrays not supported at the top level\n",
                      name);
        }

    return x;
}

4046 4047
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)
4048 4049 4050 4051 4052
{
    const type_t *type = var->type;
    /* get fundamental type for the argument */
    for (;;)
    {
4053
        switch (typegen_detect_type(type, var->attrs, TDT_IGNORE_STRINGS|TDT_IGNORE_RANGES))
4054
        {
4055 4056
        case TGT_ARRAY:
            if (is_conformance_needed_for_phase(phase))
4057
            {
4058 4059
                if (type_array_has_conformance(type) &&
                    type_array_get_conformance(type)->type != EXPR_VOID)
4060
                {
4061
                    print_file(file, indent, "__frame->_StubMsg.MaxCount = (ULONG_PTR)");
4062
                    write_expr(file, type_array_get_conformance(type), 1, 1, NULL, NULL, local_var_prefix);
4063 4064
                    fprintf(file, ";\n\n");
                }
4065
                if (type_array_has_variance(type))
4066
                {
4067
                    print_file(file, indent, "__frame->_StubMsg.Offset = 0;\n"); /* FIXME */
4068 4069 4070 4071 4072 4073 4074 4075
                    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");
4076 4077 4078
                }
            }
            break;
4079 4080 4081
        case TGT_UNION:
            if (type_get_type(type) == TYPE_UNION &&
                is_conformance_needed_for_phase(phase))
4082
            {
4083
                print_file(file, indent, "__frame->_StubMsg.MaxCount = (ULONG_PTR)");
4084
                write_expr(file, get_attrp(var->attrs, ATTR_SWITCHIS), 1, 1, NULL, NULL, local_var_prefix);
4085 4086 4087
                fprintf(file, ";\n\n");
            }
            break;
4088
        case TGT_IFACE_POINTER:
4089 4090 4091 4092 4093
        {
            expr_t *iid;

            if (is_conformance_needed_for_phase(phase) && (iid = get_attrp( var->attrs, ATTR_IIDIS )))
            {
4094
                print_file( file, indent, "__frame->_StubMsg.MaxCount = (ULONG_PTR) " );
4095
                write_expr( file, iid, 1, 1, NULL, NULL, local_var_prefix );
4096 4097 4098 4099
                fprintf( file, ";\n\n" );
            }
            break;
        }
4100
        case TGT_POINTER:
4101
            type = type_pointer_get_ref(type);
4102 4103 4104 4105 4106 4107 4108 4109 4110 4111
            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:
4112
            break;
4113 4114
        }
        break;
4115 4116 4117
    }
}

4118
static void write_remoting_arg(FILE *file, int indent, const var_t *func, const char *local_var_prefix,
4119
                               enum pass pass, enum remoting_phase phase, const var_t *var)
4120
{
4121
    int in_attr, out_attr, pointer_type;
4122
    const char *type_str = NULL;
4123
    const type_t *type = var->type;
4124
    unsigned int alignment, start_offset = type->typestring_offset;
4125

4126 4127 4128 4129
    if (is_ptr(type) || is_array(type))
        pointer_type = get_pointer_fc(type, var->attrs, pass != PASS_RETURN);
    else
        pointer_type = 0;
4130

4131 4132 4133 4134
    in_attr = is_attr(var->attrs, ATTR_IN);
    out_attr = is_attr(var->attrs, ATTR_OUT);
    if (!in_attr && !out_attr)
        in_attr = 1;
4135

4136
    if (phase != PHASE_FREE)
4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147
        switch (pass)
        {
        case PASS_IN:
            if (!in_attr) return;
            break;
        case PASS_OUT:
            if (!out_attr) return;
            break;
        case PASS_RETURN:
            break;
        }
4148

4149 4150
    if (phase == PHASE_BUFFERSIZE && get_required_buffer_size( var, &alignment, pass )) return;

4151
    write_parameter_conf_or_var_exprs(file, indent, local_var_prefix, phase, var, TRUE);
4152

4153
    switch (typegen_detect_type(type, var->attrs, TDT_ALL_TYPES))
4154
    {
4155 4156
    case TGT_CTXT_HANDLE:
    case TGT_CTXT_HANDLE_POINTER:
4157
        if (phase == PHASE_MARSHAL)
4158
        {
4159 4160
            if (pass == PASS_IN)
            {
4161 4162 4163
                /* 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 */
4164
                const char *ch_ptr = is_aliaschain_attr(type, ATTR_CONTEXTHANDLE) ? "" : "*";
4165
                print_file(file, indent, "NdrClientContextMarshall(\n");
4166
                print_file(file, indent + 1, "&__frame->_StubMsg,\n");
4167 4168
                print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s%s,\n", ch_ptr, local_var_prefix,
                           var->name);
4169 4170 4171 4172
                print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
            }
            else
            {
4173
                print_file(file, indent, "NdrServerContextNewMarshall(\n");
4174
                print_file(file, indent + 1, "&__frame->_StubMsg,\n");
4175
                print_file(file, indent + 1, "(NDR_SCONTEXT)%s%s,\n", local_var_prefix, var->name);
4176 4177
                print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown,\n", get_context_handle_type_name(var->type));
                print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
4178 4179 4180 4181 4182 4183
            }
        }
        else if (phase == PHASE_UNMARSHAL)
        {
            if (pass == PASS_OUT)
            {
4184
                if (!in_attr)
4185
                    print_file(file, indent, "*%s%s = 0;\n", local_var_prefix, var->name);
4186
                print_file(file, indent, "NdrClientContextUnmarshall(\n");
4187
                print_file(file, indent + 1, "&__frame->_StubMsg,\n");
4188
                print_file(file, indent + 1, "(NDR_CCONTEXT *)%s%s,\n", local_var_prefix, var->name);
4189
                print_file(file, indent + 1, "__frame->_Handle);\n");
4190 4191
            }
            else
4192
            {
4193
                print_file(file, indent, "%s%s = NdrServerContextNewUnmarshall(\n", local_var_prefix, var->name);
4194
                print_file(file, indent + 1, "&__frame->_StubMsg,\n");
4195 4196
                print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
            }
4197
        }
4198 4199
        break;
    case TGT_USER_TYPE:
4200
        print_phase_function(file, indent, "UserMarshal", local_var_prefix, phase, var, start_offset);
4201 4202
        break;
    case TGT_STRING:
4203 4204 4205
        if (phase == PHASE_FREE || pass == PASS_RETURN ||
            pointer_type != RPC_FC_RP)
        {
4206 4207 4208 4209 4210 4211
            /* 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);
            else if (pointer_type == RPC_FC_RP && phase == PHASE_FREE &&
4212 4213 4214 4215 4216 4217
                !in_attr && is_conformant_array(type))
            {
                print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
                indent++;
                print_file(file, indent, "__frame->_StubMsg.pfnFree(%s%s);\n", local_var_prefix, var->name);
            }
4218
        }
4219
        else
4220
        {
4221 4222 4223 4224 4225 4226 4227 4228 4229
            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;
            }
4230 4231 4232
            if (is_array(type) && !is_conformant_array(type))
                print_phase_function(file, indent, "NonConformantString",
                                     local_var_prefix, phase, var,
4233
                                     real_start_offset);
4234
            else
4235
                print_phase_function(file, indent, "ConformantString", local_var_prefix,
4236
                                     phase, var, real_start_offset);
4237
        }
4238 4239
        break;
    case TGT_ARRAY:
4240 4241
    {
        unsigned char tc = get_array_fc(type);
4242
        const char *array_type = NULL;
4243

4244 4245 4246 4247 4248 4249 4250
        /* 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);

4251
        switch (tc)
4252
        {
4253 4254 4255 4256 4257 4258
        case RPC_FC_SMFARRAY:
        case RPC_FC_LGFARRAY:
            array_type = "FixedArray";
            break;
        case RPC_FC_SMVARRAY:
        case RPC_FC_LGVARRAY:
4259
            array_type = "VaryingArray";
4260 4261
            break;
        case RPC_FC_CARRAY:
4262
            array_type = "ConformantArray";
4263 4264 4265 4266 4267 4268 4269
            break;
        case RPC_FC_CVARRAY:
            array_type = "ConformantVaryingArray";
            break;
        case RPC_FC_BOGUS_ARRAY:
            array_type = "ComplexArray";
            break;
4270
        }
4271 4272

        if (pointer_type != RPC_FC_RP) array_type = "Pointer";
4273

4274
        if (phase == PHASE_FREE && pointer_type == RPC_FC_RP)
4275
        {
4276
            /* these are all unmarshalled by allocating memory */
4277 4278 4279 4280
            if (tc == RPC_FC_BOGUS_ARRAY ||
                tc == RPC_FC_CVARRAY ||
                ((tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY) && in_attr) ||
                (tc == RPC_FC_CARRAY && !in_attr))
4281
            {
4282 4283 4284 4285 4286 4287 4288
                if (type_array_is_decl_as_ptr(type) && type->details.array.ptr_tfsoff)
                {
                    print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var,
                                         type->details.array.ptr_tfsoff);
                    break;
                }
                print_phase_function(file, indent, array_type, local_var_prefix, phase, var, start_offset);
4289
                print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
4290
                indent++;
4291
                print_file(file, indent, "__frame->_StubMsg.pfnFree(%s%s);\n", local_var_prefix, var->name);
4292
                break;
4293 4294
            }
        }
4295
        print_phase_function(file, indent, array_type, local_var_prefix, phase, var, start_offset);
4296
        break;
4297
    }
4298
    case TGT_BASIC:
4299
        print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
4300
        break;
4301
    case TGT_ENUM:
4302
        print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
4303
        break;
4304
    case TGT_RANGE:
4305
        print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319
        /* 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);
            write_type_decl(file, var->type, NULL);
4320
            fprintf(file, ")0x%x) || (%s%s > (", range_min->cval, local_var_prefix, var->name);
4321
            write_type_decl(file, var->type, NULL);
4322
            fprintf(file, ")0x%x))\n", range_max->cval);
4323 4324 4325 4326 4327
            print_file(file, indent, "{\n");
            print_file(file, indent+1, "RpcRaiseException(RPC_S_INVALID_BOUND);\n");
            print_file(file, indent, "}\n");
        }
        break;
4328
    case TGT_STRUCT:
4329
        switch (get_struct_fc(type))
4330
        {
4331
        case RPC_FC_STRUCT:
4332 4333 4334
            if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
                print_phase_function(file, indent, "SimpleStruct", local_var_prefix, phase, var, start_offset);
            break;
4335
        case RPC_FC_PSTRUCT:
4336
            print_phase_function(file, indent, "SimpleStruct", local_var_prefix, phase, var, start_offset);
4337 4338 4339
            break;
        case RPC_FC_CSTRUCT:
        case RPC_FC_CPSTRUCT:
4340
            print_phase_function(file, indent, "ConformantStruct", local_var_prefix, phase, var, start_offset);
4341 4342
            break;
        case RPC_FC_CVSTRUCT:
4343
            print_phase_function(file, indent, "ConformantVaryingStruct", local_var_prefix, phase, var, start_offset);
4344 4345
            break;
        case RPC_FC_BOGUS_STRUCT:
4346
            print_phase_function(file, indent, "ComplexStruct", local_var_prefix, phase, var, start_offset);
4347 4348
            break;
        default:
4349
            error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, get_struct_fc(type));
4350
        }
4351
        break;
4352
    case TGT_UNION:
4353 4354 4355
    {
        const char *union_type = NULL;

4356
        if (type_get_type(type) == TYPE_UNION)
4357
            union_type = "NonEncapsulatedUnion";
4358
        else if (type_get_type(type) == TYPE_ENCAPSULATED_UNION)
4359 4360 4361 4362
            union_type = "EncapsulatedUnion";

        print_phase_function(file, indent, union_type, local_var_prefix,
                             phase, var, start_offset);
4363
        break;
4364
    }
4365
    case TGT_POINTER:
4366
    {
4367
        const type_t *ref = type_pointer_get_ref(type);
4368
        if (pointer_type == RPC_FC_RP) switch (typegen_detect_type(ref, NULL, TDT_ALL_TYPES))
4369
        {
4370
        case TGT_BASIC:
4371
            print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
4372
            break;
4373
        case TGT_ENUM:
4374 4375 4376 4377 4378 4379
            /* 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;
4380
        case TGT_STRUCT:
4381
            switch (get_struct_fc(ref))
4382 4383 4384 4385 4386 4387
            {
            case RPC_FC_STRUCT:
                /* 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)
4388
                    type_str = "SimpleStruct";
4389 4390 4391 4392 4393 4394 4395
                else if (phase == PHASE_FREE && pass == PASS_RETURN)
                {
                    print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
                    indent++;
                    print_file(file, indent, "__frame->_StubMsg.pfnFree(%s%s);\n", local_var_prefix, var->name);
                    indent--;
                }
4396 4397
                break;
            case RPC_FC_PSTRUCT:
4398
                type_str = "SimpleStruct";
4399 4400 4401
                break;
            case RPC_FC_CSTRUCT:
            case RPC_FC_CPSTRUCT:
4402
                type_str = "ConformantStruct";
4403 4404
                break;
            case RPC_FC_CVSTRUCT:
4405
                type_str = "ConformantVaryingStruct";
4406 4407
                break;
            case RPC_FC_BOGUS_STRUCT:
4408
                type_str = "ComplexStruct";
4409 4410
                break;
            default:
4411
                error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, get_struct_fc(ref));
4412 4413
            }

4414
            if (type_str)
4415 4416
            {
                if (phase == PHASE_FREE)
4417
                    type_str = "Pointer";
4418 4419
                else
                    start_offset = ref->typestring_offset;
4420
                print_phase_function(file, indent, type_str, local_var_prefix, phase, var, start_offset);
4421
            }
4422
            break;
4423
        case TGT_UNION:
4424
            if (phase == PHASE_FREE)
4425
                type_str = "Pointer";
4426 4427
            else
            {
4428
                if (type_get_type(ref) == TYPE_UNION)
4429
                    type_str = "NonEncapsulatedUnion";
4430
                else if (type_get_type(ref) == TYPE_ENCAPSULATED_UNION)
4431
                    type_str = "EncapsulatedUnion";
4432 4433 4434 4435

                start_offset = ref->typestring_offset;
            }

4436
            print_phase_function(file, indent, type_str, local_var_prefix,
4437
                                 phase, var, start_offset);
4438
            break;
4439 4440 4441 4442 4443 4444 4445 4446 4447 4448
        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;
4449 4450 4451 4452 4453 4454 4455
        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:
4456 4457
            print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
            break;
4458
        case TGT_INVALID:
4459 4460
            assert(0);
            break;
4461
        }
4462 4463 4464 4465
        else
            print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
        break;
    }
4466 4467 4468 4469
    case TGT_IFACE_POINTER:
        print_phase_function(file, indent, "InterfacePointer", local_var_prefix, phase, var, start_offset);
        break;
    case TGT_INVALID:
4470 4471
        assert(0);
        break;
4472 4473 4474 4475
    }
    fprintf(file, "\n");
}

4476
void write_remoting_arguments(FILE *file, int indent, const var_t *func, const char *local_var_prefix,
4477 4478 4479 4480 4481
                              enum pass pass, enum remoting_phase phase)
{
    if (phase == PHASE_BUFFERSIZE && pass != PASS_RETURN)
    {
        unsigned int size = get_function_buffer_size( func, pass );
4482
        print_file(file, indent, "__frame->_StubMsg.BufferLength = %u;\n", size);
4483 4484 4485 4486
    }

    if (pass == PASS_RETURN)
    {
4487 4488
        write_remoting_arg( file, indent, func, local_var_prefix, pass, phase,
                            type_function_get_retval(func->type) );
4489 4490 4491 4492
    }
    else
    {
        const var_t *var;
4493
        if (!type_get_function_args(func->type))
4494
            return;
4495
        LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
4496
            write_remoting_arg( file, indent, func, local_var_prefix, pass, phase, var );
4497 4498
    }
}
4499 4500


4501
unsigned int get_size_procformatstring_func(const type_t *iface, const var_t *func)
4502
{
4503
    unsigned int offset = 0;
4504
    write_procformatstring_func( NULL, 0, iface, func, &offset, 0 );
4505
    return offset;
4506 4507
}

4508
unsigned int get_size_procformatstring(const statement_list_t *stmts, type_pred_t pred)
4509
{
4510
    const statement_t *stmt;
4511
    unsigned int size = 1;
4512

4513
    if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
4514
    {
4515
        const type_t *iface;
4516 4517
        const statement_t *stmt_func;

4518
        if (stmt->type != STMT_TYPE || type_get_type(stmt->u.type) != TYPE_INTERFACE)
4519 4520 4521 4522
            continue;

        iface = stmt->u.type;
        if (!pred(iface))
4523 4524
            continue;

4525
        STATEMENTS_FOR_EACH_FUNC( stmt_func, type_iface_get_stmts(iface) )
4526 4527 4528
        {
            const var_t *func = stmt_func->u.var;
            if (!is_local(func->attrs))
4529
                size += get_size_procformatstring_func( iface, func );
4530
        }
4531 4532 4533 4534
    }
    return size;
}

4535
unsigned int get_size_typeformatstring(const statement_list_t *stmts, type_pred_t pred)
4536
{
4537
    set_all_tfswrite(FALSE);
4538
    return process_tfs(NULL, stmts, pred);
4539 4540
}

4541
void declare_stub_args( FILE *file, int indent, const var_t *func )
4542 4543 4544
{
    int in_attr, out_attr;
    int i = 0;
4545
    const var_t *var = type_function_get_retval(func->type);
4546

4547 4548
    /* declare return value */
    if (!is_void(var->type))
4549
    {
4550
        print_file(file, indent, "%s", "");
4551 4552
        write_type_decl(file, var->type, var->name);
        fprintf(file, ";\n");
4553 4554
    }

4555
    if (!type_get_function_args(func->type))
4556 4557
        return;

4558
    LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
4559 4560 4561 4562 4563 4564
    {
        in_attr = is_attr(var->attrs, ATTR_IN);
        out_attr = is_attr(var->attrs, ATTR_OUT);
        if (!out_attr && !in_attr)
            in_attr = 1;

4565 4566 4567
        if (is_context_handle(var->type))
            print_file(file, indent, "NDR_SCONTEXT %s;\n", var->name);
        else
4568
        {
4569
            if (!in_attr && !is_conformant_array(var->type))
4570
            {
4571
                type_t *type_to_print;
4572
                char name[16];
4573
                print_file(file, indent, "%s", "");
4574 4575
                if (type_get_type(var->type) == TYPE_ARRAY &&
                    !type_array_is_decl_as_ptr(var->type))
4576 4577 4578
                    type_to_print = var->type;
                else
                    type_to_print = type_pointer_get_ref(var->type);
4579 4580
                sprintf(name, "_W%u", i++);
                write_type_decl(file, type_to_print, name);
4581 4582 4583
                fprintf(file, ";\n");
            }

4584
            print_file(file, indent, "%s", "");
4585
            write_type_decl_left(file, var->type);
4586
            fprintf(file, " ");
4587 4588
            if (type_get_type(var->type) == TYPE_ARRAY &&
                !type_array_is_decl_as_ptr(var->type)) {
4589
                fprintf(file, "(*%s)", var->name);
4590
            } else
4591
                fprintf(file, "%s", var->name);
4592
            write_type_right(file, var->type, FALSE);
4593
            fprintf(file, ";\n");
4594

4595
            if (decl_indirect(var->type))
4596
                print_file(file, indent, "void *_p_%s;\n", var->name);
4597
        }
4598 4599 4600 4601
    }
}


4602
void assign_stub_out_args( FILE *file, int indent, const var_t *func, const char *local_var_prefix )
4603 4604 4605 4606
{
    int in_attr, out_attr;
    int i = 0, sep = 0;
    const var_t *var;
4607
    type_t *ref;
4608

4609
    if (!type_get_function_args(func->type))
4610 4611
        return;

4612
    LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
4613 4614 4615 4616 4617 4618 4619 4620
    {
        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)
        {
4621
            print_file(file, indent, "%s%s", local_var_prefix, var->name);
4622

4623
            switch (typegen_detect_type(var->type, var->attrs, TDT_IGNORE_STRINGS))
4624
            {
4625
            case TGT_CTXT_HANDLE_POINTER:
4626
                fprintf(file, " = NdrContextHandleInitialize(\n");
4627
                print_file(file, indent + 1, "&__frame->_StubMsg,\n");
4628
                print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n",
4629
                           var->typestring_offset);
4630 4631 4632
                break;
            case TGT_ARRAY:
                if (type_array_has_conformance(var->type))
4633
                {
4634
                    unsigned int size;
4635
                    type_t *type;
4636 4637

                    fprintf(file, " = NdrAllocate(&__frame->_StubMsg, ");
4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650
                    for (type = var->type;
                         is_array(type) && type_array_has_conformance(type);
                         type = type_array_get_element(type))
                    {
                        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);
                    for (type = var->type;
4651 4652 4653 4654 4655 4656 4657
                         is_array(type) && type_array_has_conformance(type);
                         type = type_array_get_element(type))
                    {
                        write_expr(file, type_array_get_conformance(type), TRUE,
                                   TRUE, NULL, NULL, local_var_prefix);
                        fprintf(file, " * ");
                    }
4658
                    size = type_memsize(type);
4659
                    fprintf(file, "%u);\n", size);
4660
                }
4661 4662 4663 4664
                else
                    fprintf(file, " = &%s_W%u;\n", local_var_prefix, i++);
                break;
            case TGT_POINTER:
4665
                fprintf(file, " = &%s_W%u;\n", local_var_prefix, i);
4666 4667
                ref = type_pointer_get_ref(var->type);
                switch (typegen_detect_type(ref, var->attrs, TDT_IGNORE_STRINGS))
4668 4669 4670 4671
                {
                case TGT_BASIC:
                case TGT_ENUM:
                case TGT_POINTER:
4672
                case TGT_RANGE:
4673
                case TGT_IFACE_POINTER:
4674
                    print_file(file, indent, "%s_W%u = 0;\n", local_var_prefix, i);
4675
                    break;
4676 4677 4678 4679
                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;
4680 4681 4682 4683 4684 4685 4686 4687
                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;
                    }
                    ref = type_array_get_element(ref);
                    /* fall through */
4688 4689
                case TGT_STRUCT:
                case TGT_UNION:
4690 4691 4692 4693
                    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;
4694 4695 4696 4697 4698 4699 4700
                case TGT_CTXT_HANDLE:
                case TGT_CTXT_HANDLE_POINTER:
                case TGT_INVALID:
                case TGT_STRING:
                    /* not initialised */
                    break;
                }
4701
                i++;
4702 4703 4704
                break;
            default:
                break;
4705 4706 4707 4708 4709 4710 4711 4712 4713 4714
            }

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


4715 4716
void write_func_param_struct( FILE *file, const type_t *iface, const type_t *func,
                              const char *var_decl, int add_retval )
4717
{
4718
    var_t *retval = type_function_get_retval( func );
4719 4720
    const var_list_t *args = type_get_function_args( func );
    const var_t *arg;
4721 4722 4723 4724 4725 4726 4727 4728
    int needs_packing;
    unsigned int align = 0;

    if (args)
        LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
            if (!is_array( arg->type )) type_memsize_and_alignment( arg->type, &align );

    needs_packing = (align > pointer_size);
4729

4730
    if (needs_packing) print_file( file, 0, "#include <pshpack%u.h>\n", pointer_size );
4731 4732 4733 4734 4735 4736 4737
    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", "");
4738
        write_type_left( file, (type_t *)arg->type, NAME_DEFAULT, TRUE );
4739 4740
        if (needs_space_after( arg->type )) fputc( ' ', file );
        if (is_array( arg->type ) && !type_array_is_decl_as_ptr( arg->type )) fputc( '*', file );
4741

4742
        /* FIXME: should check for large args being passed by pointer */
4743 4744 4745 4746 4747
        align = 0;
        if (is_array( arg->type ) || is_ptr( arg->type )) align = pointer_size;
        else type_memsize_and_alignment( arg->type, &align );

        if (align >= pointer_size)
4748 4749 4750 4751
            fprintf( file, "%s;\n", arg->name );
        else
            fprintf( file, "%s DECLSPEC_ALIGN(%u);\n", arg->name, pointer_size );
    }
4752
    if (add_retval && !is_void( retval->type ))
4753 4754
    {
        print_file(file, 2, "%s", "");
4755 4756 4757
        write_type_decl( file, retval->type, retval->name );
        if (is_array( retval->type ) || is_ptr( retval->type ) ||
            type_memsize( retval->type ) == pointer_size)
4758 4759 4760
            fprintf( file, ";\n" );
        else
            fprintf( file, " DECLSPEC_ALIGN(%u);\n", pointer_size );
4761
    }
4762 4763 4764
    print_file(file, 1, "} %s;\n", var_decl );
    if (needs_packing) print_file( file, 0, "#include <poppack.h>\n" );
    print_file( file, 0, "\n" );
4765 4766
}

4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778
void write_pointer_checks( FILE *file, int indent, const var_t *func )
{
    const var_list_t *args = type_get_function_args( func->type );
    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 );
}

4779 4780
int write_expr_eval_routines(FILE *file, const char *iface)
{
4781
    static const char *var_name = "pS";
4782
    static const char *var_name_expr = "pS->";
4783 4784 4785 4786 4787 4788
    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)
    {
4789
        const char *name = eval->name;
4790
        result = 1;
4791 4792

        print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
4793
                   eval->iface ? eval->iface->name : iface, name, callback_offset);
4794
        print_file(file, 0, "{\n");
4795 4796
        if (type_get_type( eval->cont_type ) == TYPE_FUNCTION)
        {
4797 4798
            write_func_param_struct( file, eval->iface, eval->cont_type,
                                     "*pS = (struct _PARAM_STRUCT *)pStubMsg->StackTop", FALSE );
4799 4800 4801 4802
        }
        else
        {
            print_file(file, 1, "%s", "");
4803
            write_type_left(file, (type_t *)eval->cont_type, NAME_DEFAULT, TRUE);
4804
            fprintf(file, " *%s = (", var_name);
4805
            write_type_left(file, (type_t *)eval->cont_type, NAME_DEFAULT, TRUE);
4806 4807
            fprintf(file, " *)(pStubMsg->StackTop - %u);\n", eval->baseoff);
        }
4808
        print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */
4809
        print_file(file, 1, "pStubMsg->MaxCount = (ULONG_PTR)");
4810
        write_expr(file, eval->expr, 1, 1, var_name_expr, eval->cont_type, "");
4811
        fprintf(file, ";\n");
4812
        print_file(file, 0, "}\n\n");
4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828
        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)
    {
4829 4830
        print_file(file, 1, "%s_%sExprEval_%04u,\n",
                   eval->iface ? eval->iface->name : iface, eval->name, callback_offset);
4831 4832
        callback_offset++;
        list_remove(&eval->entry);
4833
        free(eval->name);
4834 4835 4836 4837 4838
        free(eval);
    }

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

4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852
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");
4853 4854 4855 4856
        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);
4857 4858 4859 4860
        print_file(file, 1, "}%s\n", sep);
    }
    fprintf(file, "};\n\n");
}
4861 4862 4863 4864 4865 4866 4867

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 */
4868
    print_file( f, 0, "static const unsigned char * const %s__RpcProtseqEndpoint[][2] =\n{\n", prefix );
4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894
    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);
}
4895

4896 4897 4898 4899 4900 4901 4902
void write_client_call_routine( FILE *file, const type_t *iface, const var_t *func,
                                const char *prefix, unsigned int proc_offset )
{
    type_t *rettype = type_function_get_rettype( func->type );
    int has_ret = !is_void( rettype );
    const var_list_t *args = type_get_function_args( func->type );
    const var_t *arg;
4903 4904 4905 4906
    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;
4907 4908

    print_file( file, 0, "{\n");
4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919
    if (needs_params)
    {
        if (has_ret) print_file( file, 1, "%s", "CLIENT_CALL_RETURN _RetVal;\n" );
        write_func_param_struct( file, iface, func->type, "__params", FALSE );
        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" );

4920 4921 4922 4923 4924
    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 );
4925 4926 4927 4928 4929
    if (needs_params)
    {
        fprintf( file, ",\n%*s&__params", len, "" );
    }
    else if (pointer_size == 8)
4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954
    {
        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");
}

4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966
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");
4967
    fprintf( file, "#undef RpcAbnormalTermination\n");
4968 4969
    fprintf( file, "\n");
    fprintf( file, "struct __exception_frame;\n");
4970
    fprintf( file, "typedef int (*__filter_func)(struct __exception_frame *);\n");
4971 4972 4973 4974 4975 4976 4977 4978
    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");
    fprintf( file, "    sigjmp_buf                    jmp; \\\n");
    fprintf( file, "    DWORD                         code; \\\n");
4979
    fprintf( file, "    unsigned char                 abnormal_termination; \\\n");
4980 4981 4982 4983
    fprintf( file, "    unsigned char                 filter_level; \\\n");
    fprintf( file, "    unsigned char                 finally_level;\n");
    fprintf( file, "\n");
    fprintf( file, "struct __exception_frame\n{\n");
4984
    fprintf( file, "    __DECL_EXCEPTION_FRAME\n");
4985 4986
    fprintf( file, "};\n");
    fprintf( file, "\n");
4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999
    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");
    fprintf( file, "    siglongjmp( exc_frame->jmp, 1 );\n");
    fprintf( file, "}\n");
    fprintf( file, "\n");
5000 5001 5002 5003 5004 5005 5006 5007 5008 5009
    fprintf( file, "static DWORD __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");
    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");
5010 5011
    fprintf( file, "        {\n" );
    fprintf( file, "            exc_frame->abnormal_termination = 1;\n");
5012
    fprintf( file, "            exc_frame->finally( exc_frame );\n");
5013
    fprintf( file, "        }\n" );
5014 5015 5016
    fprintf( file, "        return ExceptionContinueSearch;\n");
    fprintf( file, "    }\n" );
    fprintf( file, "    exc_frame->code = record->ExceptionCode;\n");
5017
    fprintf( file, "    if (exc_frame->filter_level && exc_frame->filter( exc_frame ) == EXCEPTION_EXECUTE_HANDLER)\n" );
5018
    fprintf( file, "        __wine_rtl_unwind( frame, record, __widl_unwind_target );\n");
5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051
    fprintf( file, "    return ExceptionContinueSearch;\n");
    fprintf( file, "}\n");
    fprintf( file, "\n");
    fprintf( file, "#define RpcTryExcept \\\n");
    fprintf( file, "    if (!sigsetjmp( __frame->jmp, 0 )) \\\n");
    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");
5052 5053
    fprintf( file, "#define RpcAbnormalTermination() (__frame->abnormal_termination)\n");
    fprintf( file, "\n");
5054 5055 5056 5057 5058
    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");
5059
    fprintf( file, "        __frame->abnormal_termination = 0; \\\n");
5060 5061 5062 5063 5064 5065
    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");
5066 5067 5068
    fprintf( file, "#define RpcExceptionInit(filter_func,finally_func) \\\n");
    fprintf( file, "    do { (void)(filter_func); } while(0)\n");
    fprintf( file, "\n");
5069 5070
    fprintf( file, "#define __DECL_EXCEPTION_FRAME \\\n");
    fprintf( file, "    DWORD code;\n");
5071 5072 5073
    fprintf( file, "\n");
    fprintf( file, "#endif /* USE_COMPILER_EXCEPTIONS */\n");
}