blob: b38befe944d77974af2a295ecb9f8c68d423d7fc [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 Walkin3b2278a2016-01-24 16:43:50 -0800161 break;
162 default:
163 assert(!"edge->type");
Lev Walkinb45e0672004-08-18 05:42:05 +0000164 }
165 return buf;
166}
167
Lev Walkinb45e0672004-08-18 05:42:05 +0000168static int
169_edge_is_within(const asn1cnst_range_t *range, const asn1cnst_edge_t *edge) {
170 int i;
171
172 for(i = -1; i < range->el_count; i++) {
173 const asn1cnst_range_t *r;
174 if(i == -1) {
175 if(range->el_count) continue;
176 r = range;
177 } else {
178 r = range->elements[i];
179 }
180 if(_edge_compare(&r->left, edge) <= 0
181 && _edge_compare(&r->right, edge) >= 0)
182 return 1;
183 }
184
185 return 0;
186}
187
188static int
189_check_edges_within(const asn1cnst_range_t *range, const asn1cnst_range_t *r) {
190
191 if(!_edge_is_within(range, &r->left)) {
192 FATAL("Constraint value %s at line %d "
193 "is not within "
194 "a parent constraint range",
195 _edge_value(&r->left),
196 r->left.lineno
197 );
198 return -1;
199 }
200
201 if(!_edge_is_within(range, &r->right)) {
202 FATAL("Constraint value %s at line %d "
203 "is not within "
204 "a parent constraint range",
205 _edge_value(&r->right),
206 r->right.lineno
207 );
208 return -1;
209 }
210
211 return 0;
212}
213
214static int _range_merge_in(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
215 asn1cnst_range_t *r;
216 int prev_count = into->el_count;
217 int i;
218
Lev Walkinb74ac572004-08-25 02:05:28 +0000219 into->not_PER_visible |= cr->not_PER_visible;
220 into->extensible |= cr->extensible;
221
Lev Walkinb45e0672004-08-18 05:42:05 +0000222 /*
223 * Add the element OR all its children "into".
224 */
225 for(i = -1; i < cr->el_count; i++) {
226
227 if(i == -1) {
228 if(cr->el_count) continue;
229 r = cr;
230 } else {
231 r = cr->elements[i];
232 }
233
234 if(_range_insert(into, r)) {
235 into->el_count = prev_count; /* Undo */
236 return -1;
237 }
238 }
239
240 if(cr->el_count) {
241 cr->el_count = 0;
242 _range_free(cr);
243 } else {
244 /* This range is linked into "into". */
245 }
246
247 return 0;
248}
249
250static 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) {
251 unsigned char *p, *pend;
252
253 edge->lineno = lineno;
254
255 switch(val->type) {
256 case ATV_INTEGER:
257 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000258 FATAL("Integer %" PRIdASN " value invalid "
Lev Walkinb45e0672004-08-18 05:42:05 +0000259 "for %s constraint at line %d",
Lev Walkin33c16ba2004-09-24 21:01:43 +0000260 val->value.v_integer,
Lev Walkinb45e0672004-08-18 05:42:05 +0000261 asn1p_constraint_type2str(type), lineno);
262 return -1;
263 }
264 edge->type = ARE_VALUE;
265 edge->value = val->value.v_integer;
266 return 0;
267 case ATV_MIN:
268 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
269 FATAL("MIN invalid for %s constraint at line %d",
270 asn1p_constraint_type2str(type), lineno);
271 return -1;
272 }
273 edge->type = ARE_MIN;
274 if(minmax) *edge = minmax->left;
275 edge->lineno = lineno; /* Restore lineno */
276 return 0;
277 case ATV_MAX:
278 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
279 FATAL("MAX invalid for %s constraint at line %d",
280 asn1p_constraint_type2str(type), lineno);
281 return -1;
282 }
283 edge->type = ARE_MAX;
284 if(minmax) *edge = minmax->right;
285 edge->lineno = lineno; /* Restore lineno */
286 return 0;
287 case ATV_FALSE:
288 case ATV_TRUE:
289 if(type != ACT_EL_RANGE) {
290 FATAL("%s is invalid for %s constraint at line %d",
291 val->type==ATV_TRUE?"TRUE":"FALSE",
292 asn1p_constraint_type2str(type),
293 lineno);
294 return -1;
295 }
296 edge->type = ARE_VALUE;
297 edge->value = (val->type==ATV_TRUE);
298 return 0;
Lev Walkin1e448d32005-03-24 14:26:38 +0000299 case ATV_TUPLE:
300 case ATV_QUADRUPLE:
301 edge->type = ARE_VALUE;
302 edge->value = val->value.v_integer;
303 return 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000304 case ATV_STRING:
305 if(type != ACT_CT_FROM)
306 return 0;
307 break;
Lev Walkin1ef05162004-08-25 00:42:25 +0000308 case ATV_REFERENCED:
Lev Walkinfd97d5e2004-09-15 11:45:44 +0000309 FATAL("Unresolved constraint element \"%s\" at line %d",
Lev Walkin1ef05162004-08-25 00:42:25 +0000310 asn1f_printable_reference(val->value.reference),
311 lineno);
312 return -1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000313 default:
314 FATAL("Unrecognized constraint element at line %d",
315 lineno);
316 return -1;
317 }
318
319 assert(val->type == ATV_STRING);
320
321 p = val->value.string.buf;
322 pend = p + val->value.string.size;
323 if(p == pend) return 0;
324
325 edge->type = ARE_VALUE;
326 if(val->value.string.size == 1) {
327 edge->value = *p;
328 } else {
329 /*
330 * Else this is a set:
331 * (FROM("abcdef"))
332 * However, (FROM("abc".."def")) is forbidden.
333 * See also 47.4.4.
334 */
Lev Walkinb8108ec2004-09-29 13:17:17 +0000335 asn1c_integer_t vmin, vmax;
Lev Walkinb45e0672004-08-18 05:42:05 +0000336 vmin = vmax = *p;
337 for(; p < pend; p++) {
338 asn1cnst_range_t *nr = _range_new();
339 int ret;
340 assert(nr);
341
342 if(*p < vmin) vmin = *p;
343 if(*p > vmax) vmax = *p;
344
345 ret = _range_insert(range, nr);
346 assert(ret == 0);
347
348 nr->left.type = ARE_VALUE;
349 nr->left.value = *p;
350 nr->left.lineno = lineno;
351 nr->right = nr->left;
352 }
353 edge->value = (edge == &range->right) ? vmin : vmax;
354 }
355
356 return 0;
357}
358
359/*
360 * Check if ranges contain common elements.
361 */
362static int
363_range_overlap(const asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
364 int lr, rl;
365 const asn1cnst_edge_t *ra_l = &ra->left;
366 const asn1cnst_edge_t *ra_r = &ra->right;
367 const asn1cnst_edge_t *rb_l = &rb->left;
368 const asn1cnst_edge_t *rb_r = &rb->right;
369
370 assert(_edge_compare(ra_l, ra_r) <= 0);
371 assert(_edge_compare(rb_l, rb_r) <= 0);
372
373 lr = _edge_compare(ra_l, rb_r);
374 rl = _edge_compare(ra_r, rb_l);
375
376 /*
377 * L: |---|
378 * R: |---|
379 */
380 if(lr > 0) return 0;
381
382 /*
383 * L: |---|
384 * R: |---|
385 */
386 if(rl < 0) return 0;
387
388 return 1;
389}
390
Lev Walkin3b2278a2016-01-24 16:43:50 -0800391
392static int _range_partial_compare(const void *pa, const void *pb) {
393 const asn1cnst_range_t *ra = *(const void * const *)pa;
394 const asn1cnst_range_t *rb = *(const void * const *)pb;
395
396 return _edge_compare(&ra->left, &rb->left);
397}
398
399static void _range_partial_sort_elements(asn1cnst_range_t *r) {
400 qsort(r->elements, r->el_count, sizeof(r->elements[0]),
401 _range_partial_compare);
402}
403
Lev Walkinb45e0672004-08-18 05:42:05 +0000404/*
405 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
406 */
407static asn1cnst_range_t *
408_range_split(asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
409 asn1cnst_range_t *range, *nr;
410 int ll, rr;
411
412 assert(ra);
413 assert(rb);
414 assert(!ra->el_count);
415 assert(!rb->el_count);
416
417 if(!_range_overlap(ra, rb)) {
418 errno = 0;
419 return 0;
420 }
421
422 ll = _edge_compare(&ra->left, &rb->left);
423 rr = _edge_compare(&ra->right, &rb->right);
424
425 /*
426 * L: |---|
427 * R: |-------|
428 */
429 if(ll >= 0 && rr <= 0) {
430 errno = 0;
431 return 0;
432 }
433
434 range = _range_new();
435 assert(range);
436
437 nr = _range_new();
438 assert(nr);
439
440 /*
441 * L: |---...
442 * R: |--..
443 */
Lev Walkin88693e82005-05-17 21:46:18 +0000444 while(ll < 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000445 nr->left = ra->left;
446 nr->right = rb->left;
Lev Walkin88693e82005-05-17 21:46:18 +0000447 if(nr->right.type == ARE_VALUE) {
Lev Walkin3b2278a2016-01-24 16:43:50 -0800448 if(nr->right.value == INTMAX_MIN) {
Lev Walkin88693e82005-05-17 21:46:18 +0000449 /* We've hit the limit here. */
450 break;
451 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000452 nr->right.value--;
Lev Walkin88693e82005-05-17 21:46:18 +0000453 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000454 _range_insert(range, nr);
455 nr = _range_new();
456 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000457 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000458 }
459
460 /*
461 * L: ...---|
462 * R: ..--|
463 */
Lev Walkin88693e82005-05-17 21:46:18 +0000464 while(rr > 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000465 nr->left = rb->right;
466 nr->right = ra->right;
Lev Walkin88693e82005-05-17 21:46:18 +0000467 if(nr->left.type == ARE_VALUE) {
Lev Walkin3b2278a2016-01-24 16:43:50 -0800468 if(nr->left.value == INTMAX_MAX) {
Lev Walkin88693e82005-05-17 21:46:18 +0000469 /* We've hit the limit here. */
470 break;
471 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000472 nr->left.value++;
Lev Walkin88693e82005-05-17 21:46:18 +0000473 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000474 _range_insert(range, nr);
475 nr = _range_new();
476 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000477 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000478 }
479
480 /*
481 * L: |---|
482 * R: |-----|
483 */
484 nr->left = ra->left;
485 nr->right = ra->right;
486 if(_edge_compare(&ra->left, &rb->left) < 0)
487 nr->left = rb->left;
488 if(_edge_compare(&ra->right, &rb->right) > 0)
489 nr->right = rb->right;
490
491 _range_insert(range, nr);
492
Lev Walkin3b2278a2016-01-24 16:43:50 -0800493 _range_partial_sort_elements(range);
494
Lev Walkinb45e0672004-08-18 05:42:05 +0000495 return range;
496}
497
498static int
499_range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int strict_edge_check) {
500 int ret;
501 int i, j;
502
Lev Walkinb74ac572004-08-25 02:05:28 +0000503 assert(!range->incompatible);
504
505 /* Propagate errors */
506 range->extensible |= with->extensible;
507 range->not_PER_visible |= with->not_PER_visible;
508 range->empty_constraint |= with->empty_constraint;
509
510 if(range->empty_constraint) {
511 /* No use in intersecting empty constraints */
Lev Walkinb45e0672004-08-18 05:42:05 +0000512 return 0;
513 }
514
515 /*
516 * This is an AND operation.
517 */
518
519 /* If this is the only element, insert it into itself as a child */
520 if(range->el_count == 0) {
521 asn1cnst_range_t *r = _range_new();
522 r->left = range->left;
523 r->right = range->right;
524 _range_insert(range, r);
525 assert(range->el_count == 1);
526 }
527
528 /*
529 * Make sure we're dealing with sane data.
530 * G.4.2.3
531 */
532 if(strict_edge_check) {
533 for(j = -1; j < with->el_count; j++) {
534
535 if(j == -1) {
536 if(with->el_count) continue;
537 if(_check_edges_within(range, with))
538 return -1;
539 } else {
540 if(_check_edges_within(range,
541 with->elements[j]))
542 return -1;
543 }
544 }
545 }
546
547 /*
548 * Split range in pieces.
549 */
550
551 for(i = 0; i < range->el_count; i++) {
552 for(j = -1; j < with->el_count; j++) {
553 const asn1cnst_range_t *wel;
554 asn1cnst_range_t *r;
555
556 if(j == -1) {
557 if(with->el_count) continue;
558 wel = with;
559 } else {
560 wel = with->elements[j];
Lev Walkin88693e82005-05-17 21:46:18 +0000561 assert(!wel->el_count); /* non-compound item! */
Lev Walkinb45e0672004-08-18 05:42:05 +0000562 }
563
564 r = _range_split(range->elements[i], wel);
565 if(r) {
566 int ec;
567 /* Substitute the current element with a split */
568 _range_remove_element(range, i);
569 assert(r->el_count);
570 for(ec = 0; ec < r->el_count; ec++) {
571 ret = _range_insert(range, r->elements[ec]);
572 assert(ret == 0);
573 }
574 r->el_count = 0;
575 _range_free(r);
576 i--;
577 break; /* Try again from this point */
578 }
579 }
580 }
581
582 assert(range->el_count);
583
584 /*
585 * Remove pieces which aren't AND-compatible "with" range.
586 */
587
588 for(i = 0; i < range->el_count; i++) {
589 for(j = -1; j < with->el_count; j++) {
590 const asn1cnst_range_t *wel;
591
592 if(j == -1) {
593 if(with->el_count) continue;
594 wel = with;
595 } else {
596 wel = with->elements[j];
597 }
598
599 if(_range_overlap(range->elements[i], wel))
600 break;
601 }
602 if(j == with->el_count) {
603 _range_remove_element(range, i);
604 i--;
605 }
606 }
607
608 if(range->el_count == 0)
609 range->empty_constraint = 1;
610
611 return 0;
612}
613
614static int
615_range_union(asn1cnst_range_t *range) {
616 int i;
617
618 qsort(range->elements, range->el_count, sizeof(range->elements[0]),
619 _range_compare);
620
621 /*
622 * The range is sorted by the start values.
623 */
624 for(i = 1; i < range->el_count; i++) {
625 asn1cnst_range_t *ra = range->elements[i - 1];
626 asn1cnst_range_t *rb = range->elements[i];
627
628 if(_range_overlap(ra, rb)) {
629 if(_edge_compare(&ra->left, &rb->left) < 0)
630 rb->left = ra->left;
631
632 if(_edge_compare(&ra->right, &rb->right) > 0)
633 rb->right = ra->right;
634 } else {
635 /*
636 * Still, range may be joined: (1..4)(5..10).
637 * This logic is valid only for whole numbers
638 * (i.e., not REAL type, but REAL constraints
Lev Walkinb74ac572004-08-25 02:05:28 +0000639 * are not PER-visible (X.691, #9.3.12).
Lev Walkinb45e0672004-08-18 05:42:05 +0000640 */
641 if(ra->right.type == ARE_VALUE
642 && rb->left.type == ARE_VALUE
643 && (rb->left.value - ra->right.value) == 1) {
644 /* (1..10) */
645 rb->left = ra->left;
646 } else {
647 continue;
648 }
649 }
650
651 /*
652 * Squeeze the array by removing the ra.
653 */
654 _range_remove_element(range, i - 1);
655
656 i--; /* Retry from the current point */
657 }
658
659 return 0;
660}
661
662static int
663_range_canonicalize(asn1cnst_range_t *range) {
664
665 if(range->el_count == 0) {
666 /*
667 * Switch left and right edges, make them sorted.
668 * It might be a mild warning though.
669 */
670 if(_edge_compare(&range->left, &range->right) > 0) {
671 asn1cnst_edge_t tmp = range->left;
672 range->left = range->right;
673 range->right = tmp;
674 }
675
Markus Elfringf3d18612016-03-15 08:35:24 +0100676 free(range->elements);
677 range->elements = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000678 range->el_size = 0;
679 return 0;
680 }
681
682 /*
683 * Remove duplicates and overlaps by merging them in.
684 */
685 _range_union(range);
686
687 /* Refine the left edge of a parent */
688 range->left = range->elements[0]->left;
689
690 /* Refine the right edge of a parent */
691 range->right = range->elements[range->el_count - 1]->right;
692
693 /* Remove the child, if it's a single one */
694 if(range->el_count == 1) {
695 _range_remove_element(range, 0);
696 }
697
698 return 0;
699}
700
701asn1cnst_range_t *
Lev Walkina28cbb92017-07-31 20:20:17 -0700702asn1constraint_compute_OER_range(const char *dbg_name, asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e requested_ct_type
703, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
704 return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags | CPR_strict_OER_visibility);
Lev Walkin98eabc12017-07-19 08:51:11 +0400705}
706
707asn1cnst_range_t *
Lev Walkina28cbb92017-07-31 20:20:17 -0700708asn1constraint_compute_PER_range(const char *dbg_name, asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e requested_ct_type
709, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
710 if(0) return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags | CPR_strict_PER_visibility);
711 /* Due to pecularities of PER constraint handling, we don't enable strict PER visibility upfront here. */
712 return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags);
Lev Walkin98eabc12017-07-19 08:51:11 +0400713}
714
715asn1cnst_range_t *
Lev Walkina28cbb92017-07-31 20:20:17 -0700716asn1constraint_compute_constraint_range(const char *dbg_name, 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 +0000717 asn1cnst_range_t *range;
718 asn1cnst_range_t *tmp;
719 asn1p_value_t *vmin;
720 asn1p_value_t *vmax;
721 int expectation_met;
Lev Walkind541c252004-09-05 10:36:22 +0000722 unsigned int i;
Lev Walkinb45e0672004-08-18 05:42:05 +0000723 int ret;
Lev Walkinb45e0672004-08-18 05:42:05 +0000724
725 if(!exmet) {
726 exmet = &expectation_met;
727 *exmet = 0;
728 }
729
730 /*
Lev Walkinb74ac572004-08-25 02:05:28 +0000731 * Check if the requested constraint is theoretically compatible
732 * with the given expression type.
Lev Walkinb45e0672004-08-18 05:42:05 +0000733 */
Lev Walkin4b553412005-08-14 14:45:44 +0000734 if(asn1constraint_compatible(expr_type, type,
735 cpr_flags & CPR_simulate_fbless_SIZE) != 1) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000736 errno = EINVAL;
737 return 0;
738 }
739
740 /* Check arguments' validity. */
741 switch(type) {
742 case ACT_EL_RANGE:
743 if(exmet == &expectation_met)
744 *exmet = 1;
745 break;
746 case ACT_CT_FROM:
Lev Walkin98eabc12017-07-19 08:51:11 +0400747 if(cpr_flags & CPR_strict_OER_visibility) {
748 errno = EINVAL;
749 return 0;
750 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000751 if(!minmax) {
752 minmax = asn1constraint_default_alphabet(expr_type);
753 if(minmax) {
754 break;
755 }
756 }
757 /* Fall through */
758 case ACT_CT_SIZE:
759 if(!minmax) {
760 static asn1cnst_range_t mm;
761 mm.left.type = ARE_VALUE;
762 mm.left.value = 0;
763 mm.right.type = ARE_MAX;
764 minmax = &mm;
765 }
766 break;
767 default:
768 errno = EINVAL;
769 return 0;
770 }
771
772 if(minmax) {
773 range = _range_clone(minmax);
774 } else {
775 range = _range_new();
776 }
777
Lev Walkinb74ac572004-08-25 02:05:28 +0000778 /*
779 * X.691, #9.3.6
Lev Walkin98eabc12017-07-19 08:51:11 +0400780 * Constraints on restricted character string types
Lev Walkinb74ac572004-08-25 02:05:28 +0000781 * which are not known-multiplier are not PER-visible.
782 */
783 if((expr_type & ASN_STRING_NKM_MASK))
784 range->not_PER_visible = 1;
785
Lev Walkin98eabc12017-07-19 08:51:11 +0400786 if(!ct
787 || (range->not_PER_visible && (cpr_flags & CPR_strict_PER_visibility)))
788 return range;
789
790 /*
791 * X.696 (08/2015), #8.2.2
792 * SIZE constraints on restricted character string types
793 * which are not known-multiplier are not OER-visible.
794 */
795 if(type == ACT_CT_SIZE && (expr_type & ASN_STRING_NKM_MASK))
796 range->not_OER_visible = 1;
797
798 if(!ct
799 || (range->not_OER_visible && (cpr_flags & CPR_strict_OER_visibility)))
800 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +0000801
802 switch(ct->type) {
803 case ACT_EL_VALUE:
804 vmin = vmax = ct->value;
805 break;
806 case ACT_EL_RANGE:
807 case ACT_EL_LLRANGE:
808 case ACT_EL_RLRANGE:
809 case ACT_EL_ULRANGE:
810 vmin = ct->range_start;
811 vmax = ct->range_stop;
812 break;
813 case ACT_EL_EXT:
814 if(!*exmet) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000815 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000816 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000817 _range_free(range);
818 errno = ERANGE;
819 range = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000820 }
821 return range;
822 case ACT_CT_SIZE:
823 case ACT_CT_FROM:
824 if(type == ct->type) {
825 *exmet = 1;
826 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000827 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000828 return range;
829 }
830 assert(ct->el_count == 1);
Lev Walkina28cbb92017-07-31 20:20:17 -0700831 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkin4b553412005-08-14 14:45:44 +0000832 ct->elements[0], type, minmax, exmet, cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +0000833 if(tmp) {
834 _range_free(range);
835 } else {
836 if(errno == ERANGE) {
837 range->empty_constraint = 1;
838 range->extensible = 1;
839 tmp = range;
840 } else {
841 _range_free(range);
842 }
843 }
844 return tmp;
Lev Walkinb45e0672004-08-18 05:42:05 +0000845 case ACT_CA_SET: /* (10..20)(15..17) */
846 case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */
847
848 /* AND constraints, one after another. */
849 for(i = 0; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700850 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkinb45e0672004-08-18 05:42:05 +0000851 ct->elements[i], type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000852 ct->type==ACT_CA_SET?range:minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000853 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000854 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000855 if(errno == ERANGE) {
856 continue;
857 } else {
858 _range_free(range);
859 return NULL;
860 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000861 }
862
Lev Walkinb74ac572004-08-25 02:05:28 +0000863 if(tmp->incompatible) {
864 /*
865 * Ignore constraints
866 * incompatible with arguments:
867 * SIZE(1..2) ^ FROM("ABCD")
868 * either SIZE or FROM will be ignored.
869 */
870 _range_free(tmp);
871 continue;
872 }
873
Lev Walkin98eabc12017-07-19 08:51:11 +0400874 if(tmp->not_OER_visible
875 && (cpr_flags & CPR_strict_OER_visibility)) {
876 /*
877 * Ignore not OER-visible
878 */
879 _range_free(tmp);
880 continue;
881 }
882
Lev Walkin4b553412005-08-14 14:45:44 +0000883 if(tmp->not_PER_visible
884 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000885 if(ct->type == ACT_CA_SET) {
886 /*
887 * X.691, #9.3.18:
888 * Ignore this separate component.
889 */
890 } else {
891 /*
892 * X.691, #9.3.19:
893 * Ignore not PER-visible INTERSECTION
894 */
895 }
896 _range_free(tmp);
897 continue;
898 }
899
Lev Walkinb45e0672004-08-18 05:42:05 +0000900 ret = _range_intersection(range, tmp,
901 ct->type == ACT_CA_SET);
902 _range_free(tmp);
903 if(ret) {
904 _range_free(range);
905 errno = EPERM;
906 return NULL;
907 }
908 _range_canonicalize(range);
909 }
910
911 return range;
912 case ACT_CA_CSV: /* SIZE(1..2, 3..4) */
913 case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */
914
Lev Walkinb74ac572004-08-25 02:05:28 +0000915 /*
916 * Grab the first valid constraint.
917 */
918 tmp = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000919 for(i = 0; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700920 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000921 ct->elements[i], type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000922 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000923 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000924 if(errno == ERANGE) {
925 range->extensible = 1;
926 continue;
927 } else {
928 _range_free(range);
929 return NULL;
930 }
931 }
932 if(tmp->incompatible) {
933 _range_free(tmp);
934 tmp = 0;
935 }
936 break;
937 }
938 if(tmp) {
939 tmp->extensible |= range->extensible;
940 tmp->empty_constraint |= range->empty_constraint;
941 _range_free(range);
942 range = tmp;
943 } else {
944 range->incompatible = 1;
945 return range;
946 }
947
948 /*
949 * Merge with the rest of them.
950 * Canonicalizator will do the union magic.
951 */
952 for(; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700953 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000954 ct->elements[i], type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000955 cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +0000956 if(!tmp) {
957 if(errno == ERANGE) {
958 range->extensible = 1;
959 continue;
960 } else {
961 _range_free(range);
962 return NULL;
963 }
964 }
965
966 if(tmp->incompatible) {
967 _range_free(tmp);
968 _range_canonicalize(range);
969 range->incompatible = 1;
970 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +0000971 }
972
973 if(tmp->empty_constraint) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000974 /*
975 * Ignore empty constraints in OR logic.
976 */
977 range->extensible |= tmp->extensible;
Lev Walkinb45e0672004-08-18 05:42:05 +0000978 _range_free(tmp);
979 continue;
980 }
981
Lev Walkinb45e0672004-08-18 05:42:05 +0000982 _range_merge_in(range, tmp);
983 }
984
985 _range_canonicalize(range);
986
Lev Walkin98eabc12017-07-19 08:51:11 +0400987 if(type == ACT_CT_FROM) {
988 /*
989 * X.696 permitted alphabet constraints are not OER-visible.
990 */
991 range->not_OER_visible = 1;
992 if(range->extensible) {
993 /*
994 * X.691, #9.3.10:
995 * Extensible permitted alphabet constraints
996 * are not PER-visible.
997 */
998 range->not_PER_visible = 1;
999 }
1000 }
Lev Walkinb74ac572004-08-25 02:05:28 +00001001
Lev Walkin4b553412005-08-14 14:45:44 +00001002 if(range->not_PER_visible
1003 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +00001004 /*
1005 * X.691, #9.3.19:
1006 * If not PER-visible constraint is part of UNION,
Lev Walkinb74ac572004-08-25 02:05:28 +00001007 * the whole resulting constraint is not PER-visible.
Lev Walkinb45e0672004-08-18 05:42:05 +00001008 */
1009 _range_free(range);
1010 if(minmax)
1011 range = _range_clone(minmax);
1012 else
1013 range = _range_new();
Lev Walkinb74ac572004-08-25 02:05:28 +00001014 range->not_PER_visible = 1;
1015 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001016 }
1017
1018 return range;
1019 case ACT_CA_EXC: /* FROM("ABCD") EXCEPT FROM("AB") */
1020 /*
Lev Walkindbdc0672017-07-26 18:55:30 -07001021 * X.691 (PER), #9.3.19:
Lev Walkinb45e0672004-08-18 05:42:05 +00001022 * EXCEPT and the following value set is completely ignored.
Lev Walkindbdc0672017-07-26 18:55:30 -07001023 * X.696 (OER), #8.2.6:
1024 * EXCEPT keyword and the following value set is completely ignored.
Lev Walkinb45e0672004-08-18 05:42:05 +00001025 */
1026 assert(ct->el_count >= 1);
1027 _range_free(range);
Lev Walkina28cbb92017-07-31 20:20:17 -07001028 range = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkin4b553412005-08-14 14:45:44 +00001029 ct->elements[0], type, minmax, exmet, cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +00001030 return range;
1031 default:
Lev Walkinb74ac572004-08-25 02:05:28 +00001032 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001033 return range;
1034 }
1035
1036
1037 if(!*exmet) {
1038 /*
1039 * Expectation is not met. Return the default range.
1040 */
Lev Walkinb74ac572004-08-25 02:05:28 +00001041 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001042 return range;
1043 }
1044
1045 _range_free(range);
1046 range = _range_new();
1047
1048 ret = _range_fill(vmin, minmax, &range->left,
1049 range, type, ct->_lineno);
Lev Walkin1ef05162004-08-25 00:42:25 +00001050 if(!ret)
1051 ret = _range_fill(vmax, minmax, &range->right,
Lev Walkinb45e0672004-08-18 05:42:05 +00001052 range, type, ct->_lineno);
1053 if(ret) {
1054 _range_free(range);
1055 errno = EPERM;
1056 return NULL;
1057 }
1058
1059 if(minmax) {
1060 asn1cnst_range_t *clone;
1061
1062 clone = _range_clone(minmax);
1063
1064 /* Constrain parent type with given data. */
1065 ret = _range_intersection(clone, range, 1);
1066 _range_free(range);
1067 if(ret) {
1068 _range_free(clone);
1069 errno = EPERM;
1070 return NULL;
1071 }
1072 range = clone;
1073 }
1074
1075 /*
1076 * Recompute elements's min/max, remove duplicates, etc.
1077 */
1078 _range_canonicalize(range);
1079
1080 return range;
1081}
1082
Lev Walkin3b2278a2016-01-24 16:43:50 -08001083#ifdef UNIT_TEST
1084int main() {
1085 asn1cnst_range_t *ra = _range_new();
1086 asn1cnst_range_t *rb = _range_new();
1087
1088 fprintf(stderr, "Testing (MIN..20) x (10..15) => (MIN..9,10..15,16..20)\n");
1089
1090 /* (MIN..20) */
1091 ra->left.type = ARE_MIN;
1092 ra->right.type = ARE_VALUE; ra->right.value = 20;
1093
1094 /* (10..15) */
1095 rb->left.type = ARE_VALUE; rb->left.value = 10;
1096 rb->right.type = ARE_VALUE; rb->right.value = 15;
1097
1098 /*
1099 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
1100 */
1101 asn1cnst_range_t *r = _range_split(ra, rb);
1102 assert(r);
1103 assert(r->left.type == ARE_MIN);
1104 assert(r->right.type == ARE_MAX);
1105
1106 assert(r->el_count == 3);
1107 assert(r->elements[0]->elements == NULL);
1108 assert(r->elements[1]->elements == NULL);
1109 assert(r->elements[2]->elements == NULL);
1110
1111 /* (MIN..9) */
1112 fprintf(stderr, "[0].left = %s\n", _edge_value(&r->elements[0]->left));
1113 fprintf(stderr, "[0].right = %s\n", _edge_value(&r->elements[0]->right));
1114 assert(r->elements[0]->left.type == ARE_MIN);
1115 assert(r->elements[0]->right.type == ARE_VALUE);
1116 assert(r->elements[0]->right.value == 9);
1117
1118 /* (10..15) */
1119 fprintf(stderr, "[1].left = %s\n", _edge_value(&r->elements[1]->left));
1120 fprintf(stderr, "[1].right = %s\n", _edge_value(&r->elements[1]->right));
1121 assert(r->elements[1]->left.type == ARE_VALUE);
1122 assert(r->elements[1]->left.value == 10);
1123 assert(r->elements[1]->right.type == ARE_VALUE);
1124 assert(r->elements[1]->right.value == 15);
1125
1126 /* (16..20) */
1127 fprintf(stderr, "[2].left = %s\n", _edge_value(&r->elements[2]->left));
1128 fprintf(stderr, "[2].right = %s\n", _edge_value(&r->elements[2]->right));
1129 assert(r->elements[2]->left.type == ARE_VALUE);
1130 assert(r->elements[2]->left.value == 16);
1131 assert(r->elements[2]->right.type == ARE_VALUE);
1132 assert(r->elements[2]->right.value == 20);
1133
1134 _range_free(r);
1135
1136
1137
1138 fprintf(stderr, "Testing (MIN..20) x (<min>..15) => (<min>..15,16..20)\n");
1139
1140 /* (MIN..20) */
1141 ra->left.type = ARE_MIN;
1142 ra->right.type = ARE_VALUE; ra->right.value = 20;
1143
1144 /* (<INTMAX_MIN>..15) */
1145 rb->left.type = ARE_VALUE; rb->left.value = INTMAX_MIN;
1146 rb->right.type = ARE_VALUE; rb->right.value = 15;
1147
1148 r = _range_split(ra, rb);
1149 assert(r);
1150 assert(r->left.type == ARE_MIN);
1151 assert(r->right.type == ARE_MAX);
1152
1153 assert(r->el_count == 2);
1154 assert(r->elements[0]->elements == NULL);
1155 assert(r->elements[1]->elements == NULL);
1156
1157 /* (<min>..16) */
1158 fprintf(stderr, "[0].left = %s\n", _edge_value(&r->elements[0]->left));
1159 fprintf(stderr, "[0].right = %s\n", _edge_value(&r->elements[0]->right));
1160 assert(r->elements[0]->left.type == ARE_VALUE);
1161 assert(r->elements[0]->left.value == INTMAX_MIN);
1162 assert(r->elements[0]->right.type == ARE_VALUE);
1163 assert(r->elements[0]->right.value == 15);
1164
1165 /* (16..20) */
1166 fprintf(stderr, "[1].left = %s\n", _edge_value(&r->elements[1]->left));
1167 fprintf(stderr, "[1].right = %s\n", _edge_value(&r->elements[1]->right));
1168 assert(r->elements[1]->left.type == ARE_VALUE);
1169 assert(r->elements[1]->left.value == 16);
1170 assert(r->elements[1]->right.type == ARE_VALUE);
1171 assert(r->elements[1]->right.value == 20);
1172
1173 _range_free(r);
1174
1175 return 0;
1176}
1177#endif