blob: 1e2efa45f662ab8537d1fa8736ecad5c22bf0a31 [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 Walkin84cd58e2004-08-19 13:29:46 +000015
Lev Walkin84cd58e2004-08-19 13:29:46 +000016int
17asn1c_emit_constraint_checking_code(arg_t *arg) {
18 asn1cnst_range_t *r_size;
19 asn1cnst_range_t *r_value;
20 asn1p_expr_t *expr = arg->expr;
21 asn1p_expr_type_e etype;
22 asn1p_constraint_t *ct;
23 int got_something = 0;
Lev Walkin6938d042005-03-04 23:23:50 +000024 int alphabet_table_compiled;
Lev Walkin59004fa2004-08-20 13:37:01 +000025 int produce_st = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +000026
27 ct = expr->combined_constraints;
28 if(ct == NULL)
29 return 1; /* No additional constraints defined */
30
31 etype = _find_terminal_type(arg);
32
Lev Walkinbe717ec2004-08-25 02:03:59 +000033 r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE,0,0,0);
Lev Walkin729eb862006-09-21 01:50:13 +000034 r_size =asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +000035 if(r_value) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000036 if(r_value->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000037 || r_value->empty_constraint
38 || (r_value->left.type == ARE_MIN
39 && r_value->right.type == ARE_MAX)
40 || (etype == ASN_BASIC_BOOLEAN
41 && r_value->left.value == 0
42 && r_value->right.value == 1)
43 ) {
44 asn1constraint_range_free(r_value);
45 r_value = 0;
46 }
47 }
48 if(r_size) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000049 if(r_size->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000050 || r_size->empty_constraint
51 || (r_size->left.value == 0 /* or .type == MIN */
52 && r_size->right.type == ARE_MAX)
53 ) {
54 asn1constraint_range_free(r_size);
55 r_size = 0;
56 }
57 }
58
Lev Walkin59004fa2004-08-20 13:37:01 +000059 /*
60 * Do we really need an "*st = sptr" pointer?
61 */
62 switch(etype) {
63 case ASN_BASIC_INTEGER:
64 case ASN_BASIC_ENUMERATED:
Lev Walkin082cadc2005-08-14 02:18:27 +000065 if(asn1c_type_fits_long(arg, arg->expr) == FL_NOTFIT)
66 produce_st = 1;
67 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +000068 case ASN_BASIC_REAL:
69 if(!(arg->flags & A1C_USE_NATIVE_TYPES))
Lev Walkin59004fa2004-08-20 13:37:01 +000070 produce_st = 1;
71 break;
Lev Walkin02b137d2004-08-21 07:34:58 +000072 case ASN_BASIC_BIT_STRING:
Lev Walkin59004fa2004-08-20 13:37:01 +000073 case ASN_BASIC_OCTET_STRING:
74 produce_st = 1;
Lev Walkin3a4689a2006-11-24 11:20:27 +000075 break;
Lev Walkin59004fa2004-08-20 13:37:01 +000076 default:
77 if(etype & ASN_STRING_MASK)
78 produce_st = 1;
79 break;
80 }
Lev Walkince31cdb2005-02-15 03:37:42 +000081 if(produce_st) {
82 char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
83 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
84 }
Lev Walkin84cd58e2004-08-19 13:29:46 +000085
86 if(r_size || r_value) {
87 if(r_size) {
88 OUT("size_t size;\n");
89 }
90 if(r_value)
91 switch(etype) {
92 case ASN_BASIC_INTEGER:
93 case ASN_BASIC_ENUMERATED:
94 OUT("long value;\n");
95 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +000096 case ASN_BASIC_REAL:
97 OUT("double value;\n");
98 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +000099 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000100 OUT("BOOLEAN_t value;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000101 break;
102 default:
103 break;
104 }
105 }
106
107 OUT("\n");
108
109 /*
110 * Protection against null input.
111 */
112 OUT("if(!sptr) {\n");
113 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000114 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000115 OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
116 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000117 OUT("return -1;\n");
118 INDENT(-1);
119 OUT("}\n");
120 OUT("\n");
121
122 if(r_value)
Lev Walkin6ea088f2004-09-07 06:31:15 +0000123 emit_value_determination_code(arg, etype, r_value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000124 if(r_size)
125 emit_size_determination_code(arg, etype);
126
Lev Walkin59004fa2004-08-20 13:37:01 +0000127 INDENT(-1);
128 REDIR(OT_CTABLES);
129 /* Emit FROM() tables */
Lev Walkin6938d042005-03-04 23:23:50 +0000130 alphabet_table_compiled =
131 (asn1c_emit_constraint_tables(arg, r_size?1:0) == 1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000132 REDIR(OT_CODE);
133 INDENT(+1);
134
Lev Walkin84cd58e2004-08-19 13:29:46 +0000135 /*
Lev Walkin729eb862006-09-21 01:50:13 +0000136 * Here is an if() {} else {} consrtaint checking code.
Lev Walkin84cd58e2004-08-19 13:29:46 +0000137 */
138 OUT("\n");
139 OUT("if(");
140 INDENT(+1);
141 if(r_size) {
142 if(got_something++) { OUT("\n"); OUT(" && "); }
143 OUT("(");
144 emit_range_comparison_code(arg, r_size, "size", 0, -1);
145 OUT(")");
146 }
147 if(r_value) {
148 if(got_something++) { OUT("\n"); OUT(" && "); }
149 OUT("(");
150 if(etype == ASN_BASIC_BOOLEAN)
151 emit_range_comparison_code(arg, r_value,
152 "value", 0, 1);
153 else
154 emit_range_comparison_code(arg, r_value,
155 "value", -1, -1);
156 OUT(")");
157 }
Lev Walkin6938d042005-03-04 23:23:50 +0000158 if(alphabet_table_compiled) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000159 if(got_something++) { OUT("\n"); OUT(" && "); }
Lev Walkin6938d042005-03-04 23:23:50 +0000160 OUT("!check_permitted_alphabet_%d(%s)",
161 arg->expr->_type_unique_index,
162 produce_st ? "st" : "sptr");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000163 }
164 if(!got_something) {
165 OUT("1 /* No applicable constraints whatsoever */");
Lev Walkin59004fa2004-08-20 13:37:01 +0000166 OUT(") {\n");
167 INDENT(-1);
168 INDENTED(OUT("/* Nothing is here. See below */\n"));
169 OUT("}\n");
170 OUT("\n");
171 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000172 }
173 INDENT(-1);
174 OUT(") {\n");
175 INDENT(+1);
Lev Walkin7ef83a42005-03-29 19:04:24 +0000176 switch(etype) {
177 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkin7ef83a42005-03-29 19:04:24 +0000178 case ASN_CONSTR_SET_OF:
179 OUT("/* Perform validation of the inner elements */\n");
Lev Walkin1eded352006-07-13 11:19:01 +0000180 OUT("return td->check_constraints(td, sptr, ctfailcb, app_key);\n");
Lev Walkin7ef83a42005-03-29 19:04:24 +0000181 break;
182 default:
183 OUT("/* Constraint check succeeded */\n");
184 OUT("return 0;\n");
185 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000186 INDENT(-1);
187 OUT("} else {\n");
188 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000189 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000190 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
191 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000192 OUT("return -1;\n");
193 INDENT(-1);
194 OUT("}\n");
195
196 return 0;
197}
198
Lev Walkin59004fa2004-08-20 13:37:01 +0000199static int
200asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin05363a72004-09-29 13:16:40 +0000201 asn1c_integer_t range_start;
202 asn1c_integer_t range_stop;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000203 asn1p_expr_type_e etype;
204 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000205 asn1p_constraint_t *ct;
206 int utf8_full_alphabet_check = 0;
207 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000208 int table[256];
209 int use_table;
210
Lev Walkin59004fa2004-08-20 13:37:01 +0000211 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000212 if(!ct) return 0;
213
214 etype = _find_terminal_type(arg);
215
Lev Walkinbe717ec2004-08-25 02:03:59 +0000216 range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000217 if(!range) return 0;
218
Lev Walkinbe717ec2004-08-25 02:03:59 +0000219 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000220 || range->empty_constraint) {
221 asn1constraint_range_free(range);
222 return 0;
223 }
224
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000225 if(range->left.type == ARE_MIN
226 && range->right.type == ARE_MAX) {
227 /*
228 * The permitted alphabet constraint checker code guarantees
229 * that either both bounds (left/right) are present, or
230 * they're absent simultaneously. Thus, this assertion
231 * legitimately holds true.
232 */
233 assert(range->el_count == 0);
234 /* The full range is specified. Ignore it. */
235 return 0;
236 }
237
Lev Walkin84cd58e2004-08-19 13:29:46 +0000238 range_start = range->left.value;
239 range_stop = range->right.value;
240 assert(range->left.type == ARE_VALUE);
241 assert(range->right.type == ARE_VALUE);
242 assert(range_start <= range_stop);
243
244 range_start = 0; /* Force old behavior */
245
246 /*
247 * Check if we need a test table to check the alphabet.
248 */
249 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000250 if(range->el_count == 0) {
251 /*
252 * It's better to have a short if() check
Lev Walkin729eb862006-09-21 01:50:13 +0000253 * than waste 1k of table space
Lev Walkin59004fa2004-08-20 13:37:01 +0000254 */
255 use_table = 0;
256 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000257 if((range_stop - range_start) > 255)
258 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000259 if(etype == ASN_STRING_UTF8String) {
260 if(range_stop >= 0x80)
261 use_table = 0;
262 else
263 max_table_size = 128;
264 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000265
Lev Walkin84cd58e2004-08-19 13:29:46 +0000266 if(use_table) {
Lev Walkin729eb862006-09-21 01:50:13 +0000267 int cardinal = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000268 int i, n = 0;
269 int untl;
270 memset(table, 0, sizeof(table));
271 for(i = -1; i < range->el_count; i++) {
272 asn1cnst_range_t *r;
Lev Walkin05363a72004-09-29 13:16:40 +0000273 asn1c_integer_t v;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000274 if(i == -1) {
275 if(range->el_count) continue;
276 r = range;
277 } else {
278 r = range->elements[i];
279 }
280 for(v = r->left.value; v <= r->right.value; v++) {
281 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000282 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000283 table[v - range_start] = ++n;
284 }
285 }
286
Lev Walkin84cd58e2004-08-19 13:29:46 +0000287 untl = (range_stop - range_start) + 1;
288 untl += (untl % 16)?16 - (untl % 16):0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000289 OUT("static int permitted_alphabet_table_%d[%d] = {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000290 arg->expr->_type_unique_index, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000291 for(n = 0; n < untl; n++) {
Lev Walkin729eb862006-09-21 01:50:13 +0000292 cardinal += table[n] ? 1 : 0;
293 OUT("%2d,", table[n]);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000294 if(!((n+1) % 16)) {
295 int c;
Lev Walkin729eb862006-09-21 01:50:13 +0000296 if(!n || (n-15) + range_start >= 0x80) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000297 OUT("\n");
298 continue;
299 }
300 OUT("\t/* ");
301 for(c = n - 15; c <= n; c++) {
302 if(table[c]) {
303 int a = c + range_start;
304 if(a > 0x20 && a < 0x80)
305 OUT("%c", a);
306 else
307 OUT(".");
308 } else {
309 OUT(" ");
310 }
311 }
312 OUT(" */");
313 OUT("\n");
314 }
315 }
316 OUT("};\n");
Lev Walkin729eb862006-09-21 01:50:13 +0000317
Lev Walkin725883b2006-10-09 12:07:58 +0000318 if((arg->flags & A1C_GEN_PER)
319 && (etype & ASN_STRING_KM_MASK)) {
Lev Walkin729eb862006-09-21 01:50:13 +0000320 int c;
321 OUT("static int permitted_alphabet_code2value_%d[%d] = {\n",
322 arg->expr->_type_unique_index, cardinal);
323 for(n = c = 0; c < max_table_size; c++) {
324 if(table[c]) {
325 OUT("%d,", c);
326 if(!((++n) % 16)) OUT("\n");
327 }
328 }
329 OUT("};\n");
330 OUT("\n");
Lev Walkin725883b2006-10-09 12:07:58 +0000331 DEBUG("code2value map gen for %s", arg->expr->Identifier);
332 arg->expr->_mark |= TM_PERFROMCT;
Lev Walkin729eb862006-09-21 01:50:13 +0000333 }
334
Lev Walkin84cd58e2004-08-19 13:29:46 +0000335 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000336 } else if(etype == ASN_STRING_UTF8String) {
337 /*
338 * UTF8String type is a special case in many respects.
339 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000340 if(got_size) {
341 /*
342 * Size has been already determined.
343 * The UTF8String length checker also checks
344 * for the syntax validity, so we don't have
345 * to repeat this process twice.
346 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000347 asn1constraint_range_free(range);
348 return 0;
349 } else {
350 utf8_full_alphabet_check = 1;
351 }
352 } else {
353 /*
354 * This permitted alphabet check will be
355 * expressed using conditional statements
356 * instead of table lookups. Table would be
357 * to large or otherwise inappropriate (too sparse?).
358 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000359 }
360
361 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000362 arg->expr->_type_unique_index);
Lev Walkin59004fa2004-08-20 13:37:01 +0000363 INDENT(+1);
364 if(utf8_full_alphabet_check) {
Lev Walkin29c41682004-10-02 16:44:55 +0000365 OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
366 OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000367 OUT("\n");
368 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000369 if(use_table) {
370 OUT("int *table = permitted_alphabet_table_%d;\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000371 arg->expr->_type_unique_index);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000372 emit_alphabet_check_loop(arg, 0);
373 } else {
374 emit_alphabet_check_loop(arg, range);
375 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000376 }
Lev Walkin775885e2004-08-22 12:47:03 +0000377 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000378 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000379 OUT("}\n");
380 OUT("\n");
381
382 asn1constraint_range_free(range);
383
Lev Walkin6938d042005-03-04 23:23:50 +0000384 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000385}
386
387static int
388emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin05363a72004-09-29 13:16:40 +0000389 asn1c_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000390 asn1p_expr_t *terminal;
Lev Walkince31cdb2005-02-15 03:37:42 +0000391 char *tname;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000392
Lev Walkine4d6ab82004-09-22 16:05:13 +0000393 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000394 if(terminal) {
395 OUT("/* The underlying type is %s */\n",
396 ASN_EXPR_TYPE2STR(terminal->expr_type));
397 } else {
398 terminal = arg->expr;
399 }
Lev Walkince31cdb2005-02-15 03:37:42 +0000400 tname = asn1c_type_name(arg, terminal, TNF_SAFE);
401 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000402
Lev Walkin634a3b82004-08-22 03:30:05 +0000403 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000404 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000405 OUT("const uint8_t *ch = st->buf;\n");
406 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000407 OUT("\n");
408 OUT("for(; ch < end; ch++) {\n");
409 INDENT(+1);
410 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000411 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000412 natural_stop = 0xffffffffUL;
413 break;
414 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000415 OUT("const uint8_t *ch = st->buf;\n");
416 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000417 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000418 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
419 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000420 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000421 OUT("uint32_t cv = (ch[0] << 24)\n");
422 OUT("\t\t| (ch[1] << 16)\n");
423 OUT("\t\t| (ch[2] << 8)\n");
424 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000425 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000426 natural_stop = 0xffffffffUL;
427 break;
428 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000429 OUT("const uint8_t *ch = st->buf;\n");
430 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000431 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000432 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
433 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000434 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000435 OUT("uint16_t cv = (ch[0] << 8)\n");
436 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000437 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000438 natural_stop = 0xffff;
439 break;
440 case ASN_BASIC_OCTET_STRING:
441 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000442 OUT("const uint8_t *ch = st->buf;\n");
443 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000444 OUT("\n");
445 OUT("for(; ch < end; ch++) {\n");
446 INDENT(+1);
447 OUT("uint8_t cv = *ch;\n");
448 natural_stop = 0xff;
449 break;
450 }
451
452 if(range) {
453 OUT("if(!(");
454 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
Lev Walkin775885e2004-08-22 12:47:03 +0000455 OUT(")) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000456 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000457 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000458 }
459
460 INDENT(-1);
461 OUT("}\n");
462
463 return 0;
464}
465
466static int
Lev Walkin05363a72004-09-29 13:16:40 +0000467emit_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 +0000468 int ignore_left;
469 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000470 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000471 int i;
472
473 for(i = -1; i < range->el_count; i++) {
474 asn1cnst_range_t *r;
475 if(i == -1) {
476 if(range->el_count) continue;
477 r = range;
478 } else {
479 if(i) OUT(" || ");
480 r = range->elements[i];
481 }
482
483 if(r != range) OUT("(");
484
485 ignore_left = (r->left.type == ARE_MIN)
486 || (natural_start != -1
487 && r->left.value <= natural_start);
488 ignore_right = (r->right.type == ARE_MAX)
489 || (natural_stop != -1
490 && r->right.value >= natural_stop);
491 if(ignore_left && ignore_right) {
492 OUT("1 /* Constraint matches natural range of %s */",
493 varname);
494 continue;
495 }
496
497 if(ignore_left) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000498 OUT("%s <= %" PRIdASN, varname,
499 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000500 } else if(ignore_right) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000501 OUT("%s >= %" PRIdASN, varname,
502 r->left.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000503 } else if(r->left.value == r->right.value) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000504 OUT("%s == %" PRIdASN, varname,
505 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000506 } else {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000507 OUT("%s >= %" PRIdASN " && %s <= %" PRIdASN,
Lev Walkin84cd58e2004-08-19 13:29:46 +0000508 varname,
Lev Walkin33c16ba2004-09-24 21:01:43 +0000509 r->left.value,
Lev Walkin84cd58e2004-08-19 13:29:46 +0000510 varname,
Lev Walkin33c16ba2004-09-24 21:01:43 +0000511 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000512 }
513 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000514 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000515 }
516
Lev Walkin59004fa2004-08-20 13:37:01 +0000517 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000518}
519
520static int
521emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
522
523 switch(etype) {
524 case ASN_BASIC_BIT_STRING:
525 OUT("if(st->size > 0) {\n");
526 OUT("\t/* Size in bits */\n");
Lev Walkindcf1e352006-09-08 19:34:22 +0000527 OUT("\tsize = 8 * st->size - (st->bits_unused & 0x07);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000528 OUT("} else {\n");
529 OUT("\tsize = 0;\n");
530 OUT("}\n");
531 break;
532 case ASN_STRING_UniversalString:
533 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
534 break;
535 case ASN_STRING_BMPString:
536 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
537 break;
538 case ASN_STRING_UTF8String:
Lev Walkin29c41682004-10-02 16:44:55 +0000539 OUT("size = UTF8String_length(st);\n");
540 OUT("if((ssize_t)size < 0) {\n");
Lev Walkin1eded352006-07-13 11:19:01 +0000541 OUT("\t_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin29c41682004-10-02 16:44:55 +0000542 OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
543 OUT("\t\ttd->name, __FILE__, __LINE__);\n");
544 OUT("\treturn -1;\n");
545 OUT("}\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000546 break;
547 case ASN_CONSTR_SET_OF:
548 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkinf1a51232005-07-04 02:01:03 +0000549 OUT("/* Determine the number of elements */\n");
550 OUT("size = _A_C%s_FROM_VOID(sptr)->count;\n",
551 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000552 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000553 case ASN_BASIC_OCTET_STRING:
554 OUT("size = st->size;\n");
555 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000556 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000557 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000558 OUT("size = st->size;\n");
559 break;
560 } else {
561 const char *type_name = ASN_EXPR_TYPE2STR(etype);
562 if(!type_name) type_name = arg->expr->Identifier;
563 WARNING("SizeConstraint is not defined for %s",
564 type_name);
565 OUT_NOINDENT("#warning SizeConstraint "
566 "is not defined for %s!\n", type_name);
567 OUT("size = st->size;\n");
568 }
569 return -1;
570 }
571
572 return 0;
573}
574
575static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000576emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000577
578 switch(etype) {
579 case ASN_BASIC_INTEGER:
580 case ASN_BASIC_ENUMERATED:
Lev Walkin082cadc2005-08-14 02:18:27 +0000581 if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) {
Lev Walkine0b56e02005-02-25 12:10:27 +0000582 OUT("value = *(const long *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000583 } else {
Lev Walkin6ea088f2004-09-07 06:31:15 +0000584 if(r_value->el_count == 0
585 && (
586 /* Speed-up common case: (0..MAX) */
587 (r_value->left.type == ARE_VALUE
588 && r_value->left.value == 0
589 && r_value->right.type == ARE_MAX)
590 ||
591 /* Speed-up common case: (MIN..-1) */
592 (r_value->left.type == ARE_MIN
593 && r_value->right.type == ARE_VALUE
594 && r_value->right.value == -1)
595 )) {
596 OUT("/* Check if the sign bit is present */\n");
597 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
598 break;
599 }
600
Lev Walkin05363a72004-09-29 13:16:40 +0000601 OUT("if(asn_INTEGER2long(st, &value)) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000602 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000603 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000604 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
605 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000606 OUT("return -1;\n");
607 INDENT(-1);
608 OUT("}\n");
609 }
610 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000611 case ASN_BASIC_REAL:
612 if(arg->flags & A1C_USE_NATIVE_TYPES) {
613 OUT("value = *(const double *)sptr;\n");
614 } else {
Lev Walkin05363a72004-09-29 13:16:40 +0000615 OUT("if(asn_REAL2double(st, &value)) {\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000616 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000617 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000618 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
619 OUT("\ttd->name, __FILE__, __LINE__);\n");
620 OUT("return -1;\n");
621 INDENT(-1);
622 OUT("}\n");
623 }
624 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000625 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000626 OUT("value = (*(const long *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000627 break;
628 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000629 WARNING("%s:%d: Value cannot be determined "
630 "for constraint check for %s",
Lev Walkinb85a8132005-08-18 13:38:19 +0000631 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000632 arg->expr->_lineno,
633 arg->expr->Identifier
634 );
635 OUT_NOINDENT(
636 "#error %s:%d: Value of %s cannot be determined\n",
Lev Walkinb85a8132005-08-18 13:38:19 +0000637 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000638 arg->expr->_lineno,
639 arg->expr->Identifier
640 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000641 break;
642 }
643
644 return 0;
645}
646
647static asn1p_expr_type_e
648_find_terminal_type(arg_t *arg) {
649 asn1p_expr_t *expr;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000650 expr = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000651 if(expr) return expr->expr_type;
652 return A1TC_INVALID;
653}
654