constraint checking code

git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@149 59561ff5-6e30-0410-9f3c-9617f08c8826
This commit is contained in:
vlm 2004-08-19 13:29:46 +00:00
parent 2248d718ef
commit 1d03669d1b
6 changed files with 508 additions and 705 deletions

View File

@ -13,7 +13,9 @@ libasn1compiler_la_SOURCES = \
asn1c_lang.c asn1c_lang.h \
asn1c_save.c asn1c_save.h \
asn1c_C.c asn1c_C.h \
asn1c_constraint.c asn1c_constraint.h \
asn1c_compat.c asn1c_compat.h \
asn1c_fdeps.c asn1c_fdeps.h \
asn1c_internal.h
TESTS = $(check_PROGRAMS)

View File

@ -53,7 +53,7 @@ LTLIBRARIES = $(noinst_LTLIBRARIES)
libasn1compiler_la_LIBADD =
am_libasn1compiler_la_OBJECTS = asn1compiler.lo asn1c_misc.lo \
asn1c_out.lo asn1c_lang.lo asn1c_save.lo asn1c_C.lo \
asn1c_compat.lo
asn1c_constraint.lo asn1c_compat.lo asn1c_fdeps.lo
libasn1compiler_la_OBJECTS = $(am_libasn1compiler_la_OBJECTS)
check_compiler_SOURCES = check_compiler.c
check_compiler_OBJECTS = check_compiler.$(OBJEXT)
@ -66,6 +66,8 @@ depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/asn1c_C.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1c_compat.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1c_constraint.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1c_fdeps.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1c_lang.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1c_misc.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/asn1c_out.Plo \
@ -208,7 +210,9 @@ libasn1compiler_la_SOURCES = \
asn1c_lang.c asn1c_lang.h \
asn1c_save.c asn1c_save.h \
asn1c_C.c asn1c_C.h \
asn1c_constraint.c asn1c_constraint.h \
asn1c_compat.c asn1c_compat.h \
asn1c_fdeps.c asn1c_fdeps.h \
asn1c_internal.h
TESTS = $(check_PROGRAMS)
@ -279,6 +283,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_C.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_compat.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_constraint.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_fdeps.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_lang.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_misc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_out.Plo@am__quote@

View File

