blob: 6fe896f958f1f29a84ae355a47938a96ecc66428 [file] [log] [blame]
Lev Walkin84cd58e2004-08-19 13:29:46 +00001#include "asn1c_internal.h"
2#include "asn1c_constraint.h"
Lev Walkin59004fa2004-08-20 13:37:01 +00003#include "asn1c_misc.h"
4#include "asn1c_out.h"
Lev Walkin84cd58e2004-08-19 13:29:46 +00005
6#include <asn1fix_crange.h> /* constraint groker from libasn1fix */
Lev Walkin59b176e2005-11-26 11:25:14 +00007#include <asn1fix_export.h> /* other exportables from libasn1fix */
Lev Walkin84cd58e2004-08-19 13:29:46 +00008
Lev Walkin59004fa2004-08-20 13:37:01 +00009static int asn1c_emit_constraint_tables(arg_t *arg, int got_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +000010static int emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range);
Lev Walkin6ea088f2004-09-07 06:31:15 +000011static int emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value);
Lev Walkin84cd58e2004-08-19 13:29:46 +000012static int emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype);
13static asn1p_expr_type_e _find_terminal_type(arg_t *arg);
Lev Walkin05363a72004-09-29 13:16:40 +000014static int emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1c_integer_t natural_start, asn1c_integer_t natural_stop);
Lev Walkin8bb57a22007-12-03 13:41:36 +000015static int native_long_sign(asn1cnst_range_t *r); /* -1, 0, 1 */
Lev Walkin84cd58e2004-08-19 13:29:46 +000016
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020017static int
18ulong_optimization(asn1p_expr_type_e etype, asn1cnst_range_t *r_size,
19 asn1cnst_range_t *r_value)
20{
21 return (!r_size && r_value
22 && (etype == ASN_BASIC_INTEGER
23 || etype == ASN_BASIC_ENUMERATED)
24 && native_long_sign(r_value) == 0);
25}
26
Lev Walkin84cd58e2004-08-19 13:29:46 +000027int
28asn1c_emit_constraint_checking_code(arg_t *arg) {
29 asn1cnst_range_t *r_size;
30 asn1cnst_range_t *r_value;
31 asn1p_expr_t *expr = arg->expr;
32 asn1p_expr_type_e etype;
33 asn1p_constraint_t *ct;
34 int got_something = 0;
Lev Walkin6938d042005-03-04 23:23:50 +000035 int alphabet_table_compiled;
Lev Walkin59004fa2004-08-20 13:37:01 +000036 int produce_st = 0;
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020037 int ulong_optimize = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +000038
39 ct = expr->combined_constraints;
40 if(ct == NULL)
41 return 1; /* No additional constraints defined */
42
43 etype = _find_terminal_type(arg);
44
Lev Walkinbe717ec2004-08-25 02:03:59 +000045 r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE,0,0,0);
Lev Walkin729eb862006-09-21 01:50:13 +000046 r_size =asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +000047 if(r_value) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000048 if(r_value->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000049 || r_value->empty_constraint
50 || (r_value->left.type == ARE_MIN
51 && r_value->right.type == ARE_MAX)
52 || (etype == ASN_BASIC_BOOLEAN
53 && r_value->left.value == 0
54 && r_value->right.value == 1)
55 ) {
56 asn1constraint_range_free(r_value);
57 r_value = 0;
58 }
59 }
60 if(r_size) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000061 if(r_size->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000062 || r_size->empty_constraint
63 || (r_size->left.value == 0 /* or .type == MIN */
64 && r_size->right.type == ARE_MAX)
65 ) {
66 asn1constraint_range_free(r_size);
67 r_size = 0;
68 }
69 }
70
Lev Walkin59004fa2004-08-20 13:37:01 +000071 /*
72 * Do we really need an "*st = sptr" pointer?
73 */
74 switch(etype) {
75 case ASN_BASIC_INTEGER:
76 case ASN_BASIC_ENUMERATED:
Lev Walkin082cadc2005-08-14 02:18:27 +000077 if(asn1c_type_fits_long(arg, arg->expr) == FL_NOTFIT)
78 produce_st = 1;
79 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +000080 case ASN_BASIC_REAL:
Lev Walkin2a744a72013-03-27 01:56:23 -070081 if((arg->flags & A1C_USE_WIDE_TYPES))
Lev Walkin59004fa2004-08-20 13:37:01 +000082 produce_st = 1;
83 break;
Lev Walkin02b137d2004-08-21 07:34:58 +000084 case ASN_BASIC_BIT_STRING:
Lev Walkin59004fa2004-08-20 13:37:01 +000085 case ASN_BASIC_OCTET_STRING:
86 produce_st = 1;
Lev Walkin3a4689a2006-11-24 11:20:27 +000087 break;
Lev Walkin59004fa2004-08-20 13:37:01 +000088 default:
89 if(etype & ASN_STRING_MASK)
90 produce_st = 1;
91 break;
92 }
Lev Walkince31cdb2005-02-15 03:37:42 +000093 if(produce_st) {
94 char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
95 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
96 }
Lev Walkin84cd58e2004-08-19 13:29:46 +000097
98 if(r_size || r_value) {
99 if(r_size) {
100 OUT("size_t size;\n");
101 }
102 if(r_value)
103 switch(etype) {
104 case ASN_BASIC_INTEGER:
105 case ASN_BASIC_ENUMERATED:
Lev Walkin8bb57a22007-12-03 13:41:36 +0000106 if(native_long_sign(r_value) >= 0) {
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200107 ulong_optimize = ulong_optimization(etype, r_size, r_value);
108 if(!ulong_optimize) {
109 OUT("unsigned long value;\n");
110 }
Lev Walkin8bb57a22007-12-03 13:41:36 +0000111 } else {
112 OUT("long value;\n");
113 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000114 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000115 case ASN_BASIC_REAL:
116 OUT("double value;\n");
117 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000118 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000119 OUT("BOOLEAN_t value;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000120 break;
121 default:
122 break;
123 }
124 }
125
126 OUT("\n");
127
128 /*
129 * Protection against null input.
130 */
131 OUT("if(!sptr) {\n");
132 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000133 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000134 OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
135 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000136 OUT("return -1;\n");
137 INDENT(-1);
138 OUT("}\n");
139 OUT("\n");
140
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200141 if((r_value) && (!ulong_optimize))
Lev Walkin6ea088f2004-09-07 06:31:15 +0000142 emit_value_determination_code(arg, etype, r_value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000143 if(r_size)
144 emit_size_determination_code(arg, etype);
145
Lev Walkin59004fa2004-08-20 13:37:01 +0000146 INDENT(-1);
147 REDIR(OT_CTABLES);
148 /* Emit FROM() tables */
Lev Walkin6938d042005-03-04 23:23:50 +0000149 alphabet_table_compiled =
150 (asn1c_emit_constraint_tables(arg, r_size?1:0) == 1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000151 REDIR(OT_CODE);
152 INDENT(+1);
153
Lev Walkin84cd58e2004-08-19 13:29:46 +0000154 /*
Lev Walkin8bb57a22007-12-03 13:41:36 +0000155 * Optimization for unsigned longs.
156 */
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200157 if(ulong_optimize) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000158 OUT("\n");
159 OUT("/* Constraint check succeeded */\n");
160 OUT("return 0;\n");
161 return 0;
162 }
163
164 /*
Lev Walkin729eb862006-09-21 01:50:13 +0000165 * Here is an if() {} else {} consrtaint checking code.
Lev Walkin84cd58e2004-08-19 13:29:46 +0000166 */
167 OUT("\n");
168 OUT("if(");
169 INDENT(+1);
170 if(r_size) {
171 if(got_something++) { OUT("\n"); OUT(" && "); }
172 OUT("(");
173 emit_range_comparison_code(arg, r_size, "size", 0, -1);
174 OUT(")");
175 }
176 if(r_value) {
177 if(got_something++) { OUT("\n"); OUT(" && "); }
178 OUT("(");
179 if(etype == ASN_BASIC_BOOLEAN)
180 emit_range_comparison_code(arg, r_value,
181 "value", 0, 1);
182 else
183 emit_range_comparison_code(arg, r_value,
184 "value", -1, -1);
185 OUT(")");
186 }
Lev Walkin6938d042005-03-04 23:23:50 +0000187 if(alphabet_table_compiled) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000188 if(got_something++) { OUT("\n"); OUT(" && "); }
Lev Walkin6938d042005-03-04 23:23:50 +0000189 OUT("!check_permitted_alphabet_%d(%s)",
190 arg->expr->_type_unique_index,
191 produce_st ? "st" : "sptr");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000192 }
193 if(!got_something) {
194 OUT("1 /* No applicable constraints whatsoever */");
Lev Walkin59004fa2004-08-20 13:37:01 +0000195 OUT(") {\n");
196 INDENT(-1);
197 INDENTED(OUT("/* Nothing is here. See below */\n"));
198 OUT("}\n");
199 OUT("\n");
200 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000201 }
202 INDENT(-1);
203 OUT(") {\n");
204 INDENT(+1);
Lev Walkin7ef83a42005-03-29 19:04:24 +0000205 switch(etype) {
206 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkin7ef83a42005-03-29 19:04:24 +0000207 case ASN_CONSTR_SET_OF:
208 OUT("/* Perform validation of the inner elements */\n");
Lev Walkin1eded352006-07-13 11:19:01 +0000209 OUT("return td->check_constraints(td, sptr, ctfailcb, app_key);\n");
Lev Walkin7ef83a42005-03-29 19:04:24 +0000210 break;
211 default:
212 OUT("/* Constraint check succeeded */\n");
213 OUT("return 0;\n");
214 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000215 INDENT(-1);
216 OUT("} else {\n");
217 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000218 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000219 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
220 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000221 OUT("return -1;\n");
222 INDENT(-1);
223 OUT("}\n");
224
225 return 0;
226}
227
Lev Walkin59004fa2004-08-20 13:37:01 +0000228static int
229asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin05363a72004-09-29 13:16:40 +0000230 asn1c_integer_t range_start;
231 asn1c_integer_t range_stop;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000232 asn1p_expr_type_e etype;
233 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000234 asn1p_constraint_t *ct;
235 int utf8_full_alphabet_check = 0;
236 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000237 int table[256];
238 int use_table;
239
Lev Walkin59004fa2004-08-20 13:37:01 +0000240 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000241 if(!ct) return 0;
242
243 etype = _find_terminal_type(arg);
244
Lev Walkinbe717ec2004-08-25 02:03:59 +0000245 range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000246 if(!range) return 0;
247
Lev Walkinbe717ec2004-08-25 02:03:59 +0000248 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000249 || range->empty_constraint) {
250 asn1constraint_range_free(range);
251 return 0;
252 }
253
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000254 if(range->left.type == ARE_MIN
255 && range->right.type == ARE_MAX) {
256 /*
257 * The permitted alphabet constraint checker code guarantees
258 * that either both bounds (left/right) are present, or
259 * they're absent simultaneously. Thus, this assertion
260 * legitimately holds true.
261 */
262 assert(range->el_count == 0);
263 /* The full range is specified. Ignore it. */
264 return 0;
265 }
266
Lev Walkin84cd58e2004-08-19 13:29:46 +0000267 range_start = range->left.value;
268 range_stop = range->right.value;
269 assert(range->left.type == ARE_VALUE);
270 assert(range->right.type == ARE_VALUE);
271 assert(range_start <= range_stop);
272
273 range_start = 0; /* Force old behavior */
274
275 /*
276 * Check if we need a test table to check the alphabet.
277 */
278 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000279 if(range->el_count == 0) {
280 /*
281 * It's better to have a short if() check
Lev Walkin729eb862006-09-21 01:50:13 +0000282 * than waste 1k of table space
Lev Walkin59004fa2004-08-20 13:37:01 +0000283 */
284 use_table = 0;
285 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000286 if((range_stop - range_start) > 255)
287 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000288 if(etype == ASN_STRING_UTF8String) {
289 if(range_stop >= 0x80)
290 use_table = 0;
291 else
292 max_table_size = 128;
293 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000294
Lev Walkin84cd58e2004-08-19 13:29:46 +0000295 if(use_table) {
Lev Walkin729eb862006-09-21 01:50:13 +0000296 int cardinal = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000297 int i, n = 0;
298 int untl;
299 memset(table, 0, sizeof(table));
300 for(i = -1; i < range->el_count; i++) {
301 asn1cnst_range_t *r;
Lev Walkin05363a72004-09-29 13:16:40 +0000302 asn1c_integer_t v;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000303 if(i == -1) {
304 if(range->el_count) continue;
305 r = range;
306 } else {
307 r = range->elements[i];
308 }
309 for(v = r->left.value; v <= r->right.value; v++) {
310 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000311 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000312 table[v - range_start] = ++n;
313 }
314 }
315
Lev Walkin84cd58e2004-08-19 13:29:46 +0000316 untl = (range_stop - range_start) + 1;
317 untl += (untl % 16)?16 - (untl % 16):0;
Wim Lewisa73ae672014-07-22 19:55:30 -0700318 OUT("static const int permitted_alphabet_table_%d[%d] = {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000319 arg->expr->_type_unique_index, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000320 for(n = 0; n < untl; n++) {
Lev Walkin729eb862006-09-21 01:50:13 +0000321 cardinal += table[n] ? 1 : 0;
322 OUT("%2d,", table[n]);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000323 if(!((n+1) % 16)) {
324 int c;
Lev Walkin729eb862006-09-21 01:50:13 +0000325 if(!n || (n-15) + range_start >= 0x80) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000326 OUT("\n");
327 continue;
328 }
329 OUT("\t/* ");
330 for(c = n - 15; c <= n; c++) {
331 if(table[c]) {
332 int a = c + range_start;
333 if(a > 0x20 && a < 0x80)
334 OUT("%c", a);
335 else
336 OUT(".");
337 } else {
338 OUT(" ");
339 }
340 }
341 OUT(" */");
342 OUT("\n");
343 }
344 }
345 OUT("};\n");
Lev Walkin729eb862006-09-21 01:50:13 +0000346
Lev Walkin725883b2006-10-09 12:07:58 +0000347 if((arg->flags & A1C_GEN_PER)
348 && (etype & ASN_STRING_KM_MASK)) {
Lev Walkin729eb862006-09-21 01:50:13 +0000349 int c;
Wim Lewisa73ae672014-07-22 19:55:30 -0700350 OUT("static const int permitted_alphabet_code2value_%d[%d] = {\n",
Lev Walkin729eb862006-09-21 01:50:13 +0000351 arg->expr->_type_unique_index, cardinal);
352 for(n = c = 0; c < max_table_size; c++) {
353 if(table[c]) {
354 OUT("%d,", c);
355 if(!((++n) % 16)) OUT("\n");
356 }
357 }
358 OUT("};\n");
359 OUT("\n");
Lev Walkin725883b2006-10-09 12:07:58 +0000360 DEBUG("code2value map gen for %s", arg->expr->Identifier);
361 arg->expr->_mark |= TM_PERFROMCT;
Lev Walkin729eb862006-09-21 01:50:13 +0000362 }
363
Lev Walkin84cd58e2004-08-19 13:29:46 +0000364 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000365 } else if(etype == ASN_STRING_UTF8String) {
366 /*
367 * UTF8String type is a special case in many respects.
368 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000369 if(got_size) {
370 /*
371 * Size has been already determined.
372 * The UTF8String length checker also checks
373 * for the syntax validity, so we don't have
374 * to repeat this process twice.
375 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000376 asn1constraint_range_free(range);
377 return 0;
378 } else {
379 utf8_full_alphabet_check = 1;
380 }
381 } else {
382 /*
383 * This permitted alphabet check will be
384 * expressed using conditional statements
385 * instead of table lookups. Table would be
386 * to large or otherwise inappropriate (too sparse?).
387 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000388 }
389
390 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000391 arg->expr->_type_unique_index);
Lev Walkin59004fa2004-08-20 13:37:01 +0000392 INDENT(+1);
393 if(utf8_full_alphabet_check) {
Lev Walkin29c41682004-10-02 16:44:55 +0000394 OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
395 OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000396 OUT("\n");
397 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000398 if(use_table) {
Wim Lewisa73ae672014-07-22 19:55:30 -0700399 OUT("const int *table = permitted_alphabet_table_%d;\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000400 arg->expr->_type_unique_index);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000401 emit_alphabet_check_loop(arg, 0);
402 } else {
403 emit_alphabet_check_loop(arg, range);
404 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000405 }
Lev Walkin775885e2004-08-22 12:47:03 +0000406 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000407 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000408 OUT("}\n");
409 OUT("\n");
410
411 asn1constraint_range_free(range);
412
Lev Walkin6938d042005-03-04 23:23:50 +0000413 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000414}
415
416static int
417emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin05363a72004-09-29 13:16:40 +0000418 asn1c_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000419 asn1p_expr_t *terminal;
Lev Walkince31cdb2005-02-15 03:37:42 +0000420 char *tname;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000421
Lev Walkine4d6ab82004-09-22 16:05:13 +0000422 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000423 if(terminal) {
424 OUT("/* The underlying type is %s */\n",
425 ASN_EXPR_TYPE2STR(terminal->expr_type));
426 } else {
427 terminal = arg->expr;
428 }
Lev Walkince31cdb2005-02-15 03:37:42 +0000429 tname = asn1c_type_name(arg, terminal, TNF_SAFE);
430 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000431
Lev Walkin634a3b82004-08-22 03:30:05 +0000432 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000433 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000434 OUT("const uint8_t *ch = st->buf;\n");
435 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000436 OUT("\n");
437 OUT("for(; ch < end; ch++) {\n");
438 INDENT(+1);
439 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000440 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000441 natural_stop = 0xffffffffUL;
442 break;
443 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000444 OUT("const uint8_t *ch = st->buf;\n");
445 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000446 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000447 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
448 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000449 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000450 OUT("uint32_t cv = (ch[0] << 24)\n");
451 OUT("\t\t| (ch[1] << 16)\n");
452 OUT("\t\t| (ch[2] << 8)\n");
453 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000454 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000455 natural_stop = 0xffffffffUL;
456 break;
457 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000458 OUT("const uint8_t *ch = st->buf;\n");
459 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000460 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000461 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
462 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000463 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000464 OUT("uint16_t cv = (ch[0] << 8)\n");
465 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000466 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000467 natural_stop = 0xffff;
468 break;
469 case ASN_BASIC_OCTET_STRING:
470 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000471 OUT("const uint8_t *ch = st->buf;\n");
472 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000473 OUT("\n");
474 OUT("for(; ch < end; ch++) {\n");
475 INDENT(+1);
476 OUT("uint8_t cv = *ch;\n");
477 natural_stop = 0xff;
478 break;
479 }
480
481 if(range) {
482 OUT("if(!(");
483 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
Lev Walkin775885e2004-08-22 12:47:03 +0000484 OUT(")) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000485 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000486 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000487 }
488
489 INDENT(-1);
490 OUT("}\n");
491
492 return 0;
493}
494
495static int
Lev Walkin05363a72004-09-29 13:16:40 +0000496emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1c_integer_t natural_start, asn1c_integer_t natural_stop) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000497 int ignore_left;
498 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000499 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000500 int i;
501
502 for(i = -1; i < range->el_count; i++) {
503 asn1cnst_range_t *r;
504 if(i == -1) {
505 if(range->el_count) continue;
506 r = range;
507 } else {
508 if(i) OUT(" || ");
509 r = range->elements[i];
510 }
511
512 if(r != range) OUT("(");
513
514 ignore_left = (r->left.type == ARE_MIN)
515 || (natural_start != -1
516 && r->left.value <= natural_start);
517 ignore_right = (r->right.type == ARE_MAX)
518 || (natural_stop != -1
519 && r->right.value >= natural_stop);
520 if(ignore_left && ignore_right) {
521 OUT("1 /* Constraint matches natural range of %s */",
522 varname);
523 continue;
524 }
525
526 if(ignore_left) {
Lev Walkin63b41262007-11-06 01:48:46 +0000527 OUT("%s <= ", varname);
528 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000529 } else if(ignore_right) {
Lev Walkin63b41262007-11-06 01:48:46 +0000530 OUT("%s >= ", varname);
531 OINT(r->left.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000532 } else if(r->left.value == r->right.value) {
Lev Walkin63b41262007-11-06 01:48:46 +0000533 OUT("%s == ", varname);
534 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000535 } else {
Lev Walkin63b41262007-11-06 01:48:46 +0000536 OUT("%s >= ", varname);
537 OINT(r->left.value);
538 OUT(" && ");
539 OUT("%s <= ", varname);
540 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000541 }
542 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000543 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000544 }
545
Lev Walkin59004fa2004-08-20 13:37:01 +0000546 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000547}
548
549static int
550emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
551
552 switch(etype) {
553 case ASN_BASIC_BIT_STRING:
554 OUT("if(st->size > 0) {\n");
555 OUT("\t/* Size in bits */\n");
Lev Walkindcf1e352006-09-08 19:34:22 +0000556 OUT("\tsize = 8 * st->size - (st->bits_unused & 0x07);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000557 OUT("} else {\n");
558 OUT("\tsize = 0;\n");
559 OUT("}\n");
560 break;
561 case ASN_STRING_UniversalString:
562 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
563 break;
564 case ASN_STRING_BMPString:
565 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
566 break;
567 case ASN_STRING_UTF8String:
Lev Walkin29c41682004-10-02 16:44:55 +0000568 OUT("size = UTF8String_length(st);\n");
569 OUT("if((ssize_t)size < 0) {\n");
Lev Walkin1eded352006-07-13 11:19:01 +0000570 OUT("\t_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin29c41682004-10-02 16:44:55 +0000571 OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
572 OUT("\t\ttd->name, __FILE__, __LINE__);\n");
573 OUT("\treturn -1;\n");
574 OUT("}\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000575 break;
576 case ASN_CONSTR_SET_OF:
577 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkinf1a51232005-07-04 02:01:03 +0000578 OUT("/* Determine the number of elements */\n");
579 OUT("size = _A_C%s_FROM_VOID(sptr)->count;\n",
580 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000581 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000582 case ASN_BASIC_OCTET_STRING:
583 OUT("size = st->size;\n");
584 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000585 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000586 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000587 OUT("size = st->size;\n");
588 break;
589 } else {
590 const char *type_name = ASN_EXPR_TYPE2STR(etype);
591 if(!type_name) type_name = arg->expr->Identifier;
592 WARNING("SizeConstraint is not defined for %s",
593 type_name);
594 OUT_NOINDENT("#warning SizeConstraint "
595 "is not defined for %s!\n", type_name);
596 OUT("size = st->size;\n");
597 }
598 return -1;
599 }
600
601 return 0;
602}
603
604static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000605emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000606
607 switch(etype) {
608 case ASN_BASIC_INTEGER:
609 case ASN_BASIC_ENUMERATED:
Lev Walkin8bb57a22007-12-03 13:41:36 +0000610 if(asn1c_type_fits_long(arg, arg->expr) == FL_FITS_UNSIGN) {
611 OUT("value = *(const unsigned long *)sptr;\n");
612 } else if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) {
Lev Walkine0b56e02005-02-25 12:10:27 +0000613 OUT("value = *(const long *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000614 } else {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000615 /*
616 * In some cases we can explore our knowledge of
617 * underlying INTEGER_t->buf format.
618 */
Lev Walkin6ea088f2004-09-07 06:31:15 +0000619 if(r_value->el_count == 0
620 && (
621 /* Speed-up common case: (0..MAX) */
622 (r_value->left.type == ARE_VALUE
623 && r_value->left.value == 0
624 && r_value->right.type == ARE_MAX)
625 ||
626 /* Speed-up common case: (MIN..-1) */
627 (r_value->left.type == ARE_MIN
628 && r_value->right.type == ARE_VALUE
629 && r_value->right.value == -1)
630 )) {
631 OUT("/* Check if the sign bit is present */\n");
632 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
633 break;
634 }
635
Lev Walkin8bb57a22007-12-03 13:41:36 +0000636 if(native_long_sign(r_value) >= 0) {
637 /* Special case for treating unsigned longs */
638 OUT("if(asn_INTEGER2ulong(st, &value)) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000639 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000640 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000641 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
642 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000643 OUT("return -1;\n");
644 INDENT(-1);
Lev Walkin8bb57a22007-12-03 13:41:36 +0000645 OUT("}\n");
646 } else {
647 OUT("if(asn_INTEGER2long(st, &value)) {\n");
648 INDENT(+1);
649 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
650 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
651 OUT("\ttd->name, __FILE__, __LINE__);\n");
652 OUT("return -1;\n");
653 INDENT(-1);
654 OUT("}\n");
655 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000656 }
657 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000658 case ASN_BASIC_REAL:
Lev Walkin2a744a72013-03-27 01:56:23 -0700659 if(arg->flags & A1C_USE_WIDE_TYPES) {
Lev Walkin05363a72004-09-29 13:16:40 +0000660 OUT("if(asn_REAL2double(st, &value)) {\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000661 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000662 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000663 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
664 OUT("\ttd->name, __FILE__, __LINE__);\n");
665 OUT("return -1;\n");
666 INDENT(-1);
667 OUT("}\n");
Lev Walkin2a744a72013-03-27 01:56:23 -0700668 } else {
669 OUT("value = *(const double *)sptr;\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000670 }
671 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000672 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000673 OUT("value = (*(const long *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000674 break;
675 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000676 WARNING("%s:%d: Value cannot be determined "
677 "for constraint check for %s",
Lev Walkinb85a8132005-08-18 13:38:19 +0000678 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000679 arg->expr->_lineno,
680 arg->expr->Identifier
681 );
682 OUT_NOINDENT(
683 "#error %s:%d: Value of %s cannot be determined\n",
Lev Walkinb85a8132005-08-18 13:38:19 +0000684 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000685 arg->expr->_lineno,
686 arg->expr->Identifier
687 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000688 break;
689 }
690
691 return 0;
692}
693
694static asn1p_expr_type_e
695_find_terminal_type(arg_t *arg) {
696 asn1p_expr_t *expr;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000697 expr = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000698 if(expr) return expr->expr_type;
699 return A1TC_INVALID;
700}
701
Lev Walkin8bb57a22007-12-03 13:41:36 +0000702static int
703native_long_sign(asn1cnst_range_t *r) {
704 if(r->left.type == ARE_VALUE
705 && r->left.value >= 0
706 && r->right.type == ARE_VALUE
Lev Walkin5b63acf2014-01-14 01:48:37 -0800707 && r->right.value > 2147483647
Lev Walkine5086e32014-02-10 11:00:51 -0800708 && r->right.value <= 4294967295UL) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000709 if(r->el_count == 0
710 && r->left.value == 0
711 && r->right.value == 4294967295UL)
712 return 0;
713 else
714 return 1;
715 } else {
716 return -1;
717 }
718}