blob: 4c9345d4ed35b2e1c4e2eb5ff841f4304b66ad05 [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
Lev Walkin026e21a2017-10-04 00:49:01 -070012static void
13asn1constraint_range_free_outer(asn1cnst_range_t *cr) {
Lev Walkinb45e0672004-08-18 05:42:05 +000014 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 }
Lev Walkin026e21a2017-10-04 00:49:01 -070021 memset(cr, 0, sizeof(*cr));
22 }
Lev Walkinb45e0672004-08-18 05:42:05 +000023}
Lev Walkin026e21a2017-10-04 00:49:01 -070024
25void
26asn1constraint_range_free(asn1cnst_range_t *cr) {
27 asn1constraint_range_free_outer(cr);
28 free(cr);
29}
30
Lev Walkinb45e0672004-08-18 05:42:05 +000031#define _range_free(foo) asn1constraint_range_free(foo)
32
33static asn1cnst_range_t *_range_new() {
34 asn1cnst_range_t *r;
35 r = calloc(1, sizeof(*r));
36 if(r) {
37 r->left.type = ARE_MIN;
38 r->right.type = ARE_MAX;
39 }
40 return r;
41}
42
43static void _range_remove_element(asn1cnst_range_t *range, int idx) {
44 assert(idx >= 0 && idx < range->el_count);
45
46 assert(!range->elements[idx]->elements);
47
48 _range_free(range->elements[idx]);
49
50 memmove(&range->elements[idx],
51 &range->elements[idx + 1],
52 (range->el_count - idx - 1)
53 * sizeof(range->elements[0])
54 );
55 range->el_count--;
56 range->elements[range->el_count] = 0; /* JIC */
57
58 if(range->el_count == 0) {
59 range->el_size = 0;
60 free(range->elements);
61 range->elements = 0;
62 }
63}
64
65static int _range_insert(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
66
67 assert(!cr->elements);
68
69 if(into->el_count == into->el_size) {
70 void *p;
71 int n = into->el_size?(into->el_size << 1):4;
72 p = realloc(into->elements, n * sizeof(into->elements[0]));
73 if(p) {
74 into->el_size = n;
75 into->elements = p;
76 } else {
77 assert(p);
78 return -1;
79 }
80 }
81
82 into->elements[into->el_count++] = cr;
83 return 0;
84}
85
86static asn1cnst_range_t *_range_clone(const asn1cnst_range_t *range) {
87 asn1cnst_range_t *clone;
88 int i;
89
90 clone = _range_new();
91 if(!clone) return NULL;
92
93 *clone = *range;
94 clone->elements = 0;
95 clone->el_count = 0;
96 clone->el_size = 0;
97
98 for(i = 0; i < range->el_count; i++) {
99 asn1cnst_range_t *r = _range_clone(range->elements[i]);
100 if(!r || _range_insert(clone, r)) {
101 _range_free(clone);
102 _range_free(r);
103 return NULL;
104 }
105 }
106
107 return clone;
108}
109
110static int
111_edge_compare(const asn1cnst_edge_t *el, const asn1cnst_edge_t *er) {
112
113 switch(el->type) {
114 case ARE_MIN:
115 switch(er->type) {
116 case ARE_MIN: return 0;
117 case ARE_MAX: return -1;
118 case ARE_VALUE: return -1;
119 }
120 break;
121 case ARE_MAX:
122 switch(er->type) {
123 case ARE_MIN: return 1;
124 case ARE_MAX: return 0;
125 case ARE_VALUE: return 1;
126 }
127 break;
128 case ARE_VALUE:
129 switch(er->type) {
130 case ARE_MIN: return 1;
131 case ARE_MAX: return -1;
132 case ARE_VALUE:
133 if(el->value < er->value)
134 return -1;
135 if(el->value > er->value)
136 return 1;
137 return 0;
138 }
139 break;
140 }
141
142 return 0;
143}
144
145static int
146_range_compare(const void *a, const void *b) {
147 const asn1cnst_range_t *ra = *(const asn1cnst_range_t * const *)a;
148 const asn1cnst_range_t *rb = *(const asn1cnst_range_t * const *)b;
149 int ret;
150
151 ret = _edge_compare(&ra->left, &rb->left);
152 if(!ret) {
153 ret = _edge_compare(&ra->right, &rb->right);
154 }
155
156 return ret;
157}
158
Lev Walkin026e21a2017-10-04 00:49:01 -0700159static const char *
160_edge_print(const asn1cnst_edge_t *edge, char *buf, size_t size) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000161 *buf = '\0';
Lev Walkin026e21a2017-10-04 00:49:01 -0700162 assert(size > 4);
Lev Walkinb45e0672004-08-18 05:42:05 +0000163 switch(edge->type) {
164 case ARE_MIN: strcpy(buf, "MIN"); break;
165 case ARE_MAX: strcpy(buf, "MAX"); break;
166 case ARE_VALUE:
Lev Walkin026e21a2017-10-04 00:49:01 -0700167 snprintf(buf, size, "%s", asn1p_itoa(edge->value));
Lev Walkin3b2278a2016-01-24 16:43:50 -0800168 break;
169 default:
170 assert(!"edge->type");
Lev Walkinb45e0672004-08-18 05:42:05 +0000171 }
172 return buf;
173}
174
Lev Walkin026e21a2017-10-04 00:49:01 -0700175static const char *
176_edge_string(const asn1cnst_edge_t *edge) {
177 static char buf[128];
178 return _edge_print(edge, buf, sizeof(buf));
179}
180
181static const char *
182_range_string(const asn1cnst_range_t *range) {
183 static char buf[128];
184 char buf0[128];
185 char buf1[128];
186 snprintf(buf, sizeof(buf), "(%s..%s)",
187 _edge_print(&range->left, buf0, sizeof(buf0)),
188 _edge_print(&range->right, buf1, sizeof(buf1)));
189 return buf;
190}
191
Lev Walkinb45e0672004-08-18 05:42:05 +0000192static int
193_edge_is_within(const asn1cnst_range_t *range, const asn1cnst_edge_t *edge) {
194 int i;
195
196 for(i = -1; i < range->el_count; i++) {
197 const asn1cnst_range_t *r;
198 if(i == -1) {
199 if(range->el_count) continue;
200 r = range;
201 } else {
202 r = range->elements[i];
203 }
204 if(_edge_compare(&r->left, edge) <= 0
205 && _edge_compare(&r->right, edge) >= 0)
206 return 1;
207 }
208
209 return 0;
210}
211
212static int
213_check_edges_within(const asn1cnst_range_t *range, const asn1cnst_range_t *r) {
214
215 if(!_edge_is_within(range, &r->left)) {
216 FATAL("Constraint value %s at line %d "
217 "is not within "
Lev Walkin026e21a2017-10-04 00:49:01 -0700218 "a parent constraint range %s",
219 _edge_string(&r->left),
220 r->left.lineno,
221 _range_string(range)
Lev Walkinb45e0672004-08-18 05:42:05 +0000222 );
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 "
Lev Walkin026e21a2017-10-04 00:49:01 -0700229 "a parent constraint range %s",
230 _edge_string(&r->right),
231 r->left.lineno,
232 _range_string(range)
Lev Walkinb45e0672004-08-18 05:42:05 +0000233 );
234 return -1;
235 }
236
237 return 0;
238}
239
Lev Walkin026e21a2017-10-04 00:49:01 -0700240/*
241 * Combine narrowings to get the strongest (most specific).
242 */
243static enum asn1cnst_range_narrowing
244_strongest_narrowing(const asn1cnst_range_t *ar, const asn1cnst_range_t *br) {
245 enum asn1cnst_range_narrowing an = ar->narrowing;
246 enum asn1cnst_range_narrowing bn = br->narrowing;
247
248 if(!an) {
249 return bn;
250 } else if(!bn) {
251 return an;
252 } else {
253 return an > bn ? an : bn;
254 }
255}
256
257/*
258 * Combine narrowings to get the softest one.
259 */
260static enum asn1cnst_range_narrowing
261_softest_narrowing(const asn1cnst_range_t *ar, const asn1cnst_range_t *br) {
262 enum asn1cnst_range_narrowing an = ar->narrowing;
263 enum asn1cnst_range_narrowing bn = br->narrowing;
264
265 if(an) {
266 if(bn) {
267 return an < bn ? an : bn;
268 } else {
269 assert(bn == NOT_NARROW);
270 if(br->left.type == ARE_VALUE && br->right.type == ARE_VALUE) {
271 return an;
272 } else {
273 return NOT_NARROW;
274 }
275 }
276 } else if(bn) {
277 if(ar->left.type == ARE_VALUE && ar->right.type == ARE_VALUE) {
278 return bn;
279 } else {
280 return NOT_NARROW;
281 }
282 } else {
283 return NOT_NARROW;
284 }
285}
286
Lev Walkinb45e0672004-08-18 05:42:05 +0000287static int _range_merge_in(asn1cnst_range_t *into, asn1cnst_range_t *cr) {
288 asn1cnst_range_t *r;
289 int prev_count = into->el_count;
290 int i;
291
Lev Walkined1ce782017-07-31 20:21:47 -0700292 into->not_OER_visible |= cr->not_OER_visible;
Lev Walkinb74ac572004-08-25 02:05:28 +0000293 into->not_PER_visible |= cr->not_PER_visible;
294 into->extensible |= cr->extensible;
Lev Walkined1ce782017-07-31 20:21:47 -0700295 if(into->extensible)
296 into->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +0000297
Lev Walkin026e21a2017-10-04 00:49:01 -0700298 into->narrowing = _softest_narrowing(into, cr);
299
Lev Walkinb45e0672004-08-18 05:42:05 +0000300 /*
301 * Add the element OR all its children "into".
302 */
303 for(i = -1; i < cr->el_count; i++) {
304
305 if(i == -1) {
306 if(cr->el_count) continue;
307 r = cr;
308 } else {
309 r = cr->elements[i];
310 }
311
312 if(_range_insert(into, r)) {
313 into->el_count = prev_count; /* Undo */
314 return -1;
315 }
316 }
317
318 if(cr->el_count) {
319 cr->el_count = 0;
320 _range_free(cr);
321 } else {
322 /* This range is linked into "into". */
323 }
324
325 return 0;
326}
327
Lev Walkinf6e04b52017-09-11 06:51:21 -0700328enum range_fill_result {
329 RFR_OK,
330 RFR_FAIL,
331 RFR_INCOMPATIBLE
332};
333static enum range_fill_result _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) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000334 unsigned char *p, *pend;
335
336 edge->lineno = lineno;
337
338 switch(val->type) {
339 case ATV_INTEGER:
340 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
Lev Walkinda997b12017-08-04 01:38:41 -0700341 FATAL("Integer %s value invalid "
Lev Walkinb45e0672004-08-18 05:42:05 +0000342 "for %s constraint at line %d",
Lev Walkinda997b12017-08-04 01:38:41 -0700343 asn1p_itoa(val->value.v_integer),
Lev Walkinb45e0672004-08-18 05:42:05 +0000344 asn1p_constraint_type2str(type), lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700345 return RFR_FAIL;
Lev Walkinb45e0672004-08-18 05:42:05 +0000346 }
347 edge->type = ARE_VALUE;
348 edge->value = val->value.v_integer;
Lev Walkinf6e04b52017-09-11 06:51:21 -0700349 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000350 case ATV_MIN:
351 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
352 FATAL("MIN invalid for %s constraint at line %d",
353 asn1p_constraint_type2str(type), lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700354 return RFR_FAIL;
Lev Walkinb45e0672004-08-18 05:42:05 +0000355 }
356 edge->type = ARE_MIN;
357 if(minmax) *edge = minmax->left;
358 edge->lineno = lineno; /* Restore lineno */
Lev Walkinf6e04b52017-09-11 06:51:21 -0700359 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000360 case ATV_MAX:
361 if(type != ACT_EL_RANGE && type != ACT_CT_SIZE) {
362 FATAL("MAX invalid for %s constraint at line %d",
363 asn1p_constraint_type2str(type), lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700364 return RFR_FAIL;
Lev Walkinb45e0672004-08-18 05:42:05 +0000365 }
366 edge->type = ARE_MAX;
367 if(minmax) *edge = minmax->right;
368 edge->lineno = lineno; /* Restore lineno */
Lev Walkinf6e04b52017-09-11 06:51:21 -0700369 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000370 case ATV_FALSE:
371 case ATV_TRUE:
372 if(type != ACT_EL_RANGE) {
373 FATAL("%s is invalid for %s constraint at line %d",
374 val->type==ATV_TRUE?"TRUE":"FALSE",
375 asn1p_constraint_type2str(type),
376 lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700377 return RFR_FAIL;
Lev Walkinb45e0672004-08-18 05:42:05 +0000378 }
379 edge->type = ARE_VALUE;
380 edge->value = (val->type==ATV_TRUE);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700381 return RFR_OK;
Lev Walkin1e448d32005-03-24 14:26:38 +0000382 case ATV_TUPLE:
383 case ATV_QUADRUPLE:
384 edge->type = ARE_VALUE;
385 edge->value = val->value.v_integer;
Lev Walkinf6e04b52017-09-11 06:51:21 -0700386 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000387 case ATV_STRING:
388 if(type != ACT_CT_FROM)
Lev Walkinf6e04b52017-09-11 06:51:21 -0700389 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000390 break;
Lev Walkin1ef05162004-08-25 00:42:25 +0000391 case ATV_REFERENCED:
Lev Walkinfd97d5e2004-09-15 11:45:44 +0000392 FATAL("Unresolved constraint element \"%s\" at line %d",
Lev Walkin1ef05162004-08-25 00:42:25 +0000393 asn1f_printable_reference(val->value.reference),
394 lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -0700395 return RFR_FAIL;
396 case ATV_BITVECTOR:
397 /* Value constraint... not supported yet. */
398 /* OER: X.696 (08/2015) #8.2.2i */
399 return RFR_INCOMPATIBLE;
Lev Walkinb45e0672004-08-18 05:42:05 +0000400 default:
Lev Walkinf6e04b52017-09-11 06:51:21 -0700401 FATAL("Unrecognized constraint range element type %d at line %d",
402 val->type, lineno);
403 return RFR_FAIL;
Lev Walkinb45e0672004-08-18 05:42:05 +0000404 }
405
406 assert(val->type == ATV_STRING);
407
408 p = val->value.string.buf;
409 pend = p + val->value.string.size;
Lev Walkinf6e04b52017-09-11 06:51:21 -0700410 if(p == pend) return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000411
412 edge->type = ARE_VALUE;
413 if(val->value.string.size == 1) {
414 edge->value = *p;
415 } else {
416 /*
417 * Else this is a set:
418 * (FROM("abcdef"))
419 * However, (FROM("abc".."def")) is forbidden.
420 * See also 47.4.4.
421 */
Lev Walkinb8108ec2004-09-29 13:17:17 +0000422 asn1c_integer_t vmin, vmax;
Lev Walkinb45e0672004-08-18 05:42:05 +0000423 vmin = vmax = *p;
424 for(; p < pend; p++) {
425 asn1cnst_range_t *nr = _range_new();
426 int ret;
427 assert(nr);
428
429 if(*p < vmin) vmin = *p;
430 if(*p > vmax) vmax = *p;
431
432 ret = _range_insert(range, nr);
433 assert(ret == 0);
434
435 nr->left.type = ARE_VALUE;
436 nr->left.value = *p;
437 nr->left.lineno = lineno;
438 nr->right = nr->left;
439 }
440 edge->value = (edge == &range->right) ? vmin : vmax;
441 }
442
Lev Walkinf6e04b52017-09-11 06:51:21 -0700443 return RFR_OK;
Lev Walkinb45e0672004-08-18 05:42:05 +0000444}
445
446/*
447 * Check if ranges contain common elements.
448 */
449static int
450_range_overlap(const asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
451 int lr, rl;
452 const asn1cnst_edge_t *ra_l = &ra->left;
453 const asn1cnst_edge_t *ra_r = &ra->right;
454 const asn1cnst_edge_t *rb_l = &rb->left;
455 const asn1cnst_edge_t *rb_r = &rb->right;
456
457 assert(_edge_compare(ra_l, ra_r) <= 0);
458 assert(_edge_compare(rb_l, rb_r) <= 0);
459
460 lr = _edge_compare(ra_l, rb_r);
461 rl = _edge_compare(ra_r, rb_l);
462
463 /*
464 * L: |---|
465 * R: |---|
466 */
467 if(lr > 0) return 0;
468
469 /*
470 * L: |---|
471 * R: |---|
472 */
473 if(rl < 0) return 0;
474
475 return 1;
476}
477
Lev Walkin3b2278a2016-01-24 16:43:50 -0800478
479static int _range_partial_compare(const void *pa, const void *pb) {
480 const asn1cnst_range_t *ra = *(const void * const *)pa;
481 const asn1cnst_range_t *rb = *(const void * const *)pb;
482
483 return _edge_compare(&ra->left, &rb->left);
484}
485
486static void _range_partial_sort_elements(asn1cnst_range_t *r) {
487 qsort(r->elements, r->el_count, sizeof(r->elements[0]),
488 _range_partial_compare);
489}
490
Lev Walkinb45e0672004-08-18 05:42:05 +0000491/*
492 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
493 */
494static asn1cnst_range_t *
495_range_split(asn1cnst_range_t *ra, const asn1cnst_range_t *rb) {
496 asn1cnst_range_t *range, *nr;
497 int ll, rr;
498
499 assert(ra);
500 assert(rb);
501 assert(!ra->el_count);
502 assert(!rb->el_count);
503
504 if(!_range_overlap(ra, rb)) {
505 errno = 0;
506 return 0;
507 }
508
509 ll = _edge_compare(&ra->left, &rb->left);
510 rr = _edge_compare(&ra->right, &rb->right);
511
512 /*
513 * L: |---|
514 * R: |-------|
515 */
516 if(ll >= 0 && rr <= 0) {
517 errno = 0;
518 return 0;
519 }
520
521 range = _range_new();
522 assert(range);
523
524 nr = _range_new();
525 assert(nr);
526
527 /*
528 * L: |---...
529 * R: |--..
530 */
Lev Walkin88693e82005-05-17 21:46:18 +0000531 while(ll < 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000532 nr->left = ra->left;
533 nr->right = rb->left;
Lev Walkin88693e82005-05-17 21:46:18 +0000534 if(nr->right.type == ARE_VALUE) {
Lev Walkin3b2278a2016-01-24 16:43:50 -0800535 if(nr->right.value == INTMAX_MIN) {
Lev Walkin88693e82005-05-17 21:46:18 +0000536 /* We've hit the limit here. */
537 break;
538 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000539 nr->right.value--;
Lev Walkin88693e82005-05-17 21:46:18 +0000540 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000541 _range_insert(range, nr);
542 nr = _range_new();
543 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000544 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000545 }
546
547 /*
548 * L: ...---|
549 * R: ..--|
550 */
Lev Walkin88693e82005-05-17 21:46:18 +0000551 while(rr > 0) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000552 nr->left = rb->right;
553 nr->right = ra->right;
Lev Walkin88693e82005-05-17 21:46:18 +0000554 if(nr->left.type == ARE_VALUE) {
Lev Walkin3b2278a2016-01-24 16:43:50 -0800555 if(nr->left.value == INTMAX_MAX) {
Lev Walkin88693e82005-05-17 21:46:18 +0000556 /* We've hit the limit here. */
557 break;
558 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000559 nr->left.value++;
Lev Walkin88693e82005-05-17 21:46:18 +0000560 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000561 _range_insert(range, nr);
562 nr = _range_new();
563 assert(nr);
Lev Walkin88693e82005-05-17 21:46:18 +0000564 break;
Lev Walkinb45e0672004-08-18 05:42:05 +0000565 }
566
567 /*
568 * L: |---|
569 * R: |-----|
570 */
571 nr->left = ra->left;
572 nr->right = ra->right;
573 if(_edge_compare(&ra->left, &rb->left) < 0)
574 nr->left = rb->left;
575 if(_edge_compare(&ra->right, &rb->right) > 0)
576 nr->right = rb->right;
577
578 _range_insert(range, nr);
579
Lev Walkin3b2278a2016-01-24 16:43:50 -0800580 _range_partial_sort_elements(range);
581
Lev Walkinb45e0672004-08-18 05:42:05 +0000582 return range;
583}
584
585static int
Lev Walkined1ce782017-07-31 20:21:47 -0700586_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 +0000587 int ret;
588 int i, j;
589
Lev Walkinb74ac572004-08-25 02:05:28 +0000590 assert(!range->incompatible);
591
Lev Walkined1ce782017-07-31 20:21:47 -0700592 if(is_oer) {
593 assert(range->extensible == 0);
594 assert(range->not_OER_visible == 0);
595 assert(with->extensible == 0);
596 assert(with->not_OER_visible == 0);
597 if(range->extensible) {
598 assert(range->not_OER_visible);
599 }
600 if(range->extensible || range->not_OER_visible) {
601 /* X.696 #8.2.4 Completely ignore the extensible constraints */
602 /* (XXX)(YYY,...) Retain the first one (XXX). */
603 asn1cnst_range_t *tmp = _range_new();
604 *tmp = *range;
605 *range = *with;
606 _range_free(tmp);
607 return 0;
608 }
609
610 if(with->extensible) {
611 assert(with->not_OER_visible);
612 }
613 if(with->extensible || with->not_OER_visible) {
614 /* X.696 #8.2.4 Completely ignore the extensible constraints */
615 return 0;
616 }
617 } else {
618 /* Propagate errors */
619 range->extensible |= with->extensible;
620 if(with->extensible)
621 range->not_OER_visible = 1;
622 range->not_PER_visible |= with->not_PER_visible;
623 }
Lev Walkinb74ac572004-08-25 02:05:28 +0000624 range->empty_constraint |= with->empty_constraint;
625
Lev Walkin026e21a2017-10-04 00:49:01 -0700626 range->narrowing = _strongest_narrowing(range, with);
627
Lev Walkinb74ac572004-08-25 02:05:28 +0000628 if(range->empty_constraint) {
629 /* No use in intersecting empty constraints */
Lev Walkinb45e0672004-08-18 05:42:05 +0000630 return 0;
631 }
632
633 /*
634 * This is an AND operation.
635 */
636
637 /* If this is the only element, insert it into itself as a child */
638 if(range->el_count == 0) {
639 asn1cnst_range_t *r = _range_new();
640 r->left = range->left;
641 r->right = range->right;
642 _range_insert(range, r);
643 assert(range->el_count == 1);
644 }
645
646 /*
647 * Make sure we're dealing with sane data.
648 * G.4.2.3
649 */
650 if(strict_edge_check) {
651 for(j = -1; j < with->el_count; j++) {
652
653 if(j == -1) {
654 if(with->el_count) continue;
655 if(_check_edges_within(range, with))
656 return -1;
657 } else {
658 if(_check_edges_within(range,
659 with->elements[j]))
660 return -1;
661 }
662 }
663 }
664
665 /*
666 * Split range in pieces.
667 */
668
669 for(i = 0; i < range->el_count; i++) {
670 for(j = -1; j < with->el_count; j++) {
671 const asn1cnst_range_t *wel;
672 asn1cnst_range_t *r;
673
674 if(j == -1) {
675 if(with->el_count) continue;
676 wel = with;
677 } else {
678 wel = with->elements[j];
Lev Walkin88693e82005-05-17 21:46:18 +0000679 assert(!wel->el_count); /* non-compound item! */
Lev Walkinb45e0672004-08-18 05:42:05 +0000680 }
681
682 r = _range_split(range->elements[i], wel);
683 if(r) {
684 int ec;
685 /* Substitute the current element with a split */
686 _range_remove_element(range, i);
687 assert(r->el_count);
688 for(ec = 0; ec < r->el_count; ec++) {
689 ret = _range_insert(range, r->elements[ec]);
690 assert(ret == 0);
691 }
692 r->el_count = 0;
693 _range_free(r);
694 i--;
695 break; /* Try again from this point */
696 }
697 }
698 }
699
700 assert(range->el_count);
701
702 /*
703 * Remove pieces which aren't AND-compatible "with" range.
704 */
705
706 for(i = 0; i < range->el_count; i++) {
707 for(j = -1; j < with->el_count; j++) {
708 const asn1cnst_range_t *wel;
709
710 if(j == -1) {
711 if(with->el_count) continue;
712 wel = with;
713 } else {
714 wel = with->elements[j];
715 }
716
717 if(_range_overlap(range->elements[i], wel))
718 break;
719 }
720 if(j == with->el_count) {
721 _range_remove_element(range, i);
722 i--;
723 }
724 }
725
726 if(range->el_count == 0)
727 range->empty_constraint = 1;
728
729 return 0;
730}
731
732static int
733_range_union(asn1cnst_range_t *range) {
734 int i;
735
736 qsort(range->elements, range->el_count, sizeof(range->elements[0]),
737 _range_compare);
738
739 /*
740 * The range is sorted by the start values.
741 */
742 for(i = 1; i < range->el_count; i++) {
743 asn1cnst_range_t *ra = range->elements[i - 1];
744 asn1cnst_range_t *rb = range->elements[i];
745
746 if(_range_overlap(ra, rb)) {
747 if(_edge_compare(&ra->left, &rb->left) < 0)
748 rb->left = ra->left;
749
750 if(_edge_compare(&ra->right, &rb->right) > 0)
751 rb->right = ra->right;
752 } else {
753 /*
754 * Still, range may be joined: (1..4)(5..10).
755 * This logic is valid only for whole numbers
756 * (i.e., not REAL type, but REAL constraints
Lev Walkinb74ac572004-08-25 02:05:28 +0000757 * are not PER-visible (X.691, #9.3.12).
Lev Walkinb45e0672004-08-18 05:42:05 +0000758 */
759 if(ra->right.type == ARE_VALUE
760 && rb->left.type == ARE_VALUE
761 && (rb->left.value - ra->right.value) == 1) {
762 /* (1..10) */
763 rb->left = ra->left;
764 } else {
765 continue;
766 }
767 }
768
769 /*
770 * Squeeze the array by removing the ra.
771 */
772 _range_remove_element(range, i - 1);
773
774 i--; /* Retry from the current point */
775 }
776
777 return 0;
778}
779
780static int
781_range_canonicalize(asn1cnst_range_t *range) {
782
783 if(range->el_count == 0) {
784 /*
785 * Switch left and right edges, make them sorted.
786 * It might be a mild warning though.
787 */
788 if(_edge_compare(&range->left, &range->right) > 0) {
789 asn1cnst_edge_t tmp = range->left;
790 range->left = range->right;
791 range->right = tmp;
792 }
793
Markus Elfringf3d18612016-03-15 08:35:24 +0100794 free(range->elements);
795 range->elements = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +0000796 range->el_size = 0;
797 return 0;
798 }
799
800 /*
801 * Remove duplicates and overlaps by merging them in.
802 */
803 _range_union(range);
804
805 /* Refine the left edge of a parent */
806 range->left = range->elements[0]->left;
807
808 /* Refine the right edge of a parent */
809 range->right = range->elements[range->el_count - 1]->right;
810
811 /* Remove the child, if it's a single one */
812 if(range->el_count == 1) {
813 _range_remove_element(range, 0);
814 }
815
816 return 0;
817}
818
819asn1cnst_range_t *
Lev Walkined1ce782017-07-31 20:21:47 -0700820asn1constraint_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 -0700821 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 +0400822}
823
824asn1cnst_range_t *
Lev Walkined1ce782017-07-31 20:21:47 -0700825asn1constraint_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 -0700826 if(0) return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags | CPR_strict_PER_visibility);
827 /* Due to pecularities of PER constraint handling, we don't enable strict PER visibility upfront here. */
828 return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags);
Lev Walkin98eabc12017-07-19 08:51:11 +0400829}
830
Lev Walkin026e21a2017-10-04 00:49:01 -0700831static asn1cnst_range_t *
832asn1f_real_range_from_WCOMPS(const char *dbg_name,
833 const asn1p_constraint_t *ct) {
834 asn1cnst_range_t two = {
835 {ARE_VALUE, 0, 2}, {ARE_VALUE, 0, 2}, 0, NULL, 0, 0, 0, 0, 0, 0, 0};
836 asn1cnst_range_t ten = {
837 {ARE_VALUE, 0, 10}, {ARE_VALUE, 0, 10}, 0, NULL, 0, 0, 0, 0, 0, 0, 0};
838 asn1cnst_range_t *two_ten[] = {&two, &ten};
839 /* Interpretation of X.680 #21.5 */
840 asn1cnst_range_t mantissa_default_range = {
841 {ARE_MIN, 0, 0}, {ARE_MAX, 0, 0}, 0, NULL, 0, 0, 0, 0, 0, 0, 0};
842 asn1cnst_range_t exponent_default_range = {
843 {ARE_MIN, 0, 0}, {ARE_MAX, 0, 0}, 0, NULL, 0, 0, 0, 0, 0, 0, 0};
844 asn1cnst_range_t base_default_range = {
845 {ARE_VALUE, 0, 2}, {ARE_MAX, 0, 10}, 0, two_ten, 2, 0, 0, 0, 0, 0, 0};
846
847 asn1cnst_range_t *mantissa = _range_clone(&mantissa_default_range);
848 asn1cnst_range_t *exponent = _range_clone(&exponent_default_range);
849 asn1cnst_range_t *base = _range_clone(&base_default_range);
850 asn1cnst_range_t *range;
851
852#define FREE_MEB() \
853 do { \
854 _range_free(mantissa); \
855 _range_free(exponent); \
856 _range_free(base); \
857 } while(0)
858
859 (void)dbg_name;
860
861 assert(ct->type == ACT_CT_WCOMPS);
862
863 range = _range_new();
864 range->incompatible = 1;
865
866 for(unsigned i = 0; i < ct->el_count; i++) {
867 struct asn1p_constraint_s *el = ct->elements[i];
868 asn1p_value_t *value = 0;
869 asn1cnst_range_t **dst_range = 0;
870
871 switch(el->type) {
872 case ACT_EL_EXT:
873 /* Some components might not be defined. */
874 assert(range->incompatible);
875 FREE_MEB();
876 return range;
877 default:
878 assert(range->incompatible);
879 FREE_MEB();
880 return range;
881 case ACT_EL_VALUE:
882 value = el->value;
883 if(value->type != ATV_REFERENCED) {
884 FREE_MEB();
885 return range;
886 }
887 break;
888 }
889
890 if(strcmp(asn1p_ref_string(value->value.reference), "mantissa") == 0) {
891 dst_range = &mantissa;
892 } else if(strcmp(asn1p_ref_string(value->value.reference), "exponent")
893 == 0) {
894 dst_range = &exponent;
895 } else if(strcmp(asn1p_ref_string(value->value.reference), "base")
896 == 0) {
897 dst_range = &base;
898 } else {
899 FATAL("Invalid specification \"%s\" for REAL",
900 asn1p_ref_string(value->value.reference));
901 FREE_MEB();
902 return range;
903 }
904
905 switch(el->el_count) {
906 case 0: continue;
907 case 1: break;
908 default:
909 FATAL("Too many constraints (%u) for \"%s\" for REAL", el->el_count,
910 asn1p_ref_string(value->value.reference));
911 FREE_MEB();
912 return range;
913 }
914
915 asn1cnst_range_t *tmprange = asn1constraint_compute_constraint_range(
916 dbg_name, ASN_BASIC_INTEGER, el->elements[0], ACT_EL_RANGE,
917 *dst_range, 0, CPR_noflags);
918 assert(tmprange);
919 if(tmprange->incompatible) {
920 _range_free(tmprange);
921 FREE_MEB();
922 return range;
923 }
924 asn1constraint_range_free(*dst_range);
925 *dst_range = tmprange;
926 }
927
928 range->incompatible = 0;
929
930 /* X.696 #12.2 */
931 if(mantissa->left.type == ARE_VALUE && mantissa->right.type == ARE_VALUE
932 && mantissa->left.value >= -16777215 && mantissa->right.value <= 16777215
933 && base->left.type == ARE_VALUE && base->right.type == ARE_VALUE
934 && base->left.value == 2 && base->right.value == 2
935 && exponent->left.type == ARE_VALUE && exponent->right.type == ARE_VALUE
Lev Walkinf11ebf82017-10-11 00:37:27 -0700936 && exponent->left.value >= -149 && exponent->right.value <= 104) {
Lev Walkin026e21a2017-10-04 00:49:01 -0700937 range->narrowing = NARROW_FLOAT32;
938 } else /* X.696 #12.3 */
939 if(mantissa->left.type == ARE_VALUE && mantissa->right.type == ARE_VALUE
940 && mantissa->left.value >= -9007199254740991ll
941 && mantissa->right.value <= 9007199254740991ull
942 && base->left.type == ARE_VALUE && base->right.type == ARE_VALUE
943 && base->left.value == 2 && base->right.value == 2
944 && exponent->left.type == ARE_VALUE && exponent->right.type == ARE_VALUE
Lev Walkinc44edc02017-10-04 03:28:38 -0700945 && exponent->left.value >= -1074 && exponent->right.value <= 971) {
Lev Walkin43292722017-10-05 00:33:32 -0700946 range->narrowing = NARROW_DOUBLE64;
Lev Walkin026e21a2017-10-04 00:49:01 -0700947 }
948
949 FREE_MEB();
950 return range;
951}
952
Lev Walkin98eabc12017-07-19 08:51:11 +0400953asn1cnst_range_t *
Lev Walkined1ce782017-07-31 20:21:47 -0700954asn1constraint_compute_constraint_range(
955 const char *dbg_name, asn1p_expr_type_e expr_type,
956 const asn1p_constraint_t *ct,
957 enum asn1p_constraint_type_e requested_ct_type,
958 const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) {
959 asn1cnst_range_t *range;
Lev Walkinb45e0672004-08-18 05:42:05 +0000960 asn1cnst_range_t *tmp;
961 asn1p_value_t *vmin;
962 asn1p_value_t *vmax;
963 int expectation_met;
Lev Walkind541c252004-09-05 10:36:22 +0000964 unsigned int i;
Lev Walkinb45e0672004-08-18 05:42:05 +0000965 int ret;
Lev Walkinb45e0672004-08-18 05:42:05 +0000966
967 if(!exmet) {
968 exmet = &expectation_met;
969 *exmet = 0;
970 }
971
972 /*
Lev Walkinb74ac572004-08-25 02:05:28 +0000973 * Check if the requested constraint is theoretically compatible
974 * with the given expression type.
Lev Walkinb45e0672004-08-18 05:42:05 +0000975 */
Lev Walkined1ce782017-07-31 20:21:47 -0700976 if(asn1constraint_compatible(expr_type, requested_ct_type,
Lev Walkin4b553412005-08-14 14:45:44 +0000977 cpr_flags & CPR_simulate_fbless_SIZE) != 1) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000978 errno = EINVAL;
979 return 0;
980 }
981
Lev Walkined1ce782017-07-31 20:21:47 -0700982 /*
983 * Check arguments' validity.
984 */
985 switch(requested_ct_type) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000986 case ACT_EL_RANGE:
987 if(exmet == &expectation_met)
988 *exmet = 1;
989 break;
990 case ACT_CT_FROM:
Lev Walkin98eabc12017-07-19 08:51:11 +0400991 if(cpr_flags & CPR_strict_OER_visibility) {
992 errno = EINVAL;
993 return 0;
994 }
Lev Walkinb45e0672004-08-18 05:42:05 +0000995 if(!minmax) {
996 minmax = asn1constraint_default_alphabet(expr_type);
997 if(minmax) {
998 break;
999 }
1000 }
1001 /* Fall through */
1002 case ACT_CT_SIZE:
1003 if(!minmax) {
1004 static asn1cnst_range_t mm;
1005 mm.left.type = ARE_VALUE;
1006 mm.left.value = 0;
1007 mm.right.type = ARE_MAX;
1008 minmax = &mm;
1009 }
1010 break;
1011 default:
1012 errno = EINVAL;
1013 return 0;
1014 }
1015
1016 if(minmax) {
1017 range = _range_clone(minmax);
1018 } else {
1019 range = _range_new();
1020 }
1021
Lev Walkinb74ac572004-08-25 02:05:28 +00001022 /*
1023 * X.691, #9.3.6
Lev Walkin98eabc12017-07-19 08:51:11 +04001024 * Constraints on restricted character string types
Lev Walkinb74ac572004-08-25 02:05:28 +00001025 * which are not known-multiplier are not PER-visible.
1026 */
1027 if((expr_type & ASN_STRING_NKM_MASK))
1028 range->not_PER_visible = 1;
1029
Lev Walkin98eabc12017-07-19 08:51:11 +04001030 if(!ct
1031 || (range->not_PER_visible && (cpr_flags & CPR_strict_PER_visibility)))
1032 return range;
1033
1034 /*
1035 * X.696 (08/2015), #8.2.2
1036 * SIZE constraints on restricted character string types
1037 * which are not known-multiplier are not OER-visible.
1038 */
Lev Walkined1ce782017-07-31 20:21:47 -07001039 if(requested_ct_type == ACT_CT_SIZE && (expr_type & ASN_STRING_NKM_MASK))
Lev Walkin98eabc12017-07-19 08:51:11 +04001040 range->not_OER_visible = 1;
1041
1042 if(!ct
Lev Walkin48e82d12017-10-19 03:06:35 -07001043 || (range->not_OER_visible && (cpr_flags & CPR_strict_OER_visibility))) {
Lev Walkin98eabc12017-07-19 08:51:11 +04001044 return range;
Lev Walkin48e82d12017-10-19 03:06:35 -07001045 }
Lev Walkinb45e0672004-08-18 05:42:05 +00001046
1047 switch(ct->type) {
1048 case ACT_EL_VALUE:
1049 vmin = vmax = ct->value;
1050 break;
1051 case ACT_EL_RANGE:
1052 case ACT_EL_LLRANGE:
1053 case ACT_EL_RLRANGE:
1054 case ACT_EL_ULRANGE:
1055 vmin = ct->range_start;
1056 vmax = ct->range_stop;
1057 break;
1058 case ACT_EL_EXT:
1059 if(!*exmet) {
Lev Walkined1ce782017-07-31 20:21:47 -07001060 range->extensible = 1;
1061 range->not_OER_visible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001062 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +00001063 _range_free(range);
1064 errno = ERANGE;
1065 range = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +00001066 }
1067 return range;
1068 case ACT_CT_SIZE:
1069 case ACT_CT_FROM:
Lev Walkined1ce782017-07-31 20:21:47 -07001070 if(requested_ct_type == ct->type) {
1071 /*
1072 * Specifically requested to process SIZE() or FROM() constraint.
1073 */
Lev Walkinb45e0672004-08-18 05:42:05 +00001074 *exmet = 1;
1075 } else {
Lev Walkinb74ac572004-08-25 02:05:28 +00001076 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001077 return range;
1078 }
1079 assert(ct->el_count == 1);
Lev Walkined1ce782017-07-31 20:21:47 -07001080 tmp = asn1constraint_compute_constraint_range(
1081 dbg_name, expr_type, ct->elements[0], requested_ct_type, minmax,
1082 exmet, cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +00001083 if(tmp) {
1084 _range_free(range);
1085 } else {
1086 if(errno == ERANGE) {
1087 range->empty_constraint = 1;
1088 range->extensible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -07001089 if(range->extensible)
1090 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +00001091 tmp = range;
1092 } else {
1093 _range_free(range);
1094 }
1095 }
1096 return tmp;
Lev Walkinb45e0672004-08-18 05:42:05 +00001097 case ACT_CA_SET: /* (10..20)(15..17) */
1098 case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */
1099
1100 /* AND constraints, one after another. */
1101 for(i = 0; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -07001102 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -07001103 ct->elements[i], requested_ct_type,
Lev Walkinb74ac572004-08-25 02:05:28 +00001104 ct->type==ACT_CA_SET?range:minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +00001105 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +00001106 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +00001107 if(errno == ERANGE) {
Lev Walkined1ce782017-07-31 20:21:47 -07001108 range->extensible = 1;
1109 if(range->extensible)
1110 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +00001111 continue;
1112 } else {
1113 _range_free(range);
1114 return NULL;
1115 }
Lev Walkinb45e0672004-08-18 05:42:05 +00001116 }
1117
Lev Walkinb74ac572004-08-25 02:05:28 +00001118 if(tmp->incompatible) {
1119 /*
1120 * Ignore constraints
1121 * incompatible with arguments:
1122 * SIZE(1..2) ^ FROM("ABCD")
1123 * either SIZE or FROM will be ignored.
1124 */
1125 _range_free(tmp);
1126 continue;
1127 }
1128
Lev Walkin98eabc12017-07-19 08:51:11 +04001129 if(tmp->not_OER_visible
1130 && (cpr_flags & CPR_strict_OER_visibility)) {
1131 /*
1132 * Ignore not OER-visible
1133 */
1134 _range_free(tmp);
1135 continue;
1136 }
1137
Lev Walkin4b553412005-08-14 14:45:44 +00001138 if(tmp->not_PER_visible
1139 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +00001140 if(ct->type == ACT_CA_SET) {
1141 /*
1142 * X.691, #9.3.18:
1143 * Ignore this separate component.
1144 */
1145 } else {
1146 /*
1147 * X.691, #9.3.19:
1148 * Ignore not PER-visible INTERSECTION
1149 */
1150 }
1151 _range_free(tmp);
1152 continue;
1153 }
1154
Lev Walkinb45e0672004-08-18 05:42:05 +00001155 ret = _range_intersection(range, tmp,
Lev Walkined1ce782017-07-31 20:21:47 -07001156 ct->type == ACT_CA_SET, cpr_flags & CPR_strict_OER_visibility);
Lev Walkinb45e0672004-08-18 05:42:05 +00001157 _range_free(tmp);
1158 if(ret) {
1159 _range_free(range);
1160 errno = EPERM;
1161 return NULL;
1162 }
Lev Walkined1ce782017-07-31 20:21:47 -07001163
Lev Walkinb45e0672004-08-18 05:42:05 +00001164 _range_canonicalize(range);
1165 }
1166
1167 return range;
1168 case ACT_CA_CSV: /* SIZE(1..2, 3..4) */
1169 case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */
1170
Lev Walkinb74ac572004-08-25 02:05:28 +00001171 /*
1172 * Grab the first valid constraint.
1173 */
1174 tmp = 0;
Lev Walkinb45e0672004-08-18 05:42:05 +00001175 for(i = 0; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -07001176 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -07001177 ct->elements[i], requested_ct_type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +00001178 cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +00001179 if(!tmp) {
Lev Walkinb74ac572004-08-25 02:05:28 +00001180 if(errno == ERANGE) {
1181 range->extensible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -07001182 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +00001183 continue;
1184 } else {
1185 _range_free(range);
1186 return NULL;
1187 }
1188 }
1189 if(tmp->incompatible) {
1190 _range_free(tmp);
1191 tmp = 0;
1192 }
1193 break;
1194 }
1195 if(tmp) {
1196 tmp->extensible |= range->extensible;
Lev Walkined1ce782017-07-31 20:21:47 -07001197 tmp->not_OER_visible |= range->not_OER_visible;
Lev Walkinb74ac572004-08-25 02:05:28 +00001198 tmp->empty_constraint |= range->empty_constraint;
1199 _range_free(range);
1200 range = tmp;
1201 } else {
1202 range->incompatible = 1;
1203 return range;
1204 }
1205
1206 /*
1207 * Merge with the rest of them.
1208 * Canonicalizator will do the union magic.
1209 */
1210 for(; i < ct->el_count; i++) {
Lev Walkina28cbb92017-07-31 20:20:17 -07001211 tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -07001212 ct->elements[i], requested_ct_type, minmax, exmet,
Lev Walkin4b553412005-08-14 14:45:44 +00001213 cpr_flags);
Lev Walkinb74ac572004-08-25 02:05:28 +00001214 if(!tmp) {
1215 if(errno == ERANGE) {
1216 range->extensible = 1;
Lev Walkined1ce782017-07-31 20:21:47 -07001217 range->not_OER_visible = 1;
Lev Walkinb74ac572004-08-25 02:05:28 +00001218 continue;
1219 } else {
1220 _range_free(range);
1221 return NULL;
1222 }
1223 }
1224
1225 if(tmp->incompatible) {
1226 _range_free(tmp);
1227 _range_canonicalize(range);
1228 range->incompatible = 1;
1229 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +00001230 }
1231
1232 if(tmp->empty_constraint) {
Lev Walkinb74ac572004-08-25 02:05:28 +00001233 /*
1234 * Ignore empty constraints in OR logic.
1235 */
1236 range->extensible |= tmp->extensible;
Lev Walkined1ce782017-07-31 20:21:47 -07001237 range->not_OER_visible |= tmp->not_OER_visible;
Lev Walkinb45e0672004-08-18 05:42:05 +00001238 _range_free(tmp);
1239 continue;
1240 }
1241
Lev Walkinb45e0672004-08-18 05:42:05 +00001242 _range_merge_in(range, tmp);
1243 }
1244
1245 _range_canonicalize(range);
1246
Lev Walkined1ce782017-07-31 20:21:47 -07001247 if(requested_ct_type == ACT_CT_FROM) {
Lev Walkin98eabc12017-07-19 08:51:11 +04001248 /*
1249 * X.696 permitted alphabet constraints are not OER-visible.
1250 */
1251 range->not_OER_visible = 1;
1252 if(range->extensible) {
1253 /*
1254 * X.691, #9.3.10:
1255 * Extensible permitted alphabet constraints
1256 * are not PER-visible.
1257 */
1258 range->not_PER_visible = 1;
1259 }
1260 }
Lev Walkinb74ac572004-08-25 02:05:28 +00001261
Lev Walkin4b553412005-08-14 14:45:44 +00001262 if(range->not_PER_visible
1263 && (cpr_flags & CPR_strict_PER_visibility)) {
Lev Walkinb45e0672004-08-18 05:42:05 +00001264 /*
1265 * X.691, #9.3.19:
1266 * If not PER-visible constraint is part of UNION,
Lev Walkinb74ac572004-08-25 02:05:28 +00001267 * the whole resulting constraint is not PER-visible.
Lev Walkinb45e0672004-08-18 05:42:05 +00001268 */
1269 _range_free(range);
1270 if(minmax)
1271 range = _range_clone(minmax);
1272 else
1273 range = _range_new();
Lev Walkinb74ac572004-08-25 02:05:28 +00001274 range->not_PER_visible = 1;
1275 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001276 }
1277
1278 return range;
1279 case ACT_CA_EXC: /* FROM("ABCD") EXCEPT FROM("AB") */
1280 /*
Lev Walkindbdc0672017-07-26 18:55:30 -07001281 * X.691 (PER), #9.3.19:
Lev Walkinb45e0672004-08-18 05:42:05 +00001282 * EXCEPT and the following value set is completely ignored.
Lev Walkindbdc0672017-07-26 18:55:30 -07001283 * X.696 (OER), #8.2.6:
1284 * EXCEPT keyword and the following value set is completely ignored.
Lev Walkinb45e0672004-08-18 05:42:05 +00001285 */
1286 assert(ct->el_count >= 1);
1287 _range_free(range);
Lev Walkina28cbb92017-07-31 20:20:17 -07001288 range = asn1constraint_compute_constraint_range(dbg_name, expr_type,
Lev Walkined1ce782017-07-31 20:21:47 -07001289 ct->elements[0], requested_ct_type, minmax, exmet, cpr_flags);
Lev Walkinb45e0672004-08-18 05:42:05 +00001290 return range;
Lev Walkin026e21a2017-10-04 00:49:01 -07001291 case ACT_CT_WCOMPS:
1292 if(expr_type == ASN_BASIC_REAL) {
1293 return asn1f_real_range_from_WCOMPS(dbg_name, ct);
1294 }
1295 range->incompatible = 1;
1296 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +00001297 default:
Lev Walkinb74ac572004-08-25 02:05:28 +00001298 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001299 return range;
1300 }
1301
Lev Walkinb45e0672004-08-18 05:42:05 +00001302 if(!*exmet) {
1303 /*
1304 * Expectation is not met. Return the default range.
1305 */
Lev Walkinb74ac572004-08-25 02:05:28 +00001306 range->incompatible = 1;
Lev Walkinb45e0672004-08-18 05:42:05 +00001307 return range;
1308 }
1309
Lev Walkin026e21a2017-10-04 00:49:01 -07001310 if(expr_type == ASN_BASIC_REAL
1311 && (vmin->type == ATV_REAL || vmax->type == ATV_REAL)) {
1312 range->incompatible = 1;
1313 return range;
1314 }
1315
1316 _range_free(range);
Lev Walkinb45e0672004-08-18 05:42:05 +00001317 range = _range_new();
1318
Lev Walkinf6e04b52017-09-11 06:51:21 -07001319 enum range_fill_result rfr;
1320 rfr = _range_fill(vmin, minmax, &range->left,
Lev Walkined1ce782017-07-31 20:21:47 -07001321 range, requested_ct_type, ct->_lineno);
Lev Walkinf6e04b52017-09-11 06:51:21 -07001322 if(rfr == RFR_OK) {
1323 rfr = _range_fill(vmax, minmax, &range->right,
1324 range, requested_ct_type, ct->_lineno);
1325 }
1326 switch(rfr) {
1327 case RFR_OK:
1328 break;
1329 case RFR_FAIL:
1330 _range_free(range);
1331 errno = EPERM;
1332 return NULL;
1333 case RFR_INCOMPATIBLE:
1334 range->incompatible = 1;
1335 return range;
Lev Walkinb45e0672004-08-18 05:42:05 +00001336 }
1337
1338 if(minmax) {
1339 asn1cnst_range_t *clone;
1340
1341 clone = _range_clone(minmax);
1342
1343 /* Constrain parent type with given data. */
Lev Walkined1ce782017-07-31 20:21:47 -07001344 ret = _range_intersection(clone, range, 1,
1345 cpr_flags & CPR_strict_OER_visibility);
Lev Walkinb45e0672004-08-18 05:42:05 +00001346 _range_free(range);
1347 if(ret) {
1348 _range_free(clone);
1349 errno = EPERM;
1350 return NULL;
1351 }
1352 range = clone;
1353 }
1354
1355 /*
1356 * Recompute elements's min/max, remove duplicates, etc.
1357 */
1358 _range_canonicalize(range);
1359
1360 return range;
1361}
1362
Lev Walkin3b2278a2016-01-24 16:43:50 -08001363#ifdef UNIT_TEST
1364int main() {
1365 asn1cnst_range_t *ra = _range_new();
1366 asn1cnst_range_t *rb = _range_new();
1367
1368 fprintf(stderr, "Testing (MIN..20) x (10..15) => (MIN..9,10..15,16..20)\n");
1369
1370 /* (MIN..20) */
1371 ra->left.type = ARE_MIN;
1372 ra->right.type = ARE_VALUE; ra->right.value = 20;
1373
1374 /* (10..15) */
1375 rb->left.type = ARE_VALUE; rb->left.value = 10;
1376 rb->right.type = ARE_VALUE; rb->right.value = 15;
1377
1378 /*
1379 * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
1380 */
1381 asn1cnst_range_t *r = _range_split(ra, rb);
1382 assert(r);
1383 assert(r->left.type == ARE_MIN);
1384 assert(r->right.type == ARE_MAX);
1385
1386 assert(r->el_count == 3);
1387 assert(r->elements[0]->elements == NULL);
1388 assert(r->elements[1]->elements == NULL);
1389 assert(r->elements[2]->elements == NULL);
1390
1391 /* (MIN..9) */
Lev Walkin026e21a2017-10-04 00:49:01 -07001392 fprintf(stderr, "[0].left = %s\n", _edge_string(&r->elements[0]->left));
1393 fprintf(stderr, "[0].right = %s\n", _edge_string(&r->elements[0]->right));
Lev Walkin3b2278a2016-01-24 16:43:50 -08001394 assert(r->elements[0]->left.type == ARE_MIN);
1395 assert(r->elements[0]->right.type == ARE_VALUE);
1396 assert(r->elements[0]->right.value == 9);
1397
1398 /* (10..15) */
Lev Walkin026e21a2017-10-04 00:49:01 -07001399 fprintf(stderr, "[1].left = %s\n", _edge_string(&r->elements[1]->left));
1400 fprintf(stderr, "[1].right = %s\n", _edge_string(&r->elements[1]->right));
Lev Walkin3b2278a2016-01-24 16:43:50 -08001401 assert(r->elements[1]->left.type == ARE_VALUE);
1402 assert(r->elements[1]->left.value == 10);
1403 assert(r->elements[1]->right.type == ARE_VALUE);
1404 assert(r->elements[1]->right.value == 15);
1405
1406 /* (16..20) */
Lev Walkin026e21a2017-10-04 00:49:01 -07001407 fprintf(stderr, "[2].left = %s\n", _edge_string(&r->elements[2]->left));
1408 fprintf(stderr, "[2].right = %s\n", _edge_string(&r->elements[2]->right));
Lev Walkin3b2278a2016-01-24 16:43:50 -08001409 assert(r->elements[2]->left.type == ARE_VALUE);
1410 assert(r->elements[2]->left.value == 16);
1411 assert(r->elements[2]->right.type == ARE_VALUE);
1412 assert(r->elements[2]->right.value == 20);
1413
1414 _range_free(r);
1415
1416
1417
1418 fprintf(stderr, "Testing (MIN..20) x (<min>..15) => (<min>..15,16..20)\n");
1419
1420 /* (MIN..20) */
1421 ra->left.type = ARE_MIN;
1422 ra->right.type = ARE_VALUE; ra->right.value = 20;
1423
1424 /* (<INTMAX_MIN>..15) */
1425 rb->left.type = ARE_VALUE; rb->left.value = INTMAX_MIN;
1426 rb->right.type = ARE_VALUE; rb->right.value = 15;
1427
1428 r = _range_split(ra, rb);
1429 assert(r);
1430 assert(r->left.type == ARE_MIN);
1431 assert(r->right.type == ARE_MAX);
1432
1433 assert(r->el_count == 2);
1434 assert(r->elements[0]->elements == NULL);
1435 assert(r->elements[1]->elements == NULL);
1436
1437 /* (<min>..16) */
Lev Walkin026e21a2017-10-04 00:49:01 -07001438 fprintf(stderr, "[0].left = %s\n", _edge_string(&r->elements[0]->left));
1439 fprintf(stderr, "[0].right = %s\n", _edge_string(&r->elements[0]->right));
Lev Walkin3b2278a2016-01-24 16:43:50 -08001440 assert(r->elements[0]->left.type == ARE_VALUE);
1441 assert(r->elements[0]->left.value == INTMAX_MIN);
1442 assert(r->elements[0]->right.type == ARE_VALUE);
1443 assert(r->elements[0]->right.value == 15);
1444
1445 /* (16..20) */
Lev Walkin026e21a2017-10-04 00:49:01 -07001446 fprintf(stderr, "[1].left = %s\n", _edge_string(&r->elements[1]->left));
1447 fprintf(stderr, "[1].right = %s\n", _edge_string(&r->elements[1]->right));
Lev Walkin3b2278a2016-01-24 16:43:50 -08001448 assert(r->elements[1]->left.type == ARE_VALUE);
1449 assert(r->elements[1]->left.value == 16);
1450 assert(r->elements[1]->right.type == ARE_VALUE);
1451 assert(r->elements[1]->right.value == 20);
1452
1453 _range_free(r);
1454
1455 return 0;
1456}
1457#endif