@ -4,7 +4,8 @@
*/
#include "asn1c_internal.h"
#include "asn1c_C.h"
#include <asn1fix_export.h> /* exportable stuff from libasn1fix */
#include "asn1c_constraint.h"
#include <asn1fix_export.h> /* Stuff exported by libasn1fix */
typedef struct tag2el_s {
struct asn1p_type_tag_s el_tag;
@ -25,17 +26,6 @@ static int _print_tag(arg_t *arg, asn1p_expr_t *expr, struct asn1p_type_tag_s *t
static int check_if_extensible(asn1p_expr_t *expr);
static int emit_tags_vector(arg_t *arg, asn1p_expr_t *expr, int *tags_impl_skip, int choice_mode);
static int emit_tag2member_map(arg_t *arg, tag2el_t *tag2el, int tag2el_count);
static int emit_constraint_checking_code(arg_t *arg);
static int emit_single_constraint_check(arg_t *arg, asn1p_constraint_t *ct, int mode);
static int emit_alphabet_tables(arg_t *arg, asn1p_constraint_t *ct, int *table);
static int emit_alphabet_check_cycle(arg_t *arg);
static int check_constraint_type_presence(asn1p_constraint_t *ct, enum asn1p_constraint_type_e type);
static asn1p_expr_type_e _find_terminal_type(arg_t *arg);
static int emit_value_determination_code(arg_t *arg);
static int emit_size_determination_code(arg_t *arg);
static long compute_min_size(arg_t *arg);
static long compute_max_size(arg_t *arg);
static long compute_xxx_size(arg_t *arg, int _max);
#define C99_MODE (arg->flags & A1C_NO_C99)
#define UNNAMED_UNIONS (arg->flags & A1C_UNNAMED_UNIONS)
@ -969,28 +959,28 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) {
/*
* Constraint checking.
*/
if(expr->constraints) /* Emit tables with FROM() constraints */
emit_alphabet_tables(arg, expr->constraints, 0);
/* Emit FROM() tables and others */
asn1c_emit_constraint_tables(arg, 0);
p = MKID(expr->Identifier);
OUT("int\n");
OUT("%s_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,\n", p);
INDENTED(
OUT("\t\tasn_app_consume_bytes_f *app_errlog, void *app_key) {\n");
OUT("\n");
if(expr->constraints) {
emit_constraint_checking_code(arg);
if(asn1c_emit_constraint_checking_code(arg) == 1) {
if(0) {
OUT("/* Check the constraints of the underlying type */\n");
OUT("return asn1_DEF_%s.check_constraints\n",
asn1c_type_name(arg, expr, TNF_SAFE));
OUT("\t(td, sptr, app_errlog, app_key);\n");
} else {
} else {
OUT("/* Make the underlying type checker permanent */\n");
OUT("td->check_constraints = asn1_DEF_%s.check_constraints;\n",
asn1c_type_name(arg, expr, TNF_SAFE));
OUT("return td->check_constraints\n");
OUT("\t(td, sptr, app_errlog, app_key);\n");
}
}
);
OUT("}\n");
@ -1365,687 +1355,3 @@ emit_tags_vector(arg_t *arg, asn1p_expr_t *expr, int *tags_impl_skip, int choice
return tags_count;
}
static int
emit_constraint_checking_code(arg_t *arg) {
asn1p_expr_t *expr = arg->expr;
asn1p_expr_type_e etype;
int size_present, value_present;
if(expr->constraints == NULL)
return 0; /* No constraints defined */
etype = _find_terminal_type(arg);
size_present = check_constraint_type_presence(expr->constraints,
ACT_CT_SIZE);
value_present = check_constraint_type_presence(expr->constraints,
ACT_EL_VALUE);
if(size_present || value_present) {
OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier));
if(size_present) {
OUT("size_t size;\n");
OUT("size_t min_size __attribute__ ((unused)) = %ld;\n",
compute_min_size(arg));
OUT("size_t max_size __attribute__ ((unused)) = %ld;\n",
compute_max_size(arg));
}
if(value_present)
switch(etype) {
case ASN_BASIC_INTEGER:
case ASN_BASIC_ENUMERATED:
OUT("long value;\n");
break;
case ASN_BASIC_BOOLEAN:
OUT("int value;\n");
break;
default:
break;
}
OUT("\n");
}
OUT("if(!sptr) {\n");
INDENT(+1);
OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
OUT("\t\"%%s: value not given\", td->name);\n");
OUT("return -1;\n");
INDENT(-1);
OUT("}\n");
OUT("\n");
if(size_present)
emit_size_determination_code(arg);
if(value_present)
emit_value_determination_code(arg);
OUT("\n");
OUT("if(\n");
emit_single_constraint_check(arg, expr->constraints, 0);
OUT(") {\n");
INDENTED(OUT("/* Constraint check succeeded */\n"));
OUT("} else {\n");
INDENT(+1);
OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
OUT("\t\"%%s: constraint failed\", td->name);\n");
OUT("return -1;\n");
INDENT(-1);
OUT("}\n");
return 0;
}
static int
emit_single_constraint_check(arg_t *arg, asn1p_constraint_t *ct, int mode) {
char *s_v;
int el;
assert(arg && ct);
switch(ct->type) {
case ACT_INVALID:
assert(ct->type != ACT_INVALID);
OUT("-1 /* Invalid constraint at line %d */\n", ct->_lineno);
break;
case ACT_EL_VALUE:
OUT("(");
if(mode == ACT_CT_SIZE) s_v = "size";
else s_v = "value";
OUT("%s", s_v);
if(ct->value->type != ATV_TRUE)
OUT(" == ");
switch(ct->value->type) {
case ATV_INTEGER: OUT("%lld",
(long long)ct->value->value.v_integer); break;
case ATV_MIN: OUT("min_%s", s_v); break;
case ATV_MAX: OUT("max_%s", s_v); break;
case ATV_FALSE: OUT("0"); break;
case ATV_TRUE: break;
default:
break;
}
OUT(")\n");
break;
case ACT_EL_RANGE:
case ACT_EL_LLRANGE:
case ACT_EL_RLRANGE:
case ACT_EL_ULRANGE:
if(mode == ACT_CT_SIZE) {
s_v = "size";
} else {
s_v = "value";
}
OUT("((%s", s_v);
switch(ct->type) {
case ACT_EL_RANGE:
case ACT_EL_RLRANGE:
OUT(" >= "); break;
case ACT_EL_LLRANGE:
case ACT_EL_ULRANGE:
OUT(" > "); break;
default: break;
}
switch(ct->range_start->type) {
case ATV_INTEGER: OUT("%lld",
(long long)ct->range_start->value.v_integer); break;
case ATV_MIN: OUT("min_%s", s_v); break;
case ATV_MAX: OUT("max_%s", s_v); break;
case ATV_FALSE: OUT("0"); break;
case ATV_TRUE: break;
default:
break;
}
OUT(") && (%s", s_v);
switch(ct->type) {
case ACT_EL_RANGE:
case ACT_EL_LLRANGE:
OUT(" <= "); break;
case ACT_EL_RLRANGE:
case ACT_EL_ULRANGE:
OUT(" < "); break;
default: break;
}
switch(ct->range_stop->type) {
case ATV_INTEGER: OUT("%lld",
(long long)ct->range_stop->value.v_integer); break;
case ATV_MIN: OUT("min_%s", s_v); break;
case ATV_MAX: OUT("max_%s", s_v); break;
case ATV_FALSE: OUT("0"); break;
case ATV_TRUE: break;
default:
break;
}
OUT("))\n");
break;
case ACT_EL_EXT:
OUT("0 /* Extensible (...), but not defined herein */\n");
break;
case ACT_CT_SIZE:
if(mode) {
OUT("0 /* Invalid constraint at line %d */\n",
ct->_lineno);
return -1;
}
assert(ct->el_count == 1);
return emit_single_constraint_check(arg,
ct->elements[0], ACT_CT_SIZE);
case ACT_CT_FROM:
if(mode) {
OUT("0 /* Invalid constraint at line %d */\n",
ct->_lineno);
return -1;
}
OUT("check_alphabet_%x(sptr)\n", ct);
break;
case ACT_CT_WCOMP:
case ACT_CT_WCOMPS:
OUT("%d /* Unsupported constraint at line %d */\n",
ct->type, ct->_lineno);
return -1;
break;
case ACT_CA_SET:
OUT("(\n");
INDENT(+1);
for(el = 0; el < ct->el_count; el++) {
if(el) OUT("&& ");
emit_single_constraint_check(arg,
ct->elements[el], mode);
}
INDENT(-1);
OUT(")\n");
break;
case ACT_CA_CSV:
OUT("(\n");
INDENT(+1);
for(el = 0; el < ct->el_count; el++) {
if(el) OUT("|| ");
emit_single_constraint_check(arg,
ct->elements[el], mode);
}
INDENT(-1);
OUT(")\n");
break;
case ACT_CA_UNI:
OUT("(\n");
INDENT(+1);
for(el = 0; el < ct->el_count; el++) {
if(el) OUT("|| ");
emit_single_constraint_check(arg,
ct->elements[el], mode);
}
INDENT(-1);
OUT(")\n");
break;
case ACT_CA_INT:
OUT("(\n");
INDENT(+1);
for(el = 0; el < ct->el_count; el++) {
if(el) OUT("&& ");
emit_single_constraint_check(arg,
ct->elements[el], mode);
}
INDENT(-1);
OUT(")\n");
break;
case ACT_CA_CRC:
WARNING("Unsupported component relation constraint at line %d",
ct->_lineno);
OUT("%d /* Unsupported component relation constraint "
"at line %d */\n",
ct->type, ct->_lineno);
return -1;
case ACT_CA_EXC:
WARNING("Unsupported EXCEPT constraint at line %d",
ct->_lineno);
OUT("%d /* Unsupported EXCEPT constraint at line %d */\n",
ct->type, ct->_lineno);
return -1;
}
return 0;
}
static int
check_constraint_type_presence(asn1p_constraint_t *ct, enum asn1p_constraint_type_e type) {
int el;
if(ct == NULL) return 0;
if(ct->type == type) return 1;
if(type == ACT_EL_VALUE) {
if(ct->type >= ACT_CT_SIZE
&& ct->type <= ACT_CT_WCOMPS)
/* Values defined further
* are not really value's values */
return 0;
if(ct->type > ACT_EL_VALUE && ct->type < ACT_CT_SIZE)
return 1; /* Also values */
}
for(el = 0; el < ct->el_count; el++) {
if(check_constraint_type_presence(ct->elements[el], type))
return 1;
}
return 0;
}
static int
emit_alphabet_tables(arg_t *arg, asn1p_constraint_t *ct, int *table) {
int ch = 0;
int ch_start = 0;
int ch_stop = 0;
int el = 0;
assert(arg && ct);
switch(ct->type) {
case ACT_INVALID:
break;
case ACT_EL_VALUE:
if(!table) break;
switch(ct->value->type) {
case ATV_INTEGER:
if(ct->value->value.v_integer < 0
|| ct->value->value.v_integer > 255) {
OUT("\n");
OUT("#error Value %lld out of range "
"for alphabet character at line %d\n",
(long long)ct->value->value.v_integer,
ct->_lineno);
break;
} else {
ch = ct->value->value.v_integer;
table[ch] = 1;
}
break;
case ATV_STRING:
for(ch = 0; ch < ct->value->value.string.size; ch++)
table[ct->value->value.string.buf[ch]] = 1;
break;
default:
OUT("\n");
WARNING("Invalid alphabet character specification "
"at line %d", ct->_lineno);
OUT("#error Invalid alphabet character specification "
"at line %d\n", ct->_lineno);
break;
}
break;
case ACT_EL_RANGE:
case ACT_EL_LLRANGE:
case ACT_EL_RLRANGE:
case ACT_EL_ULRANGE:
if(!table) break;
ch_start = 0;
ch_stop = 255;
switch(ct->range_start->type) {
case ATV_INTEGER:
ch_start = ct->range_start->value.v_integer; break;
case ATV_MIN: ch_start = 0; break;
case ATV_MAX: ch_start = 255; break;
case ATV_STRING:
if(ct->range_start->value.string.size == 1) {
ch_start = ct->range_start->value.string.buf[0];
break;
}
/* Fall through */
default:
OUT("\n");
FATAL("Invalid alphabet range constraint "
"at line %d\n", ct->_lineno);
OUT("#error Invalid alphabet range constraint "
"at line %d\n", ct->_lineno);
return -1;
}
switch(ct->range_stop->type) {
case ATV_INTEGER:
ch_stop = ct->range_stop->value.v_integer; break;
case ATV_MIN: ch_stop = 0; break;
case ATV_MAX: ch_stop = 255; break;
case ATV_STRING:
if(ct->range_stop->value.string.size == 1) {
ch_stop = ct->range_stop->value.string.buf[0];
break;
}
/* Fall through */
default:
OUT("\n");
FATAL("Invalid alphabet range constraint "
"at line %d\n", ct->_lineno);
OUT("#error Invalid alphabet range constraint "
"at line %d\n", ct->_lineno);
break;
}
switch(ct->type) {
case ACT_EL_RANGE: break;
case ACT_EL_RLRANGE: ch_stop--; break;
case ACT_EL_LLRANGE: ch_start++; break;
case ACT_EL_ULRANGE: ch_start++; ch_stop--; break;
default: break;
}
if(ch_start > ch_stop) {
WARNING("Empty character range "
"alphabet constraint at line %d", ct->_lineno);
OUT_NOINDENT("#warning Empty character range "
"alphabet constraint at line %d\n", ct->_lineno);
break;
}
for(ch = ch_start; ch <= ch_stop; ch++) {
if(ch < 0 || ch > 255) continue;
table[ch] = 1;
}
break;
case ACT_EL_EXT:
break;
case ACT_CT_SIZE:
break;
case ACT_CT_FROM:
if(table) {
OUT("#error Nested FROM in subtype constraints\n");
return -1;
} else {
table = alloca(256 * sizeof(table[0]));
memset(table, 0, 256 * sizeof(table[0]));
for(el = 0; el < ct->el_count; el++) {
emit_alphabet_tables(arg, ct->elements[el],
table);
}
OUT("static int alphabet_table_%x[256] = {\n", ct);
for(ch = 0; ch < 256; ch++) {
OUT("%d,", table[ch]?1:0);
if(!((ch+1) % 16)) {
if(ch) {
int c;
OUT("\t/* ");
for(c = ch - 16; c < ch; c++) {
if(table[c]) {
if(c > 0x20
&& c < 0x80)
OUT("%c", c);
else
OUT(".", c);
} else {
OUT(" ");
}
}
OUT(" */");
}
OUT("\n");
}
}
OUT("};\n");
OUT("static int check_alphabet_%x(const void *sptr) {\n", ct);
INDENT(+1);
OUT("int *table = alphabet_table_%x;\n", ct);
emit_alphabet_check_cycle(arg);
OUT("return 1;\n");
INDENT(-1);
OUT("};\n");
}
break;
case ACT_CT_WCOMP:
case ACT_CT_WCOMPS:
break;
case ACT_CA_CRC:
break;
case ACT_CA_SET:
case ACT_CA_CSV:
case ACT_CA_UNI:
for(el = 0; el < ct->el_count; el++)
emit_alphabet_tables(arg, ct->elements[el], table);
break;
case ACT_CA_INT:
if(table) {
int table2[256];
assert(ct->el_count >= 1);
emit_alphabet_tables(arg, ct->elements[0], table);
for(el = 1; el < ct->el_count; el++) {
memset(table2, 0, sizeof(table2));
emit_alphabet_tables(arg,
ct->elements[el], table2);
/* Intersection */
for(ch = 0; ch < 256; ch++) {
if(table2[ch] == 0)
table[ch] = 0;
}
}
} else {
for(el = 0; el < ct->el_count; el++)
emit_alphabet_tables(arg, ct->elements[el], 0);
}
break;
case ACT_CA_EXC:
OUT("EXC\n");
if(table) {
int table2[256];
assert(ct->el_count >= 1);
emit_alphabet_tables(arg, ct->elements[0], table);
for(el = 1; el < ct->el_count; el++) {
memset(table2, 0, sizeof(table2));
emit_alphabet_tables(arg,
ct->elements[el], table2);
/* Exclusion */
for(ch = 0; ch < 256; ch++) {
if(table2[ch])
table[ch] = 0;
}
}
} else {
for(el = 0; el < ct->el_count; el++)
emit_alphabet_tables(arg, ct->elements[el], 0);
}
break;
}
return 0;
}
static int
emit_alphabet_check_cycle(arg_t *arg) {
asn1p_expr_type_e etype;
etype = _find_terminal_type(arg);
if(!(etype & ASN_STRING_MASK)
&& !(etype == ASN_BASIC_OCTET_STRING)) {
OUT("#error Cannot apply FROM constraint to ASN.1 type %s\n",
ASN_EXPR_TYPE2STR(etype));
return -1;
}
OUT("/* The underlying type is %s */\n",
ASN_EXPR_TYPE2STR(etype));
OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier));
switch(etype) {
case ASN_STRING_UTF8String:
OUT("uint8_t *ch = st->buf;\n");
OUT("uint8_t *end = ch + st->size;\n");
OUT("\n");
OUT("for(; ch < end; ch++) {\n");
INDENT(+1);
OUT("if(*ch >= 0x80 || !table[*ch]) return 0;\n");
INDENT(-1);
OUT("}\n");
break;
case ASN_STRING_UniversalString:
OUT("uint32_t *ch = st->buf;\n");
OUT("uint32_t *end = ch + st->size;\n");
OUT("\n");
OUT("for(; ch < end; ch++) {\n");
INDENT(+1);
OUT("uint32_t wc = (((uint8_t *)ch)[0] << 24)\n");
OUT("\t\t| (((uint8_t *)ch)[1] << 16)\n");
OUT("\t\t| (((uint8_t *)ch)[2] << 8)\n");
OUT("\t\t| ((uint8_t *)ch)[3]\n");
OUT("if(wc > 255 || !table[wc]) return 0;\n");
INDENT(-1);
OUT("}\n");
OUT("if(ch != end) return 0; /* (size%4)! */\n");
break;
case ASN_STRING_BMPString:
OUT("uint16_t *ch = st->buf;\n");
OUT("uint16_t *end = ch + st->size;\n");
OUT("\n");
OUT("for(; ch < end; ch++) {\n");
INDENT(+1);
OUT("uint16_t wc = (((uint8_t *)ch)[0] << 8)\n");
OUT("\t\t| ((uint8_t *)ch)[1];\n");
OUT("if(wc > 255 || !table[wc]) return 0;\n");
INDENT(-1);
OUT("}\n");
OUT("if(ch != end) return 0; /* (size%2)! */\n");
break;
case ASN_BASIC_OCTET_STRING:
default:
OUT("uint8_t *ch = st->buf;\n");
OUT("uint8_t *end = ch + st->size;\n");
OUT("\n");
OUT("for(; ch < end; ch++) {\n");
INDENT(+1);
OUT("if(!table[*ch]) return 0;\n");
INDENT(-1);
OUT("}\n");
break;
}
return 0;
}
static int
emit_size_determination_code(arg_t *arg) {
asn1p_expr_type_e etype = _find_terminal_type(arg);
switch(etype) {
case ASN_BASIC_BIT_STRING:
OUT("if(st->size > 0) {\n");
OUT("\t/* Size in bits */\n");
OUT("\tsize = (st->size - 1) - (st->buf[0] & 0x7);\n");
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:
OUT("size = UTF8String_length(st, td->name, app_errlog, app_key);\n");
OUT("if(size == (size_t)-1) return -1;\n");
break;
default:
if((etype & ASN_STRING_MASK)
|| etype == ASN_BASIC_OCTET_STRING) {
OUT("size = st->size;\n");
break;
} else {
const char *type_name = ASN_EXPR_TYPE2STR(etype);
if(!type_name) type_name = arg->expr->Identifier;
WARNING("SIZE constraint is not defined for %s",
type_name);
OUT_NOINDENT("#warning SIZE constraint "
"not defined for %s!\n", type_name);
OUT("size = st->size;\n");
}
return -1;
}
return 0;
}
static int
emit_value_determination_code(arg_t *arg) {
asn1p_expr_type_e etype = _find_terminal_type(arg);
switch(etype) {
case ASN_BASIC_INTEGER:
case ASN_BASIC_ENUMERATED:
if(arg->flags & A1C_USE_NATIVE_INTEGERS) {
OUT("value = *(int *)st;\n");
} else {
OUT("if(asn1_INTEGER2long(st, &value)) {\n");
INDENT(+1);
OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
OUT("\t\"%%s: value too large\", td->name);\n");
OUT("return -1;\n");
INDENT(-1);
OUT("}\n");
}
break;
case ASN_BASIC_BOOLEAN:
OUT("value = st->value;\n");
break;
default:
WARNING("Value cannot be determined "
"for constraint check for %s at line %d\n",
arg->expr->Identifier, arg->expr->_lineno);
OUT("#error Value cannot be determined for %s at %d\n",
arg->expr->Identifier, arg->expr->_lineno);
break;
}
return 0;
}
static long compute_min_size(arg_t *arg) { return compute_xxx_size(arg, 0); }
static long compute_max_size(arg_t *arg) { return compute_xxx_size(arg, 1); }
static long compute_xxx_size(arg_t *arg, int _max) {
asn1p_expr_type_e etype;
long basic_max = 0x7fffffff;
long basic_min = 0x80000000;
long svalue = 0;
etype = _find_terminal_type(arg);
switch(etype) {
case ASN_BASIC_BIT_STRING:
svalue = _max?basic_max/8:0;
break;
case ASN_STRING_UTF8String:
svalue = _max?basic_max/6:0;
break;
case ASN_STRING_UniversalString:
svalue = _max?basic_max/4:0;
break;
case ASN_STRING_BMPString:
svalue = _max?basic_max/2:0;
break;
case ASN_BASIC_OCTET_STRING:
svalue = _max?basic_max:0;
break;
default:
if((etype & ASN_STRING_MASK)) {
svalue = _max?basic_max:0;
break;
}
svalue = _max?basic_max:basic_min;
break;
}
return svalue;
}
static asn1p_expr_type_e
_find_terminal_type(arg_t *arg) {
asn1p_expr_t *expr;
expr = asn1f_find_terminal_type_ex(arg->asn, arg->mod, arg->expr, NULL);
if(expr) return expr->expr_type;
return A1TC_INVALID;
}

