blob: 024232125fef314e487ebc28f88977a3a8b035b9 [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 Walkinbc09dd42017-10-19 02:16:35 -070015static abuf *emit_range_comparison_code(asn1cnst_range_t *range,
16 const char *varname,
17 asn1c_integer_t natural_start,
18 asn1c_integer_t natural_stop);
Lev Walkine0f2a5b2017-08-30 20:02:29 -070019static int native_long_sign(arg_t *arg, asn1cnst_range_t *r); /* -1, 0, 1 */
Lev Walkin84cd58e2004-08-19 13:29:46 +000020
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020021static int
Lev Walkine0f2a5b2017-08-30 20:02:29 -070022ulong_optimization(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_size,
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020023 asn1cnst_range_t *r_value)
24{
25 return (!r_size && r_value
26 && (etype == ASN_BASIC_INTEGER
27 || etype == ASN_BASIC_ENUMERATED)
Lev Walkine0f2a5b2017-08-30 20:02:29 -070028 && native_long_sign(arg, r_value) == 0);
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020029}
30
Lev Walkin84cd58e2004-08-19 13:29:46 +000031int
32asn1c_emit_constraint_checking_code(arg_t *arg) {
33 asn1cnst_range_t *r_size;
34 asn1cnst_range_t *r_value;
35 asn1p_expr_t *expr = arg->expr;
36 asn1p_expr_type_e etype;
37 asn1p_constraint_t *ct;
Lev Walkin6938d042005-03-04 23:23:50 +000038 int alphabet_table_compiled;
Lev Walkin59004fa2004-08-20 13:37:01 +000039 int produce_st = 0;
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +020040 int ulong_optimize = 0;
Lev Walkinbc09dd42017-10-19 02:16:35 -070041 int value_unsigned = 0;
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +080042 int ret = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +000043
44 ct = expr->combined_constraints;
45 if(ct == NULL)
46 return 1; /* No additional constraints defined */
47
48 etype = _find_terminal_type(arg);
49
Lev Walkina28cbb92017-07-31 20:20:17 -070050 r_value=asn1constraint_compute_constraint_range(expr->Identifier, etype, ct, ACT_EL_RANGE,0,0,0);
51 r_size =asn1constraint_compute_constraint_range(expr->Identifier, etype, ct, ACT_CT_SIZE, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +000052 if(r_value) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000053 if(r_value->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000054 || r_value->empty_constraint
55 || (r_value->left.type == ARE_MIN
56 && r_value->right.type == ARE_MAX)
57 || (etype == ASN_BASIC_BOOLEAN
58 && r_value->left.value == 0
59 && r_value->right.value == 1)
60 ) {
61 asn1constraint_range_free(r_value);
62 r_value = 0;
63 }
64 }
65 if(r_size) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000066 if(r_size->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000067 || r_size->empty_constraint
68 || (r_size->left.value == 0 /* or .type == MIN */
69 && r_size->right.type == ARE_MAX)
70 ) {
71 asn1constraint_range_free(r_size);
72 r_size = 0;
73 }
74 }
75
Lev Walkin59004fa2004-08-20 13:37:01 +000076 /*
77 * Do we really need an "*st = sptr" pointer?
78 */
79 switch(etype) {
80 case ASN_BASIC_INTEGER:
81 case ASN_BASIC_ENUMERATED:
Lev Walkin082cadc2005-08-14 02:18:27 +000082 if(asn1c_type_fits_long(arg, arg->expr) == FL_NOTFIT)
83 produce_st = 1;
84 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +000085 case ASN_BASIC_REAL:
Lev Walkin43292722017-10-05 00:33:32 -070086 if((arg->flags & A1C_USE_WIDE_TYPES)
87 && asn1c_REAL_fits(arg, arg->expr) == RL_NOTFIT)
88 produce_st = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +000089 break;
Lev Walkin02b137d2004-08-21 07:34:58 +000090 case ASN_BASIC_BIT_STRING:
Lev Walkin59004fa2004-08-20 13:37:01 +000091 case ASN_BASIC_OCTET_STRING:
92 produce_st = 1;
Lev Walkin3a4689a2006-11-24 11:20:27 +000093 break;
Lev Walkin59004fa2004-08-20 13:37:01 +000094 default:
95 if(etype & ASN_STRING_MASK)
96 produce_st = 1;
97 break;
98 }
Lev Walkince31cdb2005-02-15 03:37:42 +000099 if(produce_st) {
Lev Walkincf3f6eb2017-08-23 04:34:15 -0700100 const char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
Lev Walkince31cdb2005-02-15 03:37:42 +0000101 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
102 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000103
104 if(r_size || r_value) {
105 if(r_size) {
106 OUT("size_t size;\n");
107 }
108 if(r_value)
109 switch(etype) {
110 case ASN_BASIC_INTEGER:
111 case ASN_BASIC_ENUMERATED:
Lev Walkine0f2a5b2017-08-30 20:02:29 -0700112 if(native_long_sign(arg, r_value) >= 0) {
113 ulong_optimize = ulong_optimization(arg, etype, r_size, r_value);
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200114 if(!ulong_optimize) {
Lev Walkinbc09dd42017-10-19 02:16:35 -0700115 value_unsigned = 1;
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200116 OUT("unsigned long value;\n");
117 }
Lev Walkin8bb57a22007-12-03 13:41:36 +0000118 } else {
119 OUT("long value;\n");
120 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000121 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000122 case ASN_BASIC_REAL:
Lev Walkinb5450702017-10-04 02:52:57 -0700123 OUT("%s value;\n", c_name(arg).type.constrained_c_name);
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000124 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000125 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000126 OUT("BOOLEAN_t value;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000127 break;
128 default:
129 break;
130 }
131 }
132
133 OUT("\n");
134
135 /*
136 * Protection against null input.
137 */
138 OUT("if(!sptr) {\n");
139 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700140 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000141 OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
142 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000143 OUT("return -1;\n");
144 INDENT(-1);
145 OUT("}\n");
146 OUT("\n");
147
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200148 if((r_value) && (!ulong_optimize))
Lev Walkin6ea088f2004-09-07 06:31:15 +0000149 emit_value_determination_code(arg, etype, r_value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000150 if(r_size)
151 emit_size_determination_code(arg, etype);
152
Lev Walkin59004fa2004-08-20 13:37:01 +0000153 INDENT(-1);
154 REDIR(OT_CTABLES);
155 /* Emit FROM() tables */
Lev Walkin6938d042005-03-04 23:23:50 +0000156 alphabet_table_compiled =
157 (asn1c_emit_constraint_tables(arg, r_size?1:0) == 1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000158 REDIR(OT_CODE);
159 INDENT(+1);
160
Lev Walkin84cd58e2004-08-19 13:29:46 +0000161 /*
Lev Walkin8bb57a22007-12-03 13:41:36 +0000162 * Optimization for unsigned longs.
163 */
Santiago Carot-Nemesio8da8e732011-04-22 13:21:33 +0200164 if(ulong_optimize) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000165 OUT("\n");
166 OUT("/* Constraint check succeeded */\n");
167 OUT("return 0;\n");
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800168 goto end;
Lev Walkin8bb57a22007-12-03 13:41:36 +0000169 }
170
171 /*
Lev Walkin729eb862006-09-21 01:50:13 +0000172 * Here is an if() {} else {} consrtaint checking code.
Lev Walkin84cd58e2004-08-19 13:29:46 +0000173 */
Lev Walkinbc09dd42017-10-19 02:16:35 -0700174 int got_something = 0;
175 int value_unused = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000176 OUT("\n");
177 OUT("if(");
178 INDENT(+1);
179 if(r_size) {
Lev Walkinbc09dd42017-10-19 02:16:35 -0700180 abuf *ab = emit_range_comparison_code(r_size, "size", 0, -1);
181 if(ab->length) {
182 OUT("(%s)", ab->buffer);
183 got_something++;
184 }
185 abuf_free(ab);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000186 }
187 if(r_value) {
Lev Walkinbc09dd42017-10-19 02:16:35 -0700188 if(got_something) { OUT("\n"); OUT(" && "); }
189 abuf *ab;
190 if(etype == ASN_BASIC_BOOLEAN)
191 ab = emit_range_comparison_code(r_value, "value", 0, 1);
192 else
193 ab = emit_range_comparison_code(r_value, "value",
194 value_unsigned ? 0 : -1, -1);
195 if(ab->length) {
196 OUT("(%s)", ab->buffer);
197 got_something++;
198 } else {
199 value_unused = 1;
200 }
201 abuf_free(ab);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000202 }
Lev Walkin6938d042005-03-04 23:23:50 +0000203 if(alphabet_table_compiled) {
Lev Walkinbc09dd42017-10-19 02:16:35 -0700204 if(got_something) { OUT("\n"); OUT(" && "); }
Lev Walkin6938d042005-03-04 23:23:50 +0000205 OUT("!check_permitted_alphabet_%d(%s)",
206 arg->expr->_type_unique_index,
207 produce_st ? "st" : "sptr");
Lev Walkinbc09dd42017-10-19 02:16:35 -0700208 got_something++;
209 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000210 if(!got_something) {
211 OUT("1 /* No applicable constraints whatsoever */");
Lev Walkin59004fa2004-08-20 13:37:01 +0000212 OUT(") {\n");
213 INDENT(-1);
johvikbd3dea92017-05-09 10:20:51 +0200214 if(produce_st) {
215 INDENTED(OUT("(void)st; /* Unused variable */\n"));
216 }
Lev Walkinbc09dd42017-10-19 02:16:35 -0700217 if(value_unused) {
218 INDENTED(OUT("(void)value; /* Unused variable */\n"));
219 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000220 INDENTED(OUT("/* Nothing is here. See below */\n"));
221 OUT("}\n");
222 OUT("\n");
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800223 ret = 1;
224 goto end;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000225 }
226 INDENT(-1);
227 OUT(") {\n");
228 INDENT(+1);
Lev Walkin7ef83a42005-03-29 19:04:24 +0000229 switch(etype) {
230 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkin7ef83a42005-03-29 19:04:24 +0000231 case ASN_CONSTR_SET_OF:
232 OUT("/* Perform validation of the inner elements */\n");
Lev Walkin14e75ed2017-09-29 23:15:02 -0700233 OUT("return td->encoding_constraints.general_constraints(td, sptr, ctfailcb, app_key);\n");
Lev Walkin7ef83a42005-03-29 19:04:24 +0000234 break;
235 default:
236 OUT("/* Constraint check succeeded */\n");
237 OUT("return 0;\n");
238 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000239 INDENT(-1);
240 OUT("} else {\n");
241 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700242 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000243 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
244 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000245 OUT("return -1;\n");
246 INDENT(-1);
247 OUT("}\n");
248
Bi-Ruei, Chiu64505ef2016-11-08 13:59:29 +0800249end:
250 if (r_value) asn1constraint_range_free(r_value);
251 if (r_size) asn1constraint_range_free(r_size);
252
253 return ret;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000254}
255
Lev Walkin59004fa2004-08-20 13:37:01 +0000256static int
257asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin05363a72004-09-29 13:16:40 +0000258 asn1c_integer_t range_start;
259 asn1c_integer_t range_stop;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000260 asn1p_expr_type_e etype;
261 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000262 asn1p_constraint_t *ct;
263 int utf8_full_alphabet_check = 0;
264 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000265 int table[256];
266 int use_table;
267
Lev Walkin59004fa2004-08-20 13:37:01 +0000268 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000269 if(!ct) return 0;
270
271 etype = _find_terminal_type(arg);
272
Lev Walkina28cbb92017-07-31 20:20:17 -0700273 range = asn1constraint_compute_constraint_range(arg->expr->Identifier, etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000274 if(!range) return 0;
275
Lev Walkinbe717ec2004-08-25 02:03:59 +0000276 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000277 || range->empty_constraint) {
278 asn1constraint_range_free(range);
279 return 0;
280 }
281
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000282 if(range->left.type == ARE_MIN
283 && range->right.type == ARE_MAX) {
284 /*
285 * The permitted alphabet constraint checker code guarantees
286 * that either both bounds (left/right) are present, or
287 * they're absent simultaneously. Thus, this assertion
288 * legitimately holds true.
289 */
290 assert(range->el_count == 0);
291 /* The full range is specified. Ignore it. */
Bi-Ruei, Chiu3dcf05b2017-05-04 21:45:05 +0800292 asn1constraint_range_free(range);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000293 return 0;
294 }
295
Lev Walkin84cd58e2004-08-19 13:29:46 +0000296 range_start = range->left.value;
297 range_stop = range->right.value;
298 assert(range->left.type == ARE_VALUE);
299 assert(range->right.type == ARE_VALUE);
300 assert(range_start <= range_stop);
301
302 range_start = 0; /* Force old behavior */
303
304 /*
305 * Check if we need a test table to check the alphabet.
306 */
307 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000308 if(range->el_count == 0) {
309 /*
310 * It's better to have a short if() check
Lev Walkin729eb862006-09-21 01:50:13 +0000311 * than waste 1k of table space
Lev Walkin59004fa2004-08-20 13:37:01 +0000312 */
313 use_table = 0;
314 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000315 if((range_stop - range_start) > 255)
316 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000317 if(etype == ASN_STRING_UTF8String) {
318 if(range_stop >= 0x80)
319 use_table = 0;
320 else
321 max_table_size = 128;
322 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000323
Lev Walkin84cd58e2004-08-19 13:29:46 +0000324 if(use_table) {
Lev Walkin729eb862006-09-21 01:50:13 +0000325 int cardinal = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000326 int i, n = 0;
327 int untl;
328 memset(table, 0, sizeof(table));
329 for(i = -1; i < range->el_count; i++) {
330 asn1cnst_range_t *r;
Lev Walkin05363a72004-09-29 13:16:40 +0000331 asn1c_integer_t v;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000332 if(i == -1) {
333 if(range->el_count) continue;
334 r = range;
335 } else {
336 r = range->elements[i];
337 }
338 for(v = r->left.value; v <= r->right.value; v++) {
339 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000340 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000341 table[v - range_start] = ++n;
342 }
343 }
344
Lev Walkin84cd58e2004-08-19 13:29:46 +0000345 untl = (range_stop - range_start) + 1;
346 untl += (untl % 16)?16 - (untl % 16):0;
Wim Lewisa73ae672014-07-22 19:55:30 -0700347 OUT("static const int permitted_alphabet_table_%d[%d] = {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000348 arg->expr->_type_unique_index, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000349 for(n = 0; n < untl; n++) {
Lev Walkin729eb862006-09-21 01:50:13 +0000350 cardinal += table[n] ? 1 : 0;
351 OUT("%2d,", table[n]);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000352 if(!((n+1) % 16)) {
353 int c;
Lev Walkin729eb862006-09-21 01:50:13 +0000354 if(!n || (n-15) + range_start >= 0x80) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000355 OUT("\n");
356 continue;
357 }
358 OUT("\t/* ");
359 for(c = n - 15; c <= n; c++) {
360 if(table[c]) {
361 int a = c + range_start;
362 if(a > 0x20 && a < 0x80)
363 OUT("%c", a);
364 else
365 OUT(".");
366 } else {
367 OUT(" ");
368 }
369 }
370 OUT(" */");
371 OUT("\n");
372 }
373 }
374 OUT("};\n");
Lev Walkin729eb862006-09-21 01:50:13 +0000375
Lev Walkin725883b2006-10-09 12:07:58 +0000376 if((arg->flags & A1C_GEN_PER)
377 && (etype & ASN_STRING_KM_MASK)) {
Lev Walkin729eb862006-09-21 01:50:13 +0000378 int c;
Wim Lewisa73ae672014-07-22 19:55:30 -0700379 OUT("static const int permitted_alphabet_code2value_%d[%d] = {\n",
Lev Walkin729eb862006-09-21 01:50:13 +0000380 arg->expr->_type_unique_index, cardinal);
381 for(n = c = 0; c < max_table_size; c++) {
382 if(table[c]) {
383 OUT("%d,", c);
384 if(!((++n) % 16)) OUT("\n");
385 }
386 }
387 OUT("};\n");
388 OUT("\n");
Lev Walkin725883b2006-10-09 12:07:58 +0000389 DEBUG("code2value map gen for %s", arg->expr->Identifier);
390 arg->expr->_mark |= TM_PERFROMCT;
Lev Walkin729eb862006-09-21 01:50:13 +0000391 }
392
Lev Walkin84cd58e2004-08-19 13:29:46 +0000393 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000394 } else if(etype == ASN_STRING_UTF8String) {
395 /*
396 * UTF8String type is a special case in many respects.
397 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000398 if(got_size) {
399 /*
400 * Size has been already determined.
401 * The UTF8String length checker also checks
402 * for the syntax validity, so we don't have
403 * to repeat this process twice.
404 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000405 asn1constraint_range_free(range);
406 return 0;
407 } else {
408 utf8_full_alphabet_check = 1;
409 }
410 } else {
411 /*
412 * This permitted alphabet check will be
413 * expressed using conditional statements
414 * instead of table lookups. Table would be
415 * to large or otherwise inappropriate (too sparse?).
416 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000417 }
418
419 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000420 arg->expr->_type_unique_index);
Lev Walkin59004fa2004-08-20 13:37:01 +0000421 INDENT(+1);
422 if(utf8_full_alphabet_check) {
Lev Walkin29c41682004-10-02 16:44:55 +0000423 OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
424 OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000425 OUT("\n");
426 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000427 if(use_table) {
Wim Lewisa73ae672014-07-22 19:55:30 -0700428 OUT("const int *table = permitted_alphabet_table_%d;\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000429 arg->expr->_type_unique_index);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000430 emit_alphabet_check_loop(arg, 0);
431 } else {
432 emit_alphabet_check_loop(arg, range);
433 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000434 }
Lev Walkin775885e2004-08-22 12:47:03 +0000435 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000436 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000437 OUT("}\n");
438 OUT("\n");
439
440 asn1constraint_range_free(range);
441
Lev Walkin6938d042005-03-04 23:23:50 +0000442 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000443}
444
445static int
446emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin05363a72004-09-29 13:16:40 +0000447 asn1c_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000448 asn1p_expr_t *terminal;
Lev Walkincf3f6eb2017-08-23 04:34:15 -0700449 const char *tname;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000450
Lev Walkinc0e03b92017-08-22 01:48:23 -0700451 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->ns, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000452 if(terminal) {
453 OUT("/* The underlying type is %s */\n",
454 ASN_EXPR_TYPE2STR(terminal->expr_type));
455 } else {
456 terminal = arg->expr;
457 }
Lev Walkince31cdb2005-02-15 03:37:42 +0000458 tname = asn1c_type_name(arg, terminal, TNF_SAFE);
459 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000460
Lev Walkin634a3b82004-08-22 03:30:05 +0000461 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000462 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000463 OUT("const uint8_t *ch = st->buf;\n");
464 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000465 OUT("\n");
466 OUT("for(; ch < end; ch++) {\n");
467 INDENT(+1);
468 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000469 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000470 natural_stop = 0xffffffffUL;
471 break;
472 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000473 OUT("const uint8_t *ch = st->buf;\n");
474 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000475 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000476 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
477 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000478 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000479 OUT("uint32_t cv = (ch[0] << 24)\n");
480 OUT("\t\t| (ch[1] << 16)\n");
481 OUT("\t\t| (ch[2] << 8)\n");
482 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000483 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000484 natural_stop = 0xffffffffUL;
485 break;
486 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000487 OUT("const uint8_t *ch = st->buf;\n");
488 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000489 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000490 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
491 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000492 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000493 OUT("uint16_t cv = (ch[0] << 8)\n");
494 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000495 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000496 natural_stop = 0xffff;
497 break;
498 case ASN_BASIC_OCTET_STRING:
499 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000500 OUT("const uint8_t *ch = st->buf;\n");
501 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000502 OUT("\n");
503 OUT("for(; ch < end; ch++) {\n");
504 INDENT(+1);
505 OUT("uint8_t cv = *ch;\n");
506 natural_stop = 0xff;
507 break;
508 }
509
510 if(range) {
Lev Walkinbc09dd42017-10-19 02:16:35 -0700511 abuf *ab = emit_range_comparison_code(range, "cv", 0, natural_stop);
512 if(ab->length) {
513 OUT("if(!(%s)) return -1;\n", ab->buffer);
Lev Walkin4bd9eaf2017-10-19 01:16:42 -0700514 } else {
Lev Walkinbc09dd42017-10-19 02:16:35 -0700515 OUT("(void)cv; /* Unused variable */\n");
Lev Walkin4bd9eaf2017-10-19 01:16:42 -0700516 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000517 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000518 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000519 }
520
521 INDENT(-1);
522 OUT("}\n");
523
524 return 0;
525}
526
Lev Walkinbc09dd42017-10-19 02:16:35 -0700527static void
528abuf_oint(abuf *ab, asn1c_integer_t v) {
529 if(v == (-2147483647L - 1)) {
530 abuf_printf(ab, "(-2147483647L - 1)");
531 } else {
532 abuf_printf(ab, "%s", asn1p_itoa(v));
533 }
534}
Lev Walkin84cd58e2004-08-19 13:29:46 +0000535
Lev Walkinbc09dd42017-10-19 02:16:35 -0700536static abuf *
537emit_range_comparison_code(asn1cnst_range_t *range, const char *varname,
538 asn1c_integer_t natural_start,
539 asn1c_integer_t natural_stop) {
540 abuf *ab = abuf_new();
Lev Walkin84cd58e2004-08-19 13:29:46 +0000541
Lev Walkinbc09dd42017-10-19 02:16:35 -0700542 if(range->el_count == 0) {
543 int ignore_left =
544 (range->left.type == ARE_MIN)
545 || (natural_start != -1 && range->left.value <= natural_start);
546 int ignore_right =
547 (range->right.type == ARE_MAX)
548 || (natural_stop != -1 && range->right.value >= natural_stop);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000549
Lev Walkinbc09dd42017-10-19 02:16:35 -0700550 if(ignore_left && ignore_right) {
551 /* Empty constraint comparison */
552 } else if(ignore_left) {
553 abuf_printf(ab, "%s <= ", varname);
554 abuf_oint(ab, range->right.value);
555 } else if(ignore_right) {
556 abuf_printf(ab, "%s >= ", varname);
557 abuf_oint(ab, range->left.value);
558 } else if(range->left.value == range->right.value) {
559 abuf_printf(ab, "%s == ", varname);
560 abuf_oint(ab, range->right.value);
561 } else {
562 abuf_printf(ab, "%s >= ", varname);
563 abuf_oint(ab, range->left.value);
564 abuf_printf(ab, " && ");
565 abuf_printf(ab, "%s <= ", varname);
566 abuf_oint(ab, range->right.value);
567 }
568 } else {
569 for(int i = 0; i < range->el_count; i++) {
570 asn1cnst_range_t *r = range->elements[i];
Lev Walkin84cd58e2004-08-19 13:29:46 +0000571
Lev Walkinbc09dd42017-10-19 02:16:35 -0700572 abuf *rec = emit_range_comparison_code(r, varname, natural_start,
573 natural_stop);
574 if(rec->length) {
575 if(ab->length) {
576 abuf_str(ab, " || ");
577 }
578 abuf_str(ab, "(");
579 abuf_buf(ab, rec);
580 abuf_str(ab, ")");
581 } else {
582 /* Ignore this part */
583 }
584 abuf_free(rec);
585 }
586 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000587
Lev Walkinbc09dd42017-10-19 02:16:35 -0700588 return ab;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000589}
590
591static int
592emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
593
594 switch(etype) {
595 case ASN_BASIC_BIT_STRING:
596 OUT("if(st->size > 0) {\n");
597 OUT("\t/* Size in bits */\n");
Lev Walkindcf1e352006-09-08 19:34:22 +0000598 OUT("\tsize = 8 * st->size - (st->bits_unused & 0x07);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000599 OUT("} else {\n");
600 OUT("\tsize = 0;\n");
601 OUT("}\n");
602 break;
603 case ASN_STRING_UniversalString:
604 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
605 break;
606 case ASN_STRING_BMPString:
607 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
608 break;
609 case ASN_STRING_UTF8String:
Lev Walkin29c41682004-10-02 16:44:55 +0000610 OUT("size = UTF8String_length(st);\n");
611 OUT("if((ssize_t)size < 0) {\n");
Lev Walkin7c1dc052016-03-14 03:08:15 -0700612 OUT("\tASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin29c41682004-10-02 16:44:55 +0000613 OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
614 OUT("\t\ttd->name, __FILE__, __LINE__);\n");
615 OUT("\treturn -1;\n");
616 OUT("}\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000617 break;
618 case ASN_CONSTR_SET_OF:
619 case ASN_CONSTR_SEQUENCE_OF:
Lev Walkinf1a51232005-07-04 02:01:03 +0000620 OUT("/* Determine the number of elements */\n");
621 OUT("size = _A_C%s_FROM_VOID(sptr)->count;\n",
622 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000623 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000624 case ASN_BASIC_OCTET_STRING:
625 OUT("size = st->size;\n");
626 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000627 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000628 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000629 OUT("size = st->size;\n");
630 break;
631 } else {
632 const char *type_name = ASN_EXPR_TYPE2STR(etype);
633 if(!type_name) type_name = arg->expr->Identifier;
634 WARNING("SizeConstraint is not defined for %s",
635 type_name);
636 OUT_NOINDENT("#warning SizeConstraint "
637 "is not defined for %s!\n", type_name);
638 OUT("size = st->size;\n");
639 }
640 return -1;
641 }
642
643 return 0;
644}
645
646static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000647emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000648
649 switch(etype) {
650 case ASN_BASIC_INTEGER:
651 case ASN_BASIC_ENUMERATED:
Lev Walkin8bb57a22007-12-03 13:41:36 +0000652 if(asn1c_type_fits_long(arg, arg->expr) == FL_FITS_UNSIGN) {
653 OUT("value = *(const unsigned long *)sptr;\n");
654 } else if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) {
Lev Walkine0b56e02005-02-25 12:10:27 +0000655 OUT("value = *(const long *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000656 } else {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000657 /*
658 * In some cases we can explore our knowledge of
659 * underlying INTEGER_t->buf format.
660 */
Lev Walkin6ea088f2004-09-07 06:31:15 +0000661 if(r_value->el_count == 0
662 && (
663 /* Speed-up common case: (0..MAX) */
664 (r_value->left.type == ARE_VALUE
665 && r_value->left.value == 0
666 && r_value->right.type == ARE_MAX)
667 ||
668 /* Speed-up common case: (MIN..-1) */
669 (r_value->left.type == ARE_MIN
670 && r_value->right.type == ARE_VALUE
671 && r_value->right.value == -1)
672 )) {
673 OUT("/* Check if the sign bit is present */\n");
674 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
675 break;
676 }
677
Lev Walkine0f2a5b2017-08-30 20:02:29 -0700678 if(native_long_sign(arg, r_value) >= 0) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000679 /* Special case for treating unsigned longs */
680 OUT("if(asn_INTEGER2ulong(st, &value)) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000681 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700682 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000683 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
684 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000685 OUT("return -1;\n");
686 INDENT(-1);
Lev Walkin8bb57a22007-12-03 13:41:36 +0000687 OUT("}\n");
688 } else {
689 OUT("if(asn_INTEGER2long(st, &value)) {\n");
690 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700691 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkin8bb57a22007-12-03 13:41:36 +0000692 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
693 OUT("\ttd->name, __FILE__, __LINE__);\n");
694 OUT("return -1;\n");
695 INDENT(-1);
696 OUT("}\n");
697 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000698 }
699 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000700 case ASN_BASIC_REAL:
Lev Walkin2a744a72013-03-27 01:56:23 -0700701 if(arg->flags & A1C_USE_WIDE_TYPES) {
Lev Walkin05363a72004-09-29 13:16:40 +0000702 OUT("if(asn_REAL2double(st, &value)) {\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000703 INDENT(+1);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700704 OUT("ASN__CTFAIL(app_key, td, sptr,\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000705 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
706 OUT("\ttd->name, __FILE__, __LINE__);\n");
707 OUT("return -1;\n");
708 INDENT(-1);
709 OUT("}\n");
Lev Walkin2a744a72013-03-27 01:56:23 -0700710 } else {
Lev Walkinb5450702017-10-04 02:52:57 -0700711 OUT("value = *(const %s *)sptr;\n", c_name(arg).type.c_name);
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000712 }
713 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000714 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000715 OUT("value = (*(const long *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000716 break;
717 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000718 WARNING("%s:%d: Value cannot be determined "
719 "for constraint check for %s",
Lev Walkinb85a8132005-08-18 13:38:19 +0000720 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000721 arg->expr->_lineno,
722 arg->expr->Identifier
723 );
724 OUT_NOINDENT(
725 "#error %s:%d: Value of %s cannot be determined\n",
Lev Walkinb85a8132005-08-18 13:38:19 +0000726 arg->expr->module->source_file_name,
Lev Walkin02b137d2004-08-21 07:34:58 +0000727 arg->expr->_lineno,
728 arg->expr->Identifier
729 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000730 break;
731 }
732
733 return 0;
734}
735
736static asn1p_expr_type_e
737_find_terminal_type(arg_t *arg) {
738 asn1p_expr_t *expr;
Lev Walkinc0e03b92017-08-22 01:48:23 -0700739 expr = asn1f_find_terminal_type_ex(arg->asn, arg->ns, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000740 if(expr) return expr->expr_type;
741 return A1TC_INVALID;
742}
743
Lev Walkin8bb57a22007-12-03 13:41:36 +0000744static int
Lev Walkine0f2a5b2017-08-30 20:02:29 -0700745native_long_sign(arg_t *arg, asn1cnst_range_t *r) {
746 if(!(arg->flags & A1C_USE_WIDE_TYPES) && r->left.type == ARE_VALUE
747 && r->left.value >= 0 && r->left.value <= 2147483647
748 && r->right.type == ARE_MAX) {
749 return 1;
750 }
Lev Walkin8bb57a22007-12-03 13:41:36 +0000751 if(r->left.type == ARE_VALUE
752 && r->left.value >= 0
753 && r->right.type == ARE_VALUE
Lev Walkin5b63acf2014-01-14 01:48:37 -0800754 && r->right.value > 2147483647
Lev Walkin1b3a1352016-01-10 13:15:02 -0800755 && r->right.value <= (asn1c_integer_t)(4294967295UL)) {
Lev Walkin8bb57a22007-12-03 13:41:36 +0000756 if(r->el_count == 0
757 && r->left.value == 0
758 && r->right.value == 4294967295UL)
759 return 0;
760 else
761 return 1;
762 } else {
763 return -1;
764 }
765}