blob: cf5416b0cbe937de0adab272c98986a25c5990ef [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 */
7#include <asn1fix_export.h> /* other exportable stuff from libasn1fix */
8
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);
11static int emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype);
12static int emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype);
13static asn1p_expr_type_e _find_terminal_type(arg_t *arg);
14static int emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1_integer_t natural_start, asn1_integer_t natural_stop);
15
16#define MKID(id) asn1c_make_identifier(0, (id), 0)
17
18static int global_compile_mark;
19
20int
21asn1c_emit_constraint_checking_code(arg_t *arg) {
22 asn1cnst_range_t *r_size;
23 asn1cnst_range_t *r_value;
24 asn1p_expr_t *expr = arg->expr;
25 asn1p_expr_type_e etype;
26 asn1p_constraint_t *ct;
27 int got_something = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +000028 int produce_st = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +000029
30 ct = expr->combined_constraints;
31 if(ct == NULL)
32 return 1; /* No additional constraints defined */
33
34 etype = _find_terminal_type(arg);
35
36 r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE, 0, 0);
37 r_size = asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE, 0, 0);
38 if(r_value) {
39 if(r_value->not_PER_visible
40 || r_value->extensible
41 || r_value->empty_constraint
42 || (r_value->left.type == ARE_MIN
43 && r_value->right.type == ARE_MAX)
44 || (etype == ASN_BASIC_BOOLEAN
45 && r_value->left.value == 0
46 && r_value->right.value == 1)
47 ) {
48 asn1constraint_range_free(r_value);
49 r_value = 0;
50 }
51 }
52 if(r_size) {
53 if(r_size->not_PER_visible
54 || r_size->extensible
55 || r_size->empty_constraint
56 || (r_size->left.value == 0 /* or .type == MIN */
57 && r_size->right.type == ARE_MAX)
58 ) {
59 asn1constraint_range_free(r_size);
60 r_size = 0;
61 }
62 }
63
Lev Walkin59004fa2004-08-20 13:37:01 +000064 /*
65 * Do we really need an "*st = sptr" pointer?
66 */
67 switch(etype) {
68 case ASN_BASIC_INTEGER:
69 case ASN_BASIC_ENUMERATED:
70 if(!(arg->flags & A1C_USE_NATIVE_INTEGERS))
71 produce_st = 1;
72 break;
73 case ASN_BASIC_OCTET_STRING:
74 produce_st = 1;
75 break;
76 default:
77 if(etype & ASN_STRING_MASK)
78 produce_st = 1;
79 break;
80 }
81 if(produce_st)
Lev Walkin84cd58e2004-08-19 13:29:46 +000082 OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier));
83
84 if(r_size || r_value) {
85 if(r_size) {
86 OUT("size_t size;\n");
87 }
88 if(r_value)
89 switch(etype) {
90 case ASN_BASIC_INTEGER:
91 case ASN_BASIC_ENUMERATED:
92 OUT("long value;\n");
93 break;
94 case ASN_BASIC_BOOLEAN:
95 OUT("int value;\n");
96 break;
97 default:
98 break;
99 }
100 }
101
102 OUT("\n");
103
104 /*
105 * Protection against null input.
106 */
107 OUT("if(!sptr) {\n");
108 INDENT(+1);
109 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
110 OUT("\t\"%%s: value not given\", td->name);\n");
111 OUT("return -1;\n");
112 INDENT(-1);
113 OUT("}\n");
114 OUT("\n");
115
116 if(r_value)
117 emit_value_determination_code(arg, etype);
118 if(r_size)
119 emit_size_determination_code(arg, etype);
120
Lev Walkin59004fa2004-08-20 13:37:01 +0000121 INDENT(-1);
122 REDIR(OT_CTABLES);
123 /* Emit FROM() tables */
124 asn1c_emit_constraint_tables(arg, r_size?1:0);
125 REDIR(OT_CODE);
126 INDENT(+1);
127
Lev Walkin84cd58e2004-08-19 13:29:46 +0000128 /*
129 * Here is an if() {} else {} constaint checking code.
130 */
131 OUT("\n");
132 OUT("if(");
133 INDENT(+1);
134 if(r_size) {
135 if(got_something++) { OUT("\n"); OUT(" && "); }
136 OUT("(");
137 emit_range_comparison_code(arg, r_size, "size", 0, -1);
138 OUT(")");
139 }
140 if(r_value) {
141 if(got_something++) { OUT("\n"); OUT(" && "); }
142 OUT("(");
143 if(etype == ASN_BASIC_BOOLEAN)
144 emit_range_comparison_code(arg, r_value,
145 "value", 0, 1);
146 else
147 emit_range_comparison_code(arg, r_value,
148 "value", -1, -1);
149 OUT(")");
150 }
151 if(ct->_compile_mark) {
152 if(got_something++) { OUT("\n"); OUT(" && "); }
153 OUT("check_permitted_alphabet_%d(sptr)",
154 ct->_compile_mark);
155 }
156 if(!got_something) {
157 OUT("1 /* No applicable constraints whatsoever */");
Lev Walkin59004fa2004-08-20 13:37:01 +0000158 OUT(") {\n");
159 INDENT(-1);
160 INDENTED(OUT("/* Nothing is here. See below */\n"));
161 OUT("}\n");
162 OUT("\n");
163 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000164 }
165 INDENT(-1);
166 OUT(") {\n");
167 INDENT(+1);
168 OUT("/* Constraint check succeeded */\n");
169 OUT("return 1;\n");
170 INDENT(-1);
171 OUT("} else {\n");
172 INDENT(+1);
173 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
174 OUT("\t\"%%s: constraint failed\", td->name);\n");
175 OUT("return -1;\n");
176 INDENT(-1);
177 OUT("}\n");
178
179 return 0;
180}
181
Lev Walkin59004fa2004-08-20 13:37:01 +0000182static int
183asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000184 asn1_integer_t range_start;
185 asn1_integer_t range_stop;
186 asn1p_expr_type_e etype;
187 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000188 asn1p_constraint_t *ct;
189 int utf8_full_alphabet_check = 0;
190 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000191 int table[256];
192 int use_table;
193
Lev Walkin59004fa2004-08-20 13:37:01 +0000194 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000195 if(!ct) return 0;
196
197 etype = _find_terminal_type(arg);
198
199 range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0, 0);
200 if(!range) return 0;
201
202 if(range->not_PER_visible
203 || range->extensible
204 || range->empty_constraint) {
205 asn1constraint_range_free(range);
206 return 0;
207 }
208
209 range_start = range->left.value;
210 range_stop = range->right.value;
211 assert(range->left.type == ARE_VALUE);
212 assert(range->right.type == ARE_VALUE);
213 assert(range_start <= range_stop);
214
215 range_start = 0; /* Force old behavior */
216
217 /*
218 * Check if we need a test table to check the alphabet.
219 */
220 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000221 if(range->el_count == 0) {
222 /*
223 * It's better to have a short if() check
224 * than waste 4k of table space
225 */
226 use_table = 0;
227 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000228 if((range_stop - range_start) > 255)
229 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000230 if(etype == ASN_STRING_UTF8String) {
231 if(range_stop >= 0x80)
232 use_table = 0;
233 else
234 max_table_size = 128;
235 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000236
237 if(!ct->_compile_mark)
238 ct->_compile_mark = ++global_compile_mark;
239
240 if(use_table) {
241 int i, n = 0;
242 int untl;
243 memset(table, 0, sizeof(table));
244 for(i = -1; i < range->el_count; i++) {
245 asn1cnst_range_t *r;
246 asn1_integer_t v;
247 if(i == -1) {
248 if(range->el_count) continue;
249 r = range;
250 } else {
251 r = range->elements[i];
252 }
253 for(v = r->left.value; v <= r->right.value; v++) {
254 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000255 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000256 table[v - range_start] = ++n;
257 }
258 }
259
Lev Walkin84cd58e2004-08-19 13:29:46 +0000260 untl = (range_stop - range_start) + 1;
261 untl += (untl % 16)?16 - (untl % 16):0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000262 OUT("static int permitted_alphabet_table_%d[%d] = {\n",
263 ct->_compile_mark, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000264 for(n = 0; n < untl; n++) {
265 OUT("%d,", table[n]?1:0);
266 if(!((n+1) % 16)) {
267 int c;
268 if(!n) {
269 OUT("\n");
270 continue;
271 }
272 OUT("\t/* ");
273 for(c = n - 15; c <= n; c++) {
274 if(table[c]) {
275 int a = c + range_start;
276 if(a > 0x20 && a < 0x80)
277 OUT("%c", a);
278 else
279 OUT(".");
280 } else {
281 OUT(" ");
282 }
283 }
284 OUT(" */");
285 OUT("\n");
286 }
287 }
288 OUT("};\n");
289 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000290 } else if(etype == ASN_STRING_UTF8String) {
291 /*
292 * UTF8String type is a special case in many respects.
293 */
294 assert(range_stop > 255); /* This one's unobvious */
295 if(got_size) {
296 /*
297 * Size has been already determined.
298 * The UTF8String length checker also checks
299 * for the syntax validity, so we don't have
300 * to repeat this process twice.
301 */
302 ct->_compile_mark = 0; /* Don't generate code */
303 asn1constraint_range_free(range);
304 return 0;
305 } else {
306 utf8_full_alphabet_check = 1;
307 }
308 } else {
309 /*
310 * This permitted alphabet check will be
311 * expressed using conditional statements
312 * instead of table lookups. Table would be
313 * to large or otherwise inappropriate (too sparse?).
314 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000315 }
316
317 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
318 ct->_compile_mark);
Lev Walkin59004fa2004-08-20 13:37:01 +0000319 INDENT(+1);
320 if(utf8_full_alphabet_check) {
321 OUT("if(UTF8String_length((UTF8String_t *)sptr, td->name, \n");
322 OUT("\tapp_errlog, app_key) == -1)\n");
323 OUT("\t\treturn 0; /* Alphabet (sic!) test failed. */\n");
324 OUT("\n");
325 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000326 if(use_table) {
327 OUT("int *table = permitted_alphabet_table_%d;\n",
328 ct->_compile_mark);
329 emit_alphabet_check_loop(arg, 0);
330 } else {
331 emit_alphabet_check_loop(arg, range);
332 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000333 }
334 OUT("return 1;\n");
335 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000336 OUT("}\n");
337 OUT("\n");
338
339 asn1constraint_range_free(range);
340
341 return 0;
342}
343
344static int
345emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
346 asn1p_expr_type_e etype;
347 asn1_integer_t natural_stop;
348
349 etype = _find_terminal_type(arg);
350
351 OUT("/* The underlying type is %s */\n",
352 ASN_EXPR_TYPE2STR(etype));
353 OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier));
354
355 switch(etype) {
356 case ASN_STRING_UTF8String:
357 OUT("uint8_t *ch = st->buf;\n");
358 OUT("uint8_t *end = ch + st->size;\n");
359 OUT("\n");
360 OUT("for(; ch < end; ch++) {\n");
361 INDENT(+1);
362 OUT("uint8_t cv = *ch;\n");
363 if(!range) OUT("if(cv >= 0x80) return 0;\n");
364 natural_stop = 0xffffffffUL;
365 break;
366 case ASN_STRING_UniversalString:
367 OUT("uint32_t *ch = st->buf;\n");
368 OUT("uint32_t *end = ch + st->size;\n");
369 OUT("\n");
370 OUT("if(st->size % 4) return 0; /* (size%4)! */\n");
371 OUT("for(; ch < end; ch++) {\n");
372 INDENT(+1);
373 OUT("uint32_t cv = (((uint8_t *)ch)[0] << 24)\n");
374 OUT("\t\t| (((uint8_t *)ch)[1] << 16)\n");
375 OUT("\t\t| (((uint8_t *)ch)[2] << 8)\n");
376 OUT("\t\t| ((uint8_t *)ch)[3]\n");
377 if(!range) OUT("if(cv > 255) return 0;\n");
378 natural_stop = 0xffffffffUL;
379 break;
380 case ASN_STRING_BMPString:
381 OUT("uint16_t *ch = st->buf;\n");
382 OUT("uint16_t *end = ch + st->size;\n");
383 OUT("\n");
384 OUT("if(st->size % 2) return 0; /* (size%2)! */\n");
385 OUT("for(; ch < end; ch++) {\n");
386 INDENT(+1);
387 OUT("uint16_t cv = (((uint8_t *)ch)[0] << 8)\n");
388 OUT("\t\t| ((uint8_t *)ch)[1];\n");
389 if(!range) OUT("if(cv > 255) return 0;\n");
390 natural_stop = 0xffff;
391 break;
392 case ASN_BASIC_OCTET_STRING:
393 default:
394 OUT("uint8_t *ch = st->buf;\n");
395 OUT("uint8_t *end = ch + st->size;\n");
396 OUT("\n");
397 OUT("for(; ch < end; ch++) {\n");
398 INDENT(+1);
399 OUT("uint8_t cv = *ch;\n");
400 natural_stop = 0xff;
401 break;
402 }
403
404 if(range) {
405 OUT("if(!(");
406 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
407 OUT(")) return 0;\n");
408 } else {
409 OUT("if(!table[cv]) return 0;\n");
410 }
411
412 INDENT(-1);
413 OUT("}\n");
414
415 return 0;
416}
417
418static int
419emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1_integer_t natural_start, asn1_integer_t natural_stop) {
420 int ignore_left;
421 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000422 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000423 int i;
424
425 for(i = -1; i < range->el_count; i++) {
426 asn1cnst_range_t *r;
427 if(i == -1) {
428 if(range->el_count) continue;
429 r = range;
430 } else {
431 if(i) OUT(" || ");
432 r = range->elements[i];
433 }
434
435 if(r != range) OUT("(");
436
437 ignore_left = (r->left.type == ARE_MIN)
438 || (natural_start != -1
439 && r->left.value <= natural_start);
440 ignore_right = (r->right.type == ARE_MAX)
441 || (natural_stop != -1
442 && r->right.value >= natural_stop);
443 if(ignore_left && ignore_right) {
444 OUT("1 /* Constraint matches natural range of %s */",
445 varname);
446 continue;
447 }
448
449 if(ignore_left) {
450 OUT("%s <= %lld", varname,
451 (long long)r->right.value);
452 } else if(ignore_right) {
453 OUT("%s >= %lld", varname,
454 (long long)r->left.value);
455 } else if(r->left.value == r->right.value) {
456 OUT("%s == %lld", varname,
457 (long long)r->right.value);
458 } else {
459 OUT("%s >= %lld && %s <= %lld",
460 varname,
461 (long long)r->left.value,
462 varname,
463 (long long)r->right.value);
464 }
465 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000466 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000467 }
468
Lev Walkin59004fa2004-08-20 13:37:01 +0000469 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000470}
471
472static int
473emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
474
475 switch(etype) {
476 case ASN_BASIC_BIT_STRING:
477 OUT("if(st->size > 0) {\n");
478 OUT("\t/* Size in bits */\n");
479 OUT("\tsize = (st->size - 1) - (st->buf[0] & 0x7);\n");
480 OUT("} else {\n");
481 OUT("\tsize = 0;\n");
482 OUT("}\n");
483 break;
484 case ASN_STRING_UniversalString:
485 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
486 break;
487 case ASN_STRING_BMPString:
488 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
489 break;
490 case ASN_STRING_UTF8String:
491 OUT("size = UTF8String_length(st, td->name, app_errlog, app_key);\n");
492 OUT("if(size == (size_t)-1) return -1;\n");
493 break;
494 case ASN_CONSTR_SET_OF:
495 case ASN_CONSTR_SEQUENCE_OF:
496 OUT("{ /* Determine the number of elements */\n");
497 INDENT(+1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000498 OUT("const A_%s_OF(void) *list;\n",
Lev Walkin84cd58e2004-08-19 13:29:46 +0000499 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin59004fa2004-08-20 13:37:01 +0000500 OUT("(const void *)list = sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000501 OUT("size = list->count;\n");
502 INDENT(-1);
503 OUT("}\n");
504 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000505 case ASN_BASIC_OCTET_STRING:
506 OUT("size = st->size;\n");
507 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000508 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000509 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000510 OUT("size = st->size;\n");
511 break;
512 } else {
513 const char *type_name = ASN_EXPR_TYPE2STR(etype);
514 if(!type_name) type_name = arg->expr->Identifier;
515 WARNING("SizeConstraint is not defined for %s",
516 type_name);
517 OUT_NOINDENT("#warning SizeConstraint "
518 "is not defined for %s!\n", type_name);
519 OUT("size = st->size;\n");
520 }
521 return -1;
522 }
523
524 return 0;
525}
526
527static int
528emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
529
530 switch(etype) {
531 case ASN_BASIC_INTEGER:
532 case ASN_BASIC_ENUMERATED:
533 if(arg->flags & A1C_USE_NATIVE_INTEGERS) {
Lev Walkin59004fa2004-08-20 13:37:01 +0000534 OUT("value = *(int *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000535 } else {
536 OUT("if(asn1_INTEGER2long(st, &value)) {\n");
537 INDENT(+1);
538 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
539 OUT("\t\"%%s: value too large\", td->name);\n");
540 OUT("return -1;\n");
541 INDENT(-1);
542 OUT("}\n");
543 }
544 break;
545 case ASN_BASIC_BOOLEAN:
Lev Walkin59004fa2004-08-20 13:37:01 +0000546 OUT("value = (*(int *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000547 break;
548 default:
549 WARNING("Value cannot be determined "
550 "for constraint check for %s at line %d\n",
551 arg->expr->Identifier, arg->expr->_lineno);
552 OUT("#error Value cannot be determined for %s at %d\n",
553 arg->expr->Identifier, arg->expr->_lineno);
554 break;
555 }
556
557 return 0;
558}
559
560static asn1p_expr_type_e
561_find_terminal_type(arg_t *arg) {
562 asn1p_expr_t *expr;
563 expr = asn1f_find_terminal_type_ex(arg->asn, arg->mod, arg->expr, NULL);
564 if(expr) return expr->expr_type;
565 return A1TC_INVALID;
566}
567