blob: d68e9d1b1f8bd1acd4d7014adb0af6a6c64106be [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 Walkine0f2a5b2017-08-30 20:02:29 -070015static int native_long_sign(arg_t *arg, 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
Lev Walkine0f2a5b2017-08-30 20:02:29 -070018ulong_optimization(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_size,
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020019 asn1cnst_range_t *r_value)
20{
21 return (!r_size && r_value
22 && (etype == ASN_BASIC_INTEGER
23 || etype == ASN_BASIC_ENUMERATED)
Lev Walkine0f2a5b2017-08-30 20:02:29 -070024 && native_long_sign(arg, r_value) == 0);
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020025}
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 Walkina28cbb92017-07-31 20:20:17 -070046 r_value=asn1constraint_compute_constraint_range(expr->Identifier, etype, ct, ACT_EL_RANGE,0,0,0);
47 r_size =asn1constraint_compute_constraint_range(expr->Identifier, 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) {
Lev Walkincf3f6eb2017-08-23 04:34:15 -070095 const char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
Lev Walkince31cdb2005-02-15 03:37:42 +000096 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 Walkine0f2a5b2017-08-30 20:02:29 -0700107 if(native_long_sign(arg, r_value) >= 0) {
108 ulong_optimize = ulong_optimization(arg, etype, r_size, r_value);
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200109 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);
johvikbd3dea92017-05-09 10:20:51 +0200198 if(produce_st) {
199 INDENTED(OUT("(void)st; /* Unused variable */\n"));
200 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000201 INDENTED(OUT("/* Nothing is here. See below */\n"));
202 OUT("}\n");
203 OUT("\n");
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800204 ret = 1;
205 goto end;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000206 }
207 INDENT(-1);
208 OUT(") {\n");
209 INDENT(+1);
Lev Walkin7ef83a42005-03-29 19:04:24 +0000210 switch(etype) {
211 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkin7ef83a42005-03-29 19:04:24 +0000212 case ASN_CONSTR_SET_OF:
213 OUT("/* Perform validation of the inner elements */\n");
Lev Walkin14e75ed2017-09-29 23:15:02 -0700214 OUT("return td->encoding_constraints.general_constraints(td, sptr, ctfailcb, app_key);\n");
Lev Walkin7ef83a42005-03-29 19:04:24 +0000215 break;
216 default:
217 OUT("/* Constraint check succeeded */\n");
218 OUT("return 0;\n");
219 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000220 INDENT(-1);
221 OUT("} else {\n");
222 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700223 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000224 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
225 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000226 OUT("return -1;\n");
227 INDENT(-1);
228 OUT("}\n");
229
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800230end:
231 if (r_value) asn1constraint_range_free(r_value);
232 if (r_size) asn1constraint_range_free(r_size);
233
234 return ret;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000235}
236
Lev Walkin59004fa2004-08-20 13:37:01 +0000237static int
238asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin05363a72004-09-29 13:16:40 +0000239 asn1c_integer_t range_start;
240 asn1c_integer_t range_stop;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000241 asn1p_expr_type_e etype;
242 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000243 asn1p_constraint_t *ct;
244 int utf8_full_alphabet_check = 0;
245 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000246 int table[256];
247 int use_table;
248
Lev Walkin59004fa2004-08-20 13:37:01 +0000249 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000250 if(!ct) return 0;
251
252 etype = _find_terminal_type(arg);
253
Lev Walkina28cbb92017-07-31 20:20:17 -0700254 range = asn1constraint_compute_constraint_range(arg->expr->Identifier, etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000255 if(!range) return 0;
256
Lev Walkinbe717ec2004-08-25 02:03:59 +0000257 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000258 || range->empty_constraint) {
259 asn1constraint_range_free(range);
260 return 0;
261 }
262
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000263 if(range->left.type == ARE_MIN
264 && range->right.type == ARE_MAX) {
265 /*
266 * The permitted alphabet constraint checker code guarantees
267 * that either both bounds (left/right) are present, or
268 * they're absent simultaneously. Thus, this assertion
269 * legitimately holds true.
270 */
271 assert(range->el_count == 0);
272 /* The full range is specified. Ignore it. */
Bi-Ruei, Chiu3dcf05b2017-05-04 21:45:05 +0800273 asn1constraint_range_free(range);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000274 return 0;
275 }
276
Lev Walkin84cd58e2004-08-19 13:29:46 +0000277 range_start = range->left.value;
278 range_stop = range->right.value;
279 assert(range->left.type == ARE_VALUE);
280 assert(range->right.type == ARE_VALUE);
281 assert(range_start <= range_stop);
282
283 range_start = 0; /* Force old behavior */
284
285 /*
286 * Check if we need a test table to check the alphabet.
287 */
288 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000289 if(range->el_count == 0) {
290 /*
291 * It's better to have a short if() check
Lev Walkin729eb862006-09-21 01:50:13 +0000292 * than waste 1k of table space
Lev Walkin59004fa2004-08-20 13:37:01 +0000293 */
294 use_table = 0;
295 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000296 if((range_stop - range_start) > 255)
297 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000298 if(etype == ASN_STRING_UTF8String) {
299 if(range_stop >= 0x80)
300 use_table = 0;
301 else
302 max_table_size = 128;
303 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000304
Lev Walkin84cd58e2004-08-19 13:29:46 +0000305 if(use_table) {
Lev Walkin729eb862006-09-21 01:50:13 +0000306 int cardinal = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000307 int i, n = 0;
308 int untl;
309 memset(table, 0, sizeof(table));
310 for(i = -1; i < range->el_count; i++) {
311 asn1cnst_range_t *r;
Lev Walkin05363a72004-09-29 13:16:40 +0000312 asn1c_integer_t v;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000313 if(i == -1) {
314 if(range->el_count) continue;
315 r = range;
316 } else {
317 r = range->elements[i];
318 }
319 for(v = r->left.value; v <= r->right.value; v++) {
320 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000321 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000322 table[v - range_start] = ++n;
323 }
324 }
325
Lev Walkin84cd58e2004-08-19 13:29:46 +0000326 untl = (range_stop - range_start) + 1;
327 untl += (untl % 16)?16 - (untl % 16):0;
Wim Lewisa73ae672014-07-22 19:55:30 -0700328 OUT("static const int permitted_alphabet_table_%d[%d] = {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000329 arg->expr->_type_unique_index, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000330 for(n = 0; n < untl; n++) {
Lev Walkin729eb862006-09-21 01:50:13 +0000331 cardinal += table[n] ? 1 : 0;
332 OUT("%2d,", table[n]);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000333 if(!((n+1) % 16)) {
334 int c;
Lev Walkin729eb862006-09-21 01:50:13 +0000335 if(!n || (n-15) + range_start >= 0x80) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000336 OUT("\n");
337 continue;
338 }
339 OUT("\t/* ");
340 for(c = n - 15; c <= n; c++) {
341 if(table[c]) {
342 int a = c + range_start;
343 if(a > 0x20 && a < 0x80)
344 OUT("%c", a);
345 else
346 OUT(".");
347 } else {
348 OUT(" ");
349 }
350 }
351 OUT(" */");
352 OUT("\n");
353 }
354 }
355 OUT("};\n");
Lev Walkin729eb862006-09-21 01:50:13 +0000356
Lev Walkin725883b2006-10-09 12:07:58 +0000357 if((arg->flags & A1C_GEN_PER)
358 && (etype & ASN_STRING_KM_MASK)) {
Lev Walkin729eb862006-09-21 01:50:13 +0000359 int c;
Wim Lewisa73ae672014-07-22 19:55:30 -0700360 OUT("static const int permitted_alphabet_code2value_%d[%d] = {\n",
Lev Walkin729eb862006-09-21 01:50:13 +0000361 arg->expr->_type_unique_index, cardinal);
362 for(n = c = 0; c < max_table_size; c++) {
363 if(table[c]) {
364 OUT("%d,", c);
365 if(!((++n) % 16)) OUT("\n");
366 }
367 }
368 OUT("};\n");
369 OUT("\n");
Lev Walkin725883b2006-10-09 12:07:58 +0000370 DEBUG("code2value map gen for %s", arg->expr->Identifier);
371 arg->expr->_mark |= TM_PERFROMCT;
Lev Walkin729eb862006-09-21 01:50:13 +0000372 }
373
Lev Walkin84cd58e2004-08-19 13:29:46 +0000374 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000375 } else if(etype == ASN_STRING_UTF8String) {
376 /*
377 * UTF8String type is a special case in many respects.
378 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000379 if(got_size) {
380 /*
381 * Size has been already determined.
382 * The UTF8String length checker also checks
383 * for the syntax validity, so we don't have
384 * to repeat this process twice.
385 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000386 asn1constraint_range_free(range);
387 return 0;
388 } else {
389 utf8_full_alphabet_check = 1;
390 }
391 } else {
392 /*
393 * This permitted alphabet check will be
394 * expressed using conditional statements
395 * instead of table lookups. Table would be
396 * to large or otherwise inappropriate (too sparse?).
397 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000398 }
399
400 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000401 arg->expr->_type_unique_index);
Lev Walkin59004fa2004-08-20 13:37:01 +0000402 INDENT(+1);
403 if(utf8_full_alphabet_check) {
Lev Walkin29c41682004-10-02 16:44:55 +0000404 OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
405 OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000406 OUT("\n");
407 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000408 if(use_table) {
Wim Lewisa73ae672014-07-22 19:55:30 -0700409 OUT("const int *table = permitted_alphabet_table_%d;\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000410 arg->expr->_type_unique_index);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000411 emit_alphabet_check_loop(arg, 0);
412 } else {
413 emit_alphabet_check_loop(arg, range);
414 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000415 }
Lev Walkin775885e2004-08-22 12:47:03 +0000416 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000417 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000418 OUT("}\n");
419 OUT("\n");
420
421 asn1constraint_range_free(range);
422
Lev Walkin6938d042005-03-04 23:23:50 +0000423 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000424}
425
426static int
427emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin05363a72004-09-29 13:16:40 +0000428 asn1c_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000429 asn1p_expr_t *terminal;
Lev Walkincf3f6eb2017-08-23 04:34:15 -0700430 const char *tname;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000431
Lev Walkinc0e03b92017-08-22 01:48:23 -0700432 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->ns, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000433 if(terminal) {
434 OUT("/* The underlying type is %s */\n",
435 ASN_EXPR_TYPE2STR(terminal->expr_type));
436 } else {
437 terminal = arg->expr;
438 }
Lev Walkince31cdb2005-02-15 03:37:42 +0000439 tname = asn1c_type_name(arg, terminal, TNF_SAFE);
440 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000441
Lev Walkin634a3b82004-08-22 03:30:05 +0000442 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000443 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000444 OUT("const uint8_t *ch = st->buf;\n");
445 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000446 OUT("\n");
447 OUT("for(; ch < end; ch++) {\n");
448 INDENT(+1);
449 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000450 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000451 natural_stop = 0xffffffffUL;
452 break;
453 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000454 OUT("const uint8_t *ch = st->buf;\n");
455 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000456 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000457 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
458 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000459 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000460 OUT("uint32_t cv = (ch[0] << 24)\n");
461 OUT("\t\t| (ch[1] << 16)\n");
462 OUT("\t\t| (ch[2] << 8)\n");
463 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000464 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000465 natural_stop = 0xffffffffUL;
466 break;
467 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000468 OUT("const uint8_t *ch = st->buf;\n");
469 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000470 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000471 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
472 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000473 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000474 OUT("uint16_t cv = (ch[0] << 8)\n");
475 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000476 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000477 natural_stop = 0xffff;
478 break;
479 case ASN_BASIC_OCTET_STRING:
480 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000481 OUT("const uint8_t *ch = st->buf;\n");
482 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000483 OUT("\n");
484 OUT("for(; ch < end; ch++) {\n");
485 INDENT(+1);
486 OUT("uint8_t cv = *ch;\n");
487 natural_stop = 0xff;
488 break;
489 }
490
491 if(range) {
492 OUT("if(!(");
493 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
Lev Walkin775885e2004-08-22 12:47:03 +0000494 OUT(")) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000495 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000496 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000497 }
498
499 INDENT(-1);
500 OUT("}\n");
501
502 return 0;
503}
504
505static int
Lev Walkin05363a72004-09-29 13:16:40 +0000506emit_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 +0000507 int ignore_left;
508 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000509 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000510 int i;
511
512 for(i = -1; i < range->el_count; i++) {
513 asn1cnst_range_t *r;
514 if(i == -1) {
515 if(range->el_count) continue;
516 r = range;
517 } else {
518 if(i) OUT(" || ");
519 r = range->elements[i];
520 }
521
522 if(r != range) OUT("(");
523
524 ignore_left = (r->left.type == ARE_MIN)
525 || (natural_start != -1
526 && r->left.value <= natural_start);
527 ignore_right = (r->right.type == ARE_MAX)
528 || (natural_stop != -1
529 && r->right.value >= natural_stop);
530 if(ignore_left && ignore_right) {
531 OUT("1 /* Constraint matches natural range of %s */",
532 varname);
533 continue;
534 }
535
536 if(ignore_left) {
Lev Walkin63b41262007-11-06 01:48:46 +0000537 OUT("%s <= ", varname);
538 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000539 } else if(ignore_right) {
Lev Walkin63b41262007-11-06 01:48:46 +0000540 OUT("%s >= ", varname);
541 OINT(r->left.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000542 } else if(r->left.value == r->right.value) {
Lev Walkin63b41262007-11-06 01:48:46 +0000543 OUT("%s == ", varname);
544 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000545 } else {
Lev Walkin63b41262007-11-06 01:48:46 +0000546 OUT("%s >= ", varname);
547 OINT(r->left.value);
548 OUT(" && ");
549 OUT("%s <= ", varname);
550 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000551 }
552 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000553 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000554 }
555
Lev Walkin59004fa2004-08-20 13:37:01 +0000556 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000557}
558
559static int
560emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
561
562 switch(etype) {
563 case ASN_BASIC_BIT_STRING:
564 OUT("if(st->size > 0) {\n");
565 OUT("\t/* Size in bits */\n");
Lev Walkindcf1e352006-09-08 19:34:22 +0000566 OUT("\tsize = 8 * st->size - (st->bits_unused & 0x07);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000567 OUT("} else {\n");
568 OUT("\tsize = 0;\n");
569 OUT("}\n");
570 break;
571 case ASN_STRING_UniversalString:
572 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
573 break;
574 case ASN_STRING_BMPString:
575 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
576 break;
577 case ASN_STRING_UTF8String:
Lev Walkin29c41682004-10-02 16:44:55 +0000578 OUT("size = UTF8String_length(st);\n");
579 OUT("if((ssize_t)size < 0) {\n");
Lev Walkin7c1dc052016-03-14 03:08:15 -0700580 OUT("\tASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin29c41682004-10-02 16:44:55 +0000581 OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
582 OUT("\t\ttd->name, __FILE__, __LINE__);\n");
583 OUT("\treturn -1;\n");
584 OUT("}\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000585 break;
586 case ASN_CONSTR_SET_OF:
587 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkinf1a51232005-07-04 02:01:03 +0000588 OUT("/* Determine the number of elements */\n");
589 OUT("size = _A_C%s_FROM_VOID(sptr)->count;\n",
590 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000591 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000592 case ASN_BASIC_OCTET_STRING:
593 OUT("size = st->size;\n");
594 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000595 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000596 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000597 OUT("size = st->size;\n");
598 break;
599 } else {
600 const char *type_name = ASN_EXPR_TYPE2STR(etype);
601 if(!type_name) type_name = arg->expr->Identifier;
602 WARNING("SizeConstraint is not defined for %s",
603 type_name);
604 OUT_NOINDENT("#warning SizeConstraint "
605 "is not defined for %s!\n", type_name);
606 OUT("size = st->size;\n");
607 }
608 return -1;
609 }
610
611 return 0;
612}
613
614static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000615emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000616
617 switch(etype) {
618 case ASN_BASIC_INTEGER:
619 case ASN_BASIC_ENUMERATED:
Lev Walkin8bb57a22007-12-03 13:41:36 +0000620 if(asn1c_type_fits_long(arg, arg->expr) == FL_FITS_UNSIGN) {
621 OUT("value = *(const unsigned long *)sptr;\n");
622 } else if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) {
Lev Walkine0b56e02005-02-25 12:10:27 +0000623 OUT("value = *(const long *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000624 } else {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000625 /*
626 * In some cases we can explore our knowledge of
627 * underlying INTEGER_t->buf format.
628 */
Lev Walkin6ea088f2004-09-07 06:31:15 +0000629 if(r_value->el_count == 0
630 && (
631 /* Speed-up common case: (0..MAX) */
632 (r_value->left.type == ARE_VALUE
633 && r_value->left.value == 0
634 && r_value->right.type == ARE_MAX)
635 ||
636 /* Speed-up common case: (MIN..-1) */
637 (r_value->left.type == ARE_MIN
638 && r_value->right.type == ARE_VALUE
639 && r_value->right.value == -1)
640 )) {
641 OUT("/* Check if the sign bit is present */\n");
642 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
643 break;
644 }
645
Lev Walkine0f2a5b2017-08-30 20:02:29 -0700646 if(native_long_sign(arg, r_value) >= 0) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000647 /* Special case for treating unsigned longs */
648 OUT("if(asn_INTEGER2ulong(st, &value)) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000649 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700650 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000651 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
652 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000653 OUT("return -1;\n");
654 INDENT(-1);
Lev Walkin8bb57a22007-12-03 13:41:36 +0000655 OUT("}\n");
656 } else {
657 OUT("if(asn_INTEGER2long(st, &value)) {\n");
658 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700659 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin8bb57a22007-12-03 13:41:36 +0000660 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
661 OUT("\ttd->name, __FILE__, __LINE__);\n");
662 OUT("return -1;\n");
663 INDENT(-1);
664 OUT("}\n");
665 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000666 }
667 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000668 case ASN_BASIC_REAL:
Lev Walkin2a744a72013-03-27 01:56:23 -0700669 if(arg->flags & A1C_USE_WIDE_TYPES) {
Lev Walkin05363a72004-09-29 13:16:40 +0000670 OUT("if(asn_REAL2double(st, &value)) {\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000671 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700672 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000673 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
674 OUT("\ttd->name, __FILE__, __LINE__);\n");
675 OUT("return -1;\n");
676 INDENT(-1);
677 OUT("}\n");
Lev Walkin2a744a72013-03-27 01:56:23 -0700678 } else {
679 OUT("value = *(const double *)sptr;\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000680 }
681 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000682 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000683 OUT("value = (*(const long *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000684 break;
685 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000686 WARNING("%s:%d: Value cannot be determined "
687 "for constraint check for %s",
Lev Walkinb85a8132005-08-18 13:38:19 +0000688 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000689 arg->expr->_lineno,
690 arg->expr->Identifier
691 );
692 OUT_NOINDENT(
693 "#error %s:%d: Value of %s cannot be determined\n",
Lev Walkinb85a8132005-08-18 13:38:19 +0000694 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000695 arg->expr->_lineno,
696 arg->expr->Identifier
697 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000698 break;
699 }
700
701 return 0;
702}
703
704static asn1p_expr_type_e
705_find_terminal_type(arg_t *arg) {
706 asn1p_expr_t *expr;
Lev Walkinc0e03b92017-08-22 01:48:23 -0700707 expr = asn1f_find_terminal_type_ex(arg->asn, arg->ns, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000708 if(expr) return expr->expr_type;
709 return A1TC_INVALID;
710}
711
Lev Walkin8bb57a22007-12-03 13:41:36 +0000712static int
Lev Walkine0f2a5b2017-08-30 20:02:29 -0700713native_long_sign(arg_t *arg, asn1cnst_range_t *r) {
714 if(!(arg->flags & A1C_USE_WIDE_TYPES) && r->left.type == ARE_VALUE
715 && r->left.value >= 0 && r->left.value <= 2147483647
716 && r->right.type == ARE_MAX) {
717 return 1;
718 }
Lev Walkin8bb57a22007-12-03 13:41:36 +0000719 if(r->left.type == ARE_VALUE
720 && r->left.value >= 0
721 && r->right.type == ARE_VALUE
Lev Walkin5b63acf2014-01-14 01:48:37 -0800722 && r->right.value > 2147483647
Lev Walkin1b3a1352016-01-10 13:15:02 -0800723 && r->right.value <= (asn1c_integer_t)(4294967295UL)) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000724 if(r->el_count == 0
725 && r->left.value == 0
726 && r->right.value == 4294967295UL)
727 return 0;
728 else
729 return 1;
730 } else {
731 return -1;
732 }
733}