NativeEnumerated.c vars NULL init and check
[com/asn1c.git] / libasn1fix / asn1fix_constraint.c
1 #include "asn1fix_internal.h"
2 #include "asn1fix_constraint.h"
3 #include "asn1fix_crange.h"
4
5 static void _remove_extensions(arg_t *arg, asn1p_constraint_t *ct, int flast);
6 static int constraint_type_resolve(arg_t *arg, asn1p_constraint_t *ct);
7 static int constraint_object_resolve(arg_t *arg, asn1p_value_t *value);
8 static int constraint_value_resolve(arg_t *arg, asn1p_value_t **value, enum asn1p_constraint_type_e real_ctype);
9
10 int
11 asn1constraint_pullup(arg_t *arg) {
12         asn1p_expr_t *expr = arg->expr;
13         asn1p_expr_t *top_parent;
14         asn1p_constraint_t *ct_parent;
15         asn1p_constraint_t *ct_expr;
16         int ret;
17
18         if(expr->combined_constraints)
19                 return 0;       /* Operation already performed earlier */
20
21         switch(expr->meta_type) {
22         case AMT_TYPE:
23         case AMT_TYPEREF:
24         case AMT_VALUESET:
25                 break;
26         default:
27                 return 0;       /* Nothing to do */
28         }
29
30         if(expr->expr_type == A1TC_REFERENCE) {
31                 asn1p_ref_t *ref = expr->reference;
32                 asn1p_expr_t *parent_expr;
33
34                 assert(ref);
35         parent_expr = asn1f_lookup_symbol(arg, expr->rhs_pspecs, ref);
36         if(!parent_expr) {
37                         if(errno != EEXIST) {
38                                 DEBUG("\tWhile fetching parent constraints: "
39                                         "type \"%s\" not found: %s",
40                                         asn1f_printable_reference(ref),
41                                         strerror(errno));
42                                 return -1;
43                         } else {
44                                 /*
45                                  * -fknown-extern-type is given.
46                                  * Assume there are no constraints there.
47                                  */
48                                 WARNING("External type \"%s\": "
49                                         "assuming no constraints",
50                                         asn1f_printable_reference(ref));
51                                 ct_parent = 0;
52                         }
53                 } else {
54                         arg->expr = parent_expr;
55                         ret = asn1constraint_pullup(arg);
56                         arg->expr = expr;
57                         if(ret) return ret;
58
59                         ct_parent = parent_expr->combined_constraints;
60                 }
61     } else {
62                 ct_parent = 0;
63         }
64
65         ct_expr = expr->constraints;
66
67         if(!ct_parent && !ct_expr)
68                 return 0;       /* No constraints to consider */
69
70         /*
71          * Resolve constraints, if not already resolved.
72          */
73         top_parent = asn1f_find_terminal_type(arg, arg->expr);
74     ret = asn1constraint_resolve(
75         arg, ct_expr, top_parent ? top_parent->expr_type : A1TC_INVALID, 0);
76     if(ret) return ret;
77
78         /*
79          * Copy parent type constraints.
80          */
81         if(ct_parent) {
82                 ct_parent = asn1p_constraint_clone(ct_parent);
83                 assert(ct_parent);
84         }
85
86         /*
87          * If the current type does not have constraints, it inherits
88          * the constraints of a parent.
89          */
90         if(ct_parent && !ct_expr) {
91                 expr->combined_constraints = ct_parent;
92                 return 0;
93         }
94
95         ct_expr = asn1p_constraint_clone(ct_expr);
96         assert(ct_expr);
97
98         /*
99          * Now we have a set of current expression's constraints,
100          * and an optional set of the parent expression's constraints.
101          */
102
103         if(ct_parent) {
104                 /*
105                  * If we have a parent, remove all the extensions (46.4).
106                  */
107                 _remove_extensions(arg, ct_parent, 0);
108
109                 expr->combined_constraints = ct_parent;
110                 if(ct_expr->type == ACT_CA_SET) {
111                         unsigned int i;
112                         for(i = 0; i < ct_expr->el_count; i++) {
113                                 if(asn1p_constraint_insert(
114                                         expr->combined_constraints,
115                                                 ct_expr->elements[i])) {
116                                         expr->combined_constraints = 0;
117                                         asn1p_constraint_free(ct_expr);
118                                         asn1p_constraint_free(ct_parent);
119                                         return -1;
120                                 } else {
121                                         ct_expr->elements[i] = 0;
122                                 }
123                         }
124                         asn1p_constraint_free(ct_expr);
125                 } else {
126                         asn1p_constraint_insert(expr->combined_constraints,
127                                 ct_expr);
128                 }
129         } else {
130                 _remove_extensions(arg, ct_expr, 1);
131                 expr->combined_constraints = ct_expr;
132         }
133
134         return 0;
135 }
136
137 int
138 asn1constraint_resolve(arg_t *arg, asn1p_constraint_t *ct, asn1p_expr_type_e etype, enum asn1p_constraint_type_e effective_type) {
139         enum asn1p_constraint_type_e real_constraint_type;
140         unsigned int el;
141         int rvalue = 0;
142         int ret;
143
144         DEBUG("(\"%s\")", arg->expr->Identifier);
145
146         if(!ct) return 0;
147
148         /* Don't touch information object classes */
149         switch(ct->type) {
150         case ACT_CT_SIZE:
151         case ACT_CT_FROM:
152                 if(effective_type && effective_type != ct->type) {
153                         FATAL("%s at line %d: "
154                                 "Incompatible nested %s within %s",
155                                 arg->expr->Identifier, ct->_lineno,
156                                 asn1p_constraint_type2str(ct->type),
157                                 asn1p_constraint_type2str(effective_type)
158                         );
159                 }
160                 effective_type = ct->type;
161                 break;
162         case ACT_CT_WCOMP:
163         case ACT_CT_WCOMPS:
164         case ACT_CA_CRC:
165                 return 0;
166         default:
167                 break;
168         }
169
170         real_constraint_type = effective_type ? effective_type : ct->type;
171
172         if(etype != A1TC_INVALID) {
173
174                 ret = asn1constraint_compatible(etype, real_constraint_type,
175                                 arg->flags & A1F_EXTENDED_SizeConstraint);
176                 switch(ret) {
177                 case -1:        /* If unknown, assume OK. */
178                 case  1:
179                         break;
180                 case 0:
181                 default:
182                         FATAL("%s at line %d: "
183                                 "Constraint type %s is not applicable to %s",
184                                 arg->expr->Identifier, ct->_lineno,
185                                 asn1p_constraint_type2str(real_constraint_type),
186                                 ASN_EXPR_TYPE2STR(etype)
187                         );
188                         rvalue = -1;
189                         break;
190                 }
191         } else {
192                 WARNING("%s at line %d: "
193                         "Constraints ignored: Unresolved parent type",
194                         arg->expr->Identifier, arg->expr->_lineno);
195         }
196
197         /*
198          * Resolve all possible references, wherever they occur.
199          */
200         if(ct->containedSubtype) {
201                 ret = constraint_type_resolve(arg, ct);
202                 RET2RVAL(ret, rvalue);
203         }
204         if(ct->value && ct->value->type == ATV_REFERENCED) {
205         ret = constraint_value_resolve(arg, &ct->value, real_constraint_type);
206         RET2RVAL(ret, rvalue);
207         }
208         if(ct->range_start && ct->range_start->type == ATV_REFERENCED) {
209         ret = constraint_value_resolve(arg, &ct->range_start,
210                                        real_constraint_type);
211         RET2RVAL(ret, rvalue);
212         }
213         if(ct->range_stop && ct->range_stop->type == ATV_REFERENCED) {
214         ret = constraint_value_resolve(arg, &ct->range_stop,
215                                        real_constraint_type);
216         RET2RVAL(ret, rvalue);
217         }
218         if (ct->value && ct->value->type == ATV_UNPARSED && etype == A1TC_CLASSDEF) {
219                 ret = constraint_object_resolve(arg, ct->value);
220                 RET2RVAL(ret, rvalue);
221         }
222
223     /*
224      * Proceed recursively.
225      */
226     for(el = 0; el < ct->el_count; el++) {
227         ret = asn1constraint_resolve(arg, ct->elements[el], etype,
228                                      effective_type);
229         RET2RVAL(ret, rvalue);
230     }
231
232     return rvalue;
233 }
234
235 static void
236 _remove_extensions(arg_t *arg, asn1p_constraint_t *ct, int forgive_last) {
237         unsigned int i;
238
239         if(!ct) return;
240
241         for(i = 0; i < ct->el_count; i++) {
242                 if(ct->elements[i]->type == ACT_EL_EXT)
243                         break;
244                 if(forgive_last && ct->type == ACT_CA_SET
245                         && i + 1 == ct->el_count)
246                         return;
247                 _remove_extensions(arg, ct->elements[i], 0);
248         }
249
250         /* Remove the elements at and after the extensibility mark */
251         for(; i < ct->el_count; ct->el_count--) {
252                 asn1p_constraint_t *rm;
253                 rm = ct->elements[ct->el_count-1];
254                 asn1p_constraint_free(rm);
255         }
256
257         if(i < ct->el_size)
258                 ct->elements[i] = 0;
259 }
260
261 static asn1p_ref_t *
262 get_reference_from(asn1p_constraint_t *ct) {
263     if(ct->containedSubtype->type == ATV_REFERENCED) {
264         return ct->containedSubtype->value.reference;
265     } else if(ct->containedSubtype->type == ATV_TYPE) {
266         if(ct->containedSubtype->value.v_type->expr_type == A1TC_REFERENCE) {
267             return ct->containedSubtype->value.v_type->reference;
268         }
269     }
270     return NULL;
271 }
272
273 static int
274 constraint_type_resolve(arg_t *arg, asn1p_constraint_t *ct) {
275     asn1p_constraint_t *ct_expr;
276     int ret;
277     asn1p_expr_t *rtype = (asn1p_expr_t *)0;
278
279     DEBUG("(\"%s\")", asn1f_printable_value(ct->containedSubtype));
280
281     if(ct->containedSubtype->type == ATV_VALUESET) {
282         ct_expr = ct->containedSubtype->value.constraint;
283         DEBUG("Found %s in constraints", "ValueSet");
284     } else if(get_reference_from(ct)) {
285         arg_t tmparg;
286
287         rtype = asn1f_lookup_symbol(arg, arg->expr->rhs_pspecs,
288                                     get_reference_from(ct));
289         if(!rtype) {
290             FATAL(
291                 "Cannot find type \"%s\" in constraints "
292                 "at line %d",
293                 asn1f_printable_value(ct->containedSubtype), ct->_lineno);
294             return -1;
295         }
296
297         tmparg = *arg;
298         tmparg.expr = rtype;
299         tmparg.mod = rtype->module;
300         ret = asn1constraint_pullup(&tmparg);
301         if(ret) return ret;
302
303         if(rtype->ioc_table) {
304             if(!arg->expr->ioc_table)
305                 arg->expr->ioc_table = asn1p_ioc_table_new();
306             asn1p_ioc_table_append(arg->expr->ioc_table, rtype->ioc_table);
307             asn1p_value_free(ct->containedSubtype);
308             ct->containedSubtype = NULL;
309         }
310
311         ct_expr = rtype->combined_constraints;
312         if(!ct_expr) return 0;
313     } else {
314         FATAL("Unsupported constraint kind %s at line %d",
315               asn1f_printable_value(ct->containedSubtype), ct->_lineno);
316         return -1;
317     }
318
319     ct_expr = asn1p_constraint_clone(ct_expr);
320     assert(ct_expr);
321
322     _remove_extensions(arg, ct_expr, 0);
323
324     if(ct_expr->type == ACT_CA_SET) {
325         unsigned int i;
326         for(i = 0; i < ct_expr->el_count; i++) {
327             if(asn1p_constraint_insert(
328                 ct, ct_expr->elements[i])) {
329                 asn1p_constraint_free(ct_expr);
330                 return -1;
331             } else {
332                 ct_expr->elements[i] = 0;
333             }
334         }
335         asn1p_constraint_free(ct_expr);
336     } else {
337         ret = asn1p_constraint_insert(ct, ct_expr);
338         assert(ret == 0);
339     }
340
341     ct->type = ACT_CA_SET;
342
343     /* keep constrainedSubtype field for future usage,
344        if valueset has not been resolved yet. */
345     if(rtype &&
346         (rtype->meta_type == AMT_VALUESET) &&
347         (!rtype->ioc_table))
348         return 0;
349
350     asn1p_value_free(ct->containedSubtype);
351     ct->containedSubtype = NULL;
352
353     return 0;
354 }
355
356 static int
357 constraint_value_resolve(arg_t *arg, asn1p_value_t **value,
358                          enum asn1p_constraint_type_e real_ctype) {
359     asn1p_expr_t static_expr;
360         arg_t tmparg;
361         int rvalue = 0;
362         int ret;
363
364         DEBUG("(\"%s\", within <%s>)",
365                 asn1f_printable_value(*value),
366                 asn1p_constraint_type2str(real_ctype));
367
368         static_expr = *arg->expr;
369         static_expr.value = *value;
370         static_expr.meta_type = AMT_VALUE;
371         tmparg = *arg;
372         tmparg.mod = arg->expr->module;
373         tmparg.expr = &static_expr;
374         ret = asn1f_value_resolve(&tmparg, &static_expr, &real_ctype);
375         RET2RVAL(ret, rvalue);
376         assert(static_expr.value);
377         *value = static_expr.value;
378
379         return rvalue;
380 }
381
382 static int
383 constraint_object_resolve(arg_t *arg, asn1p_value_t *value) {
384     asn1p_expr_t tmp_expr = *arg->expr;
385         asn1p_expr_t *saved_expr = arg->expr;
386
387         tmp_expr.meta_type = AMT_VALUESET;
388         tmp_expr.expr_type = A1TC_REFERENCE;
389         tmp_expr.value = value;
390         arg->expr = &tmp_expr;
391
392         if (asn1f_check_class_object(arg)) {
393                 arg->expr = saved_expr;
394                 FATAL("Parsing ObjectSet %s failed at %d", arg->expr->Identifier,
395                                 arg->expr->_lineno);
396                 return -1;
397         }
398
399         arg->expr = saved_expr;
400         return 0;
401 }
402