blob: d76a33989117987ed27bf7b87f833e2957d3bfbc [file] [log] [blame]
Lev Walkin4efbfb72005-02-25 14:20:30 +00001#include "asn1fix_internal.h"
2#include "asn1fix_constraint.h"
3#include "asn1fix_crange.h"
Lev Walkinb45e0672004-08-18 05:42:05 +00004
5#undef FATAL
6#define FATAL(fmt, args...) do { \
7 fprintf(stderr, "FATAL: "); \
8 fprintf(stderr, fmt, ##args); \
9 fprintf(stderr, "\n"); \
10 } while(0)
11
12void
13asn1constraint_range_free(asn1cnst_range_t *cr) {
14 if(cr) {
15 int i;
16 if(cr->elements) {
17 for(i = 0; i < cr->el_count; i++)
18 asn1constraint_range_free(cr->elements[i]);
19 free(cr->elements);
20 }
21 free(cr);
22 }
23}
24#define _range_free(foo) asn1constraint_range_free(foo)
25
26static asn1cnst_range_t *_range_new() {
27 asn1cnst_range_t *r;
28 r = calloc(1, sizeof(*r));
29 if(r) {
30 r->left.type = ARE_MIN;
31 r->right.type = ARE_MAX;
32 }
33 return r;
34}
35
36static void _range_remove_element(asn1cnst_range_t *range, int idx) {
37 assert(idx >= 0 && idx < range->el_count);
38
39 assert(!range->elements[idx]->elements);
40
41 _range_free(range->elements[idx]);
42
43 memmove(&range->elements[idx],
44 &range->elements[idx + 1],
45 (range->el_count - idx - 1)
46 * sizeof(range->elements[0])
47 );
48 range->el_count--;
49 range->elements[range->el_count] = 0; /* JIC */
50
51 if(range->el_count == 0) {
52 range->el_size = 0;
53 free(range->elements);
54 range->elements = 0;
55 }
56}
57
58static int _range_insert(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
59
60 assert(!cr->elements);
61
62 if(into->el_count == into->el_size) {
63 void *p;
64 int n = into->el_size?(into->el_size << 1):4;
65 p = realloc(into->elements, n * sizeof(into->elements[0]));
66 if(p) {
67 into->el_size = n;
68 into->elements = p;
69 } else {
70 assert(p);
71 return -1;
72 }
73 }
74
75 into->elements[into->el_count++] = cr;
76 return 0;
77}
78
79static asn1cnst_range_t *_range_clone(const asn1cnst_range_t *range) {
80 asn1cnst_range_t *clone;
81 int i;
82
83 clone = _range_new();
84 if(!clone) return NULL;
85
86 *clone = *range;
87 clone->elements = 0;
88 clone->el_count = 0;
89 clone->el_size = 0;
90
91 for(i = 0; i < range->el_count; i++) {
92 asn1cnst_range_t *r = _range_clone(range->elements[i]);
93 if(!r || _range_insert(clone, r)) {
94 _range_free(clone);
95 _range_free(r);
96 return NULL;
97 }
98 }
99
100 return clone;
101}
102
103static int
104_edge_compare(const asn1cnst_edge_t *el, const asn1cnst_edge_t *er) {
105
106 switch(el->type) {
107 case ARE_MIN:
108 switch(er->type) {
109 case ARE_MIN: return 0;
110 case ARE_MAX: return -1;
111 case ARE_VALUE: return -1;
112 }
113 break;
114 case ARE_MAX:
115 switch(er->type) {
116 case ARE_MIN: return 1;
117 case ARE_MAX: return 0;
118 case ARE_VALUE: return 1;
119 }
120 break;
121 case ARE_VALUE:
122 switch(er->type) {
123 case ARE_MIN: return 1;
124 case ARE_MAX: return -1;
125 case ARE_VALUE:
126 if(el->value < er->value)
127 return -1;
128 if(el->value > er->value)
129 return 1;
130 return 0;
131 }
132 break;
133 }
134
135 return 0;
136}
137
138static int
139_range_compare(const void *a, const void *b) {
140 const asn1cnst_range_t *ra = *(const asn1cnst_range_t * const *)a;
141 const asn1cnst_range_t *rb = *(const asn1cnst_range_t * const *)b;
142 int ret;
143
144 ret = _edge_compare(&ra->left, &rb->left);
145 if(!ret) {
146 ret = _edge_compare(&ra->right, &rb->right);
147 }
148
149 return ret;
150}
151
152static char *
153_edge_value(const asn1cnst_edge_t *edge) {
154 static char buf[128];
155 *buf = '\0';
156 switch(edge->type) {
157 case ARE_MIN: strcpy(buf, "MIN"); break;
158 case ARE_MAX: strcpy(buf, "MAX"); break;
159 case ARE_VALUE:
Lev Walkin33c16ba2004-09-24 21:01:43 +0000160 snprintf(buf, sizeof(buf), "%" PRIdASN, edge->value);
Lev Walkinb45e0672004-08-18 05:42:05 +0000161 }
162 return buf;
163}
164
Lev Walkinb45e0672004-08-18 05:42:05 +0000165static int
166_edge_is_within(const asn1cnst_range_t *range, const asn1cnst_edge_t *edge) {
167 int i;
168
169 for(i = -1; i < range->el_count; i++) {
170 const asn1cnst_range_t *r;
171 if(i == -1) {
172 if(range->el_count) continue;
173 r = range;
174 } else {
175 r = range->elements[i];
176 }
177 if(_edge_compare(&r->left, edge) <= 0
178 && _edge_compare(&r->right, edge) >= 0)
179 return 1;
180 }
181
182 return 0;
183}
184
185static int
186_check_edges_within(const asn1cnst_range_t *range, const asn1cnst_range_t *r) {
187
188 if(!_edge_is_within(range, &r->left)) {
189 FATAL("Constraint value %s at line %d "
190 "is not within "
191 "a parent constraint range",
192 _edge_value(&r->left),
193 r->left.lineno
194 );
195 return -1;
196 }
197
198 if(!_edge_is_within(range, &r->right)) {
199 FATAL("Constraint value %s at line %d "
200 "is not within "
201 "a parent constraint range",
202 _edge_value(&r->right),
203 r->right.lineno
204 );
205 return -1;
206 }
207
208 return 0;
209}
210
211static int _range_merge_in(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
212 asn1cnst_range_t *r;
213 int prev_count = into->el_count;
214 int i;
215
Lev Walkinb74ac572004-08-25 02:05:28 +0000216 into->not_PER_visible |= cr->not_PER_visible;
217 into->extensible |= cr->extensible;
218
Lev Walkinb45e0672004-08-18 05:42:05 +0000219 /*
220 * Add the element OR all its children "into".
221 */
222 for(i = -1; i < cr->el_count; i++) {
223
224 if(i == -1) {
225 if(cr->el_count) continue;
226 r = cr;
227 } else {
228 r = cr->elements[i];
229 }
230
231 if(_range_insert(into, r)) {
232 into->el_count = prev_count; /* Undo */
233 return -1;
234 }
235 }
236
237 if(cr->el_count) {
238 cr->el_count = 0;
239 _range_free(cr);
240 } else {
241 /* This range is linked into "into". */
242 }
243
244 return 0;
245}
246
247static int _range_fill(asn1p_value_t *val, const asn1cnst_range_t *minmax, asn1cnst_edge_t *edge, asn1cnst_range_t *range, enum asn1p_constraint_type_e type, int lineno) {
248 unsigned char *p, *pend;
249
250 edge->lineno = lineno;
251
252 switch(val->type) {
253 case ATV_INTEGER:
254 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000255 FATAL("Integer %" PRIdASN " value invalid "
Lev Walkinb45e0672004-08-18 05:42:05 +0000256 "for %s constraint at line %d",
Lev Walkin33c16ba2004-09-24 21:01:43 +0000257 val->value.v_integer,
Lev Walkinb45e0672004-08-18 05:42:05 +0000258 asn1p_constraint_type2str(type), lineno);
259 return -1;
260 }
261 edge->type = ARE_VALUE;
262 edge->value = val->value.v_integer;
263 return 0;
264 case ATV_MIN:
265 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
266 FATAL("MIN invalid for %s constraint at line %d",
267 asn1p_constraint_type2str(type), lineno);
268 return -1;
269 }
270 edge->type = ARE_MIN;
271 if(minmax) *edge = minmax->left;
272 edge->lineno = lineno; /* Restore lineno */
273 return 0;
274 case ATV_MAX:
275 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
276 FATAL("MAX invalid for %s constraint at line %d",
277 asn1p_constraint_type2str(type), lineno);
278 return -1;
279 }
280 edge->type = ARE_MAX;
281 if(minmax) *edge = minmax->right;
282 edge->lineno = lineno; /* Restore lineno */
283 return 0;
284 case ATV_FALSE:
285 case ATV_TRUE:
286 if(type != ACT_EL_RANGE) {
287 FATAL("%s is invalid for %s constraint at line %d",
288 val->type==ATV_TRUE?"TRUE":"FALSE",
289 asn1p_constraint_type2str(type),
290 lineno);
291 return -1;
292 }
293 edge->type = ARE_VALUE;
294 edge->value = (val->type==ATV_TRUE);
295 return 0;
Lev Walkin1e448d32005-03-24 14:26:38 +0000296 case ATV_TUPLE:
297 case ATV_QUADRUPLE:
298 edge->type = ARE_VALUE;
299 edge->value = val->value.v_integer;
300 return 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000301 case ATV_STRING:
302 if(type != ACT_CT_FROM)
303 return 0;
304 break;
Lev Walkin1ef05162004-08-25 00:42:25 +0000305 case ATV_REFERENCED:
Lev Walkinfd97d5e2004-09-15 11:45:44 +0000306 FATAL("Unresolved constraint element \"%s\" at line %d",
Lev Walkin1ef05162004-08-25 00:42:25 +0000307 asn1f_printable_reference(val->value.reference),
308 lineno);
309 return -1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000310 default:
311 FATAL("Unrecognized constraint element at line %d",
312 lineno);
313 return -1;
314 }
315
316 assert(val->type == ATV_STRING);
317
318 p = val->value.string.buf;
319 pend = p + val->value.string.size;
320 if(p == pend) return 0;
321
322 edge->type = ARE_VALUE;
323 if(val->value.string.size == 1) {
324 edge->value = *p;
325 } else {
326 /*
327 * Else this is a set:
328 * (FROM("abcdef"))
329 * However, (FROM("abc".."def")) is forbidden.
330 * See also 47.4.4.
331 */
Lev Walkinb8108ec2004-09-29 13:17:17 +0000332 asn1c_integer_t vmin, vmax;
Lev Walkinb45e0672004-08-18 05:42:05 +0000333 vmin = vmax = *p;
334 for(; p < pend; p++) {
335 asn1cnst_range_t *nr = _range_new();
336 int ret;
337 assert(nr);
338
339 if(*p < vmin) vmin = *p;
340 if(*p > vmax) vmax = *p;
341
342 ret = _range_insert(range, nr);
343 assert(ret == 0);
344
345 nr->left.type = ARE_VALUE;
346 nr->left.value = *p;
347 nr->left.lineno = lineno;
348 nr->right = nr->left;
349 }
350 edge->value = (edge == &range->right) ? vmin : vmax;
351 }
352
353 return 0;
354}
355
356/*
357 * Check if ranges contain common elements.
358 */
359static int
360_range_overlap(const asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
361 int lr, rl;
362 const asn1cnst_edge_t *ra_l = &ra->left;
363 const asn1cnst_edge_t *ra_r = &ra->right;
364 const asn1cnst_edge_t *rb_l = &rb->left;
365 const asn1cnst_edge_t *rb_r = &rb->right;
366
367 assert(_edge_compare(ra_l, ra_r) <= 0);
368 assert(_edge_compare(rb_l, rb_r) <= 0);
369
370 lr = _edge_compare(ra_l, rb_r);
371 rl = _edge_compare(ra_r, rb_l);
372
373 /*
374 * L: |---|
375 * R: |---|
376 */
377 if(lr > 0) return 0;
378
379 /*
380 * L: |---|
381 * R: |---|
382 */
383 if(rl < 0) return 0;
384
385 return 1;
386}
387
388/*
389 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
390 */
391static asn1cnst_range_t *
392_range_split(asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
393 asn1cnst_range_t *range, *nr;
394 int ll, rr;
395
396 assert(ra);
397 assert(rb);
398 assert(!ra->el_count);
399 assert(!rb->el_count);
400
401 if(!_range_overlap(ra, rb)) {
402 errno = 0;
403 return 0;
404 }
405
406 ll = _edge_compare(&ra->left, &rb->left);
407 rr = _edge_compare(&ra->right, &rb->right);
408
409 /*
410 * L: |---|
411 * R: |-------|
412 */
413 if(ll >= 0 && rr <= 0) {
414 errno = 0;
415 return 0;
416 }
417
418 range = _range_new();
419 assert(range);
420
421 nr = _range_new();
422 assert(nr);
423
424 /*
425 * L: |---...
426 * R: |--..
427 */
Lev Walkin88693e82005-05-17 21:46:18 +0000428 while(ll < 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000429 nr->left = ra->left;
430 nr->right = rb->left;
Lev Walkin88693e82005-05-17 21:46:18 +0000431 if(nr->right.type == ARE_VALUE) {
432 if(nr->right.value - 1 >= nr->right.value) {
433 /* We've hit the limit here. */
434 break;
435 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000436 nr->right.value--;
Lev Walkin88693e82005-05-17 21:46:18 +0000437 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000438 _range_insert(range, nr);
439 nr = _range_new();
440 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000441 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000442 }
443
444 /*
445 * L: ...---|
446 * R: ..--|
447 */
Lev Walkin88693e82005-05-17 21:46:18 +0000448 while(rr > 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000449 nr->left = rb->right;
450 nr->right = ra->right;
Lev Walkin88693e82005-05-17 21:46:18 +0000451 if(nr->left.type == ARE_VALUE) {
452 if(nr->left.value + 1 <= nr->left.value) {
453 /* We've hit the limit here. */
454 break;
455 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000456 nr->left.value++;
Lev Walkin88693e82005-05-17 21:46:18 +0000457 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000458 _range_insert(range, nr);
459 nr = _range_new();
460 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000461 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000462 }
463
464 /*
465 * L: |---|
466 * R: |-----|
467 */
468 nr->left = ra->left;
469 nr->right = ra->right;
470 if(_edge_compare(&ra->left, &rb->left) < 0)
471 nr->left = rb->left;
472 if(_edge_compare(&ra->right, &rb->right) > 0)
473 nr->right = rb->right;
474
475 _range_insert(range, nr);
476
477 return range;
478}
479
480static int
481_range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int strict_edge_check) {
482 int ret;
483 int i, j;
484
Lev Walkinb74ac572004-08-25 02:05:28 +0000485 assert(!range->incompatible);
486
487 /* Propagate errors */
488 range->extensible |= with->extensible;
489 range->not_PER_visible |= with->not_PER_visible;
490 range->empty_constraint |= with->empty_constraint;
491
492 if(range->empty_constraint) {
493 /* No use in intersecting empty constraints */
Lev Walkinb45e0672004-08-18 05:42:05 +0000494 return 0;
495 }
496
497 /*
498 * This is an AND operation.
499 */
500
501 /* If this is the only element, insert it into itself as a child */
502 if(range->el_count == 0) {
503 asn1cnst_range_t *r = _range_new();
504 r->left = range->left;
505 r->right = range->right;
506 _range_insert(range, r);
507 assert(range->el_count == 1);
508 }
509
510 /*
511 * Make sure we're dealing with sane data.
512 * G.4.2.3
513 */
514 if(strict_edge_check) {
515 for(j = -1; j < with->el_count; j++) {
516
517 if(j == -1) {
518 if(with->el_count) continue;
519 if(_check_edges_within(range, with))
520 return -1;
521 } else {
522 if(_check_edges_within(range,
523 with->elements[j]))
524 return -1;
525 }
526 }
527 }
528
529 /*
530 * Split range in pieces.
531 */
532
533 for(i = 0; i < range->el_count; i++) {
534 for(j = -1; j < with->el_count; j++) {
535 const asn1cnst_range_t *wel;
536 asn1cnst_range_t *r;
537
538 if(j == -1) {
539 if(with->el_count) continue;
540 wel = with;
541 } else {
542 wel = with->elements[j];
Lev Walkin88693e82005-05-17 21:46:18 +0000543 assert(!wel->el_count); /* non-compound item! */
Lev Walkinb45e0672004-08-18 05:42:05 +0000544 }
545
546 r = _range_split(range->elements[i], wel);
547 if(r) {
548 int ec;
549 /* Substitute the current element with a split */
550 _range_remove_element(range, i);
551 assert(r->el_count);
552 for(ec = 0; ec < r->el_count; ec++) {
553 ret = _range_insert(range, r->elements[ec]);
554 assert(ret == 0);
555 }
556 r->el_count = 0;
557 _range_free(r);
558 i--;
559 break; /* Try again from this point */
560 }
561 }
562 }
563
564 assert(range->el_count);
565
566 /*
567 * Remove pieces which aren't AND-compatible "with" range.
568 */
569
570 for(i = 0; i < range->el_count; i++) {
571 for(j = -1; j < with->el_count; j++) {
572 const asn1cnst_range_t *wel;
573
574 if(j == -1) {
575 if(with->el_count) continue;
576 wel = with;
577 } else {
578 wel = with->elements[j];
579 }
580
581 if(_range_overlap(range->elements[i], wel))
582 break;
583 }
584 if(j == with->el_count) {
585 _range_remove_element(range, i);
586 i--;
587 }
588 }
589
590 if(range->el_count == 0)
591 range->empty_constraint = 1;
592
593 return 0;
594}
595
596static int
597_range_union(asn1cnst_range_t *range) {
598 int i;
599
600 qsort(range->elements, range->el_count, sizeof(range->elements[0]),
601 _range_compare);
602
603 /*
604 * The range is sorted by the start values.
605 */
606 for(i = 1; i < range->el_count; i++) {
607 asn1cnst_range_t *ra = range->elements[i - 1];
608 asn1cnst_range_t *rb = range->elements[i];
609
610 if(_range_overlap(ra, rb)) {
611 if(_edge_compare(&ra->left, &rb->left) < 0)
612 rb->left = ra->left;
613
614 if(_edge_compare(&ra->right, &rb->right) > 0)
615 rb->right = ra->right;
616 } else {
617 /*
618 * Still, range may be joined: (1..4)(5..10).
619 * This logic is valid only for whole numbers
620 * (i.e., not REAL type, but REAL constraints
Lev Walkinb74ac572004-08-25 02:05:28 +0000621 * are not PER-visible (X.691, #9.3.12).
Lev Walkinb45e0672004-08-18 05:42:05 +0000622 */
623 if(ra->right.type == ARE_VALUE
624 && rb->left.type == ARE_VALUE
625 && (rb->left.value - ra->right.value) == 1) {
626 /* (1..10) */
627 rb->left = ra->left;
628 } else {
629 continue;
630 }
631 }
632
633 /*
634 * Squeeze the array by removing the ra.
635 */
636 _range_remove_element(range, i - 1);
637
638 i--; /* Retry from the current point */
639 }
640
641 return 0;
642}
643
644static int
645_range_canonicalize(asn1cnst_range_t *range) {
646
647 if(range->el_count == 0) {
648 /*
649 * Switch left and right edges, make them sorted.
650 * It might be a mild warning though.
651 */
652 if(_edge_compare(&range->left, &range->right) > 0) {
653 asn1cnst_edge_t tmp = range->left;
654 range->left = range->right;
655 range->right = tmp;
656 }
657
658 if(range->elements) {
659 free(range->elements);
660 range->elements = 0;
661 }
662 range->el_size = 0;
663 return 0;
664 }
665
666 /*
667 * Remove duplicates and overlaps by merging them in.
668 */
669 _range_union(range);
670
671 /* Refine the left edge of a parent */
672 range->left = range->elements[0]->left;
673
674 /* Refine the right edge of a parent */
675 range->right = range->elements[range->el_count - 1]->right;
676
677 /* Remove the child, if it's a single one */
678 if(range->el_count == 1) {
679 _range_remove_element(range, 0);
680 }
681
682 return 0;
683}
684
685asn1cnst_range_t *
Lev Walkin4b553412005-08-14 14:45:44 +0000686asn1constraint_compute_PER_range(asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e type, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000687 asn1cnst_range_t *range;
688 asn1cnst_range_t *tmp;
689 asn1p_value_t *vmin;
690 asn1p_value_t *vmax;
691 int expectation_met;
Lev Walkind541c252004-09-05 10:36:22 +0000692 unsigned int i;
Lev Walkinb45e0672004-08-18 05:42:05 +0000693 int ret;
Lev Walkinb45e0672004-08-18 05:42:05 +0000694
695 if(!exmet) {
696 exmet = &expectation_met;
697 *exmet = 0;
698 }
699
700 /*
Lev Walkinb74ac572004-08-25 02:05:28 +0000701 * Check if the requested constraint is theoretically compatible
702 * with the given expression type.
Lev Walkinb45e0672004-08-18 05:42:05 +0000703 */
Lev Walkin4b553412005-08-14 14:45:44 +0000704 if(asn1constraint_compatible(expr_type, type,
705 cpr_flags & CPR_simulate_fbless_SIZE) != 1) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000706 errno = EINVAL;
707 return 0;
708 }
709
710 /* Check arguments' validity. */
711 switch(type) {
712 case ACT_EL_RANGE:
713 if(exmet == &expectation_met)
714 *exmet = 1;
715 break;
716 case ACT_CT_FROM:
717 if(!minmax) {
718 minmax = asn1constraint_default_alphabet(expr_type);
719 if(minmax) {
720 break;
721 }
722 }
723 /* Fall through */
724 case ACT_CT_SIZE:
725 if(!minmax) {
726 static asn1cnst_range_t mm;
727 mm.left.type = ARE_VALUE;
728 mm.left.value = 0;
729 mm.right.type = ARE_MAX;
730 minmax = &mm;
731 }
732 break;
733 default:
734 errno = EINVAL;
735 return 0;
736 }
737
738 if(minmax) {
739 range = _range_clone(minmax);
740 } else {
741 range = _range_new();
742 }
743
Lev Walkinb74ac572004-08-25 02:05:28 +0000744 /*
745 * X.691, #9.3.6
746 * Constraints on restricter character string types
747 * which are not known-multiplier are not PER-visible.
748 */
749 if((expr_type & ASN_STRING_NKM_MASK))
750 range->not_PER_visible = 1;
751
Lev Walkin4b553412005-08-14 14:45:44 +0000752 if(!ct
753 || (range->not_PER_visible && (cpr_flags & CPR_strict_PER_visibility)))
Lev Walkinb45e0672004-08-18 05:42:05 +0000754 return range;
755
756 switch(ct->type) {
757 case ACT_EL_VALUE:
758 vmin = vmax = ct->value;
759 break;
760 case ACT_EL_RANGE:
761 case ACT_EL_LLRANGE:
762 case ACT_EL_RLRANGE:
763 case ACT_EL_ULRANGE:
764 vmin = ct->range_start;
765 vmax = ct->range_stop;
766 break;
767 case ACT_EL_EXT:
768 if(!*exmet) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000769 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000770 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000771 _range_free(range);
772 errno = ERANGE;
773 range = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000774 }
775 return range;
776 case ACT_CT_SIZE:
777 case ACT_CT_FROM:
778 if(type == ct->type) {
779 *exmet = 1;
780 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000781 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000782 return range;
783 }
784 assert(ct->el_count == 1);
Lev Walkinb74ac572004-08-25 02:05:28 +0000785 tmp = asn1constraint_compute_PER_range(expr_type,
Lev Walkin4b553412005-08-14 14:45:44 +0000786 ct->elements[0], type, minmax, exmet, cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +0000787 if(tmp) {
788 _range_free(range);
789 } else {
790 if(errno == ERANGE) {
791 range->empty_constraint = 1;
792 range->extensible = 1;
793 tmp = range;
794 } else {
795 _range_free(range);
796 }
797 }
798 return tmp;
Lev Walkinb45e0672004-08-18 05:42:05 +0000799 case ACT_CA_SET: /* (10..20)(15..17) */
800 case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */
801
802 /* AND constraints, one after another. */
803 for(i = 0; i < ct->el_count; i++) {
804 tmp = asn1constraint_compute_PER_range(expr_type,
805 ct->elements[i], type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000806 ct->type==ACT_CA_SET?range:minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000807 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000808 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000809 if(errno == ERANGE) {
810 continue;
811 } else {
812 _range_free(range);
813 return NULL;
814 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000815 }
816
Lev Walkinb74ac572004-08-25 02:05:28 +0000817 if(tmp->incompatible) {
818 /*
819 * Ignore constraints
820 * incompatible with arguments:
821 * SIZE(1..2) ^ FROM("ABCD")
822 * either SIZE or FROM will be ignored.
823 */
824 _range_free(tmp);
825 continue;
826 }
827
Lev Walkin4b553412005-08-14 14:45:44 +0000828 if(tmp->not_PER_visible
829 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000830 if(ct->type == ACT_CA_SET) {
831 /*
832 * X.691, #9.3.18:
833 * Ignore this separate component.
834 */
835 } else {
836 /*
837 * X.691, #9.3.19:
838 * Ignore not PER-visible INTERSECTION
839 */
840 }
841 _range_free(tmp);
842 continue;
843 }
844
Lev Walkinb45e0672004-08-18 05:42:05 +0000845 ret = _range_intersection(range, tmp,
846 ct->type == ACT_CA_SET);
847 _range_free(tmp);
848 if(ret) {
849 _range_free(range);
850 errno = EPERM;
851 return NULL;
852 }
853 _range_canonicalize(range);
854 }
855
856 return range;
857 case ACT_CA_CSV: /* SIZE(1..2, 3..4) */
858 case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */
859
Lev Walkinb74ac572004-08-25 02:05:28 +0000860 /*
861 * Grab the first valid constraint.
862 */
863 tmp = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000864 for(i = 0; i < ct->el_count; i++) {
865 tmp = asn1constraint_compute_PER_range(expr_type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000866 ct->elements[i], type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000867 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000868 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000869 if(errno == ERANGE) {
870 range->extensible = 1;
871 continue;
872 } else {
873 _range_free(range);
874 return NULL;
875 }
876 }
877 if(tmp->incompatible) {
878 _range_free(tmp);
879 tmp = 0;
880 }
881 break;
882 }
883 if(tmp) {
884 tmp->extensible |= range->extensible;
885 tmp->empty_constraint |= range->empty_constraint;
886 _range_free(range);
887 range = tmp;
888 } else {
889 range->incompatible = 1;
890 return range;
891 }
892
893 /*
894 * Merge with the rest of them.
895 * Canonicalizator will do the union magic.
896 */
897 for(; i < ct->el_count; i++) {
898 tmp = asn1constraint_compute_PER_range(expr_type,
899 ct->elements[i], type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000900 cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +0000901 if(!tmp) {
902 if(errno == ERANGE) {
903 range->extensible = 1;
904 continue;
905 } else {
906 _range_free(range);
907 return NULL;
908 }
909 }
910
911 if(tmp->incompatible) {
912 _range_free(tmp);
913 _range_canonicalize(range);
914 range->incompatible = 1;
915 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +0000916 }
917
918 if(tmp->empty_constraint) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000919 /*
920 * Ignore empty constraints in OR logic.
921 */
922 range->extensible |= tmp->extensible;
Lev Walkinb45e0672004-08-18 05:42:05 +0000923 _range_free(tmp);
924 continue;
925 }
926
Lev Walkinb45e0672004-08-18 05:42:05 +0000927 _range_merge_in(range, tmp);
928 }
929
930 _range_canonicalize(range);
931
Lev Walkinb74ac572004-08-25 02:05:28 +0000932 if(range->extensible && type == ACT_CT_FROM) {
933 /*
934 * X.691, #9.3.10:
935 * Extensible permitted alphabet constraints
936 * are not PER-visible.
937 */
938 range->not_PER_visible = 1;
939 }
940
Lev Walkin4b553412005-08-14 14:45:44 +0000941 if(range->not_PER_visible
942 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000943 /*
944 * X.691, #9.3.19:
945 * If not PER-visible constraint is part of UNION,
Lev Walkinb74ac572004-08-25 02:05:28 +0000946 * the whole resulting constraint is not PER-visible.
Lev Walkinb45e0672004-08-18 05:42:05 +0000947 */
948 _range_free(range);
949 if(minmax)
950 range = _range_clone(minmax);
951 else
952 range = _range_new();
Lev Walkinb74ac572004-08-25 02:05:28 +0000953 range->not_PER_visible = 1;
954 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000955 }
956
957 return range;
958 case ACT_CA_EXC: /* FROM("ABCD") EXCEPT FROM("AB") */
959 /*
960 * X.691, #9.3.19:
961 * EXCEPT and the following value set is completely ignored.
962 */
963 assert(ct->el_count >= 1);
964 _range_free(range);
965 range = asn1constraint_compute_PER_range(expr_type,
Lev Walkin4b553412005-08-14 14:45:44 +0000966 ct->elements[0], type, minmax, exmet, cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000967 return range;
968 default:
Lev Walkinb74ac572004-08-25 02:05:28 +0000969 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000970 return range;
971 }
972
973
974 if(!*exmet) {
975 /*
976 * Expectation is not met. Return the default range.
977 */
Lev Walkinb74ac572004-08-25 02:05:28 +0000978 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000979 return range;
980 }
981
982 _range_free(range);
983 range = _range_new();
984
985 ret = _range_fill(vmin, minmax, &range->left,
986 range, type, ct->_lineno);
Lev Walkin1ef05162004-08-25 00:42:25 +0000987 if(!ret)
988 ret = _range_fill(vmax, minmax, &range->right,
Lev Walkinb45e0672004-08-18 05:42:05 +0000989 range, type, ct->_lineno);
990 if(ret) {
991 _range_free(range);
992 errno = EPERM;
993 return NULL;
994 }
995
996 if(minmax) {
997 asn1cnst_range_t *clone;
998
999 clone = _range_clone(minmax);
1000
1001 /* Constrain parent type with given data. */
1002 ret = _range_intersection(clone, range, 1);
1003 _range_free(range);
1004 if(ret) {
1005 _range_free(clone);
1006 errno = EPERM;
1007 return NULL;
1008 }
1009 range = clone;
1010 }
1011
1012 /*
1013 * Recompute elements's min/max, remove duplicates, etc.
1014 */
1015 _range_canonicalize(range);
1016
1017 return range;
1018}
1019