upgrade: PER related changes
diff --git a/libasn1fix/asn1fix_tags.c b/libasn1fix/asn1fix_tags.c
index ff662cc..dfda441 100644
--- a/libasn1fix/asn1fix_tags.c
+++ b/libasn1fix/asn1fix_tags.c
@@ -18,6 +18,9 @@
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;
@@ -44,9 +47,13 @@
if(expr->expr_type == ASN_TYPE_ANY
&& (flags & AFT_IMAGINARY_ANY))
tt.tag_value = -1;
- else if(expr->expr_type == ASN_CONSTR_CHOICE)
- return count ? count : -1;
- else
+ 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);
@@ -55,6 +62,7 @@
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->reference);
if(nexpr == NULL) {
if(errno != EEXIST) /* -fknown-extern-type */
@@ -87,18 +95,52 @@
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, int _aft_imaginary_any) {
+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;
- enum asn1f_aft_flags_e flags;
int count;
- flags = AFT_FETCH_OUTMOST;
- flags |= AFT_IMAGINARY_ANY * _aft_imaginary_any;
+ flags |= AFT_FETCH_OUTMOST;
count = asn1f_fetch_tags(asn, mod, expr, &tags, flags);
if(count <= 0) return count;