2004-08-19 13:29:46 +00:00
|
|
|
#include "asn1c_internal.h"
|
|
|
|
#include "asn1c_constraint.h"
|
2004-08-20 13:37:01 +00:00
|
|
|
#include "asn1c_misc.h"
|
|
|
|
#include "asn1c_out.h"
|
2004-08-19 13:29:46 +00:00
|
|
|
|
|
|
|
#include <asn1fix_crange.h> /* constraint groker from libasn1fix */
|
|
|
|
#include <asn1fix_export.h> /* other exportable stuff from libasn1fix */
|
|
|
|
|
2004-08-20 13:37:01 +00:00
|
|
|
static int asn1c_emit_constraint_tables(arg_t *arg, int got_size);
|
2004-08-19 13:29:46 +00:00
|
|
|
static int emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range);
|
2004-09-07 06:31:15 +00:00
|
|
|
static int emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value);
|
2004-08-19 13:29:46 +00:00
|
|
|
static int emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype);
|
|
|
|
static asn1p_expr_type_e _find_terminal_type(arg_t *arg);
|
2004-09-29 13:16:40 +00:00
|
|
|
static 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);
|
2004-08-19 13:29:46 +00:00
|
|
|
|
|
|
|
#define MKID(id) asn1c_make_identifier(0, (id), 0)
|
|
|
|
|
|
|
|
static int global_compile_mark;
|
|
|
|
|
|
|
|
int
|
|
|
|
asn1c_emit_constraint_checking_code(arg_t *arg) {
|
|
|
|
asn1cnst_range_t *r_size;
|
|
|
|
asn1cnst_range_t *r_value;
|
|
|
|
asn1p_expr_t *expr = arg->expr;
|
|
|
|
asn1p_expr_type_e etype;
|
|
|
|
asn1p_constraint_t *ct;
|
|
|
|
int got_something = 0;
|
2004-08-20 13:37:01 +00:00
|
|
|
int produce_st = 0;
|
2004-08-19 13:29:46 +00:00
|
|
|
|
|
|
|
ct = expr->combined_constraints;
|
|
|
|
if(ct == NULL)
|
|
|
|
return 1; /* No additional constraints defined */
|
|
|
|
|
|
|
|
etype = _find_terminal_type(arg);
|
|
|
|
|
2004-08-25 02:03:59 +00:00
|
|
|
r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE,0,0,0);
|
|
|
|
r_size = asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE,0,0,0);
|
2004-08-19 13:29:46 +00:00
|
|
|
if(r_value) {
|
2004-08-25 02:03:59 +00:00
|
|
|
if(r_value->incompatible
|
2004-08-19 13:29:46 +00:00
|
|
|
|| r_value->empty_constraint
|
|
|
|
|| (r_value->left.type == ARE_MIN
|
|
|
|
&& r_value->right.type == ARE_MAX)
|
|
|
|
|| (etype == ASN_BASIC_BOOLEAN
|
|
|
|
&& r_value->left.value == 0
|
|
|
|
&& r_value->right.value == 1)
|
|
|
|
) {
|
|
|
|
asn1constraint_range_free(r_value);
|
|
|
|
r_value = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(r_size) {
|
2004-08-25 02:03:59 +00:00
|
|
|
if(r_size->incompatible
|
2004-08-19 13:29:46 +00:00
|
|
|
|| r_size->empty_constraint
|
|
|
|
|| (r_size->left.value == 0 /* or .type == MIN */
|
|
|
|
&& r_size->right.type == ARE_MAX)
|
|
|
|
) {
|
|
|
|
asn1constraint_range_free(r_size);
|
|
|
|
r_size = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-20 13:37:01 +00:00
|
|
|
/*
|
|
|
|
* Do we really need an "*st = sptr" pointer?
|
|
|
|
*/
|
|
|
|
switch(etype) {
|
|
|
|
case ASN_BASIC_INTEGER:
|
|
|
|
case ASN_BASIC_ENUMERATED:
|
2004-09-14 12:47:45 +00:00
|
|
|
case ASN_BASIC_REAL:
|
|
|
|
if(!(arg->flags & A1C_USE_NATIVE_TYPES))
|
2004-08-20 13:37:01 +00:00
|
|
|
produce_st = 1;
|
|
|
|
break;
|
2004-08-21 07:34:58 +00:00
|
|
|
case ASN_BASIC_BIT_STRING:
|
2004-08-20 13:37:01 +00:00
|
|
|
case ASN_BASIC_OCTET_STRING:
|
|
|
|
produce_st = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if(etype & ASN_STRING_MASK)
|
|
|
|
produce_st = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(produce_st)
|
2004-08-21 07:34:58 +00:00
|
|
|
OUT("const %s_t *st = sptr;\n",
|
|
|
|
asn1c_type_name(arg, arg->expr, TNF_SAFE));
|
2004-08-19 13:29:46 +00:00
|
|
|
|
|
|
|
if(r_size || r_value) {
|
|
|
|
if(r_size) {
|
|
|
|
OUT("size_t size;\n");
|
|
|
|
}
|
|
|
|
if(r_value)
|
|
|
|
switch(etype) {
|
|
|
|
case ASN_BASIC_INTEGER:
|
|
|
|
case ASN_BASIC_ENUMERATED:
|
|
|
|
OUT("long value;\n");
|
|
|
|
break;
|
2004-09-14 12:47:45 +00:00
|
|
|
case ASN_BASIC_REAL:
|
|
|
|
OUT("double value;\n");
|
|
|
|
break;
|
2004-08-19 13:29:46 +00:00
|
|
|
case ASN_BASIC_BOOLEAN:
|
|
|
|
OUT("int value;\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
OUT("\n");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Protection against null input.
|
|
|
|
*/
|
|
|
|
OUT("if(!sptr) {\n");
|
|
|
|
INDENT(+1);
|
|
|
|
OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
|
2004-08-22 13:47:59 +00:00
|
|
|
OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
|
|
|
|
OUT("\ttd->name, __FILE__, __LINE__);\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("return -1;\n");
|
|
|
|
INDENT(-1);
|
|
|
|
OUT("}\n");
|
|
|
|
OUT("\n");
|
|
|
|
|
|
|
|
if(r_value)
|
2004-09-07 06:31:15 +00:00
|
|
|
emit_value_determination_code(arg, etype, r_value);
|
2004-08-19 13:29:46 +00:00
|
|
|
if(r_size)
|
|
|
|
emit_size_determination_code(arg, etype);
|
|
|
|
|
2004-08-20 13:37:01 +00:00
|
|
|
INDENT(-1);
|
|
|
|
REDIR(OT_CTABLES);
|
|
|
|
/* Emit FROM() tables */
|
|
|
|
asn1c_emit_constraint_tables(arg, r_size?1:0);
|
|
|
|
REDIR(OT_CODE);
|
|
|
|
INDENT(+1);
|
|
|
|
|
2004-08-19 13:29:46 +00:00
|
|
|
/*
|
|
|
|
* Here is an if() {} else {} constaint checking code.
|
|
|
|
*/
|
|
|
|
OUT("\n");
|
|
|
|
OUT("if(");
|
|
|
|
INDENT(+1);
|
|
|
|
if(r_size) {
|
|
|
|
if(got_something++) { OUT("\n"); OUT(" && "); }
|
|
|
|
OUT("(");
|
|
|
|
emit_range_comparison_code(arg, r_size, "size", 0, -1);
|
|
|
|
OUT(")");
|
|
|
|
}
|
|
|
|
if(r_value) {
|
|
|
|
if(got_something++) { OUT("\n"); OUT(" && "); }
|
|
|
|
OUT("(");
|
|
|
|
if(etype == ASN_BASIC_BOOLEAN)
|
|
|
|
emit_range_comparison_code(arg, r_value,
|
|
|
|
"value", 0, 1);
|
|
|
|
else
|
|
|
|
emit_range_comparison_code(arg, r_value,
|
|
|
|
"value", -1, -1);
|
|
|
|
OUT(")");
|
|
|
|
}
|
|
|
|
if(ct->_compile_mark) {
|
|
|
|
if(got_something++) { OUT("\n"); OUT(" && "); }
|
2004-08-22 13:11:40 +00:00
|
|
|
OUT("!check_permitted_alphabet_%d(sptr)",
|
2004-08-19 13:29:46 +00:00
|
|
|
ct->_compile_mark);
|
|
|
|
}
|
|
|
|
if(!got_something) {
|
|
|
|
OUT("1 /* No applicable constraints whatsoever */");
|
2004-08-20 13:37:01 +00:00
|
|
|
OUT(") {\n");
|
|
|
|
INDENT(-1);
|
|
|
|
INDENTED(OUT("/* Nothing is here. See below */\n"));
|
|
|
|
OUT("}\n");
|
|
|
|
OUT("\n");
|
|
|
|
return 1;
|
2004-08-19 13:29:46 +00:00
|
|
|
}
|
|
|
|
INDENT(-1);
|
|
|
|
OUT(") {\n");
|
|
|
|
INDENT(+1);
|
|
|
|
OUT("/* Constraint check succeeded */\n");
|
2004-08-22 12:37:35 +00:00
|
|
|
OUT("return 0;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
INDENT(-1);
|
|
|
|
OUT("} else {\n");
|
|
|
|
INDENT(+1);
|
|
|
|
OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
|
2004-08-22 13:47:59 +00:00
|
|
|
OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
|
|
|
|
OUT("\ttd->name, __FILE__, __LINE__);\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("return -1;\n");
|
|
|
|
INDENT(-1);
|
|
|
|
OUT("}\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-20 13:37:01 +00:00
|
|
|
static int
|
|
|
|
asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
|
2004-09-29 13:16:40 +00:00
|
|
|
asn1c_integer_t range_start;
|
|
|
|
asn1c_integer_t range_stop;
|
2004-08-19 13:29:46 +00:00
|
|
|
asn1p_expr_type_e etype;
|
|
|
|
asn1cnst_range_t *range;
|
2004-08-20 13:37:01 +00:00
|
|
|
asn1p_constraint_t *ct;
|
|
|
|
int utf8_full_alphabet_check = 0;
|
|
|
|
int max_table_size = 256;
|
2004-08-19 13:29:46 +00:00
|
|
|
int table[256];
|
|
|
|
int use_table;
|
|
|
|
|
2004-08-20 13:37:01 +00:00
|
|
|
ct = arg->expr->combined_constraints;
|
2004-08-19 13:29:46 +00:00
|
|
|
if(!ct) return 0;
|
|
|
|
|
|
|
|
etype = _find_terminal_type(arg);
|
|
|
|
|
2004-08-25 02:03:59 +00:00
|
|
|
range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0,0,0);
|
2004-08-19 13:29:46 +00:00
|
|
|
if(!range) return 0;
|
|
|
|
|
2004-08-25 02:03:59 +00:00
|
|
|
if(range->incompatible
|
2004-08-19 13:29:46 +00:00
|
|
|
|| range->empty_constraint) {
|
|
|
|
asn1constraint_range_free(range);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-09-06 08:07:19 +00:00
|
|
|
|
|
|
|
if(range->left.type == ARE_MIN
|
|
|
|
&& range->right.type == ARE_MAX) {
|
|
|
|
/*
|
|
|
|
* The permitted alphabet constraint checker code guarantees
|
|
|
|
* that either both bounds (left/right) are present, or
|
|
|
|
* they're absent simultaneously. Thus, this assertion
|
|
|
|
* legitimately holds true.
|
|
|
|
*/
|
|
|
|
assert(range->el_count == 0);
|
|
|
|
/* The full range is specified. Ignore it. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-19 13:29:46 +00:00
|
|
|
range_start = range->left.value;
|
|
|
|
range_stop = range->right.value;
|
|
|
|
assert(range->left.type == ARE_VALUE);
|
|
|
|
assert(range->right.type == ARE_VALUE);
|
|
|
|
assert(range_start <= range_stop);
|
|
|
|
|
|
|
|
range_start = 0; /* Force old behavior */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if we need a test table to check the alphabet.
|
|
|
|
*/
|
|
|
|
use_table = 1;
|
2004-08-20 13:37:01 +00:00
|
|
|
if(range->el_count == 0) {
|
|
|
|
/*
|
|
|
|
* It's better to have a short if() check
|
|
|
|
* than waste 4k of table space
|
|
|
|
*/
|
2004-08-19 13:29:46 +00:00
|
|
|
use_table = 0;
|
2004-08-20 13:37:01 +00:00
|
|
|
}
|
|
|
|
if((range_stop - range_start) > 255)
|
2004-08-19 13:29:46 +00:00
|
|
|
use_table = 0;
|
2004-08-20 13:37:01 +00:00
|
|
|
if(etype == ASN_STRING_UTF8String) {
|
|
|
|
if(range_stop >= 0x80)
|
|
|
|
use_table = 0;
|
|
|
|
else
|
|
|
|
max_table_size = 128;
|
|
|
|
}
|
2004-08-19 13:29:46 +00:00
|
|
|
|
|
|
|
if(!ct->_compile_mark)
|
|
|
|
ct->_compile_mark = ++global_compile_mark;
|
|
|
|
|
|
|
|
if(use_table) {
|
|
|
|
int i, n = 0;
|
|
|
|
int untl;
|
|
|
|
memset(table, 0, sizeof(table));
|
|
|
|
for(i = -1; i < range->el_count; i++) {
|
|
|
|
asn1cnst_range_t *r;
|
2004-09-29 13:16:40 +00:00
|
|
|
asn1c_integer_t v;
|
2004-08-19 13:29:46 +00:00
|
|
|
if(i == -1) {
|
|
|
|
if(range->el_count) continue;
|
|
|
|
r = range;
|
|
|
|
} else {
|
|
|
|
r = range->elements[i];
|
|
|
|
}
|
|
|
|
for(v = r->left.value; v <= r->right.value; v++) {
|
|
|
|
assert((v - range_start) >= 0);
|
2004-08-20 13:37:01 +00:00
|
|
|
assert((v - range_start) < max_table_size);
|
2004-08-19 13:29:46 +00:00
|
|
|
table[v - range_start] = ++n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
untl = (range_stop - range_start) + 1;
|
|
|
|
untl += (untl % 16)?16 - (untl % 16):0;
|
2004-08-20 13:37:01 +00:00
|
|
|
OUT("static int permitted_alphabet_table_%d[%d] = {\n",
|
|
|
|
ct->_compile_mark, max_table_size);
|
2004-08-19 13:29:46 +00:00
|
|
|
for(n = 0; n < untl; n++) {
|
|
|
|
OUT("%d,", table[n]?1:0);
|
|
|
|
if(!((n+1) % 16)) {
|
|
|
|
int c;
|
|
|
|
if(!n) {
|
|
|
|
OUT("\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
OUT("\t/* ");
|
|
|
|
for(c = n - 15; c <= n; c++) {
|
|
|
|
if(table[c]) {
|
|
|
|
int a = c + range_start;
|
|
|
|
if(a > 0x20 && a < 0x80)
|
|
|
|
OUT("%c", a);
|
|
|
|
else
|
|
|
|
OUT(".");
|
|
|
|
} else {
|
|
|
|
OUT(" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
OUT(" */");
|
|
|
|
OUT("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
OUT("};\n");
|
|
|
|
OUT("\n");
|
2004-08-20 13:37:01 +00:00
|
|
|
} else if(etype == ASN_STRING_UTF8String) {
|
|
|
|
/*
|
|
|
|
* UTF8String type is a special case in many respects.
|
|
|
|
*/
|
|
|
|
if(got_size) {
|
|
|
|
/*
|
|
|
|
* Size has been already determined.
|
|
|
|
* The UTF8String length checker also checks
|
|
|
|
* for the syntax validity, so we don't have
|
|
|
|
* to repeat this process twice.
|
|
|
|
*/
|
|
|
|
ct->_compile_mark = 0; /* Don't generate code */
|
|
|
|
asn1constraint_range_free(range);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
utf8_full_alphabet_check = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* This permitted alphabet check will be
|
|
|
|
* expressed using conditional statements
|
|
|
|
* instead of table lookups. Table would be
|
|
|
|
* to large or otherwise inappropriate (too sparse?).
|
|
|
|
*/
|
2004-08-19 13:29:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
|
|
|
|
ct->_compile_mark);
|
2004-08-20 13:37:01 +00:00
|
|
|
INDENT(+1);
|
|
|
|
if(utf8_full_alphabet_check) {
|
2004-10-02 16:44:55 +00:00
|
|
|
OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n");
|
|
|
|
OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n");
|
2004-08-20 13:37:01 +00:00
|
|
|
OUT("\n");
|
|
|
|
} else {
|
2004-08-19 13:29:46 +00:00
|
|
|
if(use_table) {
|
|
|
|
OUT("int *table = permitted_alphabet_table_%d;\n",
|
|
|
|
ct->_compile_mark);
|
|
|
|
emit_alphabet_check_loop(arg, 0);
|
|
|
|
} else {
|
|
|
|
emit_alphabet_check_loop(arg, range);
|
|
|
|
}
|
2004-08-20 13:37:01 +00:00
|
|
|
}
|
2004-08-22 12:47:03 +00:00
|
|
|
OUT("return 0;\n");
|
2004-08-20 13:37:01 +00:00
|
|
|
INDENT(-1);
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("}\n");
|
|
|
|
OUT("\n");
|
|
|
|
|
|
|
|
asn1constraint_range_free(range);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
|
2004-09-29 13:16:40 +00:00
|
|
|
asn1c_integer_t natural_stop;
|
2004-08-22 03:30:05 +00:00
|
|
|
asn1p_expr_t *terminal;
|
2004-08-19 13:29:46 +00:00
|
|
|
|
2004-09-22 16:05:13 +00:00
|
|
|
terminal = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
|
2004-08-22 03:30:05 +00:00
|
|
|
if(terminal) {
|
|
|
|
OUT("/* The underlying type is %s */\n",
|
|
|
|
ASN_EXPR_TYPE2STR(terminal->expr_type));
|
|
|
|
} else {
|
|
|
|
terminal = arg->expr;
|
|
|
|
}
|
2004-08-21 07:34:58 +00:00
|
|
|
OUT("const %s_t *st = sptr;\n",
|
2004-08-22 03:30:05 +00:00
|
|
|
asn1c_type_name(arg, terminal, TNF_SAFE));
|
2004-08-19 13:29:46 +00:00
|
|
|
|
2004-08-22 03:30:05 +00:00
|
|
|
switch(terminal->expr_type) {
|
2004-08-19 13:29:46 +00:00
|
|
|
case ASN_STRING_UTF8String:
|
2004-08-21 07:34:58 +00:00
|
|
|
OUT("const uint8_t *ch = st->buf;\n");
|
|
|
|
OUT("const uint8_t *end = ch + st->size;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("\n");
|
|
|
|
OUT("for(; ch < end; ch++) {\n");
|
|
|
|
INDENT(+1);
|
|
|
|
OUT("uint8_t cv = *ch;\n");
|
2004-08-22 12:47:03 +00:00
|
|
|
if(!range) OUT("if(cv >= 0x80) return -1;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
natural_stop = 0xffffffffUL;
|
|
|
|
break;
|
|
|
|
case ASN_STRING_UniversalString:
|
2004-09-06 08:07:19 +00:00
|
|
|
OUT("const uint8_t *ch = st->buf;\n");
|
|
|
|
OUT("const uint8_t *end = ch + st->size;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("\n");
|
2004-09-06 08:07:19 +00:00
|
|
|
OUT("if(st->size %% 4) return -1; /* (size%%4)! */\n");
|
|
|
|
OUT("for(; ch < end; ch += 4) {\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
INDENT(+1);
|
2004-09-06 08:07:19 +00:00
|
|
|
OUT("uint32_t cv = (ch[0] << 24)\n");
|
|
|
|
OUT("\t\t| (ch[1] << 16)\n");
|
|
|
|
OUT("\t\t| (ch[2] << 8)\n");
|
|
|
|
OUT("\t\t| ch[3];\n");
|
2004-08-22 12:47:03 +00:00
|
|
|
if(!range) OUT("if(cv > 255) return -1;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
natural_stop = 0xffffffffUL;
|
|
|
|
break;
|
|
|
|
case ASN_STRING_BMPString:
|
2004-09-06 08:07:19 +00:00
|
|
|
OUT("const uint8_t *ch = st->buf;\n");
|
|
|
|
OUT("const uint8_t *end = ch + st->size;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("\n");
|
2004-09-06 08:07:19 +00:00
|
|
|
OUT("if(st->size %% 2) return -1; /* (size%%2)! */\n");
|
|
|
|
OUT("for(; ch < end; ch += 2) {\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
INDENT(+1);
|
2004-09-06 08:07:19 +00:00
|
|
|
OUT("uint16_t cv = (ch[0] << 8)\n");
|
|
|
|
OUT("\t\t| ch[1];\n");
|
2004-08-22 12:47:03 +00:00
|
|
|
if(!range) OUT("if(cv > 255) return -1;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
natural_stop = 0xffff;
|
|
|
|
break;
|
|
|
|
case ASN_BASIC_OCTET_STRING:
|
|
|
|
default:
|
2004-08-21 07:34:58 +00:00
|
|
|
OUT("const uint8_t *ch = st->buf;\n");
|
|
|
|
OUT("const uint8_t *end = ch + st->size;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("\n");
|
|
|
|
OUT("for(; ch < end; ch++) {\n");
|
|
|
|
INDENT(+1);
|
|
|
|
OUT("uint8_t cv = *ch;\n");
|
|
|
|
natural_stop = 0xff;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(range) {
|
|
|
|
OUT("if(!(");
|
|
|
|
emit_range_comparison_code(arg, range, "cv", 0, natural_stop);
|
2004-08-22 12:47:03 +00:00
|
|
|
OUT(")) return -1;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
} else {
|
2004-08-22 12:47:03 +00:00
|
|
|
OUT("if(!table[cv]) return -1;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
INDENT(-1);
|
|
|
|
OUT("}\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2004-09-29 13:16:40 +00:00
|
|
|
emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1c_integer_t natural_start, asn1c_integer_t natural_stop) {
|
2004-08-19 13:29:46 +00:00
|
|
|
int ignore_left;
|
|
|
|
int ignore_right;
|
2004-08-20 13:37:01 +00:00
|
|
|
int generated_something = 0;
|
2004-08-19 13:29:46 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i = -1; i < range->el_count; i++) {
|
|
|
|
asn1cnst_range_t *r;
|
|
|
|
if(i == -1) {
|
|
|
|
if(range->el_count) continue;
|
|
|
|
r = range;
|
|
|
|
} else {
|
|
|
|
if(i) OUT(" || ");
|
|
|
|
r = range->elements[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if(r != range) OUT("(");
|
|
|
|
|
|
|
|
ignore_left = (r->left.type == ARE_MIN)
|
|
|
|
|| (natural_start != -1
|
|
|
|
&& r->left.value <= natural_start);
|
|
|
|
ignore_right = (r->right.type == ARE_MAX)
|
|
|
|
|| (natural_stop != -1
|
|
|
|
&& r->right.value >= natural_stop);
|
|
|
|
if(ignore_left && ignore_right) {
|
|
|
|
OUT("1 /* Constraint matches natural range of %s */",
|
|
|
|
varname);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ignore_left) {
|
2004-09-24 21:01:43 +00:00
|
|
|
OUT("%s <= %" PRIdASN, varname,
|
|
|
|
r->right.value);
|
2004-08-19 13:29:46 +00:00
|
|
|
} else if(ignore_right) {
|
2004-09-24 21:01:43 +00:00
|
|
|
OUT("%s >= %" PRIdASN, varname,
|
|
|
|
r->left.value);
|
2004-08-19 13:29:46 +00:00
|
|
|
} else if(r->left.value == r->right.value) {
|
2004-09-24 21:01:43 +00:00
|
|
|
OUT("%s == %" PRIdASN, varname,
|
|
|
|
r->right.value);
|
2004-08-19 13:29:46 +00:00
|
|
|
} else {
|
2004-09-24 21:01:43 +00:00
|
|
|
OUT("%s >= %" PRIdASN " && %s <= %" PRIdASN,
|
2004-08-19 13:29:46 +00:00
|
|
|
varname,
|
2004-09-24 21:01:43 +00:00
|
|
|
r->left.value,
|
2004-08-19 13:29:46 +00:00
|
|
|
varname,
|
2004-09-24 21:01:43 +00:00
|
|
|
r->right.value);
|
2004-08-19 13:29:46 +00:00
|
|
|
}
|
|
|
|
if(r != range) OUT(")");
|
2004-08-20 13:37:01 +00:00
|
|
|
generated_something = 1;
|
2004-08-19 13:29:46 +00:00
|
|
|
}
|
|
|
|
|
2004-08-20 13:37:01 +00:00
|
|
|
return generated_something;
|
2004-08-19 13:29:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
|
|
|
|
|
|
|
|
switch(etype) {
|
|
|
|
case ASN_BASIC_BIT_STRING:
|
|
|
|
OUT("if(st->size > 0) {\n");
|
|
|
|
OUT("\t/* Size in bits */\n");
|
2004-09-05 10:42:19 +00:00
|
|
|
OUT("\tsize = 8 * (st->size - 1) - (st->buf[0] & 0x7);\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("} else {\n");
|
|
|
|
OUT("\tsize = 0;\n");
|
|
|
|
OUT("}\n");
|
|
|
|
break;
|
|
|
|
case ASN_STRING_UniversalString:
|
|
|
|
OUT("size = st->size >> 2;\t/* 4 byte per character */\n");
|
|
|
|
break;
|
|
|
|
case ASN_STRING_BMPString:
|
|
|
|
OUT("size = st->size >> 1;\t/* 2 byte per character */\n");
|
|
|
|
break;
|
|
|
|
case ASN_STRING_UTF8String:
|
2004-10-02 16:44:55 +00:00
|
|
|
OUT("size = UTF8String_length(st);\n");
|
|
|
|
OUT("if((ssize_t)size < 0) {\n");
|
|
|
|
OUT("\t_ASN_ERRLOG(app_errlog, app_key,\n");
|
|
|
|
OUT("\t\t\"%%s: UTF-8: broken encoding (%%s:%%d)\",\n");
|
|
|
|
OUT("\t\ttd->name, __FILE__, __LINE__);\n");
|
|
|
|
OUT("\treturn -1;\n");
|
|
|
|
OUT("}\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
break;
|
|
|
|
case ASN_CONSTR_SET_OF:
|
|
|
|
case ASN_CONSTR_SEQUENCE_OF:
|
|
|
|
OUT("{ /* Determine the number of elements */\n");
|
|
|
|
INDENT(+1);
|
2004-08-20 13:37:01 +00:00
|
|
|
OUT("const A_%s_OF(void) *list;\n",
|
2004-08-19 13:29:46 +00:00
|
|
|
etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
|
2005-01-17 14:39:11 +00:00
|
|
|
OUT("list = (const A_%s_OF(void) *)sptr;\n",
|
|
|
|
etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("size = list->count;\n");
|
|
|
|
INDENT(-1);
|
|
|
|
OUT("}\n");
|
|
|
|
break;
|
2004-08-20 13:37:01 +00:00
|
|
|
case ASN_BASIC_OCTET_STRING:
|
|
|
|
OUT("size = st->size;\n");
|
|
|
|
break;
|
2004-08-19 13:29:46 +00:00
|
|
|
default:
|
2004-08-20 13:37:01 +00:00
|
|
|
if(etype & ASN_STRING_MASK) {
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("size = st->size;\n");
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
const char *type_name = ASN_EXPR_TYPE2STR(etype);
|
|
|
|
if(!type_name) type_name = arg->expr->Identifier;
|
|
|
|
WARNING("SizeConstraint is not defined for %s",
|
|
|
|
type_name);
|
|
|
|
OUT_NOINDENT("#warning SizeConstraint "
|
|
|
|
"is not defined for %s!\n", type_name);
|
|
|
|
OUT("size = st->size;\n");
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2004-09-07 06:31:15 +00:00
|
|
|
emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value) {
|
2004-08-19 13:29:46 +00:00
|
|
|
|
|
|
|
switch(etype) {
|
|
|
|
case ASN_BASIC_INTEGER:
|
|
|
|
case ASN_BASIC_ENUMERATED:
|
2004-09-14 12:47:45 +00:00
|
|
|
if(arg->flags & A1C_USE_NATIVE_TYPES) {
|
2004-08-21 07:34:58 +00:00
|
|
|
OUT("value = *(const int *)sptr;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
} else {
|
2004-09-07 06:31:15 +00:00
|
|
|
if(r_value->el_count == 0
|
|
|
|
&& (
|
|
|
|
/* Speed-up common case: (0..MAX) */
|
|
|
|
(r_value->left.type == ARE_VALUE
|
|
|
|
&& r_value->left.value == 0
|
|
|
|
&& r_value->right.type == ARE_MAX)
|
|
|
|
||
|
|
|
|
/* Speed-up common case: (MIN..-1) */
|
|
|
|
(r_value->left.type == ARE_MIN
|
|
|
|
&& r_value->right.type == ARE_VALUE
|
|
|
|
&& r_value->right.value == -1)
|
|
|
|
)) {
|
|
|
|
OUT("/* Check if the sign bit is present */\n");
|
|
|
|
OUT("value = st->buf ? ((st->buf[0] & 0x80) ? -1 : 1) : 0;\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2004-09-29 13:16:40 +00:00
|
|
|
OUT("if(asn_INTEGER2long(st, &value)) {\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
INDENT(+1);
|
|
|
|
OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
|
2004-08-22 13:47:59 +00:00
|
|
|
OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
|
|
|
|
OUT("\ttd->name, __FILE__, __LINE__);\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
OUT("return -1;\n");
|
|
|
|
INDENT(-1);
|
|
|
|
OUT("}\n");
|
|
|
|
}
|
|
|
|
break;
|
2004-09-14 12:47:45 +00:00
|
|
|
case ASN_BASIC_REAL:
|
|
|
|
if(arg->flags & A1C_USE_NATIVE_TYPES) {
|
|
|
|
OUT("value = *(const double *)sptr;\n");
|
|
|
|
} else {
|
2004-09-29 13:16:40 +00:00
|
|
|
OUT("if(asn_REAL2double(st, &value)) {\n");
|
2004-09-14 12:47:45 +00:00
|
|
|
INDENT(+1);
|
|
|
|
OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
|
|
|
|
OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
|
|
|
|
OUT("\ttd->name, __FILE__, __LINE__);\n");
|
|
|
|
OUT("return -1;\n");
|
|
|
|
INDENT(-1);
|
|
|
|
OUT("}\n");
|
|
|
|
}
|
|
|
|
break;
|
2004-08-19 13:29:46 +00:00
|
|
|
case ASN_BASIC_BOOLEAN:
|
2004-08-21 07:34:58 +00:00
|
|
|
OUT("value = (*(const int *)sptr) ? 1 : 0;\n");
|
2004-08-19 13:29:46 +00:00
|
|
|
break;
|
|
|
|
default:
|
2004-08-21 07:34:58 +00:00
|
|
|
WARNING("%s:%d: Value cannot be determined "
|
|
|
|
"for constraint check for %s",
|
|
|
|
arg->mod->source_file_name,
|
|
|
|
arg->expr->_lineno,
|
|
|
|
arg->expr->Identifier
|
|
|
|
);
|
|
|
|
OUT_NOINDENT(
|
|
|
|
"#error %s:%d: Value of %s cannot be determined\n",
|
|
|
|
arg->mod->source_file_name,
|
|
|
|
arg->expr->_lineno,
|
|
|
|
arg->expr->Identifier
|
|
|
|
);
|
2004-08-19 13:29:46 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static asn1p_expr_type_e
|
|
|
|
_find_terminal_type(arg_t *arg) {
|
|
|
|
asn1p_expr_t *expr;
|
2004-09-22 16:05:13 +00:00
|
|
|
expr = asn1f_find_terminal_type_ex(arg->asn, arg->expr);
|
2004-08-19 13:29:46 +00:00
|
|
|
if(expr) return expr->expr_type;
|
|
|
|
return A1TC_INVALID;
|
|
|
|
}
|
|
|
|
|