blob: ac543f203228ebd78e5fa0a9b8f6fe0ab1028cfc [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
2
3/*
4 * Check the validity of an enumeration.
5 */
6int
7asn1f_fix_enum(arg_t *arg) {
8 asn1p_expr_t *expr = arg->expr;
9 asn1p_expr_t *ev;
Lev Walkinb8108ec2004-09-29 13:17:17 +000010 asn1c_integer_t max_value = -1;
Lev Walkinffe79f42010-10-25 00:10:34 -070011 asn1c_integer_t max_value_ext = -1;
Lev Walkinf15320b2004-06-03 03:38:44 +000012 int rvalue = 0;
13 asn1p_expr_t *ext_marker = NULL; /* "..." position */
14 int ret;
15
Lev Walkinffe79f42010-10-25 00:10:34 -070016 /* Keep track of value collisions */
17 asn1c_integer_t *used_vals;
18 int used_vals_sz = 50;
19 int used_vals_next = 0;
20
Lev Walkinf15320b2004-06-03 03:38:44 +000021 if(expr->expr_type != ASN_BASIC_ENUMERATED)
22 return 0; /* Just ignore it */
23
Lev Walkin03850182005-03-10 10:02:50 +000024 DEBUG("(%s)", expr->Identifier);
Lev Walkinf15320b2004-06-03 03:38:44 +000025
Lev Walkinffe79f42010-10-25 00:10:34 -070026 used_vals = (asn1c_integer_t *) malloc(sizeof(asn1c_integer_t) * used_vals_sz);
27 if (!used_vals) {
28 FATAL("Out of memory");
29 return -1;
30 }
31
Lev Walkinf15320b2004-06-03 03:38:44 +000032 /*
33 * 1. Scan the enumeration values in search for inconsistencies.
34 */
35 TQ_FOR(ev, &(expr->members), next) {
Lev Walkinb8108ec2004-09-29 13:17:17 +000036 asn1c_integer_t eval;
Lev Walkinf15320b2004-06-03 03:38:44 +000037
38 if(ev->value)
39 DEBUG("\tItem %s(%s)", ev->Identifier,
40 asn1f_printable_value(ev->value));
41 else
42 DEBUG("\tItem %s", ev->Identifier);
43
44 /*
45 * 1.1 Found an extension mark "...", check correctness.
46 */
47 if(ev->expr_type == A1TC_EXTENSIBLE) {
48 if(ext_marker) {
Lev Walkina0c92902006-08-28 02:24:24 +000049 FATAL("Enumeration %s at line %d: "
Lev Walkinf15320b2004-06-03 03:38:44 +000050 "Second extension marker is not allowed",
51 expr->Identifier,
52 ev->_lineno);
53 rvalue = -1;
54 } else {
55 /*
56 * Remember the marker's position.
57 */
58 ext_marker = ev;
59 }
60 continue;
61 } else if(ev->Identifier == NULL
62 || ev->expr_type != A1TC_UNIVERVAL) {
63 FATAL(
64 "Enumeration %s at line %d: "
65 "Unsupported enumeration element %s",
66 expr->Identifier,
67 ev->_lineno,
68 ev->Identifier?ev->Identifier:"<anonymous>");
69 rvalue = -1;
70 continue;
71 }
72
73 /*
74 * 1.2 Compute the value of the enumeration element.
75 */
76 if(ev->value) {
77 switch(ev->value->type) {
78 case ATV_INTEGER:
79 eval = ev->value->value.v_integer;
80 break;
81 case ATV_REFERENCED:
82 FATAL("HERE HERE HERE", 1);
83 rvalue = -1;
84 continue;
85 break;
86 default:
87 FATAL("ENUMERATED type %s at line %d "
88 "contain element %s(%s) at line %d",
89 expr->Identifier, expr->_lineno,
90 ev->Identifier,
91 asn1f_printable_value(ev->value),
92 ev->_lineno);
93 rvalue = -1;
94 continue;
95 }
96 } else {
97 eval = max_value + 1;
98 ev->value = asn1p_value_fromint(eval);
99 if(ev->value == NULL) {
100 rvalue = -1;
101 continue;
102 }
103 }
104
105 /*
106 * 1.3 Check the applicability of this value.
107 */
Lev Walkinffe79f42010-10-25 00:10:34 -0700108
109 /*
110 * Enumeration is allowed to be unordered
111 * before the first marker, but after the marker
112 * the values must be ordered.
113 */
114 if (ext_marker) {
115 if (eval > max_value_ext) {
116 max_value_ext = eval;
117 } else {
Lev Walkinda997b12017-08-04 01:38:41 -0700118 char max_value_buf[128];
119 asn1p_itoa_s(max_value_buf, sizeof(max_value_buf),
120 max_value_ext);
121 FATAL(
Lev Walkinf15320b2004-06-03 03:38:44 +0000122 "Enumeration %s at line %d: "
Lev Walkinda997b12017-08-04 01:38:41 -0700123 "Explicit value \"%s(%s)\" "
Lev Walkinf15320b2004-06-03 03:38:44 +0000124 "is not greater "
Lev Walkinda997b12017-08-04 01:38:41 -0700125 "than previous values (max %s)",
Lev Walkinf15320b2004-06-03 03:38:44 +0000126 expr->Identifier,
127 ev->_lineno,
128 ev->Identifier,
Lev Walkinda997b12017-08-04 01:38:41 -0700129 asn1p_itoa(eval),
130 max_value_buf);
Lev Walkinf15320b2004-06-03 03:38:44 +0000131 rvalue = -1;
132 }
Lev Walkinffe79f42010-10-25 00:10:34 -0700133 }
134
135 if (eval > max_value) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000136 max_value = eval;
137 }
138
Lev Walkinffe79f42010-10-25 00:10:34 -0700139
Lev Walkinf15320b2004-06-03 03:38:44 +0000140 /*
Lev Walkinffe79f42010-10-25 00:10:34 -0700141 * 1.4 Check that all identifiers are unique
142 */
143 int unique = 1;
144 int uv_idx;
145 for (uv_idx = 0; uv_idx < used_vals_next; uv_idx++) {
146 if (used_vals[uv_idx] == eval) {
147 FATAL(
148 "Enumeration %s at line %d: "
Lev Walkinda997b12017-08-04 01:38:41 -0700149 "Explicit value \"%s(%s)\" "
Lev Walkinffe79f42010-10-25 00:10:34 -0700150 "collides with previous values",
151 expr->Identifier,
152 ev->_lineno,
153 ev->Identifier,
Lev Walkinda997b12017-08-04 01:38:41 -0700154 asn1p_itoa(eval));
Lev Walkinffe79f42010-10-25 00:10:34 -0700155 rvalue = -1;
156 unique = 0;
157 }
158 }
159
160 if (unique) {
161 /* Grow the array if needed */
162 if (used_vals_next >= used_vals_sz) {
163 asn1c_integer_t *temp;
164 int new_sz = used_vals_sz + 50;
165 temp = (asn1c_integer_t *) realloc(used_vals,
166 sizeof(asn1c_integer_t) * new_sz);
167 if (!temp) return -1;
168 used_vals = temp;
169 used_vals_sz = new_sz;
170 }
171 used_vals[used_vals_next++] = eval;
172 }
173
174 /*
175 * 1.5 Check that all identifiers before the current one
Lev Walkinf15320b2004-06-03 03:38:44 +0000176 * differs from it.
177 */
Lev Walkinfbfc7bc2006-08-28 02:45:44 +0000178 ret = asn1f_check_unique_expr_child(arg, ev, 0, "identifier");
Lev Walkinf15320b2004-06-03 03:38:44 +0000179 RET2RVAL(ret, rvalue);
180 }
181
Lev Walkinffe79f42010-10-25 00:10:34 -0700182 free(used_vals);
Lev Walkinf15320b2004-06-03 03:38:44 +0000183
184 /*
185 * 2. Reorder the first half (before optional "...") of the
186 * identifiers alphabetically.
187 */
188 // TODO
189
190 return rvalue;
191}
192