blob: b71d874cd70c76ad97d4990f20a156545a2ab630 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
2
Lev Walkin8945e0e2004-09-10 06:07:04 +00003#define AFT_MAGIC_ANY 1 /* _fetch_tag() flag */
Lev Walkind541c252004-09-05 10:36:22 +00004
Lev Walkinf15320b2004-06-03 03:38:44 +00005static int _asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v);
6static int _asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b);
Lev Walkind541c252004-09-05 10:36:22 +00007static int _asn1f_fix_type_tag(arg_t *arg, asn1p_expr_t *expr);
Lev Walkinf15320b2004-06-03 03:38:44 +00008
Lev Walkin4ec3b4c2004-08-22 03:09:24 +00009int
10asn1f_pull_components_of(arg_t *arg) {
11 TQ_HEAD(asn1p_expr_t) list;
12 asn1p_expr_t *expr = arg->expr;
13 asn1p_expr_t *memb;
14 int r_value = 0;
15
16 switch(expr->expr_type) {
17 case ASN_CONSTR_SEQUENCE:
18 case ASN_CONSTR_SET:
19 break;
20 default:
21 return 0;
22 }
23
24 TQ_INIT(&list);
25
26 /*
27 * Look into
28 */
29 while((memb = TQ_REMOVE(&(expr->members), next))) {
30 asn1p_expr_t *coft; /* COMPONENTS OF thing itself */
31 asn1p_expr_t *terminal; /* Terminal of the referenced type */
32
33 if(memb->expr_type != A1TC_COMPONENTS_OF) {
34 TQ_ADD(&list, memb, next);
35 continue;
36 }
37
38 coft = TQ_FIRST(&memb->members);
39 assert(coft);
40 assert(!TQ_NEXT(coft, next));
41
42 /*
43 * Find the referenced type.
44 */
45 terminal = asn1f_find_terminal_type(arg, coft);
46 if(!terminal || (terminal->expr_type != expr->expr_type)) {
47 FATAL("COMPONENTS OF at line %d "
48 "must reference a %s type",
49 coft->_lineno,
50 expr->expr_type==ASN_CONSTR_SET
51 ? "SET" : "SEQUENCE"
52 );
53 TQ_ADD(&list, memb, next);
54 r_value = -1;
55 continue;
56 }
57
58 /*
59 * Clone the final structure.
60 */
61
62 coft = asn1p_expr_clone(terminal, 1 /* Skip extensions */);
63 if(!coft) return -1; /* ENOMEM */
64
Lev Walkin75d76b42005-04-13 13:20:20 +000065 if(0) {
66 asn1p_expr_free(memb); /* Don't need it anymore*/
67 } else {
68 /* Actual removal clashes with constraints... skip. */
69 }
Lev Walkin4ec3b4c2004-08-22 03:09:24 +000070
71 /*
72 * Move all components of the cloned structure
73 * into the current one.
74 */
Lev Walkin1004aa92004-09-08 00:28:11 +000075 while((memb = TQ_REMOVE(&(coft->members), next))) {
Lev Walkin4ec3b4c2004-08-22 03:09:24 +000076 TQ_ADD(&list, memb, next);
Lev Walkin1004aa92004-09-08 00:28:11 +000077 memb->parent_expr = expr;
78 }
Lev Walkin4ec3b4c2004-08-22 03:09:24 +000079
80 asn1p_expr_free(coft); /* Remove wrapper */
81 }
82
83 /* Move the stuff back */
Lev Walkin1ef05162004-08-25 00:42:25 +000084 TQ_MOVE(&(expr->members), &list);
Lev Walkin4ec3b4c2004-08-22 03:09:24 +000085
86 return r_value;
87}
Lev Walkinf15320b2004-06-03 03:38:44 +000088
Lev Walkind541c252004-09-05 10:36:22 +000089/*
90 * Fix extensibility parts inside constructed types (SEQUENCE, SET, CHOICE).
91 */
Lev Walkinf15320b2004-06-03 03:38:44 +000092int
93asn1f_fix_constr_ext(arg_t *arg) {
94 asn1p_expr_t *expr = arg->expr;
95 asn1p_expr_t *v;
96 TQ_HEAD(asn1p_expr_t) root_list;
97 TQ_HEAD(asn1p_expr_t) ext_list;
98 TQ_HEAD(asn1p_expr_t) *cur_list;
99 int r_value = 0;
100 int ext_count = 0;
101
102 switch(expr->expr_type) {
103 case ASN_CONSTR_SEQUENCE:
104 case ASN_CONSTR_SET:
105 case ASN_CONSTR_CHOICE:
106 break;
107 default:
108 return 0;
109 }
110
Lev Walkin03850182005-03-10 10:02:50 +0000111 DEBUG("(%s) for line %d", expr->Identifier, expr->_lineno);
Lev Walkinf15320b2004-06-03 03:38:44 +0000112
113 TQ_INIT(&root_list);
114 TQ_INIT(&ext_list);
115 cur_list = (void *)&root_list;
116
Lev Walkind541c252004-09-05 10:36:22 +0000117 /*
118 * Split the set of fields into two lists, the root list
119 * and the extensions list.
120 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000121 while((v = TQ_REMOVE(&(expr->members), next))) {
122 if(v->expr_type == A1TC_EXTENSIBLE) {
123 ext_count++;
124 switch(ext_count) {
125 case 1: cur_list = (void *)&ext_list; break;
126 case 2:
127 cur_list = (void *)&root_list;
128 if(v->value) {
129 FATAL("Optional extension marker "
130 "must not contain "
131 "an exception mark "
132 "at line %d", v->_lineno);
133 r_value = -1;
134 }
135 asn1p_expr_free(v);
136 continue;
137 case 3:
138 FATAL("Third extension marker "
139 "is not allowed at line %d", v->_lineno);
140 default:
141 r_value = -1;
142 }
143 }
144
145 TQ_ADD(cur_list, v, next);
146 }
147
148 /*
149 * Copy the root list and extension list back into the main list.
150 */
Lev Walkin1ef05162004-08-25 00:42:25 +0000151 TQ_MOVE(&(expr->members), &root_list);
Lev Walkinf15320b2004-06-03 03:38:44 +0000152 while((v = TQ_REMOVE(&ext_list, next)))
153 TQ_ADD(&(expr->members), v, next);
154
155 if(arg->mod->module_flags & MSF_EXTENSIBILITY_IMPLIED
Lev Walkin1ef05162004-08-25 00:42:25 +0000156 && ext_count == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000157 v = asn1p_expr_new(0);
158 if(v) {
159 v->Identifier = strdup("...");
160 v->expr_type = A1TC_EXTENSIBLE;
161 v->meta_type = AMT_TYPE;
Lev Walkin7ccf2a42004-07-01 00:51:31 +0000162 v->_lineno = expr->_lineno; /* The best we can do */
Lev Walkinf15320b2004-06-03 03:38:44 +0000163 if(v->Identifier == NULL) {
164 asn1p_expr_free(v);
165 r_value = -1;
166 } else {
Lev Walkin1004aa92004-09-08 00:28:11 +0000167 asn1p_expr_add(expr, v);
Lev Walkinf15320b2004-06-03 03:38:44 +0000168 }
169 } else {
170 r_value = -1;
171 }
172 }
173
174 return r_value;
175}
176
177
178int
Lev Walkind541c252004-09-05 10:36:22 +0000179asn1f_fix_constr_tag(arg_t *arg, int fix_top_level) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000180 asn1p_expr_t *expr = arg->expr;
181 asn1p_expr_t *v;
Lev Walkinf15320b2004-06-03 03:38:44 +0000182 int root_tagged = 0; /* The root component is manually tagged */
183 int ext_tagged = 0; /* The extensions are manually tagged */
184 int component_number = 0;
185 int r_value = 0;
186
Lev Walkin03850182005-03-10 10:02:50 +0000187 DEBUG("(%s) for line %d", expr->Identifier, expr->_lineno);
Lev Walkind541c252004-09-05 10:36:22 +0000188
189 /*
190 * Fix the top-level type itself first.
191 */
192 if(fix_top_level) {
193 if(expr->tag.tag_class == TC_NOCLASS)
194 return r_value;
195
196 if(_asn1f_fix_type_tag(arg, expr))
197 r_value = -1;
198
199 return r_value;
200 }
201
Lev Walkinf15320b2004-06-03 03:38:44 +0000202 switch(expr->expr_type) {
203 case ASN_CONSTR_SEQUENCE:
204 case ASN_CONSTR_SET:
205 case ASN_CONSTR_CHOICE:
206 break;
207 default:
208 return 0;
209 }
210
Lev Walkinf15320b2004-06-03 03:38:44 +0000211 TQ_FOR(v, &(expr->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000212
213 if(v->expr_type == A1TC_EXTENSIBLE) {
214 component_number++;
215 continue;
216 }
217
218 if(v->tag.tag_class == TC_NOCLASS) {
219 continue;
Lev Walkinf15320b2004-06-03 03:38:44 +0000220 }
221
Lev Walkind541c252004-09-05 10:36:22 +0000222 switch(component_number) {
223 case 0: case 2:
224 root_tagged = 1; break;
225 default:
226 ext_tagged = 1; break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000227 }
228
Lev Walkind541c252004-09-05 10:36:22 +0000229 if(_asn1f_fix_type_tag(arg, v))
230 r_value = -1;
231
Lev Walkinf15320b2004-06-03 03:38:44 +0000232 }
233
Lev Walkind43915b2004-09-15 11:48:34 +0000234 if((arg->mod->module_flags & MSF_AUTOMATIC_TAGS)
235 && !root_tagged) {
236 if(ext_tagged) {
237 /* X.690: 28.4 */
238 FATAL("In %s at line %d: "
239 "extensions are tagged "
240 "but root components are not",
241 expr->Identifier, expr->_lineno);
242 r_value = -1;
243 } else {
244 /* Make a decision on automatic tagging */
245 expr->auto_tags_OK = 1;
246 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000247 }
248
249 return r_value;
250}
251
Lev Walkind541c252004-09-05 10:36:22 +0000252static int
253_asn1f_fix_type_tag(arg_t *arg, asn1p_expr_t *expr) {
254 int must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, expr);
Lev Walkin07f388c2004-10-11 11:43:08 +0000255 int module_impl_tags = (arg->mod->module_flags & MSF_IMPLICIT_TAGS);
Lev Walkind541c252004-09-05 10:36:22 +0000256 int r_value = 0;
257
Lev Walkin07f388c2004-10-11 11:43:08 +0000258 if(expr->tag.tag_mode == TM_DEFAULT) {
259 if(must_explicit || module_impl_tags == 0)
Lev Walkind541c252004-09-05 10:36:22 +0000260 expr->tag.tag_mode = TM_EXPLICIT;
Lev Walkin07f388c2004-10-11 11:43:08 +0000261 else
262 expr->tag.tag_mode = TM_IMPLICIT;
Lev Walkind541c252004-09-05 10:36:22 +0000263 }
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
Lev Walkinf15320b2004-06-03 03:38:44 +0000282int
283asn1f_fix_constr_autotag(arg_t *arg) {
284 asn1p_expr_t *expr = arg->expr;
285 asn1p_expr_t *v;
Lev Walkinb8108ec2004-09-29 13:17:17 +0000286 asn1c_integer_t tag_value = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000287 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
Lev Walkin03850182005-03-10 10:02:50 +0000301 DEBUG("(%s) for line %d", expr->Identifier, expr->_lineno);
Lev Walkinf15320b2004-06-03 03:38:44 +0000302
303 TQ_FOR(v, &(expr->members), next) {
304 int must_explicit;
305
Lev Walkin144db9b2004-10-12 23:26:53 +0000306 if(v->expr_type == A1TC_EXTENSIBLE) {
307 /* 28.5, d) */
308 continue;
309 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000310
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000311 if(0) {
312 /* This may be not true in case COMPONENTS OF */
313 assert(v->tag.tag_class == TC_NOCLASS);
314 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000315
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 */
329int
330asn1f_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 */
Lev Walkind43915b2004-09-15 11:48:34 +0000352 if(expr->expr_type != ASN_CONSTR_SEQUENCE || v->marker.flags) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000353 asn1p_expr_t *nv;
354 for(nv = v; (nv = TQ_NEXT(nv, next));) {
355 if(_asn1f_compare_tags(arg, v, nv))
356 r_value = -1;
357 if(expr->expr_type == ASN_CONSTR_SEQUENCE
Lev Walkind43915b2004-09-15 11:48:34 +0000358 && !nv->marker.flags) break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000359 }
360 }
361 }
362
363 return r_value;
364}
365
366static int
367_asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v) {
Lev Walkind541c252004-09-05 10:36:22 +0000368 struct asn1p_type_tag_s tag;
369 struct asn1p_type_tag_s save_tag;
Lev Walkinf15320b2004-06-03 03:38:44 +0000370 asn1p_expr_t *reft;
Lev Walkind541c252004-09-05 10:36:22 +0000371 int ret;
372
373 /*
374 * Fetch the _next_ tag for this type.
375 */
376 save_tag = v->tag; /* Save existing tag */
377 memset(&v->tag, 0, sizeof(v->tag)); /* Remove it temporarily */
Lev Walkin8945e0e2004-09-10 06:07:04 +0000378 ret = asn1f_fetch_outmost_tag(arg->asn, arg->mod, v, &tag, 0);
Lev Walkind541c252004-09-05 10:36:22 +0000379 v->tag = save_tag; /* Restore the tag back */
380
381 if(ret == 0) return 0; /* If found tag, it's okay */
Lev Walkinf15320b2004-06-03 03:38:44 +0000382
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000383 reft = asn1f_find_terminal_type(arg, v);
Lev Walkinf15320b2004-06-03 03:38:44 +0000384 if(reft) {
385 switch(reft->expr_type) {
Lev Walkind541c252004-09-05 10:36:22 +0000386 case ASN_TYPE_ANY:
Lev Walkinf15320b2004-06-03 03:38:44 +0000387 case ASN_CONSTR_CHOICE:
388 return 1;
389 default:
390 return 0;
391 }
392 }
393
394 return 0;
395}
396
397/*
398 * Check that the tags are distinct.
399 */
400static int
401_asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
402 struct asn1p_type_tag_s ta, tb;
403 int ra, rb;
404 int ret;
405
Lev Walkin8945e0e2004-09-10 06:07:04 +0000406 ra = asn1f_fetch_outmost_tag(arg->asn, arg->mod, a, &ta, AFT_MAGIC_ANY);
407 rb = asn1f_fetch_outmost_tag(arg->asn, arg->mod, b, &tb, AFT_MAGIC_ANY);
Lev Walkinf15320b2004-06-03 03:38:44 +0000408
409 /*
410 * If both tags are explicitly or implicitly given, use them.
411 */
412 if(ra == 0 && rb == 0) {
413 /*
414 * Simple case: fetched both tags.
415 */
Lev Walkind541c252004-09-05 10:36:22 +0000416
417 if((ta.tag_value == tb.tag_value
418 && ta.tag_class == tb.tag_class)
419 || ta.tag_value == -1 /* Spread IMAGINARY ANY tag... */
420 || tb.tag_value == -1 /* ...it is an evil virus, fear it! */
421 ) {
Lev Walkin71160962005-06-02 05:21:53 +0000422 char tagbuf[2][TAG2STRING_BUFFER_SIZE];
Lev Walkinf15320b2004-06-03 03:38:44 +0000423 char *p = (a->expr_type == A1TC_EXTENSIBLE)
424 ?"potentially ":"";
Lev Walkind43915b2004-09-15 11:48:34 +0000425 FATAL("Processing %s at line %d: component \"%s\" at line %d %shas the same tag "
Lev Walkinf15320b2004-06-03 03:38:44 +0000426 "with component \"%s\" at line %d",
Lev Walkind43915b2004-09-15 11:48:34 +0000427 arg->expr->Identifier,
428 arg->expr->_lineno,
Lev Walkinf15320b2004-06-03 03:38:44 +0000429 a->Identifier,
430 a->_lineno,
431 p,
432 b->Identifier,
433 b->_lineno
434 );
Lev Walkin71160962005-06-02 05:21:53 +0000435 DEBUG("Tags: %s %s vs. %s %s",
436 asn1p_tag2string(&ta, tagbuf[0]),
437 a->Identifier,
438 asn1p_tag2string(&tb, tagbuf[1]),
439 b->Identifier
440 );
Lev Walkin7ccf2a42004-07-01 00:51:31 +0000441 if((arg->mod->module_flags & MSF_EXTENSIBILITY_IMPLIED)
442 && (a->expr_type == A1TC_EXTENSIBLE)
443 && (b->expr_type == A1TC_EXTENSIBLE)) {
444 FATAL("The previous error is due to "
445 "improper use of "
446 "EXTENSIBILITY IMPLIED flag "
447 "of module %s",
448 arg->mod->Identifier);
449 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000450 return -1;
451 } else {
452 /* Tags are distinct */
453 return 0;
454 }
455 }
456
457 /**********************************************************
458 * Now we must perform some very funny recursion to check
459 * multiple components of CHOICE type, etc.
460 */
461
462 DEBUG("Comparing tags %s:%x <-> %s:%x",
463 a->Identifier, a->expr_type,
464 b->Identifier, b->expr_type);
465
Lev Walkind43915b2004-09-15 11:48:34 +0000466 if(ra && a->meta_type == AMT_TYPEREF) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000467
468 DEBUG(" %s is a type reference", a->Identifier);
469
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000470 a = asn1f_lookup_symbol(arg, a->module, a->reference);
Lev Walkinf15320b2004-06-03 03:38:44 +0000471 if(!a) return 0; /* Already FATAL()'ed somewhere else */
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000472 WITH_MODULE(a->module, ret = _asn1f_compare_tags(arg, a, b));
Lev Walkinf15320b2004-06-03 03:38:44 +0000473 return ret;
474 }
475
Lev Walkind43915b2004-09-15 11:48:34 +0000476 if(ra && a->expr_type == ASN_CONSTR_CHOICE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000477 asn1p_expr_t *v;
478
479 DEBUG(" %s is a choice type (%d)", a->Identifier, a->_mark);
480
481 /*
482 * Iterate over members of CHOICE.
483 */
484 //if(a->_mark & TM_RECURSION) return 0;
485 TQ_FOR(v, &(a->members), next) {
486 //a->_mark |= TM_RECURSION;
487 ret = _asn1f_compare_tags(arg, v, b);
488 //a->_mark &= ~TM_RECURSION;
489 if(ret) return ret;
490 }
491 return 0;
492 }
493
Lev Walkind43915b2004-09-15 11:48:34 +0000494 if(rb && b->expr_type == ASN_CONSTR_CHOICE) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000495 return _asn1f_compare_tags(arg, b, a);
496 }
497
498 if(a->_mark & TM_RECURSION) return 0;
499 if(b->_mark & TM_RECURSION) return 0;
500 a->_mark |= TM_RECURSION;
501 b->_mark |= TM_RECURSION;
502 ret = _asn1f_compare_tags(arg, b, a);
503 a->_mark &= ~TM_RECURSION;
504 b->_mark &= ~TM_RECURSION;
505
506 return ret;
507}
508