NativeEnumerated.c vars NULL init and check
[com/asn1c.git] / libasn1fix / asn1fix_crange.c
1 #include "asn1fix_internal.h"
2 #include "asn1fix_constraint.h"
3 #include "asn1fix_crange.h"
4
5 #undef  FATAL
6 #define FATAL(fmt, args...)     do {                    \
7                 fprintf(stderr, "FATAL: ");             \
8                 fprintf(stderr, fmt, ##args);           \
9                 fprintf(stderr, "\n");                  \
10         } while(0)
11
12 static void
13 asn1constraint_range_free_outer(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         memset(cr, 0, sizeof(*cr));
22     }
23 }
24
25 void
26 asn1constraint_range_free(asn1cnst_range_t *cr) {
27     asn1constraint_range_free_outer(cr);
28     free(cr);
29 }
30
31 #define _range_free(foo)        asn1constraint_range_free(foo)
32
33 static 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
43 static 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
65 static 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
86 static 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
110 static 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
145 static 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
159 static const char *
160 _edge_print(const asn1cnst_edge_t *edge, char *buf, size_t size) {
161         *buf = '\0';
162     assert(size > 4);
163         switch(edge->type) {
164         case ARE_MIN:   strcpy(buf, "MIN"); break;
165         case ARE_MAX:   strcpy(buf, "MAX"); break;
166         case ARE_VALUE:
167                 snprintf(buf, size, "%s", asn1p_itoa(edge->value));
168         break;
169     default:
170         assert(!"edge->type");
171         }
172         return buf;
173 }
174
175 static 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
181 static 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
192 static 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
212 static 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 "
218                         "a parent constraint range %s",
219                         _edge_string(&r->left),
220                         r->left.lineno,
221                         _range_string(range)
222                 );
223                 return -1;
224         }
225
226         if(!_edge_is_within(range, &r->right)) {
227                 FATAL("Constraint value %s at line %d "
228                         "is not within "
229                         "a parent constraint range %s",
230                         _edge_string(&r->right),
231                         r->left.lineno,
232                         _range_string(range)
233                 );
234                 return -1;
235         }
236
237         return 0;
238 }
239
240 /*
241  * Combine narrowings to get the strongest (most specific).
242  */
243 static 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  */
260 static 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
287 static 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
292         into->not_OER_visible |= cr->not_OER_visible;
293         into->not_PER_visible |= cr->not_PER_visible;
294         into->extensible |= cr->extensible;
295         if(into->extensible)
296                 into->not_OER_visible = 1;
297
298     into->narrowing = _softest_narrowing(into, cr);
299
300         /*
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
328 enum range_fill_result {
329     RFR_OK,
330     RFR_FAIL,
331     RFR_INCOMPATIBLE
332 };
333 static 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) {
334         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) {
341                         FATAL("Integer %s value invalid "
342                                 "for %s constraint at line %d",
343                                 asn1p_itoa(val->value.v_integer),
344                                 asn1p_constraint_type2str(type), lineno);
345                         return RFR_FAIL;
346                 }
347                 edge->type = ARE_VALUE;
348                 edge->value = val->value.v_integer;
349                 return RFR_OK;
350         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);
354                         return RFR_FAIL;
355                 }
356                 edge->type = ARE_MIN;
357                 if(minmax) *edge = minmax->left;
358                 edge->lineno = lineno;  /* Restore lineno */
359                 return RFR_OK;
360         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);
364                         return RFR_FAIL;
365                 }
366                 edge->type = ARE_MAX;
367                 if(minmax) *edge = minmax->right;
368                 edge->lineno = lineno;  /* Restore lineno */
369                 return RFR_OK;
370         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);
377                         return RFR_FAIL;
378                 }
379                 edge->type = ARE_VALUE;
380                 edge->value = (val->type==ATV_TRUE);
381                 return RFR_OK;
382         case ATV_TUPLE:
383         case ATV_QUADRUPLE:
384                 edge->type = ARE_VALUE;
385                 edge->value = val->value.v_integer;
386                 return RFR_OK;
387         case ATV_STRING:
388                 if(type != ACT_CT_FROM)
389                         return RFR_OK;
390                 break;
391         case ATV_REFERENCED:
392                 FATAL("Unresolved constraint element \"%s\" at line %d",
393                         asn1f_printable_reference(val->value.reference),
394                         lineno);
395                 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;
400         default:
401                 FATAL("Unrecognized constraint range element type %d at line %d",
402                         val->type, lineno);
403                 return RFR_FAIL;
404         }
405
406         assert(val->type == ATV_STRING);
407
408         p = val->value.string.buf;
409         pend = p + val->value.string.size;
410         if(p == pend) return RFR_OK;
411
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                  */
422                 asn1c_integer_t vmin, vmax;
423                 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
443         return RFR_OK;
444 }
445
446 /*
447  * Check if ranges contain common elements.
448  */
449 static 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
478
479 static 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
486 static 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
491 /*
492  * (MIN..20) x (10..15) = (MIN..9,10..15,16..20)
493  */
494 static 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          */
531         while(ll < 0) {
532                 nr->left = ra->left;
533                 nr->right = rb->left;
534                 if(nr->right.type == ARE_VALUE) {
535                         if(nr->right.value == INTMAX_MIN) {
536                                 /* We've hit the limit here. */
537                                 break;
538                         }
539                         nr->right.value--;
540                 }
541                 _range_insert(range, nr);
542                 nr = _range_new();
543                 assert(nr);
544                 break;
545         }
546
547         /*
548          * L: ...---|
549          * R: ..--|
550          */
551         while(rr > 0) {
552                 nr->left = rb->right;
553                 nr->right = ra->right;
554                 if(nr->left.type == ARE_VALUE) {
555                         if(nr->left.value == INTMAX_MAX) {
556                                 /* We've hit the limit here. */
557                                 break;
558                         }
559                         nr->left.value++;
560                 }
561                 _range_insert(range, nr);
562                 nr = _range_new();
563                 assert(nr);
564                 break;
565         }
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
580     _range_partial_sort_elements(range);
581
582         return range;
583 }
584
585 static int
586 _range_intersection(asn1cnst_range_t *range, const asn1cnst_range_t *with, int strict_edge_check, int is_oer) {
587         int ret;
588         int i, j;
589
590         assert(!range->incompatible);
591
592     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     }
624         range->empty_constraint |= with->empty_constraint;
625
626     range->narrowing = _strongest_narrowing(range, with);
627
628         if(range->empty_constraint) {
629                 /* No use in intersecting empty constraints */
630                 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];
679                         assert(!wel->el_count); /* non-compound item! */
680                 }
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
732 static 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
757                          * are not PER-visible (X.691, #9.3.12).
758                          */
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
780 static 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
794                 free(range->elements);
795                 range->elements = 0;
796                 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
819 asn1cnst_range_t *
820 asn1constraint_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) {
821     return asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, requested_ct_type, minmax, exmet, cpr_flags | CPR_strict_OER_visibility);
822 }
823
824 asn1cnst_range_t *
825 asn1constraint_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) {
826     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);
829 }
830
831 static asn1cnst_range_t *
832 asn1f_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
936        && exponent->left.value >= -149 && exponent->right.value <= 104) {
937         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
945        && exponent->left.value >= -1074 && exponent->right.value <= 971) {
946         range->narrowing = NARROW_DOUBLE64;
947     }
948
949     FREE_MEB();
950     return range;
951 }
952
953 asn1cnst_range_t *
954 asn1constraint_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;
960         asn1cnst_range_t *tmp;
961         asn1p_value_t *vmin;
962         asn1p_value_t *vmax;
963         int expectation_met;
964         unsigned int i;
965         int ret;
966
967         if(!exmet) {
968                 exmet = &expectation_met;
969                 *exmet = 0;
970         }
971
972         /*
973          * Check if the requested constraint is theoretically compatible
974          * with the given expression type.
975          */
976         if(asn1constraint_compatible(expr_type, requested_ct_type,
977                         cpr_flags & CPR_simulate_fbless_SIZE) != 1) {
978                 errno = EINVAL;
979                 return 0;
980         }
981
982         /*
983          * Check arguments' validity.
984          */
985         switch(requested_ct_type) {
986         case ACT_EL_RANGE:
987                 if(exmet == &expectation_met)
988                         *exmet = 1;
989                 break;
990         case ACT_CT_FROM:
991         if(cpr_flags & CPR_strict_OER_visibility) {
992             errno = EINVAL;
993             return 0;
994         }
995                 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
1022         /*
1023          * X.691, #9.3.6
1024          * Constraints on restricted character string types
1025          * 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
1030     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      */
1039         if(requested_ct_type == ACT_CT_SIZE && (expr_type & ASN_STRING_NKM_MASK))
1040                 range->not_OER_visible = 1;
1041
1042     if(!ct
1043        || (range->not_OER_visible && (cpr_flags & CPR_strict_OER_visibility))) {
1044         return range;
1045     }
1046
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) {
1060                         range->extensible = 1;
1061                         range->not_OER_visible = 1;
1062                 } else {
1063                         _range_free(range);
1064                         errno = ERANGE;
1065                         range = 0;
1066                 }
1067                 return range;
1068         case ACT_CT_SIZE:
1069         case ACT_CT_FROM:
1070                 if(requested_ct_type == ct->type) {
1071                         /*
1072                          * Specifically requested to process SIZE() or FROM() constraint.
1073                          */
1074                         *exmet = 1;
1075                 } else {
1076                         range->incompatible = 1;
1077                         return range;
1078                 }
1079                 assert(ct->el_count == 1);
1080                 tmp = asn1constraint_compute_constraint_range(
1081                         dbg_name, expr_type, ct->elements[0], requested_ct_type, minmax,
1082                         exmet, cpr_flags);
1083                 if(tmp) {
1084                         _range_free(range);
1085                 } else {
1086                         if(errno == ERANGE) {
1087                                 range->empty_constraint = 1;
1088                                 range->extensible = 1;
1089                                 if(range->extensible)
1090                                         range->not_OER_visible = 1;
1091                                 tmp = range;
1092                         } else {
1093                                 _range_free(range);
1094                         }
1095                 }
1096                 return tmp;
1097         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++) {
1102                         tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
1103                                 ct->elements[i], requested_ct_type,
1104                                 ct->type==ACT_CA_SET?range:minmax, exmet,
1105                                 cpr_flags);
1106                         if(!tmp) {
1107                                 if(errno == ERANGE) {
1108                                         range->extensible = 1;
1109                                         if(range->extensible)
1110                                                 range->not_OER_visible = 1;
1111                                         continue;
1112                                 } else {
1113                                         _range_free(range);
1114                                         return NULL;
1115                                 }
1116                         }
1117
1118                         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
1129                         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
1138                         if(tmp->not_PER_visible
1139                         && (cpr_flags & CPR_strict_PER_visibility)) {
1140                                 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
1155                         ret = _range_intersection(range, tmp,
1156                                 ct->type == ACT_CA_SET, cpr_flags & CPR_strict_OER_visibility);
1157                         _range_free(tmp);
1158                         if(ret) {
1159                                 _range_free(range);
1160                                 errno = EPERM;
1161                                 return NULL;
1162                         }
1163
1164                         _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
1171                 /*
1172                  * Grab the first valid constraint.
1173                  */
1174                 tmp = 0;
1175                 for(i = 0; i < ct->el_count; i++) {
1176                         tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
1177                                 ct->elements[i], requested_ct_type, minmax, exmet,
1178                                 cpr_flags);
1179                         if(!tmp) {
1180                                 if(errno == ERANGE) {
1181                                         range->extensible = 1;
1182                                         range->not_OER_visible = 1;
1183                                         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;
1197                         tmp->not_OER_visible |= range->not_OER_visible;
1198                         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++) {
1211                         tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type,
1212                                 ct->elements[i], requested_ct_type, minmax, exmet,
1213                                 cpr_flags);
1214                         if(!tmp) {
1215                                 if(errno == ERANGE) {
1216                                         range->extensible = 1;
1217                                         range->not_OER_visible = 1;
1218                                         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;
1230                         }
1231
1232                         if(tmp->empty_constraint) {
1233                                 /*
1234                                  * Ignore empty constraints in OR logic.
1235                                  */
1236                                 range->extensible |= tmp->extensible;
1237                                 range->not_OER_visible |= tmp->not_OER_visible;
1238                                 _range_free(tmp);
1239                                 continue;
1240                         }
1241
1242                         _range_merge_in(range, tmp);
1243                 }
1244
1245                 _range_canonicalize(range);
1246
1247         if(requested_ct_type == ACT_CT_FROM) {
1248             /*
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         }
1261
1262                 if(range->not_PER_visible
1263                 && (cpr_flags & CPR_strict_PER_visibility)) {
1264                         /*
1265                          * X.691, #9.3.19:
1266                          * If not PER-visible constraint is part of UNION,
1267                          * the whole resulting constraint is not PER-visible.
1268                          */
1269                         _range_free(range);
1270                         if(minmax)
1271                                 range = _range_clone(minmax);
1272                         else
1273                                 range = _range_new();
1274                         range->not_PER_visible = 1;
1275                         range->incompatible = 1;
1276                 }
1277
1278                 return range;
1279         case ACT_CA_EXC:        /* FROM("ABCD") EXCEPT FROM("AB") */
1280                 /*
1281                  * X.691 (PER), #9.3.19:
1282                  * EXCEPT and the following value set is completely ignored.
1283                  * X.696 (OER), #8.2.6:
1284                  * EXCEPT keyword and the following value set is completely ignored.
1285                  */
1286                 assert(ct->el_count >= 1);
1287                 _range_free(range);
1288                 range = asn1constraint_compute_constraint_range(dbg_name, expr_type,
1289                         ct->elements[0], requested_ct_type, minmax, exmet, cpr_flags);
1290                 return range;
1291         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;
1297         default:
1298                 range->incompatible = 1;
1299                 return range;
1300         }
1301
1302         if(!*exmet) {
1303                 /*
1304                  * Expectation is not met. Return the default range.
1305                  */
1306                 range->incompatible = 1;
1307                 return range;
1308         }
1309
1310     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);
1317         range = _range_new();
1318
1319     enum range_fill_result rfr;
1320         rfr = _range_fill(vmin, minmax, &range->left,
1321                                 range, requested_ct_type, ct->_lineno);
1322     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;
1336         }
1337
1338         if(minmax) {
1339                 asn1cnst_range_t *clone;
1340
1341                 clone = _range_clone(minmax);
1342
1343                 /* Constrain parent type with given data. */
1344                 ret = _range_intersection(clone, range, 1,
1345                                           cpr_flags & CPR_strict_OER_visibility);
1346                 _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
1363 #ifdef UNIT_TEST
1364 int 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) */
1392     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));
1394     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) */
1399     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));
1401     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) */
1407     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));
1409     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) */
1438     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));
1440     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) */
1446     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));
1448     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