NativeEnumerated.c vars NULL init and check
[com/asn1c.git] / libasn1fix / asn1fix_tags.c
1 #include "asn1fix_internal.h"
2 #include <asn1_namespace.h>
3
4 #define ADD_TAG(skip, newtag)   do {                                    \
5         void *__p;                                                      \
6         if(skip && !(flags & AFT_FULL_COLLECT)) {                       \
7                 if(newtag.tag_mode != TM_IMPLICIT)                      \
8                         skip--;                                         \
9                 break;                                                  \
10         } else {                                                        \
11                 if(newtag.tag_mode == TM_IMPLICIT)                      \
12                         skip++;                                         \
13         }                                                               \
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;                   \
20 } while(0)
21
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
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;
28
29         DEBUG("Fetching tag from %s: meta %d, type %s", expr->Identifier,
30                 expr->meta_type, expr->expr_type);
31
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 */
37         if(expr->expr_type == A1TC_EXTENSIBLE) {
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;
43         }
44
45         if(expr->meta_type == AMT_TYPE) {
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;
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))
61                                 return -1;
62                 }
63                 ADD_TAG(skip, tt);
64                 return count;
65         }
66
67         if(expr->meta_type == AMT_TYPEREF) {
68                 asn1p_expr_t *nexpr;
69                 DEBUG("Following the reference %s", expr->Identifier);
70                 nexpr = asn1f_lookup_symbol(arg, expr->rhs_pspecs, expr->reference);
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                 }
94                 if(expr->_mark & TM_RECURSION)
95                         return -1;
96                 expr->_mark |= TM_RECURSION;
97                 count = asn1f_fetch_tags_impl(arg, tags, count, skip, flags);
98                 expr->_mark &= ~TM_RECURSION;
99                 return count;
100         }
101
102         DEBUG("No tags discovered for type %d", expr->expr_type);
103
104         return -1;
105 }
106
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 }
141
142 int
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) {
144         struct asn1p_type_tag_s *tags;
145         int count;
146
147         flags |= AFT_FETCH_OUTMOST;
148
149         count = asn1f_fetch_tags(asn, ns, mod, expr, &tags, flags);
150         if(count <= 0) return count;
151
152         *tag = tags[0];
153         free(tags);
154
155         return 0;
156 }
157
158 int
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) {
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;
166         arg.ns = ns;
167         arg.mod = mod;
168         arg.expr = expr;
169
170         count = asn1f_fetch_tags_impl(&arg, &tags, 0, 0, flags);
171         if (count <= 0) {
172                 free(tags);
173                 tags = 0;
174         }
175         *tags_r = tags;
176         return count;
177 }