blob: e35ecad2aebaf5f842a335d4de58887528044210 [file] [log] [blame]
Lev Walkinb45e0672004-08-18 05:42:05 +00001#include <asn1fix_internal.h>
2#include <asn1fix_constraint.h>
3#include <asn1fix_crange.h>
4
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:
160 snprintf(buf, sizeof(buf), "%lld", (long long)edge->value);
161 }
162 return buf;
163}
164
165static void
166_range_print(const asn1cnst_range_t *range) {
167
168 if(_edge_compare(&range->left, &range->right)) {
169 printf("(%s.", _edge_value(&range->left));
Lev Walkinb74ac572004-08-25 02:05:28 +0000170 printf(".%s", _edge_value(&range->right));
Lev Walkinb45e0672004-08-18 05:42:05 +0000171 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000172 printf("(%s", _edge_value(&range->left));
Lev Walkinb45e0672004-08-18 05:42:05 +0000173 }
174
Lev Walkinb74ac572004-08-25 02:05:28 +0000175 if(range->extensible) {
176 printf(",...)");
177 } else {
178 printf(")");
179 }
180
181 if(range->incompatible) printf("/I");
182 if(range->not_PER_visible) printf("/!V");
183
Lev Walkinb45e0672004-08-18 05:42:05 +0000184 if(range->el_count) {
185 int i;
186 printf("-=>");
187 for(i = 0; i < range->el_count; i++)
188 _range_print(range->elements[i]);
189 }
190
191}
192
193static int
194_edge_is_within(const asn1cnst_range_t *range, const asn1cnst_edge_t *edge) {
195 int i;
196
197 for(i = -1; i < range->el_count; i++) {
198 const asn1cnst_range_t *r;
199 if(i == -1) {
200 if(range->el_count) continue;
201 r = range;
202 } else {
203 r = range->elements[i];
204 }
205 if(_edge_compare(&r->left, edge) <= 0
206 && _edge_compare(&r->right, edge) >= 0)
207 return 1;
208 }
209
210 return 0;
211}
212
213static int
214_check_edges_within(const asn1cnst_range_t *range, const asn1cnst_range_t *r) {
215
216 if(!_edge_is_within(range, &r->left)) {
217 FATAL("Constraint value %s at line %d "
218 "is not within "
219 "a parent constraint range",
220 _edge_value(&r->left),
221 r->left.lineno
222 );
223 return -1;
224 }
225
226 if(!_edge_is_within(range, &r->right)) {
227 FATAL("Constraint value %s at line %d "
228 "is not within "
229 "a parent constraint range",
230 _edge_value(&r->right),
231 r->right.lineno
232 );
233 return -1;
234 }
235
236 return 0;
237}
238
239static int _range_merge_in(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
240 asn1cnst_range_t *r;
241 int prev_count = into->el_count;
242 int i;
243
Lev Walkinb74ac572004-08-25 02:05:28 +0000244 into->not_PER_visible |= cr->not_PER_visible;
245 into->extensible |= cr->extensible;
246
Lev Walkinb45e0672004-08-18 05:42:05 +0000247 /*
248 * Add the element OR all its children "into".
249 */
250 for(i = -1; i < cr->el_count; i++) {
251
252 if(i == -1) {
253 if(cr->el_count) continue;
254 r = cr;
255 } else {
256 r = cr->elements[i];
257 }
258
259 if(_range_insert(into, r)) {
260 into->el_count = prev_count; /* Undo */
261 return -1;
262 }
263 }
264
265 if(cr->el_count) {
266 cr->el_count = 0;
267 _range_free(cr);
268 } else {
269 /* This range is linked into "into". */
270 }
271
272 return 0;
273}
274
275static 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) {
276 unsigned char *p, *pend;
277
278 edge->lineno = lineno;
279
280 switch(val->type) {
281 case ATV_INTEGER:
282 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
283 FATAL("Integer %lld value invalid "
284 "for %s constraint at line %d",
285 (long long)val->value.v_integer,
286 asn1p_constraint_type2str(type), lineno);
287 return -1;
288 }
289 edge->type = ARE_VALUE;
290 edge->value = val->value.v_integer;
291 return 0;
292 case ATV_MIN:
293 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
294 FATAL("MIN invalid for %s constraint at line %d",
295 asn1p_constraint_type2str(type), lineno);
296 return -1;
297 }
298 edge->type = ARE_MIN;
299 if(minmax) *edge = minmax->left;
300 edge->lineno = lineno; /* Restore lineno */
301 return 0;
302 case ATV_MAX:
303 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
304 FATAL("MAX invalid for %s constraint at line %d",
305 asn1p_constraint_type2str(type), lineno);
306 return -1;
307 }
308 edge->type = ARE_MAX;
309 if(minmax) *edge = minmax->right;
310 edge->lineno = lineno; /* Restore lineno */
311 return 0;
312 case ATV_FALSE:
313 case ATV_TRUE:
314 if(type != ACT_EL_RANGE) {
315 FATAL("%s is invalid for %s constraint at line %d",
316 val->type==ATV_TRUE?"TRUE":"FALSE",
317 asn1p_constraint_type2str(type),
318 lineno);
319 return -1;
320 }
321 edge->type = ARE_VALUE;
322 edge->value = (val->type==ATV_TRUE);
323 return 0;
324 case ATV_STRING:
325 if(type != ACT_CT_FROM)
326 return 0;
327 break;
Lev Walkin1ef05162004-08-25 00:42:25 +0000328 case ATV_REFERENCED:
Lev Walkinfd97d5e2004-09-15 11:45:44 +0000329 FATAL("Unresolved constraint element \"%s\" at line %d",
Lev Walkin1ef05162004-08-25 00:42:25 +0000330 asn1f_printable_reference(val->value.reference),
331 lineno);
332 return -1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000333 default:
334 FATAL("Unrecognized constraint element at line %d",
335 lineno);
336 return -1;
337 }
338
339 assert(val->type == ATV_STRING);
340
341 p = val->value.string.buf;
342 pend = p + val->value.string.size;
343 if(p == pend) return 0;
344
345 edge->type = ARE_VALUE;
346 if(val->value.string.size == 1) {
347 edge->value = *p;
348 } else {
349 /*
350 * Else this is a set:
351 * (FROM("abcdef"))
352 * However, (FROM("abc".."def")) is forbidden.
353 * See also 47.4.4.
354 */
355 asn1_integer_t vmin, vmax;
356 vmin = vmax = *p;
357 for(; p < pend; p++) {
358 asn1cnst_range_t *nr = _range_new();
359 int ret;
360 assert(nr);
361
362 if(*p < vmin) vmin = *p;
363 if(*p > vmax) vmax = *p;
364
365 ret = _range_insert(range, nr);
366 assert(ret == 0);
367
368 nr->left.type = ARE_VALUE;
369 nr->left.value = *p;
370 nr->left.lineno = lineno;
371 nr->right = nr->left;
372 }
373 edge->value = (edge == &range->right) ? vmin : vmax;
374 }
375
376 return 0;
377}
378
379/*
380 * Check if ranges contain common elements.
381 */
382static int
383_range_overlap(const asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
384 int lr, rl;
385 const asn1cnst_edge_t *ra_l = &ra->left;
386 const asn1cnst_edge_t *ra_r = &ra->right;
387 const asn1cnst_edge_t *rb_l = &rb->left;
388 const asn1cnst_edge_t *rb_r = &rb->right;
389
390 assert(_edge_compare(ra_l, ra_r) <= 0);
391 assert(_edge_compare(rb_l, rb_r) <= 0);
392
393 lr = _edge_compare(ra_l, rb_r);
394 rl = _edge_compare(ra_r, rb_l);
395
396 /*
397 * L: |---|
398 * R: |---|
399 */
400 if(lr > 0) return 0;
401
402 /*
403 * L: |---|
404 * R: |---|
405 */
406 if(rl < 0) return 0;
407
408 return 1;
409}
410
411/*
412 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
413 */
414static asn1cnst_range_t *
415_range_split(asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
416 asn1cnst_range_t *range, *nr;
417 int ll, rr;
418
419 assert(ra);
420 assert(rb);
421 assert(!ra->el_count);
422 assert(!rb->el_count);
423
424 if(!_range_overlap(ra, rb)) {
425 errno = 0;
426 return 0;
427 }
428
429 ll = _edge_compare(&ra->left, &rb->left);
430 rr = _edge_compare(&ra->right, &rb->right);
431
432 /*
433 * L: |---|
434 * R: |-------|
435 */
436 if(ll >= 0 && rr <= 0) {
437 errno = 0;
438 return 0;
439 }
440
441 range = _range_new();
442 assert(range);
443
444 nr = _range_new();
445 assert(nr);
446
447 /*
448 * L: |---...
449 * R: |--..
450 */
451 if(ll < 0) {
452 nr->left = ra->left;
453 nr->right = rb->left;
454 if(nr->right.type == ARE_VALUE)
455 nr->right.value--;
456 _range_insert(range, nr);
457 nr = _range_new();
458 assert(nr);
459 }
460
461 /*
462 * L: ...---|
463 * R: ..--|
464 */
465 if(rr > 0) {
466 nr->left = rb->right;
467 nr->right = ra->right;
468 if(nr->left.type == ARE_VALUE)
469 nr->left.value++;
470 _range_insert(range, nr);
471 nr = _range_new();
472 assert(nr);
473 }
474
475 /*
476 * L: |---|
477 * R: |-----|
478 */
479 nr->left = ra->left;
480 nr->right = ra->right;
481 if(_edge_compare(&ra->left, &rb->left) < 0)
482 nr->left = rb->left;
483 if(_edge_compare(&ra->right, &rb->right) > 0)
484 nr->right = rb->right;
485
486 _range_insert(range, nr);
487
488 return range;
489}
490
491static int
492_range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int strict_edge_check) {
493 int ret;
494 int i, j;
495
Lev Walkinb74ac572004-08-25 02:05:28 +0000496 assert(!range->incompatible);
497
498 /* Propagate errors */
499 range->extensible |= with->extensible;
500 range->not_PER_visible |= with->not_PER_visible;
501 range->empty_constraint |= with->empty_constraint;
502
503 if(range->empty_constraint) {
504 /* No use in intersecting empty constraints */
Lev Walkinb45e0672004-08-18 05:42:05 +0000505 return 0;
506 }
507
508 /*
509 * This is an AND operation.
510 */
511
512 /* If this is the only element, insert it into itself as a child */
513 if(range->el_count == 0) {
514 asn1cnst_range_t *r = _range_new();
515 r->left = range->left;
516 r->right = range->right;
517 _range_insert(range, r);
518 assert(range->el_count == 1);
519 }
520
521 /*
522 * Make sure we're dealing with sane data.
523 * G.4.2.3
524 */
525 if(strict_edge_check) {
526 for(j = -1; j < with->el_count; j++) {
527
528 if(j == -1) {
529 if(with->el_count) continue;
530 if(_check_edges_within(range, with))
531 return -1;
532 } else {
533 if(_check_edges_within(range,
534 with->elements[j]))
535 return -1;
536 }
537 }
538 }
539
540 /*
541 * Split range in pieces.
542 */
543
544 for(i = 0; i < range->el_count; i++) {
545 for(j = -1; j < with->el_count; j++) {
546 const asn1cnst_range_t *wel;
547 asn1cnst_range_t *r;
548
549 if(j == -1) {
550 if(with->el_count) continue;
551 wel = with;
552 } else {
553 wel = with->elements[j];
554 }
555
556 r = _range_split(range->elements[i], wel);
557 if(r) {
558 int ec;
559 /* Substitute the current element with a split */
560 _range_remove_element(range, i);
561 assert(r->el_count);
562 for(ec = 0; ec < r->el_count; ec++) {
563 ret = _range_insert(range, r->elements[ec]);
564 assert(ret == 0);
565 }
566 r->el_count = 0;
567 _range_free(r);
568 i--;
569 break; /* Try again from this point */
570 }
571 }
572 }
573
574 assert(range->el_count);
575
576 /*
577 * Remove pieces which aren't AND-compatible "with" range.
578 */
579
580 for(i = 0; i < range->el_count; i++) {
581 for(j = -1; j < with->el_count; j++) {
582 const asn1cnst_range_t *wel;
583
584 if(j == -1) {
585 if(with->el_count) continue;
586 wel = with;
587 } else {
588 wel = with->elements[j];
589 }
590
591 if(_range_overlap(range->elements[i], wel))
592 break;
593 }
594 if(j == with->el_count) {
595 _range_remove_element(range, i);
596 i--;
597 }
598 }
599
600 if(range->el_count == 0)
601 range->empty_constraint = 1;
602
603 return 0;
604}
605
606static int
607_range_union(asn1cnst_range_t *range) {
608 int i;
609
610 qsort(range->elements, range->el_count, sizeof(range->elements[0]),
611 _range_compare);
612
613 /*
614 * The range is sorted by the start values.
615 */
616 for(i = 1; i < range->el_count; i++) {
617 asn1cnst_range_t *ra = range->elements[i - 1];
618 asn1cnst_range_t *rb = range->elements[i];
619
620 if(_range_overlap(ra, rb)) {
621 if(_edge_compare(&ra->left, &rb->left) < 0)
622 rb->left = ra->left;
623
624 if(_edge_compare(&ra->right, &rb->right) > 0)
625 rb->right = ra->right;
626 } else {
627 /*
628 * Still, range may be joined: (1..4)(5..10).
629 * This logic is valid only for whole numbers
630 * (i.e., not REAL type, but REAL constraints
Lev Walkinb74ac572004-08-25 02:05:28 +0000631 * are not PER-visible (X.691, #9.3.12).
Lev Walkinb45e0672004-08-18 05:42:05 +0000632 */
633 if(ra->right.type == ARE_VALUE
634 && rb->left.type == ARE_VALUE
635 && (rb->left.value - ra->right.value) == 1) {
636 /* (1..10) */
637 rb->left = ra->left;
638 } else {
639 continue;
640 }
641 }
642
643 /*
644 * Squeeze the array by removing the ra.
645 */
646 _range_remove_element(range, i - 1);
647
648 i--; /* Retry from the current point */
649 }
650
651 return 0;
652}
653
654static int
655_range_canonicalize(asn1cnst_range_t *range) {
656
657 if(range->el_count == 0) {
658 /*
659 * Switch left and right edges, make them sorted.
660 * It might be a mild warning though.
661 */
662 if(_edge_compare(&range->left, &range->right) > 0) {
663 asn1cnst_edge_t tmp = range->left;
664 range->left = range->right;
665 range->right = tmp;
666 }
667
668 if(range->elements) {
669 free(range->elements);
670 range->elements = 0;
671 }
672 range->el_size = 0;
673 return 0;
674 }
675
676 /*
677 * Remove duplicates and overlaps by merging them in.
678 */
679 _range_union(range);
680
681 /* Refine the left edge of a parent */
682 range->left = range->elements[0]->left;
683
684 /* Refine the right edge of a parent */
685 range->right = range->elements[range->el_count - 1]->right;
686
687 /* Remove the child, if it's a single one */
688 if(range->el_count == 1) {
689 _range_remove_element(range, 0);
690 }
691
692 return 0;
693}
694
695asn1cnst_range_t *
Lev Walkinb74ac572004-08-25 02:05:28 +0000696asn1constraint_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, int strict_PV) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000697 asn1cnst_range_t *range;
698 asn1cnst_range_t *tmp;
699 asn1p_value_t *vmin;
700 asn1p_value_t *vmax;
701 int expectation_met;
Lev Walkind541c252004-09-05 10:36:22 +0000702 unsigned int i;
Lev Walkinb45e0672004-08-18 05:42:05 +0000703 int ret;
Lev Walkinb45e0672004-08-18 05:42:05 +0000704
705 if(!exmet) {
706 exmet = &expectation_met;
707 *exmet = 0;
708 }
709
710 /*
Lev Walkinb74ac572004-08-25 02:05:28 +0000711 * Check if the requested constraint is theoretically compatible
712 * with the given expression type.
Lev Walkinb45e0672004-08-18 05:42:05 +0000713 */
714 if(asn1constraint_compatible(expr_type, type) != 1) {
715 errno = EINVAL;
716 return 0;
717 }
718
719 /* Check arguments' validity. */
720 switch(type) {
721 case ACT_EL_RANGE:
722 if(exmet == &expectation_met)
723 *exmet = 1;
724 break;
725 case ACT_CT_FROM:
726 if(!minmax) {
727 minmax = asn1constraint_default_alphabet(expr_type);
728 if(minmax) {
729 break;
730 }
731 }
732 /* Fall through */
733 case ACT_CT_SIZE:
734 if(!minmax) {
735 static asn1cnst_range_t mm;
736 mm.left.type = ARE_VALUE;
737 mm.left.value = 0;
738 mm.right.type = ARE_MAX;
739 minmax = &mm;
740 }
741 break;
742 default:
743 errno = EINVAL;
744 return 0;
745 }
746
747 if(minmax) {
748 range = _range_clone(minmax);
749 } else {
750 range = _range_new();
751 }
752
Lev Walkinb74ac572004-08-25 02:05:28 +0000753 /*
754 * X.691, #9.3.6
755 * Constraints on restricter character string types
756 * which are not known-multiplier are not PER-visible.
757 */
758 if((expr_type & ASN_STRING_NKM_MASK))
759 range->not_PER_visible = 1;
760
761 if(!ct || (strict_PV && range->not_PER_visible))
Lev Walkinb45e0672004-08-18 05:42:05 +0000762 return range;
763
764 switch(ct->type) {
765 case ACT_EL_VALUE:
766 vmin = vmax = ct->value;
767 break;
768 case ACT_EL_RANGE:
769 case ACT_EL_LLRANGE:
770 case ACT_EL_RLRANGE:
771 case ACT_EL_ULRANGE:
772 vmin = ct->range_start;
773 vmax = ct->range_stop;
774 break;
775 case ACT_EL_EXT:
776 if(!*exmet) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000777 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000778 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000779 _range_free(range);
780 errno = ERANGE;
781 range = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000782 }
783 return range;
784 case ACT_CT_SIZE:
785 case ACT_CT_FROM:
786 if(type == ct->type) {
787 *exmet = 1;
788 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000789 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000790 return range;
791 }
792 assert(ct->el_count == 1);
Lev Walkinb74ac572004-08-25 02:05:28 +0000793 tmp = asn1constraint_compute_PER_range(expr_type,
794 ct->elements[0], type, minmax, exmet, strict_PV);
795 if(tmp) {
796 _range_free(range);
797 } else {
798 if(errno == ERANGE) {
799 range->empty_constraint = 1;
800 range->extensible = 1;
801 tmp = range;
802 } else {
803 _range_free(range);
804 }
805 }
806 return tmp;
Lev Walkinb45e0672004-08-18 05:42:05 +0000807 case ACT_CA_SET: /* (10..20)(15..17) */
808 case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */
809
810 /* AND constraints, one after another. */
811 for(i = 0; i < ct->el_count; i++) {
812 tmp = asn1constraint_compute_PER_range(expr_type,
813 ct->elements[i], type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000814 ct->type==ACT_CA_SET?range:minmax, exmet,
815 strict_PV);
Lev Walkinb45e0672004-08-18 05:42:05 +0000816 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000817 if(errno == ERANGE) {
818 continue;
819 } else {
820 _range_free(range);
821 return NULL;
822 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000823 }
824
Lev Walkinb74ac572004-08-25 02:05:28 +0000825 if(tmp->incompatible) {
826 /*
827 * Ignore constraints
828 * incompatible with arguments:
829 * SIZE(1..2) ^ FROM("ABCD")
830 * either SIZE or FROM will be ignored.
831 */
832 _range_free(tmp);
833 continue;
834 }
835
836 if(strict_PV && tmp->not_PER_visible) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000837 if(ct->type == ACT_CA_SET) {
838 /*
839 * X.691, #9.3.18:
840 * Ignore this separate component.
841 */
842 } else {
843 /*
844 * X.691, #9.3.19:
845 * Ignore not PER-visible INTERSECTION
846 */
847 }
848 _range_free(tmp);
849 continue;
850 }
851
Lev Walkinb45e0672004-08-18 05:42:05 +0000852 ret = _range_intersection(range, tmp,
853 ct->type == ACT_CA_SET);
854 _range_free(tmp);
855 if(ret) {
856 _range_free(range);
857 errno = EPERM;
858 return NULL;
859 }
860 _range_canonicalize(range);
861 }
862
863 return range;
864 case ACT_CA_CSV: /* SIZE(1..2, 3..4) */
865 case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */
866
Lev Walkinb74ac572004-08-25 02:05:28 +0000867 /*
868 * Grab the first valid constraint.
869 */
870 tmp = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000871 for(i = 0; i < ct->el_count; i++) {
872 tmp = asn1constraint_compute_PER_range(expr_type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000873 ct->elements[i], type, minmax, exmet,
874 strict_PV);
Lev Walkinb45e0672004-08-18 05:42:05 +0000875 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000876 if(errno == ERANGE) {
877 range->extensible = 1;
878 continue;
879 } else {
880 _range_free(range);
881 return NULL;
882 }
883 }
884 if(tmp->incompatible) {
885 _range_free(tmp);
886 tmp = 0;
887 }
888 break;
889 }
890 if(tmp) {
891 tmp->extensible |= range->extensible;
892 tmp->empty_constraint |= range->empty_constraint;
893 _range_free(range);
894 range = tmp;
895 } else {
896 range->incompatible = 1;
897 return range;
898 }
899
900 /*
901 * Merge with the rest of them.
902 * Canonicalizator will do the union magic.
903 */
904 for(; i < ct->el_count; i++) {
905 tmp = asn1constraint_compute_PER_range(expr_type,
906 ct->elements[i], type, minmax, exmet,
907 strict_PV);
908 if(!tmp) {
909 if(errno == ERANGE) {
910 range->extensible = 1;
911 continue;
912 } else {
913 _range_free(range);
914 return NULL;
915 }
916 }
917
918 if(tmp->incompatible) {
919 _range_free(tmp);
920 _range_canonicalize(range);
921 range->incompatible = 1;
922 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +0000923 }
924
925 if(tmp->empty_constraint) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000926 /*
927 * Ignore empty constraints in OR logic.
928 */
929 range->extensible |= tmp->extensible;
Lev Walkinb45e0672004-08-18 05:42:05 +0000930 _range_free(tmp);
931 continue;
932 }
933
Lev Walkinb45e0672004-08-18 05:42:05 +0000934 _range_merge_in(range, tmp);
935 }
936
937 _range_canonicalize(range);
938
Lev Walkinb74ac572004-08-25 02:05:28 +0000939 if(range->extensible && type == ACT_CT_FROM) {
940 /*
941 * X.691, #9.3.10:
942 * Extensible permitted alphabet constraints
943 * are not PER-visible.
944 */
945 range->not_PER_visible = 1;
946 }
947
948 if(strict_PV && range->not_PER_visible) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000949 /*
950 * X.691, #9.3.19:
951 * If not PER-visible constraint is part of UNION,
Lev Walkinb74ac572004-08-25 02:05:28 +0000952 * the whole resulting constraint is not PER-visible.
Lev Walkinb45e0672004-08-18 05:42:05 +0000953 */
954 _range_free(range);
955 if(minmax)
956 range = _range_clone(minmax);
957 else
958 range = _range_new();
Lev Walkinb74ac572004-08-25 02:05:28 +0000959 range->not_PER_visible = 1;
960 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000961 }
962
963 return range;
964 case ACT_CA_EXC: /* FROM("ABCD") EXCEPT FROM("AB") */
965 /*
966 * X.691, #9.3.19:
967 * EXCEPT and the following value set is completely ignored.
968 */
969 assert(ct->el_count >= 1);
970 _range_free(range);
971 range = asn1constraint_compute_PER_range(expr_type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000972 ct->elements[0], type, minmax, exmet, strict_PV);
Lev Walkinb45e0672004-08-18 05:42:05 +0000973 return range;
974 default:
Lev Walkinb74ac572004-08-25 02:05:28 +0000975 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000976 return range;
977 }
978
979
980 if(!*exmet) {
981 /*
982 * Expectation is not met. Return the default range.
983 */
Lev Walkinb74ac572004-08-25 02:05:28 +0000984 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000985 return range;
986 }
987
988 _range_free(range);
989 range = _range_new();
990
991 ret = _range_fill(vmin, minmax, &range->left,
992 range, type, ct->_lineno);
Lev Walkin1ef05162004-08-25 00:42:25 +0000993 if(!ret)
994 ret = _range_fill(vmax, minmax, &range->right,
Lev Walkinb45e0672004-08-18 05:42:05 +0000995 range, type, ct->_lineno);
996 if(ret) {
997 _range_free(range);
998 errno = EPERM;
999 return NULL;
1000 }
1001
1002 if(minmax) {
1003 asn1cnst_range_t *clone;
1004
1005 clone = _range_clone(minmax);
1006
1007 /* Constrain parent type with given data. */
1008 ret = _range_intersection(clone, range, 1);
1009 _range_free(range);
1010 if(ret) {
1011 _range_free(clone);
1012 errno = EPERM;
1013 return NULL;
1014 }
1015 range = clone;
1016 }
1017
1018 /*
1019 * Recompute elements's min/max, remove duplicates, etc.
1020 */
1021 _range_canonicalize(range);
1022
1023 return range;
1024}
1025