blob: 63915359c69bf2bb2b158d9f424fe3cc3eb7bb89 [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 }
79 if(produce_st)
Lev Walkin02b137d2004-08-21 07:34:58 +000080 OUT("const %s_t *st = sptr;\n",
81 asn1c_type_name(arg, arg->expr, TNF_SAFE));
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:
97 OUT("int value;\n");
98 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 */
127 asn1c_emit_constraint_tables(arg, r_size?1:0);
128 REDIR(OT_CODE);
129 INDENT(+1);
130
Lev Walkin84cd58e2004-08-19 13:29:46 +0000131 /*
132 * Here is an if() {} else {} constaint checking code.
133 */
134 OUT("\n");
135 OUT("if(");
136 INDENT(+1);
137 if(r_size) {
138 if(got_something++) { OUT("\n"); OUT(" && "); }
139 OUT("(");
140 emit_range_comparison_code(arg, r_size, "size", 0, -1);
141 OUT(")");
142 }
143 if(r_value) {
144 if(got_something++) { OUT("\n"); OUT(" && "); }
145 OUT("(");
146 if(etype == ASN_BASIC_BOOLEAN)
147 emit_range_comparison_code(arg, r_value,
148 "value", 0, 1);
149 else
150 emit_range_comparison_code(arg, r_value,
151 "value", -1, -1);
152 OUT(")");
153 }
154 if(ct->_compile_mark) {
155 if(got_something++) { OUT("\n"); OUT(" && "); }
Lev Walkin730b15a2004-08-22 13:11:40 +0000156 OUT("!check_permitted_alphabet_%d(sptr)",
Lev Walkin84cd58e2004-08-19 13:29:46 +0000157 ct->_compile_mark);
158 }
159 if(!got_something) {
160 OUT("1 /* No applicable constraints whatsoever */");
Lev Walkin59004fa2004-08-20 13:37:01 +0000161 OUT(") {\n");
162 INDENT(-1);
163 INDENTED(OUT("/* Nothing is here. See below */\n"));
164 OUT("}\n");
165 OUT("\n");
166 return 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000167 }
168 INDENT(-1);
169 OUT(") {\n");
170 INDENT(+1);
171 OUT("/* Constraint check succeeded */\n");
Lev Walkin6db2f092004-08-22 12:37:35 +0000172 OUT("return 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000173 INDENT(-1);
174 OUT("} else {\n");
175 INDENT(+1);
176 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000177 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
178 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000179 OUT("return -1;\n");
180 INDENT(-1);
181 OUT("}\n");
182
183 return 0;
184}
185
Lev Walkin59004fa2004-08-20 13:37:01 +0000186static int
187asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin05363a72004-09-29 13:16:40 +0000188 asn1c_integer_t range_start;
189 asn1c_integer_t range_stop;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000190 asn1p_expr_type_e etype;
191 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000192 asn1p_constraint_t *ct;
193 int utf8_full_alphabet_check = 0;
194 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000195 int table[256];
196 int use_table;
197
Lev Walkin59004fa2004-08-20 13:37:01 +0000198 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000199 if(!ct) return 0;
200
201 etype = _find_terminal_type(arg);
202
Lev Walkinbe717ec2004-08-25 02:03:59 +0000203 range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000204 if(!range) return 0;
205
Lev Walkinbe717ec2004-08-25 02:03:59 +0000206 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000207 || range->empty_constraint) {
208 asn1constraint_range_free(range);
209 return 0;
210 }
211
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000212
213 if(range->left.type == ARE_MIN
214 && range->right.type == ARE_MAX) {
215 /*
216 * The permitted alphabet constraint checker code guarantees
217 * that either both bounds (left/right) are present, or
218 * they're absent simultaneously. Thus, this assertion
219 * legitimately holds true.
220 */
221 assert(range->el_count == 0);
222 /* The full range is specified. Ignore it. */
223 return 0;
224 }
225
Lev Walkin84cd58e2004-08-19 13:29:46 +0000226 range_start = range->left.value;
227 range_stop = range->right.value;
228 assert(range->left.type == ARE_VALUE);
229 assert(range->right.type == ARE_VALUE);
230 assert(range_start <= range_stop);
231
232 range_start = 0; /* Force old behavior */
233
234 /*
235 * Check if we need a test table to check the alphabet.
236 */
237 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000238 if(range->el_count == 0) {
239 /*
240 * It's better to have a short if() check
241 * than waste 4k of table space
242 */
243 use_table = 0;
244 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000245 if((range_stop - range_start) > 255)
246 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000247 if(etype == ASN_STRING_UTF8String) {
248 if(range_stop >= 0x80)
249 use_table = 0;
250 else
251 max_table_size = 128;
252 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000253
254 if(!ct->_compile_mark)
255 ct->_compile_mark = ++global_compile_mark;
256
257 if(use_table) {
258 int i, n = 0;
259 int untl;
260 memset(table, 0, sizeof(table));
261 for(i = -1; i < range->el_count; i++) {
262 asn1cnst_range_t *r;
Lev Walkin05363a72004-09-29 13:16:40 +0000263 asn1c_integer_t v;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000264 if(i == -1) {
265 if(range->el_count) continue;
266 r = range;
267 } else {
268 r = range->elements[i];
269 }
270 for(v = r->left.value; v <= r->right.value; v++) {
271 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000272 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000273 table[v - range_start] = ++n;
274 }
275 }
276
Lev Walkin84cd58e2004-08-19 13:29:46 +0000277 untl = (range_stop - range_start) + 1;
278 untl += (untl % 16)?16 - (untl % 16):0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000279 OUT("static int permitted_alphabet_table_%d[%d] = {\n",
280 ct->_compile_mark, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000281 for(n = 0; n < untl; n++) {
282 OUT("%d,", table[n]?1:0);
283 if(!((n+1) % 16)) {
284 int c;
285 if(!n) {
286 OUT("\n");
287 continue;
288 }
289 OUT("\t/* ");
290 for(c = n - 15; c <= n; c++) {
291 if(table[c]) {
292 int a = c + range_start;
293 if(a > 0x20 && a < 0x80)
294 OUT("%c", a);
295 else
296 OUT(".");
297 } else {
298 OUT(" ");
299 }
300 }
301 OUT(" */");
302 OUT("\n");
303 }
304 }
305 OUT("};\n");
306 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000307 } else if(etype == ASN_STRING_UTF8String) {
308 /*
309 * UTF8String type is a special case in many respects.
310 */
Lev Walkin59004fa2004-08-20 13:37:01 +0000311 if(got_size) {
312 /*
313 * Size has been already determined.
314 * The UTF8String length checker also checks
315 * for the syntax validity, so we don't have
316 * to repeat this process twice.
317 */
318 ct->_compile_mark = 0; /* Don't generate code */
319 asn1constraint_range_free(range);
320 return 0;
321 } else {
322 utf8_full_alphabet_check = 1;
323 }
324 } else {
325 /*
326 * This permitted alphabet check will be
327 * expressed using conditional statements
328 * instead of table lookups. Table would be
329 * to large or otherwise inappropriate (too sparse?).
330 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000331 }
332
333 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
334 ct->_compile_mark);
Lev Walkin59004fa2004-08-20 13:37:01 +0000335 INDENT(+1);
336 if(utf8_full_alphabet_check) {
Lev Walkin29c41682004-10-02 16:44:55 +0000337 OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
338 OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000339 OUT("\n");
340 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000341 if(use_table) {
342 OUT("int *table = permitted_alphabet_table_%d;\n",
343 ct->_compile_mark);
344 emit_alphabet_check_loop(arg, 0);
345 } else {
346 emit_alphabet_check_loop(arg, range);
347 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000348 }
Lev Walkin775885e2004-08-22 12:47:03 +0000349 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000350 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000351 OUT("}\n");
352 OUT("\n");
353
354 asn1constraint_range_free(range);
355
356 return 0;
357}
358
359static int
360emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin05363a72004-09-29 13:16:40 +0000361 asn1c_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000362 asn1p_expr_t *terminal;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000363
Lev Walkine4d6ab82004-09-22 16:05:13 +0000364 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000365 if(terminal) {
366 OUT("/* The underlying type is %s */\n",
367 ASN_EXPR_TYPE2STR(terminal->expr_type));
368 } else {
369 terminal = arg->expr;
370 }
Lev Walkin02b137d2004-08-21 07:34:58 +0000371 OUT("const %s_t *st = sptr;\n",
Lev Walkin634a3b82004-08-22 03:30:05 +0000372 asn1c_type_name(arg, terminal, TNF_SAFE));
Lev Walkin84cd58e2004-08-19 13:29:46 +0000373
Lev Walkin634a3b82004-08-22 03:30:05 +0000374 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000375 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000376 OUT("const uint8_t *ch = st->buf;\n");
377 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000378 OUT("\n");
379 OUT("for(; ch < end; ch++) {\n");
380 INDENT(+1);
381 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000382 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000383 natural_stop = 0xffffffffUL;
384 break;
385 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000386 OUT("const uint8_t *ch = st->buf;\n");
387 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000388 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000389 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
390 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000391 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000392 OUT("uint32_t cv = (ch[0] << 24)\n");
393 OUT("\t\t| (ch[1] << 16)\n");
394 OUT("\t\t| (ch[2] << 8)\n");
395 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000396 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000397 natural_stop = 0xffffffffUL;
398 break;
399 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000400 OUT("const uint8_t *ch = st->buf;\n");
401 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000402 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000403 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
404 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000405 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000406 OUT("uint16_t cv = (ch[0] << 8)\n");
407 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000408 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000409 natural_stop = 0xffff;
410 break;
411 case ASN_BASIC_OCTET_STRING:
412 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000413 OUT("const uint8_t *ch = st->buf;\n");
414 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000415 OUT("\n");
416 OUT("for(; ch < end; ch++) {\n");
417 INDENT(+1);
418 OUT("uint8_t cv = *ch;\n");
419 natural_stop = 0xff;
420 break;
421 }
422
423 if(range) {
424 OUT("if(!(");
425 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
Lev Walkin775885e2004-08-22 12:47:03 +0000426 OUT(")) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000427 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000428 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000429 }
430
431 INDENT(-1);
432 OUT("}\n");
433
434 return 0;
435}
436
437static int
Lev Walkin05363a72004-09-29 13:16:40 +0000438emit_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 +0000439 int ignore_left;
440 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000441 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000442 int i;
443
444 for(i = -1; i < range->el_count; i++) {
445 asn1cnst_range_t *r;
446 if(i == -1) {
447 if(range->el_count) continue;
448 r = range;
449 } else {
450 if(i) OUT(" || ");
451 r = range->elements[i];
452 }
453
454 if(r != range) OUT("(");
455
456 ignore_left = (r->left.type == ARE_MIN)
457 || (natural_start != -1
458 && r->left.value <= natural_start);
459 ignore_right = (r->right.type == ARE_MAX)
460 || (natural_stop != -1
461 && r->right.value >= natural_stop);
462 if(ignore_left && ignore_right) {
463 OUT("1 /* Constraint matches natural range of %s */",
464 varname);
465 continue;
466 }
467
468 if(ignore_left) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000469 OUT("%s <= %" PRIdASN, varname,
470 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000471 } else if(ignore_right) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000472 OUT("%s >= %" PRIdASN, varname,
473 r->left.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000474 } else if(r->left.value == r->right.value) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000475 OUT("%s == %" PRIdASN, varname,
476 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000477 } else {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000478 OUT("%s >= %" PRIdASN " && %s <= %" PRIdASN,
Lev Walkin84cd58e2004-08-19 13:29:46 +0000479 varname,
Lev Walkin33c16ba2004-09-24 21:01:43 +0000480 r->left.value,
Lev Walkin84cd58e2004-08-19 13:29:46 +0000481 varname,
Lev Walkin33c16ba2004-09-24 21:01:43 +0000482 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000483 }
484 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000485 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000486 }
487
Lev Walkin59004fa2004-08-20 13:37:01 +0000488 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000489}
490
491static int
492emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
493
494 switch(etype) {
495 case ASN_BASIC_BIT_STRING:
496 OUT("if(st->size > 0) {\n");
497 OUT("\t/* Size in bits */\n");
Lev Walkincb2b2d12004-09-05 10:42:19 +0000498 OUT("\tsize = 8 * (st->size - 1) - (st->buf[0] & 0x7);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000499 OUT("} else {\n");
500 OUT("\tsize = 0;\n");
501 OUT("}\n");
502 break;
503 case ASN_STRING_UniversalString:
504 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
505 break;
506 case ASN_STRING_BMPString:
507 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
508 break;
509 case ASN_STRING_UTF8String:
Lev Walkin29c41682004-10-02 16:44:55 +0000510 OUT("size = UTF8String_length(st);\n");
511 OUT("if((ssize_t)size < 0) {\n");
512 OUT("\t_ASN_ERRLOG(app_errlog, app_key,\n");
513 OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
514 OUT("\t\ttd->name, __FILE__, __LINE__);\n");
515 OUT("\treturn -1;\n");
516 OUT("}\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000517 break;
518 case ASN_CONSTR_SET_OF:
519 case ASN_CONSTR_SEQUENCE_OF:
520 OUT("{ /* Determine the number of elements */\n");
521 INDENT(+1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000522 OUT("const A_%s_OF(void) *list;\n",
Lev Walkin84cd58e2004-08-19 13:29:46 +0000523 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin23fd2fa2005-01-27 17:58:47 +0000524 OUT("(const void *)list = sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000525 OUT("size = list->count;\n");
526 INDENT(-1);
527 OUT("}\n");
528 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000529 case ASN_BASIC_OCTET_STRING:
530 OUT("size = st->size;\n");
531 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000532 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000533 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000534 OUT("size = st->size;\n");
535 break;
536 } else {
537 const char *type_name = ASN_EXPR_TYPE2STR(etype);
538 if(!type_name) type_name = arg->expr->Identifier;
539 WARNING("SizeConstraint is not defined for %s",
540 type_name);
541 OUT_NOINDENT("#warning SizeConstraint "
542 "is not defined for %s!\n", type_name);
543 OUT("size = st->size;\n");
544 }
545 return -1;
546 }
547
548 return 0;
549}
550
551static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000552emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000553
554 switch(etype) {
555 case ASN_BASIC_INTEGER:
556 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000557 if(arg->flags & A1C_USE_NATIVE_TYPES) {
Lev Walkin02b137d2004-08-21 07:34:58 +0000558 OUT("value = *(const int *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000559 } else {
Lev Walkin6ea088f2004-09-07 06:31:15 +0000560 if(r_value->el_count == 0
561 && (
562 /* Speed-up common case: (0..MAX) */
563 (r_value->left.type == ARE_VALUE
564 && r_value->left.value == 0
565 && r_value->right.type == ARE_MAX)
566 ||
567 /* Speed-up common case: (MIN..-1) */
568 (r_value->left.type == ARE_MIN
569 && r_value->right.type == ARE_VALUE
570 && r_value->right.value == -1)
571 )) {
572 OUT("/* Check if the sign bit is present */\n");
573 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
574 break;
575 }
576
Lev Walkin05363a72004-09-29 13:16:40 +0000577 OUT("if(asn_INTEGER2long(st, &value)) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000578 INDENT(+1);
579 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000580 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
581 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000582 OUT("return -1;\n");
583 INDENT(-1);
584 OUT("}\n");
585 }
586 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000587 case ASN_BASIC_REAL:
588 if(arg->flags & A1C_USE_NATIVE_TYPES) {
589 OUT("value = *(const double *)sptr;\n");
590 } else {
Lev Walkin05363a72004-09-29 13:16:40 +0000591 OUT("if(asn_REAL2double(st, &value)) {\n");
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000592 INDENT(+1);
593 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
594 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
595 OUT("\ttd->name, __FILE__, __LINE__);\n");
596 OUT("return -1;\n");
597 INDENT(-1);
598 OUT("}\n");
599 }
600 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000601 case ASN_BASIC_BOOLEAN:
Lev Walkin02b137d2004-08-21 07:34:58 +0000602 OUT("value = (*(const int *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000603 break;
604 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000605 WARNING("%s:%d: Value cannot be determined "
606 "for constraint check for %s",
607 arg->mod->source_file_name,
608 arg->expr->_lineno,
609 arg->expr->Identifier
610 );
611 OUT_NOINDENT(
612 "#error %s:%d: Value of %s cannot be determined\n",
613 arg->mod->source_file_name,
614 arg->expr->_lineno,
615 arg->expr->Identifier
616 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000617 break;
618 }
619
620 return 0;
621}
622
623static asn1p_expr_type_e
624_find_terminal_type(arg_t *arg) {
625 asn1p_expr_t *expr;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000626 expr = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000627 if(expr) return expr->expr_type;
628 return A1TC_INVALID;
629}
630