mirror of https://gerrit.osmocom.org/asn1c
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:
parent
2248d718ef
commit
1d03669d1b
|
@ -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)
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue