Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 1 | #include "asn1fix_internal.h" |
Lev Walkin | c0e03b9 | 2017-08-22 01:48:23 -0700 | [diff] [blame] | 2 | #include <asn1_namespace.h> |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 3 | |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 4 | #define ADD_TAG(skip, newtag) do { \ |
| 5 | void *__p; \ |
Lev Walkin | 188ed2c | 2004-09-13 08:31:01 +0000 | [diff] [blame] | 6 | if(skip && !(flags & AFT_FULL_COLLECT)) { \ |
Lev Walkin | 906654e | 2004-09-10 15:49:15 +0000 | [diff] [blame] | 7 | if(newtag.tag_mode != TM_IMPLICIT) \ |
| 8 | skip--; \ |
| 9 | break; \ |
| 10 | } else { \ |
| 11 | if(newtag.tag_mode == TM_IMPLICIT) \ |
| 12 | skip++; \ |
| 13 | } \ |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 14 | __p = realloc((*tags), \ |
| 15 | sizeof(struct asn1p_type_tag_s) * (count + 1)); \ |
| 16 | if(!__p) return -1; \ |
| 17 | *tags = __p; \ |
| 18 | (*tags)[count++] = newtag; \ |
| 19 | if((flags & AFT_FETCH_OUTMOST)) return count; \ |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 20 | } while(0) |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 21 | |
Lev Walkin | 59b176e | 2005-11-26 11:25:14 +0000 | [diff] [blame] | 22 | /* X.691, #22.2 */ |
| 23 | static int asn1f_fetch_minimal_choice_root_tag(arg_t *arg, struct asn1p_type_tag_s *tag, enum asn1f_aft_flags_e flags); |
| 24 | |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 25 | static int |
| 26 | asn1f_fetch_tags_impl(arg_t *arg, struct asn1p_type_tag_s **tags, int count, int skip, enum asn1f_aft_flags_e flags) { |
| 27 | asn1p_expr_t *expr = arg->expr; |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 28 | |
Lev Walkin | 9c2285a | 2006-03-09 08:49:26 +0000 | [diff] [blame] | 29 | DEBUG("Fetching tag from %s: meta %d, type %s", expr->Identifier, |
| 30 | expr->meta_type, expr->expr_type); |
| 31 | |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 32 | /* If this type is tagged, add this tag first */ |
| 33 | if(expr->tag.tag_class != TC_NOCLASS) |
| 34 | ADD_TAG(skip, expr->tag); |
| 35 | |
| 36 | /* REMOVE ME */ |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 37 | if(expr->expr_type == A1TC_EXTENSIBLE) { |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 38 | struct asn1p_type_tag_s tt; |
| 39 | memset(&tt, 0, sizeof(tt)); |
| 40 | tt.tag_class = -1; |
| 41 | ADD_TAG(skip, tt); |
| 42 | return count; |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | if(expr->meta_type == AMT_TYPE) { |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 46 | struct asn1p_type_tag_s tt; |
| 47 | memset(&tt, 0, sizeof(tt)); |
| 48 | tt.tag_class = TC_UNIVERSAL; |
| 49 | tt.tag_value = expr_type2uclass_value[expr->expr_type]; |
| 50 | if(tt.tag_value == 0) { |
| 51 | if(expr->expr_type == ASN_TYPE_ANY |
| 52 | && (flags & AFT_IMAGINARY_ANY)) |
| 53 | tt.tag_value = -1; |
Lev Walkin | 59b176e | 2005-11-26 11:25:14 +0000 | [diff] [blame] | 54 | else if(expr->expr_type != ASN_CONSTR_CHOICE) |
| 55 | return -1; |
| 56 | else if(count) return count; |
| 57 | else if((flags & AFT_CANON_CHOICE) == 0) |
| 58 | return -1; |
| 59 | else if(asn1f_fetch_minimal_choice_root_tag(arg, |
| 60 | &tt, flags)) |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 61 | return -1; |
Lev Walkin | d541c25 | 2004-09-05 10:36:22 +0000 | [diff] [blame] | 62 | } |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 63 | ADD_TAG(skip, tt); |
| 64 | return count; |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | if(expr->meta_type == AMT_TYPEREF) { |
Lev Walkin | 906654e | 2004-09-10 15:49:15 +0000 | [diff] [blame] | 68 | asn1p_expr_t *nexpr; |
Lev Walkin | 59b176e | 2005-11-26 11:25:14 +0000 | [diff] [blame] | 69 | DEBUG("Following the reference %s", expr->Identifier); |
Lev Walkin | c0e03b9 | 2017-08-22 01:48:23 -0700 | [diff] [blame] | 70 | nexpr = asn1f_lookup_symbol(arg, expr->rhs_pspecs, expr->reference); |
Lev Walkin | 906654e | 2004-09-10 15:49:15 +0000 | [diff] [blame] | 71 | if(nexpr == NULL) { |
| 72 | if(errno != EEXIST) /* -fknown-extern-type */ |
| 73 | return -1; |
| 74 | if(!count) |
| 75 | return 0; /* OK */ |
| 76 | if((*tags)[count-1].tag_mode == TM_IMPLICIT) { |
| 77 | WARNING("Tagging mode for %s " |
| 78 | "is IMPLICIT, assuming %s " |
| 79 | "has exactly one tag", |
| 80 | expr->Identifier, |
| 81 | asn1f_printable_reference(expr->reference) |
| 82 | ); |
| 83 | return count; |
| 84 | } |
| 85 | FATAL("Tagging mode %s -> %s " |
| 86 | "dangerously incompatible", |
| 87 | expr->Identifier, |
| 88 | asn1f_printable_reference(expr->reference) |
| 89 | ); |
| 90 | return -1; |
| 91 | } else { |
| 92 | arg->expr = nexpr; |
| 93 | } |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 94 | if(expr->_mark & TM_RECURSION) |
| 95 | return -1; |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 96 | expr->_mark |= TM_RECURSION; |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 97 | count = asn1f_fetch_tags_impl(arg, tags, count, skip, flags); |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 98 | expr->_mark &= ~TM_RECURSION; |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 99 | return count; |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 100 | } |
| 101 | |
Lev Walkin | 59b176e | 2005-11-26 11:25:14 +0000 | [diff] [blame] | 102 | DEBUG("No tags discovered for type %d", expr->expr_type); |
| 103 | |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 104 | return -1; |
| 105 | } |
| 106 | |
Lev Walkin | 59b176e | 2005-11-26 11:25:14 +0000 | [diff] [blame] | 107 | static int |
| 108 | asn1f_fetch_minimal_choice_root_tag(arg_t *arg, struct asn1p_type_tag_s *tag, enum asn1f_aft_flags_e flags) { |
| 109 | struct asn1p_type_tag_s min_tag; |
| 110 | asn1p_expr_t *v; |
| 111 | |
| 112 | memset(&min_tag, 0, sizeof(min_tag)); |
| 113 | min_tag.tag_class = TC_PRIVATE + 1; |
| 114 | |
| 115 | TQ_FOR(v, &(arg->expr->members), next) { |
| 116 | arg_t tmparg = *arg; |
| 117 | struct asn1p_type_tag_s *tags = 0; |
| 118 | int count; |
| 119 | |
| 120 | if(v->expr_type == A1TC_EXTENSIBLE) |
| 121 | break; /* Search only within extension root */ |
| 122 | |
| 123 | tmparg.expr = v; |
| 124 | count = asn1f_fetch_tags_impl(&tmparg, &tags, 0, 0, flags); |
| 125 | if(count <= 0) continue; |
| 126 | |
| 127 | if(tags[0].tag_class < min_tag.tag_class) |
| 128 | min_tag = tags[0]; |
| 129 | else if(tags[0].tag_class == min_tag.tag_class |
| 130 | && tags[0].tag_value < min_tag.tag_value) |
| 131 | min_tag = tags[0]; |
| 132 | free(tags); |
| 133 | } |
| 134 | |
| 135 | if(min_tag.tag_class == TC_PRIVATE + 1) |
| 136 | return -1; |
| 137 | else |
| 138 | *tag = min_tag; |
| 139 | return 0; |
| 140 | } |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 141 | |
| 142 | int |
Lev Walkin | c0e03b9 | 2017-08-22 01:48:23 -0700 | [diff] [blame] | 143 | asn1f_fetch_outmost_tag(asn1p_t *asn, asn1_namespace_t *ns, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag, enum asn1f_aft_flags_e flags) { |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 144 | struct asn1p_type_tag_s *tags; |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 145 | int count; |
| 146 | |
Lev Walkin | 59b176e | 2005-11-26 11:25:14 +0000 | [diff] [blame] | 147 | flags |= AFT_FETCH_OUTMOST; |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 148 | |
Lev Walkin | c0e03b9 | 2017-08-22 01:48:23 -0700 | [diff] [blame] | 149 | count = asn1f_fetch_tags(asn, ns, mod, expr, &tags, flags); |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 150 | if(count <= 0) return count; |
| 151 | |
| 152 | *tag = tags[0]; |
| 153 | free(tags); |
| 154 | |
| 155 | return 0; |
| 156 | } |
| 157 | |
| 158 | int |
Lev Walkin | c0e03b9 | 2017-08-22 01:48:23 -0700 | [diff] [blame] | 159 | asn1f_fetch_tags(asn1p_t *asn, asn1_namespace_t *ns, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s **tags_r, enum asn1f_aft_flags_e flags) { |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 160 | arg_t arg; |
| 161 | struct asn1p_type_tag_s *tags = 0; |
| 162 | int count; |
| 163 | |
| 164 | memset(&arg, 0, sizeof(arg)); |
| 165 | arg.asn = asn; |
Lev Walkin | c0e03b9 | 2017-08-22 01:48:23 -0700 | [diff] [blame] | 166 | arg.ns = ns; |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 167 | arg.mod = mod; |
| 168 | arg.expr = expr; |
| 169 | |
| 170 | count = asn1f_fetch_tags_impl(&arg, &tags, 0, 0, flags); |
Markus Elfring | f3d1861 | 2016-03-15 08:35:24 +0100 | [diff] [blame] | 171 | if (count <= 0) { |
Lev Walkin | 8945e0e | 2004-09-10 06:07:04 +0000 | [diff] [blame] | 172 | free(tags); |
| 173 | tags = 0; |
| 174 | } |
| 175 | *tags_r = tags; |
| 176 | return count; |
| 177 | } |