blob: 5b854646d2cc51b6b26419c59cf769aeb90d0626 [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 Walkined1ce782017-07-31 20:21:47 -0700219 into->not_OER_visible |= cr->not_OER_visible;
Lev Walkinb74ac572004-08-25 02:05:28 +0000220 into->not_PER_visible |= cr->not_PER_visible;
221 into->extensible |= cr->extensible;
Lev Walkined1ce782017-07-31 20:21:47 -0700222 if(into->extensible)
223 into->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +0000224
Lev Walkinb45e0672004-08-18 05:42:05 +0000225 /*
226 * Add the element OR all its children "into".
227 */
228 for(i = -1; i < cr->el_count; i++) {
229
230 if(i == -1) {
231 if(cr->el_count) continue;
232 r = cr;
233 } else {
234 r = cr->elements[i];
235 }
236
237 if(_range_insert(into, r)) {
238 into->el_count = prev_count; /* Undo */
239 return -1;
240 }
241 }
242
243 if(cr->el_count) {
244 cr->el_count = 0;
245 _range_free(cr);
246 } else {
247 /* This range is linked into "into". */
248 }
249
250 return 0;
251}
252
253static 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) {
254 unsigned char *p, *pend;
255
256 edge->lineno = lineno;
257
258 switch(val->type) {
259 case ATV_INTEGER:
260 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000261 FATAL("Integer %" PRIdASN " value invalid "
Lev Walkinb45e0672004-08-18 05:42:05 +0000262 "for %s constraint at line %d",
Lev Walkin33c16ba2004-09-24 21:01:43 +0000263 val->value.v_integer,
Lev Walkinb45e0672004-08-18 05:42:05 +0000264 asn1p_constraint_type2str(type), lineno);
265 return -1;
266 }
267 edge->type = ARE_VALUE;
268 edge->value = val->value.v_integer;
269 return 0;
270 case ATV_MIN:
271 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
272 FATAL("MIN invalid for %s constraint at line %d",
273 asn1p_constraint_type2str(type), lineno);
274 return -1;
275 }
276 edge->type = ARE_MIN;
277 if(minmax) *edge = minmax->left;
278 edge->lineno = lineno; /* Restore lineno */
279 return 0;
280 case ATV_MAX:
281 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
282 FATAL("MAX invalid for %s constraint at line %d",
283 asn1p_constraint_type2str(type), lineno);
284 return -1;
285 }
286 edge->type = ARE_MAX;
287 if(minmax) *edge = minmax->right;
288 edge->lineno = lineno; /* Restore lineno */
289 return 0;
290 case ATV_FALSE:
291 case ATV_TRUE:
292 if(type != ACT_EL_RANGE) {
293 FATAL("%s is invalid for %s constraint at line %d",
294 val->type==ATV_TRUE?"TRUE":"FALSE",
295 asn1p_constraint_type2str(type),
296 lineno);
297 return -1;
298 }
299 edge->type = ARE_VALUE;
300 edge->value = (val->type==ATV_TRUE);
301 return 0;
Lev Walkin1e448d32005-03-24 14:26:38 +0000302 case ATV_TUPLE:
303 case ATV_QUADRUPLE:
304 edge->type = ARE_VALUE;
305 edge->value = val->value.v_integer;
306 return 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000307 case ATV_STRING:
308 if(type != ACT_CT_FROM)
309 return 0;
310 break;
Lev Walkin1ef05162004-08-25 00:42:25 +0000311 case ATV_REFERENCED:
Lev Walkinfd97d5e2004-09-15 11:45:44 +0000312 FATAL("Unresolved constraint element \"%s\" at line %d",
Lev Walkin1ef05162004-08-25 00:42:25 +0000313 asn1f_printable_reference(val->value.reference),
314 lineno);
315 return -1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000316 default:
317 FATAL("Unrecognized constraint element at line %d",
318 lineno);
319 return -1;
320 }
321
322 assert(val->type == ATV_STRING);
323
324 p = val->value.string.buf;
325 pend = p + val->value.string.size;
326 if(p == pend) return 0;
327
328 edge->type = ARE_VALUE;
329 if(val->value.string.size == 1) {
330 edge->value = *p;
331 } else {
332 /*
333 * Else this is a set:
334 * (FROM("abcdef"))
335 * However, (FROM("abc".."def")) is forbidden.
336 * See also 47.4.4.
337 */
Lev Walkinb8108ec2004-09-29 13:17:17 +0000338 asn1c_integer_t vmin, vmax;
Lev Walkinb45e0672004-08-18 05:42:05 +0000339 vmin = vmax = *p;
340 for(; p < pend; p++) {
341 asn1cnst_range_t *nr = _range_new();
342 int ret;
343 assert(nr);
344
345 if(*p < vmin) vmin = *p;
346 if(*p > vmax) vmax = *p;
347
348 ret = _range_insert(range, nr);
349 assert(ret == 0);
350
351 nr->left.type = ARE_VALUE;
352 nr->left.value = *p;
353 nr->left.lineno = lineno;
354 nr->right = nr->left;
355 }
356 edge->value = (edge == &range->right) ? vmin : vmax;
357 }
358
359 return 0;
360}
361
362/*
363 * Check if ranges contain common elements.
364 */
365static int
366_range_overlap(const asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
367 int lr, rl;
368 const asn1cnst_edge_t *ra_l = &ra->left;
369 const asn1cnst_edge_t *ra_r = &ra->right;
370 const asn1cnst_edge_t *rb_l = &rb->left;
371 const asn1cnst_edge_t *rb_r = &rb->right;
372
373 assert(_edge_compare(ra_l, ra_r) <= 0);
374 assert(_edge_compare(rb_l, rb_r) <= 0);
375
376 lr = _edge_compare(ra_l, rb_r);
377 rl = _edge_compare(ra_r, rb_l);
378
379 /*
380 * L: |---|
381 * R: |---|
382 */
383 if(lr > 0) return 0;
384
385 /*
386 * L: |---|
387 * R: |---|
388 */
389 if(rl < 0) return 0;
390
391 return 1;
392}
393
Lev Walkin3b2278a2016-01-24 16:43:50 -0800394
395static int _range_partial_compare(const void *pa, const void *pb) {
396 const asn1cnst_range_t *ra = *(const void * const *)pa;
397 const asn1cnst_range_t *rb = *(const void * const *)pb;
398
399 return _edge_compare(&ra->left, &rb->left);
400}
401
402static void _range_partial_sort_elements(asn1cnst_range_t *r) {
403 qsort(r->elements, r->el_count, sizeof(r->elements[0]),
404 _range_partial_compare);
405}
406
Lev Walkinb45e0672004-08-18 05:42:05 +0000407/*
408 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
409 */
410static asn1cnst_range_t *
411_range_split(asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
412 asn1cnst_range_t *range, *nr;
413 int ll, rr;
414
415 assert(ra);
416 assert(rb);
417 assert(!ra->el_count);
418 assert(!rb->el_count);
419
420 if(!_range_overlap(ra, rb)) {
421 errno = 0;
422 return 0;
423 }
424
425 ll = _edge_compare(&ra->left, &rb->left);
426 rr = _edge_compare(&ra->right, &rb->right);
427
428 /*
429 * L: |---|
430 * R: |-------|
431 */
432 if(ll >= 0 && rr <= 0) {
433 errno = 0;
434 return 0;
435 }
436
437 range = _range_new();
438 assert(range);
439
440 nr = _range_new();
441 assert(nr);
442
443 /*
444 * L: |---...
445 * R: |--..
446 */
Lev Walkin88693e82005-05-17 21:46:18 +0000447 while(ll < 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000448 nr->left = ra->left;
449 nr->right = rb->left;
Lev Walkin88693e82005-05-17 21:46:18 +0000450 if(nr->right.type == ARE_VALUE) {
Lev Walkin3b2278a2016-01-24 16:43:50 -0800451 if(nr->right.value == INTMAX_MIN) {
Lev Walkin88693e82005-05-17 21:46:18 +0000452 /* We've hit the limit here. */
453 break;
454 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000455 nr->right.value--;
Lev Walkin88693e82005-05-17 21:46:18 +0000456 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000457 _range_insert(range, nr);
458 nr = _range_new();
459 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000460 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000461 }
462
463 /*
464 * L: ...---|
465 * R: ..--|
466 */
Lev Walkin88693e82005-05-17 21:46:18 +0000467 while(rr > 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000468 nr->left = rb->right;
469 nr->right = ra->right;
Lev Walkin88693e82005-05-17 21:46:18 +0000470 if(nr->left.type == ARE_VALUE) {
Lev Walkin3b2278a2016-01-24 16:43:50 -0800471 if(nr->left.value == INTMAX_MAX) {
Lev Walkin88693e82005-05-17 21:46:18 +0000472 /* We've hit the limit here. */
473 break;
474 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000475 nr->left.value++;
Lev Walkin88693e82005-05-17 21:46:18 +0000476 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000477 _range_insert(range, nr);
478 nr = _range_new();
479 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000480 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000481 }
482
483 /*
484 * L: |---|
485 * R: |-----|
486 */
487 nr->left = ra->left;
488 nr->right = ra->right;
489 if(_edge_compare(&ra->left, &rb->left) < 0)
490 nr->left = rb->left;
491 if(_edge_compare(&ra->right, &rb->right) > 0)
492 nr->right = rb->right;
493
494 _range_insert(range, nr);
495
Lev Walkin3b2278a2016-01-24 16:43:50 -0800496 _range_partial_sort_elements(range);
497
Lev Walkinb45e0672004-08-18 05:42:05 +0000498 return range;
499}
500
501static int
Lev Walkined1ce782017-07-31 20:21:47 -0700502_range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int strict_edge_check, int is_oer) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000503 int ret;
504 int i, j;
505
Lev Walkinb74ac572004-08-25 02:05:28 +0000506 assert(!range->incompatible);
507
Lev Walkined1ce782017-07-31 20:21:47 -0700508 if(is_oer) {
509 assert(range->extensible == 0);
510 assert(range->not_OER_visible == 0);
511 assert(with->extensible == 0);
512 assert(with->not_OER_visible == 0);
513 if(range->extensible) {
514 assert(range->not_OER_visible);
515 }
516 if(range->extensible || range->not_OER_visible) {
517 /* X.696 #8.2.4 Completely ignore the extensible constraints */
518 /* (XXX)(YYY,...) Retain the first one (XXX). */
519 asn1cnst_range_t *tmp = _range_new();
520 *tmp = *range;
521 *range = *with;
522 _range_free(tmp);
523 return 0;
524 }
525
526 if(with->extensible) {
527 assert(with->not_OER_visible);
528 }
529 if(with->extensible || with->not_OER_visible) {
530 /* X.696 #8.2.4 Completely ignore the extensible constraints */
531 return 0;
532 }
533 } else {
534 /* Propagate errors */
535 range->extensible |= with->extensible;
536 if(with->extensible)
537 range->not_OER_visible = 1;
538 range->not_PER_visible |= with->not_PER_visible;
539 }
Lev Walkinb74ac572004-08-25 02:05:28 +0000540 range->empty_constraint |= with->empty_constraint;
541
542 if(range->empty_constraint) {
543 /* No use in intersecting empty constraints */
Lev Walkinb45e0672004-08-18 05:42:05 +0000544 return 0;
545 }
546
547 /*
548 * This is an AND operation.
549 */
550
551 /* If this is the only element, insert it into itself as a child */
552 if(range->el_count == 0) {
553 asn1cnst_range_t *r = _range_new();
554 r->left = range->left;
555 r->right = range->right;
556 _range_insert(range, r);
557 assert(range->el_count == 1);
558 }
559
560 /*
561 * Make sure we're dealing with sane data.
562 * G.4.2.3
563 */
564 if(strict_edge_check) {
565 for(j = -1; j < with->el_count; j++) {
566
567 if(j == -1) {
568 if(with->el_count) continue;
569 if(_check_edges_within(range, with))
570 return -1;
571 } else {
572 if(_check_edges_within(range,
573 with->elements[j]))
574 return -1;
575 }
576 }
577 }
578
579 /*
580 * Split range in pieces.
581 */
582
583 for(i = 0; i < range->el_count; i++) {
584 for(j = -1; j < with->el_count; j++) {
585 const asn1cnst_range_t *wel;
586 asn1cnst_range_t *r;
587
588 if(j == -1) {
589 if(with->el_count) continue;
590 wel = with;
591 } else {
592 wel = with->elements[j];
Lev Walkin88693e82005-05-17 21:46:18 +0000593 assert(!wel->el_count); /* non-compound item! */
Lev Walkinb45e0672004-08-18 05:42:05 +0000594 }
595
596 r = _range_split(range->elements[i], wel);
597 if(r) {
598 int ec;
599 /* Substitute the current element with a split */
600 _range_remove_element(range, i);
601 assert(r->el_count);
602 for(ec = 0; ec < r->el_count; ec++) {
603 ret = _range_insert(range, r->elements[ec]);
604 assert(ret == 0);
605 }
606 r->el_count = 0;
607 _range_free(r);
608 i--;
609 break; /* Try again from this point */
610 }
611 }
612 }
613
614 assert(range->el_count);
615
616 /*
617 * Remove pieces which aren't AND-compatible "with" range.
618 */
619
620 for(i = 0; i < range->el_count; i++) {
621 for(j = -1; j < with->el_count; j++) {
622 const asn1cnst_range_t *wel;
623
624 if(j == -1) {
625 if(with->el_count) continue;
626 wel = with;
627 } else {
628 wel = with->elements[j];
629 }
630
631 if(_range_overlap(range->elements[i], wel))
632 break;
633 }
634 if(j == with->el_count) {
635 _range_remove_element(range, i);
636 i--;
637 }
638 }
639
640 if(range->el_count == 0)
641 range->empty_constraint = 1;
642
643 return 0;
644}
645
646static int
647_range_union(asn1cnst_range_t *range) {
648 int i;
649
650 qsort(range->elements, range->el_count, sizeof(range->elements[0]),
651 _range_compare);
652
653 /*
654 * The range is sorted by the start values.
655 */
656 for(i = 1; i < range->el_count; i++) {
657 asn1cnst_range_t *ra = range->elements[i - 1];
658 asn1cnst_range_t *rb = range->elements[i];
659
660 if(_range_overlap(ra, rb)) {
661 if(_edge_compare(&ra->left, &rb->left) < 0)
662 rb->left = ra->left;
663
664 if(_edge_compare(&ra->right, &rb->right) > 0)
665 rb->right = ra->right;
666 } else {
667 /*
668 * Still, range may be joined: (1..4)(5..10).
669 * This logic is valid only for whole numbers
670 * (i.e., not REAL type, but REAL constraints
Lev Walkinb74ac572004-08-25 02:05:28 +0000671 * are not PER-visible (X.691, #9.3.12).
Lev Walkinb45e0672004-08-18 05:42:05 +0000672 */
673 if(ra->right.type == ARE_VALUE
674 && rb->left.type == ARE_VALUE
675 && (rb->left.value - ra->right.value) == 1) {
676 /* (1..10) */
677 rb->left = ra->left;
678 } else {
679 continue;
680 }
681 }
682
683 /*
684 * Squeeze the array by removing the ra.
685 */
686 _range_remove_element(range, i - 1);
687
688 i--; /* Retry from the current point */
689 }
690
691 return 0;
692}
693
694static int
695_range_canonicalize(asn1cnst_range_t *range) {
696
697 if(range->el_count == 0) {
698 /*
699 * Switch left and right edges, make them sorted.
700 * It might be a mild warning though.
701 */
702 if(_edge_compare(&range->left, &range->right) > 0) {
703 asn1cnst_edge_t tmp = range->left;
704 range->left = range->right;
705 range->right = tmp;
706 }
707
Markus Elfringf3d18612016-03-15 08:35:24 +0100708 free(range->elements);
709 range->elements = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000710 range->el_size = 0;
711 return 0;
712 }
713
714 /*
715 * Remove duplicates and overlaps by merging them in.
716 */
717 _range_union(range);
718
719 /* Refine the left edge of a parent */
720 range->left = range->elements[0]->left;
721
722 /* Refine the right edge of a parent */
723 range->right = range->elements[range->el_count - 1]->right;
724
725 /* Remove the child, if it's a single one */
726 if(range->el_count == 1) {
727 _range_remove_element(range, 0);
728 }
729
730 return 0;
731}
732
733asn1cnst_range_t *
Lev Walkined1ce782017-07-31 20:21:47 -0700734asn1constraint_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, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700735 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 +0400736}
737
738asn1cnst_range_t *
Lev Walkined1ce782017-07-31 20:21:47 -0700739asn1constraint_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, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700740 if(0) return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags | CPR_strict_PER_visibility);
741 /* Due to pecularities of PER constraint handling, we don't enable strict PER visibility upfront here. */
742 return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags);
Lev Walkin98eabc12017-07-19 08:51:11 +0400743}
744
745asn1cnst_range_t *
Lev Walkined1ce782017-07-31 20:21:47 -0700746asn1constraint_compute_constraint_range(
747 const char *dbg_name, asn1p_expr_type_e expr_type,
748 const asn1p_constraint_t *ct,
749 enum asn1p_constraint_type_e requested_ct_type,
750 const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
751 asn1cnst_range_t *range;
Lev Walkinb45e0672004-08-18 05:42:05 +0000752 asn1cnst_range_t *tmp;
753 asn1p_value_t *vmin;
754 asn1p_value_t *vmax;
755 int expectation_met;
Lev Walkind541c252004-09-05 10:36:22 +0000756 unsigned int i;
Lev Walkinb45e0672004-08-18 05:42:05 +0000757 int ret;
Lev Walkinb45e0672004-08-18 05:42:05 +0000758
759 if(!exmet) {
760 exmet = &expectation_met;
761 *exmet = 0;
762 }
763
764 /*
Lev Walkinb74ac572004-08-25 02:05:28 +0000765 * Check if the requested constraint is theoretically compatible
766 * with the given expression type.
Lev Walkinb45e0672004-08-18 05:42:05 +0000767 */
Lev Walkined1ce782017-07-31 20:21:47 -0700768 if(asn1constraint_compatible(expr_type, requested_ct_type,
Lev Walkin4b553412005-08-14 14:45:44 +0000769 cpr_flags & CPR_simulate_fbless_SIZE) != 1) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000770 errno = EINVAL;
771 return 0;
772 }
773
Lev Walkined1ce782017-07-31 20:21:47 -0700774 /*
775 * Check arguments' validity.
776 */
777 switch(requested_ct_type) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000778 case ACT_EL_RANGE:
779 if(exmet == &expectation_met)
780 *exmet = 1;
781 break;
782 case ACT_CT_FROM:
Lev Walkin98eabc12017-07-19 08:51:11 +0400783 if(cpr_flags & CPR_strict_OER_visibility) {
784 errno = EINVAL;
785 return 0;
786 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000787 if(!minmax) {
788 minmax = asn1constraint_default_alphabet(expr_type);
789 if(minmax) {
790 break;
791 }
792 }
793 /* Fall through */
794 case ACT_CT_SIZE:
795 if(!minmax) {
796 static asn1cnst_range_t mm;
797 mm.left.type = ARE_VALUE;
798 mm.left.value = 0;
799 mm.right.type = ARE_MAX;
800 minmax = &mm;
801 }
802 break;
803 default:
804 errno = EINVAL;
805 return 0;
806 }
807
808 if(minmax) {
809 range = _range_clone(minmax);
810 } else {
811 range = _range_new();
812 }
813
Lev Walkinb74ac572004-08-25 02:05:28 +0000814 /*
815 * X.691, #9.3.6
Lev Walkin98eabc12017-07-19 08:51:11 +0400816 * Constraints on restricted character string types
Lev Walkinb74ac572004-08-25 02:05:28 +0000817 * which are not known-multiplier are not PER-visible.
818 */
819 if((expr_type & ASN_STRING_NKM_MASK))
820 range->not_PER_visible = 1;
821
Lev Walkin98eabc12017-07-19 08:51:11 +0400822 if(!ct
823 || (range->not_PER_visible && (cpr_flags & CPR_strict_PER_visibility)))
824 return range;
825
826 /*
827 * X.696 (08/2015), #8.2.2
828 * SIZE constraints on restricted character string types
829 * which are not known-multiplier are not OER-visible.
830 */
Lev Walkined1ce782017-07-31 20:21:47 -0700831 if(requested_ct_type == ACT_CT_SIZE && (expr_type & ASN_STRING_NKM_MASK))
Lev Walkin98eabc12017-07-19 08:51:11 +0400832 range->not_OER_visible = 1;
833
834 if(!ct
835 || (range->not_OER_visible && (cpr_flags & CPR_strict_OER_visibility)))
836 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +0000837
838 switch(ct->type) {
839 case ACT_EL_VALUE:
840 vmin = vmax = ct->value;
841 break;
842 case ACT_EL_RANGE:
843 case ACT_EL_LLRANGE:
844 case ACT_EL_RLRANGE:
845 case ACT_EL_ULRANGE:
846 vmin = ct->range_start;
847 vmax = ct->range_stop;
848 break;
849 case ACT_EL_EXT:
850 if(!*exmet) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000851 range->incompatible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -0700852 range->extensible = 1;
853 range->not_OER_visible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000854 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000855 _range_free(range);
856 errno = ERANGE;
857 range = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000858 }
859 return range;
860 case ACT_CT_SIZE:
861 case ACT_CT_FROM:
Lev Walkined1ce782017-07-31 20:21:47 -0700862 if(requested_ct_type == ct->type) {
863 /*
864 * Specifically requested to process SIZE() or FROM() constraint.
865 */
Lev Walkinb45e0672004-08-18 05:42:05 +0000866 *exmet = 1;
867 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +0000868 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +0000869 return range;
870 }
871 assert(ct->el_count == 1);
Lev Walkined1ce782017-07-31 20:21:47 -0700872 tmp = asn1constraint_compute_constraint_range(
873 dbg_name, expr_type, ct->elements[0], requested_ct_type, minmax,
874 exmet, cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +0000875 if(tmp) {
876 _range_free(range);
877 } else {
878 if(errno == ERANGE) {
879 range->empty_constraint = 1;
880 range->extensible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -0700881 if(range->extensible)
882 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +0000883 tmp = range;
884 } else {
885 _range_free(range);
886 }
887 }
888 return tmp;
Lev Walkinb45e0672004-08-18 05:42:05 +0000889 case ACT_CA_SET: /* (10..20)(15..17) */
890 case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */
891
892 /* AND constraints, one after another. */
893 for(i = 0; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700894 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -0700895 ct->elements[i], requested_ct_type,
Lev Walkinb74ac572004-08-25 02:05:28 +0000896 ct->type==ACT_CA_SET?range:minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000897 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000898 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000899 if(errno == ERANGE) {
Lev Walkined1ce782017-07-31 20:21:47 -0700900 range->extensible = 1;
901 if(range->extensible)
902 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +0000903 continue;
904 } else {
905 _range_free(range);
906 return NULL;
907 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000908 }
909
Lev Walkinb74ac572004-08-25 02:05:28 +0000910 if(tmp->incompatible) {
911 /*
912 * Ignore constraints
913 * incompatible with arguments:
914 * SIZE(1..2) ^ FROM("ABCD")
915 * either SIZE or FROM will be ignored.
916 */
917 _range_free(tmp);
918 continue;
919 }
920
Lev Walkin98eabc12017-07-19 08:51:11 +0400921 if(tmp->not_OER_visible
922 && (cpr_flags & CPR_strict_OER_visibility)) {
923 /*
924 * Ignore not OER-visible
925 */
926 _range_free(tmp);
927 continue;
928 }
929
Lev Walkin4b553412005-08-14 14:45:44 +0000930 if(tmp->not_PER_visible
931 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000932 if(ct->type == ACT_CA_SET) {
933 /*
934 * X.691, #9.3.18:
935 * Ignore this separate component.
936 */
937 } else {
938 /*
939 * X.691, #9.3.19:
940 * Ignore not PER-visible INTERSECTION
941 */
942 }
943 _range_free(tmp);
944 continue;
945 }
946
Lev Walkinb45e0672004-08-18 05:42:05 +0000947 ret = _range_intersection(range, tmp,
Lev Walkined1ce782017-07-31 20:21:47 -0700948 ct->type == ACT_CA_SET, cpr_flags & CPR_strict_OER_visibility);
Lev Walkinb45e0672004-08-18 05:42:05 +0000949 _range_free(tmp);
950 if(ret) {
951 _range_free(range);
952 errno = EPERM;
953 return NULL;
954 }
Lev Walkined1ce782017-07-31 20:21:47 -0700955
Lev Walkinb45e0672004-08-18 05:42:05 +0000956 _range_canonicalize(range);
957 }
958
959 return range;
960 case ACT_CA_CSV: /* SIZE(1..2, 3..4) */
961 case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */
962
Lev Walkinb74ac572004-08-25 02:05:28 +0000963 /*
964 * Grab the first valid constraint.
965 */
966 tmp = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000967 for(i = 0; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -0700968 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -0700969 ct->elements[i], requested_ct_type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +0000970 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +0000971 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +0000972 if(errno == ERANGE) {
973 range->extensible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -0700974 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +0000975 continue;
976 } else {
977 _range_free(range);
978 return NULL;
979 }
980 }
981 if(tmp->incompatible) {
982 _range_free(tmp);
983 tmp = 0;
984 }
985 break;
986 }
987 if(tmp) {
988 tmp->extensible |= range->extensible;
Lev Walkined1ce782017-07-31 20:21:47 -0700989 tmp->not_OER_visible |= range->not_OER_visible;
Lev Walkinb74ac572004-08-25 02:05:28 +0000990 tmp->empty_constraint |= range->empty_constraint;
991 _range_free(range);
992 range = tmp;
993 } else {
994 range->incompatible = 1;
995 return range;
996 }
997
998 /*
999 * Merge with the rest of them.
1000 * Canonicalizator will do the union magic.
1001 */
1002 for(; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -07001003 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -07001004 ct->elements[i], requested_ct_type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +00001005 cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +00001006 if(!tmp) {
1007 if(errno == ERANGE) {
1008 range->extensible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -07001009 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +00001010 continue;
1011 } else {
1012 _range_free(range);
1013 return NULL;
1014 }
1015 }
1016
1017 if(tmp->incompatible) {
1018 _range_free(tmp);
1019 _range_canonicalize(range);
1020 range->incompatible = 1;
1021 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +00001022 }
1023
1024 if(tmp->empty_constraint) {
Lev Walkinb74ac572004-08-25 02:05:28 +00001025 /*
1026 * Ignore empty constraints in OR logic.
1027 */
1028 range->extensible |= tmp->extensible;
Lev Walkined1ce782017-07-31 20:21:47 -07001029 range->not_OER_visible |= tmp->not_OER_visible;
Lev Walkinb45e0672004-08-18 05:42:05 +00001030 _range_free(tmp);
1031 continue;
1032 }
1033
Lev Walkinb45e0672004-08-18 05:42:05 +00001034 _range_merge_in(range, tmp);
1035 }
1036
1037 _range_canonicalize(range);
1038
Lev Walkined1ce782017-07-31 20:21:47 -07001039 if(requested_ct_type == ACT_CT_FROM) {
Lev Walkin98eabc12017-07-19 08:51:11 +04001040 /*
1041 * X.696 permitted alphabet constraints are not OER-visible.
1042 */
1043 range->not_OER_visible = 1;
1044 if(range->extensible) {
1045 /*
1046 * X.691, #9.3.10:
1047 * Extensible permitted alphabet constraints
1048 * are not PER-visible.
1049 */
1050 range->not_PER_visible = 1;
1051 }
1052 }
Lev Walkinb74ac572004-08-25 02:05:28 +00001053
Lev Walkin4b553412005-08-14 14:45:44 +00001054 if(range->not_PER_visible
1055 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +00001056 /*
1057 * X.691, #9.3.19:
1058 * If not PER-visible constraint is part of UNION,
Lev Walkinb74ac572004-08-25 02:05:28 +00001059 * the whole resulting constraint is not PER-visible.
Lev Walkinb45e0672004-08-18 05:42:05 +00001060 */
1061 _range_free(range);
1062 if(minmax)
1063 range = _range_clone(minmax);
1064 else
1065 range = _range_new();
Lev Walkinb74ac572004-08-25 02:05:28 +00001066 range->not_PER_visible = 1;
1067 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001068 }
1069
1070 return range;
1071 case ACT_CA_EXC: /* FROM("ABCD") EXCEPT FROM("AB") */
1072 /*
Lev Walkindbdc0672017-07-26 18:55:30 -07001073 * X.691 (PER), #9.3.19:
Lev Walkinb45e0672004-08-18 05:42:05 +00001074 * EXCEPT and the following value set is completely ignored.
Lev Walkindbdc0672017-07-26 18:55:30 -07001075 * X.696 (OER), #8.2.6:
1076 * EXCEPT keyword and the following value set is completely ignored.
Lev Walkinb45e0672004-08-18 05:42:05 +00001077 */
1078 assert(ct->el_count >= 1);
1079 _range_free(range);
Lev Walkina28cbb92017-07-31 20:20:17 -07001080 range = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -07001081 ct->elements[0], requested_ct_type, minmax, exmet, cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +00001082 return range;
1083 default:
Lev Walkinb74ac572004-08-25 02:05:28 +00001084 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001085 return range;
1086 }
1087
1088
1089 if(!*exmet) {
1090 /*
1091 * Expectation is not met. Return the default range.
1092 */
Lev Walkinb74ac572004-08-25 02:05:28 +00001093 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001094 return range;
1095 }
1096
1097 _range_free(range);
1098 range = _range_new();
1099
1100 ret = _range_fill(vmin, minmax, &range->left,
Lev Walkined1ce782017-07-31 20:21:47 -07001101 range, requested_ct_type, ct->_lineno);
Lev Walkin1ef05162004-08-25 00:42:25 +00001102 if(!ret)
1103 ret = _range_fill(vmax, minmax, &range->right,
Lev Walkined1ce782017-07-31 20:21:47 -07001104 range, requested_ct_type, ct->_lineno);
Lev Walkinb45e0672004-08-18 05:42:05 +00001105 if(ret) {
1106 _range_free(range);
1107 errno = EPERM;
1108 return NULL;
1109 }
1110
1111 if(minmax) {
1112 asn1cnst_range_t *clone;
1113
1114 clone = _range_clone(minmax);
1115
1116 /* Constrain parent type with given data. */
Lev Walkined1ce782017-07-31 20:21:47 -07001117 ret = _range_intersection(clone, range, 1,
1118 cpr_flags & CPR_strict_OER_visibility);
Lev Walkinb45e0672004-08-18 05:42:05 +00001119 _range_free(range);
1120 if(ret) {
1121 _range_free(clone);
1122 errno = EPERM;
1123 return NULL;
1124 }
1125 range = clone;
1126 }
1127
1128 /*
1129 * Recompute elements's min/max, remove duplicates, etc.
1130 */
1131 _range_canonicalize(range);
1132
1133 return range;
1134}
1135
Lev Walkin3b2278a2016-01-24 16:43:50 -08001136#ifdef UNIT_TEST
1137int main() {
1138 asn1cnst_range_t *ra = _range_new();
1139 asn1cnst_range_t *rb = _range_new();
1140
1141 fprintf(stderr, "Testing (MIN..20) x (10..15) => (MIN..9,10..15,16..20)\n");
1142
1143 /* (MIN..20) */
1144 ra->left.type = ARE_MIN;
1145 ra->right.type = ARE_VALUE; ra->right.value = 20;
1146
1147 /* (10..15) */
1148 rb->left.type = ARE_VALUE; rb->left.value = 10;
1149 rb->right.type = ARE_VALUE; rb->right.value = 15;
1150
1151 /*
1152 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
1153 */
1154 asn1cnst_range_t *r = _range_split(ra, rb);
1155 assert(r);
1156 assert(r->left.type == ARE_MIN);
1157 assert(r->right.type == ARE_MAX);
1158
1159 assert(r->el_count == 3);
1160 assert(r->elements[0]->elements == NULL);
1161 assert(r->elements[1]->elements == NULL);
1162 assert(r->elements[2]->elements == NULL);
1163
1164 /* (MIN..9) */
1165 fprintf(stderr, "[0].left = %s\n", _edge_value(&r->elements[0]->left));
1166 fprintf(stderr, "[0].right = %s\n", _edge_value(&r->elements[0]->right));
1167 assert(r->elements[0]->left.type == ARE_MIN);
1168 assert(r->elements[0]->right.type == ARE_VALUE);
1169 assert(r->elements[0]->right.value == 9);
1170
1171 /* (10..15) */
1172 fprintf(stderr, "[1].left = %s\n", _edge_value(&r->elements[1]->left));
1173 fprintf(stderr, "[1].right = %s\n", _edge_value(&r->elements[1]->right));
1174 assert(r->elements[1]->left.type == ARE_VALUE);
1175 assert(r->elements[1]->left.value == 10);
1176 assert(r->elements[1]->right.type == ARE_VALUE);
1177 assert(r->elements[1]->right.value == 15);
1178
1179 /* (16..20) */
1180 fprintf(stderr, "[2].left = %s\n", _edge_value(&r->elements[2]->left));
1181 fprintf(stderr, "[2].right = %s\n", _edge_value(&r->elements[2]->right));
1182 assert(r->elements[2]->left.type == ARE_VALUE);
1183 assert(r->elements[2]->left.value == 16);
1184 assert(r->elements[2]->right.type == ARE_VALUE);
1185 assert(r->elements[2]->right.value == 20);
1186
1187 _range_free(r);
1188
1189
1190
1191 fprintf(stderr, "Testing (MIN..20) x (<min>..15) => (<min>..15,16..20)\n");
1192
1193 /* (MIN..20) */
1194 ra->left.type = ARE_MIN;
1195 ra->right.type = ARE_VALUE; ra->right.value = 20;
1196
1197 /* (<INTMAX_MIN>..15) */
1198 rb->left.type = ARE_VALUE; rb->left.value = INTMAX_MIN;
1199 rb->right.type = ARE_VALUE; rb->right.value = 15;
1200
1201 r = _range_split(ra, rb);
1202 assert(r);
1203 assert(r->left.type == ARE_MIN);
1204 assert(r->right.type == ARE_MAX);
1205
1206 assert(r->el_count == 2);
1207 assert(r->elements[0]->elements == NULL);
1208 assert(r->elements[1]->elements == NULL);
1209
1210 /* (<min>..16) */
1211 fprintf(stderr, "[0].left = %s\n", _edge_value(&r->elements[0]->left));
1212 fprintf(stderr, "[0].right = %s\n", _edge_value(&r->elements[0]->right));
1213 assert(r->elements[0]->left.type == ARE_VALUE);
1214 assert(r->elements[0]->left.value == INTMAX_MIN);
1215 assert(r->elements[0]->right.type == ARE_VALUE);
1216 assert(r->elements[0]->right.value == 15);
1217
1218 /* (16..20) */
1219 fprintf(stderr, "[1].left = %s\n", _edge_value(&r->elements[1]->left));
1220 fprintf(stderr, "[1].right = %s\n", _edge_value(&r->elements[1]->right));
1221 assert(r->elements[1]->left.type == ARE_VALUE);
1222 assert(r->elements[1]->left.value == 16);
1223 assert(r->elements[1]->right.type == ARE_VALUE);
1224 assert(r->elements[1]->right.value == 20);
1225
1226 _range_free(r);
1227
1228 return 0;
1229}
1230#endif