1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
#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;
}
|