blob: 86b629cb125061ae787634c453b724a8b071d1ba [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
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) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000283 FATAL("Integer %" PRIdASN " value invalid "
Lev Walkinb45e0672004-08-18 05:42:05 +0000284 "for %s constraint at line %d",
Lev Walkin33c16ba2004-09-24 21:01:43 +0000285 val->value.v_integer,
Lev Walkinb45e0672004-08-18 05:42:05 +0000286 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;
Lev Walkin1e448d32005-03-24 14:26:38 +0000324 case ATV_TUPLE:
325 case ATV_QUADRUPLE:
326 edge->type = ARE_VALUE;
327 edge->value = val->value.v_integer;
328 return 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000329 case ATV_STRING:
330 if(type != ACT_CT_FROM)
331 return 0;
332 break;
Lev Walkin1ef05162004-08-25 00:42:25 +0000333 case ATV_REFERENCED:
Lev Walkinfd97d5e2004-09-15 11:45:44 +0000334 FATAL("Unresolved constraint element \"%s\" at line %d",
Lev Walkin1ef05162004-08-25 00:42:25 +0000335 asn1f_printable_reference(val->value.reference),
336 lineno);
337 return -1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000338 default:
339 FATAL("Unrecognized constraint element at line %d",
340 lineno);
341 return -1;
342 }
343
344 assert(val->type == ATV_STRING);
345
346 p = val->value.string.buf;
347 pend = p + val->value.string.size;
348 if(p == pend) return 0;
349
350 edge->type = ARE_VALUE;
351 if(val->value.string.size == 1) {
352 edge->value = *p;
353 } else {
354 /*
355 * Else this is a set:
356 * (FROM("abcdef"))
357 * However, (FROM("abc".."def")) is forbidden.
358 * See also 47.4.4.
359 */
Lev Walkinb8108ec2004-09-29 13:17:17 +0000360 asn1c_integer_t vmin, vmax;
Lev Walkinb45e0672004-08-18 05:42:05 +0000361 vmin = vmax = *p;
362 for(; p < pend; p++) {
363 asn1cnst_range_t *nr = _range_new();
364 int ret;
365 assert(nr);
366
367 if(*p < vmin) vmin = *p;
368 if(*p > vmax) vmax = *p;
369
370 ret = _range_insert(range, nr);
371 assert(ret == 0);
372
373 nr->left.type = ARE_VALUE;
374 nr->left.value = *p;
375 nr->left.lineno = lineno;
376 nr->right = nr->left;
377 }
378 edge->value = (edge == &range->right) ? vmin : vmax;
379 }
380
381 return 0;
382}
383
384/*
385 * Check if ranges contain common elements.
386 */
387static int
388_range_overlap(const asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
389 int lr, rl;
390 const asn1cnst_edge_t *ra_l = &ra->left;
391 const asn1cnst_edge_t *ra_r = &ra->right;
392 const asn1cnst_edge_t *rb_l = &rb->left;
393 const asn1cnst_edge_t *rb_r = &rb->right;
394
395 assert(_edge_compare(ra_l, ra_r) <= 0);
396 assert(_edge_compare(rb_l, rb_r) <= 0);
397
398 lr = _edge_compare(ra_l, rb_r);
399 rl = _edge_compare(ra_r, rb_l);
400
401 /*
402 * L: |---|
403 * R: |---|
404 */
405 if(lr > 0) return 0;
406
407 /*
408 * L: |---|
409 * R: |---|
410 */
411 if(rl < 0) return 0;
412
413 return 1;
414}
415
416/*
417 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
418 */
419static asn1cnst_range_t *
420_range_split(asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
421 asn1cnst_range_t *range, *nr;
422 int ll, rr;
423
424 assert(ra);
425 assert(rb);
426 assert(!ra->el_count);
427 assert(!rb->el_count);
428
429 if(!_range_overlap(ra, rb)) {
430 errno = 0;
431 return 0;
432 }
433
434 ll = _edge_compare(&ra->left, &rb->left);
435 rr = _edge_compare(&ra->right, &rb->right);
436
437 /*
438 * L: |---|
439 * R: |-------|
440 */
441 if(ll >= 0 && rr <= 0) {
442 errno = 0;
443 return 0;
444 }
445
446 range = _range_new();
447 assert(range);
448
449 nr = _range_new();
450 assert(nr);
451
452 /*
453 * L: |---...
454 * R: |--..
455 */
Lev Walkin88693e82005-05-17 21:46:18 +0000456 while(ll < 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000457 nr->left = ra->left;
458 nr->right = rb->left;
Lev Walkin88693e82005-05-17 21:46:18 +0000459 if(nr->right.type == ARE_VALUE) {
460 if(nr->right.value - 1 >= nr->right.value) {
461 /* We've hit the limit here. */
462 break;
463 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000464 nr->right.value--;
Lev Walkin88693e82005-05-17 21:46:18 +0000465 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000466 _range_insert(range, nr);
467 nr = _range_new();
468 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000469 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000470 }
471
472 /*
473 * L: ...---|
474 * R: ..--|
475 */
Lev Walkin88693e82005-05-17 21:46:18 +0000476 while(rr > 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000477 nr->left = rb->right;
478 nr->right = ra->right;
Lev Walkin88693e82005-05-17 21:46:18 +0000479 if(nr->left.type == ARE_VALUE) {
480 if(nr->left.value + 1 <= nr->left.value) {
481 /* We've hit the limit here. */
482 break;
483 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000484 nr->left.value++;
Lev Walkin88693e82005-05-17 21:46:18 +0000485 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000486 _range_insert(range, nr);
487 nr = _range_new();
488 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000489 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000490 }
491
492 /*
493 * L: |---|
494 * R: |-----|
495 */
496 nr->left = ra->left;
497 nr->right = ra->right;
498 if(_edge_compare(&ra->left, &rb->left) < 0)
499 nr->left = rb->left;
500 if(_edge_compare(&ra->right, &rb->right) > 0)
501 nr->right = rb->right;
502
503 _range_insert(range, nr);
504
505 return range;
506}
507
508static int
509_range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int strict_edge_check) {
510 int ret;
511 int i, j;
512
Lev Walkinb74ac572004-08-25 02:05:28 +0000513 assert(!range->incompatible);
514
515 /* Propagate errors */
516 range->extensible |= with->extensible;
517 range->not_PER_visible |= with->not_PER_visible;
518 range->empty_constraint |= with->empty_constraint;
519
520 if(range->empty_constraint) {
521 /* No use in intersecting empty constraints */
Lev Walkinb45e0672004-08-18 05:42:05 +0000522 return 0;
523 }
524
525 /*
526 * This is an AND operation.
527 */
528
529 /* If this is the only element, insert it into itself as a child */
530 if(range->el_count == 0) {
531 asn1cnst_range_t *r = _range_new();
532 r->left = range->left;
533 r->right = range->right;
534 _range_insert(range, r);
535 assert(range->el_count == 1);
536 }
537
538 /*
539 * Make sure we're dealing with sane data.
540 * G.4.2.3
541 */
542 if(strict_edge_check) {
543 for(j = -1; j < with->el_count; j++) {
544
545 if(j == -1) {
546 if(with->el_count) continue;
547 if(_check_edges_within(range, with))
548 return -1;
549 } else {
550 if(_check_edges_within(range,
551 with->elements[j]))
552 return -1;
553 }
554 }
555 }
556
557 /*
558 * Split range in pieces.
559 */
560
561 for(i = 0; i < range->el_count; i++) {
562 for(j = -1; j < with->el_count; j++) {
563 const asn1cnst_range_t *wel;
564 asn1cnst_range_t *r;
565
566 if(j == -1) {
567 if(with->el_count) continue;
568 wel = with;
569 } else {
570 wel = with->elements[j];
Lev Walkin88693e82005-05-17 21:46:18 +0000571 assert(!wel->el_count); /* non-compound item! */
Lev Walkinb45e0672004-08-18 05:42:05 +0000572 }
573
574 r = _range_split(range->elements[i], wel);
575 if(r) {
576 int ec;
577 /* Substitute the current element with a split */
578 _range_remove_element(range, i);
579 assert(r->el_count);
580 for(ec = 0; ec < r->el_count; ec++) {
581 ret = _range_insert(range, r->elements[ec]);
582 assert(ret == 0);
583 }
584 r->el_count = 0;
585 _range_free(r);
586 i--;
587 break; /* Try again from this point */
588 }
589 }
590 }
591
592 assert(range->el_count);
593
594 /*
595 * Remove pieces which aren't AND-compatible "with" range.
596 */
597
598 for(i = 0; i < range->el_count; i++) {
599 for(j = -1; j < with->el_count; j++) {
600 const asn1cnst_range_t *wel;
601
602 if(j == -1) {
603 if(with->el_count) continue;
604 wel = with;
605 } else {
606 wel = with->elements[j];
607 }
608
609 if(_range_overlap(range->elements[i], wel))
610 break;
611 }
612 if(j == with->el_count) {
613 _range_remove_element(range, i);
614 i--;
615 }
616 }
617
618 if(range->el_count == 0)
619 range->empty_constraint = 1;
620
621 return 0;
622}
623
624static int
625_range_union(asn1cnst_range_t *range) {
626 int i;
627
628 qsort(range->elements, range->el_count, sizeof(range->elements[0]),
629 _range_compare);
630
631 /*
632 * The range is sorted by the start values.
633 */
634 for(i = 1; i < range->el_count; i++) {
635 asn1cnst_range_t *ra = range->elements[i - 1];
636 asn1cnst_range_t *rb = range->elements[i];
637
638 if(_range_overlap(ra, rb)) {
639 if(_edge_compare(&ra->left, &rb->left) < 0)
640 rb->left = ra->left;
641
642 if(_edge_compare(&ra->right, &rb->right) > 0)
643 rb->right = ra->right;
644 } else {
645 /*
646 * Still, range may be joined: (1..4)(5..10).
647 * This logic is valid only for whole numbers
648 * (i.e., not REAL type, but REAL constraints
Lev Walkinb74ac572004-08-25 02:05:28 +0000649 * are not PER-visible (X.691, #9.3.12).
Lev Walkinb45e0672004-08-18 05:42:05 +0000650 */
651 if(ra->right.type == ARE_VALUE
652 && rb->left.type == ARE_VALUE
653 && (rb->left.value - ra->right.value) == 1) {
654 /* (1..10) */
655 rb->left = ra->left;
656 } else {
657 continue;
658 }
659 }
660
661 /*
662 * Squeeze the array by removing the ra.
663 */
664 _range_remove_element(range, i - 1);
665
666 i--; /* Retry from the current point */
667 }
668
669 return 0;
670}
671
672static int
673_range_canonicalize(asn1cnst_range_t *range) {
674
675 if(range->el_count == 0) {
676 /*
677 * Switch left and right edges, make them sorted.
678 * It might be a mild warning though.
679 */
680 if(_edge_compare(&range->left, &range->right) > 0) {
681 asn1cnst_edge_t tmp = range->left;
682 range->left = range->right;
683 range->right = tmp;
684 }
685
686 if(range->elements) {
687 free(range->elements);
688 range->elements = 0;
689 }
690 range->el_size = 0;
691 return 0;
692 }
693
694 /*
695 * Remove duplicates and overlaps by merging them in.
696 */
697 _range_union(range);
698
699 /* Refine the left edge of a parent */
700 range->left = range->elements[0]->left;
701
702 /* Refine the right edge of a parent */
703 range->right = range->elements[range->el_count - 1]->right;
704
705 /* Remove the child, if it's a single one */
706 if(range->el_count == 1) {
707 _range_remove_element(range, 0);
708 }
709
710 return 0;
711}
712
713asn1cnst_range_t *
Lev Walkin4b553412005-08-14 14:45:44 +0000714asn1constraint_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 +0000715 asn1cnst_range_t *range;
716 asn1cnst_range_t *tmp;
717 asn1p_value_t *vmin;
718 asn1p_value_t *vmax;
719 int expectation_met;
Lev Walkind541c252004-09-05 10:36:22 +0000720 unsigned int i;
Lev Walkinb45e0672004-08-18 05:42:05 +0000721 int ret;
Lev Walkinb45e0672004-08-18 05:42:05 +0000722
723 if(!exmet) {
724 exmet = &expectation_met;
725 *exmet = 0;
726 }
727
728 /*
Lev Walkinb74ac572004-08-25 02:05:28 +0000729 * Check if the requested constraint is theoretically compatible
730 * with the given expression type.
Lev Walkinb45e0672004-08-18 05:42:05 +0000731 */
Lev Walkin4b553412005-08-14 14:45:44 +0000732 if(asn1constraint_compatible(expr_type, type,
733 cpr_flags & CPR_simulate_fbless_SIZE) != 1) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000734 errno = EINVAL;
735 return 0;
736 }
737
738 /* Check arguments' validity. */
739 switch(type) {
740 case ACT_EL_RANGE:
741 if(exmet == &expectation_met)
742 *exmet = 1;
743 break;
744 case ACT_CT_FROM:
745 if(!minmax) {
746 minmax = asn1constraint_default_alphabet(expr_type);
747 if(minmax) {
748 break;
749 }
750 }
751 /* Fall through */
752 case ACT_CT_SIZE:
753 if(!minmax) {
754 static asn1cnst_range_t mm;
755 mm.left.type = ARE_VALUE;
756 mm.left.value = 0;
757 mm.right.type = ARE_MAX;
758 minmax = &mm;
759 }
760 break;
761 default:
762 errno = EINVAL;
763 return 0;
764 }
765
766 if(minmax) {
767 range = _range_clone(minmax);
768 } else {
769 range = _range_new();
770 }
771
Lev Walkinb74ac572004-08-25 02:05:28 +0000772 /*
773 * X.691, #9.3.6
774 * Constraints on restricter character string types
775 * which are not known-multiplier are not PER-visible.
776 */
777 if((expr_type & ASN_STRING_NKM_MASK))
778 range->not_PER_visible = 1;
779
Lev Walkin4b553412005-08-14 14:45:44 +0000780 if(!ct
781 || (range->not_PER_visible && (cpr_flags & CPR_strict_PER_visibility)))
Lev Walkinb45e0672004-08-18 05:42:05 +0000782 return range;
783
784 switch(ct->type) {
785 case ACT_EL_VALUE:
786 vmin = vmax = ct->value;
787 break;
788 case ACT_EL_RANGE:
789 case ACT_EL_LLRANGE:
790 case ACT_EL_RLRANGE:
791 case ACT_EL_ULRANGE:
792 vmin = ct->range_start;
793 vmax = ct->range_stop;
794 break;
795 case ACT_EL_EXT:
796 if(!*exmet) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000797 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000798 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000799 _range_free(range);
800 errno = ERANGE;
801 range = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000802 }
803 return range;
804 case ACT_CT_SIZE:
805 case ACT_CT_FROM:
806 if(type == ct->type) {
807 *exmet = 1;
808 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000809 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000810 return range;
811 }
812 assert(ct->el_count == 1);
Lev Walkinb74ac572004-08-25 02:05:28 +0000813 tmp = asn1constraint_compute_PER_range(expr_type,
Lev Walkin4b553412005-08-14 14:45:44 +0000814 ct->elements[0], type, minmax, exmet, cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +0000815 if(tmp) {
816 _range_free(range);
817 } else {
818 if(errno == ERANGE) {
819 range->empty_constraint = 1;
820 range->extensible = 1;
821 tmp = range;
822 } else {
823 _range_free(range);
824 }
825 }
826 return tmp;
Lev Walkinb45e0672004-08-18 05:42:05 +0000827 case ACT_CA_SET: /* (10..20)(15..17) */
828 case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */
829
830 /* AND constraints, one after another. */
831 for(i = 0; i < ct->el_count; i++) {
832 tmp = asn1constraint_compute_PER_range(expr_type,
833 ct->elements[i], type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000834 ct->type==ACT_CA_SET?range:minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000835 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000836 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000837 if(errno == ERANGE) {
838 continue;
839 } else {
840 _range_free(range);
841 return NULL;
842 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000843 }
844
Lev Walkinb74ac572004-08-25 02:05:28 +0000845 if(tmp->incompatible) {
846 /*
847 * Ignore constraints
848 * incompatible with arguments:
849 * SIZE(1..2) ^ FROM("ABCD")
850 * either SIZE or FROM will be ignored.
851 */
852 _range_free(tmp);
853 continue;
854 }
855
Lev Walkin4b553412005-08-14 14:45:44 +0000856 if(tmp->not_PER_visible
857 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000858 if(ct->type == ACT_CA_SET) {
859 /*
860 * X.691, #9.3.18:
861 * Ignore this separate component.
862 */
863 } else {
864 /*
865 * X.691, #9.3.19:
866 * Ignore not PER-visible INTERSECTION
867 */
868 }
869 _range_free(tmp);
870 continue;
871 }
872
Lev Walkinb45e0672004-08-18 05:42:05 +0000873 ret = _range_intersection(range, tmp,
874 ct->type == ACT_CA_SET);
875 _range_free(tmp);
876 if(ret) {
877 _range_free(range);
878 errno = EPERM;
879 return NULL;
880 }
881 _range_canonicalize(range);
882 }
883
884 return range;
885 case ACT_CA_CSV: /* SIZE(1..2, 3..4) */
886 case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */
887
Lev Walkinb74ac572004-08-25 02:05:28 +0000888 /*
889 * Grab the first valid constraint.
890 */
891 tmp = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000892 for(i = 0; i < ct->el_count; i++) {
893 tmp = asn1constraint_compute_PER_range(expr_type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000894 ct->elements[i], type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000895 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000896 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000897 if(errno == ERANGE) {
898 range->extensible = 1;
899 continue;
900 } else {
901 _range_free(range);
902 return NULL;
903 }
904 }
905 if(tmp->incompatible) {
906 _range_free(tmp);
907 tmp = 0;
908 }
909 break;
910 }
911 if(tmp) {
912 tmp->extensible |= range->extensible;
913 tmp->empty_constraint |= range->empty_constraint;
914 _range_free(range);
915 range = tmp;
916 } else {
917 range->incompatible = 1;
918 return range;
919 }
920
921 /*
922 * Merge with the rest of them.
923 * Canonicalizator will do the union magic.
924 */
925 for(; i < ct->el_count; i++) {
926 tmp = asn1constraint_compute_PER_range(expr_type,
927 ct->elements[i], type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000928 cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +0000929 if(!tmp) {
930 if(errno == ERANGE) {
931 range->extensible = 1;
932 continue;
933 } else {
934 _range_free(range);
935 return NULL;
936 }
937 }
938
939 if(tmp->incompatible) {
940 _range_free(tmp);
941 _range_canonicalize(range);
942 range->incompatible = 1;
943 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +0000944 }
945
946 if(tmp->empty_constraint) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000947 /*
948 * Ignore empty constraints in OR logic.
949 */
950 range->extensible |= tmp->extensible;
Lev Walkinb45e0672004-08-18 05:42:05 +0000951 _range_free(tmp);
952 continue;
953 }
954
Lev Walkinb45e0672004-08-18 05:42:05 +0000955 _range_merge_in(range, tmp);
956 }
957
958 _range_canonicalize(range);
959
Lev Walkinb74ac572004-08-25 02:05:28 +0000960 if(range->extensible && type == ACT_CT_FROM) {
961 /*
962 * X.691, #9.3.10:
963 * Extensible permitted alphabet constraints
964 * are not PER-visible.
965 */
966 range->not_PER_visible = 1;
967 }
968
Lev Walkin4b553412005-08-14 14:45:44 +0000969 if(range->not_PER_visible
970 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000971 /*
972 * X.691, #9.3.19:
973 * If not PER-visible constraint is part of UNION,
Lev Walkinb74ac572004-08-25 02:05:28 +0000974 * the whole resulting constraint is not PER-visible.
Lev Walkinb45e0672004-08-18 05:42:05 +0000975 */
976 _range_free(range);
977 if(minmax)
978 range = _range_clone(minmax);
979 else
980 range = _range_new();
Lev Walkinb74ac572004-08-25 02:05:28 +0000981 range->not_PER_visible = 1;
982 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000983 }
984
985 return range;
986 case ACT_CA_EXC: /* FROM("ABCD") EXCEPT FROM("AB") */
987 /*
988 * X.691, #9.3.19:
989 * EXCEPT and the following value set is completely ignored.
990 */
991 assert(ct->el_count >= 1);
992 _range_free(range);
993 range = asn1constraint_compute_PER_range(expr_type,
Lev Walkin4b553412005-08-14 14:45:44 +0000994 ct->elements[0], type, minmax, exmet, cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000995 return range;
996 default:
Lev Walkinb74ac572004-08-25 02:05:28 +0000997 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000998 return range;
999 }
1000
1001
1002 if(!*exmet) {
1003 /*
1004 * Expectation is not met. Return the default range.
1005 */
Lev Walkinb74ac572004-08-25 02:05:28 +00001006 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001007 return range;
1008 }
1009
1010 _range_free(range);
1011 range = _range_new();
1012
1013 ret = _range_fill(vmin, minmax, &range->left,
1014 range, type, ct->_lineno);
Lev Walkin1ef05162004-08-25 00:42:25 +00001015 if(!ret)
1016 ret = _range_fill(vmax, minmax, &range->right,
Lev Walkinb45e0672004-08-18 05:42:05 +00001017 range, type, ct->_lineno);
1018 if(ret) {
1019 _range_free(range);
1020 errno = EPERM;
1021 return NULL;
1022 }
1023
1024 if(minmax) {
1025 asn1cnst_range_t *clone;
1026
1027 clone = _range_clone(minmax);
1028
1029 /* Constrain parent type with given data. */
1030 ret = _range_intersection(clone, range, 1);
1031 _range_free(range);
1032 if(ret) {
1033 _range_free(clone);
1034 errno = EPERM;
1035 return NULL;
1036 }
1037 range = clone;
1038 }
1039
1040 /*
1041 * Recompute elements's min/max, remove duplicates, etc.
1042 */
1043 _range_canonicalize(range);
1044
1045 return range;
1046}
1047