8f4331c9f0bf39b4a4b9cf505f0991ca4ac5ee95
[com/asn1c.git] / libasn1fix / asn1fix_constr.c
1 #include "asn1fix_internal.h"
2
3 static int _asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v);
4 static int _asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b);
5 static int _asn1f_fix_type_tag(arg_t *arg, asn1p_expr_t *expr);
6
7 int
8 asn1f_pull_components_of(arg_t *arg) {
9         TQ_HEAD(asn1p_expr_t) list;
10         asn1p_expr_t *expr = arg->expr;
11         asn1p_expr_t *memb;
12         int r_value = 0;
13
14         switch(expr->expr_type) {
15         case ASN_CONSTR_SEQUENCE:
16         case ASN_CONSTR_SET:
17                 break;
18         default:
19                 return 0;
20         }
21
22         TQ_INIT(&list);
23
24         /*
25          * Look into
26          */
27         while((memb = TQ_REMOVE(&(expr->members), next))) {
28                 asn1p_expr_t *coft;     /* COMPONENTS OF thing itself */
29                 asn1p_expr_t *terminal; /* Terminal of the referenced type */
30
31                 if(memb->expr_type != A1TC_COMPONENTS_OF) {
32                         TQ_ADD(&list, memb, next);
33                         continue;
34                 }
35
36                 coft = TQ_FIRST(&memb->members);
37                 assert(coft);
38                 assert(!TQ_NEXT(coft, next));
39
40                 /*
41                  * Find the referenced type.
42                  */
43                 terminal = asn1f_find_terminal_type(arg, coft);
44                 if(!terminal || (terminal->expr_type != expr->expr_type)) {
45                         FATAL("COMPONENTS OF at line %d "
46                                 "must reference a %s type",
47                                 coft->_lineno,
48                                 expr->expr_type==ASN_CONSTR_SET
49                                         ? "SET" : "SEQUENCE"
50                         );
51                         TQ_ADD(&list, memb, next);
52                         r_value = -1;
53                         continue;
54                 }
55
56                 /*
57                  * Clone the final structure.
58                  */
59
60                 coft = asn1p_expr_clone(terminal, 1 /* Skip extensions */);
61                 if(!coft) return -1;    /* ENOMEM */
62
63                 if(1) {
64                         asn1p_expr_free(memb);  /* Don't need it anymore*/
65                 } else {
66                         /* Actual removal clashes with constraints... skip. */
67                 }
68
69                 /*
70                  * Move all components of the cloned structure
71                  * into the current one.
72                  */
73                 while((memb = TQ_REMOVE(&(coft->members), next))) {
74                         TQ_ADD(&list, memb, next);
75                         memb->parent_expr = expr;
76                 }
77
78                 asn1p_expr_free(coft);  /* Remove wrapper */
79         }
80
81         /* Move the stuff back */
82         TQ_MOVE(&(expr->members), &list);
83
84         return r_value;
85 }
86
87 /*
88  * Fix extensibility parts inside constructed types (SEQUENCE, SET, CHOICE).
89  */
90 int
91 asn1f_fix_constr_ext(arg_t *arg) {
92         asn1p_expr_t *expr = arg->expr;
93         asn1p_expr_t *v;
94         TQ_HEAD(asn1p_expr_t) root_list;
95         TQ_HEAD(asn1p_expr_t) ext_list;
96         TQ_HEAD(asn1p_expr_t) *cur_list;
97         int r_value = 0;
98         int ext_count = 0;
99
100         switch(expr->expr_type) {
101         case ASN_CONSTR_SEQUENCE:
102         case ASN_CONSTR_SET:
103         case ASN_CONSTR_CHOICE:
104                 break;
105         default:
106                 return 0;
107         }
108
109         DEBUG("(%s) for line %d", expr->Identifier, expr->_lineno);
110
111         TQ_INIT(&root_list);
112         TQ_INIT(&ext_list);
113         cur_list = (void *)&root_list;
114
115         /*
116          * Split the set of fields into two lists, the root list
117          * and the extensions list.
118          */
119         while((v = TQ_REMOVE(&(expr->members), next))) {
120                 if(v->expr_type == A1TC_EXTENSIBLE) {
121                         ext_count++;
122                         switch(ext_count) {
123                         case 1: cur_list = (void *)&ext_list; break;
124                         case 2:
125                                 cur_list = (void *)&root_list;
126                                 if(v->value) {
127                                         FATAL("Optional extension marker "
128                                                 "must not contain "
129                                                 "an exception mark "
130                                                 "at line %d", v->_lineno);
131                                         r_value = -1;
132                                 }
133                                 asn1p_expr_free(v);
134                                 continue;
135                         case 3:
136                                 FATAL("Third extension marker "
137                                 "is not allowed at line %d", v->_lineno);
138                 /* Fall through */
139                         default:
140                                 r_value = -1;
141                         }
142                 }
143
144                 TQ_ADD(cur_list, v, next);
145         }
146
147         /*
148          * Copy the root list and extension list back into the main list.
149          */
150         TQ_MOVE(&(expr->members), &root_list);
151         while((v = TQ_REMOVE(&ext_list, next)))
152                 TQ_ADD(&(expr->members), v, next);
153
154         if(arg->mod->module_flags & MSF_EXTENSIBILITY_IMPLIED
155         && ext_count == 0) {
156                 v = asn1p_expr_new(0, arg->mod);
157                 if(v) {
158                         v->Identifier = strdup("...");
159                         v->expr_type = A1TC_EXTENSIBLE;
160                         v->meta_type = AMT_TYPE;
161                         v->_lineno = expr->_lineno;     /* The best we can do */
162                         if(v->Identifier == NULL) {
163                                 asn1p_expr_free(v);
164                                 r_value = -1;
165                         } else {
166                                 asn1p_expr_add(expr, v);
167                         }
168                 } else {
169                         r_value = -1;
170                 }
171         }
172
173         return r_value;
174 }
175
176
177 int
178 asn1f_fix_constr_tag(arg_t *arg, int fix_top_level) {
179         asn1p_expr_t *expr = arg->expr;
180         asn1p_expr_t *v;
181         int root_tagged = 0;    /* The root component is manually tagged */
182         int ext_tagged = 0;     /* The extensions are manually tagged */
183         int component_number = 0;
184         int r_value = 0;
185
186         DEBUG("(%s) for line %d", expr->Identifier, expr->_lineno);
187
188         /*
189          * Fix the top-level type itself first.
190          */
191         if(fix_top_level) {
192                 if(expr->tag.tag_class == TC_NOCLASS)
193                         return r_value;
194
195                 if(_asn1f_fix_type_tag(arg, expr))
196                         r_value = -1;
197
198                 return r_value;
199         }
200
201         switch(expr->expr_type) {
202         case ASN_CONSTR_SEQUENCE:
203         case ASN_CONSTR_SET:
204         case ASN_CONSTR_CHOICE:
205                 break;
206         default:
207                 return 0;
208         }
209
210         TQ_FOR(v, &(expr->members), next) {
211
212                 if(v->expr_type == A1TC_EXTENSIBLE) {
213                         component_number++;
214                         continue;
215                 }
216
217                 if(v->tag.tag_class == TC_NOCLASS) {
218                         continue;
219                 }
220
221                 switch(component_number) {
222                 case 0: case 2:
223                         root_tagged = 1; break;
224                 default:
225                         ext_tagged = 1; break;
226                 }
227
228                 if(_asn1f_fix_type_tag(arg, v))
229                         r_value = -1;
230
231         }
232
233         if((arg->mod->module_flags & MSF_AUTOMATIC_TAGS)
234         && !root_tagged) {
235                 if(ext_tagged) {
236                         /* X.690: 28.4 */
237                         FATAL("In %s at line %d: "
238                                 "extensions are tagged "
239                                 "but root components are not",
240                                 expr->Identifier, expr->_lineno);
241                         r_value = -1;
242                 } else {
243                         /* Make a decision on automatic tagging */
244                         expr->auto_tags_OK = 1;
245                 }
246         }
247
248         return r_value;
249 }
250
251 static int
252 _asn1f_fix_type_tag(arg_t *arg, asn1p_expr_t *expr) {
253         int must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, expr);
254         int module_impl_tags = (arg->mod->module_flags
255                                 & (MSF_IMPLICIT_TAGS | MSF_AUTOMATIC_TAGS));
256         int r_value = 0;
257
258         if(expr->tag.tag_mode == TM_DEFAULT) {
259                 if(must_explicit || module_impl_tags == 0)
260                         expr->tag.tag_mode = TM_EXPLICIT;
261                 else
262                         expr->tag.tag_mode = TM_IMPLICIT;
263         }
264
265         /*
266          * Perform a final sanity check.
267          */
268         if(must_explicit) {
269                 if(expr->tag.tag_mode == TM_IMPLICIT) {
270                         FATAL("%s tagged in IMPLICIT mode "
271                                 "but must be EXPLICIT at line %d",
272                                 expr->Identifier, expr->_lineno);
273                         r_value = -1;
274                 } else {
275                         expr->tag.tag_mode = TM_EXPLICIT;
276                 }
277         }
278
279         return r_value;
280 }
281
282 int
283 asn1f_fix_constr_autotag(arg_t *arg) {
284         asn1p_expr_t *expr = arg->expr;
285         asn1p_expr_t *v;
286         asn1c_integer_t tag_value = 0;
287         int r_value = 0;
288
289         switch(expr->expr_type) {
290         case ASN_CONSTR_SEQUENCE:
291         case ASN_CONSTR_SET:
292         case ASN_CONSTR_CHOICE:
293                 if(expr->auto_tags_OK)
294                         break;
295                 /* Automatic tagging is not applicable */
296                 /* Fall through */
297         default:
298                 return 0;
299         }
300
301         DEBUG("(%s) for line %d", expr->Identifier, expr->_lineno);
302
303         TQ_FOR(v, &(expr->members), next) {
304                 int must_explicit;
305
306                 if(v->expr_type == A1TC_EXTENSIBLE) {
307                         /* 28.5, d) */
308                         continue;
309                 }
310
311                 if(0) {
312                         /* This may be not true in case COMPONENTS OF */
313                         assert(v->tag.tag_class == TC_NOCLASS);
314                 }
315
316                 must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, v);
317
318                 v->tag.tag_class = TC_CONTEXT_SPECIFIC;
319                 v->tag.tag_mode = must_explicit ? TM_EXPLICIT : TM_IMPLICIT;
320                 v->tag.tag_value = tag_value++;
321         }
322
323         return r_value;
324 }
325
326 /*
327  * Check that tags are distinct.
328  */
329 int
330 asn1f_check_constr_tags_distinct(arg_t *arg) {
331         asn1p_expr_t *expr = arg->expr;
332         asn1p_expr_t *v;
333         int r_value = 0;
334
335         switch(expr->expr_type) {
336         case ASN_CONSTR_SEQUENCE:
337         case ASN_CONSTR_SET:
338         case ASN_CONSTR_CHOICE:
339                 break;
340         default:
341                 return 0;
342         }
343
344         TQ_FOR(v, &(expr->members), next) {
345                 /*
346                  * In every series of non-mandatory components,
347                  * the tags must be distinct from each other AND the
348                  * tag of the following mandatory component.
349                  * For SET and CHOICE treat everything as a big set of
350                  * non-mandatory components.
351                  */
352                 if(expr->expr_type != ASN_CONSTR_SEQUENCE || v->marker.flags) {
353                         asn1p_expr_t *nv;
354                         for(nv = v; (nv = TQ_NEXT(nv, next));) {
355                                 DEBUG("S/C comparing tags %s s. %s",
356                                         v->Identifier, nv->Identifier);
357                                 if(_asn1f_compare_tags(arg, v, nv))
358                                         r_value = -1;
359                                 if(expr->expr_type == ASN_CONSTR_SEQUENCE
360                                 && !nv->marker.flags) break;
361                         }
362                 }
363         }
364
365         return r_value;
366 }
367
368 static int
369 _asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v) {
370         struct asn1p_type_tag_s tag;
371         struct asn1p_type_tag_s save_tag;
372         asn1p_expr_t *reft;
373         int ret;
374
375         /*
376          * Fetch the _next_ tag for this type.
377          */
378         save_tag = v->tag;                      /* Save existing tag */
379         memset(&v->tag, 0, sizeof(v->tag));     /* Remove it temporarily */
380         ret = asn1f_fetch_outmost_tag(arg->asn, arg->ns, arg->mod, v, &tag, 0);
381         v->tag = save_tag;                      /* Restore the tag back */
382
383         if(ret == 0) return 0;  /* If found tag, it's okay */
384
385         reft = asn1f_find_terminal_type(arg, v);
386         if(reft) {
387                 switch(reft->expr_type) {
388                 case ASN_TYPE_ANY:
389                 case ASN_CONSTR_CHOICE:
390                         return 1;
391                 default:
392                         return 0;
393                 }
394         }
395
396         return 0;
397 }
398
399 /*
400  * Check that the tags are distinct.
401  */
402 static int
403 _asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
404         struct asn1p_type_tag_s ta, tb;
405         int ra, rb;
406         int ret;
407
408         ra = asn1f_fetch_outmost_tag(arg->asn, arg->ns, arg->mod, a,
409                         &ta, AFT_IMAGINARY_ANY);
410         rb = asn1f_fetch_outmost_tag(arg->asn, arg->ns, arg->mod, b,
411                         &tb, AFT_IMAGINARY_ANY);
412
413         /*
414          * If both tags are explicitly or implicitly given, use them.
415          */
416         DEBUG("Fetching outmost tags: %d, %d", ra, rb);
417         if(ra == 0 && rb == 0) {
418                 /*
419                  * Simple case: fetched both tags.
420                  */
421
422                 if((ta.tag_value == tb.tag_value
423                         && ta.tag_class == tb.tag_class)
424                 || ta.tag_value == -1   /* Spread IMAGINARY ANY tag... */
425                 || tb.tag_value == -1   /* ...it is an evil virus, fear it! */
426                 ) {
427                         char tagbuf[2][TAG2STRING_BUFFER_SIZE];
428                         char *p = (a->expr_type == A1TC_EXTENSIBLE)
429                                 ?"potentially ":"";
430                         FATAL("Processing %s at line %d: component \"%s\" at line %d %shas the same tag "
431                                 "as component \"%s\" at line %d",
432                                 arg->expr->Identifier,
433                                 arg->expr->_lineno,
434                                 a->Identifier,
435                                 a->_lineno,
436                                 p,
437                                 b->Identifier,
438                                 b->_lineno
439                         );
440                         FATAL("Consider adding AUTOMATIC TAGS "
441                                 "after module %s DEFINITIONS, "
442                                 "or manually tag components",
443                                 arg->expr->module->ModuleName);
444                         DEBUG("Tags: %s %s  vs.  %s %s",
445                                 asn1p_tag2string(&ta, tagbuf[0]),
446                                 a->Identifier,
447                                 asn1p_tag2string(&tb, tagbuf[1]),
448                                 b->Identifier
449                         );
450                         if((arg->mod->module_flags & MSF_EXTENSIBILITY_IMPLIED)
451                         && (a->expr_type == A1TC_EXTENSIBLE)
452                         && (b->expr_type == A1TC_EXTENSIBLE)) {
453                                 FATAL("The previous error is due to "
454                                         "improper use of "
455                                         "EXTENSIBILITY IMPLIED flag "
456                                         "of module %s",
457                                         arg->mod->ModuleName);
458                         }
459                         return -1;
460                 } else {
461                         /* Tags are distinct */
462                         return 0;
463                 }
464         }
465
466         /**********************************************************
467          * Now we must perform some very funny recursion to check
468          * multiple components of CHOICE type, etc.
469          */
470
471         DEBUG("Comparing tags %s:%x <-> %s:%x",
472                 a->Identifier, a->expr_type,
473                 b->Identifier, b->expr_type);
474
475         if(ra && a->meta_type == AMT_TYPEREF) {
476
477                 DEBUG(" %s is a type reference", a->Identifier);
478
479         a = asn1f_lookup_symbol(arg, a->rhs_pspecs, a->reference);
480         if(!a) return 0;        /* Already FATAL()'ed somewhere else */
481         return WITH_MODULE(a->module, _asn1f_compare_tags(arg, a, b));
482     }
483
484         if(ra && a->expr_type == ASN_CONSTR_CHOICE) {
485                 asn1p_expr_t *v;
486
487                 DEBUG(" %s is a choice type (%d)", a->Identifier, a->_mark);
488
489                 /*
490                  * Iterate over members of CHOICE.
491                  */
492                 //if(a->_mark & TM_RECURSION) return 0;
493                 TQ_FOR(v, &(a->members), next) {
494                         //a->_mark |= TM_RECURSION;
495                         ret = _asn1f_compare_tags(arg, v, b);
496                         //a->_mark &= ~TM_RECURSION;
497                         if(ret) return ret;
498                 }
499                 return 0;
500         }
501
502         if(rb && b->expr_type == ASN_CONSTR_CHOICE) {
503                 return _asn1f_compare_tags(arg, b, a);
504         }
505
506         if(a->_mark & TM_RECURSION) return 0;
507         if(b->_mark & TM_RECURSION) return 0;
508         a->_mark |= TM_RECURSION;
509         b->_mark |= TM_RECURSION;
510         ret = _asn1f_compare_tags(arg, b, a);
511         a->_mark &= ~TM_RECURSION;
512         b->_mark &= ~TM_RECURSION;
513
514         return ret;
515 }
516