blob: 78097838e42bd7c0bff1340da3ba7a4e24843c51 [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 */
7#include <asn1fix_export.h> /* other exportable stuff from libasn1fix */
8
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 Walkin84cd58e2004-08-19 13:29:46 +000015
Lev Walkin84cd58e2004-08-19 13:29:46 +000016int
17asn1c_emit_constraint_checking_code(arg_t *arg) {
18 asn1cnst_range_t *r_size;
19 asn1cnst_range_t *r_value;
20 asn1p_expr_t *expr = arg->expr;
21 asn1p_expr_type_e etype;
22 asn1p_constraint_t *ct;
23 int got_something = 0;
Lev Walkin6938d042005-03-04 23:23:50 +000024 int alphabet_table_compiled;
Lev Walkin59004fa2004-08-20 13:37:01 +000025 int produce_st = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +000026
27 ct = expr->combined_constraints;
28 if(ct == NULL)
29 return 1; /* No additional constraints defined */
30
31 etype = _find_terminal_type(arg);
32
Lev Walkinbe717ec2004-08-25 02:03:59 +000033 r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE,0,0,0);
34 r_size = asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE,0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +000035 if(r_value) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000036 if(r_value->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000037 || r_value->empty_constraint
38 || (r_value->left.type == ARE_MIN
39 && r_value->right.type == ARE_MAX)
40 || (etype == ASN_BASIC_BOOLEAN
41 && r_value->left.value == 0
42 && r_value->right.value == 1)
43 ) {
44 asn1constraint_range_free(r_value);
45 r_value = 0;
46 }
47 }
48 if(r_size) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000049 if(r_size->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000050 || r_size->empty_constraint
51 || (r_size->left.value == 0 /* or .type == MIN */
52 && r_size->right.type == ARE_MAX)
53 ) {
54 asn1constraint_range_free(r_size);
55 r_size = 0;
56 }
57 }
58
Lev Walkin59004fa2004-08-20 13:37:01 +000059 /*
60 * Do we really need an "*st = sptr" pointer?
61 */
62 switch(etype) {
63 case ASN_BASIC_INTEGER:
64 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +000065 case ASN_BASIC_REAL:
66 if(!(arg->flags & A1C_USE_NATIVE_TYPES))
Lev Walkin59004fa2004-08-20 13:37:01 +000067 produce_st = 1;
68 break;
Lev Walkin02b137d2004-08-21 07:34:58 +000069 case ASN_BASIC_BIT_STRING:
Lev Walkin59004fa2004-08-20 13:37:01 +000070 case ASN_BASIC_OCTET_STRING:
71 produce_st = 1;
72 break;
73 default:
74 if(etype & ASN_STRING_MASK)
75 produce_st = 1;
76 break;
77 }
Lev Walkince31cdb2005-02-15 03:37:42 +000078 if(produce_st) {
79 char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
80 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
81 }
Lev Walkin84cd58e2004-08-19 13:29:46 +000082
83 if(r_size || r_value) {
84 if(r_size) {
85 OUT("size_t size;\n");
86 }
87 if(r_value)
88 switch(etype) {
89 case ASN_BASIC_INTEGER:
90 case ASN_BASIC_ENUMERATED:
91 OUT("long value;\n");
92 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +000093 case ASN_BASIC_REAL:
94 OUT("double value;\n");
95 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +000096 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +000097 OUT("BOOLEAN_t value;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +000098 break;
99 default:
100 break;
101 }
102 }
103
104 OUT("\n");
105
106 /*
107 * Protection against null input.
108 */
109 OUT("if(!sptr) {\n");
110 INDENT(+1);
111 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000112 OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
113 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000114 OUT("return -1;\n");
115 INDENT(-1);
116 OUT("}\n");
117 OUT("\n");
118
119 if(r_value)
Lev Walkin6ea088f2004-09-07 06:31:15 +0000120 emit_value_determination_code(arg, etype, r_value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000121 if(r_size)
122 emit_size_determination_code(arg, etype);
123
Lev Walkin59004fa2004-08-20 13:37:01 +0000124 INDENT(-1);
125 REDIR(OT_CTABLES);
126 /* Emit FROM() tables */
Lev Walkin6938d042005-03-04 23:23:50 +0000127 alphabet_table_compiled =
128 (asn1c_emit_constraint_tables(arg, r_size?1:0) == 1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000129 REDIR(OT_CODE);
130 INDENT(+1);
131
Lev Walkin84cd58e2004-08-19 13:29:46 +0000132 /*
133 * Here is an if() {} else {} constaint checking code.
134 */
135 OUT("\n");
136 OUT("if(");
137 INDENT(+1);
138 if(r_size) {
139 if(got_something++) { OUT("\n"); OUT(" && "); }
140 OUT("(");
141 emit_range_comparison_code(arg, r_size, "size", 0, -1);
142 OUT(")");
143 }
144 if(r_value) {
145 if(got_something++) { OUT("\n"); OUT(" && "); }
146 OUT("(");
147 if(etype == ASN_BASIC_BOOLEAN)
148 emit_range_comparison_code(arg, r_value,
149 "value", 0, 1);
150 else
151 emit_range_comparison_code(arg, r_value,
152 "value", -1, -1);
153 OUT(")");
154 }
Lev Walkin6938d042005-03-04 23:23:50 +0000155 if(alphabet_table_compiled) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000156 if(got_something++) { OUT("\n"); OUT(" && "); }
Lev Walkin6938d042005-03-04 23:23:50 +0000157 OUT("!check_permitted_alphabet_%d(%s)",
158 arg->expr->_type_unique_index,
159 produce_st ? "st" : "sptr");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000160 }
161 if(!got_something) {
162 OUT("1 /* No applicable constraints whatsoever */");
Lev Walkin59004fa2004-08-20 13:37:01 +0000163 OUT(") {\n");
164 INDENT(-1);
165 INDENTED(OUT("/* Nothing is here. See below */\n"));
166 OUT("}\n");
167 OUT("\n");
168 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000169 }
170 INDENT(-1);
171 OUT(") {\n");
172 INDENT(+1);
Lev Walkin7ef83a42005-03-29 19:04:24 +0000173 switch(etype) {
174 case ASN_CONSTR_SEQUENCE_OF:
175 OUT("/* SEQUENCE validation code is the same as SET */\n");
176 case ASN_CONSTR_SET_OF:
177 OUT("/* Perform validation of the inner elements */\n");
178 OUT("return SET_OF_constraint(td, list, app_errlog, app_key);\n");
179 break;
180 default:
181 OUT("/* Constraint check succeeded */\n");
182 OUT("return 0;\n");
183 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000184 INDENT(-1);
185 OUT("} else {\n");
186 INDENT(+1);
187 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000188 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
189 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000190 OUT("return -1;\n");
191 INDENT(-1);
192 OUT("}\n");
193
194 return 0;
195}
196
Lev Walkin59004fa2004-08-20 13:37:01 +0000197static int
198asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin05363a72004-09-29 13:16:40 +0000199 asn1c_integer_t range_start;
200 asn1c_integer_t range_stop;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000201 asn1p_expr_type_e etype;
202 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000203 asn1p_constraint_t *ct;
204 int utf8_full_alphabet_check = 0;
205 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000206 int table[256];
207 int use_table;
208
Lev Walkin59004fa2004-08-20 13:37:01 +0000209 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000210 if(!ct) return 0;
211
212 etype = _find_terminal_type(arg);
213
Lev Walkinbe717ec2004-08-25 02:03:59 +0000214 range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000215 if(!range) return 0;
216
Lev Walkinbe717ec2004-08-25 02:03:59 +0000217 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000218 || range->empty_constraint) {
219 asn1constraint_range_free(range);
220 return 0;
221 }
222
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000223
224 if(range->left.type == ARE_MIN
225 && range->right.type == ARE_MAX) {
226 /*
227 * The permitted alphabet constraint checker code guarantees
228 * that either both bounds (left/right) are present, or
229 * they're absent simultaneously. Thus, this assertion
230 * legitimately holds true.
231 */
232 assert(range->el_count == 0);
233 /* The full range is specified. Ignore it. */
234 return 0;
235 }
236
Lev Walkin84cd58e2004-08-19 13:29:46 +0000237 range_start = range->left.value;
238 range_stop = range->right.value;
239 assert(range->left.type == ARE_VALUE);
240 assert(range->right.type == ARE_VALUE);
241 assert(range_start <= range_stop);
242
243 range_start = 0; /* Force old behavior */
244
245 /*
246 * Check if we need a test table to check the alphabet.
247 */
248 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000249 if(range->el_count == 0) {
250 /*
251 * It's better to have a short if() check
252 * than waste 4k of table space
253 */
254 use_table = 0;
255 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000256 if((range_stop - range_start) > 255)
257 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000258 if(etype == ASN_STRING_UTF8String) {
259 if(range_stop >= 0x80)
260 use_table = 0;
261 else
262 max_table_size = 128;
263 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000264
Lev Walkin84cd58e2004-08-19 13:29:46 +0000265 if(use_table) {
266 int i, n = 0;
267 int untl;
268 memset(table, 0, sizeof(table));
269 for(i = -1; i < range->el_count; i++) {
270 asn1cnst_range_t *r;
Lev Walkin05363a72004-09-29 13:16:40 +0000271 asn1c_integer_t v;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000272 if(i == -1) {
273 if(range->el_count) continue;
274 r = range;
275 } else {
276 r = range->elements[i];
277 }
278 for(v = r->left.value; v <= r->right.value; v++) {
279 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000280 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000281 table[v - range_start] = ++n;
282 }
283 }
284
Lev Walkin84cd58e2004-08-19 13:29:46 +0000285 untl = (range_stop - range_start) + 1;
286 untl += (untl % 16)?16 - (untl % 16):0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000287 OUT("static int permitted_alphabet_table_%d[%d] = {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000288 arg->expr->_type_unique_index, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000289 for(n = 0; n < untl; n++) {
290 OUT("%d,", table[n]?1:0);
291 if(!((n+1) % 16)) {
292 int c;
293 if(!n) {
294 OUT("\n");
295 continue;
296 }
297 OUT("\t/* ");
298 for(c = n - 15; c <= n; c++) {
299 if(table[c]) {
300 int a = c + range_start;
301 if(a > 0x20 && a < 0x80)
302 OUT("%c", a);
303 else
304 OUT(".");
305 } else {
306 OUT(" ");
307 }
308 }
309 OUT(" */");
310 OUT("\n");
311 }
312 }
313 OUT("};\n");
314 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000315 } else if(etype == ASN_STRING_UTF8String) {
316 /*
317 * UTF8String type is a special case in many respects.
318 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000319 if(got_size) {
320 /*
321 * Size has been already determined.
322 * The UTF8String length checker also checks
323 * for the syntax validity, so we don't have
324 * to repeat this process twice.
325 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000326 asn1constraint_range_free(range);
327 return 0;
328 } else {
329 utf8_full_alphabet_check = 1;
330 }
331 } else {
332 /*
333 * This permitted alphabet check will be
334 * expressed using conditional statements
335 * instead of table lookups. Table would be
336 * to large or otherwise inappropriate (too sparse?).
337 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000338 }
339
340 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000341 arg->expr->_type_unique_index);
Lev Walkin59004fa2004-08-20 13:37:01 +0000342 INDENT(+1);
343 if(utf8_full_alphabet_check) {
Lev Walkin29c41682004-10-02 16:44:55 +0000344 OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
345 OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000346 OUT("\n");
347 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000348 if(use_table) {
349 OUT("int *table = permitted_alphabet_table_%d;\n",
Lev Walkin6938d042005-03-04 23:23:50 +0000350 arg->expr->_type_unique_index);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000351 emit_alphabet_check_loop(arg, 0);
352 } else {
353 emit_alphabet_check_loop(arg, range);
354 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000355 }
Lev Walkin775885e2004-08-22 12:47:03 +0000356 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000357 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000358 OUT("}\n");
359 OUT("\n");
360
361 asn1constraint_range_free(range);
362
Lev Walkin6938d042005-03-04 23:23:50 +0000363 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000364}
365
366static int
367emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin05363a72004-09-29 13:16:40 +0000368 asn1c_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000369 asn1p_expr_t *terminal;
Lev Walkince31cdb2005-02-15 03:37:42 +0000370 char *tname;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000371
Lev Walkine4d6ab82004-09-22 16:05:13 +0000372 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000373 if(terminal) {
374 OUT("/* The underlying type is %s */\n",
375 ASN_EXPR_TYPE2STR(terminal->expr_type));
376 } else {
377 terminal = arg->expr;
378 }
Lev Walkince31cdb2005-02-15 03:37:42 +0000379 tname = asn1c_type_name(arg, terminal, TNF_SAFE);
380 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000381
Lev Walkin634a3b82004-08-22 03:30:05 +0000382 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000383 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000384 OUT("const uint8_t *ch = st->buf;\n");
385 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000386 OUT("\n");
387 OUT("for(; ch < end; ch++) {\n");
388 INDENT(+1);
389 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000390 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000391 natural_stop = 0xffffffffUL;
392 break;
393 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000394 OUT("const uint8_t *ch = st->buf;\n");
395 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000396 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000397 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
398 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000399 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000400 OUT("uint32_t cv = (ch[0] << 24)\n");
401 OUT("\t\t| (ch[1] << 16)\n");
402 OUT("\t\t| (ch[2] << 8)\n");
403 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000404 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000405 natural_stop = 0xffffffffUL;
406 break;
407 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000408 OUT("const uint8_t *ch = st->buf;\n");
409 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000410 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000411 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
412 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000413 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000414 OUT("uint16_t cv = (ch[0] << 8)\n");
415 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000416 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000417 natural_stop = 0xffff;
418 break;
419 case ASN_BASIC_OCTET_STRING:
420 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000421 OUT("const uint8_t *ch = st->buf;\n");
422 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000423 OUT("\n");
424 OUT("for(; ch < end; ch++) {\n");
425 INDENT(+1);
426 OUT("uint8_t cv = *ch;\n");
427 natural_stop = 0xff;
428 break;
429 }
430
431 if(range) {
432 OUT("if(!(");
433 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
Lev Walkin775885e2004-08-22 12:47:03 +0000434 OUT(")) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000435 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000436 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000437 }
438
439 INDENT(-1);
440 OUT("}\n");
441
442 return 0;
443}
444
445static int
Lev Walkin05363a72004-09-29 13:16:40 +0000446emit_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 +0000447 int ignore_left;
448 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000449 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000450 int i;
451
452 for(i = -1; i < range->el_count; i++) {
453 asn1cnst_range_t *r;
454 if(i == -1) {
455 if(range->el_count) continue;
456 r = range;
457 } else {
458 if(i) OUT(" || ");
459 r = range->elements[i];
460 }
461
462 if(r != range) OUT("(");
463
464 ignore_left = (r->left.type == ARE_MIN)
465 || (natural_start != -1
466 && r->left.value <= natural_start);
467 ignore_right = (r->right.type == ARE_MAX)
468 || (natural_stop != -1
469 && r->right.value >= natural_stop);
470 if(ignore_left && ignore_right) {
471 OUT("1 /* Constraint matches natural range of %s */",
472 varname);
473 continue;
474 }
475
476 if(ignore_left) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000477 OUT("%s <= %" PRIdASN, varname,
478 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000479 } else if(ignore_right) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000480 OUT("%s >= %" PRIdASN, varname,
481 r->left.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000482 } else if(r->left.value == r->right.value) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000483 OUT("%s == %" PRIdASN, varname,
484 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000485 } else {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000486 OUT("%s >= %" PRIdASN " && %s <= %" PRIdASN,
Lev Walkin84cd58e2004-08-19 13:29:46 +0000487 varname,
Lev Walkin33c16ba2004-09-24 21:01:43 +0000488 r->left.value,
Lev Walkin84cd58e2004-08-19 13:29:46 +0000489 varname,
Lev Walkin33c16ba2004-09-24 21:01:43 +0000490 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000491 }
492 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000493 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000494 }
495
Lev Walkin59004fa2004-08-20 13:37:01 +0000496 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000497}
498
499static int
500emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
501
502 switch(etype) {
503 case ASN_BASIC_BIT_STRING:
504 OUT("if(st->size > 0) {\n");
505 OUT("\t/* Size in bits */\n");
Lev Walkincb2b2d12004-09-05 10:42:19 +0000506 OUT("\tsize = 8 * (st->size - 1) - (st->buf[0] & 0x7);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000507 OUT("} else {\n");
508 OUT("\tsize = 0;\n");
509 OUT("}\n");
510 break;
511 case ASN_STRING_UniversalString:
512 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
513 break;
514 case ASN_STRING_BMPString:
515 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
516 break;
517 case ASN_STRING_UTF8String:
Lev Walkin29c41682004-10-02 16:44:55 +0000518 OUT("size = UTF8String_length(st);\n");
519 OUT("if((ssize_t)size < 0) {\n");
520 OUT("\t_ASN_ERRLOG(app_errlog, app_key,\n");
521 OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
522 OUT("\t\ttd->name, __FILE__, __LINE__);\n");
523 OUT("\treturn -1;\n");
524 OUT("}\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000525 break;
526 case ASN_CONSTR_SET_OF:
527 case ASN_CONSTR_SEQUENCE_OF:
528 OUT("{ /* Determine the number of elements */\n");
529 INDENT(+1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000530 OUT("const A_%s_OF(void) *list;\n",
Lev Walkin84cd58e2004-08-19 13:29:46 +0000531 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin23fd2fa2005-01-27 17:58:47 +0000532 OUT("(const void *)list = sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000533 OUT("size = list->count;\n");
534 INDENT(-1);
535 OUT("}\n");
536 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000537 case ASN_BASIC_OCTET_STRING:
538 OUT("size = st->size;\n");
539 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000540 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000541 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000542 OUT("size = st->size;\n");
543 break;
544 } else {
545 const char *type_name = ASN_EXPR_TYPE2STR(etype);
546 if(!type_name) type_name = arg->expr->Identifier;
547 WARNING("SizeConstraint is not defined for %s",
548 type_name);
549 OUT_NOINDENT("#warning SizeConstraint "
550 "is not defined for %s!\n", type_name);
551 OUT("size = st->size;\n");
552 }
553 return -1;
554 }
555
556 return 0;
557}
558
559static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000560emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000561
562 switch(etype) {
563 case ASN_BASIC_INTEGER:
564 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000565 if(arg->flags & A1C_USE_NATIVE_TYPES) {
Lev Walkine0b56e02005-02-25 12:10:27 +0000566 OUT("value = *(const long *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000567 } else {
Lev Walkin6ea088f2004-09-07 06:31:15 +0000568 if(r_value->el_count == 0
569 && (
570 /* Speed-up common case: (0..MAX) */
571 (r_value->left.type == ARE_VALUE
572 && r_value->left.value == 0
573 && r_value->right.type == ARE_MAX)
574 ||
575 /* Speed-up common case: (MIN..-1) */
576 (r_value->left.type == ARE_MIN
577 && r_value->right.type == ARE_VALUE
578 && r_value->right.value == -1)
579 )) {
580 OUT("/* Check if the sign bit is present */\n");
581 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
582 break;
583 }
584
Lev Walkin05363a72004-09-29 13:16:40 +0000585 OUT("if(asn_INTEGER2long(st, &value)) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000586 INDENT(+1);
587 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000588 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
589 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000590 OUT("return -1;\n");
591 INDENT(-1);
592 OUT("}\n");
593 }
594 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000595 case ASN_BASIC_REAL:
596 if(arg->flags & A1C_USE_NATIVE_TYPES) {
597 OUT("value = *(const double *)sptr;\n");
598 } else {
Lev Walkin05363a72004-09-29 13:16:40 +0000599 OUT("if(asn_REAL2double(st, &value)) {\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000600 INDENT(+1);
601 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
602 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
603 OUT("\ttd->name, __FILE__, __LINE__);\n");
604 OUT("return -1;\n");
605 INDENT(-1);
606 OUT("}\n");
607 }
608 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000609 case ASN_BASIC_BOOLEAN:
Lev Walkine0b56e02005-02-25 12:10:27 +0000610 OUT("value = (*(const long *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000611 break;
612 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000613 WARNING("%s:%d: Value cannot be determined "
614 "for constraint check for %s",
615 arg->mod->source_file_name,
616 arg->expr->_lineno,
617 arg->expr->Identifier
618 );
619 OUT_NOINDENT(
620 "#error %s:%d: Value of %s cannot be determined\n",
621 arg->mod->source_file_name,
622 arg->expr->_lineno,
623 arg->expr->Identifier
624 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000625 break;
626 }
627
628 return 0;
629}
630
631static asn1p_expr_type_e
632_find_terminal_type(arg_t *arg) {
633 asn1p_expr_t *expr;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000634 expr = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000635 if(expr) return expr->expr_type;
636 return A1TC_INVALID;
637}
638