aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2004-08-19 13:29:46 +0000
committerLev Walkin <vlm@lionet.info>2004-08-19 13:29:46 +0000
commit84cd58ecfbdb6cdc17cc0e1732d38a9023e84d8b (patch)
treecf0107c933fb75188234af1829a3a7236db7b442
parent4b102255b52174eeb6051dc093245c36b83a6e6c (diff)
constraint checking code
-rw-r--r--libasn1compiler/Makefile.am2
-rw-r--r--libasn1compiler/Makefile.in8
-rw-r--r--libasn1compiler/asn1c_C.c712
-rw-r--r--libasn1compiler/asn1c_constraint.c482
-rw-r--r--libasn1compiler/asn1c_constraint.h7
-rw-r--r--libasn1compiler/asn1c_internal.h2
6 files changed, 508 insertions, 705 deletions
diff --git a/libasn1compiler/Makefile.am b/libasn1compiler/Makefile.am
index ef96aef9..bcfaf93d 100644
--- a/libasn1compiler/Makefile.am
+++ b/libasn1compiler/Makefile.am
@@ -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)
diff --git a/libasn1compiler/Makefile.in b/libasn1compiler/Makefile.in
index e8153937..b427be97 100644
--- a/libasn1compiler/Makefile.in
+++ b/libasn1compiler/Makefile.in
@@ -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@
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index 197ce1f9..ac138733 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -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;
-}
-
diff --git a/libasn1compiler/asn1c_constraint.c b/libasn1compiler/asn1c_constraint.c
new file mode 100644
index 00000000..dd54224d
--- /dev/null
+++ b/libasn1compiler/asn1c_constraint.c
@@ -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;
+}
+
diff --git a/libasn1compiler/asn1c_constraint.h b/libasn1compiler/asn1c_constraint.h
new file mode 100644
index 00000000..481c0b34
--- /dev/null
+++ b/libasn1compiler/asn1c_constraint.h
@@ -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_ */
diff --git a/libasn1compiler/asn1c_internal.h b/libasn1compiler/asn1c_internal.h
index 08a490fb..061b9363 100644
--- a/libasn1compiler/asn1c_internal.h
+++ b/libasn1compiler/asn1c_internal.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>