#include "asn1fix_internal.h" #define ADD_TAG(skip, newtag) do { \ void *__p; \ if(skip && !(flags & AFT_FULL_COLLECT)) { \ if(newtag.tag_mode != TM_IMPLICIT) \ skip--; \ break; \ } else { \ if(newtag.tag_mode == TM_IMPLICIT) \ skip++; \ } \ __p = realloc((*tags), \ sizeof(struct asn1p_type_tag_s) * (count + 1)); \ if(!__p) return -1; \ *tags = __p; \ (*tags)[count++] = newtag; \ if((flags & AFT_FETCH_OUTMOST)) return count; \ } while(0) /* X.691, #22.2 */ static int asn1f_fetch_minimal_choice_root_tag(arg_t *arg, struct asn1p_type_tag_s *tag, enum asn1f_aft_flags_e flags); static int asn1f_fetch_tags_impl(arg_t *arg, struct asn1p_type_tag_s **tags, int count, int skip, enum asn1f_aft_flags_e flags) { asn1p_expr_t *expr = arg->expr; DEBUG("Fetching tag from %s: meta %d, type %s", expr->Identifier, expr->meta_type, expr->expr_type); /* If this type is tagged, add this tag first */ if(expr->tag.tag_class != TC_NOCLASS) ADD_TAG(skip, expr->tag); /* REMOVE ME */ if(expr->expr_type == A1TC_EXTENSIBLE) { struct asn1p_type_tag_s tt; memset(&tt, 0, sizeof(tt)); tt.tag_class = -1; ADD_TAG(skip, tt); return count; } if(expr->meta_type == AMT_TYPE) { struct asn1p_type_tag_s tt; memset(&tt, 0, sizeof(tt)); tt.tag_class = TC_UNIVERSAL; tt.tag_value = expr_type2uclass_value[expr->expr_type]; if(tt.tag_value == 0) { if(expr->expr_type == ASN_TYPE_ANY && (flags & AFT_IMAGINARY_ANY)) tt.tag_value = -1; else if(expr->expr_type != ASN_CONSTR_CHOICE) return -1; else if(count) return count; else if((flags & AFT_CANON_CHOICE) == 0) return -1; else if(asn1f_fetch_minimal_choice_root_tag(arg, &tt, flags)) return -1; } ADD_TAG(skip, tt); return count; } if(expr->meta_type == AMT_TYPEREF) { asn1p_expr_t *nexpr; DEBUG("Following the reference %s", expr->Identifier); nexpr = asn1f_lookup_symbol(arg, expr->module, expr->rhs_pspecs, expr->reference); if(nexpr == NULL) { if(errno != EEXIST) /* -fknown-extern-type */ return -1; if(!count) return 0; /* OK */ if((*tags)[count-1].tag_mode == TM_IMPLICIT) { WARNING("Tagging mode for %s " "is IMPLICIT, assuming %s " "has exactly one tag", expr->Identifier, asn1f_printable_reference(expr->reference) ); return count; } FATAL("Tagging mode %s -> %s " "dangerously incompatible", expr->Identifier, asn1f_printable_reference(expr->reference) ); return -1; } else { arg->expr = nexpr; } if(expr->_mark & TM_RECURSION) return -1; expr->_mark |= TM_RECURSION; count = asn1f_fetch_tags_impl(arg, tags, count, skip, flags); expr->_mark &= ~TM_RECURSION; return count; } DEBUG("No tags discovered for type %d", expr->expr_type); return -1; } static int asn1f_fetch_minimal_choice_root_tag(arg_t *arg, struct asn1p_type_tag_s *tag, enum asn1f_aft_flags_e flags) { struct asn1p_type_tag_s min_tag; asn1p_expr_t *v; memset(&min_tag, 0, sizeof(min_tag)); min_tag.tag_class = TC_PRIVATE + 1; TQ_FOR(v, &(arg->expr->members), next) { arg_t tmparg = *arg; struct asn1p_type_tag_s *tags = 0; int count; if(v->expr_type == A1TC_EXTENSIBLE) break; /* Search only within extension root */ tmparg.expr = v; count = asn1f_fetch_tags_impl(&tmparg, &tags, 0, 0, flags); if(count <= 0) continue; if(tags[0].tag_class < min_tag.tag_class) min_tag = tags[0]; else if(tags[0].tag_class == min_tag.tag_class && tags[0].tag_value < min_tag.tag_value) min_tag = tags[0]; free(tags); } if(min_tag.tag_class == TC_PRIVATE + 1) return -1; else *tag = min_tag; return 0; } int asn1f_fetch_outmost_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag, enum asn1f_aft_flags_e flags) { struct asn1p_type_tag_s *tags; int count; flags |= AFT_FETCH_OUTMOST; count = asn1f_fetch_tags(asn, mod, expr, &tags, flags); if(count <= 0) return count; *tag = tags[0]; free(tags); return 0; } int asn1f_fetch_tags(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s **tags_r, enum asn1f_aft_flags_e flags) { arg_t arg; struct asn1p_type_tag_s *tags = 0; int count; memset(&arg, 0, sizeof(arg)); arg.asn = asn; arg.mod = mod; arg.expr = expr; count = asn1f_fetch_tags_impl(&arg, &tags, 0, 0, flags); if(count <= 0 && tags) { free(tags); tags = 0; } *tags_r = tags; return count; }