blob: b586d4db1e85c7628acc4ddf8dc5672060e1649e [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 +000016static int global_compile_mark;
17
18int
19asn1c_emit_constraint_checking_code(arg_t *arg) {
20 asn1cnst_range_t *r_size;
21 asn1cnst_range_t *r_value;
22 asn1p_expr_t *expr = arg->expr;
23 asn1p_expr_type_e etype;
24 asn1p_constraint_t *ct;
25 int got_something = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +000026 int produce_st = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +000027
28 ct = expr->combined_constraints;
29 if(ct == NULL)
30 return 1; /* No additional constraints defined */
31
32 etype = _find_terminal_type(arg);
33
Lev Walkinbe717ec2004-08-25 02:03:59 +000034 r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE,0,0,0);
35 r_size = asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE,0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +000036 if(r_value) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000037 if(r_value->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000038 || r_value->empty_constraint
39 || (r_value->left.type == ARE_MIN
40 && r_value->right.type == ARE_MAX)
41 || (etype == ASN_BASIC_BOOLEAN
42 && r_value->left.value == 0
43 && r_value->right.value == 1)
44 ) {
45 asn1constraint_range_free(r_value);
46 r_value = 0;
47 }
48 }
49 if(r_size) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000050 if(r_size->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000051 || r_size->empty_constraint
52 || (r_size->left.value == 0 /* or .type == MIN */
53 && r_size->right.type == ARE_MAX)
54 ) {
55 asn1constraint_range_free(r_size);
56 r_size = 0;
57 }
58 }
59
Lev Walkin59004fa2004-08-20 13:37:01 +000060 /*
61 * Do we really need an "*st = sptr" pointer?
62 */
63 switch(etype) {
64 case ASN_BASIC_INTEGER:
65 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +000066 case ASN_BASIC_REAL:
67 if(!(arg->flags & A1C_USE_NATIVE_TYPES))
Lev Walkin59004fa2004-08-20 13:37:01 +000068 produce_st = 1;
69 break;
Lev Walkin02b137d2004-08-21 07:34:58 +000070 case ASN_BASIC_BIT_STRING:
Lev Walkin59004fa2004-08-20 13:37:01 +000071 case ASN_BASIC_OCTET_STRING:
72 produce_st = 1;
73 break;
74 default:
75 if(etype & ASN_STRING_MASK)
76 produce_st = 1;
77 break;
78 }
Lev Walkince31cdb2005-02-15 03:37:42 +000079 if(produce_st) {
80 char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
81 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
82 }
Lev Walkin84cd58e2004-08-19 13:29:46 +000083
84 if(r_size || r_value) {
85 if(r_size) {
86 OUT("size_t size;\n");
87 }
88 if(r_value)
89 switch(etype) {
90 case ASN_BASIC_INTEGER:
91 case ASN_BASIC_ENUMERATED:
92 OUT("long value;\n");
93 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +000094 case ASN_BASIC_REAL:
95 OUT("double value;\n");
96 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +000097 case ASN_BASIC_BOOLEAN:
98 OUT("int value;\n");
99 break;
100 default:
101 break;
102 }
103 }
104
105 OUT("\n");
106
107 /*
108 * Protection against null input.
109 */
110 OUT("if(!sptr) {\n");
111 INDENT(+1);
112 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000113 OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
114 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000115 OUT("return -1;\n");
116 INDENT(-1);
117 OUT("}\n");
118 OUT("\n");
119
120 if(r_value)
Lev Walkin6ea088f2004-09-07 06:31:15 +0000121 emit_value_determination_code(arg, etype, r_value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000122 if(r_size)
123 emit_size_determination_code(arg, etype);
124
Lev Walkin59004fa2004-08-20 13:37:01 +0000125 INDENT(-1);
126 REDIR(OT_CTABLES);
127 /* Emit FROM() tables */
128 asn1c_emit_constraint_tables(arg, r_size?1:0);
129 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 }
155 if(ct->_compile_mark) {
156 if(got_something++) { OUT("\n"); OUT(" && "); }
Lev Walkin730b15a2004-08-22 13:11:40 +0000157 OUT("!check_permitted_alphabet_%d(sptr)",
Lev Walkin84cd58e2004-08-19 13:29:46 +0000158 ct->_compile_mark);
159 }
160 if(!got_something) {
161 OUT("1 /* No applicable constraints whatsoever */");
Lev Walkin59004fa2004-08-20 13:37:01 +0000162 OUT(") {\n");
163 INDENT(-1);
164 INDENTED(OUT("/* Nothing is here. See below */\n"));
165 OUT("}\n");
166 OUT("\n");
167 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000168 }
169 INDENT(-1);
170 OUT(") {\n");
171 INDENT(+1);
172 OUT("/* Constraint check succeeded */\n");
Lev Walkin6db2f092004-08-22 12:37:35 +0000173 OUT("return 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000174 INDENT(-1);
175 OUT("} else {\n");
176 INDENT(+1);
177 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000178 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
179 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000180 OUT("return -1;\n");
181 INDENT(-1);
182 OUT("}\n");
183
184 return 0;
185}
186
Lev Walkin59004fa2004-08-20 13:37:01 +0000187static int
188asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin05363a72004-09-29 13:16:40 +0000189 asn1c_integer_t range_start;
190 asn1c_integer_t range_stop;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000191 asn1p_expr_type_e etype;
192 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000193 asn1p_constraint_t *ct;
194 int utf8_full_alphabet_check = 0;
195 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000196 int table[256];
197 int use_table;
198
Lev Walkin59004fa2004-08-20 13:37:01 +0000199 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000200 if(!ct) return 0;
201
202 etype = _find_terminal_type(arg);
203
Lev Walkinbe717ec2004-08-25 02:03:59 +0000204 range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000205 if(!range) return 0;
206
Lev Walkinbe717ec2004-08-25 02:03:59 +0000207 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000208 || range->empty_constraint) {
209 asn1constraint_range_free(range);
210 return 0;
211 }
212
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000213
214 if(range->left.type == ARE_MIN
215 && range->right.type == ARE_MAX) {
216 /*
217 * The permitted alphabet constraint checker code guarantees
218 * that either both bounds (left/right) are present, or
219 * they're absent simultaneously. Thus, this assertion
220 * legitimately holds true.
221 */
222 assert(range->el_count == 0);
223 /* The full range is specified. Ignore it. */
224 return 0;
225 }
226
Lev Walkin84cd58e2004-08-19 13:29:46 +0000227 range_start = range->left.value;
228 range_stop = range->right.value;
229 assert(range->left.type == ARE_VALUE);
230 assert(range->right.type == ARE_VALUE);
231 assert(range_start <= range_stop);
232
233 range_start = 0; /* Force old behavior */
234
235 /*
236 * Check if we need a test table to check the alphabet.
237 */
238 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000239 if(range->el_count == 0) {
240 /*
241 * It's better to have a short if() check
242 * than waste 4k of table space
243 */
244 use_table = 0;
245 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000246 if((range_stop - range_start) > 255)
247 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000248 if(etype == ASN_STRING_UTF8String) {
249 if(range_stop >= 0x80)
250 use_table = 0;
251 else
252 max_table_size = 128;
253 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000254
255 if(!ct->_compile_mark)
256 ct->_compile_mark = ++global_compile_mark;
257
258 if(use_table) {
259 int i, n = 0;
260 int untl;
261 memset(table, 0, sizeof(table));
262 for(i = -1; i < range->el_count; i++) {
263 asn1cnst_range_t *r;
Lev Walkin05363a72004-09-29 13:16:40 +0000264 asn1c_integer_t v;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000265 if(i == -1) {
266 if(range->el_count) continue;
267 r = range;
268 } else {
269 r = range->elements[i];
270 }
271 for(v = r->left.value; v <= r->right.value; v++) {
272 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000273 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000274 table[v - range_start] = ++n;
275 }
276 }
277
Lev Walkin84cd58e2004-08-19 13:29:46 +0000278 untl = (range_stop - range_start) + 1;
279 untl += (untl % 16)?16 - (untl % 16):0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000280 OUT("static int permitted_alphabet_table_%d[%d] = {\n",
281 ct->_compile_mark, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000282 for(n = 0; n < untl; n++) {
283 OUT("%d,", table[n]?1:0);
284 if(!((n+1) % 16)) {
285 int c;
286 if(!n) {
287 OUT("\n");
288 continue;
289 }
290 OUT("\t/* ");
291 for(c = n - 15; c <= n; c++) {
292 if(table[c]) {
293 int a = c + range_start;
294 if(a > 0x20 && a < 0x80)
295 OUT("%c", a);
296 else
297 OUT(".");
298 } else {
299 OUT(" ");
300 }
301 }
302 OUT(" */");
303 OUT("\n");
304 }
305 }
306 OUT("};\n");
307 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000308 } else if(etype == ASN_STRING_UTF8String) {
309 /*
310 * UTF8String type is a special case in many respects.
311 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000312 if(got_size) {
313 /*
314 * Size has been already determined.
315 * The UTF8String length checker also checks
316 * for the syntax validity, so we don't have
317 * to repeat this process twice.
318 */
319 ct->_compile_mark = 0; /* Don't generate code */
320 asn1constraint_range_free(range);
321 return 0;
322 } else {
323 utf8_full_alphabet_check = 1;
324 }
325 } else {
326 /*
327 * This permitted alphabet check will be
328 * expressed using conditional statements
329 * instead of table lookups. Table would be
330 * to large or otherwise inappropriate (too sparse?).
331 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000332 }
333
334 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
335 ct->_compile_mark);
Lev Walkin59004fa2004-08-20 13:37:01 +0000336 INDENT(+1);
337 if(utf8_full_alphabet_check) {
Lev Walkin29c41682004-10-02 16:44:55 +0000338 OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
339 OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000340 OUT("\n");
341 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000342 if(use_table) {
343 OUT("int *table = permitted_alphabet_table_%d;\n",
344 ct->_compile_mark);
345 emit_alphabet_check_loop(arg, 0);
346 } else {
347 emit_alphabet_check_loop(arg, range);
348 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000349 }
Lev Walkin775885e2004-08-22 12:47:03 +0000350 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000351 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000352 OUT("}\n");
353 OUT("\n");
354
355 asn1constraint_range_free(range);
356
357 return 0;
358}
359
360static int
361emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin05363a72004-09-29 13:16:40 +0000362 asn1c_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000363 asn1p_expr_t *terminal;
Lev Walkince31cdb2005-02-15 03:37:42 +0000364 char *tname;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000365
Lev Walkine4d6ab82004-09-22 16:05:13 +0000366 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000367 if(terminal) {
368 OUT("/* The underlying type is %s */\n",
369 ASN_EXPR_TYPE2STR(terminal->expr_type));
370 } else {
371 terminal = arg->expr;
372 }
Lev Walkince31cdb2005-02-15 03:37:42 +0000373 tname = asn1c_type_name(arg, terminal, TNF_SAFE);
374 OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000375
Lev Walkin634a3b82004-08-22 03:30:05 +0000376 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000377 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000378 OUT("const uint8_t *ch = st->buf;\n");
379 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000380 OUT("\n");
381 OUT("for(; ch < end; ch++) {\n");
382 INDENT(+1);
383 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000384 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000385 natural_stop = 0xffffffffUL;
386 break;
387 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000388 OUT("const uint8_t *ch = st->buf;\n");
389 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000390 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000391 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
392 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000393 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000394 OUT("uint32_t cv = (ch[0] << 24)\n");
395 OUT("\t\t| (ch[1] << 16)\n");
396 OUT("\t\t| (ch[2] << 8)\n");
397 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000398 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000399 natural_stop = 0xffffffffUL;
400 break;
401 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000402 OUT("const uint8_t *ch = st->buf;\n");
403 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000404 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000405 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
406 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000407 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000408 OUT("uint16_t cv = (ch[0] << 8)\n");
409 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000410 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000411 natural_stop = 0xffff;
412 break;
413 case ASN_BASIC_OCTET_STRING:
414 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000415 OUT("const uint8_t *ch = st->buf;\n");
416 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000417 OUT("\n");
418 OUT("for(; ch < end; ch++) {\n");
419 INDENT(+1);
420 OUT("uint8_t cv = *ch;\n");
421 natural_stop = 0xff;
422 break;
423 }
424
425 if(range) {
426 OUT("if(!(");
427 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
Lev Walkin775885e2004-08-22 12:47:03 +0000428 OUT(")) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000429 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000430 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000431 }
432
433 INDENT(-1);
434 OUT("}\n");
435
436 return 0;
437}
438
439static int
Lev Walkin05363a72004-09-29 13:16:40 +0000440emit_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 +0000441 int ignore_left;
442 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000443 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000444 int i;
445
446 for(i = -1; i < range->el_count; i++) {
447 asn1cnst_range_t *r;
448 if(i == -1) {
449 if(range->el_count) continue;
450 r = range;
451 } else {
452 if(i) OUT(" || ");
453 r = range->elements[i];
454 }
455
456 if(r != range) OUT("(");
457
458 ignore_left = (r->left.type == ARE_MIN)
459 || (natural_start != -1
460 && r->left.value <= natural_start);
461 ignore_right = (r->right.type == ARE_MAX)
462 || (natural_stop != -1
463 && r->right.value >= natural_stop);
464 if(ignore_left && ignore_right) {
465 OUT("1 /* Constraint matches natural range of %s */",
466 varname);
467 continue;
468 }
469
470 if(ignore_left) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000471 OUT("%s <= %" PRIdASN, varname,
472 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000473 } else if(ignore_right) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000474 OUT("%s >= %" PRIdASN, varname,
475 r->left.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000476 } else if(r->left.value == r->right.value) {
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 {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000480 OUT("%s >= %" PRIdASN " && %s <= %" PRIdASN,
Lev Walkin84cd58e2004-08-19 13:29:46 +0000481 varname,
Lev Walkin33c16ba2004-09-24 21:01:43 +0000482 r->left.value,
Lev Walkin84cd58e2004-08-19 13:29:46 +0000483 varname,
Lev Walkin33c16ba2004-09-24 21:01:43 +0000484 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000485 }
486 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000487 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000488 }
489
Lev Walkin59004fa2004-08-20 13:37:01 +0000490 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000491}
492
493static int
494emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
495
496 switch(etype) {
497 case ASN_BASIC_BIT_STRING:
498 OUT("if(st->size > 0) {\n");
499 OUT("\t/* Size in bits */\n");
Lev Walkincb2b2d12004-09-05 10:42:19 +0000500 OUT("\tsize = 8 * (st->size - 1) - (st->buf[0] & 0x7);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000501 OUT("} else {\n");
502 OUT("\tsize = 0;\n");
503 OUT("}\n");
504 break;
505 case ASN_STRING_UniversalString:
506 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
507 break;
508 case ASN_STRING_BMPString:
509 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
510 break;
511 case ASN_STRING_UTF8String:
Lev Walkin29c41682004-10-02 16:44:55 +0000512 OUT("size = UTF8String_length(st);\n");
513 OUT("if((ssize_t)size < 0) {\n");
514 OUT("\t_ASN_ERRLOG(app_errlog, app_key,\n");
515 OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
516 OUT("\t\ttd->name, __FILE__, __LINE__);\n");
517 OUT("\treturn -1;\n");
518 OUT("}\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000519 break;
520 case ASN_CONSTR_SET_OF:
521 case ASN_CONSTR_SEQUENCE_OF:
522 OUT("{ /* Determine the number of elements */\n");
523 INDENT(+1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000524 OUT("const A_%s_OF(void) *list;\n",
Lev Walkin84cd58e2004-08-19 13:29:46 +0000525 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin23fd2fa2005-01-27 17:58:47 +0000526 OUT("(const void *)list = sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000527 OUT("size = list->count;\n");
528 INDENT(-1);
529 OUT("}\n");
530 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000531 case ASN_BASIC_OCTET_STRING:
532 OUT("size = st->size;\n");
533 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000534 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000535 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000536 OUT("size = st->size;\n");
537 break;
538 } else {
539 const char *type_name = ASN_EXPR_TYPE2STR(etype);
540 if(!type_name) type_name = arg->expr->Identifier;
541 WARNING("SizeConstraint is not defined for %s",
542 type_name);
543 OUT_NOINDENT("#warning SizeConstraint "
544 "is not defined for %s!\n", type_name);
545 OUT("size = st->size;\n");
546 }
547 return -1;
548 }
549
550 return 0;
551}
552
553static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000554emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000555
556 switch(etype) {
557 case ASN_BASIC_INTEGER:
558 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000559 if(arg->flags & A1C_USE_NATIVE_TYPES) {
Lev Walkin02b137d2004-08-21 07:34:58 +0000560 OUT("value = *(const int *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000561 } else {
Lev Walkin6ea088f2004-09-07 06:31:15 +0000562 if(r_value->el_count == 0
563 && (
564 /* Speed-up common case: (0..MAX) */
565 (r_value->left.type == ARE_VALUE
566 && r_value->left.value == 0
567 && r_value->right.type == ARE_MAX)
568 ||
569 /* Speed-up common case: (MIN..-1) */
570 (r_value->left.type == ARE_MIN
571 && r_value->right.type == ARE_VALUE
572 && r_value->right.value == -1)
573 )) {
574 OUT("/* Check if the sign bit is present */\n");
575 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
576 break;
577 }
578
Lev Walkin05363a72004-09-29 13:16:40 +0000579 OUT("if(asn_INTEGER2long(st, &value)) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000580 INDENT(+1);
581 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000582 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
583 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000584 OUT("return -1;\n");
585 INDENT(-1);
586 OUT("}\n");
587 }
588 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000589 case ASN_BASIC_REAL:
590 if(arg->flags & A1C_USE_NATIVE_TYPES) {
591 OUT("value = *(const double *)sptr;\n");
592 } else {
Lev Walkin05363a72004-09-29 13:16:40 +0000593 OUT("if(asn_REAL2double(st, &value)) {\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000594 INDENT(+1);
595 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
596 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
597 OUT("\ttd->name, __FILE__, __LINE__);\n");
598 OUT("return -1;\n");
599 INDENT(-1);
600 OUT("}\n");
601 }
602 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000603 case ASN_BASIC_BOOLEAN:
Lev Walkin02b137d2004-08-21 07:34:58 +0000604 OUT("value = (*(const int *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000605 break;
606 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000607 WARNING("%s:%d: Value cannot be determined "
608 "for constraint check for %s",
609 arg->mod->source_file_name,
610 arg->expr->_lineno,
611 arg->expr->Identifier
612 );
613 OUT_NOINDENT(
614 "#error %s:%d: Value of %s cannot be determined\n",
615 arg->mod->source_file_name,
616 arg->expr->_lineno,
617 arg->expr->Identifier
618 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000619 break;
620 }
621
622 return 0;
623}
624
625static asn1p_expr_type_e
626_find_terminal_type(arg_t *arg) {
627 asn1p_expr_t *expr;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000628 expr = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000629 if(expr) return expr->expr_type;
630 return A1TC_INVALID;
631}
632