blob: 9f2edeca6255ebe9a3ba4484ed43ab21d417f2b5 [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);
14static int emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1_integer_t natural_start, asn1_integer_t natural_stop);
15
16#define MKID(id) asn1c_make_identifier(0, (id), 0)
17
18static int global_compile_mark;
19
20int
21asn1c_emit_constraint_checking_code(arg_t *arg) {
22 asn1cnst_range_t *r_size;
23 asn1cnst_range_t *r_value;
24 asn1p_expr_t *expr = arg->expr;
25 asn1p_expr_type_e etype;
26 asn1p_constraint_t *ct;
27 int got_something = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +000028 int produce_st = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +000029
30 ct = expr->combined_constraints;
31 if(ct == NULL)
32 return 1; /* No additional constraints defined */
33
34 etype = _find_terminal_type(arg);
35
Lev Walkinbe717ec2004-08-25 02:03:59 +000036 r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE,0,0,0);
37 r_size = asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE,0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +000038 if(r_value) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000039 if(r_value->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000040 || r_value->empty_constraint
41 || (r_value->left.type == ARE_MIN
42 && r_value->right.type == ARE_MAX)
43 || (etype == ASN_BASIC_BOOLEAN
44 && r_value->left.value == 0
45 && r_value->right.value == 1)
46 ) {
47 asn1constraint_range_free(r_value);
48 r_value = 0;
49 }
50 }
51 if(r_size) {
Lev Walkinbe717ec2004-08-25 02:03:59 +000052 if(r_size->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +000053 || r_size->empty_constraint
54 || (r_size->left.value == 0 /* or .type == MIN */
55 && r_size->right.type == ARE_MAX)
56 ) {
57 asn1constraint_range_free(r_size);
58 r_size = 0;
59 }
60 }
61
Lev Walkin59004fa2004-08-20 13:37:01 +000062 /*
63 * Do we really need an "*st = sptr" pointer?
64 */
65 switch(etype) {
66 case ASN_BASIC_INTEGER:
67 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +000068 case ASN_BASIC_REAL:
69 if(!(arg->flags & A1C_USE_NATIVE_TYPES))
Lev Walkin59004fa2004-08-20 13:37:01 +000070 produce_st = 1;
71 break;
Lev Walkin02b137d2004-08-21 07:34:58 +000072 case ASN_BASIC_BIT_STRING:
Lev Walkin59004fa2004-08-20 13:37:01 +000073 case ASN_BASIC_OCTET_STRING:
74 produce_st = 1;
75 break;
76 default:
77 if(etype & ASN_STRING_MASK)
78 produce_st = 1;
79 break;
80 }
81 if(produce_st)
Lev Walkin02b137d2004-08-21 07:34:58 +000082 OUT("const %s_t *st = sptr;\n",
83 asn1c_type_name(arg, arg->expr, TNF_SAFE));
Lev Walkin84cd58e2004-08-19 13:29:46 +000084
85 if(r_size || r_value) {
86 if(r_size) {
87 OUT("size_t size;\n");
88 }
89 if(r_value)
90 switch(etype) {
91 case ASN_BASIC_INTEGER:
92 case ASN_BASIC_ENUMERATED:
93 OUT("long value;\n");
94 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +000095 case ASN_BASIC_REAL:
96 OUT("double value;\n");
97 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +000098 case ASN_BASIC_BOOLEAN:
99 OUT("int value;\n");
100 break;
101 default:
102 break;
103 }
104 }
105
106 OUT("\n");
107
108 /*
109 * Protection against null input.
110 */
111 OUT("if(!sptr) {\n");
112 INDENT(+1);
113 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000114 OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
115 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000116 OUT("return -1;\n");
117 INDENT(-1);
118 OUT("}\n");
119 OUT("\n");
120
121 if(r_value)
Lev Walkin6ea088f2004-09-07 06:31:15 +0000122 emit_value_determination_code(arg, etype, r_value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000123 if(r_size)
124 emit_size_determination_code(arg, etype);
125
Lev Walkin59004fa2004-08-20 13:37:01 +0000126 INDENT(-1);
127 REDIR(OT_CTABLES);
128 /* Emit FROM() tables */
129 asn1c_emit_constraint_tables(arg, r_size?1:0);
130 REDIR(OT_CODE);
131 INDENT(+1);
132
Lev Walkin84cd58e2004-08-19 13:29:46 +0000133 /*
134 * Here is an if() {} else {} constaint checking code.
135 */
136 OUT("\n");
137 OUT("if(");
138 INDENT(+1);
139 if(r_size) {
140 if(got_something++) { OUT("\n"); OUT(" && "); }
141 OUT("(");
142 emit_range_comparison_code(arg, r_size, "size", 0, -1);
143 OUT(")");
144 }
145 if(r_value) {
146 if(got_something++) { OUT("\n"); OUT(" && "); }
147 OUT("(");
148 if(etype == ASN_BASIC_BOOLEAN)
149 emit_range_comparison_code(arg, r_value,
150 "value", 0, 1);
151 else
152 emit_range_comparison_code(arg, r_value,
153 "value", -1, -1);
154 OUT(")");
155 }
156 if(ct->_compile_mark) {
157 if(got_something++) { OUT("\n"); OUT(" && "); }
Lev Walkin730b15a2004-08-22 13:11:40 +0000158 OUT("!check_permitted_alphabet_%d(sptr)",
Lev Walkin84cd58e2004-08-19 13:29:46 +0000159 ct->_compile_mark);
160 }
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);
173 OUT("/* Constraint check succeeded */\n");
Lev Walkin6db2f092004-08-22 12:37:35 +0000174 OUT("return 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000175 INDENT(-1);
176 OUT("} else {\n");
177 INDENT(+1);
178 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000179 OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
180 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000181 OUT("return -1;\n");
182 INDENT(-1);
183 OUT("}\n");
184
185 return 0;
186}
187
Lev Walkin59004fa2004-08-20 13:37:01 +0000188static int
189asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000190 asn1_integer_t range_start;
191 asn1_integer_t range_stop;
192 asn1p_expr_type_e etype;
193 asn1cnst_range_t *range;
Lev Walkin59004fa2004-08-20 13:37:01 +0000194 asn1p_constraint_t *ct;
195 int utf8_full_alphabet_check = 0;
196 int max_table_size = 256;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000197 int table[256];
198 int use_table;
199
Lev Walkin59004fa2004-08-20 13:37:01 +0000200 ct = arg->expr->combined_constraints;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000201 if(!ct) return 0;
202
203 etype = _find_terminal_type(arg);
204
Lev Walkinbe717ec2004-08-25 02:03:59 +0000205 range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0,0,0);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000206 if(!range) return 0;
207
Lev Walkinbe717ec2004-08-25 02:03:59 +0000208 if(range->incompatible
Lev Walkin84cd58e2004-08-19 13:29:46 +0000209 || range->empty_constraint) {
210 asn1constraint_range_free(range);
211 return 0;
212 }
213
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000214
215 if(range->left.type == ARE_MIN
216 && range->right.type == ARE_MAX) {
217 /*
218 * The permitted alphabet constraint checker code guarantees
219 * that either both bounds (left/right) are present, or
220 * they're absent simultaneously. Thus, this assertion
221 * legitimately holds true.
222 */
223 assert(range->el_count == 0);
224 /* The full range is specified. Ignore it. */
225 return 0;
226 }
227
Lev Walkin84cd58e2004-08-19 13:29:46 +0000228 range_start = range->left.value;
229 range_stop = range->right.value;
230 assert(range->left.type == ARE_VALUE);
231 assert(range->right.type == ARE_VALUE);
232 assert(range_start <= range_stop);
233
234 range_start = 0; /* Force old behavior */
235
236 /*
237 * Check if we need a test table to check the alphabet.
238 */
239 use_table = 1;
Lev Walkin59004fa2004-08-20 13:37:01 +0000240 if(range->el_count == 0) {
241 /*
242 * It's better to have a short if() check
243 * than waste 4k of table space
244 */
245 use_table = 0;
246 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000247 if((range_stop - range_start) > 255)
248 use_table = 0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000249 if(etype == ASN_STRING_UTF8String) {
250 if(range_stop >= 0x80)
251 use_table = 0;
252 else
253 max_table_size = 128;
254 }
Lev Walkin84cd58e2004-08-19 13:29:46 +0000255
256 if(!ct->_compile_mark)
257 ct->_compile_mark = ++global_compile_mark;
258
259 if(use_table) {
260 int i, n = 0;
261 int untl;
262 memset(table, 0, sizeof(table));
263 for(i = -1; i < range->el_count; i++) {
264 asn1cnst_range_t *r;
265 asn1_integer_t v;
266 if(i == -1) {
267 if(range->el_count) continue;
268 r = range;
269 } else {
270 r = range->elements[i];
271 }
272 for(v = r->left.value; v <= r->right.value; v++) {
273 assert((v - range_start) >= 0);
Lev Walkin59004fa2004-08-20 13:37:01 +0000274 assert((v - range_start) < max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000275 table[v - range_start] = ++n;
276 }
277 }
278
Lev Walkin84cd58e2004-08-19 13:29:46 +0000279 untl = (range_stop - range_start) + 1;
280 untl += (untl % 16)?16 - (untl % 16):0;
Lev Walkin59004fa2004-08-20 13:37:01 +0000281 OUT("static int permitted_alphabet_table_%d[%d] = {\n",
282 ct->_compile_mark, max_table_size);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000283 for(n = 0; n < untl; n++) {
284 OUT("%d,", table[n]?1:0);
285 if(!((n+1) % 16)) {
286 int c;
287 if(!n) {
288 OUT("\n");
289 continue;
290 }
291 OUT("\t/* ");
292 for(c = n - 15; c <= n; c++) {
293 if(table[c]) {
294 int a = c + range_start;
295 if(a > 0x20 && a < 0x80)
296 OUT("%c", a);
297 else
298 OUT(".");
299 } else {
300 OUT(" ");
301 }
302 }
303 OUT(" */");
304 OUT("\n");
305 }
306 }
307 OUT("};\n");
308 OUT("\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000309 } else if(etype == ASN_STRING_UTF8String) {
310 /*
311 * UTF8String type is a special case in many respects.
312 */
313 assert(range_stop > 255); /* This one's unobvious */
314 if(got_size) {
315 /*
316 * Size has been already determined.
317 * The UTF8String length checker also checks
318 * for the syntax validity, so we don't have
319 * to repeat this process twice.
320 */
321 ct->_compile_mark = 0; /* Don't generate code */
322 asn1constraint_range_free(range);
323 return 0;
324 } else {
325 utf8_full_alphabet_check = 1;
326 }
327 } else {
328 /*
329 * This permitted alphabet check will be
330 * expressed using conditional statements
331 * instead of table lookups. Table would be
332 * to large or otherwise inappropriate (too sparse?).
333 */
Lev Walkin84cd58e2004-08-19 13:29:46 +0000334 }
335
336 OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
337 ct->_compile_mark);
Lev Walkin59004fa2004-08-20 13:37:01 +0000338 INDENT(+1);
339 if(utf8_full_alphabet_check) {
340 OUT("if(UTF8String_length((UTF8String_t *)sptr, td->name, \n");
341 OUT("\tapp_errlog, app_key) == -1)\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000342 OUT("\t\treturn -1; /* Alphabet (sic!) test failed. */\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000343 OUT("\n");
344 } else {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000345 if(use_table) {
346 OUT("int *table = permitted_alphabet_table_%d;\n",
347 ct->_compile_mark);
348 emit_alphabet_check_loop(arg, 0);
349 } else {
350 emit_alphabet_check_loop(arg, range);
351 }
Lev Walkin59004fa2004-08-20 13:37:01 +0000352 }
Lev Walkin775885e2004-08-22 12:47:03 +0000353 OUT("return 0;\n");
Lev Walkin59004fa2004-08-20 13:37:01 +0000354 INDENT(-1);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000355 OUT("}\n");
356 OUT("\n");
357
358 asn1constraint_range_free(range);
359
360 return 0;
361}
362
363static int
364emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000365 asn1_integer_t natural_stop;
Lev Walkin634a3b82004-08-22 03:30:05 +0000366 asn1p_expr_t *terminal;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000367
Lev Walkine4d6ab82004-09-22 16:05:13 +0000368 terminal = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin634a3b82004-08-22 03:30:05 +0000369 if(terminal) {
370 OUT("/* The underlying type is %s */\n",
371 ASN_EXPR_TYPE2STR(terminal->expr_type));
372 } else {
373 terminal = arg->expr;
374 }
Lev Walkin02b137d2004-08-21 07:34:58 +0000375 OUT("const %s_t *st = sptr;\n",
Lev Walkin634a3b82004-08-22 03:30:05 +0000376 asn1c_type_name(arg, terminal, TNF_SAFE));
Lev Walkin84cd58e2004-08-19 13:29:46 +0000377
Lev Walkin634a3b82004-08-22 03:30:05 +0000378 switch(terminal->expr_type) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000379 case ASN_STRING_UTF8String:
Lev Walkin02b137d2004-08-21 07:34:58 +0000380 OUT("const uint8_t *ch = st->buf;\n");
381 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000382 OUT("\n");
383 OUT("for(; ch < end; ch++) {\n");
384 INDENT(+1);
385 OUT("uint8_t cv = *ch;\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000386 if(!range) OUT("if(cv >= 0x80) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000387 natural_stop = 0xffffffffUL;
388 break;
389 case ASN_STRING_UniversalString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000390 OUT("const uint8_t *ch = st->buf;\n");
391 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000392 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000393 OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
394 OUT("for(; ch < end; ch += 4) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000395 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000396 OUT("uint32_t cv = (ch[0] << 24)\n");
397 OUT("\t\t| (ch[1] << 16)\n");
398 OUT("\t\t| (ch[2] << 8)\n");
399 OUT("\t\t| ch[3];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000400 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000401 natural_stop = 0xffffffffUL;
402 break;
403 case ASN_STRING_BMPString:
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000404 OUT("const uint8_t *ch = st->buf;\n");
405 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000406 OUT("\n");
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000407 OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
408 OUT("for(; ch < end; ch += 2) {\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000409 INDENT(+1);
Lev Walkinfd71d1e2004-09-06 08:07:19 +0000410 OUT("uint16_t cv = (ch[0] << 8)\n");
411 OUT("\t\t| ch[1];\n");
Lev Walkin775885e2004-08-22 12:47:03 +0000412 if(!range) OUT("if(cv > 255) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000413 natural_stop = 0xffff;
414 break;
415 case ASN_BASIC_OCTET_STRING:
416 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000417 OUT("const uint8_t *ch = st->buf;\n");
418 OUT("const uint8_t *end = ch + st->size;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000419 OUT("\n");
420 OUT("for(; ch < end; ch++) {\n");
421 INDENT(+1);
422 OUT("uint8_t cv = *ch;\n");
423 natural_stop = 0xff;
424 break;
425 }
426
427 if(range) {
428 OUT("if(!(");
429 emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
Lev Walkin775885e2004-08-22 12:47:03 +0000430 OUT(")) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000431 } else {
Lev Walkin775885e2004-08-22 12:47:03 +0000432 OUT("if(!table[cv]) return -1;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000433 }
434
435 INDENT(-1);
436 OUT("}\n");
437
438 return 0;
439}
440
441static int
442emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1_integer_t natural_start, asn1_integer_t natural_stop) {
443 int ignore_left;
444 int ignore_right;
Lev Walkin59004fa2004-08-20 13:37:01 +0000445 int generated_something = 0;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000446 int i;
447
448 for(i = -1; i < range->el_count; i++) {
449 asn1cnst_range_t *r;
450 if(i == -1) {
451 if(range->el_count) continue;
452 r = range;
453 } else {
454 if(i) OUT(" || ");
455 r = range->elements[i];
456 }
457
458 if(r != range) OUT("(");
459
460 ignore_left = (r->left.type == ARE_MIN)
461 || (natural_start != -1
462 && r->left.value <= natural_start);
463 ignore_right = (r->right.type == ARE_MAX)
464 || (natural_stop != -1
465 && r->right.value >= natural_stop);
466 if(ignore_left && ignore_right) {
467 OUT("1 /* Constraint matches natural range of %s */",
468 varname);
469 continue;
470 }
471
472 if(ignore_left) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000473 OUT("%s <= %" PRIdASN, varname,
474 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000475 } else if(ignore_right) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000476 OUT("%s >= %" PRIdASN, varname,
477 r->left.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000478 } else if(r->left.value == r->right.value) {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000479 OUT("%s == %" PRIdASN, varname,
480 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000481 } else {
Lev Walkin33c16ba2004-09-24 21:01:43 +0000482 OUT("%s >= %" PRIdASN " && %s <= %" PRIdASN,
Lev Walkin84cd58e2004-08-19 13:29:46 +0000483 varname,
Lev Walkin33c16ba2004-09-24 21:01:43 +0000484 r->left.value,
Lev Walkin84cd58e2004-08-19 13:29:46 +0000485 varname,
Lev Walkin33c16ba2004-09-24 21:01:43 +0000486 r->right.value);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000487 }
488 if(r != range) OUT(")");
Lev Walkin59004fa2004-08-20 13:37:01 +0000489 generated_something = 1;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000490 }
491
Lev Walkin59004fa2004-08-20 13:37:01 +0000492 return generated_something;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000493}
494
495static int
496emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
497
498 switch(etype) {
499 case ASN_BASIC_BIT_STRING:
500 OUT("if(st->size > 0) {\n");
501 OUT("\t/* Size in bits */\n");
Lev Walkincb2b2d12004-09-05 10:42:19 +0000502 OUT("\tsize = 8 * (st->size - 1) - (st->buf[0] & 0x7);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000503 OUT("} else {\n");
504 OUT("\tsize = 0;\n");
505 OUT("}\n");
506 break;
507 case ASN_STRING_UniversalString:
508 OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
509 break;
510 case ASN_STRING_BMPString:
511 OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
512 break;
513 case ASN_STRING_UTF8String:
514 OUT("size = UTF8String_length(st, td->name, app_errlog, app_key);\n");
515 OUT("if(size == (size_t)-1) return -1;\n");
516 break;
517 case ASN_CONSTR_SET_OF:
518 case ASN_CONSTR_SEQUENCE_OF:
519 OUT("{ /* Determine the number of elements */\n");
520 INDENT(+1);
Lev Walkin59004fa2004-08-20 13:37:01 +0000521 OUT("const A_%s_OF(void) *list;\n",
Lev Walkin84cd58e2004-08-19 13:29:46 +0000522 etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
Lev Walkin59004fa2004-08-20 13:37:01 +0000523 OUT("(const void *)list = sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000524 OUT("size = list->count;\n");
525 INDENT(-1);
526 OUT("}\n");
527 break;
Lev Walkin59004fa2004-08-20 13:37:01 +0000528 case ASN_BASIC_OCTET_STRING:
529 OUT("size = st->size;\n");
530 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000531 default:
Lev Walkin59004fa2004-08-20 13:37:01 +0000532 if(etype & ASN_STRING_MASK) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000533 OUT("size = st->size;\n");
534 break;
535 } else {
536 const char *type_name = ASN_EXPR_TYPE2STR(etype);
537 if(!type_name) type_name = arg->expr->Identifier;
538 WARNING("SizeConstraint is not defined for %s",
539 type_name);
540 OUT_NOINDENT("#warning SizeConstraint "
541 "is not defined for %s!\n", type_name);
542 OUT("size = st->size;\n");
543 }
544 return -1;
545 }
546
547 return 0;
548}
549
550static int
Lev Walkin6ea088f2004-09-07 06:31:15 +0000551emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
Lev Walkin84cd58e2004-08-19 13:29:46 +0000552
553 switch(etype) {
554 case ASN_BASIC_INTEGER:
555 case ASN_BASIC_ENUMERATED:
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000556 if(arg->flags & A1C_USE_NATIVE_TYPES) {
Lev Walkin02b137d2004-08-21 07:34:58 +0000557 OUT("value = *(const int *)sptr;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000558 } else {
Lev Walkin6ea088f2004-09-07 06:31:15 +0000559 if(r_value->el_count == 0
560 && (
561 /* Speed-up common case: (0..MAX) */
562 (r_value->left.type == ARE_VALUE
563 && r_value->left.value == 0
564 && r_value->right.type == ARE_MAX)
565 ||
566 /* Speed-up common case: (MIN..-1) */
567 (r_value->left.type == ARE_MIN
568 && r_value->right.type == ARE_VALUE
569 && r_value->right.value == -1)
570 )) {
571 OUT("/* Check if the sign bit is present */\n");
572 OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
573 break;
574 }
575
Lev Walkin84cd58e2004-08-19 13:29:46 +0000576 OUT("if(asn1_INTEGER2long(st, &value)) {\n");
577 INDENT(+1);
578 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
Lev Walkin16835b62004-08-22 13:47:59 +0000579 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
580 OUT("\ttd->name, __FILE__, __LINE__);\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000581 OUT("return -1;\n");
582 INDENT(-1);
583 OUT("}\n");
584 }
585 break;
Lev Walkinc78cbfb2004-09-14 12:47:45 +0000586 case ASN_BASIC_REAL:
587 if(arg->flags & A1C_USE_NATIVE_TYPES) {
588 OUT("value = *(const double *)sptr;\n");
589 } else {
590 OUT("if(asn1_REAL2double(st, &value)) {\n");
591 INDENT(+1);
592 OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
593 OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
594 OUT("\ttd->name, __FILE__, __LINE__);\n");
595 OUT("return -1;\n");
596 INDENT(-1);
597 OUT("}\n");
598 }
599 break;
Lev Walkin84cd58e2004-08-19 13:29:46 +0000600 case ASN_BASIC_BOOLEAN:
Lev Walkin02b137d2004-08-21 07:34:58 +0000601 OUT("value = (*(const int *)sptr) ? 1 : 0;\n");
Lev Walkin84cd58e2004-08-19 13:29:46 +0000602 break;
603 default:
Lev Walkin02b137d2004-08-21 07:34:58 +0000604 WARNING("%s:%d: Value cannot be determined "
605 "for constraint check for %s",
606 arg->mod->source_file_name,
607 arg->expr->_lineno,
608 arg->expr->Identifier
609 );
610 OUT_NOINDENT(
611 "#error %s:%d: Value of %s cannot be determined\n",
612 arg->mod->source_file_name,
613 arg->expr->_lineno,
614 arg->expr->Identifier
615 );
Lev Walkin84cd58e2004-08-19 13:29:46 +0000616 break;
617 }
618
619 return 0;
620}
621
622static asn1p_expr_type_e
623_find_terminal_type(arg_t *arg) {
624 asn1p_expr_t *expr;
Lev Walkine4d6ab82004-09-22 16:05:13 +0000625 expr = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
Lev Walkin84cd58e2004-08-19 13:29:46 +0000626 if(expr) return expr->expr_type;
627 return A1TC_INVALID;
628}
629