blob: e67590a4a9ecb9d68b6b738158a192cfbcf90e04 [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;
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +080038 int ret = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +000039
40 ct = expr->combined_constraints;
41 if(ct == NULL)
42 return 1; /* No additional constraints defined */
43
44 etype = _find_terminal_type(arg);
45
Lev Walkinbe717ec2004-08-25 02:03:59 +000046 r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE,0,0,0);
Lev Walkin729eb862006-09-21 01:50:13 +000047 r_size =asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +000048 if(r_value) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000049 if(r_value->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000050 || r_value->empty_constraint
51 || (r_value->left.type == ARE_MIN
52 && r_value->right.type == ARE_MAX)
53 || (etype == ASN_BASIC_BOOLEAN
54 && r_value->left.value == 0
55 && r_value->right.value == 1)
56 ) {
57 asn1constraint_range_free(r_value);
58 r_value = 0;
59 }
60 }
61 if(r_size) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000062 if(r_size->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000063 || r_size->empty_constraint
64 || (r_size->left.value == 0 /* or .type == MIN */
65 && r_size->right.type == ARE_MAX)
66 ) {
67 asn1constraint_range_free(r_size);
68 r_size = 0;
69 }
70 }
71
Lev Walkin59004fa2004-08-20 13:37:01 +000072 /*
73 * Do we really need an "*st = sptr" pointer?
74 */
75 switch(etype) {
76 case ASN_BASIC_INTEGER:
77 case ASN_BASIC_ENUMERATED:
Lev Walkin082cadc2005-08-14 02:18:27 +000078 if(asn1c_type_fits_long(arg, arg->expr) == FL_NOTFIT)
79 produce_st = 1;
80 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +000081 case ASN_BASIC_REAL:
Lev Walkin2a744a72013-03-27 01:56:23 -070082 if((arg->flags & A1C_USE_WIDE_TYPES))
Lev Walkin59004fa2004-08-20 13:37:01 +000083 produce_st = 1;
84 break;
Lev Walkin02b137d2004-08-21 07:34:58 +000085 case ASN_BASIC_BIT_STRING:
Lev Walkin59004fa2004-08-20 13:37:01 +000086 case ASN_BASIC_OCTET_STRING:
87 produce_st = 1;
Lev Walkin3a4689a2006-11-24 11:20:27 +000088 break;
Lev Walkin59004fa2004-08-20 13:37:01 +000089 default:
90 if(etype & ASN_STRING_MASK)
91 produce_st = 1;
92 break;
93 }
Lev Walkince31cdb2005-02-15 03:37:42 +000094 if(produce_st) {
95 char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
96 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
97 }
Lev Walkin84cd58e2004-08-19 13:29:46 +000098
99 if(r_size || r_value) {
100 if(r_size) {
101 OUT("size_t size;\n");
102 }
103 if(r_value)
104 switch(etype) {
105 case ASN_BASIC_INTEGER:
106 case ASN_BASIC_ENUMERATED:
Lev Walkin8bb57a22007-12-03 13:41:36 +0000107 if(native_long_sign(r_value) >= 0) {
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200108 ulong_optimize = ulong_optimization(etype, r_size, r_value);
109 if(!ulong_optimize) {
110 OUT("unsigned long value;\n");
111 }
Lev Walkin8bb57a22007-12-03 13:41:36 +0000112 } else {
113 OUT("long value;\n");
114 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000115 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000116 case ASN_BASIC_REAL:
117 OUT("double value;\n");
118 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000119 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000120 OUT("BOOLEAN_t value;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000121 break;
122 default:
123 break;
124 }
125 }
126
127 OUT("\n");
128
129 /*
130 * Protection against null input.
131 */
132 OUT("if(!sptr) {\n");
133 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700134 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000135 OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
136 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000137 OUT("return -1;\n");
138 INDENT(-1);
139 OUT("}\n");
140 OUT("\n");
141
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200142 if((r_value) && (!ulong_optimize))
Lev Walkin6ea088f2004-09-07 06:31:15 +0000143 emit_value_determination_code(arg, etype, r_value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000144 if(r_size)
145 emit_size_determination_code(arg, etype);
146
Lev Walkin59004fa2004-08-20 13:37:01 +0000147 INDENT(-1);
148 REDIR(OT_CTABLES);
149 /* Emit FROM() tables */
Lev Walkin6938d042005-03-04 23:23:50 +0000150 alphabet_table_compiled =
151 (asn1c_emit_constraint_tables(arg, r_size?1:0) == 1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000152 REDIR(OT_CODE);
153 INDENT(+1);
154
Lev Walkin84cd58e2004-08-19 13:29:46 +0000155 /*
Lev Walkin8bb57a22007-12-03 13:41:36 +0000156 * Optimization for unsigned longs.
157 */
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200158 if(ulong_optimize) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000159 OUT("\n");
160 OUT("/* Constraint check succeeded */\n");
161 OUT("return 0;\n");
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800162 goto end;
Lev Walkin8bb57a22007-12-03 13:41:36 +0000163 }
164
165 /*
Lev Walkin729eb862006-09-21 01:50:13 +0000166 * Here is an if() {} else {} consrtaint checking code.
Lev Walkin84cd58e2004-08-19 13:29:46 +0000167 */
168 OUT("\n");
169 OUT("if(");
170 INDENT(+1);
171 if(r_size) {
172 if(got_something++) { OUT("\n"); OUT(" && "); }
173 OUT("(");
174 emit_range_comparison_code(arg, r_size, "size", 0, -1);
175 OUT(")");
176 }
177 if(r_value) {
178 if(got_something++) { OUT("\n"); OUT(" && "); }
179 OUT("(");
180 if(etype == ASN_BASIC_BOOLEAN)
181 emit_range_comparison_code(arg, r_value,
182 "value", 0, 1);
183 else
184 emit_range_comparison_code(arg, r_value,
185 "value", -1, -1);
186 OUT(")");
187 }
Lev Walkin6938d042005-03-04 23:23:50 +0000188 if(alphabet_table_compiled) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000189 if(got_something++) { OUT("\n"); OUT(" && "); }
Lev Walkin6938d042005-03-04 23:23:50 +0000190 OUT("!check_permitted_alphabet_%d(%s)",
191 arg->expr->_type_unique_index,
192 produce_st ? "st" : "sptr");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000193 }
194 if(!got_something) {
195 OUT("1 /* No applicable constraints whatsoever */");
Lev Walkin59004fa2004-08-20 13:37:01 +0000196 OUT(") {\n");
197 INDENT(-1);
198 INDENTED(OUT("/* Nothing is here. See below */\n"));
199 OUT("}\n");
200 OUT("\n");
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800201 ret = 1;
202 goto end;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000203 }
204 INDENT(-1);
205 OUT(") {\n");
206 INDENT(+1);
Lev Walkin7ef83a42005-03-29 19:04:24 +0000207 switch(etype) {
208 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkin7ef83a42005-03-29 19:04:24 +0000209 case ASN_CONSTR_SET_OF:
210 OUT("/* Perform validation of the inner elements */\n");
Lev Walkin1eded352006-07-13 11:19:01 +0000211 OUT("return td->check_constraints(td, sptr, ctfailcb, app_key);\n");
Lev Walkin7ef83a42005-03-29 19:04:24 +0000212 break;
213 default:
214 OUT("/* Constraint check succeeded */\n");
215 OUT("return 0;\n");
216 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000217 INDENT(-1);
218 OUT("} else {\n");
219 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700220 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000221 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
222 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000223 OUT("return -1;\n");
224 INDENT(-1);
225 OUT("}\n");
226
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800227end:
228 if (r_value) asn1constraint_range_free(r_value);
229 if (r_size) asn1constraint_range_free(r_size);
230
231 return ret;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000232}
233
Lev Walkin59004fa2004-08-20 13:37:01 +0000234static int
235asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin05363a72004-09-29 13:16:40 +0000236 asn1c_integer_t range_start;
237 asn1c_integer_t range_stop;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000238 asn1p_expr_type_e etype;
239 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000240 asn1p_constraint_t *ct;
241 int utf8_full_alphabet_check = 0;
242 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000243 int table[256];
244 int use_table;
245
Lev Walkin59004fa2004-08-20 13:37:01 +0000246 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000247 if(!ct) return 0;
248
249 etype = _find_terminal_type(arg);
250
Lev Walkinbe717ec2004-08-25 02:03:59 +0000251 range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000252 if(!range) return 0;
253
Lev Walkinbe717ec2004-08-25 02:03:59 +0000254 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000255 || range->empty_constraint) {
256 asn1constraint_range_free(range);
257 return 0;
258 }
259
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000260 if(range->left.type == ARE_MIN
261 && range->right.type == ARE_MAX) {
262 /*
263 * The permitted alphabet constraint checker code guarantees
264 * that either both bounds (left/right) are present, or
265 * they're absent simultaneously. Thus, this assertion
266 * legitimately holds true.
267 */
268 assert(range->el_count == 0);
269 /* The full range is specified. Ignore it. */
270 return 0;
271 }
272
Lev Walkin84cd58e2004-08-19 13:29:46 +0000273 range_start = range->left.value;
274 range_stop = range->right.value;
275 assert(range->left.type == ARE_VALUE);
276 assert(range->right.type == ARE_VALUE);
277 assert(range_start <= range_stop);
278
279 range_start = 0; /* Force old behavior */
280
281 /*
282 * Check if we need a test table to check the alphabet.
283 */
284 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000285 if(range->el_count == 0) {
286 /*
287 * It's better to have a short if() check
Lev Walkin729eb862006-09-21 01:50:13 +0000288 * than waste 1k of table space
Lev Walkin59004fa2004-08-20 13:37:01 +0000289 */
290 use_table = 0;
291 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000292 if((range_stop - range_start) > 255)
293 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000294 if(etype == ASN_STRING_UTF8String) {
295 if(range_stop >= 0x80)
296 use_table = 0;
297 else
298 max_table_size = 128;
299 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000300
Lev Walkin84cd58e2004-08-19 13:29:46 +0000301 if(use_table) {
Lev Walkin729eb862006-09-21 01:50:13 +0000302 int cardinal = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000303 int i, n = 0;
304 int untl;
305 memset(table, 0, sizeof(table));
306 for(i = -1; i < range->el_count; i++) {
307 asn1cnst_range_t *r;
Lev Walkin05363a72004-09-29 13:16:40 +0000308 asn1c_integer_t v;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000309 if(i == -1) {
310 if(range->el_count) continue;
311 r = range;
312 } else {
313 r = range->elements[i];
314 }
315 for(v = r->left.value; v <= r->right.value; v++) {
316 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000317 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000318 table[v - range_start] = ++n;
319 }
320 }
321
Lev Walkin84cd58e2004-08-19 13:29:46 +0000322 untl = (range_stop - range_start) + 1;
323 untl += (untl % 16)?16 - (untl % 16):0;
Wim Lewisa73ae672014-07-22 19:55:30 -0700324 OUT("static const int permitted_alphabet_table_%d[%d] = {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000325 arg->expr->_type_unique_index, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000326 for(n = 0; n < untl; n++) {
Lev Walkin729eb862006-09-21 01:50:13 +0000327 cardinal += table[n] ? 1 : 0;
328 OUT("%2d,", table[n]);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000329 if(!((n+1) % 16)) {
330 int c;
Lev Walkin729eb862006-09-21 01:50:13 +0000331 if(!n || (n-15) + range_start >= 0x80) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000332 OUT("\n");
333 continue;
334 }
335 OUT("\t/* ");
336 for(c = n - 15; c <= n; c++) {
337 if(table[c]) {
338 int a = c + range_start;
339 if(a > 0x20 && a < 0x80)
340 OUT("%c", a);
341 else
342 OUT(".");
343 } else {
344 OUT(" ");
345 }
346 }
347 OUT(" */");
348 OUT("\n");
349 }
350 }
351 OUT("};\n");
Lev Walkin729eb862006-09-21 01:50:13 +0000352
Lev Walkin725883b2006-10-09 12:07:58 +0000353 if((arg->flags & A1C_GEN_PER)
354 && (etype & ASN_STRING_KM_MASK)) {
Lev Walkin729eb862006-09-21 01:50:13 +0000355 int c;
Wim Lewisa73ae672014-07-22 19:55:30 -0700356 OUT("static const int permitted_alphabet_code2value_%d[%d] = {\n",
Lev Walkin729eb862006-09-21 01:50:13 +0000357 arg->expr->_type_unique_index, cardinal);
358 for(n = c = 0; c < max_table_size; c++) {
359 if(table[c]) {
360 OUT("%d,", c);
361 if(!((++n) % 16)) OUT("\n");
362 }
363 }
364 OUT("};\n");
365 OUT("\n");
Lev Walkin725883b2006-10-09 12:07:58 +0000366 DEBUG("code2value map gen for %s", arg->expr->Identifier);
367 arg->expr->_mark |= TM_PERFROMCT;
Lev Walkin729eb862006-09-21 01:50:13 +0000368 }
369
Lev Walkin84cd58e2004-08-19 13:29:46 +0000370 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000371 } else if(etype == ASN_STRING_UTF8String) {
372 /*
373 * UTF8String type is a special case in many respects.
374 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000375 if(got_size) {
376 /*
377 * Size has been already determined.
378 * The UTF8String length checker also checks
379 * for the syntax validity, so we don't have
380 * to repeat this process twice.
381 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000382 asn1constraint_range_free(range);
383 return 0;
384 } else {
385 utf8_full_alphabet_check = 1;
386 }
387 } else {
388 /*
389 * This permitted alphabet check will be
390 * expressed using conditional statements
391 * instead of table lookups. Table would be
392 * to large or otherwise inappropriate (too sparse?).
393 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000394 }
395
396 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000397 arg->expr->_type_unique_index);
Lev Walkin59004fa2004-08-20 13:37:01 +0000398 INDENT(+1);
399 if(utf8_full_alphabet_check) {
Lev Walkin29c41682004-10-02 16:44:55 +0000400 OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
401 OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000402 OUT("\n");
403 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000404 if(use_table) {
Wim Lewisa73ae672014-07-22 19:55:30 -0700405 OUT("const int *table = permitted_alphabet_table_%d;\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000406 arg->expr->_type_unique_index);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000407 emit_alphabet_check_loop(arg, 0);
408 } else {
409 emit_alphabet_check_loop(arg, range);
410 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000411 }
Lev Walkin775885e2004-08-22 12:47:03 +0000412 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000413 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000414 OUT("}\n");
415 OUT("\n");
416
417 asn1constraint_range_free(range);
418
Lev Walkin6938d042005-03-04 23:23:50 +0000419 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000420}
421
422static int
423emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin05363a72004-09-29 13:16:40 +0000424 asn1c_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000425 asn1p_expr_t *terminal;
Lev Walkince31cdb2005-02-15 03:37:42 +0000426 char *tname;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000427
Lev Walkine4d6ab82004-09-22 16:05:13 +0000428 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000429 if(terminal) {
430 OUT("/* The underlying type is %s */\n",
431 ASN_EXPR_TYPE2STR(terminal->expr_type));
432 } else {
433 terminal = arg->expr;
434 }
Lev Walkince31cdb2005-02-15 03:37:42 +0000435 tname = asn1c_type_name(arg, terminal, TNF_SAFE);
436 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000437
Lev Walkin634a3b82004-08-22 03:30:05 +0000438 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000439 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000440 OUT("const uint8_t *ch = st->buf;\n");
441 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000442 OUT("\n");
443 OUT("for(; ch < end; ch++) {\n");
444 INDENT(+1);
445 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000446 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000447 natural_stop = 0xffffffffUL;
448 break;
449 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000450 OUT("const uint8_t *ch = st->buf;\n");
451 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000452 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000453 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
454 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000455 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000456 OUT("uint32_t cv = (ch[0] << 24)\n");
457 OUT("\t\t| (ch[1] << 16)\n");
458 OUT("\t\t| (ch[2] << 8)\n");
459 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000460 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000461 natural_stop = 0xffffffffUL;
462 break;
463 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000464 OUT("const uint8_t *ch = st->buf;\n");
465 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000466 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000467 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
468 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000469 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000470 OUT("uint16_t cv = (ch[0] << 8)\n");
471 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000472 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000473 natural_stop = 0xffff;
474 break;
475 case ASN_BASIC_OCTET_STRING:
476 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000477 OUT("const uint8_t *ch = st->buf;\n");
478 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000479 OUT("\n");
480 OUT("for(; ch < end; ch++) {\n");
481 INDENT(+1);
482 OUT("uint8_t cv = *ch;\n");
483 natural_stop = 0xff;
484 break;
485 }
486
487 if(range) {
488 OUT("if(!(");
489 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
Lev Walkin775885e2004-08-22 12:47:03 +0000490 OUT(")) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000491 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000492 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000493 }
494
495 INDENT(-1);
496 OUT("}\n");
497
498 return 0;
499}
500
501static int
Lev Walkin05363a72004-09-29 13:16:40 +0000502emit_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 +0000503 int ignore_left;
504 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000505 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000506 int i;
507
508 for(i = -1; i < range->el_count; i++) {
509 asn1cnst_range_t *r;
510 if(i == -1) {
511 if(range->el_count) continue;
512 r = range;
513 } else {
514 if(i) OUT(" || ");
515 r = range->elements[i];
516 }
517
518 if(r != range) OUT("(");
519
520 ignore_left = (r->left.type == ARE_MIN)
521 || (natural_start != -1
522 && r->left.value <= natural_start);
523 ignore_right = (r->right.type == ARE_MAX)
524 || (natural_stop != -1
525 && r->right.value >= natural_stop);
526 if(ignore_left && ignore_right) {
527 OUT("1 /* Constraint matches natural range of %s */",
528 varname);
529 continue;
530 }
531
532 if(ignore_left) {
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 if(ignore_right) {
Lev Walkin63b41262007-11-06 01:48:46 +0000536 OUT("%s >= ", varname);
537 OINT(r->left.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000538 } else if(r->left.value == r->right.value) {
Lev Walkin63b41262007-11-06 01:48:46 +0000539 OUT("%s == ", varname);
540 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000541 } else {
Lev Walkin63b41262007-11-06 01:48:46 +0000542 OUT("%s >= ", varname);
543 OINT(r->left.value);
544 OUT(" && ");
545 OUT("%s <= ", varname);
546 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000547 }
548 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000549 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000550 }
551
Lev Walkin59004fa2004-08-20 13:37:01 +0000552 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000553}
554
555static int
556emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
557
558 switch(etype) {
559 case ASN_BASIC_BIT_STRING:
560 OUT("if(st->size > 0) {\n");
561 OUT("\t/* Size in bits */\n");
Lev Walkindcf1e352006-09-08 19:34:22 +0000562 OUT("\tsize = 8 * st->size - (st->bits_unused & 0x07);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000563 OUT("} else {\n");
564 OUT("\tsize = 0;\n");
565 OUT("}\n");
566 break;
567 case ASN_STRING_UniversalString:
568 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
569 break;
570 case ASN_STRING_BMPString:
571 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
572 break;
573 case ASN_STRING_UTF8String:
Lev Walkin29c41682004-10-02 16:44:55 +0000574 OUT("size = UTF8String_length(st);\n");
575 OUT("if((ssize_t)size < 0) {\n");
Lev Walkin7c1dc052016-03-14 03:08:15 -0700576 OUT("\tASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin29c41682004-10-02 16:44:55 +0000577 OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
578 OUT("\t\ttd->name, __FILE__, __LINE__);\n");
579 OUT("\treturn -1;\n");
580 OUT("}\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000581 break;
582 case ASN_CONSTR_SET_OF:
583 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkinf1a51232005-07-04 02:01:03 +0000584 OUT("/* Determine the number of elements */\n");
585 OUT("size = _A_C%s_FROM_VOID(sptr)->count;\n",
586 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000587 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000588 case ASN_BASIC_OCTET_STRING:
589 OUT("size = st->size;\n");
590 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000591 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000592 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000593 OUT("size = st->size;\n");
594 break;
595 } else {
596 const char *type_name = ASN_EXPR_TYPE2STR(etype);
597 if(!type_name) type_name = arg->expr->Identifier;
598 WARNING("SizeConstraint is not defined for %s",
599 type_name);
600 OUT_NOINDENT("#warning SizeConstraint "
601 "is not defined for %s!\n", type_name);
602 OUT("size = st->size;\n");
603 }
604 return -1;
605 }
606
607 return 0;
608}
609
610static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000611emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000612
613 switch(etype) {
614 case ASN_BASIC_INTEGER:
615 case ASN_BASIC_ENUMERATED:
Lev Walkin8bb57a22007-12-03 13:41:36 +0000616 if(asn1c_type_fits_long(arg, arg->expr) == FL_FITS_UNSIGN) {
617 OUT("value = *(const unsigned long *)sptr;\n");
618 } else if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) {
Lev Walkine0b56e02005-02-25 12:10:27 +0000619 OUT("value = *(const long *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000620 } else {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000621 /*
622 * In some cases we can explore our knowledge of
623 * underlying INTEGER_t->buf format.
624 */
Lev Walkin6ea088f2004-09-07 06:31:15 +0000625 if(r_value->el_count == 0
626 && (
627 /* Speed-up common case: (0..MAX) */
628 (r_value->left.type == ARE_VALUE
629 && r_value->left.value == 0
630 && r_value->right.type == ARE_MAX)
631 ||
632 /* Speed-up common case: (MIN..-1) */
633 (r_value->left.type == ARE_MIN
634 && r_value->right.type == ARE_VALUE
635 && r_value->right.value == -1)
636 )) {
637 OUT("/* Check if the sign bit is present */\n");
638 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
639 break;
640 }
641
Lev Walkin8bb57a22007-12-03 13:41:36 +0000642 if(native_long_sign(r_value) >= 0) {
643 /* Special case for treating unsigned longs */
644 OUT("if(asn_INTEGER2ulong(st, &value)) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000645 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700646 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000647 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
648 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000649 OUT("return -1;\n");
650 INDENT(-1);
Lev Walkin8bb57a22007-12-03 13:41:36 +0000651 OUT("}\n");
652 } else {
653 OUT("if(asn_INTEGER2long(st, &value)) {\n");
654 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700655 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin8bb57a22007-12-03 13:41:36 +0000656 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
657 OUT("\ttd->name, __FILE__, __LINE__);\n");
658 OUT("return -1;\n");
659 INDENT(-1);
660 OUT("}\n");
661 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000662 }
663 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000664 case ASN_BASIC_REAL:
Lev Walkin2a744a72013-03-27 01:56:23 -0700665 if(arg->flags & A1C_USE_WIDE_TYPES) {
Lev Walkin05363a72004-09-29 13:16:40 +0000666 OUT("if(asn_REAL2double(st, &value)) {\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000667 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700668 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000669 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
670 OUT("\ttd->name, __FILE__, __LINE__);\n");
671 OUT("return -1;\n");
672 INDENT(-1);
673 OUT("}\n");
Lev Walkin2a744a72013-03-27 01:56:23 -0700674 } else {
675 OUT("value = *(const double *)sptr;\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000676 }
677 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000678 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000679 OUT("value = (*(const long *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000680 break;
681 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000682 WARNING("%s:%d: Value cannot be determined "
683 "for constraint check for %s",
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 );
688 OUT_NOINDENT(
689 "#error %s:%d: Value of %s cannot be determined\n",
Lev Walkinb85a8132005-08-18 13:38:19 +0000690 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000691 arg->expr->_lineno,
692 arg->expr->Identifier
693 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000694 break;
695 }
696
697 return 0;
698}
699
700static asn1p_expr_type_e
701_find_terminal_type(arg_t *arg) {
702 asn1p_expr_t *expr;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000703 expr = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000704 if(expr) return expr->expr_type;
705 return A1TC_INVALID;
706}
707
Lev Walkin8bb57a22007-12-03 13:41:36 +0000708static int
709native_long_sign(asn1cnst_range_t *r) {
710 if(r->left.type == ARE_VALUE
711 && r->left.value >= 0
712 && r->right.type == ARE_VALUE
Lev Walkin5b63acf2014-01-14 01:48:37 -0800713 && r->right.value > 2147483647
Lev Walkin1b3a1352016-01-10 13:15:02 -0800714 && r->right.value <= (asn1c_integer_t)(4294967295UL)) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000715 if(r->el_count == 0
716 && r->left.value == 0
717 && r->right.value == 4294967295UL)
718 return 0;
719 else
720 return 1;
721 } else {
722 return -1;
723 }
724}