ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

typegen.c
Go to the documentation of this file.
00001 /*
00002  * Format String Generator for IDL Compiler
00003  *
00004  * Copyright 2005-2006 Eric Kohl
00005  * Copyright 2005-2006 Robert Shearman
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include "config.h"
00023 #include "wine/port.h"
00024 
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #ifdef HAVE_UNISTD_H
00028 # include <unistd.h>
00029 #endif
00030 #include <string.h>
00031 #include <assert.h>
00032 #include <ctype.h>
00033 #include <limits.h>
00034 
00035 #include "widl.h"
00036 #include "utils.h"
00037 #include "parser.h"
00038 #include "header.h"
00039 #include "typetree.h"
00040 
00041 #include "typegen.h"
00042 #include "expr.h"
00043 
00044 /* round size up to multiple of alignment */
00045 #define ROUND_SIZE(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1))
00046 /* value to add on to round size up to a multiple of alignment */
00047 #define ROUNDING(size, alignment) (((alignment) - 1) - (((size) + ((alignment) - 1)) & ((alignment) - 1)))
00048 
00049 static const type_t *current_structure;
00050 static const var_t *current_func;
00051 static const type_t *current_iface;
00052 
00053 static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
00054 struct expr_eval_routine
00055 {
00056     struct list   entry;
00057     const type_t *iface;
00058     const type_t *cont_type;
00059     char         *name;
00060     unsigned int  baseoff;
00061     const expr_t *expr;
00062 };
00063 
00064 enum type_context
00065 {
00066     TYPE_CONTEXT_TOPLEVELPARAM,
00067     TYPE_CONTEXT_PARAM,
00068     TYPE_CONTEXT_CONTAINER,
00069     TYPE_CONTEXT_CONTAINER_NO_POINTERS,
00070 };
00071 
00072 /* parameter flags in Oif mode */
00073 static const unsigned short MustSize = 0x0001;
00074 static const unsigned short MustFree = 0x0002;
00075 static const unsigned short IsPipe = 0x0004;
00076 static const unsigned short IsIn = 0x0008;
00077 static const unsigned short IsOut = 0x0010;
00078 static const unsigned short IsReturn = 0x0020;
00079 static const unsigned short IsBasetype = 0x0040;
00080 static const unsigned short IsByValue = 0x0080;
00081 static const unsigned short IsSimpleRef = 0x0100;
00082 /* static const unsigned short IsDontCallFreeInst = 0x0200; */
00083 /* static const unsigned short SaveForAsyncFinish = 0x0400; */
00084 
00085 static unsigned int field_memsize(const type_t *type, unsigned int *offset);
00086 static unsigned int fields_memsize(const var_list_t *fields, unsigned int *align);
00087 static unsigned int type_memsize_and_alignment(const type_t *t, unsigned int *align);
00088 static unsigned int write_struct_tfs(FILE *file, type_t *type, const char *name, unsigned int *tfsoff);
00089 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
00090                                 const char *name, int write_ptr, unsigned int *tfsoff);
00091 static const var_t *find_array_or_string_in_struct(const type_t *type);
00092 static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
00093                                      type_t *type, enum type_context context,
00094                                      const char *name, unsigned int *typestring_offset);
00095 static unsigned int get_required_buffer_size_type( const type_t *type, const char *name,
00096                                                    const attr_list_t *attrs, int toplevel_param,
00097                                                    unsigned int *alignment );
00098 static unsigned int get_function_buffer_size( const var_t *func, enum pass pass );
00099 
00100 static const char *string_of_type(unsigned char type)
00101 {
00102     switch (type)
00103     {
00104     case RPC_FC_BYTE: return "FC_BYTE";
00105     case RPC_FC_CHAR: return "FC_CHAR";
00106     case RPC_FC_SMALL: return "FC_SMALL";
00107     case RPC_FC_USMALL: return "FC_USMALL";
00108     case RPC_FC_WCHAR: return "FC_WCHAR";
00109     case RPC_FC_SHORT: return "FC_SHORT";
00110     case RPC_FC_USHORT: return "FC_USHORT";
00111     case RPC_FC_LONG: return "FC_LONG";
00112     case RPC_FC_ULONG: return "FC_ULONG";
00113     case RPC_FC_FLOAT: return "FC_FLOAT";
00114     case RPC_FC_HYPER: return "FC_HYPER";
00115     case RPC_FC_DOUBLE: return "FC_DOUBLE";
00116     case RPC_FC_ENUM16: return "FC_ENUM16";
00117     case RPC_FC_ENUM32: return "FC_ENUM32";
00118     case RPC_FC_IGNORE: return "FC_IGNORE";
00119     case RPC_FC_ERROR_STATUS_T: return "FC_ERROR_STATUS_T";
00120     case RPC_FC_RP: return "FC_RP";
00121     case RPC_FC_UP: return "FC_UP";
00122     case RPC_FC_OP: return "FC_OP";
00123     case RPC_FC_FP: return "FC_FP";
00124     case RPC_FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION";
00125     case RPC_FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION";
00126     case RPC_FC_STRUCT: return "FC_STRUCT";
00127     case RPC_FC_PSTRUCT: return "FC_PSTRUCT";
00128     case RPC_FC_CSTRUCT: return "FC_CSTRUCT";
00129     case RPC_FC_CPSTRUCT: return "FC_CPSTRUCT";
00130     case RPC_FC_CVSTRUCT: return "FC_CVSTRUCT";
00131     case RPC_FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT";
00132     case RPC_FC_SMFARRAY: return "FC_SMFARRAY";
00133     case RPC_FC_LGFARRAY: return "FC_LGFARRAY";
00134     case RPC_FC_SMVARRAY: return "FC_SMVARRAY";
00135     case RPC_FC_LGVARRAY: return "FC_LGVARRAY";
00136     case RPC_FC_CARRAY: return "FC_CARRAY";
00137     case RPC_FC_CVARRAY: return "FC_CVARRAY";
00138     case RPC_FC_BOGUS_ARRAY: return "FC_BOGUS_ARRAY";
00139     case RPC_FC_ALIGNM2: return "FC_ALIGNM2";
00140     case RPC_FC_ALIGNM4: return "FC_ALIGNM4";
00141     case RPC_FC_ALIGNM8: return "FC_ALIGNM8";
00142     case RPC_FC_POINTER: return "FC_POINTER";
00143     case RPC_FC_C_CSTRING: return "FC_C_CSTRING";
00144     case RPC_FC_C_WSTRING: return "FC_C_WSTRING";
00145     case RPC_FC_CSTRING: return "FC_CSTRING";
00146     case RPC_FC_WSTRING: return "FC_WSTRING";
00147     case RPC_FC_BYTE_COUNT_POINTER: return "FC_BYTE_COUNT_POINTER";
00148     case RPC_FC_TRANSMIT_AS: return "FC_TRANSMIT_AS";
00149     case RPC_FC_REPRESENT_AS: return "FC_REPRESENT_AS";
00150     case RPC_FC_IP: return "FC_IP";
00151     case RPC_FC_BIND_CONTEXT: return "FC_BIND_CONTEXT";
00152     case RPC_FC_BIND_GENERIC: return "FC_BIND_GENERIC";
00153     case RPC_FC_BIND_PRIMITIVE: return "FC_BIND_PRIMITIVE";
00154     case RPC_FC_AUTO_HANDLE: return "FC_AUTO_HANDLE";
00155     case RPC_FC_CALLBACK_HANDLE: return "FC_CALLBACK_HANDLE";
00156     case RPC_FC_STRUCTPAD1: return "FC_STRUCTPAD1";
00157     case RPC_FC_STRUCTPAD2: return "FC_STRUCTPAD2";
00158     case RPC_FC_STRUCTPAD3: return "FC_STRUCTPAD3";
00159     case RPC_FC_STRUCTPAD4: return "FC_STRUCTPAD4";
00160     case RPC_FC_STRUCTPAD5: return "FC_STRUCTPAD5";
00161     case RPC_FC_STRUCTPAD6: return "FC_STRUCTPAD6";
00162     case RPC_FC_STRUCTPAD7: return "FC_STRUCTPAD7";
00163     case RPC_FC_STRING_SIZED: return "FC_STRING_SIZED";
00164     case RPC_FC_NO_REPEAT: return "FC_NO_REPEAT";
00165     case RPC_FC_FIXED_REPEAT: return "FC_FIXED_REPEAT";
00166     case RPC_FC_VARIABLE_REPEAT: return "FC_VARIABLE_REPEAT";
00167     case RPC_FC_FIXED_OFFSET: return "FC_FIXED_OFFSET";
00168     case RPC_FC_VARIABLE_OFFSET: return "FC_VARIABLE_OFFSET";
00169     case RPC_FC_PP: return "FC_PP";
00170     case RPC_FC_EMBEDDED_COMPLEX: return "FC_EMBEDDED_COMPLEX";
00171     case RPC_FC_DEREFERENCE: return "FC_DEREFERENCE";
00172     case RPC_FC_DIV_2: return "FC_DIV_2";
00173     case RPC_FC_MULT_2: return "FC_MULT_2";
00174     case RPC_FC_ADD_1: return "FC_ADD_1";
00175     case RPC_FC_SUB_1: return "FC_SUB_1";
00176     case RPC_FC_CALLBACK: return "FC_CALLBACK";
00177     case RPC_FC_CONSTANT_IID: return "FC_CONSTANT_IID";
00178     case RPC_FC_END: return "FC_END";
00179     case RPC_FC_PAD: return "FC_PAD";
00180     case RPC_FC_USER_MARSHAL: return "FC_USER_MARSHAL";
00181     case RPC_FC_RANGE: return "FC_RANGE";
00182     case RPC_FC_INT3264: return "FC_INT3264";
00183     case RPC_FC_UINT3264: return "FC_UINT3264";
00184     default:
00185         error("string_of_type: unknown type 0x%02x\n", type);
00186         return NULL;
00187     }
00188 }
00189 
00190 static void *get_aliaschain_attrp(const type_t *type, enum attr_type attr)
00191 {
00192     const type_t *t = type;
00193     for (;;)
00194     {
00195         if (is_attr(t->attrs, attr))
00196             return get_attrp(t->attrs, attr);
00197         else if (type_is_alias(t))
00198             t = type_alias_get_aliasee(t);
00199         else return NULL;
00200     }
00201 }
00202 
00203 unsigned char get_basic_fc(const type_t *type)
00204 {
00205     int sign = type_basic_get_sign(type);
00206     switch (type_basic_get_type(type))
00207     {
00208     case TYPE_BASIC_INT8: return (sign <= 0 ? RPC_FC_SMALL : RPC_FC_USMALL);
00209     case TYPE_BASIC_INT16: return (sign <= 0 ? RPC_FC_SHORT : RPC_FC_USHORT);
00210     case TYPE_BASIC_INT32: return (sign <= 0 ? RPC_FC_LONG : RPC_FC_ULONG);
00211     case TYPE_BASIC_INT64: return RPC_FC_HYPER;
00212     case TYPE_BASIC_INT: return (sign <= 0 ? RPC_FC_LONG : RPC_FC_ULONG);
00213     case TYPE_BASIC_INT3264: return (sign <= 0 ? RPC_FC_INT3264 : RPC_FC_UINT3264);
00214     case TYPE_BASIC_BYTE: return RPC_FC_BYTE;
00215     case TYPE_BASIC_CHAR: return RPC_FC_CHAR;
00216     case TYPE_BASIC_WCHAR: return RPC_FC_WCHAR;
00217     case TYPE_BASIC_HYPER: return RPC_FC_HYPER;
00218     case TYPE_BASIC_FLOAT: return RPC_FC_FLOAT;
00219     case TYPE_BASIC_DOUBLE: return RPC_FC_DOUBLE;
00220     case TYPE_BASIC_ERROR_STATUS_T: return RPC_FC_ERROR_STATUS_T;
00221     case TYPE_BASIC_HANDLE: return RPC_FC_BIND_PRIMITIVE;
00222     }
00223     return 0;
00224 }
00225 
00226 static unsigned char get_basic_fc_signed(const type_t *type)
00227 {
00228     switch (type_basic_get_type(type))
00229     {
00230     case TYPE_BASIC_INT8: return RPC_FC_SMALL;
00231     case TYPE_BASIC_INT16: return RPC_FC_SHORT;
00232     case TYPE_BASIC_INT32: return RPC_FC_LONG;
00233     case TYPE_BASIC_INT64: return RPC_FC_HYPER;
00234     case TYPE_BASIC_INT: return RPC_FC_LONG;
00235     case TYPE_BASIC_INT3264: return RPC_FC_INT3264;
00236     case TYPE_BASIC_BYTE: return RPC_FC_BYTE;
00237     case TYPE_BASIC_CHAR: return RPC_FC_CHAR;
00238     case TYPE_BASIC_WCHAR: return RPC_FC_WCHAR;
00239     case TYPE_BASIC_HYPER: return RPC_FC_HYPER;
00240     case TYPE_BASIC_FLOAT: return RPC_FC_FLOAT;
00241     case TYPE_BASIC_DOUBLE: return RPC_FC_DOUBLE;
00242     case TYPE_BASIC_ERROR_STATUS_T: return RPC_FC_ERROR_STATUS_T;
00243     case TYPE_BASIC_HANDLE: return RPC_FC_BIND_PRIMITIVE;
00244     }
00245     return 0;
00246 }
00247 
00248 static inline unsigned int clamp_align(unsigned int align)
00249 {
00250     unsigned int packing = (pointer_size == 4) ? win32_packing : win64_packing;
00251     if(align > packing) align = packing;
00252     return align;
00253 }
00254 
00255 unsigned char get_pointer_fc(const type_t *type, const attr_list_t *attrs, int toplevel_param)
00256 {
00257     const type_t *t;
00258     int pointer_type;
00259 
00260     assert(is_ptr(type) || is_array(type));
00261 
00262     pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
00263     if (pointer_type)
00264         return pointer_type;
00265 
00266     for (t = type; type_is_alias(t); t = type_alias_get_aliasee(t))
00267     {
00268         pointer_type = get_attrv(t->attrs, ATTR_POINTERTYPE);
00269         if (pointer_type)
00270             return pointer_type;
00271     }
00272 
00273     if (toplevel_param)
00274         return RPC_FC_RP;
00275     else if (is_ptr(type))
00276         return type_pointer_get_default_fc(type);
00277     else
00278         return type_array_get_ptr_default_fc(type);
00279 }
00280 
00281 static unsigned char get_pointer_fc_context( const type_t *type, const attr_list_t *attrs,
00282                                              enum type_context context )
00283 {
00284     int pointer_fc = get_pointer_fc(type, attrs, context == TYPE_CONTEXT_TOPLEVELPARAM);
00285 
00286     if (pointer_fc == RPC_FC_UP && is_attr( attrs, ATTR_OUT ) &&
00287         context == TYPE_CONTEXT_PARAM && is_object( current_iface ))
00288         pointer_fc = RPC_FC_OP;
00289 
00290     return pointer_fc;
00291 }
00292 
00293 static unsigned char get_enum_fc(const type_t *type)
00294 {
00295     assert(type_get_type(type) == TYPE_ENUM);
00296     if (is_aliaschain_attr(type, ATTR_V1ENUM))
00297         return RPC_FC_ENUM32;
00298     else
00299         return RPC_FC_ENUM16;
00300 }
00301 
00302 static type_t *get_user_type(const type_t *t, const char **pname)
00303 {
00304     for (;;)
00305     {
00306         type_t *ut = get_attrp(t->attrs, ATTR_WIREMARSHAL);
00307         if (ut)
00308         {
00309             if (pname)
00310                 *pname = t->name;
00311             return ut;
00312         }
00313 
00314         if (type_is_alias(t))
00315             t = type_alias_get_aliasee(t);
00316         else
00317             return NULL;
00318     }
00319 }
00320 
00321 static int is_user_type(const type_t *t)
00322 {
00323     return get_user_type(t, NULL) != NULL;
00324 }
00325 
00326 enum typegen_type typegen_detect_type(const type_t *type, const attr_list_t *attrs, unsigned int flags)
00327 {
00328     if (is_user_type(type))
00329         return TGT_USER_TYPE;
00330 
00331     if (is_aliaschain_attr(type, ATTR_CONTEXTHANDLE))
00332         return TGT_CTXT_HANDLE;
00333 
00334     if (!(flags & TDT_IGNORE_STRINGS) && is_string_type(attrs, type))
00335         return TGT_STRING;
00336 
00337     switch (type_get_type(type))
00338     {
00339     case TYPE_BASIC:
00340         if (!(flags & TDT_IGNORE_RANGES) &&
00341             (is_attr(attrs, ATTR_RANGE) || is_aliaschain_attr(type, ATTR_RANGE)))
00342             return TGT_RANGE;
00343         return TGT_BASIC;
00344     case TYPE_ENUM:
00345         if (!(flags & TDT_IGNORE_RANGES) &&
00346             (is_attr(attrs, ATTR_RANGE) || is_aliaschain_attr(type, ATTR_RANGE)))
00347             return TGT_RANGE;
00348         return TGT_ENUM;
00349     case TYPE_POINTER:
00350         if (type_get_type(type_pointer_get_ref(type)) == TYPE_INTERFACE ||
00351             (type_get_type(type_pointer_get_ref(type)) == TYPE_VOID && is_attr(attrs, ATTR_IIDIS)))
00352             return TGT_IFACE_POINTER;
00353         else if (is_aliaschain_attr(type_pointer_get_ref(type), ATTR_CONTEXTHANDLE))
00354             return TGT_CTXT_HANDLE_POINTER;
00355         else
00356             return TGT_POINTER;
00357     case TYPE_STRUCT:
00358         return TGT_STRUCT;
00359     case TYPE_ENCAPSULATED_UNION:
00360     case TYPE_UNION:
00361         return TGT_UNION;
00362     case TYPE_ARRAY:
00363         return TGT_ARRAY;
00364     case TYPE_FUNCTION:
00365     case TYPE_COCLASS:
00366     case TYPE_INTERFACE:
00367     case TYPE_MODULE:
00368     case TYPE_VOID:
00369     case TYPE_ALIAS:
00370     case TYPE_BITFIELD:
00371         break;
00372     }
00373     return TGT_INVALID;
00374 }
00375 
00376 static int cant_be_null(const var_t *v)
00377 {
00378     switch (typegen_detect_type(v->type, v->attrs, TDT_IGNORE_STRINGS))
00379     {
00380     case TGT_ARRAY:
00381         if (!type_array_is_decl_as_ptr( v->type )) return 0;
00382         /* fall through */
00383     case TGT_POINTER:
00384         return (get_pointer_fc(v->type, v->attrs, TRUE) == RPC_FC_RP);
00385     case TGT_CTXT_HANDLE_POINTER:
00386         return TRUE;
00387     default:
00388         return 0;
00389     }
00390 
00391 }
00392 
00393 static int get_padding(const var_list_t *fields)
00394 {
00395     unsigned short offset = 0;
00396     unsigned int salign = 1;
00397     const var_t *f;
00398 
00399     if (!fields)
00400         return 0;
00401 
00402     LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry)
00403     {
00404         type_t *ft = f->type;
00405         unsigned int align = 0;
00406         unsigned int size = type_memsize_and_alignment(ft, &align);
00407         align = clamp_align(align);
00408         if (align > salign) salign = align;
00409         offset = ROUND_SIZE(offset, align);
00410         offset += size;
00411     }
00412 
00413     return ROUNDING(offset, salign);
00414 }
00415 
00416 static unsigned int get_stack_size( const type_t *type, const attr_list_t *attrs, int *by_value )
00417 {
00418     unsigned int stack_size;
00419     int by_val;
00420 
00421     switch (typegen_detect_type( type, attrs, TDT_ALL_TYPES ))
00422     {
00423     case TGT_BASIC:
00424     case TGT_ENUM:
00425     case TGT_RANGE:
00426     case TGT_STRUCT:
00427     case TGT_UNION:
00428     case TGT_USER_TYPE:
00429         stack_size = type_memsize( type );
00430         by_val = (pointer_size < 8 || stack_size <= pointer_size); /* FIXME: should be platform-specific */
00431         break;
00432     default:
00433         by_val = 0;
00434         break;
00435     }
00436     if (!by_val) stack_size = pointer_size;
00437     if (by_value) *by_value = by_val;
00438     return ROUND_SIZE( stack_size, pointer_size );
00439 }
00440 
00441 static unsigned char get_contexthandle_flags( const type_t *iface, const attr_list_t *attrs,
00442                                               const type_t *type )
00443 {
00444     unsigned char flags = 0;
00445 
00446     if (is_attr(iface->attrs, ATTR_STRICTCONTEXTHANDLE)) flags |= NDR_STRICT_CONTEXT_HANDLE;
00447 
00448     if (is_ptr(type) &&
00449         !is_attr( type->attrs, ATTR_CONTEXTHANDLE ) &&
00450         !is_attr( attrs, ATTR_CONTEXTHANDLE ))
00451         flags |= 0x80;
00452 
00453     if (is_attr(attrs, ATTR_IN))
00454     {
00455         flags |= 0x40;
00456         if (!is_attr(attrs, ATTR_OUT)) flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
00457     }
00458     if (is_attr(attrs, ATTR_OUT)) flags |= 0x20;
00459 
00460     return flags;
00461 }
00462 
00463 static unsigned int get_rpc_flags( const attr_list_t *attrs )
00464 {
00465     unsigned int flags = 0;
00466 
00467     if (is_attr( attrs, ATTR_IDEMPOTENT )) flags |= 0x0001;
00468     if (is_attr( attrs, ATTR_BROADCAST )) flags |= 0x0002;
00469     if (is_attr( attrs, ATTR_MAYBE )) flags |= 0x0004;
00470     if (is_attr( attrs, ATTR_MESSAGE )) flags |= 0x0100;
00471     if (is_attr( attrs, ATTR_ASYNC )) flags |= 0x4000;
00472     return flags;
00473 }
00474 
00475 unsigned char get_struct_fc(const type_t *type)
00476 {
00477   int has_pointer = 0;
00478   int has_conformance = 0;
00479   int has_variance = 0;
00480   var_t *field;
00481   var_list_t *fields;
00482 
00483   fields = type_struct_get_fields(type);
00484 
00485   if (get_padding(fields))
00486     return RPC_FC_BOGUS_STRUCT;
00487 
00488   if (fields) LIST_FOR_EACH_ENTRY( field, fields, var_t, entry )
00489   {
00490     type_t *t = field->type;
00491     enum typegen_type typegen_type;
00492 
00493     typegen_type = typegen_detect_type(t, field->attrs, TDT_IGNORE_STRINGS);
00494 
00495     if (typegen_type == TGT_ARRAY && !type_array_is_decl_as_ptr(t))
00496     {
00497         if (is_string_type(field->attrs, field->type))
00498         {
00499             if (is_conformant_array(t))
00500                 has_conformance = 1;
00501             has_variance = 1;
00502             continue;
00503         }
00504 
00505         if (is_array(type_array_get_element(field->type)))
00506             return RPC_FC_BOGUS_STRUCT;
00507 
00508         if (type_array_has_conformance(field->type))
00509         {
00510             has_conformance = 1;
00511             if (list_next(fields, &field->entry))
00512                 error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
00513                         field->name);
00514         }
00515         if (type_array_has_variance(t))
00516             has_variance = 1;
00517 
00518         t = type_array_get_element(t);
00519         typegen_type = typegen_detect_type(t, field->attrs, TDT_IGNORE_STRINGS);
00520     }
00521 
00522     switch (typegen_type)
00523     {
00524     case TGT_USER_TYPE:
00525     case TGT_IFACE_POINTER:
00526         return RPC_FC_BOGUS_STRUCT;
00527     case TGT_BASIC:
00528         if (type_basic_get_type(t) == TYPE_BASIC_INT3264 && pointer_size != 4)
00529             return RPC_FC_BOGUS_STRUCT;
00530         break;
00531     case TGT_ENUM:
00532         if (get_enum_fc(t) == RPC_FC_ENUM16)
00533             return RPC_FC_BOGUS_STRUCT;
00534         break;
00535     case TGT_POINTER:
00536     case TGT_ARRAY:
00537         if (get_pointer_fc(t, field->attrs, FALSE) == RPC_FC_RP || pointer_size != 4)
00538             return RPC_FC_BOGUS_STRUCT;
00539         has_pointer = 1;
00540         break;
00541     case TGT_UNION:
00542         return RPC_FC_BOGUS_STRUCT;
00543     case TGT_STRUCT:
00544     {
00545         unsigned char fc = get_struct_fc(t);
00546         switch (fc)
00547         {
00548         case RPC_FC_STRUCT:
00549             break;
00550         case RPC_FC_CVSTRUCT:
00551             has_conformance = 1;
00552             has_variance = 1;
00553             has_pointer = 1;
00554             break;
00555 
00556         case RPC_FC_CPSTRUCT:
00557             has_conformance = 1;
00558             if (list_next( fields, &field->entry ))
00559                 error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
00560                         field->name);
00561             has_pointer = 1;
00562             break;
00563 
00564         case RPC_FC_CSTRUCT:
00565             has_conformance = 1;
00566             if (list_next( fields, &field->entry ))
00567                 error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
00568                       field->name);
00569             break;
00570 
00571         case RPC_FC_PSTRUCT:
00572             has_pointer = 1;
00573             break;
00574 
00575         default:
00576             error_loc("Unknown struct member %s with type (0x%02x)\n", field->name, fc);
00577             /* fallthru - treat it as complex */
00578 
00579         /* as soon as we see one of these these members, it's bogus... */
00580         case RPC_FC_BOGUS_STRUCT:
00581             return RPC_FC_BOGUS_STRUCT;
00582         }
00583         break;
00584     }
00585     case TGT_RANGE:
00586         return RPC_FC_BOGUS_STRUCT;
00587     case TGT_STRING:
00588         /* shouldn't get here because of TDT_IGNORE_STRINGS above. fall through */
00589     case TGT_INVALID:
00590     case TGT_CTXT_HANDLE:
00591     case TGT_CTXT_HANDLE_POINTER:
00592         /* checking after parsing should mean that we don't get here. if we do,
00593          * it's a checker bug */
00594         assert(0);
00595     }
00596   }
00597 
00598   if( has_variance )
00599   {
00600     if ( has_conformance )
00601       return RPC_FC_CVSTRUCT;
00602     else
00603       return RPC_FC_BOGUS_STRUCT;
00604   }
00605   if( has_conformance && has_pointer )
00606     return RPC_FC_CPSTRUCT;
00607   if( has_conformance )
00608     return RPC_FC_CSTRUCT;
00609   if( has_pointer )
00610     return RPC_FC_PSTRUCT;
00611   return RPC_FC_STRUCT;
00612 }
00613 
00614 static unsigned char get_array_fc(const type_t *type)
00615 {
00616     unsigned char fc;
00617     const expr_t *size_is;
00618     const type_t *elem_type;
00619 
00620     elem_type = type_array_get_element(type);
00621     size_is = type_array_get_conformance(type);
00622 
00623     if (!size_is)
00624     {
00625         unsigned int size = type_memsize(elem_type);
00626         if (size * type_array_get_dim(type) > 0xffffuL)
00627             fc = RPC_FC_LGFARRAY;
00628         else
00629             fc = RPC_FC_SMFARRAY;
00630     }
00631     else
00632         fc = RPC_FC_CARRAY;
00633 
00634     if (type_array_has_variance(type))
00635     {
00636         if (fc == RPC_FC_SMFARRAY)
00637             fc = RPC_FC_SMVARRAY;
00638         else if (fc == RPC_FC_LGFARRAY)
00639             fc = RPC_FC_LGVARRAY;
00640         else if (fc == RPC_FC_CARRAY)
00641             fc = RPC_FC_CVARRAY;
00642     }
00643 
00644     switch (typegen_detect_type(elem_type, NULL, TDT_IGNORE_STRINGS))
00645     {
00646     case TGT_USER_TYPE:
00647         fc = RPC_FC_BOGUS_ARRAY;
00648         break;
00649     case TGT_BASIC:
00650         if (type_basic_get_type(elem_type) == TYPE_BASIC_INT3264 &&
00651             pointer_size != 4)
00652             fc = RPC_FC_BOGUS_ARRAY;
00653         break;
00654     case TGT_STRUCT:
00655         switch (get_struct_fc(elem_type))
00656         {
00657         case RPC_FC_BOGUS_STRUCT:
00658             fc = RPC_FC_BOGUS_ARRAY;
00659             break;
00660         }
00661         break;
00662     case TGT_ENUM:
00663         /* is 16-bit enum - if so, wire size differs from mem size and so
00664          * the array cannot be block copied, which means the array is complex */
00665         if (get_enum_fc(elem_type) == RPC_FC_ENUM16)
00666             fc = RPC_FC_BOGUS_ARRAY;
00667         break;
00668     case TGT_UNION:
00669     case TGT_IFACE_POINTER:
00670         fc = RPC_FC_BOGUS_ARRAY;
00671         break;
00672     case TGT_POINTER:
00673         /* ref pointers cannot just be block copied. unique pointers to
00674          * interfaces need special treatment. either case means the array is
00675          * complex */
00676         if (get_pointer_fc(elem_type, NULL, FALSE) == RPC_FC_RP || pointer_size != 4)
00677             fc = RPC_FC_BOGUS_ARRAY;
00678         break;
00679     case TGT_RANGE:
00680         fc = RPC_FC_BOGUS_ARRAY;
00681         break;
00682     case TGT_CTXT_HANDLE:
00683     case TGT_CTXT_HANDLE_POINTER:
00684     case TGT_STRING:
00685     case TGT_INVALID:
00686     case TGT_ARRAY:
00687         /* nothing to do for everything else */
00688         break;
00689     }
00690 
00691     return fc;
00692 }
00693 
00694 static int is_non_complex_struct(const type_t *type)
00695 {
00696     return (type_get_type(type) == TYPE_STRUCT &&
00697             get_struct_fc(type) != RPC_FC_BOGUS_STRUCT);
00698 }
00699 
00700 static int type_has_pointers(const type_t *type)
00701 {
00702     switch (typegen_detect_type(type, NULL, TDT_IGNORE_STRINGS))
00703     {
00704     case TGT_USER_TYPE:
00705         return FALSE;
00706     case TGT_POINTER:
00707         return TRUE;
00708     case TGT_ARRAY:
00709         return type_array_is_decl_as_ptr(type) || type_has_pointers(type_array_get_element(type));
00710     case TGT_STRUCT:
00711     {
00712         var_list_t *fields = type_struct_get_fields(type);
00713         const var_t *field;
00714         if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
00715         {
00716             if (type_has_pointers(field->type))
00717                 return TRUE;
00718         }
00719         break;
00720     }
00721     case TGT_UNION:
00722     {
00723         var_list_t *fields;
00724         const var_t *field;
00725         fields = type_union_get_cases(type);
00726         if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
00727         {
00728             if (field->type && type_has_pointers(field->type))
00729                 return TRUE;
00730         }
00731         break;
00732     }
00733     case TGT_CTXT_HANDLE:
00734     case TGT_CTXT_HANDLE_POINTER:
00735     case TGT_STRING:
00736     case TGT_IFACE_POINTER:
00737     case TGT_BASIC:
00738     case TGT_ENUM:
00739     case TGT_RANGE:
00740     case TGT_INVALID:
00741         break;
00742     }
00743 
00744     return FALSE;
00745 }
00746 
00747 static int type_has_full_pointer(const type_t *type, const attr_list_t *attrs,
00748                                  int toplevel_param)
00749 {
00750     switch (typegen_detect_type(type, NULL, TDT_IGNORE_STRINGS))
00751     {
00752     case TGT_USER_TYPE:
00753         return FALSE;
00754     case TGT_POINTER:
00755         if (get_pointer_fc(type, attrs, toplevel_param) == RPC_FC_FP)
00756             return TRUE;
00757         else
00758             return FALSE;
00759     case TGT_ARRAY:
00760         if (get_pointer_fc(type, attrs, toplevel_param) == RPC_FC_FP)
00761             return TRUE;
00762         else
00763             return type_has_full_pointer(type_array_get_element(type), NULL, FALSE);
00764     case TGT_STRUCT:
00765     {
00766         var_list_t *fields = type_struct_get_fields(type);
00767         const var_t *field;
00768         if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
00769         {
00770             if (type_has_full_pointer(field->type, field->attrs, FALSE))
00771                 return TRUE;
00772         }
00773         break;
00774     }
00775     case TGT_UNION:
00776     {
00777         var_list_t *fields;
00778         const var_t *field;
00779         fields = type_union_get_cases(type);
00780         if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
00781         {
00782             if (field->type && type_has_full_pointer(field->type, field->attrs, FALSE))
00783                 return TRUE;
00784         }
00785         break;
00786     }
00787     case TGT_CTXT_HANDLE:
00788     case TGT_CTXT_HANDLE_POINTER:
00789     case TGT_STRING:
00790     case TGT_IFACE_POINTER:
00791     case TGT_BASIC:
00792     case TGT_ENUM:
00793     case TGT_RANGE:
00794     case TGT_INVALID:
00795         break;
00796     }
00797 
00798     return FALSE;
00799 }
00800 
00801 static unsigned short user_type_offset(const char *name)
00802 {
00803     user_type_t *ut;
00804     unsigned short off = 0;
00805     LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
00806     {
00807         if (strcmp(name, ut->name) == 0)
00808             return off;
00809         ++off;
00810     }
00811     error("user_type_offset: couldn't find type (%s)\n", name);
00812     return 0;
00813 }
00814 
00815 static void update_tfsoff(type_t *type, unsigned int offset, FILE *file)
00816 {
00817     type->typestring_offset = offset;
00818     if (file) type->tfswrite = FALSE;
00819 }
00820 
00821 static void guard_rec(type_t *type)
00822 {
00823     /* types that contain references to themselves (like a linked list),
00824        need to be shielded from infinite recursion when writing embedded
00825        types  */
00826     if (type->typestring_offset)
00827         type->tfswrite = FALSE;
00828     else
00829         type->typestring_offset = 1;
00830 }
00831 
00832 static int is_embedded_complex(const type_t *type)
00833 {
00834     switch (typegen_detect_type(type, NULL, TDT_ALL_TYPES))
00835     {
00836     case TGT_USER_TYPE:
00837     case TGT_STRUCT:
00838     case TGT_UNION:
00839     case TGT_ARRAY:
00840     case TGT_IFACE_POINTER:
00841         return TRUE;
00842     default:
00843         return FALSE;
00844     }
00845 }
00846 
00847 static const char *get_context_handle_type_name(const type_t *type)
00848 {
00849     const type_t *t;
00850     for (t = type;
00851          is_ptr(t) || type_is_alias(t);
00852          t = type_is_alias(t) ? type_alias_get_aliasee(t) : type_pointer_get_ref(t))
00853         if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
00854             return t->name;
00855     assert(0);
00856     return NULL;
00857 }
00858 
00859 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
00860     do { \
00861         if (file) \
00862             fprintf(file, "/* %2u */\n", typestring_offset); \
00863         print_file((file), 2, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
00864     } \
00865     while (0)
00866 
00867 static void print_file(FILE *file, int indent, const char *format, ...) __attribute__((format (printf, 3, 4)));
00868 static void print_file(FILE *file, int indent, const char *format, ...)
00869 {
00870     va_list va;
00871     va_start(va, format);
00872     print(file, indent, format, va);
00873     va_end(va);
00874 }
00875 
00876 void print(FILE *file, int indent, const char *format, va_list va)
00877 {
00878     if (file)
00879     {
00880         if (format[0] != '\n')
00881             while (0 < indent--)
00882                 fprintf(file, "    ");
00883         vfprintf(file, format, va);
00884     }
00885 }
00886 
00887 
00888 static void write_var_init(FILE *file, int indent, const type_t *t, const char *n, const char *local_var_prefix)
00889 {
00890     if (decl_indirect(t))
00891     {
00892         print_file(file, indent, "MIDL_memset(&%s%s, 0, sizeof(%s%s));\n",
00893                    local_var_prefix, n, local_var_prefix, n);
00894         print_file(file, indent, "%s_p_%s = &%s%s;\n", local_var_prefix, n, local_var_prefix, n);
00895     }
00896     else if (is_ptr(t) || is_array(t))
00897         print_file(file, indent, "%s%s = 0;\n", local_var_prefix, n);
00898 }
00899 
00900 void write_parameters_init(FILE *file, int indent, const var_t *func, const char *local_var_prefix)
00901 {
00902     const var_t *var;
00903 
00904     if (!is_void(type_function_get_rettype(func->type)))
00905         write_var_init(file, indent, type_function_get_rettype(func->type), "_RetVal", local_var_prefix);
00906 
00907     if (!type_get_function_args(func->type))
00908         return;
00909 
00910     LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
00911         write_var_init(file, indent, var->type, var->name, local_var_prefix);
00912 
00913     fprintf(file, "\n");
00914 }
00915 
00916 static void write_formatdesc(FILE *f, int indent, const char *str)
00917 {
00918     print_file(f, indent, "typedef struct _MIDL_%s_FORMAT_STRING\n", str);
00919     print_file(f, indent, "{\n");
00920     print_file(f, indent + 1, "short Pad;\n");
00921     print_file(f, indent + 1, "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str);
00922     print_file(f, indent, "} MIDL_%s_FORMAT_STRING;\n", str);
00923     print_file(f, indent, "\n");
00924 }
00925 
00926 void write_formatstringsdecl(FILE *f, int indent, const statement_list_t *stmts, type_pred_t pred)
00927 {
00928     clear_all_offsets();
00929 
00930     print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n",
00931                get_size_typeformatstring(stmts, pred));
00932 
00933     print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n",
00934                get_size_procformatstring(stmts, pred));
00935 
00936     fprintf(f, "\n");
00937     write_formatdesc(f, indent, "TYPE");
00938     write_formatdesc(f, indent, "PROC");
00939     fprintf(f, "\n");
00940     print_file(f, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n");
00941     print_file(f, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n");
00942     print_file(f, indent, "\n");
00943 }
00944 
00945 int decl_indirect(const type_t *t)
00946 {
00947     if (is_user_type(t))
00948         return TRUE;
00949     return (type_get_type(t) != TYPE_BASIC &&
00950             type_get_type(t) != TYPE_ENUM &&
00951             type_get_type(t) != TYPE_POINTER &&
00952             type_get_type(t) != TYPE_ARRAY);
00953 }
00954 
00955 static unsigned char get_parameter_fc( const type_t *type, const attr_list_t *attrs, int is_return,
00956                                        unsigned short *flags, unsigned int *stack_size,
00957                                        unsigned int *typestring_offset )
00958 {
00959     unsigned int alignment, server_size = 0, buffer_size = 0;
00960     unsigned char fc = 0;
00961     int is_byval;
00962     int is_in = is_attr(attrs, ATTR_IN);
00963     int is_out = is_attr(attrs, ATTR_OUT);
00964 
00965     if (is_return) is_out = TRUE;
00966     else if (!is_in && !is_out) is_in = TRUE;
00967 
00968     *flags = 0;
00969     *stack_size = get_stack_size( type, attrs, &is_byval );
00970     *typestring_offset = type->typestring_offset;
00971 
00972     if (is_in)     *flags |= IsIn;
00973     if (is_out)    *flags |= IsOut;
00974     if (is_return) *flags |= IsReturn;
00975 
00976     if (!is_string_type( attrs, type ))
00977         buffer_size = get_required_buffer_size_type( type, NULL, attrs, TRUE, &alignment );
00978 
00979     switch (typegen_detect_type( type, attrs, TDT_ALL_TYPES ))
00980     {
00981     case TGT_BASIC:
00982         *flags |= IsBasetype;
00983         fc = get_basic_fc_signed( type );
00984         if (fc == RPC_FC_BIND_PRIMITIVE)
00985         {
00986             buffer_size = 4;  /* actually 0 but avoids setting MustSize */
00987             fc = RPC_FC_LONG;
00988         }
00989         break;
00990     case TGT_ENUM:
00991         *flags |= IsBasetype;
00992         fc = get_enum_fc( type );
00993         break;
00994     case TGT_RANGE:
00995         *flags |= IsByValue;
00996         break;
00997     case TGT_STRUCT:
00998     case TGT_UNION:
00999     case TGT_USER_TYPE:
01000         *flags |= MustFree | (is_byval ? IsByValue : IsSimpleRef);
01001         break;
01002     case TGT_IFACE_POINTER:
01003         *flags |= MustFree;
01004         break;
01005     case TGT_ARRAY:
01006         *flags |= MustFree;
01007         if (type_array_is_decl_as_ptr(type) && type->details.array.ptr_tfsoff &&
01008             get_pointer_fc( type, attrs, !is_return ) == RPC_FC_RP)
01009             *flags |= IsSimpleRef;
01010         break;
01011     case TGT_STRING:
01012         *flags |= MustFree;
01013         if (is_declptr( type ) && get_pointer_fc( type, attrs, !is_return ) == RPC_FC_RP)
01014         {
01015             /* skip over pointer description straight to string description */
01016             if (is_conformant_array( type )) *typestring_offset += 4;
01017             else *typestring_offset += 2;
01018             *flags |= IsSimpleRef;
01019         }
01020         break;
01021     case TGT_CTXT_HANDLE_POINTER:
01022         *flags |= IsSimpleRef;
01023         *typestring_offset += 4;
01024         /* fall through */
01025     case TGT_CTXT_HANDLE:
01026         buffer_size = 20;
01027         break;
01028     case TGT_POINTER:
01029         if (get_pointer_fc( type, attrs, !is_return ) == RPC_FC_RP)
01030         {
01031             const type_t *ref = type_pointer_get_ref( type );
01032 
01033             if (!is_string_type( attrs, ref ))
01034                 buffer_size = get_required_buffer_size_type( ref, NULL, NULL, TRUE, &alignment );
01035 
01036             switch (typegen_detect_type( ref, NULL, TDT_ALL_TYPES ))
01037             {
01038             case TGT_BASIC:
01039                 *flags |= IsSimpleRef | IsBasetype;
01040                 fc = get_basic_fc( ref );
01041                 if (!is_in && is_out) server_size = pointer_size;
01042                 break;
01043             case TGT_ENUM:
01044                 if ((fc = get_enum_fc( ref )) == RPC_FC_ENUM32)
01045                 {
01046                     *flags |= IsSimpleRef | IsBasetype;
01047                     if (!is_in && is_out) server_size = pointer_size;
01048                 }
01049                 else
01050                 {
01051                     server_size = pointer_size;
01052                 }
01053                 break;
01054             case TGT_UNION:
01055             case TGT_USER_TYPE:
01056             case TGT_RANGE:
01057                 *flags |= IsSimpleRef | MustFree;
01058                 *typestring_offset = ref->typestring_offset;
01059                 if (!is_in && is_out) server_size = type_memsize( ref );
01060                 break;
01061             case TGT_STRING:
01062             case TGT_POINTER:
01063             case TGT_ARRAY:
01064             case TGT_CTXT_HANDLE:
01065             case TGT_CTXT_HANDLE_POINTER:
01066                 *flags |= MustFree;
01067                 server_size = pointer_size;
01068                 break;
01069             case TGT_IFACE_POINTER:
01070                 *flags |= MustFree;
01071                 if (is_in && is_out) server_size = pointer_size;
01072                 break;
01073             case TGT_STRUCT:
01074                 *flags |= IsSimpleRef | MustFree;
01075                 *typestring_offset = ref->typestring_offset;
01076                 switch (get_struct_fc(ref))
01077                 {
01078                 case RPC_FC_STRUCT:
01079                 case RPC_FC_PSTRUCT:
01080                 case RPC_FC_BOGUS_STRUCT:
01081                     if (!is_in && is_out) server_size = type_memsize( ref );
01082                     break;
01083                 default:
01084                     break;
01085                 }
01086                 break;
01087             case TGT_INVALID:
01088                 assert(0);
01089             }
01090         }
01091         else  /* not ref pointer */
01092         {
01093             *flags |= MustFree;
01094         }
01095         break;
01096     case TGT_INVALID:
01097         assert(0);
01098     }
01099 
01100     if (!buffer_size) *flags |= MustSize;
01101 
01102     if (server_size)
01103     {
01104         server_size = (server_size + 7) / 8;
01105         if (server_size < 8) *flags |= server_size << 13;
01106     }
01107     return fc;
01108 }
01109 
01110 static unsigned char get_func_oi2_flags( const var_t *func )
01111 {
01112     const var_t *var;
01113     var_list_t *args = type_get_function_args( func->type );
01114     type_t *ret_type = type_function_get_rettype( func->type );
01115     unsigned char oi2_flags = 0x40;  /* HasExtensions */
01116     unsigned short flags;
01117     unsigned int stack_size, typestring_offset;
01118 
01119     if (args) LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
01120     {
01121         get_parameter_fc( var->type, var->attrs, 0, &flags, &stack_size, &typestring_offset );
01122         if (flags & MustSize)
01123         {
01124             if (flags & IsIn) oi2_flags |= 0x02; /* ClientMustSize */
01125             if (flags & IsOut) oi2_flags |= 0x01;  /* ServerMustSize */
01126         }
01127     }
01128 
01129     if (!is_void( ret_type ))
01130     {
01131         oi2_flags |= 0x04;  /* HasRet */
01132         get_parameter_fc( ret_type, NULL, 1, &flags, &stack_size, &typestring_offset );
01133         if (flags & MustSize) oi2_flags |= 0x01;  /* ServerMustSize */
01134     }
01135     return oi2_flags;
01136 }
01137 
01138 static unsigned int write_new_procformatstring_type(FILE *file, int indent,
01139                                                     const type_t *type,
01140                                                     const attr_list_t *attrs,
01141                                                     int is_return, unsigned int *stack_offset)
01142 {
01143     char buffer[64];
01144     unsigned int stack_size, typestring_offset;
01145     unsigned short flags;
01146     unsigned char fc = get_parameter_fc( type, attrs, is_return, &flags, &stack_size, &typestring_offset );
01147 
01148     strcpy( buffer, "/* flags:" );
01149     if (flags & MustSize) strcat( buffer, " must size," );
01150     if (flags & MustFree) strcat( buffer, " must free," );
01151     if (flags & IsPipe) strcat( buffer, " pipe," );
01152     if (flags & IsIn) strcat( buffer, " in," );
01153     if (flags & IsOut) strcat( buffer, " out," );
01154     if (flags & IsReturn) strcat( buffer, " return," );
01155     if (flags & IsBasetype) strcat( buffer, " base type," );
01156     if (flags & IsByValue) strcat( buffer, " by value," );
01157     if (flags & IsSimpleRef) strcat( buffer, " simple ref," );
01158     if (flags >> 13) sprintf( buffer + strlen(buffer), " srv size=%u,", (flags >> 13) * 8 );
01159     strcpy( buffer + strlen( buffer ) - 1, " */" );
01160     print_file( file, indent, "NdrFcShort(0x%hx),\t%s\n", flags, buffer );
01161     print_file( file, indent, "NdrFcShort(0x%hx),   /* stack offset = %hu */\n",
01162                 *stack_offset, *stack_offset );
01163     if (flags & IsBasetype)
01164     {
01165         print_file( file, indent, "0x%02x,  /* %s */\n", fc, string_of_type(fc) );
01166         print_file( file, indent, "0x0,\n" );
01167     }
01168     else
01169         print_file( file, indent, "NdrFcShort(0x%x),    /* type offset = %u */\n",
01170                     typestring_offset, typestring_offset );
01171     *stack_offset += max( stack_size, pointer_size );
01172     return 6;
01173 }
01174 
01175 static unsigned int write_old_procformatstring_type(FILE *file, int indent,
01176                                                     const type_t *type,
01177                                                     const attr_list_t *attrs,
01178                                                     int is_return, int is_interpreted)
01179 {
01180     unsigned int size;
01181 
01182     int is_in = is_attr(attrs, ATTR_IN);
01183     int is_out = is_attr(attrs, ATTR_OUT);
01184 
01185     if (!is_in && !is_out) is_in = TRUE;
01186 
01187     if (type_get_type(type) == TYPE_BASIC ||
01188         type_get_type(type) == TYPE_ENUM)
01189     {
01190         unsigned char fc;
01191 
01192         if (is_return)
01193             print_file(file, indent, "0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
01194         else
01195             print_file(file, indent, "0x4e,    /* FC_IN_PARAM_BASETYPE */\n");
01196 
01197         if (type_get_type(type) == TYPE_ENUM)
01198         {
01199             fc = get_enum_fc(type);
01200         }
01201         else
01202         {
01203             fc = get_basic_fc_signed(type);
01204 
01205             if (fc == RPC_FC_BIND_PRIMITIVE)
01206                 fc = RPC_FC_IGNORE;
01207         }
01208 
01209         print_file(file, indent, "0x%02x,    /* %s */\n",
01210                    fc, string_of_type(fc));
01211         size = 2; /* includes param type prefix */
01212     }
01213     else
01214     {
01215         unsigned short offset = type->typestring_offset;
01216 
01217         if (is_interpreted && is_array(type) &&
01218             type_array_is_decl_as_ptr(type) &&
01219             type->details.array.ptr_tfsoff)
01220             offset = type->details.array.ptr_tfsoff;
01221 
01222         if (is_return)
01223             print_file(file, indent, "0x52,    /* FC_RETURN_PARAM */\n");
01224         else if (is_in && is_out)
01225             print_file(file, indent, "0x50,    /* FC_IN_OUT_PARAM */\n");
01226         else if (is_out)
01227             print_file(file, indent, "0x51,    /* FC_OUT_PARAM */\n");
01228         else
01229             print_file(file, indent, "0x4d,    /* FC_IN_PARAM */\n");
01230 
01231         size = get_stack_size( type, attrs, NULL );
01232         print_file(file, indent, "0x%02x,\n", size / pointer_size );
01233         print_file(file, indent, "NdrFcShort(0x%x), /* type offset = %u */\n", offset, offset);
01234         size = 4; /* includes param type prefix */
01235     }
01236     return size;
01237 }
01238 
01239 int is_interpreted_func( const type_t *iface, const var_t *func )
01240 {
01241     const char *str;
01242     const var_t *var;
01243     const var_list_t *args = type_get_function_args( func->type );
01244     const type_t *ret_type = type_function_get_rettype( func->type );
01245 
01246     if (type_get_type( ret_type ) == TYPE_BASIC)
01247     {
01248         switch (type_basic_get_type( ret_type ))
01249         {
01250         case TYPE_BASIC_INT64:
01251         case TYPE_BASIC_HYPER:
01252             /* return value must fit in a long_ptr */
01253             if (pointer_size < 8) return 0;
01254             break;
01255         case TYPE_BASIC_FLOAT:
01256         case TYPE_BASIC_DOUBLE:
01257             /* floating point values can't be returned */
01258             return 0;
01259         default:
01260             break;
01261         }
01262     }
01263     if (get_stub_mode() != MODE_Oif && args)
01264     {
01265         LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
01266             switch (type_get_type( var->type ))
01267             {
01268             case TYPE_BASIC:
01269                 switch (type_basic_get_type( var->type ))
01270                 {
01271                 /* floating point arguments are not supported in Oi mode */
01272                 case TYPE_BASIC_FLOAT:  return 0;
01273                 case TYPE_BASIC_DOUBLE: return 0;
01274                 default: break;
01275                 }
01276                 break;
01277             /* unions passed by value are not supported in Oi mode */
01278             case TYPE_UNION: return 0;
01279             case TYPE_ENCAPSULATED_UNION: return 0;
01280             default: break;
01281             }
01282     }
01283 
01284     if ((str = get_attrp( func->attrs, ATTR_OPTIMIZE ))) return !strcmp( str, "i" );
01285     if ((str = get_attrp( iface->attrs, ATTR_OPTIMIZE ))) return !strcmp( str, "i" );
01286     return (get_stub_mode() != MODE_Os);
01287 }
01288 
01289 static void write_proc_func_header( FILE *file, int indent, const type_t *iface,
01290                                     const var_t *func, unsigned int *offset,
01291                                     unsigned short num_proc )
01292 {
01293     var_t *var;
01294     var_list_t *args = type_get_function_args( func->type );
01295     unsigned char explicit_fc, implicit_fc;
01296     unsigned char handle_flags;
01297     const var_t *handle_var = get_func_handle_var( iface, func, &explicit_fc, &implicit_fc );
01298     unsigned char oi_flags = RPC_FC_PROC_OIF_RPCFLAGS | RPC_FC_PROC_OIF_NEWINIT;
01299     unsigned int rpc_flags = get_rpc_flags( func->attrs );
01300     unsigned int nb_args = 0;
01301     unsigned int stack_size = 0;
01302     unsigned short param_num = 0;
01303     unsigned short handle_stack_offset = 0;
01304     unsigned short handle_param_num = 0;
01305 
01306     if (is_full_pointer_function( func )) oi_flags |= RPC_FC_PROC_OIF_FULLPTR;
01307     if (is_object( iface ))
01308     {
01309         oi_flags |= RPC_FC_PROC_OIF_OBJECT;
01310         if (get_stub_mode() == MODE_Oif) oi_flags |= RPC_FC_PROC_OIF_OBJ_V2;
01311         stack_size += pointer_size;
01312     }
01313 
01314     if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )
01315     {
01316         if (var == handle_var)
01317         {
01318             handle_stack_offset = stack_size;
01319             handle_param_num = param_num;
01320         }
01321         stack_size += get_stack_size( var->type, var->attrs, NULL );
01322         param_num++;
01323         nb_args++;
01324     }
01325     if (!is_void( type_function_get_rettype( func->type )))
01326     {
01327         stack_size += pointer_size;
01328         nb_args++;
01329     }
01330 
01331     print_file( file, 0, "/* %u (procedure %s::%s) */\n", *offset, iface->name, func->name );
01332     print_file( file, indent, "0x%02x,\t/* %s */\n", implicit_fc,
01333                 implicit_fc ? string_of_type(implicit_fc) : "explicit handle" );
01334     print_file( file, indent, "0x%02x,\n", oi_flags );
01335     print_file( file, indent, "NdrFcLong(0x%x),\n", rpc_flags );
01336     print_file( file, indent, "NdrFcShort(0x%hx),\t/* method %hu */\n", num_proc, num_proc );
01337     print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack size = %hu */\n", stack_size, stack_size );
01338     *offset += 10;
01339 
01340     if (!implicit_fc)
01341     {
01342         switch (explicit_fc)
01343         {
01344         case RPC_FC_BIND_PRIMITIVE:
01345             handle_flags = 0;
01346             print_file( file, indent, "0x%02x,\t/* %s */\n", explicit_fc, string_of_type(explicit_fc) );
01347             print_file( file, indent, "0x%02x,\n", handle_flags );
01348             print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack offset = %hu */\n",
01349                         handle_stack_offset, handle_stack_offset );
01350             *offset += 4;
01351             break;
01352         case RPC_FC_BIND_GENERIC:
01353             handle_flags = type_memsize( handle_var->type );
01354             print_file( file, indent, "0x%02x,\t/* %s */\n", explicit_fc, string_of_type(explicit_fc) );
01355             print_file( file, indent, "0x%02x,\n", handle_flags );
01356             print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack offset = %hu */\n",
01357                         handle_stack_offset, handle_stack_offset );
01358             print_file( file, indent, "0x%02x,\n", get_generic_handle_offset( handle_var->type ) );
01359             print_file( file, indent, "0x%x,\t/* FC_PAD */\n", RPC_FC_PAD);
01360             *offset += 6;
01361             break;
01362         case RPC_FC_BIND_CONTEXT:
01363             handle_flags = get_contexthandle_flags( iface, handle_var->attrs, handle_var->type );
01364             print_file( file, indent, "0x%02x,\t/* %s */\n", explicit_fc, string_of_type(explicit_fc) );
01365             print_file( file, indent, "0x%02x,\n", handle_flags );
01366             print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack offset = %hu */\n",
01367                         handle_stack_offset, handle_stack_offset );
01368             print_file( file, indent, "0x%02x,\n", get_context_handle_offset( handle_var->type ) );
01369             print_file( file, indent, "0x%02x,\t/* param %hu */\n", handle_param_num, handle_param_num );
01370             *offset += 6;
01371             break;
01372         }
01373     }
01374 
01375     if (get_stub_mode() == MODE_Oif)
01376     {
01377         unsigned char oi2_flags = get_func_oi2_flags( func );
01378         unsigned char ext_flags = 0;
01379         unsigned int size;
01380 
01381         if (is_attr( func->attrs, ATTR_NOTIFY )) ext_flags |= 0x08;  /* HasNotify */
01382         if (is_attr( func->attrs, ATTR_NOTIFYFLAG )) ext_flags |= 0x10;  /* HasNotify2 */
01383 
01384         size = get_function_buffer_size( func, PASS_IN );
01385         print_file( file, indent, "NdrFcShort(0x%x),\t/* client buffer = %hu */\n", size, size );
01386         size = get_function_buffer_size( func, PASS_OUT );
01387         print_file( file, indent, "NdrFcShort(0x%x),\t/* server buffer = %hu */\n", size, size );
01388         print_file( file, indent, "0x%02x,\n", oi2_flags );
01389         print_file( file, indent, "0x%02x,\t/* %u params */\n", nb_args, nb_args );
01390         print_file( file, indent, "0x%02x,\n", pointer_size == 8 ? 10 : 8 );
01391         print_file( file, indent, "0x%02x,\n", ext_flags );
01392         print_file( file, indent, "NdrFcShort(0x0),\n" );  /* server corr hint */
01393         print_file( file, indent, "NdrFcShort(0x0),\n" );  /* client corr hint */
01394         print_file( file, indent, "NdrFcShort(0x0),\n" );  /* FIXME: notify index */
01395         *offset += 14;
01396         if (pointer_size == 8)
01397         {
01398             unsigned short pos = 0, fpu_mask = 0;
01399 
01400             if (is_object( iface )) pos += 2;
01401             if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )
01402             {
01403                 if (type_get_type( var->type ) == TYPE_BASIC)
01404                 {
01405                     switch (type_basic_get_type( var->type ))
01406                     {
01407                     case TYPE_BASIC_FLOAT:  fpu_mask |= 1 << pos; break;
01408                     case TYPE_BASIC_DOUBLE: fpu_mask |= 2 << pos; break;
01409                     default: break;
01410                     }
01411                 }
01412                 pos += 2;
01413                 if (pos >= 16) break;
01414             }
01415             print_file( file, indent, "NdrFcShort(0x%x),\n", fpu_mask );  /* floating point mask */
01416             *offset += 2;
01417         }
01418     }
01419 }
01420 
01421 static void write_procformatstring_func( FILE *file, int indent, const type_t *iface,
01422                                          const var_t *func, unsigned int *offset,
01423                                          unsigned short num_proc )
01424 {
01425     unsigned int stack_offset = is_object( iface ) ? pointer_size : 0;
01426     int is_interpreted = is_interpreted_func( iface, func );
01427     int is_new_style = is_interpreted && (get_stub_mode() == MODE_Oif);
01428 
01429     if (is_interpreted) write_proc_func_header( file, indent, iface, func, offset, num_proc );
01430 
01431     /* emit argument data */
01432     if (type_get_function_args(func->type))
01433     {
01434         const var_t *var;
01435         LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
01436         {
01437             print_file( file, 0, "/* %u (parameter %s) */\n", *offset, var->name );
01438             if (is_new_style)
01439                 *offset += write_new_procformatstring_type(file, indent, var->type, var->attrs,
01440                                                            FALSE, &stack_offset);
01441             else
01442                 *offset += write_old_procformatstring_type(file, indent, var->type, var->attrs,
01443                                                            FALSE, is_interpreted);
01444         }
01445     }
01446 
01447     /* emit return value data */
01448     if (is_void(type_function_get_rettype(func->type)))
01449     {
01450         if (!is_new_style)
01451         {
01452             print_file(file, 0, "/* %u (void) */\n", *offset);
01453             print_file(file, indent, "0x5b,    /* FC_END */\n");
01454             print_file(file, indent, "0x5c,    /* FC_PAD */\n");
01455             *offset += 2;
01456         }
01457     }
01458     else
01459     {
01460         print_file( file, 0, "/* %u (return value) */\n", *offset );
01461         if (is_new_style)
01462             *offset += write_new_procformatstring_type(file, indent, type_function_get_rettype(func->type),
01463                                                        NULL, TRUE, &stack_offset);
01464         else
01465             *offset += write_old_procformatstring_type(file, indent, type_function_get_rettype(func->type),
01466                                                        NULL, TRUE, is_interpreted);
01467     }
01468 }
01469 
01470 static void write_procformatstring_stmts(FILE *file, int indent, const statement_list_t *stmts,
01471                                          type_pred_t pred, unsigned int *offset)
01472 {
01473     const statement_t *stmt;
01474     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
01475     {
01476         if (stmt->type == STMT_TYPE && type_get_type(stmt->u.type) == TYPE_INTERFACE)
01477         {
01478             const statement_t *stmt_func;
01479             const type_t *iface = stmt->u.type;
01480             const type_t *parent = type_iface_get_inherit( iface );
01481             int count = parent ? count_methods( parent ) : 0;
01482 
01483             if (!pred(iface)) continue;
01484             STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(iface))
01485             {
01486                 var_t *func = stmt_func->u.var;
01487                 if (is_local(func->attrs)) continue;
01488                 write_procformatstring_func( file, indent, iface, func, offset, count++ );
01489             }
01490         }
01491         else if (stmt->type == STMT_LIBRARY)
01492             write_procformatstring_stmts(file, indent, stmt->u.lib->stmts, pred, offset);
01493     }
01494 }
01495 
01496 void write_procformatstring(FILE *file, const statement_list_t *stmts, type_pred_t pred)
01497 {
01498     int indent = 0;
01499     unsigned int offset = 0;
01500 
01501     print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
01502     print_file(file, indent, "{\n");
01503     indent++;
01504     print_file(file, indent, "0,\n");
01505     print_file(file, indent, "{\n");
01506     indent++;
01507 
01508     write_procformatstring_stmts(file, indent, stmts, pred, &offset);
01509 
01510     print_file(file, indent, "0x0\n");
01511     indent--;
01512     print_file(file, indent, "}\n");
01513     indent--;
01514     print_file(file, indent, "};\n");
01515     print_file(file, indent, "\n");
01516 }
01517 
01518 void write_procformatstring_offsets( FILE *file, const type_t *iface )
01519 {
01520     const statement_t *stmt;
01521     int indent = 0;
01522 
01523     print_file( file, indent,  "static const unsigned short %s_FormatStringOffsetTable[] =\n",
01524                 iface->name );
01525     print_file( file, indent,  "{\n" );
01526     indent++;
01527     STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
01528     {
01529         var_t *func = stmt->u.var;
01530         if (is_local( func->attrs )) continue;
01531         print_file( file, indent,  "%u,  /* %s */\n", func->procstring_offset, func->name );
01532     }
01533     indent--;
01534     print_file( file, indent,  "};\n\n" );
01535 }
01536 
01537 static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
01538 {
01539     unsigned char fc;
01540 
01541     if (type_get_type(type) == TYPE_BASIC)
01542         fc = get_basic_fc_signed(type);
01543     else if (type_get_type(type) == TYPE_ENUM)
01544         fc = get_enum_fc(type);
01545     else
01546         return 0;
01547 
01548     print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
01549     *typestring_offset += 1;
01550     return 1;
01551 }
01552 
01553 /* write conformance / variance descriptor */
01554 static unsigned int write_conf_or_var_desc(FILE *file, const type_t *cont_type,
01555                                            unsigned int baseoff, const type_t *type,
01556                                            const expr_t *expr)
01557 {
01558     unsigned char operator_type = 0;
01559     unsigned char conftype = RPC_FC_NORMAL_CONFORMANCE;
01560     const char *conftype_string = "field";
01561     const expr_t *subexpr;
01562     const type_t *iface = NULL;
01563     const char *name;
01564 
01565     if (!expr)
01566     {
01567         print_file(file, 2, "NdrFcLong(0xffffffff),\t/* -1 */\n");
01568         return 4;
01569     }
01570 
01571     if (expr->is_const)
01572     {
01573         if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
01574             error("write_conf_or_var_desc: constant value %d is greater than "
01575                   "the maximum constant size of %d\n", expr->cval,
01576                   UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
01577 
01578         print_file(file, 2, "0x%x, /* Corr desc: constant, val = %d */\n",
01579                    RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
01580         print_file(file, 2, "0x%x,\n", expr->cval >> 16);
01581         print_file(file, 2, "NdrFcShort(0x%hx),\n", (unsigned short)expr->cval);
01582 
01583         return 4;
01584     }
01585 
01586     if (!cont_type)  /* top-level conformance */
01587     {
01588         conftype = RPC_FC_TOP_LEVEL_CONFORMANCE;
01589         conftype_string = "parameter";
01590         cont_type = current_func->type;
01591         name = current_func->name;
01592         iface = current_iface;
01593     }
01594     else
01595     {
01596         name = cont_type->name;
01597         if (is_ptr(type) || (is_array(type) && type_array_is_decl_as_ptr(type)))
01598         {
01599             conftype = RPC_FC_POINTER_CONFORMANCE;
01600             conftype_string = "field pointer";
01601         }
01602     }
01603 
01604     subexpr = expr;
01605     switch (subexpr->type)
01606     {
01607     case EXPR_PPTR:
01608         subexpr = subexpr->ref;
01609         operator_type = RPC_FC_DEREFERENCE;
01610         break;
01611     case EXPR_DIV:
01612         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
01613         {
01614             subexpr = subexpr->ref;
01615             operator_type = RPC_FC_DIV_2;
01616         }
01617         break;
01618     case EXPR_MUL:
01619         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
01620         {
01621             subexpr = subexpr->ref;
01622             operator_type = RPC_FC_MULT_2;
01623         }
01624         break;
01625     case EXPR_SUB:
01626         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
01627         {
01628             subexpr = subexpr->ref;
01629             operator_type = RPC_FC_SUB_1;
01630         }
01631         break;
01632     case EXPR_ADD:
01633         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
01634         {
01635             subexpr = subexpr->ref;
01636             operator_type = RPC_FC_ADD_1;
01637         }
01638         break;
01639     default:
01640         break;
01641     }
01642 
01643     if (subexpr->type == EXPR_IDENTIFIER)
01644     {
01645         const type_t *correlation_variable = NULL;
01646         unsigned char param_type = 0;
01647         unsigned int offset = 0;
01648         const var_t *var;
01649         struct expr_loc expr_loc;
01650 
01651         if (type_get_type(cont_type) == TYPE_FUNCTION)
01652         {
01653             var_list_t *args = type_get_function_args( cont_type );
01654 
01655             if (is_object( iface )) offset += pointer_size;
01656             if (args) LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
01657             {
01658                 if (var->name && !strcmp(var->name, subexpr->u.sval))
01659                 {
01660                     expr_loc.v = var;
01661                     correlation_variable = var->type;
01662                     break;
01663                 }
01664                 offset += get_stack_size( var->type, var->attrs, NULL );
01665             }
01666         }
01667         else
01668         {
01669             var_list_t *fields = type_struct_get_fields( cont_type );
01670 
01671             if (fields) LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
01672             {
01673                 unsigned int size = field_memsize( var->type, &offset );
01674                 if (var->name && !strcmp(var->name, subexpr->u.sval))
01675                 {
01676                     expr_loc.v = var;
01677                     correlation_variable = var->type;
01678                     break;
01679                 }
01680                 offset += size;
01681             }
01682         }
01683 
01684         if (!correlation_variable)
01685             error("write_conf_or_var_desc: couldn't find variable %s in %s\n", subexpr->u.sval, name);
01686         expr_loc.attr = NULL;
01687         correlation_variable = expr_resolve_type(&expr_loc, cont_type, expr);
01688 
01689         offset -= baseoff;
01690 
01691         if (type_get_type(correlation_variable) == TYPE_BASIC)
01692         {
01693             switch (get_basic_fc(correlation_variable))
01694             {
01695             case RPC_FC_CHAR:
01696             case RPC_FC_SMALL:
01697                 param_type = RPC_FC_SMALL;
01698                 break;
01699             case RPC_FC_BYTE:
01700             case RPC_FC_USMALL:
01701                 param_type = RPC_FC_USMALL;
01702                 break;
01703             case RPC_FC_WCHAR:
01704             case RPC_FC_SHORT:
01705                 param_type = RPC_FC_SHORT;
01706                 break;
01707             case RPC_FC_USHORT:
01708                 param_type = RPC_FC_USHORT;
01709                 break;
01710             case RPC_FC_LONG:
01711                 param_type = RPC_FC_LONG;
01712                 break;
01713             case RPC_FC_ULONG:
01714                 param_type = RPC_FC_ULONG;
01715                 break;
01716             default:
01717                 error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
01718                       get_basic_fc(correlation_variable));
01719             }
01720         }
01721         else if (type_get_type(correlation_variable) == TYPE_ENUM)
01722         {
01723             if (get_enum_fc(correlation_variable) == RPC_FC_ENUM32)
01724                 param_type = RPC_FC_LONG;
01725             else
01726                 param_type = RPC_FC_SHORT;
01727         }
01728         else if (type_get_type(correlation_variable) == TYPE_POINTER)
01729         {
01730             if (pointer_size == 8)
01731                 param_type = RPC_FC_HYPER;
01732             else
01733                 param_type = RPC_FC_LONG;
01734         }
01735         else
01736         {
01737             error("write_conf_or_var_desc: non-arithmetic type used as correlation variable %s\n",
01738                   subexpr->u.sval);
01739             return 0;
01740         }
01741 
01742         print_file(file, 2, "0x%x,\t/* Corr desc: %s %s, %s */\n",
01743                    conftype | param_type, conftype_string, subexpr->u.sval, string_of_type(param_type));
01744         print_file(file, 2, "0x%x,\t/* %s */\n", operator_type,
01745                    operator_type ? string_of_type(operator_type) : "no operators");
01746         print_file(file, 2, "NdrFcShort(0x%hx),\t/* offset = %d */\n",
01747                    (unsigned short)offset, offset);
01748     }
01749     else if (!iface || is_interpreted_func( iface, current_func ))
01750     {
01751         unsigned int callback_offset = 0;
01752         struct expr_eval_routine *eval;
01753         int found = 0;
01754 
01755         LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
01756         {
01757             if (eval->cont_type == cont_type ||
01758                 (type_get_type( eval->cont_type ) == type_get_type( cont_type ) &&
01759                  eval->iface == iface &&
01760                  eval->name && name && !strcmp(eval->name, name) &&
01761                  !compare_expr(eval->expr, expr)))
01762             {
01763                 found = 1;
01764                 break;
01765             }
01766             callback_offset++;
01767         }
01768 
01769         if (!found)
01770         {
01771             eval = xmalloc (sizeof(*eval));
01772             eval->iface = iface;
01773             eval->cont_type = cont_type;
01774             eval->name = xstrdup( name );
01775             eval->baseoff = baseoff;
01776             eval->expr = expr;
01777             list_add_tail (&expr_eval_routines, &eval->entry);
01778         }
01779 
01780         if (callback_offset > USHRT_MAX)
01781             error("Maximum number of callback routines reached\n");
01782 
01783         print_file(file, 2, "0x%x,\t/* Corr desc: %s in %s */\n", conftype, conftype_string, name);
01784         print_file(file, 2, "0x%x,\t/* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
01785         print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)callback_offset, callback_offset);
01786     }
01787     else  /* output a dummy corr desc that isn't used */
01788     {
01789         print_file(file, 2, "0x%x,\t/* Corr desc: unused for %s */\n", conftype, name);
01790         print_file(file, 2, "0x0,\n" );
01791         print_file(file, 2, "NdrFcShort(0x0),\n" );
01792     }
01793     return 4;
01794 }
01795 
01796 /* return size and start offset of a data field based on current offset */
01797 static unsigned int field_memsize(const type_t *type, unsigned int *offset)
01798 {
01799     unsigned int align = 0;
01800     unsigned int size = type_memsize_and_alignment( type, &align );
01801 
01802     *offset = ROUND_SIZE( *offset, align );
01803     return size;
01804 }
01805 
01806 static unsigned int fields_memsize(const var_list_t *fields, unsigned int *align)
01807 {
01808     unsigned int size = 0;
01809     unsigned int max_align;
01810     const var_t *v;
01811 
01812     if (!fields) return 0;
01813     LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
01814     {
01815         unsigned int falign = 0;
01816         unsigned int fsize = type_memsize_and_alignment(v->type, &falign);
01817         if (*align < falign) *align = falign;
01818         falign = clamp_align(falign);
01819         size = ROUND_SIZE(size, falign);
01820         size += fsize;
01821     }
01822 
01823     max_align = clamp_align(*align);
01824     size = ROUND_SIZE(size, max_align);
01825 
01826     return size;
01827 }
01828 
01829 static unsigned int union_memsize(const var_list_t *fields, unsigned int *pmaxa)
01830 {
01831     unsigned int size, maxs = 0;
01832     unsigned int align = *pmaxa;
01833     const var_t *v;
01834 
01835     if (fields) LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
01836     {
01837         /* we could have an empty default field with NULL type */
01838         if (v->type)
01839         {
01840             size = type_memsize_and_alignment(v->type, &align);
01841             if (maxs < size) maxs = size;
01842             if (*pmaxa < align) *pmaxa = align;
01843         }
01844     }
01845 
01846     return maxs;
01847 }
01848 
01849 static unsigned int type_memsize_and_alignment(const type_t *t, unsigned int *align)
01850 {
01851     unsigned int size = 0;
01852 
01853     switch (type_get_type(t))
01854     {
01855     case TYPE_BASIC:
01856         switch (get_basic_fc(t))
01857         {
01858         case RPC_FC_BYTE:
01859         case RPC_FC_CHAR:
01860         case RPC_FC_USMALL:
01861         case RPC_FC_SMALL:
01862             size = 1;
01863             if (size > *align) *align = size;
01864             break;
01865         case RPC_FC_WCHAR:
01866         case RPC_FC_USHORT:
01867         case RPC_FC_SHORT:
01868             size = 2;
01869             if (size > *align) *align = size;
01870             break;
01871         case RPC_FC_ULONG:
01872         case RPC_FC_LONG:
01873         case RPC_FC_ERROR_STATUS_T:
01874         case RPC_FC_FLOAT:
01875             size = 4;
01876             if (size > *align) *align = size;
01877             break;
01878         case RPC_FC_HYPER:
01879         case RPC_FC_DOUBLE:
01880             size = 8;
01881             if (size > *align) *align = size;
01882             break;
01883         case RPC_FC_INT3264:
01884         case RPC_FC_UINT3264:
01885         case RPC_FC_BIND_PRIMITIVE:
01886             assert( pointer_size );
01887             size = pointer_size;
01888             if (size > *align) *align = size;
01889             break;
01890         default:
01891             error("type_memsize: Unknown type 0x%x\n", get_basic_fc(t));
01892             size = 0;
01893         }
01894         break;
01895     case TYPE_ENUM:
01896         switch (get_enum_fc(t))
01897         {
01898         case RPC_FC_ENUM16:
01899         case RPC_FC_ENUM32:
01900             size = 4;
01901             if (size > *align) *align = size;
01902             break;
01903         default:
01904             error("type_memsize: Unknown enum type\n");
01905             size = 0;
01906         }
01907         break;
01908     case TYPE_STRUCT:
01909         size = fields_memsize(type_struct_get_fields(t), align);
01910         break;
01911     case TYPE_ENCAPSULATED_UNION:
01912         size = fields_memsize(type_encapsulated_union_get_fields(t), align);
01913         break;
01914     case TYPE_UNION:
01915         size = union_memsize(type_union_get_cases(t), align);
01916         break;
01917     case TYPE_POINTER:
01918         assert( pointer_size );
01919         size = pointer_size;
01920         if (size > *align) *align = size;
01921         break;
01922     case TYPE_ARRAY:
01923         if (!type_array_is_decl_as_ptr(t))
01924         {
01925             if (is_conformant_array(t))
01926             {
01927                 type_memsize_and_alignment(type_array_get_element(t), align);
01928                 size = 0;
01929             }
01930             else
01931                 size = type_array_get_dim(t) *
01932                     type_memsize_and_alignment(type_array_get_element(t), align);
01933         }
01934         else /* declared as a pointer */
01935         {
01936             assert( pointer_size );
01937             size = pointer_size;
01938             if (size > *align) *align = size;
01939         }
01940         break;
01941     case TYPE_INTERFACE:
01942     case TYPE_ALIAS:
01943     case TYPE_VOID:
01944     case TYPE_COCLASS:
01945     case TYPE_MODULE:
01946     case TYPE_FUNCTION:
01947     case TYPE_BITFIELD:
01948         /* these types should not be encountered here due to language
01949          * restrictions (interface, void, coclass, module), logical
01950          * restrictions (alias - due to type_get_type call above) or
01951          * checking restrictions (function, bitfield). */
01952         assert(0);
01953     }
01954 
01955     return size;
01956 }
01957 
01958 unsigned int type_memsize(const type_t *t)
01959 {
01960     unsigned int align = 0;
01961     return type_memsize_and_alignment( t, &align );
01962 }
01963 
01964 static unsigned int type_buffer_alignment(const type_t *t)
01965 {
01966     const var_list_t *fields;
01967     const var_t *var;
01968     unsigned int max = 0, align;
01969 
01970     switch (type_get_type(t))
01971     {
01972     case TYPE_BASIC:
01973         switch (get_basic_fc(t))
01974         {
01975         case RPC_FC_BYTE:
01976         case RPC_FC_CHAR:
01977         case RPC_FC_USMALL:
01978         case RPC_FC_SMALL:
01979             return 1;
01980         case RPC_FC_WCHAR:
01981         case RPC_FC_USHORT:
01982         case RPC_FC_SHORT:
01983             return 2;
01984         case RPC_FC_ULONG:
01985         case RPC_FC_LONG:
01986         case RPC_FC_ERROR_STATUS_T:
01987         case RPC_FC_FLOAT:
01988         case RPC_FC_INT3264:
01989         case RPC_FC_UINT3264:
01990             return 4;
01991         case RPC_FC_HYPER:
01992         case RPC_FC_DOUBLE:
01993             return 8;
01994         default:
01995             error("type_buffer_alignment: Unknown type 0x%x\n", get_basic_fc(t));
01996         }
01997         break;
01998     case TYPE_ENUM:
01999         switch (get_enum_fc(t))
02000         {
02001         case RPC_FC_ENUM16:
02002             return 2;
02003         case RPC_FC_ENUM32:
02004             return 4;
02005         default:
02006             error("type_buffer_alignment: Unknown enum type\n");
02007         }
02008         break;
02009     case TYPE_STRUCT:
02010         if (!(fields = type_struct_get_fields(t))) break;
02011         LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
02012         {
02013             if (!var->type) continue;
02014             align = type_buffer_alignment( var->type );
02015             if (max < align) max = align;
02016         }
02017         break;
02018     case TYPE_ENCAPSULATED_UNION:
02019         if (!(fields = type_encapsulated_union_get_fields(t))) break;
02020         LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
02021         {
02022             if (!var->type) continue;
02023             align = type_buffer_alignment( var->type );
02024             if (max < align) max = align;
02025         }
02026         break;
02027     case TYPE_UNION:
02028         if (!(fields = type_union_get_cases(t))) break;
02029         LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
02030         {
02031             if (!var->type) continue;
02032             align = type_buffer_alignment( var->type );
02033             if (max < align) max = align;
02034         }
02035         break;
02036     case TYPE_ARRAY:
02037         if (!type_array_is_decl_as_ptr(t))
02038             return type_buffer_alignment( type_array_get_element(t) );
02039         /* else fall through */
02040     case TYPE_POINTER:
02041         return 4;
02042     case TYPE_INTERFACE:
02043     case TYPE_ALIAS:
02044     case TYPE_VOID:
02045     case TYPE_COCLASS:
02046     case TYPE_MODULE:
02047     case TYPE_FUNCTION:
02048     case TYPE_BITFIELD:
02049         /* these types should not be encountered here due to language
02050          * restrictions (interface, void, coclass, module), logical
02051          * restrictions (alias - due to type_get_type call above) or
02052          * checking restrictions (function, bitfield). */
02053         assert(0);
02054     }
02055     return max;
02056 }
02057 
02058 int is_full_pointer_function(const var_t *func)
02059 {
02060     const var_t *var;
02061     if (type_has_full_pointer(type_function_get_rettype(func->type), func->attrs, TRUE))
02062         return TRUE;
02063     if (!type_get_function_args(func->type))
02064         return FALSE;
02065     LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
02066         if (type_has_full_pointer( var->type, var->attrs, TRUE ))
02067             return TRUE;
02068     return FALSE;
02069 }
02070 
02071 void write_full_pointer_init(FILE *file, int indent, const var_t *func, int is_server)
02072 {
02073     print_file(file, indent, "__frame->_StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,%s);\n",
02074                    is_server ? "XLAT_SERVER" : "XLAT_CLIENT");
02075     fprintf(file, "\n");
02076 }
02077 
02078 void write_full_pointer_free(FILE *file, int indent, const var_t *func)
02079 {
02080     print_file(file, indent, "NdrFullPointerXlatFree(__frame->_StubMsg.FullPtrXlatTables);\n");
02081     fprintf(file, "\n");
02082 }
02083 
02084 static unsigned int write_nonsimple_pointer(FILE *file, const attr_list_t *attrs,
02085                                             const type_t *type,
02086                                             enum type_context context,
02087                                             unsigned int offset,
02088                                             unsigned int *typeformat_offset)
02089 {
02090     unsigned int start_offset = *typeformat_offset;
02091     short reloff = offset - (*typeformat_offset + 2);
02092     int in_attr, out_attr;
02093     int pointer_type;
02094     unsigned char flags = 0;
02095 
02096     pointer_type = get_pointer_fc_context(type, attrs, context);
02097 
02098     in_attr = is_attr(attrs, ATTR_IN);
02099     out_attr = is_attr(attrs, ATTR_OUT);
02100     if (!in_attr && !out_attr) in_attr = 1;
02101 
02102     if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
02103         flags |= RPC_FC_P_ONSTACK;
02104 
02105     if (is_ptr(type))
02106     {
02107         type_t *ref = type_pointer_get_ref(type);
02108         if(is_declptr(ref) && !is_user_type(ref))
02109             flags |= RPC_FC_P_DEREF;
02110     }
02111 
02112     print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
02113                pointer_type,
02114                flags,
02115                string_of_type(pointer_type));
02116     if (file)
02117     {
02118         if (flags & RPC_FC_P_ONSTACK)
02119             fprintf(file, " [allocated_on_stack]");
02120         if (flags & RPC_FC_P_DEREF)
02121             fprintf(file, " [pointer_deref]");
02122         fprintf(file, " */\n");
02123     }
02124 
02125     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n", reloff, reloff, offset);
02126     *typeformat_offset += 4;
02127 
02128     return start_offset;
02129 }
02130 
02131 static unsigned int write_simple_pointer(FILE *file, const attr_list_t *attrs,
02132                                          const type_t *type, enum type_context context)
02133 {
02134     unsigned char fc;
02135     unsigned char pointer_fc;
02136     const type_t *ref;
02137     int in_attr = is_attr(attrs, ATTR_IN);
02138     int out_attr = is_attr(attrs, ATTR_OUT);
02139     unsigned char flags = RPC_FC_P_SIMPLEPOINTER;
02140 
02141     /* for historical reasons, write_simple_pointer also handled string types,
02142      * but no longer does. catch bad uses of the function with this check */
02143     if (is_string_type(attrs, type))
02144         error("write_simple_pointer: can't handle type %s which is a string type\n", type->name);
02145 
02146     pointer_fc = get_pointer_fc_context(type, attrs, context);
02147 
02148     ref = type_pointer_get_ref(type);
02149     if (type_get_type(ref) == TYPE_ENUM)
02150         fc = get_enum_fc(ref);
02151     else
02152         fc = get_basic_fc(ref);
02153 
02154     if (out_attr && !in_attr)
02155         flags |= RPC_FC_P_ONSTACK;
02156 
02157     print_file(file, 2, "0x%02x, 0x%x,\t/* %s %s[simple_pointer] */\n",
02158                pointer_fc, flags, string_of_type(pointer_fc),
02159                flags & RPC_FC_P_ONSTACK ? "[allocated_on_stack] " : "");
02160     print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
02161     print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
02162     return 4;
02163 }
02164 
02165 static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff)
02166 {
02167     print_file(file, 0, "/* %u (", tfsoff);
02168     write_type_decl(file, t, NULL);
02169     print_file(file, 0, ") */\n");
02170 }
02171 
02172 static unsigned int write_pointer_tfs(FILE *file, const attr_list_t *attrs,
02173                                       type_t *type, unsigned int ref_offset,
02174                                       enum type_context context,
02175                                       unsigned int *typestring_offset)
02176 {
02177     unsigned int offset = *typestring_offset;
02178     type_t *ref = type_pointer_get_ref(type);
02179 
02180     print_start_tfs_comment(file, type, offset);
02181     update_tfsoff(type, offset, file);
02182 
02183     switch (typegen_detect_type(ref, attrs, TDT_ALL_TYPES))
02184     {
02185     case TGT_BASIC:
02186     case TGT_ENUM:
02187         *typestring_offset += write_simple_pointer(file, attrs, type, context);
02188         break;
02189     default:
02190         if (ref_offset)
02191             write_nonsimple_pointer(file, attrs, type, context, ref_offset, typestring_offset);
02192         break;
02193     }
02194 
02195     return offset;
02196 }
02197 
02198 static int processed(const type_t *type)
02199 {
02200     return type->typestring_offset && !type->tfswrite;
02201 }
02202 
02203 static int user_type_has_variable_size(const type_t *t)
02204 {
02205     if (is_ptr(t))
02206         return TRUE;
02207     else if (type_get_type(t) == TYPE_STRUCT)
02208     {
02209         switch (get_struct_fc(t))
02210         {
02211         case RPC_FC_PSTRUCT:
02212         case RPC_FC_CSTRUCT:
02213         case RPC_FC_CPSTRUCT:
02214         case RPC_FC_CVSTRUCT:
02215             return TRUE;
02216         }
02217     }
02218     /* Note: Since this only applies to user types, we can't have a conformant
02219        array here, and strings should get filed under pointer in this case.  */
02220     return FALSE;
02221 }
02222 
02223 static unsigned int write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
02224 {
02225     unsigned int start, absoff, flags;
02226     const char *name = NULL;
02227     type_t *utype = get_user_type(type, &name);
02228     unsigned int usize = type_memsize(utype);
02229     unsigned int ualign = type_buffer_alignment(utype);
02230     unsigned int size = type_memsize(type);
02231     unsigned short funoff = user_type_offset(name);
02232     short reloff;
02233 
02234     if (processed(type)) return type->typestring_offset;
02235 
02236     guard_rec(type);
02237 
02238     if(user_type_has_variable_size(utype)) usize = 0;
02239 
02240     if (type_get_type(utype) == TYPE_BASIC ||
02241         type_get_type(utype) == TYPE_ENUM)
02242     {
02243         unsigned char fc;
02244 
02245         if (type_get_type(utype) == TYPE_ENUM)
02246             fc = get_enum_fc(utype);
02247         else
02248             fc = get_basic_fc(utype);
02249 
02250         absoff = *tfsoff;
02251         print_start_tfs_comment(file, utype, absoff);
02252         print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
02253         print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
02254         *tfsoff += 2;
02255     }
02256     else
02257     {
02258         if (!processed(utype))
02259             write_embedded_types(file, NULL, utype, utype->name, TRUE, tfsoff);
02260         absoff = utype->typestring_offset;
02261     }
02262 
02263     if (type_get_type(utype) == TYPE_POINTER && get_pointer_fc(utype, NULL, FALSE) == RPC_FC_RP)
02264         flags = 0x40;
02265     else if (type_get_type(utype) == TYPE_POINTER && get_pointer_fc(utype, NULL, FALSE) == RPC_FC_UP)
02266         flags = 0x80;
02267     else
02268         flags = 0;
02269 
02270     start = *tfsoff;
02271     update_tfsoff(type, start, file);
02272     print_start_tfs_comment(file, type, start);
02273     print_file(file, 2, "0x%x,\t/* FC_USER_MARSHAL */\n", RPC_FC_USER_MARSHAL);
02274     print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
02275                flags | (ualign - 1), ualign - 1, flags);
02276     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
02277     print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)size, size);
02278     print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)usize, usize);
02279     *tfsoff += 8;
02280     reloff = absoff - *tfsoff;
02281     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n", reloff, reloff, absoff);
02282     *tfsoff += 2;
02283     return start;
02284 }
02285 
02286 static void write_member_type(FILE *file, const type_t *cont,
02287                               int cont_is_complex, const attr_list_t *attrs,
02288                               const type_t *type, unsigned int *corroff,
02289                               unsigned int *tfsoff)
02290 {
02291     if (is_embedded_complex(type) && !is_conformant_array(type))
02292     {
02293         unsigned int absoff;
02294         short reloff;
02295 
02296         if (type_get_type(type) == TYPE_UNION && is_attr(attrs, ATTR_SWITCHIS))
02297         {
02298             absoff = *corroff;
02299             *corroff += 8;
02300         }
02301         else
02302         {
02303             absoff = type->typestring_offset;
02304         }
02305         reloff = absoff - (*tfsoff + 2);
02306 
02307         print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
02308         /* padding is represented using FC_STRUCTPAD* types, so presumably
02309          * this is left over in the format for historical purposes in MIDL
02310          * or rpcrt4. */
02311         print_file(file, 2, "0x0,\n");
02312         print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
02313                    reloff, reloff, absoff);
02314         *tfsoff += 4;
02315     }
02316     else if (is_ptr(type) || is_conformant_array(type))
02317     {
02318         unsigned char fc = cont_is_complex ? RPC_FC_POINTER : RPC_FC_LONG;
02319         print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
02320         *tfsoff += 1;
02321     }
02322     else if (!write_base_type(file, type, tfsoff))
02323         error("Unsupported member type %d\n", type_get_type(type));
02324 }
02325 
02326 static void write_array_element_type(FILE *file, const type_t *type,
02327                                      int cont_is_complex, unsigned int *tfsoff)
02328 {
02329     type_t *elem = type_array_get_element(type);
02330 
02331     if (!is_embedded_complex(elem) && is_ptr(elem))
02332     {
02333         type_t *ref = type_pointer_get_ref(elem);
02334 
02335         if (processed(ref))
02336         {
02337             write_nonsimple_pointer(file, NULL, elem, TYPE_CONTEXT_CONTAINER,
02338                                     ref->typestring_offset, tfsoff);
02339             return;
02340         }
02341         if (!is_string_type(NULL, elem) &&
02342             (type_get_type(ref) == TYPE_BASIC || type_get_type(ref) == TYPE_ENUM))
02343         {
02344             *tfsoff += write_simple_pointer(file, NULL, elem, TYPE_CONTEXT_CONTAINER);
02345             return;
02346         }
02347     }
02348     return write_member_type(file, type, cont_is_complex, NULL, elem, NULL, tfsoff);
02349 }
02350 
02351 static void write_end(FILE *file, unsigned int *tfsoff)
02352 {
02353     if (*tfsoff % 2 == 0)
02354     {
02355         print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD);
02356         *tfsoff += 1;
02357     }
02358     print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END);
02359     *tfsoff += 1;
02360 }
02361 
02362 static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
02363 {
02364     unsigned int offset = 0;
02365     var_list_t *fs = type_struct_get_fields(type);
02366     var_t *f;
02367 
02368     if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
02369     {
02370         type_t *ft = f->type;
02371         unsigned int size = field_memsize( ft, &offset );
02372         if (type_get_type(ft) == TYPE_UNION && is_attr(f->attrs, ATTR_SWITCHIS))
02373         {
02374             short reloff;
02375             unsigned int absoff = ft->typestring_offset;
02376             if (is_attr(ft->attrs, ATTR_SWITCHTYPE))
02377                 absoff += 8; /* we already have a corr descr, skip it */
02378             reloff = absoff - (*tfsoff + 6);
02379             print_file(file, 0, "/* %d */\n", *tfsoff);
02380             print_file(file, 2, "0x%x,\t/* FC_NON_ENCAPSULATED_UNION */\n", RPC_FC_NON_ENCAPSULATED_UNION);
02381             print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", RPC_FC_LONG);
02382             write_conf_or_var_desc(file, current_structure, offset, ft,
02383                                    get_attrp(f->attrs, ATTR_SWITCHIS));
02384             print_file(file, 2, "NdrFcShort(%hd),\t/* Offset= %hd (%u) */\n",
02385                        reloff, reloff, absoff);
02386             *tfsoff += 8;
02387         }
02388         offset += size;
02389     }
02390 }
02391 
02392 static int write_pointer_description_offsets(
02393     FILE *file, const attr_list_t *attrs, type_t *type,
02394     unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
02395     unsigned int *typestring_offset)
02396 {
02397     int written = 0;
02398 
02399     if ((is_ptr(type) && type_get_type(type_pointer_get_ref(type)) != TYPE_INTERFACE) ||
02400         (is_array(type) && type_array_is_decl_as_ptr(type)))
02401     {
02402         if (offset_in_memory && offset_in_buffer)
02403         {
02404             unsigned int memsize;
02405 
02406             /* pointer instance
02407              *
02408              * note that MSDN states that for pointer layouts in structures,
02409              * this is a negative offset from the end of the structure, but
02410              * this statement is incorrect. all offsets are positive */
02411             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Memory offset = %d */\n", (unsigned short)*offset_in_memory, *offset_in_memory);
02412             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Buffer offset = %d */\n", (unsigned short)*offset_in_buffer, *offset_in_buffer);
02413 
02414             memsize = type_memsize(type);
02415             *offset_in_memory += memsize;
02416             /* increment these separately as in the case of conformant (varying)
02417              * structures these start at different values */
02418             *offset_in_buffer += memsize;
02419         }
02420         *typestring_offset += 4;
02421 
02422         if (is_ptr(type))
02423         {
02424             type_t *ref = type_pointer_get_ref(type);
02425 
02426             if (is_string_type(attrs, type))
02427                 write_string_tfs(file, attrs, type, TYPE_CONTEXT_CONTAINER, NULL, typestring_offset);
02428             else if (processed(ref))
02429                 write_nonsimple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER,
02430                                         ref->typestring_offset, typestring_offset);
02431             else if (type_get_type(ref) == TYPE_BASIC || type_get_type(ref) == TYPE_ENUM)
02432                 *typestring_offset += write_simple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER);
02433             else
02434                 error("write_pointer_description_offsets: type format string unknown\n");
02435         }
02436         else
02437         {
02438             unsigned int offset = type->typestring_offset;
02439             /* skip over the pointer that is written for strings, since a
02440              * pointer has to be written in-place here */
02441             if (is_string_type(attrs, type))
02442                 offset += 4;
02443             write_nonsimple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER, offset, typestring_offset);
02444         }
02445 
02446         return 1;
02447     }
02448 
02449     if (is_array(type))
02450     {
02451         return write_pointer_description_offsets(
02452             file, attrs, type_array_get_element(type), offset_in_memory,
02453             offset_in_buffer, typestring_offset);
02454     }
02455     else if (is_non_complex_struct(type))
02456     {
02457         /* otherwise search for interesting fields to parse */
02458         const var_t *v;
02459         LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
02460         {
02461             if (offset_in_memory && offset_in_buffer)
02462             {
02463                 unsigned int padding;
02464                 unsigned int align = 0;
02465                 type_memsize_and_alignment(v->type, &align);
02466                 padding = ROUNDING(*offset_in_memory, align);
02467                 *offset_in_memory += padding;
02468                 *offset_in_buffer += padding;
02469             }
02470             written += write_pointer_description_offsets(
02471                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
02472                 typestring_offset);
02473         }
02474     }
02475     else
02476     {
02477         if (offset_in_memory && offset_in_buffer)
02478         {
02479             unsigned int memsize = type_memsize(type);
02480             *offset_in_memory += memsize;
02481             /* increment these separately as in the case of conformant (varying)
02482              * structures these start at different values */
02483             *offset_in_buffer += memsize;
02484         }
02485     }
02486 
02487     return written;
02488 }
02489 
02490 static int write_no_repeat_pointer_descriptions(
02491     FILE *file, const attr_list_t *attrs, type_t *type,
02492     unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
02493     unsigned int *typestring_offset)
02494 {
02495     int written = 0;
02496 
02497     if (is_ptr(type) ||
02498         (is_conformant_array(type) && type_array_is_decl_as_ptr(type)))
02499     {
02500         print_file(file, 2, "0x%02x, /* FC_NO_REPEAT */\n", RPC_FC_NO_REPEAT);
02501         print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
02502         *typestring_offset += 2;
02503 
02504         return write_pointer_description_offsets(file, attrs, type,
02505                        offset_in_memory, offset_in_buffer, typestring_offset);
02506     }
02507 
02508     if (is_non_complex_struct(type))
02509     {
02510         const var_t *v;
02511         LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
02512         {
02513             if (offset_in_memory && offset_in_buffer)
02514             {
02515                 unsigned int padding;
02516                 unsigned int align = 0;
02517                 type_memsize_and_alignment(v->type, &align);
02518                 padding = ROUNDING(*offset_in_memory, align);
02519                 *offset_in_memory += padding;
02520                 *offset_in_buffer += padding;
02521             }
02522             written += write_no_repeat_pointer_descriptions(
02523                 file, v->attrs, v->type,
02524                 offset_in_memory, offset_in_buffer, typestring_offset);
02525         }
02526     }
02527     else
02528     {
02529         unsigned int memsize = type_memsize(type);
02530         *offset_in_memory += memsize;
02531         /* increment these separately as in the case of conformant (varying)
02532          * structures these start at different values */
02533         *offset_in_buffer += memsize;
02534     }
02535 
02536     return written;
02537 }
02538 
02539 /* Note: if file is NULL return value is number of pointers to write, else
02540  * it is the number of type format characters written */
02541 static int write_fixed_array_pointer_descriptions(
02542     FILE *file, const attr_list_t *attrs, type_t *type,
02543     unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
02544     unsigned int *typestring_offset)
02545 {
02546     int pointer_count = 0;
02547 
02548     if (type_get_type(type) == TYPE_ARRAY &&
02549         !type_array_has_conformance(type) && !type_array_has_variance(type))
02550     {
02551         unsigned int temp = 0;
02552         /* unfortunately, this needs to be done in two passes to avoid
02553          * writing out redundant FC_FIXED_REPEAT descriptions */
02554         pointer_count = write_pointer_description_offsets(
02555             NULL, attrs, type_array_get_element(type), NULL, NULL, &temp);
02556         if (pointer_count > 0)
02557         {
02558             unsigned int increment_size;
02559             unsigned int offset_of_array_pointer_mem = 0;
02560             unsigned int offset_of_array_pointer_buf = 0;
02561 
02562             increment_size = type_memsize(type_array_get_element(type));
02563 
02564             print_file(file, 2, "0x%02x, /* FC_FIXED_REPEAT */\n", RPC_FC_FIXED_REPEAT);
02565             print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
02566             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Iterations = %d */\n", (unsigned short)type_array_get_dim(type), type_array_get_dim(type));
02567             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Increment = %d */\n", (unsigned short)increment_size, increment_size);
02568             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset to array = %d */\n", (unsigned short)*offset_in_memory, *offset_in_memory);
02569             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Number of pointers = %d */\n", (unsigned short)pointer_count, pointer_count);
02570             *typestring_offset += 10;
02571 
02572             pointer_count = write_pointer_description_offsets(
02573                 file, attrs, type, &offset_of_array_pointer_mem,
02574                 &offset_of_array_pointer_buf, typestring_offset);
02575         }
02576     }
02577     else if (type_get_type(type) == TYPE_STRUCT)
02578     {
02579         const var_t *v;
02580         LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
02581         {
02582             if (offset_in_memory && offset_in_buffer)
02583             {
02584                 unsigned int padding;
02585                 unsigned int align = 0;
02586                 type_memsize_and_alignment(v->type, &align);
02587                 padding = ROUNDING(*offset_in_memory, align);
02588                 *offset_in_memory += padding;
02589                 *offset_in_buffer += padding;
02590             }
02591             pointer_count += write_fixed_array_pointer_descriptions(
02592                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
02593                 typestring_offset);
02594         }
02595     }
02596     else
02597     {
02598         if (offset_in_memory && offset_in_buffer)
02599         {
02600             unsigned int memsize;
02601             memsize = type_memsize(type);
02602             *offset_in_memory += memsize;
02603             /* increment these separately as in the case of conformant (varying)
02604              * structures these start at different values */
02605             *offset_in_buffer += memsize;
02606         }
02607     }
02608 
02609     return pointer_count;
02610 }
02611 
02612 /* Note: if file is NULL return value is number of pointers to write, else
02613  * it is the number of type format characters written */
02614 static int write_conformant_array_pointer_descriptions(
02615     FILE *file, const attr_list_t *attrs, type_t *type,
02616     unsigned int offset_in_memory, unsigned int *typestring_offset)
02617 {
02618     int pointer_count = 0;
02619 
02620     if (is_conformant_array(type) && !type_array_has_variance(type))
02621     {
02622         unsigned int temp = 0;
02623         /* unfortunately, this needs to be done in two passes to avoid
02624          * writing out redundant FC_VARIABLE_REPEAT descriptions */
02625         pointer_count = write_pointer_description_offsets(
02626             NULL, attrs, type_array_get_element(type), NULL, NULL, &temp);
02627         if (pointer_count > 0)
02628         {
02629             unsigned int increment_size;
02630             unsigned int offset_of_array_pointer_mem = offset_in_memory;
02631             unsigned int offset_of_array_pointer_buf = offset_in_memory;
02632 
02633             increment_size = type_memsize(type_array_get_element(type));
02634 
02635             if (increment_size > USHRT_MAX)
02636                 error("array size of %u bytes is too large\n", increment_size);
02637 
02638             print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
02639             print_file(file, 2, "0x%02x, /* FC_FIXED_OFFSET */\n", RPC_FC_FIXED_OFFSET);
02640             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Increment = %d */\n", (unsigned short)increment_size, increment_size);
02641             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset to array = %d */\n", (unsigned short)offset_in_memory, offset_in_memory);
02642             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Number of pointers = %d */\n", (unsigned short)pointer_count, pointer_count);
02643             *typestring_offset += 8;
02644 
02645             pointer_count = write_pointer_description_offsets(
02646                 file, attrs, type_array_get_element(type),
02647                 &offset_of_array_pointer_mem, &offset_of_array_pointer_buf,
02648                 typestring_offset);
02649         }
02650     }
02651 
02652     return pointer_count;
02653 }
02654 
02655 /* Note: if file is NULL return value is number of pointers to write, else
02656  * it is the number of type format characters written */
02657 static int write_varying_array_pointer_descriptions(
02658     FILE *file, const attr_list_t *attrs, type_t *type,
02659     unsigned int *offset_in_memory, unsigned int *offset_in_buffer,
02660     unsigned int *typestring_offset)
02661 {
02662     int pointer_count = 0;
02663 
02664     if (is_array(type) && type_array_has_variance(type))
02665     {
02666         unsigned int temp = 0;
02667         /* unfortunately, this needs to be done in two passes to avoid
02668          * writing out redundant FC_VARIABLE_REPEAT descriptions */
02669         pointer_count = write_pointer_description_offsets(
02670             NULL, attrs, type_array_get_element(type), NULL, NULL, &temp);
02671         if (pointer_count > 0)
02672         {
02673             unsigned int increment_size;
02674 
02675             increment_size = type_memsize(type_array_get_element(type));
02676 
02677             if (increment_size > USHRT_MAX)
02678                 error("array size of %u bytes is too large\n", increment_size);
02679 
02680             print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
02681             print_file(file, 2, "0x%02x, /* FC_VARIABLE_OFFSET */\n", RPC_FC_VARIABLE_OFFSET);
02682             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Increment = %d */\n", (unsigned short)increment_size, increment_size);
02683             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset to array = %d */\n", (unsigned short)*offset_in_memory, *offset_in_memory);
02684             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Number of pointers = %d */\n", (unsigned short)pointer_count, pointer_count);
02685             *typestring_offset += 8;
02686 
02687             pointer_count = write_pointer_description_offsets(
02688                 file, attrs, type_array_get_element(type), offset_in_memory,
02689                 offset_in_buffer, typestring_offset);
02690         }
02691     }
02692     else if (type_get_type(type) == TYPE_STRUCT)
02693     {
02694         const var_t *v;
02695         LIST_FOR_EACH_ENTRY( v, type_struct_get_fields(type), const var_t, entry )
02696         {
02697             if (offset_in_memory && offset_in_buffer)
02698             {
02699                 unsigned int align = 0, padding;
02700 
02701                 if (is_array(v->type) && type_array_has_variance(v->type))
02702                 {
02703                     *offset_in_buffer = ROUND_SIZE(*offset_in_buffer, 4);
02704                     /* skip over variance and offset in buffer */
02705                     *offset_in_buffer += 8;
02706                 }
02707 
02708                 type_memsize_and_alignment(v->type, &align);
02709                 padding = ROUNDING(*offset_in_memory, align);
02710                 *offset_in_memory += padding;
02711                 *offset_in_buffer += padding;
02712             }
02713             pointer_count += write_varying_array_pointer_descriptions(
02714                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
02715                 typestring_offset);
02716         }
02717     }
02718     else
02719     {
02720         if (offset_in_memory && offset_in_buffer)
02721         {
02722             unsigned int memsize = type_memsize(type);
02723             *offset_in_memory += memsize;
02724             /* increment these separately as in the case of conformant (varying)
02725              * structures these start at different values */
02726             *offset_in_buffer += memsize;
02727         }
02728     }
02729 
02730     return pointer_count;
02731 }
02732 
02733 static void write_pointer_description(FILE *file, type_t *type,
02734                                       unsigned int *typestring_offset)
02735 {
02736     unsigned int offset_in_buffer;
02737     unsigned int offset_in_memory;
02738 
02739     /* pass 1: search for single instance of a pointer (i.e. don't descend
02740      * into arrays) */
02741     if (!is_array(type))
02742     {
02743         offset_in_memory = 0;
02744         offset_in_buffer = 0;
02745         write_no_repeat_pointer_descriptions(
02746             file, NULL, type,
02747             &offset_in_memory, &offset_in_buffer, typestring_offset);
02748     }
02749 
02750     /* pass 2: search for pointers in fixed arrays */
02751     offset_in_memory = 0;
02752     offset_in_buffer = 0;
02753     write_fixed_array_pointer_descriptions(
02754         file, NULL, type,
02755         &offset_in_memory, &offset_in_buffer, typestring_offset);
02756 
02757     /* pass 3: search for pointers in conformant only arrays (but don't descend
02758      * into conformant varying or varying arrays) */
02759     if (is_conformant_array(type) &&
02760         (type_array_is_decl_as_ptr(type) || !current_structure))
02761         write_conformant_array_pointer_descriptions(
02762             file, NULL, type, 0, typestring_offset);
02763     else if (type_get_type(type) == TYPE_STRUCT &&
02764              get_struct_fc(type) == RPC_FC_CPSTRUCT)
02765     {
02766         type_t *carray = find_array_or_string_in_struct(type)->type;
02767         write_conformant_array_pointer_descriptions( file, NULL, carray,
02768                                                      type_memsize(type), typestring_offset);
02769     }
02770 
02771     /* pass 4: search for pointers in varying arrays */
02772     offset_in_memory = 0;
02773     offset_in_buffer = 0;
02774     write_varying_array_pointer_descriptions(
02775             file, NULL, type,
02776             &offset_in_memory, &offset_in_buffer, typestring_offset);
02777 }
02778 
02779 int is_declptr(const type_t *t)
02780 {
02781   return is_ptr(t) || (type_get_type(t) == TYPE_ARRAY && type_array_is_decl_as_ptr(t));
02782 }
02783 
02784 static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
02785                                      type_t *type, enum type_context context,
02786                                      const char *name, unsigned int *typestring_offset)
02787 {
02788     unsigned int start_offset;
02789     unsigned char rtype;
02790     type_t *elem_type;
02791     int is_processed = processed(type);
02792 
02793     start_offset = *typestring_offset;
02794 
02795     if (is_declptr(type))
02796     {
02797         unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER;
02798         int pointer_type = get_pointer_fc_context(type, attrs, context);
02799         if (!pointer_type)
02800             pointer_type = RPC_FC_RP;
02801         print_start_tfs_comment(file, type, *typestring_offset);
02802         print_file(file, 2,"0x%x, 0x%x,\t/* %s%s */\n",
02803                    pointer_type, flag, string_of_type(pointer_type),
02804                    flag ? " [simple_pointer]" : "");
02805         *typestring_offset += 2;
02806         if (!flag)
02807         {
02808             print_file(file, 2, "NdrFcShort(0x2),\n");
02809             *typestring_offset += 2;
02810         }
02811         is_processed = FALSE;
02812     }
02813 
02814     if (is_array(type))
02815         elem_type = type_array_get_element(type);
02816     else
02817         elem_type = type_pointer_get_ref(type);
02818 
02819     if (type_get_type(elem_type) != TYPE_BASIC)
02820     {
02821         error("write_string_tfs: Unimplemented for non-basic type %s\n", name);
02822         return start_offset;
02823     }
02824 
02825     rtype = get_basic_fc(elem_type);
02826     if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR))
02827     {
02828         error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
02829         return start_offset;
02830     }
02831 
02832     if (type_get_type(type) == TYPE_ARRAY && !type_array_has_conformance(type))
02833     {
02834         unsigned int dim = type_array_get_dim(type);
02835 
02836         if (is_processed) return start_offset;
02837 
02838         /* FIXME: multi-dimensional array */
02839         if (0xffffu < dim)
02840             error("array size for parameter %s exceeds %u bytes by %u bytes\n",
02841                   name, 0xffffu, dim - 0xffffu);
02842 
02843         if (rtype == RPC_FC_WCHAR)
02844             WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
02845         else
02846             WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
02847         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
02848         *typestring_offset += 2;
02849 
02850         print_file(file, 2, "NdrFcShort(0x%hx),\t/* %d */\n", (unsigned short)dim, dim);
02851         *typestring_offset += 2;
02852 
02853         update_tfsoff(type, start_offset, file);
02854         return start_offset;
02855     }
02856     else if (is_conformant_array(type))
02857     {
02858         if (rtype == RPC_FC_WCHAR)
02859             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
02860         else
02861             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
02862         print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
02863         *typestring_offset += 2;
02864 
02865         *typestring_offset += write_conf_or_var_desc(
02866             file, current_structure,
02867             (!type_array_is_decl_as_ptr(type) && current_structure
02868              ? type_memsize(current_structure)
02869              : 0),
02870             type, type_array_get_conformance(type));
02871 
02872         update_tfsoff(type, start_offset, file);
02873         return start_offset;
02874     }
02875     else
02876     {
02877         if (is_processed) return start_offset;
02878 
02879         if (rtype == RPC_FC_WCHAR)
02880             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
02881         else
02882             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
02883         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
02884         *typestring_offset += 2;
02885 
02886         update_tfsoff(type, start_offset, file);
02887         return start_offset;
02888     }
02889 }
02890 
02891 static unsigned int write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
02892                                     const char *name, unsigned int *typestring_offset)
02893 {
02894     const expr_t *length_is = type_array_get_variance(type);
02895     const expr_t *size_is = type_array_get_conformance(type);
02896     unsigned int align;
02897     unsigned int size;
02898     unsigned int start_offset;
02899     unsigned char fc;
02900     int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
02901     unsigned int baseoff
02902         = !type_array_is_decl_as_ptr(type) && current_structure
02903         ? type_memsize(current_structure)
02904         : 0;
02905 
02906     if (!pointer_type)
02907         pointer_type = RPC_FC_RP;
02908 
02909     write_embedded_types(file, attrs, type_array_get_element(type), name, FALSE, typestring_offset);
02910 
02911     size = type_memsize(is_conformant_array(type) ? type_array_get_element(type) : type);
02912     align = type_buffer_alignment(is_conformant_array(type) ? type_array_get_element(type) : type);
02913     fc = get_array_fc(type);
02914 
02915     start_offset = *typestring_offset;
02916     update_tfsoff(type, start_offset, file);
02917     print_start_tfs_comment(file, type, start_offset);
02918     print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
02919     print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
02920     *typestring_offset += 2;
02921 
02922     align = 0;
02923     if (fc != RPC_FC_BOGUS_ARRAY)
02924     {
02925         if (fc == RPC_FC_LGFARRAY || fc == RPC_FC_LGVARRAY)
02926         {
02927             print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", size, size);
02928             *typestring_offset += 4;
02929         }
02930         else
02931         {
02932             print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)size, size);
02933             *typestring_offset += 2;
02934         }
02935 
02936         if (is_conformant_array(type))
02937             *typestring_offset
02938                 += write_conf_or_var_desc(file, current_structure, baseoff,
02939                                           type, size_is);
02940 
02941         if (fc == RPC_FC_SMVARRAY || fc == RPC_FC_LGVARRAY)
02942         {
02943             unsigned int elsize = type_memsize(type_array_get_element(type));
02944             unsigned int dim = type_array_get_dim(type);
02945 
02946             if (fc == RPC_FC_LGVARRAY)
02947             {
02948                 print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", dim, dim);
02949                 *typestring_offset += 4;
02950             }
02951             else
02952             {
02953                 print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)dim, dim);
02954                 *typestring_offset += 2;
02955             }
02956 
02957             print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)elsize, elsize);
02958             *typestring_offset += 2;
02959         }
02960 
02961         if (length_is)
02962             *typestring_offset
02963                 += write_conf_or_var_desc(file, current_structure, baseoff,
02964                                           type, length_is);
02965 
02966         if (type_has_pointers(type_array_get_element(type)) &&
02967             (type_array_is_decl_as_ptr(type) || !current_structure))
02968         {
02969             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
02970             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
02971             *typestring_offset += 2;
02972             write_pointer_description(file, type, typestring_offset);
02973             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
02974             *typestring_offset += 1;
02975         }
02976 
02977         write_array_element_type(file, type, FALSE, typestring_offset);
02978         write_end(file, typestring_offset);
02979     }
02980     else
02981     {
02982         unsigned int dim = size_is ? 0 : type_array_get_dim(type);
02983         print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)dim, dim);
02984         *typestring_offset += 2;
02985         *typestring_offset
02986             += write_conf_or_var_desc(file, current_structure, baseoff,
02987                                       type, size_is);
02988         *typestring_offset
02989             += write_conf_or_var_desc(file, current_structure, baseoff,
02990                                       type, length_is);
02991 
02992         write_array_element_type(file, type, TRUE, typestring_offset);
02993         write_end(file, typestring_offset);
02994     }
02995 
02996     return start_offset;
02997 }
02998 
02999 static const var_t *find_array_or_string_in_struct(const type_t *type)
03000 {
03001     const var_list_t *fields = type_struct_get_fields(type);
03002     const var_t *last_field;
03003     const type_t *ft;
03004 
03005     if (!fields || list_empty(fields))
03006         return NULL;
03007 
03008     last_field = LIST_ENTRY( list_tail(fields), const var_t, entry );
03009     ft = last_field->type;
03010 
03011     if (is_conformant_array(ft) && !type_array_is_decl_as_ptr(ft))
03012         return last_field;
03013 
03014     if (type_get_type(ft) == TYPE_STRUCT)
03015         return find_array_or_string_in_struct(ft);
03016     else
03017         return NULL;
03018 }
03019 
03020 static void write_struct_members(FILE *file, const type_t *type,
03021                                  int is_complex, unsigned int *corroff,
03022                                  unsigned int *typestring_offset)
03023 {
03024     const var_t *field;
03025     unsigned short offset = 0;
03026     unsigned int salign = 1;
03027     int padding;
03028     var_list_t *fields = type_struct_get_fields(type);
03029 
03030     if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
03031     {
03032         type_t *ft = field->type;
03033         unsigned int align = 0;
03034         unsigned int size = type_memsize_and_alignment(ft, &align);
03035         align = clamp_align(align);
03036         if (salign < align) salign = align;
03037 
03038         if (!is_conformant_array(ft) || type_array_is_decl_as_ptr(ft))
03039         {
03040             if ((align - 1) & offset)
03041             {
03042                 unsigned char fc = 0;
03043                 switch (align)
03044                 {
03045                 case 2:
03046                     fc = RPC_FC_ALIGNM2;
03047                     break;
03048                 case 4:
03049                     fc = RPC_FC_ALIGNM4;
03050                     break;
03051                 case 8:
03052                     fc = RPC_FC_ALIGNM8;
03053                     break;
03054                 default:
03055                     error("write_struct_members: cannot align type %d\n", type_get_type(ft));
03056                 }
03057                 print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
03058                 offset = ROUND_SIZE(offset, align);
03059                 *typestring_offset += 1;
03060             }
03061             write_member_type(file, type, is_complex, field->attrs, field->type, corroff,
03062                               typestring_offset);
03063             offset += size;
03064         }
03065     }
03066 
03067     padding = ROUNDING(offset, salign);
03068     if (padding)
03069     {
03070         print_file(file, 2, "0x%x,\t/* FC_STRUCTPAD%d */\n",
03071                    RPC_FC_STRUCTPAD1 + padding - 1,
03072                    padding);
03073         *typestring_offset += 1;
03074     }
03075 
03076     write_end(file, typestring_offset);
03077 }
03078 
03079 static unsigned int write_struct_tfs(FILE *file, type_t *type,
03080                                      const char *name, unsigned int *tfsoff)
03081 {
03082     const type_t *save_current_structure = current_structure;
03083     unsigned int total_size;
03084     const var_t *array;
03085     unsigned int start_offset;
03086     unsigned int align;
03087     unsigned int corroff;
03088     var_t *f;
03089     unsigned char fc = get_struct_fc(type);
03090     var_list_t *fields = type_struct_get_fields(type);
03091 
03092     if (processed(type)) return type->typestring_offset;
03093 
03094     guard_rec(type);
03095     current_structure = type;
03096 
03097     total_size = type_memsize(type);
03098     align = type_buffer_alignment(type);
03099     if (total_size > USHRT_MAX)
03100         error("structure size for %s exceeds %d bytes by %d bytes\n",
03101               name, USHRT_MAX, total_size - USHRT_MAX);
03102 
03103     if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
03104         write_embedded_types(file, f->attrs, f->type, f->name, FALSE, tfsoff);
03105 
03106     array = find_array_or_string_in_struct(type);
03107     if (array && !processed(array->type))
03108     {
03109         if(is_string_type(array->attrs, array->type))
03110             write_string_tfs(file, array->attrs, array->type, TYPE_CONTEXT_CONTAINER, array->name, tfsoff);
03111         else
03112             write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
03113     }
03114 
03115     corroff = *tfsoff;
03116     write_descriptors(file, type, tfsoff);
03117 
03118     start_offset = *tfsoff;
03119     update_tfsoff(type, start_offset, file);
03120     print_start_tfs_comment(file, type, start_offset);
03121     print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
03122     print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
03123     print_file(file, 2, "NdrFcShort(0x%hx),\t/* %d */\n", (unsigned short)total_size, total_size);
03124     *tfsoff += 4;
03125 
03126     if (array)
03127     {
03128         unsigned int absoff = array->type->typestring_offset;
03129         short reloff = absoff - *tfsoff;
03130         print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
03131                    reloff, reloff, absoff);
03132         *tfsoff += 2;
03133     }
03134     else if (fc == RPC_FC_BOGUS_STRUCT)
03135     {
03136         print_file(file, 2, "NdrFcShort(0x0),\n");
03137         *tfsoff += 2;
03138     }
03139 
03140     if (fc == RPC_FC_BOGUS_STRUCT)
03141     {
03142         /* On the sizing pass, type->ptrdesc may be zero, but it's ok as
03143            nothing is written to file yet.  On the actual writing pass,
03144            this will have been updated.  */
03145         unsigned int absoff = type->ptrdesc ? type->ptrdesc : *tfsoff;
03146         int reloff = absoff - *tfsoff;
03147         assert( reloff >= 0 );
03148         print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %d (%u) */\n",
03149                    (unsigned short)reloff, reloff, absoff);
03150         *tfsoff += 2;
03151     }
03152     else if ((fc == RPC_FC_PSTRUCT) ||
03153              (fc == RPC_FC_CPSTRUCT) ||
03154              (fc == RPC_FC_CVSTRUCT && type_has_pointers(type)))
03155     {
03156         print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
03157         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
03158         *tfsoff += 2;
03159         write_pointer_description(file, type, tfsoff);
03160         print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
03161         *tfsoff += 1;
03162     }
03163 
03164     write_struct_members(file, type, fc == RPC_FC_BOGUS_STRUCT, &corroff,
03165                          tfsoff);
03166 
03167     if (fc == RPC_FC_BOGUS_STRUCT)
03168     {
03169         const var_t *f;
03170 
03171         type->ptrdesc = *tfsoff;
03172         if (fields) LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry)
03173         {
03174             type_t *ft = f->type;
03175             switch (typegen_detect_type(ft, f->attrs, TDT_IGNORE_STRINGS))
03176             {
03177             case TGT_POINTER:
03178                 if (is_string_type(f->attrs, ft))
03179                     write_string_tfs(file, f->attrs, ft, TYPE_CONTEXT_CONTAINER, f->name, tfsoff);
03180                 else
03181                     write_pointer_tfs(file, f->attrs, ft,
03182                                       type_pointer_get_ref(ft)->typestring_offset,
03183                                       TYPE_CONTEXT_CONTAINER, tfsoff);
03184                 break;
03185             case TGT_ARRAY:
03186                 if (type_array_is_decl_as_ptr(ft))
03187                 {
03188                     unsigned int offset;
03189 
03190                     print_file(file, 0, "/* %d */\n", *tfsoff);
03191 
03192                     offset = ft->typestring_offset;
03193                     /* skip over the pointer that is written for strings, since a
03194                      * pointer has to be written in-place here */
03195                     if (is_string_type(f->attrs, ft))
03196                         offset += 4;
03197                     write_nonsimple_pointer(file, f->attrs, ft, TYPE_CONTEXT_CONTAINER, offset, tfsoff);
03198                 }
03199                 break;
03200             default:
03201                 break;
03202             }
03203         }
03204         if (type->ptrdesc == *tfsoff)
03205             type->ptrdesc = 0;
03206     }
03207 
03208     current_structure = save_current_structure;
03209     return start_offset;
03210 }
03211 
03212 static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
03213 {
03214     if (t == NULL)
03215     {
03216         print_file(file, 2, "NdrFcShort(0x0),\t/* No type */\n");
03217     }
03218     else
03219     {
03220         if (type_get_type(t) == TYPE_BASIC || type_get_type(t) == TYPE_ENUM)
03221         {
03222             unsigned char fc;
03223             if (type_get_type(t) == TYPE_BASIC)
03224                 fc = get_basic_fc(t);
03225             else
03226                 fc = get_enum_fc(t);
03227             print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n",
03228                        fc, string_of_type(fc));
03229         }
03230         else if (t->typestring_offset)
03231         {
03232             short reloff = t->typestring_offset - *tfsoff;
03233             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %d (%d) */\n",
03234                        reloff, reloff, t->typestring_offset);
03235         }
03236         else
03237             error("write_branch_type: type unimplemented %d\n", type_get_type(t));
03238     }
03239 
03240     *tfsoff += 2;
03241 }
03242 
03243 static unsigned int write_union_tfs(FILE *file, const attr_list_t *attrs,
03244                                     type_t *type, unsigned int *tfsoff)
03245 {
03246     unsigned int start_offset;
03247     unsigned int size;
03248     var_list_t *fields;
03249     unsigned int nbranch = 0;
03250     type_t *deftype = NULL;
03251     short nodeftype = 0xffff;
03252     var_t *f;
03253 
03254     if (processed(type) &&
03255         (type_get_type(type) == TYPE_ENCAPSULATED_UNION || !is_attr(type->attrs, ATTR_SWITCHTYPE)))
03256         return type->typestring_offset;
03257 
03258     guard_rec(type);
03259 
03260     size = type_memsize(type);
03261 
03262     fields = type_union_get_cases(type);
03263 
03264     if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
03265     {
03266         expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
03267         if (cases)
03268             nbranch += list_count(cases);
03269         if (f->type)
03270             write_embedded_types(file, f->attrs, f->type, f->name, TRUE, tfsoff);
03271     }
03272 
03273     start_offset = *tfsoff;
03274     update_tfsoff(type, start_offset, file);
03275     print_start_tfs_comment(file, type, start_offset);
03276     if (type_get_type(type) == TYPE_ENCAPSULATED_UNION)
03277     {
03278         const var_t *sv = type_union_get_switch_value(type);
03279         const type_t *st = sv->type;
03280         unsigned char fc;
03281 
03282         if (type_get_type(st) == TYPE_BASIC)
03283         {
03284             fc = get_basic_fc(st);
03285             switch (fc)
03286             {
03287             case RPC_FC_CHAR:
03288             case RPC_FC_SMALL:
03289             case RPC_FC_BYTE:
03290             case RPC_FC_USMALL:
03291             case RPC_FC_WCHAR:
03292             case RPC_FC_SHORT:
03293             case RPC_FC_USHORT:
03294             case RPC_FC_LONG:
03295             case RPC_FC_ULONG:
03296                 break;
03297             default:
03298                 fc = 0;
03299                 error("union switch type must be an integer, char, or enum\n");
03300             }
03301         }
03302         else if (type_get_type(st) == TYPE_ENUM)
03303             fc = get_enum_fc(st);
03304         else
03305             error("union switch type must be an integer, char, or enum\n");
03306 
03307         print_file(file, 2, "0x%x,\t/* FC_ENCAPSULATED_UNION */\n", RPC_FC_ENCAPSULATED_UNION);
03308         print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
03309                    0x40 | fc, string_of_type(fc));
03310         *tfsoff += 2;
03311     }
03312     else if (is_attr(type->attrs, ATTR_SWITCHTYPE))
03313     {
03314         const expr_t *switch_is = get_attrp(attrs, ATTR_SWITCHIS);
03315         const type_t *st = get_attrp(type->attrs, ATTR_SWITCHTYPE);
03316         unsigned char fc;
03317 
03318         if (type_get_type(st) == TYPE_BASIC)
03319         {
03320             fc = get_basic_fc(st);
03321             switch (fc)
03322             {
03323             case RPC_FC_CHAR:
03324             case RPC_FC_SMALL:
03325             case RPC_FC_USMALL:
03326             case RPC_FC_SHORT:
03327             case RPC_FC_USHORT:
03328             case RPC_FC_LONG:
03329             case RPC_FC_ULONG:
03330             case RPC_FC_ENUM16:
03331             case RPC_FC_ENUM32:
03332                 break;
03333             default:
03334                 fc = 0;
03335                 error("union switch type must be an integer, char, or enum\n");
03336             }
03337         }
03338         else if (type_get_type(st) == TYPE_ENUM)
03339             fc = get_enum_fc(st);
03340         else
03341             error("union switch type must be an integer, char, or enum\n");
03342 
03343         print_file(file, 2, "0x%x,\t/* FC_NON_ENCAPSULATED_UNION */\n", RPC_FC_NON_ENCAPSULATED_UNION);
03344         print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
03345                    fc, string_of_type(fc));
03346         *tfsoff += 2;
03347         *tfsoff += write_conf_or_var_desc(file, current_structure, 0, st, switch_is );
03348         print_file(file, 2, "NdrFcShort(0x2),\t/* Offset= 2 (%u) */\n", *tfsoff + 2);
03349         *tfsoff += 2;
03350         print_file(file, 0, "/* %u */\n", *tfsoff);
03351     }
03352 
03353     print_file(file, 2, "NdrFcShort(0x%hx),\t/* %d */\n", (unsigned short)size, size);
03354     print_file(file, 2, "NdrFcShort(0x%hx),\t/* %d */\n", (unsigned short)nbranch, nbranch);
03355     *tfsoff += 4;
03356 
03357     if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
03358     {
03359         type_t *ft = f->type;
03360         expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
03361         int deflt = is_attr(f->attrs, ATTR_DEFAULT);
03362         expr_t *c;
03363 
03364         if (cases == NULL && !deflt)
03365             error("union field %s with neither case nor default attribute\n", f->name);
03366 
03367         if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry)
03368         {
03369             /* MIDL doesn't check for duplicate cases, even though that seems
03370                like a reasonable thing to do, it just dumps them to the TFS
03371                like we're going to do here.  */
03372             print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
03373             *tfsoff += 4;
03374             write_branch_type(file, ft, tfsoff);
03375         }
03376 
03377         /* MIDL allows multiple default branches, even though that seems
03378            illogical, it just chooses the last one, which is what we will
03379            do.  */
03380         if (deflt)
03381         {
03382             deftype = ft;
03383             nodeftype = 0;
03384         }
03385     }
03386 
03387     if (deftype)
03388     {
03389         write_branch_type(file, deftype, tfsoff);
03390     }
03391     else
03392     {
03393         print_file(file, 2, "NdrFcShort(0x%hx),\n", nodeftype);
03394         *tfsoff += 2;
03395     }
03396 
03397     return start_offset;
03398 }
03399 
03400 static unsigned int write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
03401                                  unsigned int *typeformat_offset)
03402 {
03403     unsigned int i;
03404     unsigned int start_offset = *typeformat_offset;
03405     expr_t *iid = get_attrp(attrs, ATTR_IIDIS);
03406 
03407     if (!iid && processed(type)) return type->typestring_offset;
03408 
03409     print_start_tfs_comment(file, type, start_offset);
03410     update_tfsoff(type, start_offset, file);
03411 
03412     if (iid)
03413     {
03414         print_file(file, 2, "0x2f,  /* FC_IP */\n");
03415         print_file(file, 2, "0x5c,  /* FC_PAD */\n");
03416         *typeformat_offset
03417             += write_conf_or_var_desc(file, current_structure, 0, type, iid) + 2;
03418     }
03419     else
03420     {
03421         const type_t *base = is_ptr(type) ? type_pointer_get_ref(type) : type;
03422         const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
03423 
03424         if (! uuid)
03425             error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
03426 
03427         print_file(file, 2, "0x2f,\t/* FC_IP */\n");
03428         print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
03429         print_file(file, 2, "NdrFcLong(0x%08x),\n", uuid->Data1);
03430         print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2);
03431         print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3);
03432         for (i = 0; i < 8; ++i)
03433             print_file(file, 2, "0x%02x,\n", uuid->Data4[i]);
03434 
03435         if (file)
03436             fprintf(file, "\n");
03437 
03438         *typeformat_offset += 18;
03439     }
03440     return start_offset;
03441 }
03442 
03443 static unsigned int write_contexthandle_tfs(FILE *file,
03444                                             const attr_list_t *attrs,
03445                                             type_t *type,
03446                                             int toplevel_param,
03447                                             unsigned int *typeformat_offset)
03448 {
03449     unsigned int start_offset = *typeformat_offset;
03450     unsigned char flags = get_contexthandle_flags( current_iface, attrs, type );
03451 
03452     print_start_tfs_comment(file, type, start_offset);
03453 
03454     if (flags & 0x80)  /* via ptr */
03455     {
03456         int pointer_type = get_pointer_fc( type, attrs, toplevel_param );
03457         if (!pointer_type) pointer_type = RPC_FC_RP;
03458         *typeformat_offset += 4;
03459         print_file(file, 2,"0x%x, 0x0,\t/* %s */\n", pointer_type, string_of_type(pointer_type) );
03460         print_file(file, 2, "NdrFcShort(0x2),\t /* Offset= 2 (%u) */\n", *typeformat_offset);
03461         print_file(file, 0, "/* %2u */\n", *typeformat_offset);
03462     }
03463 
03464     print_file(file, 2, "0x%02x,\t/* FC_BIND_CONTEXT */\n", RPC_FC_BIND_CONTEXT);
03465     print_file(file, 2, "0x%x,\t/* Context flags: ", flags);
03466     /* return and can't be null values overlap */
03467     if (((flags & 0x21) != 0x21) && (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL))
03468         print_file(file, 0, "can't be null, ");
03469     if (flags & NDR_CONTEXT_HANDLE_SERIALIZE)
03470         print_file(file, 0, "serialize, ");
03471     if (flags & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
03472         print_file(file, 0, "no serialize, ");
03473     if (flags & NDR_STRICT_CONTEXT_HANDLE)
03474         print_file(file, 0, "strict, ");
03475     if ((flags & 0x21) == 0x20)
03476         print_file(file, 0, "out, ");
03477     if ((flags & 0x21) == 0x21)
03478         print_file(file, 0, "return, ");
03479     if (flags & 0x40)
03480         print_file(file, 0, "in, ");
03481     if (flags & 0x80)
03482         print_file(file, 0, "via ptr, ");
03483     print_file(file, 0, "*/\n");
03484     print_file(file, 2, "0x%x,\t/* rundown routine */\n", get_context_handle_offset( type ));
03485     print_file(file, 2, "0, /* FIXME: param num */\n");
03486     *typeformat_offset += 4;
03487 
03488     update_tfsoff( type, start_offset, file );
03489     return start_offset;
03490 }
03491 
03492 static unsigned int write_range_tfs(FILE *file, const attr_list_t *attrs,
03493                                     type_t *type, expr_list_t *range_list,
03494                                     unsigned int *typeformat_offset)
03495 {
03496     unsigned char fc;
03497     unsigned int start_offset = *typeformat_offset;
03498     const expr_t *range_min = LIST_ENTRY(list_head(range_list), const expr_t, entry);
03499     const expr_t *range_max = LIST_ENTRY(list_next(range_list, list_head(range_list)), const expr_t, entry);
03500 
03501     if (type_get_type(type) == TYPE_BASIC)
03502         fc = get_basic_fc(type);
03503     else
03504         fc = get_enum_fc(type);
03505 
03506     /* fc must fit in lower 4-bits of 8-bit field below */
03507     assert(fc <= 0xf);
03508 
03509     print_file(file, 0, "/* %u */\n", *typeformat_offset);
03510     print_file(file, 2, "0x%x,\t/* FC_RANGE */\n", RPC_FC_RANGE);
03511     print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
03512     print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", range_min->cval, range_min->cval);
03513     print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", range_max->cval, range_max->cval);
03514     update_tfsoff( type, start_offset, file );
03515     *typeformat_offset += 10;
03516 
03517     return start_offset;
03518 }
03519 
03520 static unsigned int write_type_tfs(FILE *file, int indent,
03521                                    const attr_list_t *attrs, type_t *type,
03522                                    const char *name,
03523                                    enum type_context context,
03524                                    unsigned int *typeformat_offset)
03525 {
03526     unsigned int offset;
03527 
03528     switch (typegen_detect_type(type, attrs, TDT_ALL_TYPES))
03529     {
03530     case TGT_CTXT_HANDLE:
03531     case TGT_CTXT_HANDLE_POINTER:
03532         return write_contexthandle_tfs(file, attrs, type,
03533                                        context == TYPE_CONTEXT_TOPLEVELPARAM, typeformat_offset);
03534     case TGT_USER_TYPE:
03535         return write_user_tfs(file, type, typeformat_offset);
03536     case TGT_STRING:
03537         return write_string_tfs(file, attrs, type, context, name, typeformat_offset);
03538     case TGT_ARRAY:
03539     {
03540         unsigned int off;
03541         /* conformant and pointer arrays are handled specially */
03542         if ((context != TYPE_CONTEXT_CONTAINER &&
03543              context != TYPE_CONTEXT_CONTAINER_NO_POINTERS) ||
03544             !is_conformant_array(type) || type_array_is_decl_as_ptr(type))
03545             off = write_array_tfs(file, attrs, type, name, typeformat_offset);
03546         else
03547             off = 0;
03548         if (context != TYPE_CONTEXT_CONTAINER &&
03549             context != TYPE_CONTEXT_CONTAINER_NO_POINTERS)
03550         {
03551             int ptr_type;
03552             ptr_type = get_pointer_fc(type, attrs,
03553                                       context == TYPE_CONTEXT_TOPLEVELPARAM);
03554             if (ptr_type != RPC_FC_RP || type_array_is_decl_as_ptr(type))
03555             {
03556                 unsigned int absoff = type->typestring_offset;
03557                 short reloff = absoff - (*typeformat_offset + 2);
03558                 off = *typeformat_offset;
03559                 print_file(file, 0, "/* %d */\n", off);
03560                 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
03561                            string_of_type(ptr_type));
03562                 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
03563                            reloff, reloff, absoff);
03564                 if (ptr_type != RPC_FC_RP) update_tfsoff( type, off, file );
03565                 *typeformat_offset += 4;
03566             }
03567             type->details.array.ptr_tfsoff = off;
03568         }
03569         return off;
03570     }
03571     case TGT_STRUCT:
03572         return write_struct_tfs(file, type, name, typeformat_offset);
03573     case TGT_UNION:
03574         return write_union_tfs(file, attrs, type, typeformat_offset);
03575     case TGT_ENUM:
03576     case TGT_BASIC:
03577         /* nothing to do */
03578         return 0;
03579     case TGT_RANGE:
03580     {
03581         expr_list_t *range_list = get_attrp(attrs, ATTR_RANGE);
03582         if (!range_list)
03583             range_list = get_aliaschain_attrp(type, ATTR_RANGE);
03584         return write_range_tfs(file, attrs, type, range_list, typeformat_offset);
03585     }
03586     case TGT_IFACE_POINTER:
03587         return write_ip_tfs(file, attrs, type, typeformat_offset);
03588     case TGT_POINTER:
03589     {
03590         enum type_context ref_context;
03591         if (context == TYPE_CONTEXT_TOPLEVELPARAM)
03592             ref_context = TYPE_CONTEXT_PARAM;
03593         else if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
03594             ref_context = TYPE_CONTEXT_CONTAINER;
03595         else
03596             ref_context = context;
03597         offset = write_type_tfs( file, indent, attrs, type_pointer_get_ref(type), name,
03598                                  ref_context, typeformat_offset);
03599         if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
03600             return 0;
03601         return write_pointer_tfs(file, attrs, type, offset, context, typeformat_offset);
03602     }
03603     case TGT_INVALID:
03604         break;
03605     }
03606     error("invalid type %s for var %s\n", type->name, name);
03607     return 0;
03608 }
03609 
03610 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
03611                                 const char *name, int write_ptr, unsigned int *tfsoff)
03612 {
03613     return write_type_tfs(file, 2, attrs, type, name, write_ptr ? TYPE_CONTEXT_CONTAINER : TYPE_CONTEXT_CONTAINER_NO_POINTERS, tfsoff);
03614 }
03615 
03616 static unsigned int process_tfs_stmts(FILE *file, const statement_list_t *stmts,
03617                                       type_pred_t pred, unsigned int *typeformat_offset)
03618 {
03619     const var_t *var;
03620     const statement_t *stmt;
03621 
03622     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
03623     {
03624         const type_t *iface;
03625         const statement_t *stmt_func;
03626 
03627         if (stmt->type == STMT_LIBRARY)
03628         {
03629             process_tfs_stmts(file, stmt->u.lib->stmts, pred, typeformat_offset);
03630             continue;
03631         }
03632         else if (stmt->type != STMT_TYPE || type_get_type(stmt->u.type) != TYPE_INTERFACE)
03633             continue;
03634 
03635         iface = stmt->u.type;
03636         if (!pred(iface))
03637             continue;
03638 
03639         current_iface = iface;
03640         STATEMENTS_FOR_EACH_FUNC( stmt_func, type_iface_get_stmts(iface) )
03641         {
03642             const var_t *func = stmt_func->u.var;
03643             current_func = func;
03644             if (is_local(func->attrs)) continue;
03645 
03646             if (!is_void(type_function_get_rettype(func->type)))
03647             {
03648                 write_type_tfs( file, 2, func->attrs, type_function_get_rettype(func->type),
03649                                 func->name, TYPE_CONTEXT_PARAM, typeformat_offset);
03650             }
03651 
03652             if (type_get_function_args(func->type))
03653                 LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
03654                     write_type_tfs( file, 2, var->attrs, var->type, var->name,
03655                                     TYPE_CONTEXT_TOPLEVELPARAM, typeformat_offset );
03656         }
03657     }
03658 
03659     return *typeformat_offset + 1;
03660 }
03661 
03662 static unsigned int process_tfs(FILE *file, const statement_list_t *stmts, type_pred_t pred)
03663 {
03664     unsigned int typeformat_offset = 2;
03665 
03666     return process_tfs_stmts(file, stmts, pred, &typeformat_offset);
03667 }
03668 
03669 
03670 void write_typeformatstring(FILE *file, const statement_list_t *stmts, type_pred_t pred)
03671 {
03672     int indent = 0;
03673 
03674     print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
03675     print_file(file, indent, "{\n");
03676     indent++;
03677     print_file(file, indent, "0,\n");
03678     print_file(file, indent, "{\n");
03679     indent++;
03680     print_file(file, indent, "NdrFcShort(0x0),\n");
03681 
03682     set_all_tfswrite(TRUE);
03683     process_tfs(file, stmts, pred);
03684 
03685     print_file(file, indent, "0x0\n");
03686     indent--;
03687     print_file(file, indent, "}\n");
03688     indent--;
03689     print_file(file, indent, "};\n");
03690     print_file(file, indent, "\n");
03691 }
03692 
03693 static unsigned int get_required_buffer_size_type(
03694     const type_t *type, const char *name, const attr_list_t *attrs, int toplevel_param, unsigned int *alignment)
03695 {
03696     *alignment = 0;
03697     switch (typegen_detect_type(type, NULL, TDT_IGNORE_RANGES))
03698     {
03699     case TGT_USER_TYPE:
03700     {
03701         const char *uname;
03702         const type_t *utype = get_user_type(type, &uname);
03703         return get_required_buffer_size_type(utype, uname, NULL, FALSE, alignment);
03704     }
03705     case TGT_BASIC:
03706         switch (get_basic_fc(type))
03707         {
03708         case RPC_FC_BYTE:
03709         case RPC_FC_CHAR:
03710         case RPC_FC_USMALL:
03711         case RPC_FC_SMALL:
03712             *alignment = 4;
03713             return 1;
03714 
03715         case RPC_FC_WCHAR:
03716         case RPC_FC_USHORT:
03717         case RPC_FC_SHORT:
03718             *alignment = 4;
03719             return 2;
03720 
03721         case RPC_FC_ULONG:
03722         case RPC_FC_LONG:
03723         case RPC_FC_FLOAT:
03724         case RPC_FC_ERROR_STATUS_T:
03725             *alignment = 4;
03726             return 4;
03727 
03728         case RPC_FC_HYPER:
03729         case RPC_FC_DOUBLE:
03730             *alignment = 8;
03731             return 8;
03732 
03733         case RPC_FC_INT3264:
03734         case RPC_FC_UINT3264:
03735             assert( pointer_size );
03736             *alignment = pointer_size;
03737             return pointer_size;
03738 
03739         case RPC_FC_IGNORE:
03740         case RPC_FC_BIND_PRIMITIVE:
03741             return 0;
03742 
03743         default:
03744             error("get_required_buffer_size: unknown basic type 0x%02x\n",
03745                   get_basic_fc(type));
03746             return 0;
03747         }
03748         break;
03749 
03750     case TGT_ENUM:
03751         switch (get_enum_fc(type))
03752         {
03753         case RPC_FC_ENUM32:
03754             *alignment = 4;
03755             return 4;
03756         case RPC_FC_ENUM16:
03757             *alignment = 4;
03758             return 2;
03759         }
03760         break;
03761 
03762     case TGT_STRUCT:
03763         if (get_struct_fc(type) == RPC_FC_STRUCT)
03764         {
03765             if (!type_struct_get_fields(type)) return 0;
03766             return fields_memsize(type_struct_get_fields(type), alignment);
03767         }
03768         break;
03769 
03770     case TGT_POINTER:
03771         {
03772             unsigned int size, align;
03773             const type_t *ref = type_pointer_get_ref(type);
03774             if (is_string_type( attrs, ref )) break;
03775             if (!(size = get_required_buffer_size_type( ref, name, NULL, FALSE, &align ))) break;
03776             if (get_pointer_fc(type, attrs, toplevel_param) != RPC_FC_RP)
03777             {
03778                 size += 4 + align;
03779                 align = 4;
03780             }
03781             *alignment = align;
03782             return size;
03783         }
03784 
03785     case TGT_ARRAY:
03786         if (get_pointer_fc(type, attrs, toplevel_param) == RPC_FC_RP)
03787         {
03788             switch (get_array_fc(type))
03789             {
03790             case RPC_FC_SMFARRAY:
03791             case RPC_FC_LGFARRAY:
03792                 return type_array_get_dim(type) *
03793                     get_required_buffer_size_type(type_array_get_element(type), name,
03794                                                   NULL, FALSE, alignment);
03795             }
03796         }
03797         break;
03798 
03799     default:
03800         break;
03801     }
03802     return 0;
03803 }
03804 
03805 static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
03806 {
03807     int in_attr = is_attr(var->attrs, ATTR_IN);
03808     int out_attr = is_attr(var->attrs, ATTR_OUT);
03809 
03810     if (!in_attr && !out_attr)
03811         in_attr = 1;
03812 
03813     *alignment = 0;
03814 
03815     if ((pass == PASS_IN && in_attr) || (pass == PASS_OUT && out_attr) ||
03816         pass == PASS_RETURN)
03817     {
03818         if (is_ptrchain_attr(var, ATTR_CONTEXTHANDLE))
03819         {
03820             *alignment = 4;
03821             return 20;
03822         }
03823 
03824         if (!is_string_type(var->attrs, var->type))
03825             return get_required_buffer_size_type(var->type, var->name,
03826                                                  var->attrs, TRUE, alignment);
03827     }
03828     return 0;
03829 }
03830 
03831 static unsigned int get_function_buffer_size( const var_t *func, enum pass pass )
03832 {
03833     const var_t *var;
03834     unsigned int total_size = 0, alignment;
03835 
03836     if (type_get_function_args(func->type))
03837     {
03838         LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
03839         {
03840             total_size += get_required_buffer_size(var, &alignment, pass);
03841             total_size += alignment;
03842         }
03843     }
03844 
03845     if (pass == PASS_OUT && !is_void(type_function_get_rettype(func->type)))
03846     {
03847         var_t v = *func;
03848         v.type = type_function_get_rettype(func->type);
03849         total_size += get_required_buffer_size(&v, &alignment, PASS_RETURN);
03850         total_size += alignment;
03851     }
03852     return total_size;
03853 }
03854 
03855 static void print_phase_function(FILE *file, int indent, const char *type,
03856                                  const char *local_var_prefix, enum remoting_phase phase,
03857                                  const var_t *var, unsigned int type_offset)
03858 {
03859     const char *function;
03860     switch (phase)
03861     {
03862     case PHASE_BUFFERSIZE:
03863         function = "BufferSize";
03864         break;
03865     case PHASE_MARSHAL:
03866         function = "Marshall";
03867         break;
03868     case PHASE_UNMARSHAL:
03869         function = "Unmarshall";
03870         break;
03871     case PHASE_FREE:
03872         function = "Free";
03873         break;
03874     default:
03875         assert(0);
03876         return;
03877     }
03878 
03879     print_file(file, indent, "Ndr%s%s(\n", type, function);
03880     indent++;
03881     print_file(file, indent, "&__frame->_StubMsg,\n");
03882     print_file(file, indent, "%s%s%s%s%s,\n",
03883                (phase == PHASE_UNMARSHAL) ? "(unsigned char **)" : "(unsigned char *)",
03884                (phase == PHASE_UNMARSHAL || decl_indirect(var->type)) ? "&" : "",
03885                local_var_prefix,
03886                (phase == PHASE_UNMARSHAL && decl_indirect(var->type)) ? "_p_" : "",
03887                var->name);
03888     print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
03889                type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
03890     if (phase == PHASE_UNMARSHAL)
03891         print_file(file, indent, "0);\n");
03892     indent--;
03893 }
03894 
03895 void print_phase_basetype(FILE *file, int indent, const char *local_var_prefix,
03896                           enum remoting_phase phase, enum pass pass, const var_t *var,
03897                           const char *varname)
03898 {
03899     type_t *type = var->type;
03900     unsigned int alignment = 0;
03901 
03902     /* no work to do for other phases, buffer sizing is done elsewhere */
03903     if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
03904         return;
03905 
03906     if (type_get_type(type) == TYPE_ENUM ||
03907         (type_get_type(type) == TYPE_BASIC &&
03908          type_basic_get_type(type) == TYPE_BASIC_INT3264 &&
03909          pointer_size != 4))
03910     {
03911         unsigned char fc;
03912 
03913         if (type_get_type(type) == TYPE_ENUM)
03914             fc = get_enum_fc(type);
03915         else
03916             fc = get_basic_fc(type);
03917 
03918         if (phase == PHASE_MARSHAL)
03919             print_file(file, indent, "NdrSimpleTypeMarshall(\n");
03920         else
03921             print_file(file, indent, "NdrSimpleTypeUnmarshall(\n");
03922         print_file(file, indent+1, "&__frame->_StubMsg,\n");
03923         print_file(file, indent+1, "(unsigned char *)&%s%s,\n",
03924                    local_var_prefix,
03925                    var->name);
03926         print_file(file, indent+1, "0x%02x /* %s */);\n", fc, string_of_type(fc));
03927     }
03928     else
03929     {
03930         const type_t *ref = is_ptr(type) ? type_pointer_get_ref(type) : type;
03931         switch (get_basic_fc(ref))
03932         {
03933         case RPC_FC_BYTE:
03934         case RPC_FC_CHAR:
03935         case RPC_FC_SMALL:
03936         case RPC_FC_USMALL:
03937             alignment = 1;
03938             break;
03939 
03940         case RPC_FC_WCHAR:
03941         case RPC_FC_USHORT:
03942         case RPC_FC_SHORT:
03943             alignment = 2;
03944             break;
03945 
03946         case RPC_FC_ULONG:
03947         case RPC_FC_LONG:
03948         case RPC_FC_FLOAT:
03949         case RPC_FC_ERROR_STATUS_T:
03950         /* pointer_size must be 4 if we got here in these two cases */
03951         case RPC_FC_INT3264:
03952         case RPC_FC_UINT3264:
03953             alignment = 4;
03954             break;
03955 
03956         case RPC_FC_HYPER:
03957         case RPC_FC_DOUBLE:
03958             alignment = 8;
03959             break;
03960 
03961         case RPC_FC_IGNORE:
03962         case RPC_FC_BIND_PRIMITIVE:
03963             /* no marshalling needed */
03964             return;
03965 
03966         default:
03967             error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n",
03968                   var->name, get_basic_fc(ref));
03969         }
03970 
03971         if (phase == PHASE_MARSHAL && alignment > 1)
03972             print_file(file, indent, "MIDL_memset(__frame->_StubMsg.Buffer, 0, (0x%x - (ULONG_PTR)__frame->_StubMsg.Buffer) & 0x%x);\n", alignment, alignment - 1);
03973         print_file(file, indent, "__frame->_StubMsg.Buffer = (unsigned char *)(((ULONG_PTR)__frame->_StubMsg.Buffer + %u) & ~0x%x);\n",
03974                     alignment - 1, alignment - 1);
03975 
03976         if (phase == PHASE_MARSHAL)
03977         {
03978             print_file(file, indent, "*(");
03979             write_type_decl(file, is_ptr(type) ? type_pointer_get_ref(type) : type, NULL);
03980             if (is_ptr(type))
03981                 fprintf(file, " *)__frame->_StubMsg.Buffer = *");
03982             else
03983                 fprintf(file, " *)__frame->_StubMsg.Buffer = ");
03984             fprintf(file, "%s%s", local_var_prefix, varname);
03985             fprintf(file, ";\n");
03986         }
03987         else if (phase == PHASE_UNMARSHAL)
03988         {
03989             print_file(file, indent, "if (__frame->_StubMsg.Buffer + sizeof(");
03990             write_type_decl(file, is_ptr(type) ? type_pointer_get_ref(type) : type, NULL);
03991             fprintf(file, ") > __frame->_StubMsg.BufferEnd)\n");
03992             print_file(file, indent, "{\n");
03993             print_file(file, indent + 1, "RpcRaiseException(RPC_X_BAD_STUB_DATA);\n");
03994             print_file(file, indent, "}\n");
03995             print_file(file, indent, "%s%s%s",
03996                        (pass == PASS_IN || pass == PASS_RETURN) ? "" : "*",
03997                        local_var_prefix, varname);
03998             if (pass == PASS_IN && is_ptr(type))
03999                 fprintf(file, " = (");
04000             else
04001                 fprintf(file, " = *(");
04002             write_type_decl(file, is_ptr(type) ? type_pointer_get_ref(type) : type, NULL);
04003             fprintf(file, " *)__frame->_StubMsg.Buffer;\n");
04004         }
04005 
04006         print_file(file, indent, "__frame->_StubMsg.Buffer += sizeof(");
04007         write_type_decl(file, is_ptr(type) ? type_pointer_get_ref(type) : type, NULL);
04008         fprintf(file, ");\n");
04009     }
04010 }
04011 
04012 /* returns whether the MaxCount, Offset or ActualCount members need to be
04013  * filled in for the specified phase */
04014 static inline int is_conformance_needed_for_phase(enum remoting_phase phase)
04015 {
04016     return (phase != PHASE_UNMARSHAL);
04017 }
04018 
04019 expr_t *get_size_is_expr(const type_t *t, const char *name)
04020 {
04021     expr_t *x = NULL;
04022 
04023     for ( ; is_array(t); t = type_array_get_element(t))
04024         if (type_array_has_conformance(t) &&
04025             type_array_get_conformance(t)->type != EXPR_VOID)
04026         {
04027             if (!x)
04028                 x = type_array_get_conformance(t);
04029             else
04030                 error("%s: multidimensional conformant"
04031                       " arrays not supported at the top level\n",
04032                       name);
04033         }
04034 
04035     return x;
04036 }
04037 
04038 void write_parameter_conf_or_var_exprs(FILE *file, int indent, const char *local_var_prefix,
04039                                        enum remoting_phase phase, const var_t *var, int valid_variance)
04040 {
04041     const type_t *type = var->type;
04042     /* get fundamental type for the argument */
04043     for (;;)
04044     {
04045         switch (typegen_detect_type(type, var->attrs, TDT_IGNORE_STRINGS|TDT_IGNORE_RANGES))
04046         {
04047         case TGT_ARRAY:
04048             if (is_conformance_needed_for_phase(phase))
04049             {
04050                 if (type_array_has_conformance(type) &&
04051                     type_array_get_conformance(type)->type != EXPR_VOID)
04052                 {
04053                     print_file(file, indent, "__frame->_StubMsg.MaxCount = (ULONG_PTR)");
04054                     write_expr(file, type_array_get_conformance(type), 1, 1, NULL, NULL, local_var_prefix);
04055                     fprintf(file, ";\n\n");
04056                 }
04057                 if (type_array_has_variance(type))
04058                 {
04059                     print_file(file, indent, "__frame->_StubMsg.Offset = 0;\n"); /* FIXME */
04060                     if (valid_variance)
04061                     {
04062                         print_file(file, indent, "__frame->_StubMsg.ActualCount = (ULONG_PTR)");
04063                         write_expr(file, type_array_get_variance(type), 1, 1, NULL, NULL, local_var_prefix);
04064                         fprintf(file, ";\n\n");
04065                     }
04066                     else
04067                         print_file(file, indent, "__frame->_StubMsg.ActualCount = __frame->_StubMsg.MaxCount;\n\n");
04068                 }
04069             }
04070             break;
04071         case TGT_UNION:
04072             if (type_get_type(type) == TYPE_UNION &&
04073                 is_conformance_needed_for_phase(phase))
04074             {
04075                 print_file(file, indent, "__frame->_StubMsg.MaxCount = (ULONG_PTR)");
04076                 write_expr(file, get_attrp(var->attrs, ATTR_SWITCHIS), 1, 1, NULL, NULL, local_var_prefix);
04077                 fprintf(file, ";\n\n");
04078             }
04079             break;
04080         case TGT_IFACE_POINTER:
04081         {
04082             expr_t *iid;
04083 
04084             if (is_conformance_needed_for_phase(phase) && (iid = get_attrp( var->attrs, ATTR_IIDIS )))
04085             {
04086                 print_file( file, indent, "__frame->_StubMsg.MaxCount = (ULONG_PTR) " );
04087                 write_expr( file, iid, 1, 1, NULL, NULL, local_var_prefix );
04088                 fprintf( file, ";\n\n" );
04089             }
04090             break;
04091         }
04092         case TGT_POINTER:
04093             type = type_pointer_get_ref(type);
04094             continue;
04095         case TGT_INVALID:
04096         case TGT_USER_TYPE:
04097         case TGT_CTXT_HANDLE:
04098         case TGT_CTXT_HANDLE_POINTER:
04099         case TGT_STRING:
04100         case TGT_BASIC:
04101         case TGT_ENUM:
04102         case TGT_STRUCT:
04103         case TGT_RANGE:
04104             break;
04105         }
04106         break;
04107     }
04108 }
04109 
04110 static void write_remoting_arg(FILE *file, int indent, const var_t *func, const char *local_var_prefix,
04111                                enum pass pass, enum remoting_phase phase, const var_t *var)
04112 {
04113     int in_attr, out_attr, pointer_type;
04114     const char *type_str = NULL;
04115     const type_t *type = var->type;
04116     unsigned int alignment, start_offset = type->typestring_offset;
04117 
04118     if (is_ptr(type) || is_array(type))
04119         pointer_type = get_pointer_fc(type, var->attrs, pass != PASS_RETURN);
04120     else
04121         pointer_type = 0;
04122 
04123     in_attr = is_attr(var->attrs, ATTR_IN);
04124     out_attr = is_attr(var->attrs, ATTR_OUT);
04125     if (!in_attr && !out_attr)
04126         in_attr = 1;
04127 
04128     if (phase != PHASE_FREE)
04129         switch (pass)
04130         {
04131         case PASS_IN:
04132             if (!in_attr) return;
04133             break;
04134         case PASS_OUT:
04135             if (!out_attr) return;
04136             break;
04137         case PASS_RETURN:
04138             break;
04139         }
04140 
04141     if (phase == PHASE_BUFFERSIZE && get_required_buffer_size( var, &alignment, pass )) return;
04142 
04143     write_parameter_conf_or_var_exprs(file, indent, local_var_prefix, phase, var, TRUE);
04144 
04145     switch (typegen_detect_type(type, var->attrs, TDT_ALL_TYPES))
04146     {
04147     case TGT_CTXT_HANDLE:
04148     case TGT_CTXT_HANDLE_POINTER:
04149         if (phase == PHASE_MARSHAL)
04150         {
04151             if (pass == PASS_IN)
04152             {
04153                 /* if the context_handle attribute appears in the chain of types
04154                  * without pointers being followed, then the context handle must
04155                  * be direct, otherwise it is a pointer */
04156                 int is_ch_ptr = is_aliaschain_attr(type, ATTR_CONTEXTHANDLE) ? FALSE : TRUE;
04157                 print_file(file, indent, "NdrClientContextMarshall(\n");
04158                 print_file(file, indent + 1, "&__frame->_StubMsg,\n");
04159                 print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s%s,\n", is_ch_ptr ? "*" : "", local_var_prefix, var->name);
04160                 print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
04161             }
04162             else
04163             {
04164                 print_file(file, indent, "NdrServerContextNewMarshall(\n");
04165                 print_file(file, indent + 1, "&__frame->_StubMsg,\n");
04166                 print_file(file, indent + 1, "(NDR_SCONTEXT)%s%s,\n", local_var_prefix, var->name);
04167                 print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown,\n", get_context_handle_type_name(var->type));
04168                 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
04169             }
04170         }
04171         else if (phase == PHASE_UNMARSHAL)
04172         {
04173             if (pass == PASS_OUT)
04174             {
04175                 if (!in_attr)
04176                     print_file(file, indent, "*%s%s = 0;\n", local_var_prefix, var->name);
04177                 print_file(file, indent, "NdrClientContextUnmarshall(\n");
04178                 print_file(file, indent + 1, "&__frame->_StubMsg,\n");
04179                 print_file(file, indent + 1, "(NDR_CCONTEXT *)%s%s,\n", local_var_prefix, var->name);
04180                 print_file(file, indent + 1, "__frame->_Handle);\n");
04181             }
04182             else
04183             {
04184                 print_file(file, indent, "%s%s = NdrServerContextNewUnmarshall(\n", local_var_prefix, var->name);
04185                 print_file(file, indent + 1, "&__frame->_StubMsg,\n");
04186                 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
04187             }
04188         }
04189         break;
04190     case TGT_USER_TYPE:
04191         print_phase_function(file, indent, "UserMarshal", local_var_prefix, phase, var, start_offset);
04192         break;
04193     case TGT_STRING:
04194         if (phase == PHASE_FREE || pass == PASS_RETURN ||
04195             pointer_type != RPC_FC_RP)
04196         {
04197             /* strings returned are assumed to be global and hence don't
04198              * need freeing */
04199             if (is_declptr(type) && !(phase == PHASE_FREE && pass == PASS_RETURN))
04200                 print_phase_function(file, indent, "Pointer", local_var_prefix,
04201                                      phase, var, start_offset);
04202             else if (pointer_type == RPC_FC_RP && phase == PHASE_FREE &&
04203                 !in_attr && is_conformant_array(type))
04204             {
04205                 print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
04206                 indent++;
04207                 print_file(file, indent, "__frame->_StubMsg.pfnFree(%s%s);\n", local_var_prefix, var->name);
04208             }
04209         }
04210         else
04211         {
04212             unsigned int real_start_offset = start_offset;
04213             /* skip over pointer description straight to string description */
04214             if (is_declptr(type))
04215             {
04216                 if (is_conformant_array(type))
04217                     real_start_offset += 4;
04218                 else
04219                     real_start_offset += 2;
04220             }
04221             if (is_array(type) && !is_conformant_array(type))
04222                 print_phase_function(file, indent, "NonConformantString",
04223                                      local_var_prefix, phase, var,
04224                                      real_start_offset);
04225             else
04226                 print_phase_function(file, indent, "ConformantString", local_var_prefix,
04227                                      phase, var, real_start_offset);
04228         }
04229         break;
04230     case TGT_ARRAY:
04231     {
04232         unsigned char tc = get_array_fc(type);
04233         const char *array_type = NULL;
04234 
04235         /* We already have the size_is expression since it's at the
04236            top level, but do checks for multidimensional conformant
04237            arrays.  When we handle them, we'll need to extend this
04238            function to return a list, and then we'll actually use
04239            the return value.  */
04240         get_size_is_expr(type, var->name);
04241 
04242         switch (tc)
04243         {
04244         case RPC_FC_SMFARRAY:
04245         case RPC_FC_LGFARRAY:
04246             array_type = "FixedArray";
04247             break;
04248         case RPC_FC_SMVARRAY:
04249         case RPC_FC_LGVARRAY:
04250             array_type = "VaryingArray";
04251             break;
04252         case RPC_FC_CARRAY:
04253             array_type = "ConformantArray";
04254             break;
04255         case RPC_FC_CVARRAY:
04256             array_type = "ConformantVaryingArray";
04257             break;
04258         case RPC_FC_BOGUS_ARRAY:
04259             array_type = "ComplexArray";
04260             break;
04261         }
04262 
04263         if (pointer_type != RPC_FC_RP) array_type = "Pointer";
04264 
04265         if (phase == PHASE_FREE && pointer_type == RPC_FC_RP)
04266         {
04267             /* these are all unmarshalled by allocating memory */
04268             if (tc == RPC_FC_BOGUS_ARRAY ||
04269                 tc == RPC_FC_CVARRAY ||
04270                 ((tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY) && in_attr) ||
04271                 (tc == RPC_FC_CARRAY && !in_attr))
04272             {
04273                 if (type_array_is_decl_as_ptr(type) && type->details.array.ptr_tfsoff)
04274                 {
04275                     print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var,
04276                                          type->details.array.ptr_tfsoff);
04277                     break;
04278                 }
04279                 print_phase_function(file, indent, array_type, local_var_prefix, phase, var, start_offset);
04280                 print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
04281                 indent++;
04282                 print_file(file, indent, "__frame->_StubMsg.pfnFree(%s%s);\n", local_var_prefix, var->name);
04283                 break;
04284             }
04285         }
04286         print_phase_function(file, indent, array_type, local_var_prefix, phase, var, start_offset);
04287         break;
04288     }
04289     case TGT_BASIC:
04290         print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
04291         break;
04292     case TGT_ENUM:
04293         print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
04294         break;
04295     case TGT_RANGE:
04296         print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
04297         /* Note: this goes beyond what MIDL does - it only supports arguments
04298          * with the [range] attribute in Oicf mode */
04299         if (phase == PHASE_UNMARSHAL)
04300         {
04301             const expr_t *range_min;
04302             const expr_t *range_max;
04303             expr_list_t *range_list = get_attrp(var->attrs, ATTR_RANGE);
04304             if (!range_list)
04305                 range_list = get_aliaschain_attrp(type, ATTR_RANGE);
04306             range_min = LIST_ENTRY(list_head(range_list), const expr_t, entry);
04307             range_max = LIST_ENTRY(list_next(range_list, list_head(range_list)), const expr_t, entry);
04308 
04309             print_file(file, indent, "if ((%s%s < (", local_var_prefix, var->name);
04310             write_type_decl(file, var->type, NULL);
04311             fprintf(file, ")0x%x) || (%s%s > (", range_min->cval, local_var_prefix, var->name);
04312             write_type_decl(file, var->type, NULL);
04313             fprintf(file, ")0x%x))\n", range_max->cval);
04314             print_file(file, indent, "{\n");
04315             print_file(file, indent+1, "RpcRaiseException(RPC_S_INVALID_BOUND);\n");
04316             print_file(file, indent, "}\n");
04317         }
04318         break;
04319     case TGT_STRUCT:
04320         switch (get_struct_fc(type))
04321         {
04322         case RPC_FC_STRUCT:
04323             if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
04324                 print_phase_function(file, indent, "SimpleStruct", local_var_prefix, phase, var, start_offset);
04325             break;
04326         case RPC_FC_PSTRUCT:
04327             print_phase_function(file, indent, "SimpleStruct", local_var_prefix, phase, var, start_offset);
04328             break;
04329         case RPC_FC_CSTRUCT:
04330         case RPC_FC_CPSTRUCT:
04331             print_phase_function(file, indent, "ConformantStruct", local_var_prefix, phase, var, start_offset);
04332             break;
04333         case RPC_FC_CVSTRUCT:
04334             print_phase_function(file, indent, "ConformantVaryingStruct", local_var_prefix, phase, var, start_offset);
04335             break;
04336         case RPC_FC_BOGUS_STRUCT:
04337             print_phase_function(file, indent, "ComplexStruct", local_var_prefix, phase, var, start_offset);
04338             break;
04339         default:
04340             error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, get_struct_fc(type));
04341         }
04342         break;
04343     case TGT_UNION:
04344     {
04345         const char *union_type = NULL;
04346 
04347         if (type_get_type(type) == TYPE_UNION)
04348             union_type = "NonEncapsulatedUnion";
04349         else if (type_get_type(type) == TYPE_ENCAPSULATED_UNION)
04350             union_type = "EncapsulatedUnion";
04351 
04352         print_phase_function(file, indent, union_type, local_var_prefix,
04353                              phase, var, start_offset);
04354         break;
04355     }
04356     case TGT_POINTER:
04357     {
04358         const type_t *ref = type_pointer_get_ref(type);
04359         if (pointer_type == RPC_FC_RP) switch (typegen_detect_type(ref, NULL, TDT_ALL_TYPES))
04360         {
04361         case TGT_BASIC:
04362             print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
04363             break;
04364         case TGT_ENUM:
04365             /* base types have known sizes, so don't need a sizing pass
04366              * and don't have any memory to free and so don't need a
04367              * freeing pass */
04368             if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
04369                 print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
04370             break;
04371         case TGT_STRUCT:
04372             switch (get_struct_fc(ref))
04373             {
04374             case RPC_FC_STRUCT:
04375                 /* simple structs have known sizes, so don't need a sizing
04376                  * pass and don't have any memory to free and so don't
04377                  * need a freeing pass */
04378                 if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
04379                     type_str = "SimpleStruct";
04380                 else if (phase == PHASE_FREE && pass == PASS_RETURN)
04381                 {
04382                     print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
04383                     indent++;
04384                     print_file(file, indent, "__frame->_StubMsg.pfnFree(%s%s);\n", local_var_prefix, var->name);
04385                     indent--;
04386                 }
04387                 break;
04388             case RPC_FC_PSTRUCT:
04389                 type_str = "SimpleStruct";
04390                 break;
04391             case RPC_FC_CSTRUCT:
04392             case RPC_FC_CPSTRUCT:
04393                 type_str = "ConformantStruct";
04394                 break;
04395             case RPC_FC_CVSTRUCT:
04396                 type_str = "ConformantVaryingStruct";
04397                 break;
04398             case RPC_FC_BOGUS_STRUCT:
04399                 type_str = "ComplexStruct";
04400                 break;
04401             default:
04402                 error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, get_struct_fc(ref));
04403             }
04404 
04405             if (type_str)
04406             {
04407                 if (phase == PHASE_FREE)
04408                     type_str = "Pointer";
04409                 else
04410                     start_offset = ref->typestring_offset;
04411                 print_phase_function(file, indent, type_str, local_var_prefix, phase, var, start_offset);
04412             }
04413             break;
04414         case TGT_UNION:
04415             if (phase == PHASE_FREE)
04416                 type_str = "Pointer";
04417             else
04418             {
04419                 if (type_get_type(ref) == TYPE_UNION)
04420                     type_str = "NonEncapsulatedUnion";
04421                 else if (type_get_type(ref) == TYPE_ENCAPSULATED_UNION)
04422                     type_str = "EncapsulatedUnion";
04423 
04424                 start_offset = ref->typestring_offset;
04425             }
04426 
04427             print_phase_function(file, indent, type_str, local_var_prefix,
04428                                  phase, var, start_offset);
04429             break;
04430         case TGT_USER_TYPE:
04431             if (phase != PHASE_FREE)
04432             {
04433                 type_str = "UserMarshal";
04434                 start_offset = ref->typestring_offset;
04435             }
04436             else type_str = "Pointer";
04437 
04438             print_phase_function(file, indent, type_str, local_var_prefix, phase, var, start_offset);
04439             break;
04440         case TGT_STRING:
04441         case TGT_POINTER:
04442         case TGT_ARRAY:
04443         case TGT_RANGE:
04444         case TGT_IFACE_POINTER:
04445         case TGT_CTXT_HANDLE:
04446         case TGT_CTXT_HANDLE_POINTER:
04447             print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
04448             break;
04449         case TGT_INVALID:
04450             assert(0);
04451             break;
04452         }
04453         else
04454             print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
04455         break;
04456     }
04457     case TGT_IFACE_POINTER:
04458         print_phase_function(file, indent, "InterfacePointer", local_var_prefix, phase, var, start_offset);
04459         break;
04460     case TGT_INVALID:
04461         assert(0);
04462         break;
04463     }
04464     fprintf(file, "\n");
04465 }
04466 
04467 void write_remoting_arguments(FILE *file, int indent, const var_t *func, const char *local_var_prefix,
04468                               enum pass pass, enum remoting_phase phase)
04469 {
04470     if (phase == PHASE_BUFFERSIZE && pass != PASS_RETURN)
04471     {
04472         unsigned int size = get_function_buffer_size( func, pass );
04473         print_file(file, indent, "__frame->_StubMsg.BufferLength = %u;\n", size);
04474     }
04475 
04476     if (pass == PASS_RETURN)
04477     {
04478         var_t var;
04479         var = *func;
04480         var.type = type_function_get_rettype(func->type);
04481         var.name = xstrdup( "_RetVal" );
04482         write_remoting_arg( file, indent, func, local_var_prefix, pass, phase, &var );
04483         free( var.name );
04484     }
04485     else
04486     {
04487         const var_t *var;
04488         if (!type_get_function_args(func->type))
04489             return;
04490         LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
04491             write_remoting_arg( file, indent, func, local_var_prefix, pass, phase, var );
04492     }
04493 }
04494 
04495 
04496 unsigned int get_size_procformatstring_func(const type_t *iface, const var_t *func)
04497 {
04498     unsigned int offset = 0;
04499     write_procformatstring_func( NULL, 0, iface, func, &offset, 0 );
04500     return offset;
04501 }
04502 
04503 unsigned int get_size_procformatstring(const statement_list_t *stmts, type_pred_t pred)
04504 {
04505     const statement_t *stmt;
04506     unsigned int size = 1;
04507 
04508     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
04509     {
04510         const type_t *iface;
04511         const statement_t *stmt_func;
04512 
04513         if (stmt->type == STMT_LIBRARY)
04514         {
04515             size += get_size_procformatstring(stmt->u.lib->stmts, pred) - 1;
04516             continue;
04517         }
04518         else if (stmt->type != STMT_TYPE || type_get_type(stmt->u.type) != TYPE_INTERFACE)
04519             continue;
04520 
04521         iface = stmt->u.type;
04522         if (!pred(iface))
04523             continue;
04524 
04525         STATEMENTS_FOR_EACH_FUNC( stmt_func, type_iface_get_stmts(iface) )
04526         {
04527             const var_t *func = stmt_func->u.var;
04528             if (!is_local(func->attrs))
04529                 size += get_size_procformatstring_func( iface, func );
04530         }
04531     }
04532     return size;
04533 }
04534 
04535 unsigned int get_size_typeformatstring(const statement_list_t *stmts, type_pred_t pred)
04536 {
04537     set_all_tfswrite(FALSE);
04538     return process_tfs(NULL, stmts, pred);
04539 }
04540 
04541 void declare_stub_args( FILE *file, int indent, const var_t *func )
04542 {
04543     int in_attr, out_attr;
04544     int i = 0;
04545     const var_t *var;
04546 
04547     /* declare return value '_RetVal' */
04548     if (!is_void(type_function_get_rettype(func->type)))
04549     {
04550         print_file(file, indent, "%s", "");
04551         write_type_decl_left(file, type_function_get_rettype(func->type));
04552         fprintf(file, " _RetVal;\n");
04553     }
04554 
04555     if (!type_get_function_args(func->type))
04556         return;
04557 
04558     LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
04559     {
04560         in_attr = is_attr(var->attrs, ATTR_IN);
04561         out_attr = is_attr(var->attrs, ATTR_OUT);
04562         if (!out_attr && !in_attr)
04563             in_attr = 1;
04564 
04565         if (is_context_handle(var->type))
04566             print_file(file, indent, "NDR_SCONTEXT %s;\n", var->name);
04567         else
04568         {
04569             if (!in_attr && !is_conformant_array(var->type))
04570             {
04571                 type_t *type_to_print;
04572                 char name[16];
04573                 print_file(file, indent, "%s", "");
04574                 if (type_get_type(var->type) == TYPE_ARRAY &&
04575                     !type_array_is_decl_as_ptr(var->type))
04576                     type_to_print = var->type;
04577                 else
04578                     type_to_print = type_pointer_get_ref(var->type);
04579                 sprintf(name, "_W%u", i++);
04580                 write_type_decl(file, type_to_print, name);
04581                 fprintf(file, ";\n");
04582             }
04583 
04584             print_file(file, indent, "%s", "");
04585             write_type_decl_left(file, var->type);
04586             fprintf(file, " ");
04587             if (type_get_type(var->type) == TYPE_ARRAY &&
04588                 !type_array_is_decl_as_ptr(var->type)) {
04589                 fprintf(file, "(*%s)", var->name);
04590             } else
04591                 fprintf(file, "%s", var->name);
04592             write_type_right(file, var->type, FALSE);
04593             fprintf(file, ";\n");
04594 
04595             if (decl_indirect(var->type))
04596                 print_file(file, indent, "void *_p_%s;\n", var->name);
04597         }
04598     }
04599 }
04600 
04601 
04602 void assign_stub_out_args( FILE *file, int indent, const var_t *func, const char *local_var_prefix )
04603 {
04604     int in_attr, out_attr;
04605     int i = 0, sep = 0;
04606     const var_t *var;
04607 
04608     if (!type_get_function_args(func->type))
04609         return;
04610 
04611     LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
04612     {
04613         in_attr = is_attr(var->attrs, ATTR_IN);
04614         out_attr = is_attr(var->attrs, ATTR_OUT);
04615         if (!out_attr && !in_attr)
04616             in_attr = 1;
04617 
04618         if (!in_attr)
04619         {
04620             print_file(file, indent, "%s%s", local_var_prefix, var->name);
04621 
04622             switch (typegen_detect_type(var->type, var->attrs, TDT_IGNORE_STRINGS))
04623             {
04624             case TGT_CTXT_HANDLE_POINTER:
04625                 fprintf(file, " = NdrContextHandleInitialize(\n");
04626                 print_file(file, indent + 1, "&__frame->_StubMsg,\n");
04627                 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n",
04628                            var->type->typestring_offset);
04629                 break;
04630             case TGT_ARRAY:
04631                 if (type_array_has_conformance(var->type))
04632                 {
04633                     unsigned int size;
04634                     type_t *type;
04635 
04636                     fprintf(file, " = NdrAllocate(&__frame->_StubMsg, ");
04637                     for (type = var->type;
04638                          is_array(type) && type_array_has_conformance(type);
04639                          type = type_array_get_element(type))
04640                     {
04641                         write_expr(file, type_array_get_conformance(type), TRUE,
04642                                    TRUE, NULL, NULL, local_var_prefix);
04643                         fprintf(file, " * ");
04644                     }
04645                     size = type_memsize(type);
04646                     fprintf(file, "%u);\n", size);
04647 
04648                     print_file(file, indent, "memset(%s%s, 0, ", local_var_prefix, var->name);
04649                     for (type = var->type;
04650                          is_array(type) && type_array_has_conformance(type);
04651                          type = type_array_get_element(type))
04652                     {
04653                         write_expr(file, type_array_get_conformance(type), TRUE,
04654                                    TRUE, NULL, NULL, local_var_prefix);
04655                         fprintf(file, " * ");
04656                     }
04657                     size = type_memsize(type);
04658                     fprintf(file, "%u);\n", size);
04659                 }
04660                 else
04661                     fprintf(file, " = &%s_W%u;\n", local_var_prefix, i++);
04662                 break;
04663             case TGT_POINTER:
04664                 fprintf(file, " = &%s_W%u;\n", local_var_prefix, i);
04665                 switch (typegen_detect_type(type_pointer_get_ref(var->type), var->attrs, TDT_IGNORE_STRINGS))
04666                 {
04667                 case TGT_BASIC:
04668                 case TGT_ENUM:
04669                 case TGT_POINTER:
04670                 case TGT_RANGE:
04671                 case TGT_IFACE_POINTER:
04672                     print_file(file, indent, "%s_W%u = 0;\n", local_var_prefix, i);
04673                     break;
04674                 case TGT_USER_TYPE:
04675                     print_file(file, indent, "memset(&%s_W%u, 0, sizeof(%s_W%u));\n",
04676                                local_var_prefix, i, local_var_prefix, i);
04677                     break;
04678                 case TGT_STRUCT:
04679                 case TGT_UNION:
04680                 case TGT_ARRAY:
04681                 case TGT_CTXT_HANDLE:
04682                 case TGT_CTXT_HANDLE_POINTER:
04683                 case TGT_INVALID:
04684                 case TGT_STRING:
04685                     /* not initialised */
04686                     break;
04687                 }
04688                 i++;
04689                 break;
04690             default:
04691                 break;
04692             }
04693 
04694             sep = 1;
04695         }
04696     }
04697     if (sep)
04698         fprintf(file, "\n");
04699 }
04700 
04701 
04702 void write_func_param_struct( FILE *file, const type_t *iface, const type_t *func,
04703                               const char *var_decl, int add_retval )
04704 {
04705     type_t *rettype = type_function_get_rettype( func );
04706     const var_list_t *args = type_get_function_args( func );
04707     const var_t *arg;
04708     int needs_packing;
04709     unsigned int align = 0;
04710 
04711     if (args)
04712         LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
04713             if (!is_array( arg->type )) type_memsize_and_alignment( arg->type, &align );
04714 
04715     needs_packing = (align > pointer_size);
04716 
04717     if (needs_packing) print_file( file, 0, "#include <pshpack%u.h>\n", pointer_size );
04718     print_file(file, 1, "struct _PARAM_STRUCT\n" );
04719     print_file(file, 1, "{\n" );
04720     if (is_object( iface )) print_file(file, 2, "%s *This;\n", iface->name );
04721 
04722     if (args) LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
04723     {
04724         print_file(file, 2, "%s", "");
04725         write_type_left( file, (type_t *)arg->type, TRUE );
04726         if (needs_space_after( arg->type )) fputc( ' ', file );
04727         if (is_array( arg->type ) && !type_array_is_decl_as_ptr( arg->type )) fputc( '*', file );
04728 
04729         /* FIXME: should check for large args being passed by pointer */
04730         align = 0;
04731         if (is_array( arg->type ) || is_ptr( arg->type )) align = pointer_size;
04732         else type_memsize_and_alignment( arg->type, &align );
04733 
04734         if (align >= pointer_size)
04735             fprintf( file, "%s;\n", arg->name );
04736         else
04737             fprintf( file, "%s DECLSPEC_ALIGN(%u);\n", arg->name, pointer_size );
04738     }
04739     if (add_retval && !is_void( rettype ))
04740     {
04741         print_file(file, 2, "%s", "");
04742         write_type_decl( file, rettype, "_RetVal" );
04743         if (is_array( rettype ) || is_ptr( rettype ) || type_memsize( rettype ) == pointer_size)
04744             fprintf( file, ";\n" );
04745         else
04746             fprintf( file, " DECLSPEC_ALIGN(%u);\n", pointer_size );
04747     }
04748     print_file(file, 1, "} %s;\n", var_decl );
04749     if (needs_packing) print_file( file, 0, "#include <poppack.h>\n" );
04750     print_file( file, 0, "\n" );
04751 }
04752 
04753 void write_pointer_checks( FILE *file, int indent, const var_t *func )
04754 {
04755     const var_list_t *args = type_get_function_args( func->type );
04756     const var_t *var;
04757 
04758     if (!args) return;
04759 
04760     LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
04761         if (cant_be_null( var ))
04762             print_file( file, indent, "if (!%s) RpcRaiseException(RPC_X_NULL_REF_POINTER);\n", var->name );
04763 }
04764 
04765 int write_expr_eval_routines(FILE *file, const char *iface)
04766 {
04767     static const char *var_name = "pS";
04768     static const char *var_name_expr = "pS->";
04769     int result = 0;
04770     struct expr_eval_routine *eval;
04771     unsigned short callback_offset = 0;
04772 
04773     LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
04774     {
04775         const char *name = eval->name;
04776         result = 1;
04777 
04778         print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
04779                    eval->iface ? eval->iface->name : iface, name, callback_offset);
04780         print_file(file, 0, "{\n");
04781         if (type_get_type( eval->cont_type ) == TYPE_FUNCTION)
04782         {
04783             write_func_param_struct( file, eval->iface, eval->cont_type,
04784                                      "*pS = (struct _PARAM_STRUCT *)pStubMsg->StackTop", FALSE );
04785         }
04786         else
04787         {
04788             print_file(file, 1, "%s", "");
04789             write_type_left(file, (type_t *)eval->cont_type, TRUE);
04790             fprintf(file, " *%s = (", var_name);
04791             write_type_left(file, (type_t *)eval->cont_type, TRUE);
04792             fprintf(file, " *)(pStubMsg->StackTop - %u);\n", eval->baseoff);
04793         }
04794         print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */
04795         print_file(file, 1, "pStubMsg->MaxCount = (ULONG_PTR)");
04796         write_expr(file, eval->expr, 1, 1, var_name_expr, eval->cont_type, "");
04797         fprintf(file, ";\n");
04798         print_file(file, 0, "}\n\n");
04799         callback_offset++;
04800     }
04801     return result;
04802 }
04803 
04804 void write_expr_eval_routine_list(FILE *file, const char *iface)
04805 {
04806     struct expr_eval_routine *eval;
04807     struct expr_eval_routine *cursor;
04808     unsigned short callback_offset = 0;
04809 
04810     fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
04811     fprintf(file, "{\n");
04812 
04813     LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
04814     {
04815         print_file(file, 1, "%s_%sExprEval_%04u,\n",
04816                    eval->iface ? eval->iface->name : iface, eval->name, callback_offset);
04817         callback_offset++;
04818         list_remove(&eval->entry);
04819         free(eval->name);
04820         free(eval);
04821     }
04822 
04823     fprintf(file, "};\n\n");
04824 }
04825 
04826 void write_user_quad_list(FILE *file)
04827 {
04828     user_type_t *ut;
04829 
04830     if (list_empty(&user_type_list))
04831         return;
04832 
04833     fprintf(file, "static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[] =\n");
04834     fprintf(file, "{\n");
04835     LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
04836     {
04837         const char *sep = &ut->entry == list_tail(&user_type_list) ? "" : ",";
04838         print_file(file, 1, "{\n");
04839         print_file(file, 2, "(USER_MARSHAL_SIZING_ROUTINE)%s_UserSize,\n", ut->name);
04840         print_file(file, 2, "(USER_MARSHAL_MARSHALLING_ROUTINE)%s_UserMarshal,\n", ut->name);
04841         print_file(file, 2, "(USER_MARSHAL_UNMARSHALLING_ROUTINE)%s_UserUnmarshal,\n", ut->name);
04842         print_file(file, 2, "(USER_MARSHAL_FREEING_ROUTINE)%s_UserFree\n", ut->name);
04843         print_file(file, 1, "}%s\n", sep);
04844     }
04845     fprintf(file, "};\n\n");
04846 }
04847 
04848 void write_endpoints( FILE *f, const char *prefix, const str_list_t *list )
04849 {
04850     const struct str_list_entry_t *endpoint;
04851     const char *p;
04852 
04853     /* this should be an array of RPC_PROTSEQ_ENDPOINT but we want const strings */
04854     print_file( f, 0, "static const unsigned char * const %s__RpcProtseqEndpoint[][2] =\n{\n", prefix );
04855     LIST_FOR_EACH_ENTRY( endpoint, list, const struct str_list_entry_t, entry )
04856     {
04857         print_file( f, 1, "{ (const unsigned char *)\"" );
04858         for (p = endpoint->str; *p && *p != ':'; p++)
04859         {
04860             if (*p == '"' || *p == '\\') fputc( '\\', f );
04861             fputc( *p, f );
04862         }
04863         if (!*p) goto error;
04864         if (p[1] != '[') goto error;
04865 
04866         fprintf( f, "\", (const unsigned char *)\"" );
04867         for (p += 2; *p && *p != ']'; p++)
04868         {
04869             if (*p == '"' || *p == '\\') fputc( '\\', f );
04870             fputc( *p, f );
04871         }
04872         if (*p != ']') goto error;
04873         fprintf( f, "\" },\n" );
04874     }
04875     print_file( f, 0, "};\n\n" );
04876     return;
04877 
04878 error:
04879     error("Invalid endpoint syntax '%s'\n", endpoint->str);
04880 }
04881 
04882 void write_client_call_routine( FILE *file, const type_t *iface, const var_t *func,
04883                                 const char *prefix, unsigned int proc_offset )
04884 {
04885     type_t *rettype = type_function_get_rettype( func->type );
04886     int has_ret = !is_void( rettype );
04887     const var_list_t *args = type_get_function_args( func->type );
04888     const var_t *arg;
04889     int len, needs_params = 0;
04890 
04891     /* we need a param structure if we have more than one arg */
04892     if (pointer_size == 4 && args) needs_params = is_object( iface ) || list_count( args ) > 1;
04893 
04894     print_file( file, 0, "{\n");
04895     if (needs_params)
04896     {
04897         if (has_ret) print_file( file, 1, "%s", "CLIENT_CALL_RETURN _RetVal;\n" );
04898         write_func_param_struct( file, iface, func->type, "__params", FALSE );
04899         if (is_object( iface )) print_file( file, 1, "__params.This = This;\n" );
04900         if (args)
04901             LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
04902                 print_file( file, 1, "__params.%s = %s;\n", arg->name, arg->name );
04903     }
04904     else if (has_ret) print_file( file, 1, "%s", "CLIENT_CALL_RETURN _RetVal;\n\n" );
04905 
04906     len = fprintf( file, "    %s%s( ",
04907                    has_ret ? "_RetVal = " : "",
04908                    get_stub_mode() == MODE_Oif ? "NdrClientCall2" : "NdrClientCall" );
04909     fprintf( file, "&%s_StubDesc,", prefix );
04910     fprintf( file, "\n%*s&__MIDL_ProcFormatString.Format[%u]", len, "", proc_offset );
04911     if (needs_params)
04912     {
04913         fprintf( file, ",\n%*s&__params", len, "" );
04914     }
04915     else if (pointer_size == 8)
04916     {
04917         if (is_object( iface )) fprintf( file, ",\n%*sThis", len, "" );
04918         if (args)
04919             LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
04920                 fprintf( file, ",\n%*s%s", len, "", arg->name );
04921     }
04922     else
04923     {
04924         if (is_object( iface )) fprintf( file, ",\n%*s&This", len, "" );
04925         else if (args)
04926         {
04927             arg = LIST_ENTRY( list_head(args), const var_t, entry );
04928             fprintf( file, ",\n%*s&%s", len, "", arg->name );
04929         }
04930     }
04931     fprintf( file, " );\n" );
04932     if (has_ret)
04933     {
04934         print_file( file, 1, "return (" );
04935         write_type_decl_left(file, rettype);
04936         fprintf( file, ")%s;\n", pointer_size == 8 ? "_RetVal.Simple" : "*(LONG_PTR *)&_RetVal" );
04937     }
04938     print_file( file, 0, "}\n\n");
04939 }
04940 
04941 void write_exceptions( FILE *file )
04942 {
04943     fprintf( file, "#ifndef USE_COMPILER_EXCEPTIONS\n");
04944     fprintf( file, "\n");
04945     fprintf( file, "#include \"wine/exception.h\"\n");
04946     fprintf( file, "#undef RpcTryExcept\n");
04947     fprintf( file, "#undef RpcExcept\n");
04948     fprintf( file, "#undef RpcEndExcept\n");
04949     fprintf( file, "#undef RpcTryFinally\n");
04950     fprintf( file, "#undef RpcFinally\n");
04951     fprintf( file, "#undef RpcEndFinally\n");
04952     fprintf( file, "#undef RpcExceptionCode\n");
04953     fprintf( file, "#undef RpcAbnormalTermination\n");
04954     fprintf( file, "\n");
04955     fprintf( file, "struct __exception_frame;\n");
04956     fprintf( file, "typedef int (*__filter_func)(struct __exception_frame *);\n");
04957     fprintf( file, "typedef void (*__finally_func)(struct __exception_frame *);\n");
04958     fprintf( file, "\n");
04959     fprintf( file, "#define __DECL_EXCEPTION_FRAME \\\n");
04960     fprintf( file, "    EXCEPTION_REGISTRATION_RECORD frame; \\\n");
04961     fprintf( file, "    __filter_func                 filter; \\\n");
04962     fprintf( file, "    __finally_func                finally; \\\n");
04963     fprintf( file, "    sigjmp_buf                    jmp; \\\n");
04964     fprintf( file, "    DWORD                         code; \\\n");
04965     fprintf( file, "    unsigned char                 abnormal_termination; \\\n");
04966     fprintf( file, "    unsigned char                 filter_level; \\\n");
04967     fprintf( file, "    unsigned char                 finally_level;\n");
04968     fprintf( file, "\n");
04969     fprintf( file, "struct __exception_frame\n{\n");
04970     fprintf( file, "    __DECL_EXCEPTION_FRAME\n");
04971     fprintf( file, "};\n");
04972     fprintf( file, "\n");
04973     fprintf( file, "static inline void __widl_unwind_target(void)\n" );
04974     fprintf( file, "{\n");
04975     fprintf( file, "    struct __exception_frame *exc_frame = (struct __exception_frame *)__wine_get_frame();\n" );
04976     fprintf( file, "    if (exc_frame->finally_level > exc_frame->filter_level)\n" );
04977     fprintf( file, "    {\n");
04978     fprintf( file, "        exc_frame->abnormal_termination = 1;\n");
04979     fprintf( file, "        exc_frame->finally( exc_frame );\n");
04980     fprintf( file, "        __wine_pop_frame( &exc_frame->frame );\n");
04981     fprintf( file, "    }\n");
04982     fprintf( file, "    exc_frame->filter_level = 0;\n");
04983     fprintf( file, "    siglongjmp( exc_frame->jmp, 1 );\n");
04984     fprintf( file, "}\n");
04985     fprintf( file, "\n");
04986     fprintf( file, "static DWORD __widl_exception_handler( EXCEPTION_RECORD *record,\n");
04987     fprintf( file, "                                       EXCEPTION_REGISTRATION_RECORD *frame,\n");
04988     fprintf( file, "                                       CONTEXT *context,\n");
04989     fprintf( file, "                                       EXCEPTION_REGISTRATION_RECORD **pdispatcher )\n");
04990     fprintf( file, "{\n");
04991     fprintf( file, "    struct __exception_frame *exc_frame = (struct __exception_frame *)frame;\n");
04992     fprintf( file, "\n");
04993     fprintf( file, "    if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))\n");
04994     fprintf( file, "    {\n" );
04995     fprintf( file, "        if (exc_frame->finally_level && (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))\n");
04996     fprintf( file, "        {\n" );
04997     fprintf( file, "            exc_frame->abnormal_termination = 1;\n");
04998     fprintf( file, "            exc_frame->finally( exc_frame );\n");
04999     fprintf( file, "        }\n" );
05000     fprintf( file, "        return ExceptionContinueSearch;\n");
05001     fprintf( file, "    }\n" );
05002     fprintf( file, "    exc_frame->code = record->ExceptionCode;\n");
05003     fprintf( file, "    if (exc_frame->filter_level && exc_frame->filter( exc_frame ) == EXCEPTION_EXECUTE_HANDLER)\n" );
05004     fprintf( file, "        __wine_rtl_unwind( frame, record, __widl_unwind_target );\n");
05005     fprintf( file, "    return ExceptionContinueSearch;\n");
05006     fprintf( file, "}\n");
05007     fprintf( file, "\n");
05008     fprintf( file, "#define RpcTryExcept \\\n");
05009     fprintf( file, "    if (!sigsetjmp( __frame->jmp, 0 )) \\\n");
05010     fprintf( file, "    { \\\n");
05011     fprintf( file, "        if (!__frame->finally_level) \\\n" );
05012     fprintf( file, "            __wine_push_frame( &__frame->frame ); \\\n");
05013     fprintf( file, "        __frame->filter_level = __frame->finally_level + 1;\n" );
05014     fprintf( file, "\n");
05015     fprintf( file, "#define RpcExcept(expr) \\\n");
05016     fprintf( file, "        if (!__frame->finally_level) \\\n" );
05017     fprintf( file, "            __wine_pop_frame( &__frame->frame ); \\\n");
05018     fprintf( file, "        __frame->filter_level = 0; \\\n" );
05019     fprintf( file, "    } \\\n");
05020     fprintf( file, "    else \\\n");
05021     fprintf( file, "\n");
05022     fprintf( file, "#define RpcEndExcept\n");
05023     fprintf( file, "\n");
05024     fprintf( file, "#define RpcExceptionCode() (__frame->code)\n");
05025     fprintf( file, "\n");
05026     fprintf( file, "#define RpcTryFinally \\\n");
05027     fprintf( file, "    if (!__frame->filter_level) \\\n");
05028     fprintf( file, "        __wine_push_frame( &__frame->frame ); \\\n");
05029     fprintf( file, "    __frame->finally_level = __frame->filter_level + 1;\n");
05030     fprintf( file, "\n");
05031     fprintf( file, "#define RpcFinally \\\n");
05032     fprintf( file, "    if (!__frame->filter_level) \\\n");
05033     fprintf( file, "        __wine_pop_frame( &__frame->frame ); \\\n");
05034     fprintf( file, "    __frame->finally_level = 0;\n");
05035     fprintf( file, "\n");
05036     fprintf( file, "#define RpcEndFinally\n");
05037     fprintf( file, "\n");
05038     fprintf( file, "#define RpcAbnormalTermination() (__frame->abnormal_termination)\n");
05039     fprintf( file, "\n");
05040     fprintf( file, "#define RpcExceptionInit(filter_func,finally_func) \\\n");
05041     fprintf( file, "    do { \\\n");
05042     fprintf( file, "        __frame->frame.Handler = __widl_exception_handler; \\\n");
05043     fprintf( file, "        __frame->filter = (__filter_func)(filter_func); \\\n" );
05044     fprintf( file, "        __frame->finally = (__finally_func)(finally_func); \\\n");
05045     fprintf( file, "        __frame->abnormal_termination = 0; \\\n");
05046     fprintf( file, "        __frame->filter_level = 0; \\\n");
05047     fprintf( file, "        __frame->finally_level = 0; \\\n");
05048     fprintf( file, "    } while (0)\n");
05049     fprintf( file, "\n");
05050     fprintf( file, "#else /* USE_COMPILER_EXCEPTIONS */\n");
05051     fprintf( file, "\n");
05052     fprintf( file, "#define RpcExceptionInit(filter_func,finally_func) \\\n");
05053     fprintf( file, "    do { (void)(filter_func); } while(0)\n");
05054     fprintf( file, "\n");
05055     fprintf( file, "#define __DECL_EXCEPTION_FRAME \\\n");
05056     fprintf( file, "    DWORD code;\n");
05057     fprintf( file, "\n");
05058     fprintf( file, "#endif /* USE_COMPILER_EXCEPTIONS */\n");
05059 }

Generated on Sun May 27 2012 04:37:52 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.