View File

@ -0,0 +1,482 @@
#include "asn1c_internal.h"
#include "asn1c_constraint.h"
#include <asn1fix_crange.h> /* constraint groker from libasn1fix */
#include <asn1fix_export.h> /* other exportable stuff from libasn1fix */
static int emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range);
static int emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype);
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);
static 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);
#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;
ct = expr->combined_constraints;
if(ct == NULL)
return 1; /* No additional constraints defined */
etype = _find_terminal_type(arg);
r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE, 0, 0);
r_size = asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE, 0, 0);
if(r_value) {
if(r_value->not_PER_visible
|| r_value->extensible
|| 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) {
if(r_size->not_PER_visible
|| r_size->extensible
|| 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;
}
}
OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier));
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;
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");
OUT("\t\"%%s: value not given\", td->name);\n");
OUT("return -1;\n");
INDENT(-1);
OUT("}\n");
OUT("\n");
if(r_value)
emit_value_determination_code(arg, etype);
if(r_size)
emit_size_determination_code(arg, etype);
/*
* 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(" && "); }
OUT("check_permitted_alphabet_%d(sptr)",
ct->_compile_mark);
}
if(!got_something) {
OUT("1 /* No applicable constraints whatsoever */");
}
INDENT(-1);
OUT(") {\n");
INDENT(+1);
OUT("/* Constraint check succeeded */\n");
OUT("return 1;\n");
INDENT(-1);
OUT("} else {\n");
INDENT(+1);
OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
OUT("\t\"%%s: constraint failed\", td->name);\n");
OUT("return -1;\n");
INDENT(-1);
OUT("}\n");
return 0;
}
int
asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct) {
asn1_integer_t range_start;
asn1_integer_t range_stop;
asn1p_expr_type_e etype;
asn1cnst_range_t *range;
int table[256];
int use_table;
if(!ct) ct = arg->expr->combined_constraints;
if(!ct) return 0;
etype = _find_terminal_type(arg);
range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0, 0);
if(!range) return 0;
if(range->not_PER_visible
|| range->extensible
|| range->empty_constraint) {
asn1constraint_range_free(range);
return 0;
}
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;
if((range_stop - range_start) > 255)
use_table = 0;
if(range->el_count == 0)
use_table = 0;
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;
asn1_integer_t v;
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);
assert((v - range_start) < 256);
table[v - range_start] = ++n;
}
}
OUT("static int permitted_alphabet_table_%d[256] = {\n",
ct->_compile_mark);
untl = (range_stop - range_start) + 1;
untl += (untl % 16)?16 - (untl % 16):0;
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");
}
OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n",
ct->_compile_mark);
INDENT(+1);
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);
}
OUT("return 1;\n");
INDENT(-1);
OUT("}\n");
OUT("\n");
asn1constraint_range_free(range);
return 0;
}
static int
emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) {
asn1p_expr_type_e etype;
asn1_integer_t natural_stop;
etype = _find_terminal_type(arg);
OUT("/* The underlying type is %s */\n",
ASN_EXPR_TYPE2STR(etype));
OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier));
switch(etype) {
case ASN_STRING_UTF8String:
OUT("uint8_t *ch = st->buf;\n");
OUT("uint8_t *end = ch + st->size;\n");
OUT("\n");
OUT("for(; ch < end; ch++) {\n");
INDENT(+1);
OUT("uint8_t cv = *ch;\n");
if(!range) OUT("if(cv >= 0x80) return 0;\n");
natural_stop = 0xffffffffUL;
break;
case ASN_STRING_UniversalString:
OUT("uint32_t *ch = st->buf;\n");
OUT("uint32_t *end = ch + st->size;\n");
OUT("\n");
OUT("if(st->size % 4) return 0; /* (size%4)! */\n");
OUT("for(; ch < end; ch++) {\n");
INDENT(+1);
OUT("uint32_t cv = (((uint8_t *)ch)[0] << 24)\n");
OUT("\t\t| (((uint8_t *)ch)[1] << 16)\n");
OUT("\t\t| (((uint8_t *)ch)[2] << 8)\n");
OUT("\t\t| ((uint8_t *)ch)[3]\n");
if(!range) OUT("if(cv > 255) return 0;\n");
natural_stop = 0xffffffffUL;
break;
case ASN_STRING_BMPString:
OUT("uint16_t *ch = st->buf;\n");
OUT("uint16_t *end = ch + st->size;\n");
OUT("\n");
OUT("if(st->size % 2) return 0; /* (size%2)! */\n");
OUT("for(; ch < end; ch++) {\n");
INDENT(+1);
OUT("uint16_t cv = (((uint8_t *)ch)[0] << 8)\n");
OUT("\t\t| ((uint8_t *)ch)[1];\n");
if(!range) OUT("if(cv > 255) return 0;\n");
natural_stop = 0xffff;
break;
case ASN_BASIC_OCTET_STRING:
default:
OUT("uint8_t *ch = st->buf;\n");
OUT("uint8_t *end = ch + st->size;\n");
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);
OUT(")) return 0;\n");
} else {
OUT("if(!table[cv]) return 0;\n");
}
INDENT(-1);
OUT("}\n");
return 0;
}
static 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) {
int ignore_left;
int ignore_right;
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) {
OUT("%s <= %lld", varname,
(long long)r->right.value);
} else if(ignore_right) {
OUT("%s >= %lld", varname,
(long long)r->left.value);
} else if(r->left.value == r->right.value) {
OUT("%s == %lld", varname,
(long long)r->right.value);
} else {
OUT("%s >= %lld && %s <= %lld",
varname,
(long long)r->left.value,
varname,
(long long)r->right.value);
}
if(r != range) OUT(")");
}
return 0;
}
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");
OUT("\tsize = (st->size - 1) - (st->buf[0] & 0x7);\n");
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:
OUT("size = UTF8String_length(st, td->name, app_errlog, app_key);\n");
OUT("if(size == (size_t)-1) return -1;\n");
break;
case ASN_CONSTR_SET_OF:
case ASN_CONSTR_SEQUENCE_OF:
OUT("{ /* Determine the number of elements */\n");
INDENT(+1);
OUT("A_%s_OF(void) *list;\n",
etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE");
OUT("(void *)list = st;\n");
OUT("size = list->count;\n");
INDENT(-1);
OUT("}\n");
break;
default:
if((etype & ASN_STRING_MASK)
|| etype == ASN_BASIC_OCTET_STRING) {
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
emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype) {
switch(etype) {
case ASN_BASIC_INTEGER:
case ASN_BASIC_ENUMERATED:
if(arg->flags & A1C_USE_NATIVE_INTEGERS) {
OUT("value = *(int *)st;\n");
} else {
OUT("if(asn1_INTEGER2long(st, &value)) {\n");
INDENT(+1);
OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
OUT("\t\"%%s: value too large\", td->name);\n");
OUT("return -1;\n");
INDENT(-1);
OUT("}\n");
}
break;
case ASN_BASIC_BOOLEAN:
OUT("value = (*(int *)st) ? 1 : 0;\n");
break;
default:
WARNING("Value cannot be determined "
"for constraint check for %s at line %d\n",
arg->expr->Identifier, arg->expr->_lineno);
OUT("#error Value cannot be determined for %s at %d\n",
arg->expr->Identifier, arg->expr->_lineno);
break;
}
return 0;
}
static asn1p_expr_type_e
_find_terminal_type(arg_t *arg) {
asn1p_expr_t *expr;
expr = asn1f_find_terminal_type_ex(arg->asn, arg->mod, arg->expr, NULL);
if(expr) return expr->expr_type;
return A1TC_INVALID;
}

View File

@ -0,0 +1,7 @@
#ifndef _ASN1C_CONSTRAINT_H_
#define _ASN1C_CONSTRAINT_H_
int asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct);
int asn1c_emit_constraint_checking_code(arg_t *arg);
#endif /* _ASN1C_CONSTRAINT_H_ */

View File

@ -11,7 +11,7 @@
#include <unistd.h> /* for unlink(2) */
#include <fcntl.h> /* for open(2) */
#include <glob.h> /* for glob(3) */
#include <string.h>
#include <string.h> /* for strlen(3) and memset(3) */
#include <ctype.h> /* for isalnum(3) */
#include <stdarg.h>
#include <errno.h>