blob: 52874b3a0c2ec84e020327b1b65135ccc16ee045 [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 Walkinb5450702017-10-04 02:52:57 -07005#include "asn1c_naming.h"
Lev Walkin84cd58e2004-08-19 13:29:46 +00006
7#include <asn1fix_crange.h> /* constraint groker from libasn1fix */
Lev Walkin59b176e2005-11-26 11:25:14 +00008#include <asn1fix_export.h> /* other exportables from libasn1fix */
Lev Walkin84cd58e2004-08-19 13:29:46 +00009
Lev Walkin59004fa2004-08-20 13:37:01 +000010static int asn1c_emit_constraint_tables(arg_t *arg, int got_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +000011static int emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range);
Lev Walkin6ea088f2004-09-07 06:31:15 +000012static 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 +000013static int emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype);
14static asn1p_expr_type_e _find_terminal_type(arg_t *arg);
Lev Walkin05363a72004-09-29 13:16:40 +000015static 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 -070016static int native_long_sign(arg_t *arg, asn1cnst_range_t *r); /* -1, 0, 1 */
Lev Walkin84cd58e2004-08-19 13:29:46 +000017
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020018static int
Lev Walkine0f2a5b2017-08-30 20:02:29 -070019ulong_optimization(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_size,
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020020 asn1cnst_range_t *r_value)
21{
22 return (!r_size && r_value
23 && (etype == ASN_BASIC_INTEGER
24 || etype == ASN_BASIC_ENUMERATED)
Lev Walkine0f2a5b2017-08-30 20:02:29 -070025 && native_long_sign(arg, r_value) == 0);
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020026}
27
Lev Walkin84cd58e2004-08-19 13:29:46 +000028int
29asn1c_emit_constraint_checking_code(arg_t *arg) {
30 asn1cnst_range_t *r_size;
31 asn1cnst_range_t *r_value;
32 asn1p_expr_t *expr = arg->expr;
33 asn1p_expr_type_e etype;
34 asn1p_constraint_t *ct;
35 int got_something = 0;
Lev Walkin6938d042005-03-04 23:23:50 +000036 int alphabet_table_compiled;
Lev Walkin59004fa2004-08-20 13:37:01 +000037 int produce_st = 0;
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020038 int ulong_optimize = 0;
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +080039 int ret = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +000040
41 ct = expr->combined_constraints;
42 if(ct == NULL)
43 return 1; /* No additional constraints defined */
44
45 etype = _find_terminal_type(arg);
46
Lev Walkina28cbb92017-07-31 20:20:17 -070047 r_value=asn1constraint_compute_constraint_range(expr->Identifier, etype, ct, ACT_EL_RANGE,0,0,0);
48 r_size =asn1constraint_compute_constraint_range(expr->Identifier, etype, ct, ACT_CT_SIZE, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +000049 if(r_value) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000050 if(r_value->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000051 || r_value->empty_constraint
52 || (r_value->left.type == ARE_MIN
53 && r_value->right.type == ARE_MAX)
54 || (etype == ASN_BASIC_BOOLEAN
55 && r_value->left.value == 0
56 && r_value->right.value == 1)
57 ) {
58 asn1constraint_range_free(r_value);
59 r_value = 0;
60 }
61 }
62 if(r_size) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000063 if(r_size->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000064 || r_size->empty_constraint
65 || (r_size->left.value == 0 /* or .type == MIN */
66 && r_size->right.type == ARE_MAX)
67 ) {
68 asn1constraint_range_free(r_size);
69 r_size = 0;
70 }
71 }
72
Lev Walkin59004fa2004-08-20 13:37:01 +000073 /*
74 * Do we really need an "*st = sptr" pointer?
75 */
76 switch(etype) {
77 case ASN_BASIC_INTEGER:
78 case ASN_BASIC_ENUMERATED:
Lev Walkin082cadc2005-08-14 02:18:27 +000079 if(asn1c_type_fits_long(arg, arg->expr) == FL_NOTFIT)
80 produce_st = 1;
81 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +000082 case ASN_BASIC_REAL:
Lev Walkin43292722017-10-05 00:33:32 -070083 if((arg->flags & A1C_USE_WIDE_TYPES)
84 && asn1c_REAL_fits(arg, arg->expr) == RL_NOTFIT)
85 produce_st = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +000086 break;
Lev Walkin02b137d2004-08-21 07:34:58 +000087 case ASN_BASIC_BIT_STRING:
Lev Walkin59004fa2004-08-20 13:37:01 +000088 case ASN_BASIC_OCTET_STRING:
89 produce_st = 1;
Lev Walkin3a4689a2006-11-24 11:20:27 +000090 break;
Lev Walkin59004fa2004-08-20 13:37:01 +000091 default:
92 if(etype & ASN_STRING_MASK)
93 produce_st = 1;
94 break;
95 }
Lev Walkince31cdb2005-02-15 03:37:42 +000096 if(produce_st) {
Lev Walkincf3f6eb2017-08-23 04:34:15 -070097 const char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
Lev Walkince31cdb2005-02-15 03:37:42 +000098 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
99 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000100
101 if(r_size || r_value) {
102 if(r_size) {
103 OUT("size_t size;\n");
104 }
105 if(r_value)
106 switch(etype) {
107 case ASN_BASIC_INTEGER:
108 case ASN_BASIC_ENUMERATED:
Lev Walkine0f2a5b2017-08-30 20:02:29 -0700109 if(native_long_sign(arg, r_value) >= 0) {
110 ulong_optimize = ulong_optimization(arg, etype, r_size, r_value);
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200111 if(!ulong_optimize) {
112 OUT("unsigned long value;\n");
113 }
Lev Walkin8bb57a22007-12-03 13:41:36 +0000114 } else {
115 OUT("long value;\n");
116 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000117 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000118 case ASN_BASIC_REAL:
Lev Walkinb5450702017-10-04 02:52:57 -0700119 OUT("%s value;\n", c_name(arg).type.constrained_c_name);
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000120 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000121 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000122 OUT("BOOLEAN_t value;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000123 break;
124 default:
125 break;
126 }
127 }
128
129 OUT("\n");
130
131 /*
132 * Protection against null input.
133 */
134 OUT("if(!sptr) {\n");
135 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700136 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000137 OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
138 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000139 OUT("return -1;\n");
140 INDENT(-1);
141 OUT("}\n");
142 OUT("\n");
143
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200144 if((r_value) && (!ulong_optimize))
Lev Walkin6ea088f2004-09-07 06:31:15 +0000145 emit_value_determination_code(arg, etype, r_value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000146 if(r_size)
147 emit_size_determination_code(arg, etype);
148
Lev Walkin59004fa2004-08-20 13:37:01 +0000149 INDENT(-1);
150 REDIR(OT_CTABLES);
151 /* Emit FROM() tables */
Lev Walkin6938d042005-03-04 23:23:50 +0000152 alphabet_table_compiled =
153 (asn1c_emit_constraint_tables(arg, r_size?1:0) == 1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000154 REDIR(OT_CODE);
155 INDENT(+1);
156
Lev Walkin84cd58e2004-08-19 13:29:46 +0000157 /*
Lev Walkin8bb57a22007-12-03 13:41:36 +0000158 * Optimization for unsigned longs.
159 */
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200160 if(ulong_optimize) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000161 OUT("\n");
162 OUT("/* Constraint check succeeded */\n");
163 OUT("return 0;\n");
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800164 goto end;
Lev Walkin8bb57a22007-12-03 13:41:36 +0000165 }
166
167 /*
Lev Walkin729eb862006-09-21 01:50:13 +0000168 * Here is an if() {} else {} consrtaint checking code.
Lev Walkin84cd58e2004-08-19 13:29:46 +0000169 */
170 OUT("\n");
171 OUT("if(");
172 INDENT(+1);
173 if(r_size) {
174 if(got_something++) { OUT("\n"); OUT(" && "); }
175 OUT("(");
176 emit_range_comparison_code(arg, r_size, "size", 0, -1);
177 OUT(")");
178 }
179 if(r_value) {
180 if(got_something++) { OUT("\n"); OUT(" && "); }
181 OUT("(");
182 if(etype == ASN_BASIC_BOOLEAN)
183 emit_range_comparison_code(arg, r_value,
184 "value", 0, 1);
185 else
186 emit_range_comparison_code(arg, r_value,
187 "value", -1, -1);
188 OUT(")");
189 }
Lev Walkin6938d042005-03-04 23:23:50 +0000190 if(alphabet_table_compiled) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000191 if(got_something++) { OUT("\n"); OUT(" && "); }
Lev Walkin6938d042005-03-04 23:23:50 +0000192 OUT("!check_permitted_alphabet_%d(%s)",
193 arg->expr->_type_unique_index,
194 produce_st ? "st" : "sptr");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000195 }
196 if(!got_something) {
197 OUT("1 /* No applicable constraints whatsoever */");
Lev Walkin59004fa2004-08-20 13:37:01 +0000198 OUT(") {\n");
199 INDENT(-1);
johvikbd3dea92017-05-09 10:20:51 +0200200 if(produce_st) {
201 INDENTED(OUT("(void)st; /* Unused variable */\n"));
202 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000203 INDENTED(OUT("/* Nothing is here. See below */\n"));
204 OUT("}\n");
205 OUT("\n");
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800206 ret = 1;
207 goto end;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000208 }
209 INDENT(-1);
210 OUT(") {\n");
211 INDENT(+1);
Lev Walkin7ef83a42005-03-29 19:04:24 +0000212 switch(etype) {
213 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkin7ef83a42005-03-29 19:04:24 +0000214 case ASN_CONSTR_SET_OF:
215 OUT("/* Perform validation of the inner elements */\n");
Lev Walkin14e75ed2017-09-29 23:15:02 -0700216 OUT("return td->encoding_constraints.general_constraints(td, sptr, ctfailcb, app_key);\n");
Lev Walkin7ef83a42005-03-29 19:04:24 +0000217 break;
218 default:
219 OUT("/* Constraint check succeeded */\n");
220 OUT("return 0;\n");
221 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000222 INDENT(-1);
223 OUT("} else {\n");
224 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700225 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000226 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
227 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000228 OUT("return -1;\n");
229 INDENT(-1);
230 OUT("}\n");
231
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800232end:
233 if (r_value) asn1constraint_range_free(r_value);
234 if (r_size) asn1constraint_range_free(r_size);
235
236 return ret;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000237}
238
Lev Walkin59004fa2004-08-20 13:37:01 +0000239static int
240asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin05363a72004-09-29 13:16:40 +0000241 asn1c_integer_t range_start;
242 asn1c_integer_t range_stop;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000243 asn1p_expr_type_e etype;
244 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000245 asn1p_constraint_t *ct;
246 int utf8_full_alphabet_check = 0;
247 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000248 int table[256];
249 int use_table;
250
Lev Walkin59004fa2004-08-20 13:37:01 +0000251 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000252 if(!ct) return 0;
253
254 etype = _find_terminal_type(arg);
255
Lev Walkina28cbb92017-07-31 20:20:17 -0700256 range = asn1constraint_compute_constraint_range(arg->expr->Identifier, etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000257 if(!range) return 0;
258
Lev Walkinbe717ec2004-08-25 02:03:59 +0000259 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000260 || range->empty_constraint) {
261 asn1constraint_range_free(range);
262 return 0;
263 }
264
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000265 if(range->left.type == ARE_MIN
266 && range->right.type == ARE_MAX) {
267 /*
268 * The permitted alphabet constraint checker code guarantees
269 * that either both bounds (left/right) are present, or
270 * they're absent simultaneously. Thus, this assertion
271 * legitimately holds true.
272 */
273 assert(range->el_count == 0);
274 /* The full range is specified. Ignore it. */
Bi-Ruei, Chiu3dcf05b2017-05-04 21:45:05 +0800275 asn1constraint_range_free(range);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000276 return 0;
277 }
278
Lev Walkin84cd58e2004-08-19 13:29:46 +0000279 range_start = range->left.value;
280 range_stop = range->right.value;
281 assert(range->left.type == ARE_VALUE);
282 assert(range->right.type == ARE_VALUE);
283 assert(range_start <= range_stop);
284
285 range_start = 0; /* Force old behavior */
286
287 /*
288 * Check if we need a test table to check the alphabet.
289 */
290 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000291 if(range->el_count == 0) {
292 /*
293 * It's better to have a short if() check
Lev Walkin729eb862006-09-21 01:50:13 +0000294 * than waste 1k of table space
Lev Walkin59004fa2004-08-20 13:37:01 +0000295 */
296 use_table = 0;
297 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000298 if((range_stop - range_start) > 255)
299 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000300 if(etype == ASN_STRING_UTF8String) {
301 if(range_stop >= 0x80)
302 use_table = 0;
303 else
304 max_table_size = 128;
305 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000306
Lev Walkin84cd58e2004-08-19 13:29:46 +0000307 if(use_table) {
Lev Walkin729eb862006-09-21 01:50:13 +0000308 int cardinal = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000309 int i, n = 0;
310 int untl;
311 memset(table, 0, sizeof(table));
312 for(i = -1; i < range->el_count; i++) {
313 asn1cnst_range_t *r;
Lev Walkin05363a72004-09-29 13:16:40 +0000314 asn1c_integer_t v;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000315 if(i == -1) {
316 if(range->el_count) continue;
317 r = range;
318 } else {
319 r = range->elements[i];
320 }
321 for(v = r->left.value; v <= r->right.value; v++) {
322 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000323 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000324 table[v - range_start] = ++n;
325 }
326 }
327
Lev Walkin84cd58e2004-08-19 13:29:46 +0000328 untl = (range_stop - range_start) + 1;
329 untl += (untl % 16)?16 - (untl % 16):0;
Wim Lewisa73ae672014-07-22 19:55:30 -0700330 OUT("static const int permitted_alphabet_table_%d[%d] = {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000331 arg->expr->_type_unique_index, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000332 for(n = 0; n < untl; n++) {
Lev Walkin729eb862006-09-21 01:50:13 +0000333 cardinal += table[n] ? 1 : 0;
334 OUT("%2d,", table[n]);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000335 if(!((n+1) % 16)) {
336 int c;
Lev Walkin729eb862006-09-21 01:50:13 +0000337 if(!n || (n-15) + range_start >= 0x80) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000338 OUT("\n");
339 continue;
340 }
341 OUT("\t/* ");
342 for(c = n - 15; c <= n; c++) {
343 if(table[c]) {
344 int a = c + range_start;
345 if(a > 0x20 && a < 0x80)
346 OUT("%c", a);
347 else
348 OUT(".");
349 } else {
350 OUT(" ");
351 }
352 }
353 OUT(" */");
354 OUT("\n");
355 }
356 }
357 OUT("};\n");
Lev Walkin729eb862006-09-21 01:50:13 +0000358
Lev Walkin725883b2006-10-09 12:07:58 +0000359 if((arg->flags & A1C_GEN_PER)
360 && (etype & ASN_STRING_KM_MASK)) {
Lev Walkin729eb862006-09-21 01:50:13 +0000361 int c;
Wim Lewisa73ae672014-07-22 19:55:30 -0700362 OUT("static const int permitted_alphabet_code2value_%d[%d] = {\n",
Lev Walkin729eb862006-09-21 01:50:13 +0000363 arg->expr->_type_unique_index, cardinal);
364 for(n = c = 0; c < max_table_size; c++) {
365 if(table[c]) {
366 OUT("%d,", c);
367 if(!((++n) % 16)) OUT("\n");
368 }
369 }
370 OUT("};\n");
371 OUT("\n");
Lev Walkin725883b2006-10-09 12:07:58 +0000372 DEBUG("code2value map gen for %s", arg->expr->Identifier);
373 arg->expr->_mark |= TM_PERFROMCT;
Lev Walkin729eb862006-09-21 01:50:13 +0000374 }
375
Lev Walkin84cd58e2004-08-19 13:29:46 +0000376 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000377 } else if(etype == ASN_STRING_UTF8String) {
378 /*
379 * UTF8String type is a special case in many respects.
380 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000381 if(got_size) {
382 /*
383 * Size has been already determined.
384 * The UTF8String length checker also checks
385 * for the syntax validity, so we don't have
386 * to repeat this process twice.
387 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000388 asn1constraint_range_free(range);
389 return 0;
390 } else {
391 utf8_full_alphabet_check = 1;
392 }
393 } else {
394 /*
395 * This permitted alphabet check will be
396 * expressed using conditional statements
397 * instead of table lookups. Table would be
398 * to large or otherwise inappropriate (too sparse?).
399 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000400 }
401
402 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000403 arg->expr->_type_unique_index);
Lev Walkin59004fa2004-08-20 13:37:01 +0000404 INDENT(+1);
405 if(utf8_full_alphabet_check) {
Lev Walkin29c41682004-10-02 16:44:55 +0000406 OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
407 OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000408 OUT("\n");
409 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000410 if(use_table) {
Wim Lewisa73ae672014-07-22 19:55:30 -0700411 OUT("const int *table = permitted_alphabet_table_%d;\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000412 arg->expr->_type_unique_index);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000413 emit_alphabet_check_loop(arg, 0);
414 } else {
415 emit_alphabet_check_loop(arg, range);
416 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000417 }
Lev Walkin775885e2004-08-22 12:47:03 +0000418 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000419 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000420 OUT("}\n");
421 OUT("\n");
422
423 asn1constraint_range_free(range);
424
Lev Walkin6938d042005-03-04 23:23:50 +0000425 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000426}
427
428static int
429emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin05363a72004-09-29 13:16:40 +0000430 asn1c_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000431 asn1p_expr_t *terminal;
Lev Walkincf3f6eb2017-08-23 04:34:15 -0700432 const char *tname;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000433
Lev Walkinc0e03b92017-08-22 01:48:23 -0700434 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->ns, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000435 if(terminal) {
436 OUT("/* The underlying type is %s */\n",
437 ASN_EXPR_TYPE2STR(terminal->expr_type));
438 } else {
439 terminal = arg->expr;
440 }
Lev Walkince31cdb2005-02-15 03:37:42 +0000441 tname = asn1c_type_name(arg, terminal, TNF_SAFE);
442 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000443
Lev Walkin634a3b82004-08-22 03:30:05 +0000444 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000445 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000446 OUT("const uint8_t *ch = st->buf;\n");
447 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000448 OUT("\n");
449 OUT("for(; ch < end; ch++) {\n");
450 INDENT(+1);
451 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000452 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000453 natural_stop = 0xffffffffUL;
454 break;
455 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000456 OUT("const uint8_t *ch = st->buf;\n");
457 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000458 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000459 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
460 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000461 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000462 OUT("uint32_t cv = (ch[0] << 24)\n");
463 OUT("\t\t| (ch[1] << 16)\n");
464 OUT("\t\t| (ch[2] << 8)\n");
465 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000466 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000467 natural_stop = 0xffffffffUL;
468 break;
469 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000470 OUT("const uint8_t *ch = st->buf;\n");
471 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000472 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000473 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
474 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000475 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000476 OUT("uint16_t cv = (ch[0] << 8)\n");
477 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000478 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000479 natural_stop = 0xffff;
480 break;
481 case ASN_BASIC_OCTET_STRING:
482 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000483 OUT("const uint8_t *ch = st->buf;\n");
484 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000485 OUT("\n");
486 OUT("for(; ch < end; ch++) {\n");
487 INDENT(+1);
488 OUT("uint8_t cv = *ch;\n");
489 natural_stop = 0xff;
490 break;
491 }
492
493 if(range) {
494 OUT("if(!(");
Lev Walkin4bd9eaf2017-10-19 01:16:42 -0700495 int produced_something =
496 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
497 if(produced_something) {
498 OUT(")) return -1;\n");
499 } else {
500 OUT(")) {\n");
501 OUT("\t(void)cv; /* Unused variable */\n");
502 OUT("\treturn -1;\n");
503 OUT("}\n");
504 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000505 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000506 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000507 }
508
509 INDENT(-1);
510 OUT("}\n");
511
512 return 0;
513}
514
515static int
Lev Walkin05363a72004-09-29 13:16:40 +0000516emit_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 +0000517 int ignore_left;
518 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000519 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000520 int i;
521
522 for(i = -1; i < range->el_count; i++) {
523 asn1cnst_range_t *r;
524 if(i == -1) {
525 if(range->el_count) continue;
526 r = range;
527 } else {
528 if(i) OUT(" || ");
529 r = range->elements[i];
530 }
531
532 if(r != range) OUT("(");
533
534 ignore_left = (r->left.type == ARE_MIN)
535 || (natural_start != -1
536 && r->left.value <= natural_start);
537 ignore_right = (r->right.type == ARE_MAX)
538 || (natural_stop != -1
539 && r->right.value >= natural_stop);
540 if(ignore_left && ignore_right) {
541 OUT("1 /* Constraint matches natural range of %s */",
542 varname);
543 continue;
544 }
545
546 if(ignore_left) {
Lev Walkin63b41262007-11-06 01:48:46 +0000547 OUT("%s <= ", varname);
548 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000549 } else if(ignore_right) {
Lev Walkin63b41262007-11-06 01:48:46 +0000550 OUT("%s >= ", varname);
551 OINT(r->left.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000552 } else if(r->left.value == r->right.value) {
Lev Walkin63b41262007-11-06 01:48:46 +0000553 OUT("%s == ", varname);
554 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000555 } else {
Lev Walkin63b41262007-11-06 01:48:46 +0000556 OUT("%s >= ", varname);
557 OINT(r->left.value);
558 OUT(" && ");
559 OUT("%s <= ", varname);
560 OINT(r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000561 }
562 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000563 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000564 }
565
Lev Walkin59004fa2004-08-20 13:37:01 +0000566 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000567}
568
569static int
570emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
571
572 switch(etype) {
573 case ASN_BASIC_BIT_STRING:
574 OUT("if(st->size > 0) {\n");
575 OUT("\t/* Size in bits */\n");
Lev Walkindcf1e352006-09-08 19:34:22 +0000576 OUT("\tsize = 8 * st->size - (st->bits_unused & 0x07);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000577 OUT("} else {\n");
578 OUT("\tsize = 0;\n");
579 OUT("}\n");
580 break;
581 case ASN_STRING_UniversalString:
582 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
583 break;
584 case ASN_STRING_BMPString:
585 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
586 break;
587 case ASN_STRING_UTF8String:
Lev Walkin29c41682004-10-02 16:44:55 +0000588 OUT("size = UTF8String_length(st);\n");
589 OUT("if((ssize_t)size < 0) {\n");
Lev Walkin7c1dc052016-03-14 03:08:15 -0700590 OUT("\tASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin29c41682004-10-02 16:44:55 +0000591 OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
592 OUT("\t\ttd->name, __FILE__, __LINE__);\n");
593 OUT("\treturn -1;\n");
594 OUT("}\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000595 break;
596 case ASN_CONSTR_SET_OF:
597 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkinf1a51232005-07-04 02:01:03 +0000598 OUT("/* Determine the number of elements */\n");
599 OUT("size = _A_C%s_FROM_VOID(sptr)->count;\n",
600 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000601 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000602 case ASN_BASIC_OCTET_STRING:
603 OUT("size = st->size;\n");
604 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000605 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000606 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000607 OUT("size = st->size;\n");
608 break;
609 } else {
610 const char *type_name = ASN_EXPR_TYPE2STR(etype);
611 if(!type_name) type_name = arg->expr->Identifier;
612 WARNING("SizeConstraint is not defined for %s",
613 type_name);
614 OUT_NOINDENT("#warning SizeConstraint "
615 "is not defined for %s!\n", type_name);
616 OUT("size = st->size;\n");
617 }
618 return -1;
619 }
620
621 return 0;
622}
623
624static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000625emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000626
627 switch(etype) {
628 case ASN_BASIC_INTEGER:
629 case ASN_BASIC_ENUMERATED:
Lev Walkin8bb57a22007-12-03 13:41:36 +0000630 if(asn1c_type_fits_long(arg, arg->expr) == FL_FITS_UNSIGN) {
631 OUT("value = *(const unsigned long *)sptr;\n");
632 } else if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) {
Lev Walkine0b56e02005-02-25 12:10:27 +0000633 OUT("value = *(const long *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000634 } else {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000635 /*
636 * In some cases we can explore our knowledge of
637 * underlying INTEGER_t->buf format.
638 */
Lev Walkin6ea088f2004-09-07 06:31:15 +0000639 if(r_value->el_count == 0
640 && (
641 /* Speed-up common case: (0..MAX) */
642 (r_value->left.type == ARE_VALUE
643 && r_value->left.value == 0
644 && r_value->right.type == ARE_MAX)
645 ||
646 /* Speed-up common case: (MIN..-1) */
647 (r_value->left.type == ARE_MIN
648 && r_value->right.type == ARE_VALUE
649 && r_value->right.value == -1)
650 )) {
651 OUT("/* Check if the sign bit is present */\n");
652 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
653 break;
654 }
655
Lev Walkine0f2a5b2017-08-30 20:02:29 -0700656 if(native_long_sign(arg, r_value) >= 0) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000657 /* Special case for treating unsigned longs */
658 OUT("if(asn_INTEGER2ulong(st, &value)) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000659 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700660 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000661 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
662 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000663 OUT("return -1;\n");
664 INDENT(-1);
Lev Walkin8bb57a22007-12-03 13:41:36 +0000665 OUT("}\n");
666 } else {
667 OUT("if(asn_INTEGER2long(st, &value)) {\n");
668 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700669 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin8bb57a22007-12-03 13:41:36 +0000670 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
671 OUT("\ttd->name, __FILE__, __LINE__);\n");
672 OUT("return -1;\n");
673 INDENT(-1);
674 OUT("}\n");
675 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000676 }
677 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000678 case ASN_BASIC_REAL:
Lev Walkin2a744a72013-03-27 01:56:23 -0700679 if(arg->flags & A1C_USE_WIDE_TYPES) {
Lev Walkin05363a72004-09-29 13:16:40 +0000680 OUT("if(asn_REAL2double(st, &value)) {\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000681 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700682 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000683 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
684 OUT("\ttd->name, __FILE__, __LINE__);\n");
685 OUT("return -1;\n");
686 INDENT(-1);
687 OUT("}\n");
Lev Walkin2a744a72013-03-27 01:56:23 -0700688 } else {
Lev Walkinb5450702017-10-04 02:52:57 -0700689 OUT("value = *(const %s *)sptr;\n", c_name(arg).type.c_name);
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000690 }
691 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000692 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000693 OUT("value = (*(const long *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000694 break;
695 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000696 WARNING("%s:%d: Value cannot be determined "
697 "for constraint check for %s",
Lev Walkinb85a8132005-08-18 13:38:19 +0000698 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000699 arg->expr->_lineno,
700 arg->expr->Identifier
701 );
702 OUT_NOINDENT(
703 "#error %s:%d: Value of %s cannot be determined\n",
Lev Walkinb85a8132005-08-18 13:38:19 +0000704 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000705 arg->expr->_lineno,
706 arg->expr->Identifier
707 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000708 break;
709 }
710
711 return 0;
712}
713
714static asn1p_expr_type_e
715_find_terminal_type(arg_t *arg) {
716 asn1p_expr_t *expr;
Lev Walkinc0e03b92017-08-22 01:48:23 -0700717 expr = asn1f_find_terminal_type_ex(arg->asn, arg->ns, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000718 if(expr) return expr->expr_type;
719 return A1TC_INVALID;
720}
721
Lev Walkin8bb57a22007-12-03 13:41:36 +0000722static int
Lev Walkine0f2a5b2017-08-30 20:02:29 -0700723native_long_sign(arg_t *arg, asn1cnst_range_t *r) {
724 if(!(arg->flags & A1C_USE_WIDE_TYPES) && r->left.type == ARE_VALUE
725 && r->left.value >= 0 && r->left.value <= 2147483647
726 && r->right.type == ARE_MAX) {
727 return 1;
728 }
Lev Walkin8bb57a22007-12-03 13:41:36 +0000729 if(r->left.type == ARE_VALUE
730 && r->left.value >= 0
731 && r->right.type == ARE_VALUE
Lev Walkin5b63acf2014-01-14 01:48:37 -0800732 && r->right.value > 2147483647
Lev Walkin1b3a1352016-01-10 13:15:02 -0800733 && r->right.value <= (asn1c_integer_t)(4294967295UL)) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000734 if(r->el_count == 0
735 && r->left.value == 0
736 && r->right.value == 4294967295UL)
737 return 0;
738 else
739 return 1;
740 } else {
741 return -1;
742 }
743}