#include "asn1fix_internal.h" typedef struct resolver_arg { asn1p_expr_t *(*resolver)(asn1p_expr_t *, void *arg); arg_t *arg; asn1p_expr_t *original_expr; asn1p_paramlist_t *lhs_params; asn1p_expr_t *rhs_pspecs; char *resolved_name; } resolver_arg_t; static asn1p_expr_t *resolve_expr(asn1p_expr_t *, void *resolver_arg); static int compare_specializations(const asn1p_expr_t *a, const asn1p_expr_t *b); static asn1p_expr_t *find_target_specialization_byvalueset(resolver_arg_t *rarg, asn1p_constraint_t *ct); static asn1p_expr_t *find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref); static asn1p_expr_t *find_target_specialization_bystr(resolver_arg_t *rarg, char *str); asn1p_expr_t * asn1f_parameterization_fork(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *rhs_pspecs) { resolver_arg_t rarg; /* resolver argument */ asn1p_expr_t *exc; /* expr clone */ asn1p_expr_t *rpc; /* rhs_pspecs clone */ asn1p_expr_t *m; /* expr members */ asn1p_expr_t *target; void *p; struct asn1p_pspec_s *pspec; int npspecs; assert(rhs_pspecs); assert(expr->lhs_params); assert(expr->parent_expr == 0); /* * Find if this exact specialization has been used already. */ for(npspecs = 0; npspecs < expr->specializations.pspecs_count; npspecs++) { if(compare_specializations(rhs_pspecs, expr->specializations.pspec[npspecs].rhs_pspecs) == 0) { DEBUG("Reused parameterization for %s", expr->Identifier); return expr->specializations.pspec[npspecs].my_clone; } } DEBUG("Forking parameterization at %d for %s (%d alr)", rhs_pspecs->_lineno, expr->Identifier, expr->specializations.pspecs_count); rarg.resolver = resolve_expr; rarg.arg = arg; rarg.original_expr = expr; rarg.lhs_params = expr->lhs_params; rarg.rhs_pspecs = rhs_pspecs; rarg.resolved_name = NULL; exc = asn1p_expr_clone_with_resolver(expr, resolve_expr, &rarg); if(!exc) return NULL; if(rarg.resolved_name) { free(exc->Identifier); exc->Identifier = strdup(rarg.resolved_name); exc->_lineno = 0; } rpc = asn1p_expr_clone(rhs_pspecs, 0); assert(rpc); /* * Create a new specialization. */ npspecs = expr->specializations.pspecs_count; p = realloc(expr->specializations.pspec, (npspecs + 1) * sizeof(expr->specializations.pspec[0])); assert(p); expr->specializations.pspec = p; pspec = &expr->specializations.pspec[npspecs]; memset(pspec, 0, sizeof *pspec); pspec->rhs_pspecs = rpc; pspec->my_clone = exc; exc->spec_index = npspecs; exc->rhs_pspecs = asn1p_expr_clone_with_resolver(expr->rhs_pspecs ? expr->rhs_pspecs : rhs_pspecs, resolve_expr, &rarg); /* Passing arguments to members and type references */ target = TQ_FIRST(&expr->members); TQ_FOR(m, &exc->members, next) { m->rhs_pspecs = asn1p_expr_clone_with_resolver(target->rhs_pspecs ? target->rhs_pspecs : exc->rhs_pspecs, resolve_expr, &rarg); target = TQ_NEXT(target, next); } DEBUG("Forked new parameterization for %s", expr->Identifier); /* Commit */ expr->specializations.pspecs_count = npspecs + 1; return exc; } static int compare_specializations(const asn1p_expr_t *a, const asn1p_expr_t *b) { return asn1p_expr_compare(a, b); } static asn1p_expr_t * resolve_expr(asn1p_expr_t *expr_to_resolve, void *resolver_arg) { resolver_arg_t *rarg = resolver_arg; arg_t *arg = rarg->arg; asn1p_expr_t *expr; asn1p_expr_t *nex; DEBUG("Resolving %s (meta %d)", expr_to_resolve->Identifier, expr_to_resolve->meta_type); if(expr_to_resolve->meta_type == AMT_TYPEREF) { expr = find_target_specialization_byref(rarg, expr_to_resolve->reference); if(!expr) return NULL; } else if(expr_to_resolve->meta_type == AMT_VALUE) { if(!expr_to_resolve->value) return NULL; expr = find_target_specialization_bystr(rarg, expr_to_resolve->Identifier); if(!expr) return NULL; } else if(expr_to_resolve->meta_type == AMT_VALUESET) { assert(expr_to_resolve->constraints); expr = find_target_specialization_byvalueset(rarg, expr_to_resolve->constraints); if(!expr) return NULL; } else { errno = ESRCH; return NULL; } DEBUG("Found target %s (%d/%x)", expr->Identifier, expr->meta_type, expr->expr_type); if(expr->meta_type == AMT_TYPE || expr->meta_type == AMT_VALUE || expr->meta_type == AMT_TYPEREF || expr->meta_type == AMT_VALUESET) { DEBUG("Target is a simple type %s", ASN_EXPR_TYPE2STR(expr->expr_type)); nex = asn1p_expr_clone(expr, 0); free(nex->Identifier); nex->Identifier = expr_to_resolve->Identifier ? strdup(expr_to_resolve->Identifier) : 0; if(expr->meta_type == AMT_TYPEREF) { asn1p_ref_t *ref = expr->reference; rarg->resolved_name = ref->components[ref->comp_count - 1].name; } else if(expr->meta_type == AMT_VALUESET) { asn1p_constraint_t *ct = expr->constraints; if(ct->type == ACT_EL_TYPE) { asn1p_ref_t *ref = ct->containedSubtype->value.v_type->reference; rarg->resolved_name = ref->components[ref->comp_count - 1].name; } } return nex; } else { FATAL("Feature not implemented for %s (%d/%x), " "please contact the asn1c author", rarg->original_expr->Identifier, expr->meta_type, expr->expr_type); errno = EPERM; return NULL; } return NULL; } static asn1p_expr_t * find_target_specialization_byvalueset(resolver_arg_t *rarg, asn1p_constraint_t *ct) { asn1p_ref_t *ref; if (ct->type != ACT_EL_TYPE) return NULL; ref = ct->containedSubtype->value.v_type->reference; return find_target_specialization_byref(rarg, ref); } static asn1p_expr_t * find_target_specialization_byref(resolver_arg_t *rarg, asn1p_ref_t *ref) { char *refstr; if(!ref || ref->comp_count != 1) { errno = ESRCH; return NULL; } refstr = ref->components[0].name; /* T */ return find_target_specialization_bystr(rarg, refstr); } static asn1p_expr_t * find_target_specialization_bystr(resolver_arg_t *rarg, char *refstr) { arg_t *arg = rarg->arg; asn1p_expr_t *target; int i; if(!refstr) return NULL; target = TQ_FIRST(&rarg->rhs_pspecs->members); for(i = 0; i < rarg->lhs_params->params_count; i++, target = TQ_NEXT(target, next)) { struct asn1p_param_s *param = &rarg->lhs_params->params[i]; if(!target) break; if(strcmp(param->argument, refstr)) continue; return target; } if(i != rarg->lhs_params->params_count) { FATAL("Parameterization of %s failed: " "parameters number mismatch", rarg->original_expr->Identifier); errno = EPERM; return NULL; } errno = ESRCH; return NULL; }