Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- tools/widl/expr.c | 1 + tools/widl/header.c | 16 +++++++++----- tools/widl/parser.l | 1 + tools/widl/parser.y | 20 +++++++++++++++++ tools/widl/typegen.c | 4 ++++ tools/widl/typelib.c | 1 + tools/widl/typetree.c | 49 ++++++++++++++++++++++++++++++++++++++++++ tools/widl/typetree.h | 10 +++++++++ tools/widl/widltypes.h | 7 ++++++ 9 files changed, 104 insertions(+), 5 deletions(-)
diff --git a/tools/widl/expr.c b/tools/widl/expr.c index c83e9aa5ec0..88d59290d6b 100644 --- a/tools/widl/expr.c +++ b/tools/widl/expr.c @@ -466,6 +466,7 @@ static type_t *find_identifier(const char *identifier, const type_t *cont_type, case TYPE_RUNTIMECLASS: case TYPE_PARAMETERIZED_TYPE: case TYPE_PARAMETER: + case TYPE_DELEGATE: /* nothing to do */ break; case TYPE_ALIAS: diff --git a/tools/widl/header.c b/tools/widl/header.c index f0f2b39073b..3c8ad09bd63 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -470,6 +470,9 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i case TYPE_RUNTIMECLASS: fprintf(h, "%s", type_get_name(type_runtimeclass_get_default_iface(t), name_type)); break; + case TYPE_DELEGATE: + fprintf(h, "%s", type_get_name(type_delegate_get_iface(t), name_type)); + break; case TYPE_VOID: fprintf(h, "void"); break; @@ -555,6 +558,7 @@ void write_type_right(FILE *h, type_t *t, int is_field) case TYPE_COCLASS: case TYPE_INTERFACE: case TYPE_RUNTIMECLASS: + case TYPE_DELEGATE: break; case TYPE_APICONTRACT: case TYPE_PARAMETERIZED_TYPE: @@ -974,7 +978,7 @@ int has_out_arg_or_return(const var_t *func) int is_object(const type_t *iface) { const attr_t *attr; - if (type_is_defined(iface) && type_iface_get_inherit(iface)) + if (type_is_defined(iface) && (type_get_type(iface) == TYPE_DELEGATE || type_iface_get_inherit(iface))) return 1; if (iface->attrs) LIST_FOR_EACH_ENTRY( attr, iface->attrs, const attr_t, entry ) if (attr->type == ATTR_OBJECT || attr->type == ATTR_ODL) return 1; @@ -1799,9 +1803,10 @@ static void write_forward_decls(FILE *header, const statement_list_t *stmts) switch (stmt->type) { case STMT_TYPE: - if (type_get_type(stmt->u.type) == TYPE_INTERFACE) + if (type_get_type(stmt->u.type) == TYPE_INTERFACE || type_get_type(stmt->u.type) == TYPE_DELEGATE) { type_t *iface = stmt->u.type; + if (type_get_type(iface) == TYPE_DELEGATE) iface = type_delegate_get_iface(iface); if (is_object(iface) || is_attr(iface->attrs, ATTR_DISPINTERFACE)) { write_forward(header, iface); @@ -1841,10 +1846,11 @@ static void write_header_stmts(FILE *header, const statement_list_t *stmts, cons switch (stmt->type) { case STMT_TYPE: - if (type_get_type(stmt->u.type) == TYPE_INTERFACE) + if (type_get_type(stmt->u.type) == TYPE_INTERFACE || type_get_type(stmt->u.type) == TYPE_DELEGATE) { - type_t *iface = stmt->u.type; - type_t *async_iface = type_iface_get_async_iface(iface); + type_t *iface = stmt->u.type, *async_iface; + if (type_get_type(stmt->u.type) == TYPE_DELEGATE) iface = type_delegate_get_iface(iface); + async_iface = type_iface_get_async_iface(iface); if (is_object(iface)) is_object_interface++; if (is_attr(stmt->u.type->attrs, ATTR_DISPINTERFACE) || is_object(stmt->u.type)) { diff --git a/tools/widl/parser.l b/tools/widl/parser.l index 741e9cbcfca..4d3b9d683e8 100644 --- a/tools/widl/parser.l +++ b/tools/widl/parser.l @@ -278,6 +278,7 @@ static const struct keyword keywords[] = { {"cpp_quote", tCPPQUOTE, 0}, {"declare", tDECLARE, 1}, {"default", tDEFAULT, 0}, + {"delegate", tDELEGATE, 1}, {"dispinterface", tDISPINTERFACE, 0}, {"double", tDOUBLE, 0}, {"enum", tENUM, 0}, diff --git a/tools/widl/parser.y b/tools/widl/parser.y index cc849619ce8..16d2e0023b7 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -106,6 +106,7 @@ static statement_t *make_statement_module(type_t *type); static statement_t *make_statement_typedef(var_list_t *names, int declonly); static statement_t *make_statement_import(const char *str); static statement_t *make_statement_parameterized_type(type_t *type, typeref_list_t *params); +static statement_t *make_statement_delegate(type_t *ret, var_list_t *args); static statement_list_t *append_statement(statement_list_t *list, statement_t *stmt); static statement_list_t *append_statements(statement_list_t *, statement_list_t *); static attr_list_t *append_attribs(attr_list_t *, attr_list_t *); @@ -180,6 +181,7 @@ static typelib_t *current_typelib; %token tCUSTOM %token tDECLARE %token tDECODE tDEFAULT tDEFAULTBIND +%token tDELEGATE %token tDEFAULTCOLLELEM %token tDEFAULTVALUE %token tDEFAULTVTABLE @@ -278,6 +280,7 @@ static typelib_t *current_typelib; %type <expr_list> m_exprs /* exprs expr_list */ expr_list_int_const %type <expr> contract_req %type <expr> static_attr +%type <type> delegatedef %type <stgclass> storage_cls_spec %type <type_qualifier> type_qualifier m_type_qual_list %type <function_specifier> function_specifier @@ -384,6 +387,7 @@ gbl_statements: { $$ = NULL; } | gbl_statements interface ';' { $$ = append_statement($1, make_statement_reference($2)); } | gbl_statements dispinterface ';' { $$ = append_statement($1, make_statement_reference($2)); } | gbl_statements interfacedef { $$ = append_statement($1, make_statement_type_decl($2)); } + | gbl_statements delegatedef { $$ = append_statement($1, make_statement_type_decl($2)); } | gbl_statements coclass ';' { $$ = $1; reg_type($2, $2->name, current_namespace, 0); } @@ -408,6 +412,7 @@ imp_statements: { $$ = NULL; } | imp_statements namespacedef '{' { push_namespace($2); } imp_statements '}' { pop_namespace($2); $$ = append_statements($1, $5); } | imp_statements interfacedef { $$ = append_statement($1, make_statement_type_decl($2)); } + | imp_statements delegatedef { $$ = append_statement($1, make_statement_type_decl($2)); } | imp_statements coclass ';' { $$ = $1; reg_type($2, $2->name, current_namespace, 0); } | imp_statements coclassdef { $$ = append_statement($1, make_statement_type_decl($2)); reg_type($2, $2->name, current_namespace, 0); @@ -1029,6 +1034,12 @@ interface: { $$ = type_parameterized_interface_declare($2, current_namespace, $5); } ;
+delegatedef: m_attributes tDELEGATE type ident '(' m_args ')' semicolon_opt + { $$ = type_delegate_declare($4->name, current_namespace); + $$ = type_delegate_define($$, $1, append_statement(NULL, make_statement_delegate($3, $6))); + } + ; + required_types: qualified_type { $$ = append_typeref(NULL, make_typeref($1)); } | parameterized_type { $$ = append_typeref(NULL, make_typeref($1)); } @@ -2663,6 +2674,7 @@ static int is_allowed_conf_type(const type_t *type) case TYPE_INTERFACE: case TYPE_BITFIELD: case TYPE_RUNTIMECLASS: + case TYPE_DELEGATE: return FALSE; case TYPE_APICONTRACT: case TYPE_PARAMETERIZED_TYPE: @@ -3299,6 +3311,14 @@ static statement_t *make_statement_parameterized_type(type_t *type, typeref_list return stmt; }
+static statement_t *make_statement_delegate(type_t *ret, var_list_t *args) +{ + declarator_t *decl = make_declarator(make_var(xstrdup("Invoke"))); + decl_spec_t *spec = make_decl_spec(ret, NULL, NULL, STG_NONE, 0, 0); + append_chain_type(decl, type_new_function(args), 0); + return make_statement_declaration(declare_var(NULL, spec, decl, FALSE)); +} + static statement_list_t *append_statements(statement_list_t *l1, statement_list_t *l2) { if (!l2) return l1; diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c index 6ae55ac1934..2c1017b9f2b 100644 --- a/tools/widl/typegen.c +++ b/tools/widl/typegen.c @@ -354,6 +354,7 @@ enum typegen_type typegen_detect_type(const type_t *type, const attr_list_t *att case TYPE_POINTER: if (type_get_type(type_pointer_get_ref_type(type)) == TYPE_INTERFACE || type_get_type(type_pointer_get_ref_type(type)) == TYPE_RUNTIMECLASS || + type_get_type(type_pointer_get_ref_type(type)) == TYPE_DELEGATE || (type_get_type(type_pointer_get_ref_type(type)) == TYPE_VOID && is_attr(attrs, ATTR_IIDIS))) return TGT_IFACE_POINTER; else if (is_aliaschain_attr(type_pointer_get_ref_type(type), ATTR_CONTEXTHANDLE)) @@ -375,6 +376,7 @@ enum typegen_type typegen_detect_type(const type_t *type, const attr_list_t *att case TYPE_ALIAS: case TYPE_BITFIELD: case TYPE_RUNTIMECLASS: + case TYPE_DELEGATE: break; case TYPE_APICONTRACT: case TYPE_PARAMETERIZED_TYPE: @@ -1978,6 +1980,7 @@ unsigned int type_memsize_and_alignment(const type_t *t, unsigned int *align) case TYPE_RUNTIMECLASS: case TYPE_PARAMETERIZED_TYPE: case TYPE_PARAMETER: + case TYPE_DELEGATE: /* these types should not be encountered here due to language * restrictions (interface, void, coclass, module), logical * restrictions (alias - due to type_get_type call above) or @@ -2083,6 +2086,7 @@ static unsigned int type_buffer_alignment(const type_t *t) case TYPE_RUNTIMECLASS: case TYPE_PARAMETERIZED_TYPE: case TYPE_PARAMETER: + case TYPE_DELEGATE: /* these types should not be encountered here due to language * restrictions (interface, void, coclass, module), logical * restrictions (alias - due to type_get_type call above) or diff --git a/tools/widl/typelib.c b/tools/widl/typelib.c index 6f6c5f3ccc8..8b2a2401367 100644 --- a/tools/widl/typelib.c +++ b/tools/widl/typelib.c @@ -219,6 +219,7 @@ unsigned short get_type_vt(type_t *t) case TYPE_UNION: case TYPE_ENCAPSULATED_UNION: case TYPE_RUNTIMECLASS: + case TYPE_DELEGATE: return VT_USERDEFINED;
case TYPE_VOID: diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 3f90fcbe014..468b81d450d 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -664,6 +664,54 @@ type_t *type_apicontract_define(type_t *apicontract, attr_list_t *attrs) return apicontract; }
+static void compute_delegate_iface_names(type_t *delegate) +{ + type_t *iface = delegate->details.delegate.iface; + iface->namespace = delegate->namespace; + iface->name = strmake("I%s", delegate->name); + iface->c_name = format_namespace(delegate->namespace, "__x_", "_C", iface->name, use_abi_namespace ? "ABI" : NULL); +} + +type_t *type_delegate_declare(char *name, struct namespace *namespace) +{ + type_t *type = get_type(TYPE_DELEGATE, name, NULL, 0); + if (type_get_type_detect_alias(type) != TYPE_DELEGATE) + error_loc("delegate %s previously not declared a delegate at %s:%d\n", + type->name, type->loc_info.input_name, type->loc_info.line_number); + return type; +} + +type_t *type_delegate_define(type_t *delegate, attr_list_t *attrs, statement_list_t *stmts) +{ + type_t *iface; + + if (delegate->defined) + error_loc("delegate %s already defined at %s:%d\n", + delegate->name, delegate->loc_info.input_name, delegate->loc_info.line_number); + + delegate->attrs = check_interface_attrs(delegate->name, attrs); + + iface = make_type(TYPE_INTERFACE); + iface->attrs = delegate->attrs; + iface->details.iface = xmalloc(sizeof(*iface->details.iface)); + iface->details.iface->disp_props = NULL; + iface->details.iface->disp_methods = NULL; + iface->details.iface->stmts = stmts; + iface->details.iface->inherit = find_type("IUnknown", NULL, 0); + if (!iface->details.iface->inherit) error_loc("IUnknown is undefined\n"); + iface->details.iface->disp_inherit = NULL; + iface->details.iface->async_iface = NULL; + iface->details.iface->requires = NULL; + iface->defined = TRUE; + compute_method_indexes(iface); + + delegate->details.delegate.iface = iface; + delegate->defined = TRUE; + compute_delegate_iface_names(delegate); + + return delegate; +} + type_t *type_parameterized_interface_declare(char *name, struct namespace *namespace, typeref_list_t *params) { type_t *type = get_type(TYPE_PARAMETERIZED_TYPE, name, namespace, 0); @@ -821,6 +869,7 @@ static type_t *replace_type_parameters_in_type(type_t *type, typeref_list_t *ori case TYPE_BITFIELD: case TYPE_INTERFACE: case TYPE_RUNTIMECLASS: + case TYPE_DELEGATE: return type; case TYPE_PARAMETER: if (!orig || !repl) return NULL; diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h index 4f2d39a0434..c2b3b6c90c6 100644 --- a/tools/widl/typetree.h +++ b/tools/widl/typetree.h @@ -64,6 +64,8 @@ type_t *type_coclass_define(type_t *coclass, attr_list_t *attrs, typeref_list_t type_t *type_runtimeclass_define(type_t *runtimeclass, attr_list_t *attrs, typeref_list_t *ifaces); type_t *type_apicontract_declare(char *name, struct namespace *namespace); type_t *type_apicontract_define(type_t *apicontract, attr_list_t *attrs); +type_t *type_delegate_declare(char *name, struct namespace *namespace); +type_t *type_delegate_define(type_t *delegate, attr_list_t *attrs, statement_list_t *stmts); type_t *type_parameterized_interface_declare(char *name, struct namespace *namespace, typeref_list_t *params); type_t *type_parameterized_interface_define(type_t *type, attr_list_t *attrs, type_t *inherit, statement_list_t *stmts, typeref_list_t *requires); type_t *type_parameterized_type_specialize_partial(type_t *type, typeref_list_t *params); @@ -254,6 +256,7 @@ static inline int type_is_complete(const type_t *type) case TYPE_ARRAY: case TYPE_BITFIELD: case TYPE_RUNTIMECLASS: + case TYPE_DELEGATE: return TRUE; case TYPE_APICONTRACT: case TYPE_PARAMETERIZED_TYPE: @@ -376,6 +379,13 @@ static inline type_t *type_runtimeclass_get_default_iface(const type_t *type) return NULL; }
+static inline type_t *type_delegate_get_iface(const type_t *type) +{ + type = type_get_real_type(type); + assert(type_get_type(type) == TYPE_DELEGATE); + return type->details.delegate.iface; +} + static inline const decl_spec_t *type_pointer_get_ref(const type_t *type) { type = type_get_real_type(type); diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h index 777aabc78ff..e07aeddf511 100644 --- a/tools/widl/widltypes.h +++ b/tools/widl/widltypes.h @@ -441,6 +441,11 @@ struct parameterized_details typeref_list_t *params; };
+struct delegate_details +{ + type_t *iface; +}; + #define HASHMAX 64
struct namespace { @@ -471,6 +476,7 @@ enum type_type TYPE_RUNTIMECLASS, TYPE_PARAMETERIZED_TYPE, TYPE_PARAMETER, + TYPE_DELEGATE, };
struct _type_t { @@ -493,6 +499,7 @@ struct _type_t { struct alias_details alias; struct runtimeclass_details runtimeclass; struct parameterized_details parameterized; + struct delegate_details delegate; } details; const char *c_name; unsigned int typestring_offset;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/windows.foundation.idl | 6 +++ tools/widl/parser.y | 6 +++ tools/widl/typetree.c | 76 ++++++++++++++++++++++++++++++---- tools/widl/typetree.h | 2 + 4 files changed, 82 insertions(+), 8 deletions(-)
diff --git a/include/windows.foundation.idl b/include/windows.foundation.idl index 5f7a49c38e4..bb0fafcab77 100644 --- a/include/windows.foundation.idl +++ b/include/windows.foundation.idl @@ -113,6 +113,12 @@ namespace Windows { }
#ifdef __WIDL__ + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(9de1c535-6ae1-11e0-84e1-18a905bcc53f) + ] + delegate HRESULT EventHandler<T>([in] IInspectable *sender, [in] T args); + namespace Collections { [ diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 16d2e0023b7..57e7809fc1a 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -1038,6 +1038,12 @@ delegatedef: m_attributes tDELEGATE type ident '(' m_args ')' semicolon_opt { $$ = type_delegate_declare($4->name, current_namespace); $$ = type_delegate_define($$, $1, append_statement(NULL, make_statement_delegate($3, $6))); } + | m_attributes tDELEGATE type ident + '<' { push_parameters_namespace($4->name); } type_parameters '>' + '(' m_args ')' { pop_parameters_namespace($4->name); } semicolon_opt + { $$ = type_parameterized_delegate_declare($4->name, current_namespace, $7); + $$ = type_parameterized_delegate_define($$, $1, append_statement(NULL, make_statement_delegate($3, $10))); + } ;
required_types: diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 468b81d450d..0a63b7ebf7f 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -142,15 +142,15 @@ static char const *parameterized_type_shorthands[][2] = { {"Windows_CFoundation_C", "__F"}, };
-static char *format_parameterized_type_c_name(type_t *type, typeref_list_t *params) +static char *format_parameterized_type_c_name(type_t *type, typeref_list_t *params, const char *prefix) { size_t len = 0, pos = 0; char *buf = NULL, *tmp; int i, count = params ? list_count(params) : 0; typeref_t *ref;
- pos += append_namespaces(&buf, &len, pos, type->namespace, "__x_", "_C", type->name, use_abi_namespace ? "ABI" : NULL); - pos += strappend(&buf, &len, pos, "_%d", count); + pos += append_namespaces(&buf, &len, pos, type->namespace, "__x_", "_C", "", use_abi_namespace ? "ABI" : NULL); + pos += strappend(&buf, &len, pos, "%s%s_%d", prefix, type->name, count); if (params) LIST_FOR_EACH_ENTRY(ref, params, typeref_t, entry) { for (type = ref->type; type->type_type == TYPE_POINTER; type = type_pointer_get_ref_type(type)) {} @@ -664,12 +664,13 @@ type_t *type_apicontract_define(type_t *apicontract, attr_list_t *attrs) return apicontract; }
-static void compute_delegate_iface_names(type_t *delegate) +static void compute_delegate_iface_names(type_t *delegate, type_t *type, typeref_list_t *params) { type_t *iface = delegate->details.delegate.iface; iface->namespace = delegate->namespace; iface->name = strmake("I%s", delegate->name); - iface->c_name = format_namespace(delegate->namespace, "__x_", "_C", iface->name, use_abi_namespace ? "ABI" : NULL); + if (type) iface->c_name = format_parameterized_type_c_name(type, params, "I"); + else iface->c_name = format_namespace(delegate->namespace, "__x_", "_C", iface->name, use_abi_namespace ? "ABI" : NULL); }
type_t *type_delegate_declare(char *name, struct namespace *namespace) @@ -707,7 +708,7 @@ type_t *type_delegate_define(type_t *delegate, attr_list_t *attrs, statement_lis
delegate->details.delegate.iface = iface; delegate->defined = TRUE; - compute_delegate_iface_names(delegate); + compute_delegate_iface_names(delegate, NULL, NULL);
return delegate; } @@ -751,6 +752,46 @@ type_t *type_parameterized_interface_define(type_t *type, attr_list_t *attrs, ty return type; }
+type_t *type_parameterized_delegate_declare(char *name, struct namespace *namespace, typeref_list_t *params) +{ + type_t *type = get_type(TYPE_PARAMETERIZED_TYPE, name, namespace, 0); + if (type_get_type_detect_alias(type) != TYPE_PARAMETERIZED_TYPE) + error_loc("pdelegate %s previously not declared a pdelegate at %s:%d\n", + type->name, type->loc_info.input_name, type->loc_info.line_number); + type->details.parameterized.type = make_type(TYPE_DELEGATE); + type->details.parameterized.params = params; + return type; +} + +type_t *type_parameterized_delegate_define(type_t *type, attr_list_t *attrs, statement_list_t *stmts) +{ + type_t *iface, *delegate; + + if (type->defined) + error_loc("pdelegate %s already defined at %s:%d\n", + type->name, type->loc_info.input_name, type->loc_info.line_number); + + type->attrs = check_interface_attrs(type->name, attrs); + + delegate = type->details.parameterized.type; + delegate->attrs = type->attrs; + delegate->details.delegate.iface = make_type(TYPE_INTERFACE); + + iface = delegate->details.delegate.iface; + iface->details.iface = xmalloc(sizeof(*iface->details.iface)); + iface->details.iface->disp_props = NULL; + iface->details.iface->disp_methods = NULL; + iface->details.iface->stmts = stmts; + iface->details.iface->inherit = find_type("IUnknown", NULL, 0); + if (!iface->details.iface->inherit) error_loc("IUnknown is undefined\n"); + iface->details.iface->disp_inherit = NULL; + iface->details.iface->async_iface = NULL; + iface->details.iface->requires = NULL; + + type->defined = TRUE; + return type; +} + type_t *type_parameterized_type_specialize_partial(type_t *type, typeref_list_t *params) { type_t *new_type = duptype(type, 0); @@ -932,6 +973,11 @@ static void type_parameterized_interface_specialize(type_t *tmpl, type_t *iface, iface->details.iface->requires = NULL; }
+static void type_parameterized_delegate_specialize(type_t *tmpl, type_t *delegate, typeref_list_t *orig, typeref_list_t *repl) +{ + type_parameterized_interface_specialize(tmpl->details.delegate.iface, delegate->details.delegate.iface, orig, repl); +} + type_t *type_parameterized_type_specialize_declare(type_t *type, typeref_list_t *params) { type_t *tmpl = type->details.parameterized.type; @@ -940,7 +986,13 @@ type_t *type_parameterized_type_specialize_declare(type_t *type, typeref_list_t new_type->namespace = type->namespace; new_type->name = format_parameterized_type_name(type, params); reg_type(new_type, new_type->name, new_type->namespace, 0); - new_type->c_name = format_parameterized_type_c_name(type, params); + new_type->c_name = format_parameterized_type_c_name(type, params, ""); + + if (new_type->type_type == TYPE_DELEGATE) + { + new_type->details.delegate.iface = duptype(tmpl->details.delegate.iface, 0); + compute_delegate_iface_names(new_type, type, params); + }
return new_type; } @@ -960,11 +1012,19 @@ type_t *type_parameterized_type_specialize_define(type_t *type) if (type_get_type_detect_alias(tmpl->details.parameterized.type) == TYPE_INTERFACE && type_get_type_detect_alias(iface) == TYPE_INTERFACE) type_parameterized_interface_specialize(tmpl->details.parameterized.type, iface, orig, repl); + else if (type_get_type_detect_alias(tmpl->details.parameterized.type) == TYPE_DELEGATE && + type_get_type_detect_alias(iface) == TYPE_DELEGATE) + type_parameterized_delegate_specialize(tmpl->details.parameterized.type, iface, orig, repl); else - error_loc("pinterface %s previously not declared a pinterface at %s:%d\n", + error_loc("pinterface/pdelegate %s previously not declared a pinterface/pdelegate at %s:%d\n", iface->name, iface->loc_info.input_name, iface->loc_info.line_number);
iface->defined = TRUE; + if (iface->type_type == TYPE_DELEGATE) + { + iface = iface->details.delegate.iface; + iface->defined = TRUE; + } compute_method_indexes(iface); return iface; } diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h index c2b3b6c90c6..8130174fe2a 100644 --- a/tools/widl/typetree.h +++ b/tools/widl/typetree.h @@ -68,6 +68,8 @@ type_t *type_delegate_declare(char *name, struct namespace *namespace); type_t *type_delegate_define(type_t *delegate, attr_list_t *attrs, statement_list_t *stmts); type_t *type_parameterized_interface_declare(char *name, struct namespace *namespace, typeref_list_t *params); type_t *type_parameterized_interface_define(type_t *type, attr_list_t *attrs, type_t *inherit, statement_list_t *stmts, typeref_list_t *requires); +type_t *type_parameterized_delegate_declare(char *name, struct namespace *namespace, typeref_list_t *params); +type_t *type_parameterized_delegate_define(type_t *type, attr_list_t *attrs, statement_list_t *stmts); type_t *type_parameterized_type_specialize_partial(type_t *type, typeref_list_t *params); type_t *type_parameterized_type_specialize_declare(type_t *type, typeref_list_t *params); type_t *type_parameterized_type_specialize_define(type_t *type);
Signed-off-by: Jacek Cabanjacek@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- tools/widl/typetree.c | 149 +++++++++++++++++++++++++++++++++++++++++ tools/widl/widltypes.h | 1 + 2 files changed, 150 insertions(+)
diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 0a63b7ebf7f..3db88945058 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -49,6 +49,7 @@ type_t *make_type(enum type_type type) t->type_type = type; t->attrs = NULL; t->c_name = NULL; + t->signature = NULL; memset(&t->details, 0, sizeof(t->details)); t->typestring_offset = 0; t->ptrdesc = 0; @@ -110,6 +111,128 @@ static size_t append_namespaces(char **buf, size_t *len, size_t pos, struct name return n; }
+static size_t append_type_signature(char **buf, size_t *len, size_t pos, type_t *type); + +static size_t append_var_list_signature(char **buf, size_t *len, size_t pos, var_list_t *var_list) +{ + var_t *var; + size_t n = 0; + + if (!var_list) n += strappend(buf, len, pos + n, ";"); + else LIST_FOR_EACH_ENTRY(var, var_list, var_t, entry) + { + n += strappend(buf, len, pos + n, ";"); + n += append_type_signature(buf, len, pos + n, var->declspec.type); + } + + return n; +} + +static size_t append_type_signature(char **buf, size_t *len, size_t pos, type_t *type) +{ + const GUID *uuid; + size_t n = 0; + + if (!type) return 0; + switch (type->type_type) + { + case TYPE_INTERFACE: + if (type->signature) n += strappend(buf, len, pos + n, "%s", type->signature); + else + { + if (!(uuid = get_attrp(type->attrs, ATTR_UUID))) + error_loc_info(&type->loc_info, "cannot compute type signature, no uuid found for type %s.\n", type->name); + + n += strappend(buf, len, pos + n, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + uuid->Data1, uuid->Data2, uuid->Data3, + uuid->Data4[0], uuid->Data4[1], uuid->Data4[2], uuid->Data4[3], + uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], uuid->Data4[7]); + } + return n; + case TYPE_DELEGATE: + n += strappend(buf, len, pos + n, "delegate("); + n += append_type_signature(buf, len, pos + n, type_delegate_get_iface(type)); + n += strappend(buf, len, pos + n, ")"); + return n; + case TYPE_RUNTIMECLASS: + n += strappend(buf, len, pos + n, "rc("); + n += append_namespaces(buf, len, pos + n, type->namespace, "", ".", type->name, NULL); + n += strappend(buf, len, pos + n, ";"); + n += append_type_signature(buf, len, pos + n, type_runtimeclass_get_default_iface(type)); + n += strappend(buf, len, pos + n, ")"); + return n; + case TYPE_POINTER: + n += append_type_signature(buf, len, pos + n, type->details.pointer.ref.type); + return n; + case TYPE_ALIAS: + if (!strcmp(type->name, "boolean")) n += strappend(buf, len, pos + n, "b1"); + else n += append_type_signature(buf, len, pos + n, type->details.alias.aliasee.type); + return n; + case TYPE_STRUCT: + n += strappend(buf, len, pos + n, "struct("); + n += append_namespaces(buf, len, pos + n, type->namespace, "", ".", type->name, NULL); + n += append_var_list_signature(buf, len, pos + n, type->details.structure->fields); + n += strappend(buf, len, pos + n, ")"); + return n; + case TYPE_BASIC: + switch (type_basic_get_type(type)) + { + case TYPE_BASIC_INT: + case TYPE_BASIC_INT32: + n += strappend(buf, len, pos + n, type_basic_get_sign(type) < 0 ? "i4" : "u4"); + return n; + case TYPE_BASIC_INT64: + n += strappend(buf, len, pos + n, type_basic_get_sign(type) < 0 ? "i8" : "u8"); + return n; + case TYPE_BASIC_INT8: + assert(type_basic_get_sign(type) >= 0); /* signature string for signed char isn't specified */ + n += strappend(buf, len, pos + n, "u1"); + return n; + case TYPE_BASIC_FLOAT: + n += strappend(buf, len, pos + n, "f4"); + return n; + case TYPE_BASIC_DOUBLE: + n += strappend(buf, len, pos + n, "f8"); + return n; + case TYPE_BASIC_INT16: + case TYPE_BASIC_INT3264: + case TYPE_BASIC_LONG: + case TYPE_BASIC_CHAR: + case TYPE_BASIC_HYPER: + case TYPE_BASIC_BYTE: + case TYPE_BASIC_WCHAR: + case TYPE_BASIC_ERROR_STATUS_T: + case TYPE_BASIC_HANDLE: + error_loc_info(&type->loc_info, "unimplemented type signature for basic type %d.\n", type_basic_get_type(type)); + break; + } + case TYPE_ENUM: + n += strappend(buf, len, pos + n, "enum("); + n += append_namespaces(buf, len, pos + n, type->namespace, "", ".", type->name, NULL); + if (is_attr(type->attrs, ATTR_FLAGS)) n += strappend(buf, len, pos + n, ";u4"); + else n += strappend(buf, len, pos + n, ";i4"); + n += strappend(buf, len, pos + n, ")"); + return n; + case TYPE_ARRAY: + case TYPE_ENCAPSULATED_UNION: + case TYPE_UNION: + case TYPE_COCLASS: + case TYPE_VOID: + case TYPE_FUNCTION: + case TYPE_BITFIELD: + case TYPE_MODULE: + case TYPE_APICONTRACT: + error_loc_info(&type->loc_info, "unimplemented type signature for type %s of type %d.\n", type->name, type->type_type); + break; + case TYPE_PARAMETERIZED_TYPE: + case TYPE_PARAMETER: + assert(0); /* should not be there */ + break; + } + + return n; +} + char *format_namespace(struct namespace *namespace, const char *prefix, const char *separator, const char *suffix, const char *abi_prefix) { size_t len = 0; @@ -171,6 +294,30 @@ static char *format_parameterized_type_c_name(type_t *type, typeref_list_t *para return buf; }
+static char *format_parameterized_type_signature(type_t *type, typeref_list_t *params) +{ + size_t len = 0, pos = 0; + char *buf = NULL; + typeref_t *ref; + const GUID *uuid; + + if (!(uuid = get_attrp(type->attrs, ATTR_UUID))) + error_loc_info(&type->loc_info, "cannot compute type signature, no uuid found for type %s.\n", type->name); + + pos += strappend(&buf, &len, pos, "pinterface({%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + uuid->Data1, uuid->Data2, uuid->Data3, + uuid->Data4[0], uuid->Data4[1], uuid->Data4[2], uuid->Data4[3], + uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], uuid->Data4[7]); + if (params) LIST_FOR_EACH_ENTRY(ref, params, typeref_t, entry) + { + pos += strappend(&buf, &len, pos, ";"); + pos += append_type_signature(&buf, &len, pos, ref->type); + } + pos += strappend(&buf, &len, pos, ")"); + + return buf; +} + type_t *type_new_function(var_list_t *args) { var_t *arg; @@ -1019,10 +1166,12 @@ type_t *type_parameterized_type_specialize_define(type_t *type) error_loc("pinterface/pdelegate %s previously not declared a pinterface/pdelegate at %s:%d\n", iface->name, iface->loc_info.input_name, iface->loc_info.line_number);
+ iface->signature = format_parameterized_type_signature(type, repl); iface->defined = TRUE; if (iface->type_type == TYPE_DELEGATE) { iface = iface->details.delegate.iface; + iface->signature = format_parameterized_type_signature(type, repl); iface->defined = TRUE; } compute_method_indexes(iface); diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h index e07aeddf511..e01bd122b45 100644 --- a/tools/widl/widltypes.h +++ b/tools/widl/widltypes.h @@ -502,6 +502,7 @@ struct _type_t { struct delegate_details delegate; } details; const char *c_name; + const char *signature; unsigned int typestring_offset; unsigned int ptrdesc; /* used for complex structs */ int typelib_idx;
Signed-off-by: Jacek Cabanjacek@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- tools/widl/hash.c | 178 ++++++++++++++++++++++++++++++++++++++++++ tools/widl/hash.h | 14 ++++ tools/widl/parser.y | 6 +- tools/widl/typetree.c | 40 ++++++++++ tools/widl/typetree.h | 2 + 5 files changed, 236 insertions(+), 4 deletions(-)
diff --git a/tools/widl/hash.c b/tools/widl/hash.c index 15ec88001d6..df6133866e0 100644 --- a/tools/widl/hash.c +++ b/tools/widl/hash.c @@ -639,3 +639,181 @@ unsigned int lhash_val_of_name_sys( syskind_t skind, LCID lcid, LPCSTR lpStr)
return nHiWord | nLoWord; } + +/* SHA1 algorithm + * + * Based on public domain SHA code by Steve Reid steve@edmweb.com + */ + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) +/* FIXME: This definition of DWORD2BE is little endian specific! */ +#define DWORD2BE(x) (((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000); +/* FIXME: This definition of blk0 is little endian specific! */ +#define blk0(i) (Block[i] = (rol(Block[i],24)&0xFF00FF00)|(rol(Block[i],8)&0x00FF00FF)) +#define blk1(i) (Block[i&15] = rol(Block[(i+13)&15]^Block[(i+8)&15]^Block[(i+2)&15]^Block[i&15],1)) +#define f1(x,y,z) (z^(x&(y^z))) +#define f2(x,y,z) (x^y^z) +#define f3(x,y,z) ((x&y)|(z&(x|y))) +#define f4(x,y,z) (x^y^z) +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +static void SHA1Transform(ULONG State[5], UCHAR Buffer[64]) +{ + ULONG a, b, c, d, e; + ULONG *Block; + + Block = (ULONG*)Buffer; + + /* Copy Context->State[] to working variables */ + a = State[0]; + b = State[1]; + c = State[2]; + d = State[3]; + e = State[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working variables back into Context->State[] */ + State[0] += a; + State[1] += b; + State[2] += c; + State[3] += d; + State[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/****************************************************************************** + * A_SHAInit (ntdll.@) + * + * Initialize a SHA context structure. + * + * PARAMS + * Context [O] SHA context + * + * RETURNS + * Nothing + */ +void A_SHAInit(SHA_CTX *Context) +{ + /* SHA1 initialization constants */ + Context->State[0] = 0x67452301; + Context->State[1] = 0xEFCDAB89; + Context->State[2] = 0x98BADCFE; + Context->State[3] = 0x10325476; + Context->State[4] = 0xC3D2E1F0; + Context->Count[0] = + Context->Count[1] = 0; +} + +/****************************************************************************** + * A_SHAUpdate (ntdll.@) + * + * Update a SHA context with a hashed data from supplied buffer. + * + * PARAMS + * Context [O] SHA context + * Buffer [I] hashed data + * BufferSize [I] hashed data size + * + * RETURNS + * Nothing + */ +void A_SHAUpdate(SHA_CTX *Context, const unsigned char *Buffer, UINT BufferSize) +{ + ULONG BufferContentSize; + + BufferContentSize = Context->Count[1] & 63; + Context->Count[1] += BufferSize; + if (Context->Count[1] < BufferSize) + Context->Count[0]++; + Context->Count[0] += (BufferSize >> 29); + + if (BufferContentSize + BufferSize < 64) + { + RtlCopyMemory(&Context->Buffer[BufferContentSize], Buffer, + BufferSize); + } + else + { + while (BufferContentSize + BufferSize >= 64) + { + RtlCopyMemory(Context->Buffer + BufferContentSize, Buffer, + 64 - BufferContentSize); + Buffer += 64 - BufferContentSize; + BufferSize -= 64 - BufferContentSize; + SHA1Transform(Context->State, Context->Buffer); + BufferContentSize = 0; + } + RtlCopyMemory(Context->Buffer + BufferContentSize, Buffer, BufferSize); + } +} + +/****************************************************************************** + * A_SHAFinal (ntdll.@) + * + * Finalize SHA context and return the resulting hash. + * + * PARAMS + * Context [I/O] SHA context + * Result [O] resulting hash + * + * RETURNS + * Nothing + */ +void A_SHAFinal(SHA_CTX *Context, PULONG Result) +{ + INT Pad, Index; + UCHAR Buffer[72]; + ULONG *Count; + ULONG BufferContentSize, LengthHi, LengthLo; + + BufferContentSize = Context->Count[1] & 63; + if (BufferContentSize >= 56) + Pad = 56 + 64 - BufferContentSize; + else + Pad = 56 - BufferContentSize; + + LengthHi = (Context->Count[0] << 3) | (Context->Count[1] >> (32 - 3)); + LengthLo = (Context->Count[1] << 3); + + RtlZeroMemory(Buffer + 1, Pad - 1); + Buffer[0] = 0x80; + Count = (ULONG*)(Buffer + Pad); + Count[0] = DWORD2BE(LengthHi); + Count[1] = DWORD2BE(LengthLo); + A_SHAUpdate(Context, Buffer, Pad + 8); + + for (Index = 0; Index < 5; Index++) + Result[Index] = DWORD2BE(Context->State[Index]); + + A_SHAInit(Context); +} diff --git a/tools/widl/hash.h b/tools/widl/hash.h index 3c2fd2914bf..208b193ac87 100644 --- a/tools/widl/hash.h +++ b/tools/widl/hash.h @@ -22,6 +22,20 @@ #ifndef __WIDL_HASH_H #define __WIDL_HASH_H
+#include "windef.h" + extern unsigned int lhash_val_of_name_sys( syskind_t skind, LCID lcid, LPCSTR lpStr);
+typedef struct +{ + ULONG Unknown[6]; + ULONG State[5]; + ULONG Count[2]; + UCHAR Buffer[64]; +} SHA_CTX; + +VOID A_SHAInit(SHA_CTX *ctx); +VOID A_SHAUpdate(SHA_CTX *ctx, const UCHAR *buffer, UINT size); +VOID A_SHAFinal(SHA_CTX *ctx, PULONG result); + #endif diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 57e7809fc1a..4c115adf4ab 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -45,13 +45,11 @@ struct _import_t };
static str_list_t *append_str(str_list_t *list, char *str); -static attr_list_t *append_attr(attr_list_t *list, attr_t *attr); static attr_list_t *append_attr_list(attr_list_t *new_list, attr_list_t *old_list); static decl_spec_t *make_decl_spec(type_t *type, decl_spec_t *left, decl_spec_t *right, enum storage_class stgclass, enum type_qualifier qual, enum function_specifier func_specifier); static attr_t *make_attr(enum attr_type type); static attr_t *make_attrv(enum attr_type type, unsigned int val); -static attr_t *make_attrp(enum attr_type type, void *val); static attr_t *make_custom_attr(UUID *id, expr_t *pval); static expr_list_t *append_expr(expr_list_t *list, expr_t *expr); static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, declarator_t *decl, int top); @@ -1507,7 +1505,7 @@ static attr_t *make_attrv(enum attr_type type, unsigned int val) return a; }
-static attr_t *make_attrp(enum attr_type type, void *val) +attr_t *make_attrp(enum attr_type type, void *val) { attr_t *a = xmalloc(sizeof(attr_t)); a->type = type; @@ -2407,7 +2405,7 @@ struct allowed_attr allowed_attr[] = /* ATTR_WIREMARSHAL */ { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "wire_marshal" }, };
-static attr_list_t *append_attr(attr_list_t *list, attr_t *attr) +attr_list_t *append_attr(attr_list_t *list, attr_t *attr) { attr_t *attr_existing; if (!attr) return list; diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 3db88945058..9a2d3f3c053 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -29,6 +29,7 @@ #include "parser.h" #include "typetree.h" #include "header.h" +#include "hash.h"
type_t *duptype(type_t *t, int dupname) { @@ -1144,6 +1145,44 @@ type_t *type_parameterized_type_specialize_declare(type_t *type, typeref_list_t return new_type; }
+static void compute_interface_signature_uuid(type_t *iface) +{ + static unsigned char const wrt_pinterface_namespace[] = {0x11,0xf4,0x7a,0xd5,0x7b,0x73,0x42,0xc0,0xab,0xae,0x87,0x8b,0x1e,0x16,0xad,0xee}; + static const int version = 5; + unsigned char hash[20]; + SHA_CTX sha_ctx; + GUID *uuid; + + if (!(uuid = get_attrp(iface->attrs, ATTR_UUID))) + { + uuid = xmalloc(sizeof(GUID)); + iface->attrs = append_attr(iface->attrs, make_attrp(ATTR_UUID, uuid)); + } + + A_SHAInit(&sha_ctx); + A_SHAUpdate(&sha_ctx, wrt_pinterface_namespace, sizeof(wrt_pinterface_namespace)); + A_SHAUpdate(&sha_ctx, (const UCHAR *)iface->signature, strlen(iface->signature)); + A_SHAFinal(&sha_ctx, (ULONG *)hash); + + /* https://tools.ietf.org/html/rfc4122: + + * Set the four most significant bits (bits 12 through 15) of the + time_hi_and_version field to the appropriate 4-bit version number + from Section 4.1.3. + + * Set the two most significant bits (bits 6 and 7) of the + clock_seq_hi_and_reserved to zero and one, respectively. + */ + + hash[6] = ((hash[6] & 0x0f) | (version << 4)); + hash[8] = ((hash[8] & 0x3f) | 0x80); + + uuid->Data1 = ((DWORD)hash[0] << 24)|((DWORD)hash[1] << 16)|((DWORD)hash[2] << 8)|(DWORD)hash[3]; + uuid->Data2 = ((WORD)hash[4] << 8)|(WORD)hash[5]; + uuid->Data3 = ((WORD)hash[6] << 8)|(WORD)hash[7]; + memcpy(&uuid->Data4, hash + 8, sizeof(*uuid) - offsetof(GUID, Data4)); +} + type_t *type_parameterized_type_specialize_define(type_t *type) { type_t *tmpl = type->details.parameterized.type; @@ -1174,6 +1213,7 @@ type_t *type_parameterized_type_specialize_define(type_t *type) iface->signature = format_parameterized_type_signature(type, repl); iface->defined = TRUE; } + compute_interface_signature_uuid(iface); compute_method_indexes(iface); return iface; } diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h index 8130174fe2a..c8bccc2fec9 100644 --- a/tools/widl/typetree.h +++ b/tools/widl/typetree.h @@ -80,6 +80,8 @@ extern int is_attr(const attr_list_t *list, enum attr_type t);
typeref_t *make_typeref(type_t *type); typeref_list_t *append_typeref(typeref_list_t *list, typeref_t *ref); +attr_t *make_attrp(enum attr_type type, void *val); +attr_list_t *append_attr(attr_list_t *list, attr_t *attr);
/* FIXME: shouldn't need to export this */ type_t *duptype(type_t *t, int dupname);
Hi Rémi,
On 18/02/2021 10:39, Rémi Bernon wrote:
+/* SHA1 algorithm
- Based on public domain SHA code by Steve Reidsteve@edmweb.com
- */
A bit more adaptation of the code would be nice, bellow are a few suggestions.
+/******************************************************************************
- A_SHAInit (ntdll.@)
It looks like a copy&paste typo. There are a few more 'ntdll's in the patch. (And as a side note, the whole comment does not feel more informative to me than the function name itself, especially if you renamed it to something like sha1_init).
- Initialize a SHA context structure.
- PARAMS
- Context [O] SHA context
- RETURNS
- Nothing
- */
(...)
+}
+/******************************************************************************
- A_SHAUpdate (ntdll.@)
- Update a SHA context with a hashed data from supplied buffer.
- PARAMS
- Context [O] SHA context
- Buffer [I] hashed data
- BufferSize [I] hashed data size
- RETURNS
- Nothing
- */
+void A_SHAUpdate(SHA_CTX *Context, const unsigned char *Buffer, UINT BufferSize) +{
- ULONG BufferContentSize;
- BufferContentSize = Context->Count[1] & 63;
- Context->Count[1] += BufferSize;
- if (Context->Count[1] < BufferSize)
Context->Count[0]++;
- Context->Count[0] += (BufferSize >> 29);
- if (BufferContentSize + BufferSize < 64)
- {
RtlCopyMemory(&Context->Buffer[BufferContentSize], Buffer,
BufferSize);
memcpy() would be more consistent with the rest of widl.
Thanks,
Jacek
On 2/18/21 11:27 AM, Jacek Caban wrote:
Hi Rémi,
On 18/02/2021 10:39, Rémi Bernon wrote:
+/* SHA1 algorithm
- Based on public domain SHA code by Steve Reidsteve@edmweb.com
- */
A bit more adaptation of the code would be nice, bellow are a few suggestions.
+/******************************************************************************
- A_SHAInit (ntdll.@)
It looks like a copy&paste typo. There are a few more 'ntdll's in the patch. (And as a side note, the whole comment does not feel more informative to me than the function name itself, especially if you renamed it to something like sha1_init).
- Initialize a SHA context structure.
- PARAMS
- * Context [O] SHA context
- RETURNS
- * Nothing
- */
(...)
+}
+/******************************************************************************
- A_SHAUpdate (ntdll.@)
- Update a SHA context with a hashed data from supplied buffer.
- PARAMS
- * Context [O] SHA context
- * Buffer [I] hashed data
- * BufferSize [I] hashed data size
- RETURNS
- * Nothing
- */
+void A_SHAUpdate(SHA_CTX *Context, const unsigned char *Buffer, UINT BufferSize) +{ + ULONG BufferContentSize;
+ BufferContentSize = Context->Count[1] & 63; + Context->Count[1] += BufferSize; + if (Context->Count[1] < BufferSize) + Context->Count[0]++; + Context->Count[0] += (BufferSize >> 29);
+ if (BufferContentSize + BufferSize < 64) + { + RtlCopyMemory(&Context->Buffer[BufferContentSize], Buffer, + BufferSize);
memcpy() would be more consistent with the rest of widl.
Thanks,
Jacek
Ah yes, I just blindly copied everything from ntdll source and never thought about it again.
There's probably not going to be much maintenance to this code, but is it alright then to completely rewrite it to make it more consistent with widl source, or should we still keep it close to the original code to make greps more likely to match both?
Cheers,
On 18/02/2021 11:34, Rémi Bernon wrote:
Ah yes, I just blindly copied everything from ntdll source and never thought about it again.
There's probably not going to be much maintenance to this code, but is it alright then to completely rewrite it to make it more consistent with widl source, or should we still keep it close to the original code to make greps more likely to match both?
I don't see much point in keeping it close to ntdll code in this case, it's already an adopted version of another code. I'd say that it's fine to do some style changes, I wouldn't count them as a complete rewrite.
Jacek
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
Updating only this patch with the SHA1 code adaptation to WIDL style. I also added a WORDS_BIGENDIAN check for DWORD2BE portability.
tools/widl/hash.c | 133 ++++++++++++++++++++++++++++++++++++++++++ tools/widl/hash.h | 13 +++++ tools/widl/parser.y | 6 +- tools/widl/typetree.c | 40 +++++++++++++ tools/widl/typetree.h | 2 + 5 files changed, 190 insertions(+), 4 deletions(-)
diff --git a/tools/widl/hash.c b/tools/widl/hash.c index 15ec88001d6..70ef11545c8 100644 --- a/tools/widl/hash.c +++ b/tools/widl/hash.c @@ -639,3 +639,136 @@ unsigned int lhash_val_of_name_sys( syskind_t skind, LCID lcid, LPCSTR lpStr)
return nHiWord | nLoWord; } + +/* SHA1 algorithm + * + * Based on public domain SHA code by Steve Reid steve@edmweb.com + * Copied and adapted from ntdll.sha1_init / ntdll.A_SHAUpdate / ntdll.A_SHAFinal + */ + +#ifdef WORDS_BIGENDIAN +#define DWORD2BE(x) (x) +#else +#define DWORD2BE(x) ((((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000)) +#endif + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) +#define blk0(i) (block[i] = DWORD2BE(block[i])) +#define blk1(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15]^block[(i+2)&15]^block[i&15],1)) +#define f1(x,y,z) (z^(x&(y^z))) +#define f2(x,y,z) (x^y^z) +#define f3(x,y,z) ((x&y)|(z&(x|y))) +#define f4(x,y,z) (x^y^z) +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +static void sha1_transform(struct sha1_context *ctx) +{ + DWORD a, b, c, d, e, *block = (DWORD *)ctx->buffer; + + /* Copy ctx->state[] to working variables */ + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working variables back into ctx->state[] */ + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + +void sha1_init(struct sha1_context *ctx) +{ + /* SHA1 initialization constants */ + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->count[0] = 0; + ctx->count[1] = 0; +} + +void sha1_update(struct sha1_context *ctx, const char *data, size_t data_size) +{ + size_t buffer_size; + + buffer_size = ctx->count[1] & 63; + ctx->count[1] += data_size; + if (ctx->count[1] < data_size) ctx->count[0]++; + ctx->count[0] += (data_size >> 29); + + if (buffer_size + data_size < 64) + memcpy(&ctx->buffer[buffer_size], data, data_size); + else + { + while (buffer_size + data_size >= 64) + { + memcpy(ctx->buffer + buffer_size, data, 64 - buffer_size); + data += 64 - buffer_size; + data_size -= 64 - buffer_size; + sha1_transform(ctx); + buffer_size = 0; + } + memcpy(ctx->buffer + buffer_size, data, data_size); + } +} + +void sha1_finalize(struct sha1_context *ctx, DWORD result[5]) +{ + unsigned int *count, length_hi, length_lo, i; + size_t pad_size, buffer_size; + char pad[72]; + + buffer_size = ctx->count[1] & 63; + if (buffer_size >= 56) pad_size = 56 + 64 - buffer_size; + else pad_size = 56 - buffer_size; + + length_hi = (ctx->count[0] << 3) | (ctx->count[1] >> (32 - 3)); + length_lo = (ctx->count[1] << 3); + + memset(pad + 1, 0, pad_size - 1); + pad[0] = 0x80; + count = (unsigned int*)(pad + pad_size); + count[0] = DWORD2BE(length_hi); + count[1] = DWORD2BE(length_lo); + sha1_update(ctx, pad, pad_size + 8); + + for (i = 0; i < 5; i++) result[i] = DWORD2BE(ctx->state[i]); + + sha1_init(ctx); +} diff --git a/tools/widl/hash.h b/tools/widl/hash.h index 3c2fd2914bf..f62fe5e25b5 100644 --- a/tools/widl/hash.h +++ b/tools/widl/hash.h @@ -22,6 +22,19 @@ #ifndef __WIDL_HASH_H #define __WIDL_HASH_H
+#include "windef.h" + extern unsigned int lhash_val_of_name_sys( syskind_t skind, LCID lcid, LPCSTR lpStr);
+struct sha1_context +{ + DWORD state[5]; + DWORD count[2]; + char buffer[64]; +}; + +void sha1_init(struct sha1_context *ctx); +void sha1_update(struct sha1_context *ctx, const char *data, size_t data_size); +void sha1_finalize(struct sha1_context *ctx, DWORD hash[5]); + #endif diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 57e7809fc1a..4c115adf4ab 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -45,13 +45,11 @@ struct _import_t };
static str_list_t *append_str(str_list_t *list, char *str); -static attr_list_t *append_attr(attr_list_t *list, attr_t *attr); static attr_list_t *append_attr_list(attr_list_t *new_list, attr_list_t *old_list); static decl_spec_t *make_decl_spec(type_t *type, decl_spec_t *left, decl_spec_t *right, enum storage_class stgclass, enum type_qualifier qual, enum function_specifier func_specifier); static attr_t *make_attr(enum attr_type type); static attr_t *make_attrv(enum attr_type type, unsigned int val); -static attr_t *make_attrp(enum attr_type type, void *val); static attr_t *make_custom_attr(UUID *id, expr_t *pval); static expr_list_t *append_expr(expr_list_t *list, expr_t *expr); static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, declarator_t *decl, int top); @@ -1507,7 +1505,7 @@ static attr_t *make_attrv(enum attr_type type, unsigned int val) return a; }
-static attr_t *make_attrp(enum attr_type type, void *val) +attr_t *make_attrp(enum attr_type type, void *val) { attr_t *a = xmalloc(sizeof(attr_t)); a->type = type; @@ -2407,7 +2405,7 @@ struct allowed_attr allowed_attr[] = /* ATTR_WIREMARSHAL */ { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "wire_marshal" }, };
-static attr_list_t *append_attr(attr_list_t *list, attr_t *attr) +attr_list_t *append_attr(attr_list_t *list, attr_t *attr) { attr_t *attr_existing; if (!attr) return list; diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 3db88945058..9d0b5576d45 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -29,6 +29,7 @@ #include "parser.h" #include "typetree.h" #include "header.h" +#include "hash.h"
type_t *duptype(type_t *t, int dupname) { @@ -1144,6 +1145,44 @@ type_t *type_parameterized_type_specialize_declare(type_t *type, typeref_list_t return new_type; }
+static void compute_interface_signature_uuid(type_t *iface) +{ + static const char winrt_pinterface_namespace[] = {0x11,0xf4,0x7a,0xd5,0x7b,0x73,0x42,0xc0,0xab,0xae,0x87,0x8b,0x1e,0x16,0xad,0xee}; + static const int version = 5; + struct sha1_context ctx; + unsigned char hash[20]; + GUID *uuid; + + if (!(uuid = get_attrp(iface->attrs, ATTR_UUID))) + { + uuid = xmalloc(sizeof(GUID)); + iface->attrs = append_attr(iface->attrs, make_attrp(ATTR_UUID, uuid)); + } + + sha1_init(&ctx); + sha1_update(&ctx, winrt_pinterface_namespace, sizeof(winrt_pinterface_namespace)); + sha1_update(&ctx, iface->signature, strlen(iface->signature)); + sha1_finalize(&ctx, (ULONG *)hash); + + /* https://tools.ietf.org/html/rfc4122: + + * Set the four most significant bits (bits 12 through 15) of the + time_hi_and_version field to the appropriate 4-bit version number + from Section 4.1.3. + + * Set the two most significant bits (bits 6 and 7) of the + clock_seq_hi_and_reserved to zero and one, respectively. + */ + + hash[6] = ((hash[6] & 0x0f) | (version << 4)); + hash[8] = ((hash[8] & 0x3f) | 0x80); + + uuid->Data1 = ((DWORD)hash[0] << 24)|((DWORD)hash[1] << 16)|((DWORD)hash[2] << 8)|(DWORD)hash[3]; + uuid->Data2 = ((WORD)hash[4] << 8)|(WORD)hash[5]; + uuid->Data3 = ((WORD)hash[6] << 8)|(WORD)hash[7]; + memcpy(&uuid->Data4, hash + 8, sizeof(*uuid) - offsetof(GUID, Data4)); +} + type_t *type_parameterized_type_specialize_define(type_t *type) { type_t *tmpl = type->details.parameterized.type; @@ -1174,6 +1213,7 @@ type_t *type_parameterized_type_specialize_define(type_t *type) iface->signature = format_parameterized_type_signature(type, repl); iface->defined = TRUE; } + compute_interface_signature_uuid(iface); compute_method_indexes(iface); return iface; } diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h index 8130174fe2a..c8bccc2fec9 100644 --- a/tools/widl/typetree.h +++ b/tools/widl/typetree.h @@ -80,6 +80,8 @@ extern int is_attr(const attr_list_t *list, enum attr_type t);
typeref_t *make_typeref(type_t *type); typeref_list_t *append_typeref(typeref_list_t *list, typeref_t *ref); +attr_t *make_attrp(enum attr_type type, void *val); +attr_list_t *append_attr(attr_list_t *list, attr_t *attr);
/* FIXME: shouldn't need to export this */ type_t *duptype(type_t *t, int dupname);