| /* |
| * Format String Generator for IDL Compiler |
| * |
| * Copyright 2005-2006 Eric Kohl |
| * Copyright 2005-2006 Robert Shearman |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #ifdef HAVE_UNISTD_H |
| # include <unistd.h> |
| #endif |
| #include <string.h> |
| #include <assert.h> |
| #include <ctype.h> |
| #include <limits.h> |
| |
| #include "widl.h" |
| #include "utils.h" |
| #include "parser.h" |
| #include "header.h" |
| #include "wine/list.h" |
| |
| #include "typegen.h" |
| |
| static const func_t *current_func; |
| static const type_t *current_structure; |
| static const ifref_t *current_iface; |
| |
| static struct list expr_eval_routines = LIST_INIT(expr_eval_routines); |
| struct expr_eval_routine |
| { |
| struct list entry; |
| const type_t *structure; |
| unsigned int baseoff; |
| const expr_t *expr; |
| }; |
| |
| static size_t fields_memsize(const var_list_t *fields, unsigned int *align); |
| static size_t write_struct_tfs(FILE *file, type_t *type, const char *name, unsigned int *tfsoff); |
| static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type, |
| const char *name, int write_ptr, unsigned int *tfsoff); |
| static const var_t *find_array_or_string_in_struct(const type_t *type); |
| |
| const char *string_of_type(unsigned char type) |
| { |
| switch (type) |
| { |
| case RPC_FC_BYTE: return "FC_BYTE"; |
| case RPC_FC_CHAR: return "FC_CHAR"; |
| case RPC_FC_SMALL: return "FC_SMALL"; |
| case RPC_FC_USMALL: return "FC_USMALL"; |
| case RPC_FC_WCHAR: return "FC_WCHAR"; |
| case RPC_FC_SHORT: return "FC_SHORT"; |
| case RPC_FC_USHORT: return "FC_USHORT"; |
| case RPC_FC_LONG: return "FC_LONG"; |
| case RPC_FC_ULONG: return "FC_ULONG"; |
| case RPC_FC_FLOAT: return "FC_FLOAT"; |
| case RPC_FC_HYPER: return "FC_HYPER"; |
| case RPC_FC_DOUBLE: return "FC_DOUBLE"; |
| case RPC_FC_ENUM16: return "FC_ENUM16"; |
| case RPC_FC_ENUM32: return "FC_ENUM32"; |
| case RPC_FC_IGNORE: return "FC_IGNORE"; |
| case RPC_FC_ERROR_STATUS_T: return "FC_ERROR_STATUS_T"; |
| case RPC_FC_RP: return "FC_RP"; |
| case RPC_FC_UP: return "FC_UP"; |
| case RPC_FC_OP: return "FC_OP"; |
| case RPC_FC_FP: return "FC_FP"; |
| case RPC_FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION"; |
| case RPC_FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION"; |
| case RPC_FC_STRUCT: return "FC_STRUCT"; |
| case RPC_FC_PSTRUCT: return "FC_PSTRUCT"; |
| case RPC_FC_CSTRUCT: return "FC_CSTRUCT"; |
| case RPC_FC_CPSTRUCT: return "FC_CPSTRUCT"; |
| case RPC_FC_CVSTRUCT: return "FC_CVSTRUCT"; |
| case RPC_FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT"; |
| case RPC_FC_SMFARRAY: return "FC_SMFARRAY"; |
| case RPC_FC_LGFARRAY: return "FC_LGFARRAY"; |
| case RPC_FC_SMVARRAY: return "FC_SMVARRAY"; |
| case RPC_FC_LGVARRAY: return "FC_LGVARRAY"; |
| case RPC_FC_CARRAY: return "FC_CARRAY"; |
| case RPC_FC_CVARRAY: return "FC_CVARRAY"; |
| case RPC_FC_BOGUS_ARRAY: return "FC_BOGUS_ARRAY"; |
| case RPC_FC_ALIGNM4: return "FC_ALIGNM4"; |
| case RPC_FC_ALIGNM8: return "FC_ALIGNM8"; |
| case RPC_FC_POINTER: return "FC_POINTER"; |
| case RPC_FC_C_CSTRING: return "FC_C_CSTRING"; |
| case RPC_FC_C_WSTRING: return "FC_C_WSTRING"; |
| case RPC_FC_CSTRING: return "FC_CSTRING"; |
| case RPC_FC_WSTRING: return "FC_WSTRING"; |
| default: |
| error("string_of_type: unknown type 0x%02x\n", type); |
| return NULL; |
| } |
| } |
| |
| int is_struct(unsigned char type) |
| { |
| switch (type) |
| { |
| case RPC_FC_STRUCT: |
| case RPC_FC_PSTRUCT: |
| case RPC_FC_CSTRUCT: |
| case RPC_FC_CPSTRUCT: |
| case RPC_FC_CVSTRUCT: |
| case RPC_FC_BOGUS_STRUCT: |
| return 1; |
| default: |
| return 0; |
| } |
| } |
| |
| static int is_non_complex_struct(const type_t *type) |
| { |
| switch (type->type) |
| { |
| case RPC_FC_STRUCT: |
| case RPC_FC_PSTRUCT: |
| case RPC_FC_CSTRUCT: |
| case RPC_FC_CPSTRUCT: |
| case RPC_FC_CVSTRUCT: |
| return 1; |
| default: |
| return 0; |
| } |
| } |
| |
| int is_union(unsigned char type) |
| { |
| switch (type) |
| { |
| case RPC_FC_ENCAPSULATED_UNION: |
| case RPC_FC_NON_ENCAPSULATED_UNION: |
| return 1; |
| default: |
| return 0; |
| } |
| } |
| |
| static int type_has_pointers(const type_t *type) |
| { |
| if (is_user_type(type)) |
| return FALSE; |
| else if (is_ptr(type)) |
| return TRUE; |
| else if (is_array(type)) |
| return type_has_pointers(type->ref); |
| else if (is_struct(type->type)) |
| { |
| const var_t *field; |
| if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry ) |
| { |
| if (type_has_pointers(field->type)) |
| return TRUE; |
| } |
| } |
| else if (is_union(type->type)) |
| { |
| var_list_t *fields; |
| const var_t *field; |
| if (type->type == RPC_FC_ENCAPSULATED_UNION) |
| { |
| const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry); |
| fields = uv->type->fields; |
| } |
| else |
| fields = type->fields; |
| if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry ) |
| { |
| if (field->type && type_has_pointers(field->type)) |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| static int type_has_full_pointer(const type_t *type) |
| { |
| if (is_user_type(type)) |
| return FALSE; |
| else if (type->type == RPC_FC_FP) |
| return TRUE; |
| else if (is_ptr(type)) |
| return FALSE; |
| else if (is_array(type)) |
| return type_has_full_pointer(type->ref); |
| else if (is_struct(type->type)) |
| { |
| const var_t *field; |
| if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry ) |
| { |
| if (type_has_full_pointer(field->type)) |
| return TRUE; |
| } |
| } |
| else if (is_union(type->type)) |
| { |
| var_list_t *fields; |
| const var_t *field; |
| if (type->type == RPC_FC_ENCAPSULATED_UNION) |
| { |
| const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry); |
| fields = uv->type->fields; |
| } |
| else |
| fields = type->fields; |
| if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry ) |
| { |
| if (field->type && type_has_full_pointer(field->type)) |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| static unsigned short user_type_offset(const char *name) |
| { |
| user_type_t *ut; |
| unsigned short off = 0; |
| LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry) |
| { |
| if (strcmp(name, ut->name) == 0) |
| return off; |
| ++off; |
| } |
| error("user_type_offset: couldn't find type (%s)\n", name); |
| return 0; |
| } |
| |
| static void update_tfsoff(type_t *type, unsigned int offset, FILE *file) |
| { |
| type->typestring_offset = offset; |
| if (file) type->tfswrite = FALSE; |
| } |
| |
| static void guard_rec(type_t *type) |
| { |
| /* types that contain references to themselves (like a linked list), |
| need to be shielded from infinite recursion when writing embedded |
| types */ |
| if (type->typestring_offset) |
| type->tfswrite = FALSE; |
| else |
| type->typestring_offset = 1; |
| } |
| |
| static type_t *get_user_type(const type_t *t, const char **pname) |
| { |
| for (;;) |
| { |
| type_t *ut = get_attrp(t->attrs, ATTR_WIREMARSHAL); |
| if (ut) |
| { |
| if (pname) |
| *pname = t->name; |
| return ut; |
| } |
| |
| if (t->kind == TKIND_ALIAS) |
| t = t->orig; |
| else |
| return 0; |
| } |
| } |
| |
| int is_user_type(const type_t *t) |
| { |
| return get_user_type(t, NULL) != NULL; |
| } |
| |
| static int is_embedded_complex(const type_t *type) |
| { |
| unsigned char tc = type->type; |
| return is_struct(tc) || is_union(tc) || is_array(type) || is_user_type(type) |
| || (is_ptr(type) && type->ref->type == RPC_FC_IP); |
| } |
| |
| static const char *get_context_handle_type_name(const type_t *type) |
| { |
| const type_t *t; |
| for (t = type; is_ptr(t); t = t->ref) |
| if (is_attr(t->attrs, ATTR_CONTEXTHANDLE)) |
| return t->name; |
| assert(0); |
| return NULL; |
| } |
| |
| /* This is actually fairly involved to implement precisely, due to the |
| effects attributes may have and things like that. Right now this is |
| only used for optimization, so just check for a very small set of |
| criteria that guarantee the types are equivalent; assume every thing |
| else is different. */ |
| static int compare_type(const type_t *a, const type_t *b) |
| { |
| if (a == b |
| || (a->name |
| && b->name |
| && strcmp(a->name, b->name) == 0)) |
| return 0; |
| /* Ordering doesn't need to be implemented yet. */ |
| return 1; |
| } |
| |
| static int compare_expr(const expr_t *a, const expr_t *b) |
| { |
| int ret; |
| |
| if (a->type != b->type) |
| return a->type - b->type; |
| |
| switch (a->type) |
| { |
| case EXPR_NUM: |
| case EXPR_HEXNUM: |
| case EXPR_TRUEFALSE: |
| return a->u.lval - b->u.lval; |
| case EXPR_DOUBLE: |
| return a->u.dval - b->u.dval; |
| case EXPR_IDENTIFIER: |
| return strcmp(a->u.sval, b->u.sval); |
| case EXPR_COND: |
| ret = compare_expr(a->ref, b->ref); |
| if (ret != 0) |
| return ret; |
| ret = compare_expr(a->u.ext, b->u.ext); |
| if (ret != 0) |
| return ret; |
| return compare_expr(a->ext2, b->ext2); |
| case EXPR_OR: |
| case EXPR_AND: |
| case EXPR_ADD: |
| case EXPR_SUB: |
| case EXPR_MUL: |
| case EXPR_DIV: |
| case EXPR_SHL: |
| case EXPR_SHR: |
| ret = compare_expr(a->ref, b->ref); |
| if (ret != 0) |
| return ret; |
| return compare_expr(a->u.ext, b->u.ext); |
| case EXPR_CAST: |
| ret = compare_type(a->u.tref, b->u.tref); |
| if (ret != 0) |
| return ret; |
| /* Fall through. */ |
| case EXPR_NOT: |
| case EXPR_NEG: |
| case EXPR_PPTR: |
| case EXPR_ADDRESSOF: |
| return compare_expr(a->ref, b->ref); |
| case EXPR_SIZEOF: |
| return compare_type(a->u.tref, b->u.tref); |
| case EXPR_VOID: |
| return 0; |
| } |
| return -1; |
| } |
| |
| #define WRITE_FCTYPE(file, fctype, typestring_offset) \ |
| do { \ |
| if (file) \ |
| fprintf(file, "/* %2u */\n", typestring_offset); \ |
| print_file((file), 2, "0x%02x, /* " #fctype " */\n", RPC_##fctype); \ |
| } \ |
| while (0) |
| |
| static void print_file(FILE *file, int indent, const char *format, ...) |
| { |
| va_list va; |
| va_start(va, format); |
| print(file, indent, format, va); |
| va_end(va); |
| } |
| |
| void print(FILE *file, int indent, const char *format, va_list va) |
| { |
| if (file) |
| { |
| if (format[0] != '\n') |
| while (0 < indent--) |
| fprintf(file, " "); |
| vfprintf(file, format, va); |
| } |
| } |
| |
| |
| static void write_var_init(FILE *file, int indent, const type_t *t, const char *n) |
| { |
| if (decl_indirect(t)) |
| print_file(file, indent, "MIDL_memset(&%s, 0, sizeof(%s));\n", n, n); |
| else if (is_ptr(t) || is_array(t)) |
| print_file(file, indent, "%s = 0;\n", n); |
| } |
| |
| void write_parameters_init(FILE *file, int indent, const func_t *func) |
| { |
| const var_t *var; |
| |
| if (!is_void(func->def->type)) |
| write_var_init(file, indent, func->def->type, "_RetVal"); |
| |
| if (!func->args) |
| return; |
| |
| LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) |
| write_var_init(file, indent, var->type, var->name); |
| |
| fprintf(file, "\n"); |
| } |
| |
| static void write_formatdesc(FILE *f, int indent, const char *str) |
| { |
| print_file(f, indent, "typedef struct _MIDL_%s_FORMAT_STRING\n", str); |
| print_file(f, indent, "{\n"); |
| print_file(f, indent + 1, "short Pad;\n"); |
| print_file(f, indent + 1, "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str); |
| print_file(f, indent, "} MIDL_%s_FORMAT_STRING;\n", str); |
| print_file(f, indent, "\n"); |
| } |
| |
| void write_formatstringsdecl(FILE *f, int indent, ifref_list_t *ifaces, type_pred_t pred) |
| { |
| print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n", |
| get_size_typeformatstring(ifaces, pred)); |
| |
| print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n", |
| get_size_procformatstring(ifaces, pred)); |
| |
| fprintf(f, "\n"); |
| write_formatdesc(f, indent, "TYPE"); |
| write_formatdesc(f, indent, "PROC"); |
| fprintf(f, "\n"); |
| print_file(f, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n"); |
| print_file(f, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n"); |
| print_file(f, indent, "\n"); |
| } |
| |
| static inline int is_base_type(unsigned char type) |
| { |
| switch (type) |
| { |
| case RPC_FC_BYTE: |
| case RPC_FC_CHAR: |
| case RPC_FC_USMALL: |
| case RPC_FC_SMALL: |
| case RPC_FC_WCHAR: |
| case RPC_FC_USHORT: |
| case RPC_FC_SHORT: |
| case RPC_FC_ULONG: |
| case RPC_FC_LONG: |
| case RPC_FC_HYPER: |
| case RPC_FC_IGNORE: |
| case RPC_FC_FLOAT: |
| case RPC_FC_DOUBLE: |
| case RPC_FC_ENUM16: |
| case RPC_FC_ENUM32: |
| case RPC_FC_ERROR_STATUS_T: |
| case RPC_FC_BIND_PRIMITIVE: |
| return TRUE; |
| |
| default: |
| return FALSE; |
| } |
| } |
| |
| int decl_indirect(const type_t *t) |
| { |
| return is_user_type(t) |
| || (!is_base_type(t->type) |
| && !is_ptr(t) |
| && !is_array(t)); |
| } |
| |
| static size_t write_procformatstring_var(FILE *file, int indent, |
| const var_t *var, int is_return) |
| { |
| size_t size; |
| const type_t *type = var->type; |
| |
| int is_in = is_attr(var->attrs, ATTR_IN); |
| int is_out = is_attr(var->attrs, ATTR_OUT); |
| |
| if (!is_in && !is_out) is_in = TRUE; |
| |
| if (!type->declarray && is_base_type(type->type)) |
| { |
| if (is_return) |
| print_file(file, indent, "0x53, /* FC_RETURN_PARAM_BASETYPE */\n"); |
| else |
| print_file(file, indent, "0x4e, /* FC_IN_PARAM_BASETYPE */\n"); |
| |
| if (type->type == RPC_FC_BIND_PRIMITIVE) |
| { |
| print_file(file, indent, "0x%02x, /* FC_IGNORE */\n", RPC_FC_IGNORE); |
| size = 2; /* includes param type prefix */ |
| } |
| else if (is_base_type(type->type)) |
| { |
| print_file(file, indent, "0x%02x, /* %s */\n", type->type, string_of_type(type->type)); |
| size = 2; /* includes param type prefix */ |
| } |
| else |
| { |
| error("Unknown/unsupported type: %s (0x%02x)\n", var->name, type->type); |
| size = 0; |
| } |
| } |
| else |
| { |
| if (is_return) |
| print_file(file, indent, "0x52, /* FC_RETURN_PARAM */\n"); |
| else if (is_in && is_out) |
| print_file(file, indent, "0x50, /* FC_IN_OUT_PARAM */\n"); |
| else if (is_out) |
| print_file(file, indent, "0x51, /* FC_OUT_PARAM */\n"); |
| else |
| print_file(file, indent, "0x4d, /* FC_IN_PARAM */\n"); |
| |
| print_file(file, indent, "0x01,\n"); |
| print_file(file, indent, "NdrFcShort(0x%x),\n", type->typestring_offset); |
| size = 4; /* includes param type prefix */ |
| } |
| return size; |
| } |
| |
| void write_procformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred) |
| { |
| const ifref_t *iface; |
| int indent = 0; |
| const var_t *var; |
| |
| print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n"); |
| print_file(file, indent, "{\n"); |
| indent++; |
| print_file(file, indent, "0,\n"); |
| print_file(file, indent, "{\n"); |
| indent++; |
| |
| if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry ) |
| { |
| if (!pred(iface->iface)) |
| continue; |
| |
| if (iface->iface->funcs) |
| { |
| const func_t *func; |
| LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry ) |
| { |
| if (is_local(func->def->attrs)) continue; |
| /* emit argument data */ |
| if (func->args) |
| { |
| LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) |
| write_procformatstring_var(file, indent, var, FALSE); |
| } |
| |
| /* emit return value data */ |
| var = func->def; |
| if (is_void(var->type)) |
| { |
| print_file(file, indent, "0x5b, /* FC_END */\n"); |
| print_file(file, indent, "0x5c, /* FC_PAD */\n"); |
| } |
| else |
| write_procformatstring_var(file, indent, var, TRUE); |
| } |
| } |
| } |
| |
| print_file(file, indent, "0x0\n"); |
| indent--; |
| print_file(file, indent, "}\n"); |
| indent--; |
| print_file(file, indent, "};\n"); |
| print_file(file, indent, "\n"); |
| } |
| |
| static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset) |
| { |
| if (is_base_type(type->type)) |
| { |
| print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type)); |
| *typestring_offset += 1; |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* write conformance / variance descriptor */ |
| static size_t write_conf_or_var_desc(FILE *file, const type_t *structure, |
| unsigned int baseoff, const type_t *type, |
| const expr_t *expr) |
| { |
| unsigned char operator_type = 0; |
| unsigned char conftype = RPC_FC_NORMAL_CONFORMANCE; |
| const char *conftype_string = ""; |
| const char *operator_string = "no operators"; |
| const expr_t *subexpr; |
| |
| if (!expr) |
| { |
| print_file(file, 2, "NdrFcLong(0xffffffff),\t/* -1 */\n"); |
| return 4; |
| } |
| |
| if (!structure) |
| { |
| /* Top-level conformance calculations are done inline. */ |
| print_file (file, 2, "0x%x,\t/* Corr desc: parameter */\n", |
| RPC_FC_TOP_LEVEL_CONFORMANCE); |
| print_file (file, 2, "0x0,\n"); |
| print_file (file, 2, "NdrFcShort(0x0),\n"); |
| return 4; |
| } |
| |
| if (expr->is_const) |
| { |
| if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX) |
| error("write_conf_or_var_desc: constant value %ld is greater than " |
| "the maximum constant size of %d\n", expr->cval, |
| UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX); |
| |
| print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n", |
| RPC_FC_CONSTANT_CONFORMANCE, expr->cval); |
| print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX); |
| print_file(file, 2, "NdrFcShort(0x%x),\n", expr->cval & USHRT_MAX); |
| |
| return 4; |
| } |
| |
| if (is_ptr(type) || (is_array(type) && !type->declarray)) |
| { |
| conftype = RPC_FC_POINTER_CONFORMANCE; |
| conftype_string = "field pointer, "; |
| } |
| |
| subexpr = expr; |
| switch (subexpr->type) |
| { |
| case EXPR_PPTR: |
| subexpr = subexpr->ref; |
| operator_type = RPC_FC_DEREFERENCE; |
| operator_string = "FC_DEREFERENCE"; |
| break; |
| case EXPR_DIV: |
| if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2)) |
| { |
| subexpr = subexpr->ref; |
| operator_type = RPC_FC_DIV_2; |
| operator_string = "FC_DIV_2"; |
| } |
| break; |
| case EXPR_MUL: |
| if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2)) |
| { |
| subexpr = subexpr->ref; |
| operator_type = RPC_FC_MULT_2; |
| operator_string = "FC_MULT_2"; |
| } |
| break; |
| case EXPR_SUB: |
| if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1)) |
| { |
| subexpr = subexpr->ref; |
| operator_type = RPC_FC_SUB_1; |
| operator_string = "FC_SUB_1"; |
| } |
| break; |
| case EXPR_ADD: |
| if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1)) |
| { |
| subexpr = subexpr->ref; |
| operator_type = RPC_FC_ADD_1; |
| operator_string = "FC_ADD_1"; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| if (subexpr->type == EXPR_IDENTIFIER) |
| { |
| const type_t *correlation_variable = NULL; |
| unsigned char correlation_variable_type; |
| unsigned char param_type = 0; |
| size_t offset = 0; |
| const var_t *var; |
| |
| if (structure->fields) LIST_FOR_EACH_ENTRY( var, structure->fields, const var_t, entry ) |
| { |
| unsigned int align = 0; |
| /* FIXME: take alignment into account */ |
| if (var->name && !strcmp(var->name, subexpr->u.sval)) |
| { |
| correlation_variable = var->type; |
| break; |
| } |
| offset += type_memsize(var->type, &align); |
| } |
| if (!correlation_variable) |
| error("write_conf_or_var_desc: couldn't find variable %s in structure\n", |
| subexpr->u.sval); |
| |
| offset -= baseoff; |
| correlation_variable_type = correlation_variable->type; |
| |
| switch (correlation_variable_type) |
| { |
| case RPC_FC_CHAR: |
| case RPC_FC_SMALL: |
| param_type = RPC_FC_SMALL; |
| break; |
| case RPC_FC_BYTE: |
| case RPC_FC_USMALL: |
| param_type = RPC_FC_USMALL; |
| break; |
| case RPC_FC_WCHAR: |
| case RPC_FC_SHORT: |
| case RPC_FC_ENUM16: |
| param_type = RPC_FC_SHORT; |
| break; |
| case RPC_FC_USHORT: |
| param_type = RPC_FC_USHORT; |
| break; |
| case RPC_FC_LONG: |
| case RPC_FC_ENUM32: |
| param_type = RPC_FC_LONG; |
| break; |
| case RPC_FC_ULONG: |
| param_type = RPC_FC_ULONG; |
| break; |
| case RPC_FC_RP: |
| case RPC_FC_UP: |
| case RPC_FC_OP: |
| case RPC_FC_FP: |
| if (sizeof(void *) == 4) /* FIXME */ |
| param_type = RPC_FC_LONG; |
| else |
| param_type = RPC_FC_HYPER; |
| break; |
| default: |
| error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n", |
| correlation_variable_type); |
| } |
| |
| print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n", |
| conftype | param_type, conftype_string, string_of_type(param_type)); |
| print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string); |
| print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d */\n", |
| offset, offset); |
| } |
| else |
| { |
| unsigned int callback_offset = 0; |
| struct expr_eval_routine *eval; |
| int found = 0; |
| |
| LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry) |
| { |
| if (!strcmp (eval->structure->name, structure->name) |
| && !compare_expr (eval->expr, expr)) |
| { |
| found = 1; |
| break; |
| } |
| callback_offset++; |
| } |
| |
| if (!found) |
| { |
| eval = xmalloc (sizeof(*eval)); |
| eval->structure = structure; |
| eval->baseoff = baseoff; |
| eval->expr = expr; |
| list_add_tail (&expr_eval_routines, &eval->entry); |
| } |
| |
| if (callback_offset > USHRT_MAX) |
| error("Maximum number of callback routines reached\n"); |
| |
| print_file(file, 2, "0x%x, /* Corr desc: %s */\n", conftype, conftype_string); |
| print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK"); |
| print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", callback_offset, callback_offset); |
| } |
| return 4; |
| } |
| |
| static size_t fields_memsize(const var_list_t *fields, unsigned int *align) |
| { |
| int have_align = FALSE; |
| size_t size = 0; |
| const var_t *v; |
| |
| if (!fields) return 0; |
| LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry ) |
| { |
| unsigned int falign = 0; |
| size_t fsize = type_memsize(v->type, &falign); |
| if (!have_align) |
| { |
| *align = falign; |
| have_align = TRUE; |
| } |
| size = (size + (falign - 1)) & ~(falign - 1); |
| size += fsize; |
| } |
| |
| size = (size + (*align - 1)) & ~(*align - 1); |
| return size; |
| } |
| |
| static size_t union_memsize(const var_list_t *fields, unsigned int *pmaxa) |
| { |
| size_t size, maxs = 0; |
| unsigned int align = *pmaxa; |
| const var_t *v; |
| |
| if (fields) LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry ) |
| { |
| /* we could have an empty default field with NULL type */ |
| if (v->type) |
| { |
| size = type_memsize(v->type, &align); |
| if (maxs < size) maxs = size; |
| if (*pmaxa < align) *pmaxa = align; |
| } |
| } |
| |
| return maxs; |
| } |
| |
| int get_padding(const var_list_t *fields) |
| { |
| unsigned short offset = 0; |
| int salign = -1; |
| const var_t *f; |
| |
| if (!fields) |
| return 0; |
| |
| LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry) |
| { |
| type_t *ft = f->type; |
| unsigned int align = 0; |
| size_t size = type_memsize(ft, &align); |
| if (salign == -1) |
| salign = align; |
| offset = (offset + (align - 1)) & ~(align - 1); |
| offset += size; |
| } |
| |
| return ((offset + (salign - 1)) & ~(salign - 1)) - offset; |
| } |
| |
| size_t type_memsize(const type_t *t, unsigned int *align) |
| { |
| size_t size = 0; |
| |
| if (t->declarray && is_conformant_array(t)) |
| { |
| type_memsize(t->ref, align); |
| size = 0; |
| } |
| else if (is_ptr(t) || is_conformant_array(t)) |
| { |
| size = sizeof(void *); |
| if (size > *align) *align = size; |
| } |
| else switch (t->type) |
| { |
| case RPC_FC_BYTE: |
| case RPC_FC_CHAR: |
| case RPC_FC_USMALL: |
| case RPC_FC_SMALL: |
| size = 1; |
| if (size > *align) *align = size; |
| break; |
| case RPC_FC_WCHAR: |
| case RPC_FC_USHORT: |
| case RPC_FC_SHORT: |
| case RPC_FC_ENUM16: |
| size = 2; |
| if (size > *align) *align = size; |
| break; |
| case RPC_FC_ULONG: |
| case RPC_FC_LONG: |
| case RPC_FC_ERROR_STATUS_T: |
| case RPC_FC_ENUM32: |
| case RPC_FC_FLOAT: |
| size = 4; |
| if (size > *align) *align = size; |
| break; |
| case RPC_FC_HYPER: |
| case RPC_FC_DOUBLE: |
| size = 8; |
| if (size > *align) *align = size; |
| break; |
| case RPC_FC_STRUCT: |
| case RPC_FC_CVSTRUCT: |
| case RPC_FC_CPSTRUCT: |
| case RPC_FC_CSTRUCT: |
| case RPC_FC_PSTRUCT: |
| case RPC_FC_BOGUS_STRUCT: |
| size = fields_memsize(t->fields, align); |
| break; |
| case RPC_FC_ENCAPSULATED_UNION: |
| case RPC_FC_NON_ENCAPSULATED_UNION: |
| size = union_memsize(t->fields, align); |
| break; |
| case RPC_FC_SMFARRAY: |
| case RPC_FC_LGFARRAY: |
| case RPC_FC_SMVARRAY: |
| case RPC_FC_LGVARRAY: |
| case RPC_FC_BOGUS_ARRAY: |
| size = t->dim * type_memsize(t->ref, align); |
| break; |
| default: |
| error("type_memsize: Unknown type %d\n", t->type); |
| size = 0; |
| } |
| |
| return size; |
| } |
| |
| int is_full_pointer_function(const func_t *func) |
| { |
| const var_t *var; |
| if (type_has_full_pointer(func->def->type)) |
| return TRUE; |
| if (!func->args) |
| return FALSE; |
| LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) |
| if (type_has_full_pointer( var->type )) |
| return TRUE; |
| return FALSE; |
| } |
| |
| void write_full_pointer_init(FILE *file, int indent, const func_t *func, int is_server) |
| { |
| print_file(file, indent, "_StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,%s);\n", |
| is_server ? "XLAT_SERVER" : "XLAT_CLIENT"); |
| fprintf(file, "\n"); |
| } |
| |
| void write_full_pointer_free(FILE *file, int indent, const func_t *func) |
| { |
| print_file(file, indent, "NdrFullPointerXlatFree(_StubMsg.FullPtrXlatTables);\n"); |
| fprintf(file, "\n"); |
| } |
| |
| static unsigned int write_nonsimple_pointer(FILE *file, const type_t *type, size_t offset) |
| { |
| short absoff = type->ref->typestring_offset; |
| short reloff = absoff - (offset + 2); |
| int ptr_attr = is_ptr(type->ref) ? 0x10 : 0x0; |
| |
| print_file(file, 2, "0x%02x, 0x%x,\t/* %s */\n", |
| type->type, ptr_attr, string_of_type(type->type)); |
| print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%hd) */\n", |
| reloff, reloff, absoff); |
| return 4; |
| } |
| |
| static unsigned char conf_string_type_of_char_type(unsigned char t) |
| { |
| switch (t) |
| { |
| case RPC_FC_BYTE: |
| case RPC_FC_CHAR: |
| return RPC_FC_C_CSTRING; |
| case RPC_FC_WCHAR: |
| return RPC_FC_C_WSTRING; |
| } |
| |
| error("string_type_of_char_type: unrecognized type %d\n", t); |
| return 0; |
| } |
| |
| static unsigned int write_simple_pointer(FILE *file, const type_t *type) |
| { |
| unsigned char fc |
| = is_string_type(type->attrs, type) |
| ? conf_string_type_of_char_type(type->ref->type) |
| : type->ref->type; |
| print_file(file, 2, "0x%02x, 0x8,\t/* %s [simple_pointer] */\n", |
| type->type, string_of_type(type->type)); |
| print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc)); |
| print_file(file, 2, "0x5c,\t/* FC_PAD */\n"); |
| return 4; |
| } |
| |
| static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff) |
| { |
| print_file(file, 0, "/* %u (", tfsoff); |
| write_type_decl(file, t, NULL); |
| print_file(file, 0, ") */\n"); |
| } |
| |
| static size_t write_pointer_tfs(FILE *file, type_t *type, unsigned int *typestring_offset) |
| { |
| unsigned int offset = *typestring_offset; |
| |
| print_start_tfs_comment(file, type, offset); |
| update_tfsoff(type, offset, file); |
| |
| if (type->ref->typestring_offset) |
| *typestring_offset += write_nonsimple_pointer(file, type, offset); |
| else if (is_base_type(type->ref->type)) |
| *typestring_offset += write_simple_pointer(file, type); |
| |
| return offset; |
| } |
| |
| static int processed(const type_t *type) |
| { |
| return type->typestring_offset && !type->tfswrite; |
| } |
| |
| static int user_type_has_variable_size(const type_t *t) |
| { |
| if (is_ptr(t)) |
| return TRUE; |
| else |
| switch (t->type) |
| { |
| case RPC_FC_PSTRUCT: |
| case RPC_FC_CSTRUCT: |
| case RPC_FC_CPSTRUCT: |
| case RPC_FC_CVSTRUCT: |
| return TRUE; |
| } |
| /* Note: Since this only applies to user types, we can't have a conformant |
| array here, and strings should get filed under pointer in this case. */ |
| return FALSE; |
| } |
| |
| static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff) |
| { |
| unsigned int start, absoff, flags; |
| unsigned int align = 0, ualign = 0; |
| const char *name; |
| type_t *utype = get_user_type(type, &name); |
| size_t usize = user_type_has_variable_size(utype) ? 0 : type_memsize(utype, &ualign); |
| size_t size = type_memsize(type, &align); |
| unsigned short funoff = user_type_offset(name); |
| short reloff; |
| |
| guard_rec(type); |
| |
| if (is_base_type(utype->type)) |
| { |
| absoff = *tfsoff; |
| print_start_tfs_comment(file, utype, absoff); |
| print_file(file, 2, "0x%x,\t/* %s */\n", utype->type, string_of_type(utype->type)); |
| print_file(file, 2, "0x5c,\t/* FC_PAD */\n"); |
| *tfsoff += 2; |
| } |
| else |
| { |
| if (!processed(utype)) |
| write_embedded_types(file, NULL, utype, utype->name, TRUE, tfsoff); |
| absoff = utype->typestring_offset; |
| } |
| |
| if (utype->type == RPC_FC_RP) |
| flags = 0x40; |
| else if (utype->type == RPC_FC_UP) |
| flags = 0x80; |
| else |
| flags = 0; |
| |
| start = *tfsoff; |
| update_tfsoff(type, start, file); |
| print_start_tfs_comment(file, type, start); |
| print_file(file, 2, "0x%x,\t/* FC_USER_MARSHAL */\n", RPC_FC_USER_MARSHAL); |
| print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n", |
| flags | (align - 1), align - 1, flags); |
| print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff); |
| print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", size, size); |
| print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize); |
| *tfsoff += 8; |
| reloff = absoff - *tfsoff; |
| print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", reloff, reloff, absoff); |
| *tfsoff += 2; |
| } |
| |
| static void write_member_type(FILE *file, const type_t *cont, |
| const attr_list_t *attrs, const type_t *type, |
| unsigned int *corroff, unsigned int *tfsoff) |
| { |
| if (is_embedded_complex(type) && !is_conformant_array(type)) |
| { |
| size_t absoff; |
| short reloff; |
| |
| if (is_union(type->type) && is_attr(attrs, ATTR_SWITCHIS)) |
| { |
| absoff = *corroff; |
| *corroff += 8; |
| } |
| else |
| { |
| absoff = type->typestring_offset; |
| } |
| reloff = absoff - (*tfsoff + 2); |
| |
| print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n"); |
| /* FIXME: actually compute necessary padding */ |
| print_file(file, 2, "0x0,\t/* FIXME: padding */\n"); |
| print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", |
| reloff, reloff, absoff); |
| *tfsoff += 4; |
| } |
| else if (is_ptr(type) || is_conformant_array(type)) |
| { |
| unsigned char fc = (cont->type == RPC_FC_BOGUS_STRUCT |
| ? RPC_FC_POINTER |
| : RPC_FC_LONG); |
| print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc)); |
| *tfsoff += 1; |
| } |
| else if (!write_base_type(file, type, tfsoff)) |
| error("Unsupported member type 0x%x\n", type->type); |
| } |
| |
| static void write_end(FILE *file, unsigned int *tfsoff) |
| { |
| if (*tfsoff % 2 == 0) |
| { |
| print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD); |
| *tfsoff += 1; |
| } |
| print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END); |
| *tfsoff += 1; |
| } |
| |
| static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff) |
| { |
| unsigned int offset = 0; |
| var_list_t *fs = type->fields; |
| var_t *f; |
| |
| if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry) |
| { |
| unsigned int align = 0; |
| type_t *ft = f->type; |
| if (is_union(ft->type) && is_attr(f->attrs, ATTR_SWITCHIS)) |
| { |
| unsigned int absoff = ft->typestring_offset; |
| short reloff = absoff - (*tfsoff + 6); |
| print_file(file, 0, "/* %d */\n", *tfsoff); |
| print_file(file, 2, "0x%x,\t/* %s */\n", ft->type, string_of_type(ft->type)); |
| print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", RPC_FC_LONG); |
| write_conf_or_var_desc(file, current_structure, offset, ft, |
| get_attrp(f->attrs, ATTR_SWITCHIS)); |
| print_file(file, 2, "NdrFcShort(%hd),\t/* Offset= %hd (%u) */\n", |
| reloff, reloff, absoff); |
| *tfsoff += 8; |
| } |
| |
| /* FIXME: take alignment into account */ |
| offset += type_memsize(ft, &align); |
| } |
| } |
| |
| static int write_no_repeat_pointer_descriptions( |
| FILE *file, type_t *type, |
| size_t *offset_in_memory, size_t *offset_in_buffer, |
| unsigned int *typestring_offset) |
| { |
| int written = 0; |
| unsigned int align; |
| |
| if (is_ptr(type) || (!type->declarray && is_conformant_array(type))) |
| { |
| print_file(file, 2, "0x%02x, /* FC_NO_REPEAT */\n", RPC_FC_NO_REPEAT); |
| print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD); |
| |
| /* pointer instance */ |
| print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer); |
| *typestring_offset += 6; |
| |
| if (is_ptr(type)) |
| write_pointer_tfs(file, type, typestring_offset); |
| else |
| { |
| unsigned absoff = type->typestring_offset; |
| short reloff = absoff - (*typestring_offset + 2); |
| /* FIXME: get pointer attributes from field */ |
| print_file(file, 2, "0x%02x, 0x0,\t/* %s */\n", RPC_FC_UP, "FC_UP"); |
| print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n", |
| reloff, reloff, absoff); |
| *typestring_offset += 4; |
| } |
| |
| align = 0; |
| *offset_in_memory += type_memsize(type, &align); |
| /* FIXME: is there a case where these two are different? */ |
| align = 0; |
| *offset_in_buffer += type_memsize(type, &align); |
| |
| return 1; |
| } |
| |
| if (is_non_complex_struct(type)) |
| { |
| const var_t *v; |
| LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry ) |
| written += write_no_repeat_pointer_descriptions( |
| file, v->type, |
| offset_in_memory, offset_in_buffer, typestring_offset); |
| } |
| else |
| { |
| align = 0; |
| *offset_in_memory += type_memsize(type, &align); |
| /* FIXME: is there a case where these two are different? */ |
| align = 0; |
| *offset_in_buffer += type_memsize(type, &align); |
| } |
| |
| return written; |
| } |
| |
| static int write_pointer_description_offsets( |
| FILE *file, const attr_list_t *attrs, type_t *type, |
| size_t *offset_in_memory, size_t *offset_in_buffer, |
| unsigned int *typestring_offset) |
| { |
| int written = 0; |
| unsigned int align; |
| |
| if (is_ptr(type) && type->ref->type != RPC_FC_IP) |
| { |
| if (offset_in_memory && offset_in_buffer) |
| { |
| /* pointer instance */ |
| /* FIXME: sometimes from end of structure, sometimes from beginning */ |
| print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer); |
| |
| align = 0; |
| *offset_in_memory += type_memsize(type, &align); |
| /* FIXME: is there a case where these two are different? */ |
| align = 0; |
| *offset_in_buffer += type_memsize(type, &align); |
| } |
| *typestring_offset += 4; |
| |
| if (processed(type->ref) || is_base_type(type->ref->type)) |
| write_pointer_tfs(file, type, typestring_offset); |
| else |
| error("write_pointer_description_offsets: type format string unknown\n"); |
| |
| return 1; |
| } |
| |
| if (is_array(type)) |
| { |
| return write_pointer_description_offsets( |
| file, attrs, type->ref, offset_in_memory, offset_in_buffer, |
| typestring_offset); |
| } |
| else if (is_non_complex_struct(type)) |
| { |
| /* otherwise search for interesting fields to parse */ |
| const var_t *v; |
| LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry ) |
| { |
| written += write_pointer_description_offsets( |
| file, v->attrs, v->type, offset_in_memory, offset_in_buffer, |
| typestring_offset); |
| } |
| } |
| else |
| { |
| align = 0; |
| if (offset_in_memory) |
| *offset_in_memory += type_memsize(type, &align); |
| /* FIXME: is there a case where these two are different? */ |
| align = 0; |
| if (offset_in_buffer) |
| *offset_in_buffer += type_memsize(type, &align); |
| } |
| |
| return written; |
| } |
| |
| /* Note: if file is NULL return value is number of pointers to write, else |
| * it is the number of type format characters written */ |
| static int write_fixed_array_pointer_descriptions( |
| FILE *file, const attr_list_t *attrs, type_t *type, |
| size_t *offset_in_memory, size_t *offset_in_buffer, |
| unsigned int *typestring_offset) |
| { |
| unsigned int align; |
| int pointer_count = 0; |
| |
| if (type->type == RPC_FC_SMFARRAY || type->type == RPC_FC_LGFARRAY) |
| { |
| unsigned int temp = 0; |
| /* unfortunately, this needs to be done in two passes to avoid |
| * writing out redundant FC_FIXED_REPEAT descriptions */ |
| pointer_count = write_pointer_description_offsets( |
| NULL, attrs, type->ref, NULL, NULL, &temp); |
| if (pointer_count > 0) |
| { |
| unsigned int increment_size; |
| size_t offset_of_array_pointer_mem = 0; |
| size_t offset_of_array_pointer_buf = 0; |
| |
| align = 0; |
| increment_size = type_memsize(type->ref, &align); |
| |
| print_file(file, 2, "0x%02x, /* FC_FIXED_REPEAT */\n", RPC_FC_FIXED_REPEAT); |
| print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Iterations = %d */\n", type->dim, type->dim); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count); |
| *typestring_offset += 10; |
| |
| pointer_count = write_pointer_description_offsets( |
| file, attrs, type, &offset_of_array_pointer_mem, |
| &offset_of_array_pointer_buf, typestring_offset); |
| } |
| } |
| else if (is_struct(type->type)) |
| { |
| const var_t *v; |
| LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry ) |
| { |
| pointer_count += write_fixed_array_pointer_descriptions( |
| file, v->attrs, v->type, offset_in_memory, offset_in_buffer, |
| typestring_offset); |
| } |
| } |
| else |
| { |
| align = 0; |
| if (offset_in_memory) |
| *offset_in_memory += type_memsize(type, &align); |
| /* FIXME: is there a case where these two are different? */ |
| align = 0; |
| if (offset_in_buffer) |
| *offset_in_buffer += type_memsize(type, &align); |
| } |
| |
| return pointer_count; |
| } |
| |
| /* Note: if file is NULL return value is number of pointers to write, else |
| * it is the number of type format characters written */ |
| static int write_conformant_array_pointer_descriptions( |
| FILE *file, const attr_list_t *attrs, type_t *type, |
| size_t offset_in_memory, unsigned int *typestring_offset) |
| { |
| unsigned int align; |
| int pointer_count = 0; |
| |
| if (is_conformant_array(type) && !type->length_is) |
| { |
| unsigned int temp = 0; |
| /* unfortunately, this needs to be done in two passes to avoid |
| * writing out redundant FC_VARIABLE_REPEAT descriptions */ |
| pointer_count = write_pointer_description_offsets( |
| NULL, attrs, type->ref, NULL, NULL, &temp); |
| if (pointer_count > 0) |
| { |
| unsigned int increment_size; |
| size_t offset_of_array_pointer_mem = offset_in_memory; |
| size_t offset_of_array_pointer_buf = offset_in_memory; |
| |
| align = 0; |
| increment_size = type_memsize(type->ref, &align); |
| |
| if (increment_size > USHRT_MAX) |
| error("array size of %u bytes is too large\n", increment_size); |
| |
| print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT); |
| print_file(file, 2, "0x%02x, /* FC_FIXED_OFFSET */\n", RPC_FC_FIXED_OFFSET); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", offset_in_memory, offset_in_memory); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count); |
| *typestring_offset += 8; |
| |
| pointer_count = write_pointer_description_offsets( |
| file, attrs, type->ref, &offset_of_array_pointer_mem, |
| &offset_of_array_pointer_buf, typestring_offset); |
| } |
| } |
| |
| return pointer_count; |
| } |
| |
| /* Note: if file is NULL return value is number of pointers to write, else |
| * it is the number of type format characters written */ |
| static int write_varying_array_pointer_descriptions( |
| FILE *file, const attr_list_t *attrs, type_t *type, |
| size_t *offset_in_memory, size_t *offset_in_buffer, |
| unsigned int *typestring_offset) |
| { |
| unsigned int align; |
| int pointer_count = 0; |
| |
| /* FIXME: do varying array searching here, but pointer searching in write_pointer_description_offsets */ |
| |
| if (is_array(type) && type->length_is) |
| { |
| unsigned int temp = 0; |
| /* unfortunately, this needs to be done in two passes to avoid |
| * writing out redundant FC_VARIABLE_REPEAT descriptions */ |
| pointer_count = write_pointer_description_offsets( |
| NULL, attrs, type->ref, NULL, NULL, &temp); |
| if (pointer_count > 0) |
| { |
| unsigned int increment_size; |
| size_t offset_of_array_pointer_mem = 0; |
| size_t offset_of_array_pointer_buf = 0; |
| |
| align = 0; |
| increment_size = type_memsize(type->ref, &align); |
| |
| if (increment_size > USHRT_MAX) |
| error("array size of %u bytes is too large\n", increment_size); |
| |
| print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT); |
| print_file(file, 2, "0x%02x, /* FC_VARIABLE_OFFSET */\n", RPC_FC_VARIABLE_OFFSET); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory); |
| print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count); |
| *typestring_offset += 8; |
| |
| pointer_count = write_pointer_description_offsets( |
| file, attrs, type, &offset_of_array_pointer_mem, |
| &offset_of_array_pointer_buf, typestring_offset); |
| } |
| } |
| else if (is_struct(type->type)) |
| { |
| const var_t *v; |
| LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry ) |
| { |
| pointer_count += write_varying_array_pointer_descriptions( |
| file, v->attrs, v->type, offset_in_memory, offset_in_buffer, |
| typestring_offset); |
| } |
| } |
| else |
| { |
| align = 0; |
| if (offset_in_memory) |
| *offset_in_memory += type_memsize(type, &align); |
| /* FIXME: is there a case where these two are different? */ |
| align = 0; |
| if (offset_in_buffer) |
| *offset_in_buffer += type_memsize(type, &align); |
| } |
| |
| return pointer_count; |
| } |
| |
| static void write_pointer_description(FILE *file, type_t *type, |
| unsigned int *typestring_offset) |
| { |
| size_t offset_in_buffer; |
| size_t offset_in_memory; |
| |
| /* pass 1: search for single instance of a pointer (i.e. don't descend |
| * into arrays) */ |
| if (!is_array(type)) |
| { |
| offset_in_memory = 0; |
| offset_in_buffer = 0; |
| write_no_repeat_pointer_descriptions( |
| file, type, |
| &offset_in_memory, &offset_in_buffer, typestring_offset); |
| } |
| |
| /* pass 2: search for pointers in fixed arrays */ |
| offset_in_memory = 0; |
| offset_in_buffer = 0; |
| write_fixed_array_pointer_descriptions( |
| file, NULL, type, |
| &offset_in_memory, &offset_in_buffer, typestring_offset); |
| |
| /* pass 3: search for pointers in conformant only arrays (but don't descend |
| * into conformant varying or varying arrays) */ |
| if ((!type->declarray || !current_structure) && is_conformant_array(type)) |
| write_conformant_array_pointer_descriptions( |
| file, NULL, type, 0, typestring_offset); |
| else if (type->type == RPC_FC_CPSTRUCT) |
| { |
| unsigned int align = 0; |
| type_t *carray = find_array_or_string_in_struct(type)->type; |
| write_conformant_array_pointer_descriptions( |
| file, NULL, carray, |
| type_memsize(type, &align), |
| typestring_offset); |
| } |
| |
| /* pass 4: search for pointers in varying arrays */ |
| offset_in_memory = 0; |
| offset_in_buffer = 0; |
| write_varying_array_pointer_descriptions( |
| file, NULL, type, |
| &offset_in_memory, &offset_in_buffer, typestring_offset); |
| } |
| |
| int is_declptr(const type_t *t) |
| { |
| return is_ptr(t) || (is_conformant_array(t) && !t->declarray); |
| } |
| |
| static size_t write_string_tfs(FILE *file, const attr_list_t *attrs, |
| type_t *type, |
| const char *name, unsigned int *typestring_offset, |
| int toplevel) |
| { |
| size_t start_offset; |
| unsigned char rtype; |
| |
| if (toplevel && is_declptr(type)) |
| { |
| unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER; |
| int pointer_type = is_ptr(type) ? type->type : get_attrv(attrs, ATTR_POINTERTYPE); |
| if (!pointer_type) |
| pointer_type = RPC_FC_RP; |
| print_file(file, 2,"0x%x, 0x%x,\t/* %s%s */\n", |
| pointer_type, flag, string_of_type(pointer_type), |
| flag ? " [simple_pointer]" : ""); |
| *typestring_offset += 2; |
| if (!flag) |
| { |
| print_file(file, 2, "NdrFcShort(0x2),\n"); |
| *typestring_offset += 2; |
| } |
| } |
| |
| start_offset = *typestring_offset; |
| update_tfsoff(type, start_offset, file); |
| |
| rtype = type->ref->type; |
| |
| if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR)) |
| { |
| error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name); |
| return start_offset; |
| } |
| |
| if (type->declarray && !is_conformant_array(type)) |
| { |
| /* FIXME: multi-dimensional array */ |
| if (0xffffuL < type->dim) |
| error("array size for parameter %s exceeds %u bytes by %lu bytes\n", |
| name, 0xffffu, type->dim - 0xffffu); |
| |
| if (rtype == RPC_FC_CHAR) |
| WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset); |
| else |
| WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset); |
| print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD); |
| *typestring_offset += 2; |
| |
| print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", type->dim, type->dim); |
| *typestring_offset += 2; |
| |
| return start_offset; |
| } |
| else if (type->size_is) |
| { |
| unsigned int align = 0; |
| |
| if (rtype == RPC_FC_CHAR) |
| WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset); |
| else |
| WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset); |
| print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED); |
| *typestring_offset += 2; |
| |
| *typestring_offset += write_conf_or_var_desc( |
| file, current_structure, |
| (type->declarray && current_structure |
| ? type_memsize(current_structure, &align) |
| : 0), |
| type, type->size_is); |
| |
| return start_offset; |
| } |
| else |
| { |
| if (rtype == RPC_FC_WCHAR) |
| WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset); |
| else |
| WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset); |
| print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD); |
| *typestring_offset += 2; |
| |
| return start_offset; |
| } |
| } |
| |
| static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type, |
| const char *name, unsigned int *typestring_offset) |
| { |
| const expr_t *length_is = type->length_is; |
| const expr_t *size_is = type->size_is; |
| unsigned int align = 0; |
| size_t size; |
| size_t start_offset; |
| int has_pointer; |
| int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE); |
| unsigned int baseoff |
| = type->declarray && current_structure |
| ? type_memsize(current_structure, &align) |
| : 0; |
| |
| if (!pointer_type) |
| pointer_type = RPC_FC_RP; |
| |
| if (write_embedded_types(file, attrs, type->ref, name, FALSE, typestring_offset)) |
| has_pointer = TRUE; |
| else |
| has_pointer = type_has_pointers(type->ref); |
| |
| align = 0; |
| size = type_memsize((is_conformant_array(type) ? type->ref : type), &align); |
| |
| start_offset = *typestring_offset; |
| update_tfsoff(type, start_offset, file); |
| print_start_tfs_comment(file, type, start_offset); |
| print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type)); |
| print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1); |
| *typestring_offset += 2; |
| |
| align = 0; |
| if (type->type != RPC_FC_BOGUS_ARRAY) |
| { |
| unsigned char tc = type->type; |
| |
| if (tc == RPC_FC_LGFARRAY || tc == RPC_FC_LGVARRAY) |
| { |
| print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", size, size); |
| *typestring_offset += 4; |
| } |
| else |
| { |
| print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", size, size); |
| *typestring_offset += 2; |
| } |
| |
| if (is_conformant_array(type)) |
| *typestring_offset |
| += write_conf_or_var_desc(file, current_structure, baseoff, |
| type, size_is); |
| |
| if (type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY) |
| { |
| unsigned int elalign = 0; |
| size_t elsize = type_memsize(type->ref, &elalign); |
| |
| if (type->type == RPC_FC_LGVARRAY) |
| { |
| print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", type->dim, type->dim); |
| *typestring_offset += 4; |
| } |
| else |
| { |
| print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", type->dim, type->dim); |
| *typestring_offset += 2; |
| } |
| |
| print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", elsize, elsize); |
| *typestring_offset += 2; |
| } |
| |
| if (length_is) |
| *typestring_offset |
| += write_conf_or_var_desc(file, current_structure, baseoff, |
| type, length_is); |
| |
| if (has_pointer && (!type->declarray || !current_structure)) |
| { |
| print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP); |
| print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD); |
| *typestring_offset += 2; |
| write_pointer_description(file, type, typestring_offset); |
| print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END); |
| *typestring_offset += 1; |
| } |
| |
| write_member_type(file, type, NULL, type->ref, NULL, typestring_offset); |
| write_end(file, typestring_offset); |
| } |
| else |
| { |
| unsigned int dim = size_is ? 0 : type->dim; |
| print_file(file, 2, "NdrFcShort(0x%x),\t/* %u */\n", dim, dim); |
| *typestring_offset += 2; |
| *typestring_offset |
| += write_conf_or_var_desc(file, current_structure, baseoff, |
| type, size_is); |
| *typestring_offset |
| += write_conf_or_var_desc(file, current_structure, baseoff, |
| type, length_is); |
| write_member_type(file, type, NULL, type->ref, NULL, typestring_offset); |
| write_end(file, typestring_offset); |
| } |
| |
| return start_offset; |
| } |
| |
| static const var_t *find_array_or_string_in_struct(const type_t *type) |
| { |
| const var_t *last_field = LIST_ENTRY( list_tail(type->fields), const var_t, entry ); |
| const type_t *ft = last_field->type; |
| |
| if (ft->declarray && is_conformant_array(ft)) |
| return last_field; |
| |
| if (ft->type == RPC_FC_CSTRUCT || ft->type == RPC_FC_CPSTRUCT || ft->type == RPC_FC_CVSTRUCT) |
| return find_array_or_string_in_struct(last_field->type); |
| else |
| return NULL; |
| } |
| |
| static void write_struct_members(FILE *file, const type_t *type, |
| unsigned int *corroff, unsigned int *typestring_offset) |
| { |
| const var_t *field; |
| unsigned short offset = 0; |
| int salign = -1; |
| int padding; |
| |
| if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry ) |
| { |
| type_t *ft = field->type; |
| if (!ft->declarray || !is_conformant_array(ft)) |
| { |
| unsigned int align = 0; |
| size_t size = type_memsize(ft, &align); |
| if (salign == -1) |
| salign = align; |
| if ((align - 1) & offset) |
| { |
| unsigned char fc = 0; |
| switch (align) |
| { |
| case 4: |
| fc = RPC_FC_ALIGNM4; |
| break; |
| case 8: |
| fc = RPC_FC_ALIGNM8; |
| break; |
| default: |
| error("write_struct_members: cannot align type %d\n", ft->type); |
| } |
| print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc)); |
| offset = (offset + (align - 1)) & ~(align - 1); |
| *typestring_offset += 1; |
| } |
| write_member_type(file, type, field->attrs, field->type, corroff, |
| typestring_offset); |
| offset += size; |
| } |
| } |
| |
| padding = ((offset + (salign - 1)) & ~(salign - 1)) - offset; |
| if (padding) |
| { |
| print_file(file, 2, "0x%x,\t/* FC_STRUCTPAD%d */\n", |
| RPC_FC_STRUCTPAD1 + padding - 1, |
| padding); |
| *typestring_offset += 1; |
| } |
| |
| write_end(file, typestring_offset); |
| } |
| |
| static size_t write_struct_tfs(FILE *file, type_t *type, |
| const char *name, unsigned int *tfsoff) |
| { |
| const type_t *save_current_structure = current_structure; |
| unsigned int total_size; |
| const var_t *array; |
| size_t start_offset; |
| size_t array_offset; |
| int has_pointers = 0; |
| unsigned int align = 0; |
| unsigned int corroff; |
| var_t *f; |
| |
| guard_rec(type); |
| current_structure = type; |
| |
| total_size = type_memsize(type, &align); |
| if (total_size > USHRT_MAX) |
| error("structure size for %s exceeds %d bytes by %d bytes\n", |
| name, USHRT_MAX, total_size - USHRT_MAX); |
| |
| if (type->fields) LIST_FOR_EACH_ENTRY(f, type->fields, var_t, entry) |
| has_pointers |= write_embedded_types(file, f->attrs, f->type, f->name, |
| FALSE, tfsoff); |
| if (!has_pointers) has_pointers = type_has_pointers(type); |
| |
| array = find_array_or_string_in_struct(type); |
| if (array && !processed(array->type)) |
| array_offset |
| = is_attr(array->attrs, ATTR_STRING) |
| ? write_string_tfs(file, array->attrs, array->type, array->name, tfsoff, FALSE) |
| : write_array_tfs(file, array->attrs, array->type, array->name, tfsoff); |
| |
| corroff = *tfsoff; |
| write_descriptors(file, type, tfsoff); |
| |
| start_offset = *tfsoff; |
| update_tfsoff(type, start_offset, file); |
| print_start_tfs_comment(file, type, start_offset); |
| print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type)); |
| print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1); |
| print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size); |
| *tfsoff += 4; |
| |
| if (array) |
| { |
| unsigned int absoff = array->type->typestring_offset; |
| short reloff = absoff - *tfsoff; |
| print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", |
| reloff, reloff, absoff); |
| *tfsoff += 2; |
| } |
| else if (type->type == RPC_FC_BOGUS_STRUCT) |
| { |
| print_file(file, 2, "NdrFcShort(0x0),\n"); |
| *tfsoff += 2; |
| } |
| |
| if (type->type == RPC_FC_BOGUS_STRUCT) |
| { |
| /* On the sizing pass, type->ptrdesc may be zero, but it's ok as |
| nothing is written to file yet. On the actual writing pass, |
| this will have been updated. */ |
| unsigned int absoff = type->ptrdesc ? type->ptrdesc : *tfsoff; |
| short reloff = absoff - *tfsoff; |
| print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n", |
| reloff, reloff, absoff); |
| *tfsoff += 2; |
| } |
| else if ((type->type == RPC_FC_PSTRUCT) || |
| (type->type == RPC_FC_CPSTRUCT) || |
| (type->type == RPC_FC_CVSTRUCT && has_pointers)) |
| { |
| print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP); |
| print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD); |
| *tfsoff += 2; |
| write_pointer_description(file, type, tfsoff); |
| print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END); |
| *tfsoff += 1; |
| } |
| |
| write_struct_members(file, type, &corroff, tfsoff); |
| |
| if (type->type == RPC_FC_BOGUS_STRUCT) |
| { |
| const var_list_t *fs = type->fields; |
| const var_t *f; |
| |
| type->ptrdesc = *tfsoff; |
| if (fs) LIST_FOR_EACH_ENTRY(f, fs, const var_t, entry) |
| { |
| type_t *ft = f->type; |
| if (is_ptr(ft)) |
| write_pointer_tfs(file, ft, tfsoff); |
| else if (!ft->declarray && is_conformant_array(ft)) |
| { |
| unsigned int absoff = ft->typestring_offset; |
| short reloff = absoff - (*tfsoff + 2); |
| int ptr_type = get_attrv(f->attrs, ATTR_POINTERTYPE); |
| /* FIXME: We need to store pointer attributes for arrays |
| so we don't lose pointer_default info. */ |
| if (ptr_type == 0) |
| ptr_type = RPC_FC_UP; |
| print_file(file, 0, "/* %d */\n", *tfsoff); |
| print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type, |
| string_of_type(ptr_type)); |
| print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n", |
| reloff, reloff, absoff); |
| *tfsoff += 4; |
| } |
| } |
| if (type->ptrdesc == *tfsoff) |
| type->ptrdesc = 0; |
| } |
| |
| current_structure = save_current_structure; |
| return start_offset; |
| } |
| |
| static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type, |
| unsigned char flags, size_t offset, |
| unsigned int *typeformat_offset) |
| { |
| size_t start_offset = *typeformat_offset; |
| short reloff = offset - (*typeformat_offset + 2); |
| int in_attr, out_attr; |
| in_attr = is_attr(attrs, ATTR_IN); |
| out_attr = is_attr(attrs, ATTR_OUT); |
| if (!in_attr && !out_attr) in_attr = 1; |
| |
| if (out_attr && !in_attr && pointer_type == RPC_FC_RP) |
| flags |= 0x04; |
| |
| print_file(file, 2, "0x%x, 0x%x,\t\t/* %s", |
| pointer_type, |
| flags, |
| string_of_type(pointer_type)); |
| if (file) |
| { |
| if (flags & 0x04) |
| fprintf(file, " [allocated_on_stack]"); |
| if (flags & 0x10) |
| fprintf(file, " [pointer_deref]"); |
| fprintf(file, " */\n"); |
| } |
| |
| print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", reloff, offset); |
| *typeformat_offset += 4; |
| |
| return start_offset; |
| } |
| |
| static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff) |
| { |
| if (t == NULL) |
| { |
| print_file(file, 2, "NdrFcShort(0x0),\t/* No type */\n"); |
| } |
| else if (is_base_type(t->type)) |
| { |
| print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n", |
| t->type, string_of_type(t->type)); |
| } |
| else if (t->typestring_offset) |
| { |
| short reloff = t->typestring_offset - *tfsoff; |
| print_file(file, 2, "NdrFcShort(0x%x),\t/* Offset= %d (%d) */\n", |
| reloff, reloff, t->typestring_offset); |
| } |
| else |
| error("write_branch_type: type unimplemented (0x%x)\n", t->type); |
| |
| *tfsoff += 2; |
| } |
| |
| static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff) |
| { |
| unsigned int align = 0; |
| unsigned int start_offset; |
| size_t size = type_memsize(type, &align); |
| var_list_t *fields; |
| size_t nbranch = 0; |
| type_t *deftype = NULL; |
| short nodeftype = 0xffff; |
| var_t *f; |
| |
| guard_rec(type); |
| |
| if (type->type == RPC_FC_ENCAPSULATED_UNION) |
| { |
| const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry); |
| fields = uv->type->fields; |
| } |
| else |
| fields = type->fields; |
| |
| if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry) |
| { |
| expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE); |
| if (cases) |
| nbranch += list_count(cases); |
| if (f->type) |
| write_embedded_types(file, f->attrs, f->type, f->name, TRUE, tfsoff); |
| } |
| |
| start_offset = *tfsoff; |
| update_tfsoff(type, start_offset, file); |
| print_start_tfs_comment(file, type, start_offset); |
| if (type->type == RPC_FC_ENCAPSULATED_UNION) |
| { |
| const var_t *sv = LIST_ENTRY(list_head(type->fields), const var_t, entry); |
| const type_t *st = sv->type; |
| |
| switch (st->type) |
| { |
| case RPC_FC_CHAR: |
| case RPC_FC_SMALL: |
| case RPC_FC_USMALL: |
| case RPC_FC_SHORT: |
| case RPC_FC_USHORT: |
| case RPC_FC_LONG: |
| case RPC_FC_ULONG: |
| case RPC_FC_ENUM16: |
| case RPC_FC_ENUM32: |
| print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type)); |
| print_file(file, 2, "0x%x,\t/* Switch type= %s */\n", |
| 0x40 | st->type, string_of_type(st->type)); |
| *tfsoff += 2; |
| break; |
| default: |
| error("union switch type must be an integer, char, or enum\n"); |
| } |
| } |
| print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", size, size); |
| print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", nbranch, nbranch); |
| *tfsoff += 4; |
| |
| if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry) |
| { |
| type_t *ft = f->type; |
| expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE); |
| int deflt = is_attr(f->attrs, ATTR_DEFAULT); |
| expr_t *c; |
| |
| if (cases == NULL && !deflt) |
| error("union field %s with neither case nor default attribute\n", f->name); |
| |
| if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry) |
| { |
| /* MIDL doesn't check for duplicate cases, even though that seems |
| like a reasonable thing to do, it just dumps them to the TFS |
| like we're going to do here. */ |
| print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval); |
| *tfsoff += 4; |
| write_branch_type(file, ft, tfsoff); |
| } |
| |
| /* MIDL allows multiple default branches, even though that seems |
| illogical, it just chooses the last one, which is what we will |
| do. */ |
| if (deflt) |
| { |
| deftype = ft; |
| nodeftype = 0; |
| } |
| } |
| |
| if (deftype) |
| { |
| write_branch_type(file, deftype, tfsoff); |
| } |
| else |
| { |
| print_file(file, 2, "NdrFcShort(0x%x),\n", nodeftype); |
| *tfsoff += 2; |
| } |
| |
| return start_offset; |
| } |
| |
| static size_t write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *type, |
| unsigned int *typeformat_offset) |
| { |
| size_t i; |
| size_t start_offset = *typeformat_offset; |
| expr_t *iid = get_attrp(attrs, ATTR_IIDIS); |
| |
| if (iid) |
| { |
| print_file(file, 2, "0x2f, /* FC_IP */\n"); |
| print_file(file, 2, "0x5c, /* FC_PAD */\n"); |
| *typeformat_offset |
| += write_conf_or_var_desc(file, NULL, 0, type, iid) + 2; |
| } |
| else |
| { |
| const type_t *base = is_ptr(type) ? type->ref : type; |
| const UUID *uuid = get_attrp(base->attrs, ATTR_UUID); |
| |
| if (! uuid) |
| error("%s: interface %s missing UUID\n", __FUNCTION__, base->name); |
| |
| update_tfsoff(type, start_offset, file); |
| print_start_tfs_comment(file, type, start_offset); |
| print_file(file, 2, "0x2f,\t/* FC_IP */\n"); |
| print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n"); |
| print_file(file, 2, "NdrFcLong(0x%08lx),\n", uuid->Data1); |
| print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2); |
| print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3); |
| for (i = 0; i < 8; ++i) |
| print_file(file, 2, "0x%02x,\n", uuid->Data4[i]); |
| |
| if (file) |
| fprintf(file, "\n"); |
| |
| *typeformat_offset += 18; |
| } |
| return start_offset; |
| } |
| |
| static size_t write_contexthandle_tfs(FILE *file, const type_t *type, |
| const var_t *var, |
| unsigned int *typeformat_offset) |
| { |
| size_t start_offset = *typeformat_offset; |
| unsigned char flags = 0; |
| |
| if (is_attr(current_iface->attrs, ATTR_STRICTCONTEXTHANDLE)) |
| flags |= NDR_STRICT_CONTEXT_HANDLE; |
| |
| if (is_ptr(type)) |
| flags |= 0x80; |
| if (is_attr(var->attrs, ATTR_IN)) |
| { |
| flags |= 0x40; |
| if (!is_attr(var->attrs, ATTR_OUT)) |
| flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL; |
| } |
| if (is_attr(var->attrs, ATTR_OUT)) |
| flags |= 0x20; |
| |
| WRITE_FCTYPE(file, FC_BIND_CONTEXT, *typeformat_offset); |
| print_file(file, 2, "0x%x,\t/* Context flags: ", flags); |
| /* return and can't be null values overlap */ |
| if (((flags & 0x21) != 0x21) && (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL)) |
| print_file(file, 0, "can't be null, "); |
| if (flags & NDR_CONTEXT_HANDLE_SERIALIZE) |
| print_file(file, 0, "serialize, "); |
| if (flags & NDR_CONTEXT_HANDLE_NO_SERIALIZE) |
| print_file(file, 0, "no serialize, "); |
| if (flags & NDR_STRICT_CONTEXT_HANDLE) |
| print_file(file, 0, "strict, "); |
| if ((flags & 0x21) == 0x20) |
| print_file(file, 0, "out, "); |
| if ((flags & 0x21) == 0x21) |
| print_file(file, 0, "return, "); |
| if (flags & 0x40) |
| print_file(file, 0, "in, "); |
| if (flags & 0x80) |
| print_file(file, 0, "via ptr, "); |
| print_file(file, 0, "*/\n"); |
| print_file(file, 2, "0, /* FIXME: rundown routine index*/\n"); |
| print_file(file, 2, "0, /* FIXME: param num */\n"); |
| *typeformat_offset += 4; |
| |
| return start_offset; |
| } |
| |
| static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *func, |
| type_t *type, const var_t *var, |
| unsigned int *typeformat_offset) |
| { |
| size_t offset; |
| |
| if (is_context_handle(type)) |
| return write_contexthandle_tfs(file, type, var, typeformat_offset); |
| |
| if (is_user_type(type)) |
| { |
| write_user_tfs(file, type, typeformat_offset); |
| return type->typestring_offset; |
| } |
| |
| if ((last_ptr(type) || last_array(type)) && is_ptrchain_attr(var, ATTR_STRING)) |
| return write_string_tfs(file, var->attrs, type, var->name, typeformat_offset, TRUE); |
| |
| if (is_array(type)) |
| { |
| int ptr_type; |
| size_t off; |
| off = write_array_tfs(file, var->attrs, type, var->name, typeformat_offset); |
| ptr_type = get_attrv(var->attrs, ATTR_POINTERTYPE); |
| /* Top level pointers to conformant arrays may be handled specially |
| since we can bypass the pointer, but if the array is buried |
| beneath another pointer (e.g., "[size_is(,n)] int **p" then we |
| always need to write the pointer. */ |
| if (!ptr_type && var->type != type) |
| /* FIXME: This should use pointer_default, but the information |
| isn't kept around for arrays. */ |
| ptr_type = RPC_FC_UP; |
| if (ptr_type && ptr_type != RPC_FC_RP) |
| { |
| unsigned int absoff = type->typestring_offset; |
| short reloff = absoff - (*typeformat_offset + 2); |
| off = *typeformat_offset; |
| print_file(file, 0, "/* %d */\n", off); |
| print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type, |
| string_of_type(ptr_type)); |
| print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n", |
| reloff, reloff, absoff); |
| *typeformat_offset += 4; |
| } |
| return off; |
| } |
| |
| if (!is_ptr(type)) |
| { |
| /* basic types don't need a type format string */ |
| if (is_base_type(type->type)) |
| return 0; |
| |
| switch (type->type) |
| { |
| case RPC_FC_STRUCT: |
| case RPC_FC_PSTRUCT: |
| case RPC_FC_CSTRUCT: |
| case RPC_FC_CPSTRUCT: |
| case RPC_FC_CVSTRUCT: |
| case RPC_FC_BOGUS_STRUCT: |
| return write_struct_tfs(file, type, var->name, typeformat_offset); |
| case RPC_FC_ENCAPSULATED_UNION: |
| case RPC_FC_NON_ENCAPSULATED_UNION: |
| return write_union_tfs(file, type, typeformat_offset); |
| case RPC_FC_IGNORE: |
| case RPC_FC_BIND_PRIMITIVE: |
| /* nothing to do */ |
| return 0; |
| default: |
| error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name); |
| } |
| } |
| else if (last_ptr(type)) |
| { |
| size_t start_offset = *typeformat_offset; |
| int in_attr = is_attr(var->attrs, ATTR_IN); |
| int out_attr = is_attr(var->attrs, ATTR_OUT); |
| const type_t *base = type->ref; |
| |
| if (base->type == RPC_FC_IP |
| || (base->type == 0 |
| && is_attr(var->attrs, ATTR_IIDIS))) |
| { |
| return write_ip_tfs(file, var->attrs, type, typeformat_offset); |
| } |
| |
| /* special case for pointers to base types */ |
| if (is_base_type(base->type)) |
| { |
| print_file(file, indent, "0x%x, 0x%x, /* %s %s[simple_pointer] */\n", |
| type->type, (!in_attr && out_attr) ? 0x0C : 0x08, |
| string_of_type(type->type), |
| (!in_attr && out_attr) ? "[allocated_on_stack] " : ""); |
| print_file(file, indent, "0x%02x, /* %s */\n", base->type, string_of_type(base->type)); |
| print_file(file, indent, "0x5c, /* FC_PAD */\n"); |
| *typeformat_offset += 4; |
| return start_offset; |
| } |
| } |
| |
| assert(is_ptr(type)); |
| |
| offset = write_typeformatstring_var(file, indent, func, type->ref, var, typeformat_offset); |
| if (file) |
| fprintf(file, "/* %2u */\n", *typeformat_offset); |
| return write_pointer_only_tfs(file, var->attrs, type->type, |
| !last_ptr(type) ? 0x10 : 0, |
| offset, typeformat_offset); |
| } |
| |
| static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type, |
| const char *name, int write_ptr, unsigned int *tfsoff) |
| { |
| int retmask = 0; |
| |
| if (is_user_type(type)) |
| { |
| write_user_tfs(file, type, tfsoff); |
| } |
| else if (is_ptr(type)) |
| { |
| type_t *ref = type->ref; |
| |
| if (ref->type == RPC_FC_IP |
| || (ref->type == 0 |
| && is_attr(attrs, ATTR_IIDIS))) |
| { |
| write_ip_tfs(file, attrs, type, tfsoff); |
| } |
| else |
| { |
| if (!processed(ref) && !is_base_type(ref->type)) |
| retmask |= write_embedded_types(file, NULL, ref, name, TRUE, tfsoff); |
| |
| if (write_ptr) |
| write_pointer_tfs(file, type, tfsoff); |
| |
| retmask |= 1; |
| } |
| } |
| else if (last_array(type) && is_attr(attrs, ATTR_STRING)) |
| { |
| write_string_tfs(file, attrs, type, name, tfsoff, FALSE); |
| } |
| else if (type->declarray && is_conformant_array(type)) |
| ; /* conformant arrays and strings are handled specially */ |
| else if (is_array(type)) |
| { |
| write_array_tfs(file, attrs, type, name, tfsoff); |
| if (is_conformant_array(type)) |
| retmask |= 1; |
| } |
| else if (is_struct(type->type)) |
| { |
| if (!processed(type)) |
| write_struct_tfs(file, type, name, tfsoff); |
| } |
| else if (is_union(type->type)) |
| { |
| if (!processed(type)) |
| write_union_tfs(file, type, tfsoff); |
| } |
| else if (!is_base_type(type->type)) |
| error("write_embedded_types: unknown embedded type for %s (0x%x)\n", |
| name, type->type); |
| |
| return retmask; |
| } |
| |
| static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, type_pred_t pred) |
| { |
| const var_t *var; |
| const ifref_t *iface; |
| unsigned int typeformat_offset = 2; |
| |
| if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry ) |
| { |
| if (!pred(iface->iface)) |
| continue; |
| |
| if (iface->iface->funcs) |
| { |
| const func_t *func; |
| current_iface = iface; |
| LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry ) |
| { |
| if (is_local(func->def->attrs)) continue; |
| |
| if (!is_void(func->def->type)) |
| update_tfsoff(func->def->type, |
| write_typeformatstring_var( |
| file, 2, NULL, func->def->type, |
| func->def, &typeformat_offset), |
| file); |
| |
| current_func = func; |
| if (func->args) |
| LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) |
| update_tfsoff( |
| var->type, |
| write_typeformatstring_var( |
| file, 2, func, var->type, var, |
| &typeformat_offset), |
| file); |
| } |
| } |
| } |
| |
| return typeformat_offset + 1; |
| } |
| |
| |
| void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred) |
| { |
| int indent = 0; |
| |
| print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n"); |
| print_file(file, indent, "{\n"); |
| indent++; |
| print_file(file, indent, "0,\n"); |
| print_file(file, indent, "{\n"); |
| indent++; |
| print_file(file, indent, "NdrFcShort(0x0),\n"); |
| |
| set_all_tfswrite(TRUE); |
| process_tfs(file, ifaces, pred); |
| |
| print_file(file, indent, "0x0\n"); |
| indent--; |
| print_file(file, indent, "}\n"); |
| indent--; |
| print_file(file, indent, "};\n"); |
| print_file(file, indent, "\n"); |
| } |
| |
| static unsigned int get_required_buffer_size_type( |
| const type_t *type, const char *name, unsigned int *alignment) |
| { |
| *alignment = 0; |
| if (is_user_type(type)) |
| { |
| const char *uname; |
| const type_t *utype = get_user_type(type, &uname); |
| return get_required_buffer_size_type(utype, uname, alignment); |
| } |
| else |
| { |
| switch (type->type) |
| { |
| case RPC_FC_BYTE: |
| case RPC_FC_CHAR: |
| case RPC_FC_USMALL: |
| case RPC_FC_SMALL: |
| *alignment = 4; |
| return 1; |
| |
| case RPC_FC_WCHAR: |
| case RPC_FC_USHORT: |
| case RPC_FC_SHORT: |
| case RPC_FC_ENUM16: |
| *alignment = 4; |
| return 2; |
| |
| case RPC_FC_ULONG: |
| case RPC_FC_LONG: |
| case RPC_FC_ENUM32: |
| case RPC_FC_FLOAT: |
| case RPC_FC_ERROR_STATUS_T: |
| *alignment = 4; |
| return 4; |
| |
| case RPC_FC_HYPER: |
| case RPC_FC_DOUBLE: |
| *alignment = 8; |
| return 8; |
| |
| case RPC_FC_IGNORE: |
| case RPC_FC_BIND_PRIMITIVE: |
| return 0; |
| |
| case RPC_FC_STRUCT: |
| case RPC_FC_PSTRUCT: |
| { |
| size_t size = 0; |
| const var_t *field; |
| if (!type->fields) return 0; |
| LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry ) |
| { |
| unsigned int alignment; |
| size += get_required_buffer_size_type(field->type, field->name, |
| &alignment); |
| } |
| return size; |
| } |
| |
| case RPC_FC_RP: |
| return |
| is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT |
| ? get_required_buffer_size_type( type->ref, name, alignment ) |
| : 0; |
| |
| case RPC_FC_SMFARRAY: |
| case RPC_FC_LGFARRAY: |
| return type->dim * get_required_buffer_size_type(type->ref, name, alignment); |
| |
| default: |
| return 0; |
| } |
| } |
| } |
| |
| static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass) |
| { |
| int in_attr = is_attr(var->attrs, ATTR_IN); |
| int out_attr = is_attr(var->attrs, ATTR_OUT); |
| const type_t *t; |
| |
| if (!in_attr && !out_attr) |
| in_attr = 1; |
| |
| *alignment = 0; |
| |
| for (t = var->type; is_ptr(t); t = t->ref) |
| if (is_attr(t->attrs, ATTR_CONTEXTHANDLE)) |
| { |
| *alignment = 4; |
| return 20; |
| } |
| |
| if (pass == PASS_OUT) |
| { |
| if (out_attr && is_ptr(var->type)) |
| { |
| type_t *type = var->type; |
| |
| if (type->type == RPC_FC_STRUCT) |
| { |
| const var_t *field; |
| unsigned int size = 36; |
| |
| if (!type->fields) return size; |
| LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry ) |
| { |
| unsigned int align; |
| size += get_required_buffer_size_type( |
| field->type, field->name, &align); |
| } |
| return size; |
| } |
| } |
| return 0; |
| } |
| else |
| { |
| if ((!out_attr || in_attr) && !var->type->size_is |
| && !is_attr(var->attrs, ATTR_STRING) && !var->type->declarray) |
| { |
| if (is_ptr(var->type)) |
| { |
| type_t *type = var->type; |
| |
| if (is_base_type(type->type)) |
| { |
| return 25; |
| } |
| else if (type->type == RPC_FC_STRUCT) |
| { |
| unsigned int size = 36; |
| const var_t *field; |
| |
| if (!type->fields) return size; |
| LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry ) |
| { |
| unsigned int align; |
| size += get_required_buffer_size_type( |
| field->type, field->name, &align); |
| } |
| return size; |
| } |
| } |
| } |
| |
| return get_required_buffer_size_type(var->type, var->name, alignment); |
| } |
| } |
| |
| static unsigned int get_function_buffer_size( const func_t *func, enum pass pass ) |
| { |
| const var_t *var; |
| unsigned int total_size = 0, alignment; |
| |
| if (func->args) |
| { |
| LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) |
| { |
| total_size += get_required_buffer_size(var, &alignment, pass); |
| total_size += alignment; |
| } |
| } |
| |
| if (pass == PASS_OUT && !is_void(func->def->type)) |
| { |
| total_size += get_required_buffer_size(func->def, &alignment, PASS_RETURN); |
| total_size += alignment; |
| } |
| return total_size; |
| } |
| |
| static void print_phase_function(FILE *file, int indent, const char *type, |
| enum remoting_phase phase, |
| const var_t *var, unsigned int type_offset) |
| { |
| const char *function; |
| switch (phase) |
| { |
| case PHASE_BUFFERSIZE: |
| function = "BufferSize"; |
| break; |
| case PHASE_MARSHAL: |
| function = "Marshall"; |
| break; |
| case PHASE_UNMARSHAL: |
| function = "Unmarshall"; |
| break; |
| case PHASE_FREE: |
| function = "Free"; |
| break; |
| default: |
| assert(0); |
| return; |
| } |
| |
| print_file(file, indent, "Ndr%s%s(\n", type, function); |
| indent++; |
| print_file(file, indent, "&_StubMsg,\n"); |
| print_file(file, indent, "%s%s%s%s,\n", |
| (phase == PHASE_UNMARSHAL) ? "(unsigned char **)" : "(unsigned char *)", |
| (phase == PHASE_UNMARSHAL || decl_indirect(var->type)) ? "&" : "", |
| (phase == PHASE_UNMARSHAL && decl_indirect(var->type)) ? "_p_" : "", |
| var->name); |
| print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n", |
| type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");"); |
| if (phase == PHASE_UNMARSHAL) |
| print_file(file, indent, "0);\n"); |
| indent--; |
| } |
| |
| void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase, |
| enum pass pass, const var_t *var, |
| const char *varname) |
| { |
| type_t *type = var->type; |
| unsigned int size; |
| unsigned int alignment = 0; |
| unsigned char rtype; |
| |
| /* no work to do for other phases, buffer sizing is done elsewhere */ |
| if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL) |
| return; |
| |
| rtype = is_ptr(type) ? type->ref->type : type->type; |
| |
| switch (rtype) |
| { |
| case RPC_FC_BYTE: |
| case RPC_FC_CHAR: |
| case RPC_FC_SMALL: |
| case RPC_FC_USMALL: |
| size = 1; |
| alignment = 1; |
| break; |
| |
| case RPC_FC_WCHAR: |
| case RPC_FC_USHORT: |
| case RPC_FC_SHORT: |
| case RPC_FC_ENUM16: |
| size = 2; |
| alignment = 2; |
| break; |
| |
| case RPC_FC_ULONG: |
| case RPC_FC_LONG: |
| case RPC_FC_ENUM32: |
| case RPC_FC_FLOAT: |
| case RPC_FC_ERROR_STATUS_T: |
| size = 4; |
| alignment = 4; |
| break; |
| |
| case RPC_FC_HYPER: |
| case RPC_FC_DOUBLE: |
| size = 8; |
| alignment = 8; |
| break; |
| |
| case RPC_FC_IGNORE: |
| case RPC_FC_BIND_PRIMITIVE: |
| /* no marshalling needed */ |
| return; |
| |
| default: |
| error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, rtype); |
| size = 0; |
| } |
| |
| if (phase == PHASE_MARSHAL) |
| print_file(file, indent, "MIDL_memset(_StubMsg.Buffer, 0, (0x%x - (long)_StubMsg.Buffer) & 0x%x);\n", alignment, alignment - 1); |
| print_file(file, indent, "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n", |
| alignment - 1, alignment - 1); |
| |
| if (phase == PHASE_MARSHAL) |
| { |
| print_file(file, indent, "*("); |
| write_type_decl(file, is_ptr(type) ? type->ref : type, NULL); |
| if (is_ptr(type)) |
| fprintf(file, " *)_StubMsg.Buffer = *"); |
| else |
| fprintf(file, " *)_StubMsg.Buffer = "); |
| fprintf(file, "%s", varname); |
| fprintf(file, ";\n"); |
| } |
| else if (phase == PHASE_UNMARSHAL) |
| { |
| print_file(file, indent, "if (_StubMsg.Buffer + sizeof("); |
| write_type_decl(file, is_ptr(type) ? type->ref : type, NULL); |
| fprintf(file, ") > _StubMsg.BufferEnd)\n"); |
| print_file(file, indent, "{\n"); |
| print_file(file, indent + 1, "RpcRaiseException(RPC_X_BAD_STUB_DATA);\n"); |
| print_file(file, indent, "}\n"); |
| if (pass == PASS_IN || pass == PASS_RETURN) |
| print_file(file, indent, ""); |
| else |
| print_file(file, indent, "*"); |
| fprintf(file, "%s", varname); |
| if (pass == PASS_IN && is_ptr(type)) |
| fprintf(file, " = ("); |
| else |
| fprintf(file, " = *("); |
| write_type_decl(file, is_ptr(type) ? type->ref : type, NULL); |
| fprintf(file, " *)_StubMsg.Buffer;\n"); |
| } |
| |
| print_file(file, indent, "_StubMsg.Buffer += sizeof("); |
| write_type_decl(file, var->type, NULL); |
| fprintf(file, ");\n"); |
| } |
| |
| /* returns whether the MaxCount, Offset or ActualCount members need to be |
| * filled in for the specified phase */ |
| static inline int is_size_needed_for_phase(enum remoting_phase phase) |
| { |
| return (phase != PHASE_UNMARSHAL); |
| } |
| |
| expr_t *get_size_is_expr(const type_t *t, const char *name) |
| { |
| expr_t *x = NULL; |
| |
| for ( ; is_ptr(t) || is_array(t); t = t->ref) |
| if (t->size_is) |
| { |
| if (!x) |
| x = t->size_is; |
| else |
| error("%s: multidimensional conformant" |
| " arrays not supported at the top level\n", |
| name); |
| } |
| |
| return x; |
| } |
| |
| static void write_remoting_arg(FILE *file, int indent, const func_t *func, |
| enum pass pass, enum remoting_phase phase, |
| const var_t *var) |
| { |
| int in_attr, out_attr, pointer_type; |
| const type_t *type = var->type; |
| unsigned char rtype; |
| size_t start_offset = type->typestring_offset; |
| |
| pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE); |
| if (!pointer_type) |
| pointer_type = RPC_FC_RP; |
| |
| in_attr = is_attr(var->attrs, ATTR_IN); |
| out_attr = is_attr(var->attrs, ATTR_OUT); |
| if (!in_attr && !out_attr) |
| in_attr = 1; |
| |
| if (phase != PHASE_FREE) |
| switch (pass) |
| { |
| case PASS_IN: |
| if (!in_attr) return; |
| break; |
| case PASS_OUT: |
| if (!out_attr) return; |
| break; |
| case PASS_RETURN: |
| break; |
| } |
| |
| rtype = type->type; |
| |
| if (is_context_handle(type)) |
| { |
| if (phase == PHASE_MARSHAL) |
| { |
| if (pass == PASS_IN) |
| { |
| print_file(file, indent, "NdrClientContextMarshall(\n"); |
| print_file(file, indent + 1, "&_StubMsg,\n"); |
| print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ptr(type) ? "*" : "", var->name); |
| print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0"); |
| } |
| else |
| { |
| print_file(file, indent, "NdrServerContextNewMarshall(\n"); |
| print_file(file, indent + 1, "&_StubMsg,\n"); |
| print_file(file, indent + 1, "(NDR_SCONTEXT)%s,\n", var->name); |
| print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown,\n", get_context_handle_type_name(var->type)); |
| print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset); |
| } |
| } |
| else if (phase == PHASE_UNMARSHAL) |
| { |
| if (pass == PASS_OUT) |
| { |
| if (!in_attr) |
| print_file(file, indent, "*%s = 0;\n", var->name); |
| print_file(file, indent, "NdrClientContextUnmarshall(\n"); |
| print_file(file, indent + 1, "&_StubMsg,\n"); |
| print_file(file, indent + 1, "(NDR_CCONTEXT *)%s,\n", var->name); |
| print_file(file, indent + 1, "_Handle);\n"); |
| } |
| else |
| { |
| print_file(file, indent, "%s = NdrServerContextNewUnmarshall(\n", var->name); |
| print_file(file, indent + 1, "&_StubMsg,\n"); |
| print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset); |
| } |
| } |
| } |
| else if (is_user_type(var->type)) |
| { |
| print_phase_function(file, indent, "UserMarshal", phase, var, start_offset); |
| } |
| else if (is_string_type(var->attrs, var->type)) |
| { |
| if (is_array(type) && !is_conformant_array(type)) |
| print_phase_function(file, indent, "NonConformantString", phase, var, start_offset); |
| else |
| { |
| if (type->size_is && is_size_needed_for_phase(phase)) |
| { |
| print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)"); |
| write_expr(file, type->size_is, 1); |
| fprintf(file, ";\n"); |
| } |
| |
| if (phase == PHASE_FREE || pass == PASS_RETURN || pointer_type == RPC_FC_UP) |
| print_phase_function(file, indent, "Pointer", phase, var, |
| start_offset - (type->size_is ? 4 : 2)); |
| else |
| print_phase_function(file, indent, "ConformantString", phase, var, |
| start_offset); |
| } |
| } |
| else if (is_array(type)) |
| { |
| unsigned char tc = type->type; |
| const char *array_type = "FixedArray"; |
| |
| /* We already have the size_is expression since it's at the |
| top level, but do checks for multidimensional conformant |
| arrays. When we handle them, we'll need to extend this |
| function to return a list, and then we'll actually use |
| the return value. */ |
| get_size_is_expr(type, var->name); |
| |
| if (tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY) |
| { |
| if (is_size_needed_for_phase(phase)) |
| { |
| print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */ |
| print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)"); |
| write_expr(file, type->length_is, 1); |
| fprintf(file, ";\n\n"); |
| } |
| array_type = "VaryingArray"; |
| } |
| else if (tc == RPC_FC_CARRAY) |
| { |
| if (is_size_needed_for_phase(phase)) |
| { |
| print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)"); |
| write_expr(file, type->size_is, 1); |
| fprintf(file, ";\n\n"); |
| } |
| array_type = "ConformantArray"; |
| } |
| else if (tc == RPC_FC_CVARRAY || tc == RPC_FC_BOGUS_ARRAY) |
| { |
| if (is_size_needed_for_phase(phase)) |
| { |
| if (type->size_is) |
| { |
| print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)"); |
| write_expr(file, type->size_is, 1); |
| fprintf(file, ";\n"); |
| } |
| if (type->length_is) |
| { |
| print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */ |
| print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)"); |
| write_expr(file, type->length_is, 1); |
| fprintf(file, ";\n\n"); |
| } |
| } |
| array_type = (tc == RPC_FC_BOGUS_ARRAY |
| ? "ComplexArray" |
| : "ConformantVaryingArray"); |
| } |
| |
| if (pointer_type != RPC_FC_RP) array_type = "Pointer"; |
| print_phase_function(file, indent, array_type, phase, var, start_offset); |
| if (phase == PHASE_FREE && pointer_type == RPC_FC_RP) |
| { |
| /* these are all unmarshalled by allocating memory */ |
| if (type->type == RPC_FC_BOGUS_ARRAY || |
| type->type == RPC_FC_CVARRAY || |
| ((type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY) && in_attr) || |
| (type->type == RPC_FC_CARRAY && !in_attr)) |
| { |
| print_file(file, indent, "if (%s)\n", var->name); |
| indent++; |
| print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name); |
| } |
| } |
| } |
| else if (!is_ptr(var->type) && is_base_type(rtype)) |
| { |
| if (phase != PHASE_FREE) |
| print_phase_basetype(file, indent, phase, pass, var, var->name); |
| } |
| else if (!is_ptr(var->type)) |
| { |
| switch (rtype) |
| { |
| case RPC_FC_STRUCT: |
| case RPC_FC_PSTRUCT: |
| print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset); |
| break; |
| case RPC_FC_CSTRUCT: |
| case RPC_FC_CPSTRUCT: |
| print_phase_function(file, indent, "ConformantStruct", phase, var, start_offset); |
| break; |
| case RPC_FC_CVSTRUCT: |
| print_phase_function(file, indent, "ConformantVaryingStruct", phase, var, start_offset); |
| break; |
| case RPC_FC_BOGUS_STRUCT: |
| print_phase_function(file, indent, "ComplexStruct", phase, var, start_offset); |
| break; |
| case RPC_FC_RP: |
| if (is_base_type( var->type->ref->type )) |
| { |
| print_phase_basetype(file, indent, phase, pass, var, var->name); |
| } |
| else if (var->type->ref->type == RPC_FC_STRUCT) |
| { |
| if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE) |
| print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4); |
| } |
| else |
| { |
| expr_t *iid; |
| if ((iid = get_attrp( var->attrs, ATTR_IIDIS ))) |
| { |
| print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " ); |
| write_expr( file, iid, 1 ); |
| fprintf( file, ";\n\n" ); |
| } |
| print_phase_function(file, indent, "Pointer", phase, var, start_offset); |
| } |
| break; |
| default: |
| error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype); |
| } |
| } |
| else |
| { |
| if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype)) |
| { |
| if (phase != PHASE_FREE) |
| print_phase_basetype(file, indent, phase, pass, var, var->name); |
| } |
| else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT)) |
| { |
| if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE) |
| print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4); |
| } |
| else |
| { |
| expr_t *iid; |
| expr_t *sx = get_size_is_expr(type, var->name); |
| |
| if ((iid = get_attrp( var->attrs, ATTR_IIDIS ))) |
| { |
| print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " ); |
| write_expr( file, iid, 1 ); |
| fprintf( file, ";\n\n" ); |
| } |
| else if (sx) |
| { |
| print_file(file, indent, "_StubMsg.MaxCount = (unsigned long) "); |
| write_expr(file, sx, 1); |
| fprintf(file, ";\n\n"); |
| } |
| if (var->type->ref->type == RPC_FC_IP) |
| print_phase_function(file, indent, "InterfacePointer", phase, var, start_offset); |
| else |
| print_phase_function(file, indent, "Pointer", phase, var, start_offset); |
| } |
| } |
| fprintf(file, "\n"); |
| } |
| |
| void write_remoting_arguments(FILE *file, int indent, const func_t *func, |
| enum pass pass, enum remoting_phase phase) |
| { |
| if (phase == PHASE_BUFFERSIZE && pass != PASS_RETURN) |
| { |
| unsigned int size = get_function_buffer_size( func, pass ); |
| print_file(file, indent, "_StubMsg.BufferLength = %u;\n", size); |
| } |
| |
| if (pass == PASS_RETURN) |
| { |
| var_t var; |
| var = *func->def; |
| var.name = xstrdup( "_RetVal" ); |
| write_remoting_arg( file, indent, func, pass, phase, &var ); |
| free( var.name ); |
| } |
| else |
| { |
| const var_t *var; |
| if (!func->args) |
| return; |
| LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) |
| write_remoting_arg( file, indent, func, pass, phase, var ); |
| } |
| } |
| |
| |
| size_t get_size_procformatstring_var(const var_t *var) |
| { |
| return write_procformatstring_var(NULL, 0, var, FALSE); |
| } |
| |
| |
| size_t get_size_procformatstring_func(const func_t *func) |
| { |
| const var_t *var; |
| size_t size = 0; |
| |
| /* argument list size */ |
| if (func->args) |
| LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) |
| size += get_size_procformatstring_var(var); |
| |
| /* return value size */ |
| if (is_void(func->def->type)) |
| size += 2; /* FC_END and FC_PAD */ |
| else |
| size += get_size_procformatstring_var(func->def); |
| |
| return size; |
| } |
| |
| size_t get_size_procformatstring(const ifref_list_t *ifaces, type_pred_t pred) |
| { |
| const ifref_t *iface; |
| size_t size = 1; |
| const func_t *func; |
| |
| if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry ) |
| { |
| if (!pred(iface->iface)) |
| continue; |
| |
| if (iface->iface->funcs) |
| LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry ) |
| if (!is_local(func->def->attrs)) |
| size += get_size_procformatstring_func( func ); |
| } |
| return size; |
| } |
| |
| size_t get_size_typeformatstring(const ifref_list_t *ifaces, type_pred_t pred) |
| { |
| set_all_tfswrite(FALSE); |
| return process_tfs(NULL, ifaces, pred); |
| } |
| |
| static void write_struct_expr(FILE *h, const expr_t *e, int brackets, |
| const var_list_t *fields, const char *structvar) |
| { |
| switch (e->type) { |
| case EXPR_VOID: |
| break; |
| case EXPR_NUM: |
| fprintf(h, "%lu", e->u.lval); |
| break; |
| case EXPR_HEXNUM: |
| fprintf(h, "0x%lx", e->u.lval); |
| break; |
| case EXPR_DOUBLE: |
| fprintf(h, "%#.15g", e->u.dval); |
| break; |
| case EXPR_TRUEFALSE: |
| if (e->u.lval == 0) |
| fprintf(h, "FALSE"); |
| else |
| fprintf(h, "TRUE"); |
| break; |
| case EXPR_IDENTIFIER: |
| { |
| const var_t *field; |
| LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry ) |
| if (!strcmp(e->u.sval, field->name)) |
| { |
| fprintf(h, "%s->%s", structvar, e->u.sval); |
| break; |
| } |
| |
| if (&field->entry == fields) error("no field found for identifier %s\n", e->u.sval); |
| break; |
| } |
| case EXPR_NEG: |
| fprintf(h, "-"); |
| write_struct_expr(h, e->ref, 1, fields, structvar); |
| break; |
| case EXPR_NOT: |
| fprintf(h, "~"); |
| write_struct_expr(h, e->ref, 1, fields, structvar); |
| break; |
| case EXPR_PPTR: |
| fprintf(h, "*"); |
| write_struct_expr(h, e->ref, 1, fields, structvar); |
| break; |
| case EXPR_CAST: |
| fprintf(h, "("); |
| write_type_decl(h, e->u.tref, NULL); |
| fprintf(h, ")"); |
| write_struct_expr(h, e->ref, 1, fields, structvar); |
| break; |
| case EXPR_SIZEOF: |
| fprintf(h, "sizeof("); |
| write_type_decl(h, e->u.tref, NULL); |
| fprintf(h, ")"); |
| break; |
| case EXPR_SHL: |
| case EXPR_SHR: |
| case EXPR_MUL: |
| case EXPR_DIV: |
| case EXPR_ADD: |
| case EXPR_SUB: |
| case EXPR_AND: |
| case EXPR_OR: |
| if (brackets) fprintf(h, "("); |
| write_struct_expr(h, e->ref, 1, fields, structvar); |
| switch (e->type) { |
| case EXPR_SHL: fprintf(h, " << "); break; |
| case EXPR_SHR: fprintf(h, " >> "); break; |
| case EXPR_MUL: fprintf(h, " * "); break; |
| case EXPR_DIV: fprintf(h, " / "); break; |
| case EXPR_ADD: fprintf(h, " + "); break; |
| case EXPR_SUB: fprintf(h, " - "); break; |
| case EXPR_AND: fprintf(h, " & "); break; |
| case EXPR_OR: fprintf(h, " | "); break; |
| default: break; |
| } |
| write_struct_expr(h, e->u.ext, 1, fields, structvar); |
| if (brackets) fprintf(h, ")"); |
| break; |
| case EXPR_COND: |
| if (brackets) fprintf(h, "("); |
| write_struct_expr(h, e->ref, 1, fields, structvar); |
| fprintf(h, " ? "); |
| write_struct_expr(h, e->u.ext, 1, fields, structvar); |
| fprintf(h, " : "); |
| write_struct_expr(h, e->ext2, 1, fields, structvar); |
| if (brackets) fprintf(h, ")"); |
| break; |
| case EXPR_ADDRESSOF: |
| fprintf(h, "&"); |
| write_struct_expr(h, e->ref, 1, fields, structvar); |
| break; |
| } |
| } |
| |
| |
| void declare_stub_args( FILE *file, int indent, const func_t *func ) |
| { |
| int in_attr, out_attr; |
| int i = 0; |
| const var_t *def = func->def; |
| const var_t *var; |
| |
| /* declare return value '_RetVal' */ |
| if (!is_void(def->type)) |
| { |
| print_file(file, indent, ""); |
| write_type_decl_left(file, def->type); |
| fprintf(file, " _RetVal;\n"); |
| } |
| |
| if (!func->args) |
| return; |
| |
| LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) |
| { |
| int is_string = is_attr(var->attrs, ATTR_STRING); |
| |
| in_attr = is_attr(var->attrs, ATTR_IN); |
| out_attr = is_attr(var->attrs, ATTR_OUT); |
| if (!out_attr && !in_attr) |
| in_attr = 1; |
| |
| if (is_context_handle(var->type)) |
| print_file(file, indent, "NDR_SCONTEXT %s;\n", var->name); |
| else |
| { |
| if (!in_attr && !var->type->size_is && !is_string) |
| { |
| print_file(file, indent, ""); |
| write_type_decl(file, var->type->declarray ? var->type : var->type->ref, |
| "_W%u", i++); |
| fprintf(file, ";\n"); |
| } |
| |
| print_file(file, indent, ""); |
| write_type_decl_left(file, var->type); |
| fprintf(file, " "); |
| if (var->type->declarray) { |
| fprintf(file, "( *"); |
| write_name(file, var); |
| fprintf(file, " )"); |
| } else |
| write_name(file, var); |
| write_type_right(file, var->type, FALSE); |
| fprintf(file, ";\n"); |
| |
| if (decl_indirect(var->type)) |
| print_file(file, indent, "void *_p_%s = &%s;\n", |
| var->name, var->name); |
| } |
| } |
| } |
| |
| |
| void assign_stub_out_args( FILE *file, int indent, const func_t *func ) |
| { |
| int in_attr, out_attr; |
| int i = 0, sep = 0; |
| const var_t *var; |
| |
| if (!func->args) |
| return; |
| |
| LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) |
| { |
| int is_string = is_attr(var->attrs, ATTR_STRING); |
| in_attr = is_attr(var->attrs, ATTR_IN); |
| out_attr = is_attr(var->attrs, ATTR_OUT); |
| if (!out_attr && !in_attr) |
| in_attr = 1; |
| |
| if (!in_attr) |
| { |
| print_file(file, indent, ""); |
| write_name(file, var); |
| |
| if (is_context_handle(var->type)) |
| { |
| fprintf(file, " = NdrContextHandleInitialize(\n"); |
| print_file(file, indent + 1, "&_StubMsg,\n"); |
| print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", |
| var->type->typestring_offset); |
| } |
| else if (var->type->size_is) |
| { |
| unsigned int size, align = 0; |
| type_t *type = var->type; |
| |
| fprintf(file, " = NdrAllocate(&_StubMsg, "); |
| for ( ; type->size_is ; type = type->ref) |
| { |
| write_expr(file, type->size_is, TRUE); |
| fprintf(file, " * "); |
| } |
| size = type_memsize(type, &align); |
| fprintf(file, "%u);\n", size); |
| } |
| else if (!is_string) |
| { |
| fprintf(file, " = &_W%u;\n", i); |
| if (is_ptr(var->type) && !last_ptr(var->type)) |
| print_file(file, indent, "_W%u = 0;\n", i); |
| i++; |
| } |
| |
| sep = 1; |
| } |
| } |
| if (sep) |
| fprintf(file, "\n"); |
| } |
| |
| |
| int write_expr_eval_routines(FILE *file, const char *iface) |
| { |
| static const char *var_name = "pS"; |
| int result = 0; |
| struct expr_eval_routine *eval; |
| unsigned short callback_offset = 0; |
| |
| LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry) |
| { |
| const char *name = eval->structure->name; |
| const var_list_t *fields = eval->structure->fields; |
| result = 1; |
| |
| print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n", |
| iface, name, callback_offset); |
| print_file(file, 0, "{\n"); |
| print_file (file, 1, "%s *%s = (%s *)(pStubMsg->StackTop - %u);\n", |
| name, var_name, name, eval->baseoff); |
| print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */ |
| print_file(file, 1, "pStubMsg->MaxCount = (unsigned long)"); |
| write_struct_expr(file, eval->expr, 1, fields, var_name); |
| fprintf(file, ";\n"); |
| print_file(file, 0, "}\n\n"); |
| callback_offset++; |
| } |
| return result; |
| } |
| |
| void write_expr_eval_routine_list(FILE *file, const char *iface) |
| { |
| struct expr_eval_routine *eval; |
| struct expr_eval_routine *cursor; |
| unsigned short callback_offset = 0; |
| |
| fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n"); |
| fprintf(file, "{\n"); |
| |
| LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry) |
| { |
| const char *name = eval->structure->name; |
| print_file(file, 1, "%s_%sExprEval_%04u,\n", iface, name, callback_offset); |
| callback_offset++; |
| list_remove(&eval->entry); |
| free(eval); |
| } |
| |
| fprintf(file, "};\n\n"); |
| } |
| |
| void write_user_quad_list(FILE *file) |
| { |
| user_type_t *ut; |
| |
| if (list_empty(&user_type_list)) |
| return; |
| |
| fprintf(file, "static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[] =\n"); |
| fprintf(file, "{\n"); |
| LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry) |
| { |
| const char *sep = &ut->entry == list_tail(&user_type_list) ? "" : ","; |
| print_file(file, 1, "{\n"); |
| print_file(file, 2, "(USER_MARSHAL_SIZING_ROUTINE)%s_UserSize,\n", ut->name); |
| print_file(file, 2, "(USER_MARSHAL_MARSHALLING_ROUTINE)%s_UserMarshal,\n", ut->name); |
| print_file(file, 2, "(USER_MARSHAL_UNMARSHALLING_ROUTINE)%s_UserUnmarshal,\n", ut->name); |
| print_file(file, 2, "(USER_MARSHAL_FREEING_ROUTINE)%s_UserFree\n", ut->name); |
| print_file(file, 1, "}%s\n", sep); |
| } |
| fprintf(file, "};\n\n"); |
| } |
| |
| void write_endpoints( FILE *f, const char *prefix, const str_list_t *list ) |
| { |
| const struct str_list_entry_t *endpoint; |
| const char *p; |
| |
| /* this should be an array of RPC_PROTSEQ_ENDPOINT but we want const strings */ |
| print_file( f, 0, "static const unsigned char * %s__RpcProtseqEndpoint[][2] =\n{\n", prefix ); |
| LIST_FOR_EACH_ENTRY( endpoint, list, const struct str_list_entry_t, entry ) |
| { |
| print_file( f, 1, "{ (const unsigned char *)\"" ); |
| for (p = endpoint->str; *p && *p != ':'; p++) |
| { |
| if (*p == '"' || *p == '\\') fputc( '\\', f ); |
| fputc( *p, f ); |
| } |
| if (!*p) goto error; |
| if (p[1] != '[') goto error; |
| |
| fprintf( f, "\", (const unsigned char *)\"" ); |
| for (p += 2; *p && *p != ']'; p++) |
| { |
| if (*p == '"' || *p == '\\') fputc( '\\', f ); |
| fputc( *p, f ); |
| } |
| if (*p != ']') goto error; |
| fprintf( f, "\" },\n" ); |
| } |
| print_file( f, 0, "};\n\n" ); |
| return; |
| |
| error: |
| error("Invalid endpoint syntax '%s'\n", endpoint->str); |
| } |