blob: 2b1420e81fcf7af3a4b671dfd015b8b879060438 [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
Lev Walkin84cd58e2004-08-19 13:29:46 +000017int
18asn1c_emit_constraint_checking_code(arg_t *arg) {
19 asn1cnst_range_t *r_size;
20 asn1cnst_range_t *r_value;
21 asn1p_expr_t *expr = arg->expr;
22 asn1p_expr_type_e etype;
23 asn1p_constraint_t *ct;
24 int got_something = 0;
Lev Walkin6938d042005-03-04 23:23:50 +000025 int alphabet_table_compiled;
Lev Walkin59004fa2004-08-20 13:37:01 +000026 int produce_st = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +000027
28 ct = expr->combined_constraints;
29 if(ct == NULL)
30 return 1; /* No additional constraints defined */
31
32 etype = _find_terminal_type(arg);
33
Lev Walkinbe717ec2004-08-25 02:03:59 +000034 r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE,0,0,0);
Lev Walkin729eb862006-09-21 01:50:13 +000035 r_size =asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +000036 if(r_value) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000037 if(r_value->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000038 || r_value->empty_constraint
39 || (r_value->left.type == ARE_MIN
40 && r_value->right.type == ARE_MAX)
41 || (etype == ASN_BASIC_BOOLEAN
42 && r_value->left.value == 0
43 && r_value->right.value == 1)
44 ) {
45 asn1constraint_range_free(r_value);
46 r_value = 0;
47 }
48 }
49 if(r_size) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000050 if(r_size->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000051 || r_size->empty_constraint
52 || (r_size->left.value == 0 /* or .type == MIN */
53 && r_size->right.type == ARE_MAX)
54 ) {
55 asn1constraint_range_free(r_size);
56 r_size = 0;
57 }
58 }
59
Lev Walkin59004fa2004-08-20 13:37:01 +000060 /*
61 * Do we really need an "*st = sptr" pointer?
62 */
63 switch(etype) {
64 case ASN_BASIC_INTEGER:
65 case ASN_BASIC_ENUMERATED:
Lev Walkin082cadc2005-08-14 02:18:27 +000066 if(asn1c_type_fits_long(arg, arg->expr) == FL_NOTFIT)
67 produce_st = 1;
68 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +000069 case ASN_BASIC_REAL:
70 if(!(arg->flags & A1C_USE_NATIVE_TYPES))
Lev Walkin59004fa2004-08-20 13:37:01 +000071 produce_st = 1;
72 break;
Lev Walkin02b137d2004-08-21 07:34:58 +000073 case ASN_BASIC_BIT_STRING:
Lev Walkin59004fa2004-08-20 13:37:01 +000074 case ASN_BASIC_OCTET_STRING:
75 produce_st = 1;
Lev Walkin3a4689a2006-11-24 11:20:27 +000076 break;
Lev Walkin59004fa2004-08-20 13:37:01 +000077 default:
78 if(etype & ASN_STRING_MASK)
79 produce_st = 1;
80 break;
81 }
Lev Walkince31cdb2005-02-15 03:37:42 +000082 if(produce_st) {
83 char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
84 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
85 }
Lev Walkin84cd58e2004-08-19 13:29:46 +000086
87 if(r_size || r_value) {
88 if(r_size) {
89 OUT("size_t size;\n");
90 }
91 if(r_value)
92 switch(etype) {
93 case ASN_BASIC_INTEGER:
94 case ASN_BASIC_ENUMERATED:
Lev Walkin8bb57a22007-12-03 13:41:36 +000095 if(native_long_sign(r_value) >= 0) {
96 OUT("unsigned long value;\n");
97 } else {
98 OUT("long value;\n");
99 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000100 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000101 case ASN_BASIC_REAL:
102 OUT("double value;\n");
103 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000104 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000105 OUT("BOOLEAN_t value;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000106 break;
107 default:
108 break;
109 }
110 }
111
112 OUT("\n");
113
114 /*
115 * Protection against null input.
116 */
117 OUT("if(!sptr) {\n");
118 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000119 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000120 OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
121 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000122 OUT("return -1;\n");
123 INDENT(-1);
124 OUT("}\n");
125 OUT("\n");
126
127 if(r_value)
Lev Walkin6ea088f2004-09-07 06:31:15 +0000128 emit_value_determination_code(arg, etype, r_value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000129 if(r_size)
130 emit_size_determination_code(arg, etype);
131
Lev Walkin59004fa2004-08-20 13:37:01 +0000132 INDENT(-1);
133 REDIR(OT_CTABLES);
134 /* Emit FROM() tables */
Lev Walkin6938d042005-03-04 23:23:50 +0000135 alphabet_table_compiled =
136 (asn1c_emit_constraint_tables(arg, r_size?1:0) == 1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000137 REDIR(OT_CODE);
138 INDENT(+1);
139
Lev Walkin84cd58e2004-08-19 13:29:46 +0000140 /*
Lev Walkin8bb57a22007-12-03 13:41:36 +0000141 * Optimization for unsigned longs.
142 */
143 if(!r_size && r_value
144 && (etype == ASN_BASIC_INTEGER
145 || etype == ASN_BASIC_ENUMERATED)
146 && native_long_sign(r_value) == 0) {
147 OUT("\n");
148 OUT("/* Constraint check succeeded */\n");
149 OUT("return 0;\n");
150 return 0;
151 }
152
153 /*
Lev Walkin729eb862006-09-21 01:50:13 +0000154 * Here is an if() {} else {} consrtaint checking code.
Lev Walkin84cd58e2004-08-19 13:29:46 +0000155 */
156 OUT("\n");
157 OUT("if(");
158 INDENT(+1);
159 if(r_size) {
160 if(got_something++) { OUT("\n"); OUT(" && "); }
161 OUT("(");
162 emit_range_comparison_code(arg, r_size, "size", 0, -1);
163 OUT(")");
164 }
165 if(r_value) {
166 if(got_something++) { OUT("\n"); OUT(" && "); }
167 OUT("(");
168 if(etype == ASN_BASIC_BOOLEAN)
169 emit_range_comparison_code(arg, r_value,
170 "value", 0, 1);
171 else
172 emit_range_comparison_code(arg, r_value,
173 "value", -1, -1);
174 OUT(")");
175 }
Lev Walkin6938d042005-03-04 23:23:50 +0000176 if(alphabet_table_compiled) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000177 if(got_something++) { OUT("\n"); OUT(" && "); }
Lev Walkin6938d042005-03-04 23:23:50 +0000178 OUT("!check_permitted_alphabet_%d(%s)",
179 arg->expr->_type_unique_index,
180 produce_st ? "st" : "sptr");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000181 }
182 if(!got_something) {
183 OUT("1 /* No applicable constraints whatsoever */");
Lev Walkin59004fa2004-08-20 13:37:01 +0000184 OUT(") {\n");
185 INDENT(-1);
186 INDENTED(OUT("/* Nothing is here. See below */\n"));
187 OUT("}\n");
188 OUT("\n");
189 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000190 }
191 INDENT(-1);
192 OUT(") {\n");
193 INDENT(+1);
Lev Walkin7ef83a42005-03-29 19:04:24 +0000194 switch(etype) {
195 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkin7ef83a42005-03-29 19:04:24 +0000196 case ASN_CONSTR_SET_OF:
197 OUT("/* Perform validation of the inner elements */\n");
Lev Walkin1eded352006-07-13 11:19:01 +0000198 OUT("return td->check_constraints(td, sptr, ctfailcb, app_key);\n");
Lev Walkin7ef83a42005-03-29 19:04:24 +0000199 break;
200 default:
201 OUT("/* Constraint check succeeded */\n");
202 OUT("return 0;\n");
203 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000204 INDENT(-1);
205 OUT("} else {\n");
206 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000207 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000208 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
209 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000210 OUT("return -1;\n");
211 INDENT(-1);
212 OUT("}\n");
213
214 return 0;
215}
216
Lev Walkin59004fa2004-08-20 13:37:01 +0000217static int
218asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin05363a72004-09-29 13:16:40 +0000219 asn1c_integer_t range_start;
220 asn1c_integer_t range_stop;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000221 asn1p_expr_type_e etype;
222 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000223 asn1p_constraint_t *ct;
224 int utf8_full_alphabet_check = 0;
225 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000226 int table[256];
227 int use_table;
228
Lev Walkin59004fa2004-08-20 13:37:01 +0000229 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000230 if(!ct) return 0;
231
232 etype = _find_terminal_type(arg);
233
Lev Walkinbe717ec2004-08-25 02:03:59 +0000234 range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000235 if(!range) return 0;
236
Lev Walkinbe717ec2004-08-25 02:03:59 +0000237 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000238 || range->empty_constraint) {
239 asn1constraint_range_free(range);
240 return 0;
241 }
242
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000243 if(range->left.type == ARE_MIN
244 && range->right.type == ARE_MAX) {
245 /*
246 * The permitted alphabet constraint checker code guarantees
247 * that either both bounds (left/right) are present, or
248 * they're absent simultaneously. Thus, this assertion
249 * legitimately holds true.
250 */
251 assert(range->el_count == 0);
252 /* The full range is specified. Ignore it. */
253 return 0;
254 }
255
Lev Walkin84cd58e2004-08-19 13:29:46 +0000256 range_start = range->left.value;
257 range_stop = range->right.value;
258 assert(range->left.type == ARE_VALUE);
259 assert(range->right.type == ARE_VALUE);
260 assert(range_start <= range_stop);
261
262 range_start = 0; /* Force old behavior */
263
264 /*
265 * Check if we need a test table to check the alphabet.
266 */
267 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000268 if(range->el_count == 0) {
269 /*
270 * It's better to have a short if() check
Lev Walkin729eb862006-09-21 01:50:13 +0000271 * than waste 1k of table space
Lev Walkin59004fa2004-08-20 13:37:01 +0000272 */
273 use_table = 0;
274 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000275 if((range_stop - range_start) > 255)
276 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000277 if(etype == ASN_STRING_UTF8String) {
278 if(range_stop >= 0x80)
279 use_table = 0;
280 else
281 max_table_size = 128;
282 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000283
Lev Walkin84cd58e2004-08-19 13:29:46 +0000284 if(use_table) {
Lev Walkin729eb862006-09-21 01:50:13 +0000285 int cardinal = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000286 int i, n = 0;
287 int untl;
288 memset(table, 0, sizeof(table));
289 for(i = -1; i < range->el_count; i++) {
290 asn1cnst_range_t *r;
Lev Walkin05363a72004-09-29 13:16:40 +0000291 asn1c_integer_t v;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000292 if(i == -1) {
293 if(range->el_count) continue;
294 r = range;
295 } else {
296 r = range->elements[i];
297 }
298 for(v = r->left.value; v <= r->right.value; v++) {
299 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000300 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000301 table[v - range_start] = ++n;
302 }
303 }
304
Lev Walkin84cd58e2004-08-19 13:29:46 +0000305 untl = (range_stop - range_start) + 1;
306 untl += (untl % 16)?16 - (untl % 16):0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000307 OUT("static int permitted_alphabet_table_%d[%d] = {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000308 arg->expr->_type_unique_index, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000309 for(n = 0; n < untl; n++) {
Lev Walkin729eb862006-09-21 01:50:13 +0000310 cardinal += table[n] ? 1 : 0;
311 OUT("%2d,", table[n]);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000312 if(!((n+1) % 16)) {
313 int c;
Lev Walkin729eb862006-09-21 01:50:13 +0000314 if(!n || (n-15) + range_start >= 0x80) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000315 OUT("\n");
316 continue;
317 }
318 OUT("\t/* ");
319 for(c = n - 15; c <= n; c++) {
320 if(table[c]) {
321 int a = c + range_start;
322 if(a > 0x20 && a < 0x80)
323 OUT("%c", a);
324 else
325 OUT(".");
326 } else {
327 OUT(" ");
328 }
329 }
330 OUT(" */");
331 OUT("\n");
332 }
333 }
334 OUT("};\n");
Lev Walkin729eb862006-09-21 01:50:13 +0000335
Lev Walkin725883b2006-10-09 12:07:58 +0000336 if((arg->flags & A1C_GEN_PER)
337 && (etype & ASN_STRING_KM_MASK)) {
Lev Walkin729eb862006-09-21 01:50:13 +0000338 int c;
339 OUT("static int permitted_alphabet_code2value_%d[%d] = {\n",
340 arg->expr->_type_unique_index, cardinal);
341 for(n = c = 0; c < max_table_size; c++) {
342 if(table[c]) {
343 OUT("%d,", c);
344 if(!((++n) % 16)) OUT("\n");
345 }
346 }
347 OUT("};\n");
348 OUT("\n");
Lev Walkin725883b2006-10-09 12:07:58 +0000349 DEBUG("code2value map gen for %s", arg->expr->Identifier);
350 arg->expr->_mark |= TM_PERFROMCT;
Lev Walkin729eb862006-09-21 01:50:13 +0000351 }
352
Lev Walkin84cd58e2004-08-19 13:29:46 +0000353 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000354 } else if(etype == ASN_STRING_UTF8String) {
355 /*
356 * UTF8String type is a special case in many respects.
357 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000358 if(got_size) {
359 /*
360 * Size has been already determined.
361 * The UTF8String length checker also checks
362 * for the syntax validity, so we don't have
363 * to repeat this process twice.
364 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000365 asn1constraint_range_free(range);
366 return 0;
367 } else {
368 utf8_full_alphabet_check = 1;
369 }
370 } else {
371 /*
372 * This permitted alphabet check will be
373 * expressed using conditional statements
374 * instead of table lookups. Table would be
375 * to large or otherwise inappropriate (too sparse?).
376 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000377 }
378
379 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000380 arg->expr->_type_unique_index);
Lev Walkin59004fa2004-08-20 13:37:01 +0000381 INDENT(+1);
382 if(utf8_full_alphabet_check) {
Lev Walkin29c41682004-10-02 16:44:55 +0000383 OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
384 OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000385 OUT("\n");
386 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000387 if(use_table) {
388 OUT("int *table = permitted_alphabet_table_%d;\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000389 arg->expr->_type_unique_index);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000390 emit_alphabet_check_loop(arg, 0);
391 } else {
392 emit_alphabet_check_loop(arg, range);
393 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000394 }
Lev Walkin775885e2004-08-22 12:47:03 +0000395 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000396 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000397 OUT("}\n");
398 OUT("\n");
399
400 asn1constraint_range_free(range);
401
Lev Walkin6938d042005-03-04 23:23:50 +0000402 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000403}
404
405static int
406emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin05363a72004-09-29 13:16:40 +0000407 asn1c_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000408 asn1p_expr_t *terminal;
Lev Walkince31cdb2005-02-15 03:37:42 +0000409 char *tname;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000410
Lev Walkine4d6ab82004-09-22 16:05:13 +0000411 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000412 if(terminal) {
413 OUT("/* The underlying type is %s */\n",
414 ASN_EXPR_TYPE2STR(terminal->expr_type));
415 } else {
416 terminal = arg->expr;
417 }
Lev Walkince31cdb2005-02-15 03:37:42 +0000418 tname = asn1c_type_name(arg, terminal, TNF_SAFE);
419 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000420
Lev Walkin634a3b82004-08-22 03:30:05 +0000421 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000422 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000423 OUT("const uint8_t *ch = st->buf;\n");
424 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000425 OUT("\n");
426 OUT("for(; ch < end; ch++) {\n");
427 INDENT(+1);
428 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000429 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000430 natural_stop = 0xffffffffUL;
431 break;
432 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000433 OUT("const uint8_t *ch = st->buf;\n");
434 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000435 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000436 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
437 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000438 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000439 OUT("uint32_t cv = (ch[0] << 24)\n");
440 OUT("\t\t| (ch[1] << 16)\n");
441 OUT("\t\t| (ch[2] << 8)\n");
442 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000443 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000444 natural_stop = 0xffffffffUL;
445 break;
446 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000447 OUT("const uint8_t *ch = st->buf;\n");
448 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000449 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000450 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
451 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000452 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000453 OUT("uint16_t cv = (ch[0] << 8)\n");
454 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000455 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000456 natural_stop = 0xffff;
457 break;
458 case ASN_BASIC_OCTET_STRING:
459 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000460 OUT("const uint8_t *ch = st->buf;\n");
461 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000462 OUT("\n");
463 OUT("for(; ch < end; ch++) {\n");
464 INDENT(+1);
465 OUT("uint8_t cv = *ch;\n");
466 natural_stop = 0xff;
467 break;
468 }
469
470 if(range) {
471 OUT("if(!(");
472 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
Lev Walkin775885e2004-08-22 12:47:03 +0000473 OUT(")) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000474 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000475 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000476 }
477
478 INDENT(-1);
479 OUT("}\n");
480
481 return 0;
482}
483
484static int
Lev Walkin05363a72004-09-29 13:16:40 +0000485emit_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 +0000486 int ignore_left;
487 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000488 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000489 int i;
490
491 for(i = -1; i < range->el_count; i++) {
492 asn1cnst_range_t *r;
493 if(i == -1) {
494 if(range->el_count) continue;
495 r = range;
496 } else {
497 if(i) OUT(" || ");
498 r = range->elements[i];
499 }
500
501 if(r != range) OUT("(");
502
503 ignore_left = (r->left.type == ARE_MIN)
504 || (natural_start != -1
505 && r->left.value <= natural_start);
506 ignore_right = (r->right.type == ARE_MAX)
507 || (natural_stop != -1
508 && r->right.value >= natural_stop);
509 if(ignore_left && ignore_right) {
510 OUT("1 /* Constraint matches natural range of %s */",
511 varname);
512 continue;
513 }
514
515 if(ignore_left) {
Lev Walkin63b41262007-11-06 01:48:46 +0000516 OUT("%s <= ", varname);
517 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000518 } else if(ignore_right) {
Lev Walkin63b41262007-11-06 01:48:46 +0000519 OUT("%s >= ", varname);
520 OINT(r->left.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000521 } else if(r->left.value == r->right.value) {
Lev Walkin63b41262007-11-06 01:48:46 +0000522 OUT("%s == ", varname);
523 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000524 } else {
Lev Walkin63b41262007-11-06 01:48:46 +0000525 OUT("%s >= ", varname);
526 OINT(r->left.value);
527 OUT(" && ");
528 OUT("%s <= ", varname);
529 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000530 }
531 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000532 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000533 }
534
Lev Walkin59004fa2004-08-20 13:37:01 +0000535 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000536}
537
538static int
539emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
540
541 switch(etype) {
542 case ASN_BASIC_BIT_STRING:
543 OUT("if(st->size > 0) {\n");
544 OUT("\t/* Size in bits */\n");
Lev Walkindcf1e352006-09-08 19:34:22 +0000545 OUT("\tsize = 8 * st->size - (st->bits_unused & 0x07);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000546 OUT("} else {\n");
547 OUT("\tsize = 0;\n");
548 OUT("}\n");
549 break;
550 case ASN_STRING_UniversalString:
551 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
552 break;
553 case ASN_STRING_BMPString:
554 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
555 break;
556 case ASN_STRING_UTF8String:
Lev Walkin29c41682004-10-02 16:44:55 +0000557 OUT("size = UTF8String_length(st);\n");
558 OUT("if((ssize_t)size < 0) {\n");
Lev Walkin1eded352006-07-13 11:19:01 +0000559 OUT("\t_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin29c41682004-10-02 16:44:55 +0000560 OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
561 OUT("\t\ttd->name, __FILE__, __LINE__);\n");
562 OUT("\treturn -1;\n");
563 OUT("}\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000564 break;
565 case ASN_CONSTR_SET_OF:
566 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkinf1a51232005-07-04 02:01:03 +0000567 OUT("/* Determine the number of elements */\n");
568 OUT("size = _A_C%s_FROM_VOID(sptr)->count;\n",
569 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000570 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000571 case ASN_BASIC_OCTET_STRING:
572 OUT("size = st->size;\n");
573 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000574 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000575 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000576 OUT("size = st->size;\n");
577 break;
578 } else {
579 const char *type_name = ASN_EXPR_TYPE2STR(etype);
580 if(!type_name) type_name = arg->expr->Identifier;
581 WARNING("SizeConstraint is not defined for %s",
582 type_name);
583 OUT_NOINDENT("#warning SizeConstraint "
584 "is not defined for %s!\n", type_name);
585 OUT("size = st->size;\n");
586 }
587 return -1;
588 }
589
590 return 0;
591}
592
593static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000594emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000595
596 switch(etype) {
597 case ASN_BASIC_INTEGER:
598 case ASN_BASIC_ENUMERATED:
Lev Walkin8bb57a22007-12-03 13:41:36 +0000599 if(asn1c_type_fits_long(arg, arg->expr) == FL_FITS_UNSIGN) {
600 OUT("value = *(const unsigned long *)sptr;\n");
601 } else if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) {
Lev Walkine0b56e02005-02-25 12:10:27 +0000602 OUT("value = *(const long *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000603 } else {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000604 /*
605 * In some cases we can explore our knowledge of
606 * underlying INTEGER_t->buf format.
607 */
Lev Walkin6ea088f2004-09-07 06:31:15 +0000608 if(r_value->el_count == 0
609 && (
610 /* Speed-up common case: (0..MAX) */
611 (r_value->left.type == ARE_VALUE
612 && r_value->left.value == 0
613 && r_value->right.type == ARE_MAX)
614 ||
615 /* Speed-up common case: (MIN..-1) */
616 (r_value->left.type == ARE_MIN
617 && r_value->right.type == ARE_VALUE
618 && r_value->right.value == -1)
619 )) {
620 OUT("/* Check if the sign bit is present */\n");
621 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
622 break;
623 }
624
Lev Walkin8bb57a22007-12-03 13:41:36 +0000625 if(native_long_sign(r_value) >= 0) {
626 /* Special case for treating unsigned longs */
627 OUT("if(asn_INTEGER2ulong(st, &value)) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000628 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000629 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000630 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
631 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000632 OUT("return -1;\n");
633 INDENT(-1);
Lev Walkin8bb57a22007-12-03 13:41:36 +0000634 OUT("}\n");
635 } else {
636 OUT("if(asn_INTEGER2long(st, &value)) {\n");
637 INDENT(+1);
638 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
639 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
640 OUT("\ttd->name, __FILE__, __LINE__);\n");
641 OUT("return -1;\n");
642 INDENT(-1);
643 OUT("}\n");
644 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000645 }
646 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000647 case ASN_BASIC_REAL:
648 if(arg->flags & A1C_USE_NATIVE_TYPES) {
649 OUT("value = *(const double *)sptr;\n");
650 } else {
Lev Walkin05363a72004-09-29 13:16:40 +0000651 OUT("if(asn_REAL2double(st, &value)) {\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000652 INDENT(+1);
Lev Walkin1eded352006-07-13 11:19:01 +0000653 OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000654 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
655 OUT("\ttd->name, __FILE__, __LINE__);\n");
656 OUT("return -1;\n");
657 INDENT(-1);
658 OUT("}\n");
659 }
660 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000661 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000662 OUT("value = (*(const long *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000663 break;
664 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000665 WARNING("%s:%d: Value cannot be determined "
666 "for constraint check for %s",
Lev Walkinb85a8132005-08-18 13:38:19 +0000667 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000668 arg->expr->_lineno,
669 arg->expr->Identifier
670 );
671 OUT_NOINDENT(
672 "#error %s:%d: Value of %s cannot be determined\n",
Lev Walkinb85a8132005-08-18 13:38:19 +0000673 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000674 arg->expr->_lineno,
675 arg->expr->Identifier
676 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000677 break;
678 }
679
680 return 0;
681}
682
683static asn1p_expr_type_e
684_find_terminal_type(arg_t *arg) {
685 asn1p_expr_t *expr;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000686 expr = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000687 if(expr) return expr->expr_type;
688 return A1TC_INVALID;
689}
690
Lev Walkin8bb57a22007-12-03 13:41:36 +0000691static int
692native_long_sign(asn1cnst_range_t *r) {
693 if(r->left.type == ARE_VALUE
694 && r->left.value >= 0
695 && r->right.type == ARE_VALUE
696 && r->right.value > 2147483647UL
697 && r->right.value <= 4294967295UL) {
698 if(r->el_count == 0
699 && r->left.value == 0
700 && r->right.value == 4294967295UL)
701 return 0;
702 else
703 return 1;
704 } else {
705 return -1;
706 }
707}