diff --git a/libasn1compiler/Makefile.am b/libasn1compiler/Makefile.am index bcfaf93d9ce5a099f3f545cbed9ac6196f48b253..55c529859aeb16facfc8636ebc3066072bd6bac9 100644 --- a/libasn1compiler/Makefile.am +++ b/libasn1compiler/Makefile.am @@ -1,7 +1,7 @@ AM_CPPFLAGS = \ - -I${top_srcdir}/libasn1parser \ - -I${top_srcdir}/libasn1fix + -I$(top_srcdir)/libasn1parser \ + -I$(top_srcdir)/libasn1fix noinst_LTLIBRARIES = libasn1compiler.la @@ -17,11 +17,3 @@ libasn1compiler_la_SOURCES = \ asn1c_compat.c asn1c_compat.h \ asn1c_fdeps.c asn1c_fdeps.h \ asn1c_internal.h - -TESTS = $(check_PROGRAMS) - -check_PROGRAMS = check_compiler - -check_compiler_LDADD = $(noinst_LTLIBRARIES) \ - $(top_builddir)/libasn1parser/libasn1parser.la \ - $(top_builddir)/libasn1fix/libasn1fix.la diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c index ac13873372336c7b5e191a6e35915c440b4ec718..f54d2d5825f4a84bed7fb66f7742761c7a31e433 100644 --- a/libasn1compiler/asn1c_C.c +++ b/libasn1compiler/asn1c_C.c @@ -5,6 +5,8 @@ #include "asn1c_internal.h" #include "asn1c_C.h" #include "asn1c_constraint.h" +#include "asn1c_out.h" +#include "asn1c_misc.h" #include <asn1fix_export.h> /* Stuff exported by libasn1fix */ typedef struct tag2el_s { @@ -17,6 +19,8 @@ typedef struct tag2el_s { static int _fill_tag2el_map(arg_t *arg, tag2el_t **tag2el, int *count, int el_no); static int _add_tag2el_member(arg_t *arg, tag2el_t **tag2el, int *count, int el_no); +static int _expr_elements_count(arg_t *arg, asn1p_expr_t *expr); +static int _emit_member_table(arg_t *arg, asn1p_expr_t *expr); static int asn1c_lang_C_type_SEQUENCE_def(arg_t *arg); static int asn1c_lang_C_type_SET_def(arg_t *arg); @@ -27,7 +31,7 @@ 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); -#define C99_MODE (arg->flags & A1C_NO_C99) +#define C99_MODE (!(arg->flags & A1C_NO_C99)) #define UNNAMED_UNIONS (arg->flags & A1C_UNNAMED_UNIONS) #define PCTX_DEF INDENTED( \ @@ -176,7 +180,7 @@ asn1c_lang_C_type_SEQUENCE_def(arg_t *arg) { * Print out the table according to which the parsing is performed. */ p = MKID(expr->Identifier); - OUT("static asn1_SEQUENCE_element_t asn1_DEF_%s_elements[] = {\n", p); + OUT("static asn1_TYPE_member_t asn1_MBR_%s[] = {\n", p); elements = 0; INDENTED(TQ_FOR(v, &(expr->members), next) { @@ -187,43 +191,8 @@ asn1c_lang_C_type_SEQUENCE_def(arg_t *arg) { ext_stop = elements - 1; continue; } - OUT("{ "); elements++; - OUT("offsetof(struct %s, ", MKID(expr->Identifier)); - OUT("%s), ", MKID(v->Identifier)); - if(v->marker) { - asn1p_expr_t *tv; - int opts = 0; - for(tv = v; tv && tv->marker; - tv = TQ_NEXT(tv, next), opts++) { - if(tv->expr_type == A1TC_EXTENSIBLE) - opts--; - } - OUT("%d,", opts); - } else { - OUT("0,"); - } - OUT("\n"); - INDENT(+1); - if(C99_MODE) OUT(".tag = "); - _print_tag(arg, v, NULL); - OUT(",\n"); - if(C99_MODE) OUT(".tag_mode = "); - if(v->tag.tag_class) { - if(v->tag.tag_mode == TM_IMPLICIT) - OUT("-1,\t/* IMPLICIT tag at current level */\n"); - else - OUT("+1,\t/* EXPLICIT tag at current level */\n"); - } else { - OUT("0,\n"); - } - if(C99_MODE) OUT(".type = "); - OUT("(void *)&asn1_DEF_%s,\n", - asn1c_type_name(arg, v, TNF_SAFE)); - if(C99_MODE) OUT(".name = "); - OUT("\"%s\"\n", v->Identifier); - OUT("},\n"); - INDENT(-1); + _emit_member_table(arg, v); }); OUT("};\n"); @@ -242,8 +211,6 @@ asn1c_lang_C_type_SEQUENCE_def(arg_t *arg) { INDENTED( OUT("sizeof(struct %s),\n", p); OUT("offsetof(struct %s, _ber_dec_ctx),\n", p); - OUT("asn1_DEF_%s_elements,\n", p); - OUT("%d,\t/* Elements count */\n", elements); OUT("asn1_DEF_%s_tag2el,\n", p); OUT("%d,\t/* Count of tags in the map */\n", tag2el_count); OUT("%d,\t/* Start extensions */\n", @@ -272,6 +239,8 @@ asn1c_lang_C_type_SEQUENCE_def(arg_t *arg) { } OUT("%d,\t/* Tags to skip */\n", tags_impl_skip); OUT("%d,\t/* Whether CONSTRUCTED */\n", 1); + OUT("asn1_MBR_%s,\n", p); + OUT("%d,\t/* Elements count */\n", elements); OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p); ); OUT("};\n"); @@ -405,48 +374,19 @@ asn1c_lang_C_type_SET_def(arg_t *arg) { * Print out the table according to which the parsing is performed. */ p = MKID(expr->Identifier); - OUT("static asn1_SET_element_t asn1_DEF_%s_elements[] = {\n", p); + OUT("static asn1_TYPE_member_t asn1_MBR_%s[] = {\n", p); elements = 0; INDENTED(TQ_FOR(v, &(expr->members), next) { if(v->expr_type != A1TC_EXTENSIBLE) { if(comp_mode == 1) v->marker = EM_OPTIONAL; - elements++; } else { if(comp_mode < 3) comp_mode++; continue; } - OUT("{ "); - p = MKID(expr->Identifier); - OUT("offsetof(struct %s, ", p); - p = MKID(v->Identifier); - OUT("%s), ", p); - if(v->marker) { - OUT("1, /* Optional element */\n"); - } else { - OUT("0,\n"); - } - INDENT(+1); - if(C99_MODE) OUT(".tag = "); - _print_tag(arg, v, NULL); - OUT(",\n"); - if(C99_MODE) OUT(".tag_mode = "); - if(v->tag.tag_class) { - if(v->tag.tag_mode == TM_IMPLICIT) - OUT("-1,\t/* IMPLICIT tag at current level */\n"); - else - OUT("+1,\t/* EXPLICIT tag at current level */\n"); - } else { - OUT("0,\n"); - } - if(C99_MODE) OUT(".type = "); - OUT("(void *)&asn1_DEF_%s,\n", - asn1c_type_name(arg, v, TNF_SAFE)); - if(C99_MODE) OUT(".name = "); - OUT("\"%s\"\n", v->Identifier); - OUT("},\n"); - INDENT(-1); + elements++; + _emit_member_table(arg, v); }); OUT("};\n"); @@ -496,8 +436,6 @@ asn1c_lang_C_type_SET_def(arg_t *arg) { OUT("sizeof(struct %s),\n", p); OUT("offsetof(struct %s, _ber_dec_ctx),\n", p); OUT("offsetof(struct %s, _presence_map),\n", p); - OUT("asn1_DEF_%s_elements,\n", p); - OUT("%d,\t/* Elements count */\n", elements); OUT("asn1_DEF_%s_tag2el,\n", p); OUT("%d,\t/* Count of tags in the map */\n", tag2el_count); OUT("%d,\t/* Whether extensible */\n", @@ -525,6 +463,8 @@ asn1c_lang_C_type_SET_def(arg_t *arg) { } OUT("%d,\t/* Tags to skip */\n", tags_impl_skip); OUT("%d,\t/* Whether CONSTRUCTED */\n", 1); + OUT("asn1_MBR_%s,\n", p); + OUT("%d,\t/* Elements count */\n", elements); OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p); ); OUT("};\n"); @@ -589,20 +529,11 @@ asn1c_lang_C_type_SEx_OF_def(arg_t *arg, int seq_of) { * Print out the table according to which the parsing is performed. */ p = MKID(expr->Identifier); - OUT("static asn1_SET_OF_element_t asn1_DEF_%s_elements[] = {\n", p); + OUT("static asn1_TYPE_member_t asn1_MBR_%s[] = {\n", p); - INDENTED(OUT("{ "); + INDENTED( v = TQ_FIRST(&(expr->members)); - INDENT(+1); - if(C99_MODE) OUT(".tag = "); - _print_tag(arg, v, NULL); - OUT(",\n"); - if(C99_MODE) OUT(".type = "); - OUT("(void *)&asn1_DEF_%s", - asn1c_type_name(arg, v, TNF_SAFE)); - OUT(" "); - OUT("},\n"); - INDENT(-1); + _emit_member_table(arg, v); ); OUT("};\n"); @@ -616,7 +547,6 @@ asn1c_lang_C_type_SEx_OF_def(arg_t *arg, int seq_of) { INDENTED( OUT("sizeof(struct %s),\n", p); OUT("offsetof(struct %s, _ber_dec_ctx),\n", p); - OUT("asn1_DEF_%s_elements\n", p); ); OUT("};\n"); OUT("asn1_TYPE_descriptor_t asn1_DEF_%s = {\n", p); @@ -647,6 +577,8 @@ asn1c_lang_C_type_SEx_OF_def(arg_t *arg, int seq_of) { } OUT("%d,\t/* Tags to skip */\n", tags_impl_skip); OUT("%d,\t/* Whether CONSTRUCTED */\n", 1); + OUT("asn1_MBR_%s,\n", p); + OUT("1,\t/* Single element */\n"); OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p); ); OUT("};\n"); @@ -742,49 +674,19 @@ asn1c_lang_C_type_CHOICE_def(arg_t *arg) { * Print out the table according to which the parsing is performed. */ p = MKID(expr->Identifier); - OUT("static asn1_CHOICE_element_t asn1_DEF_%s_elements[] = {\n", p); + OUT("static asn1_TYPE_member_t asn1_MBR_%s[] = {\n", p); elements = 0; INDENTED(TQ_FOR(v, &(expr->members), next) { if(v->expr_type != A1TC_EXTENSIBLE) { if(comp_mode == 1) v->marker = EM_OPTIONAL; - elements++; } else { if(comp_mode < 3) comp_mode++; continue; } - OUT("{ "); - p = MKID(expr->Identifier); - OUT("offsetof(struct %s, ", p); - p = MKID(v->Identifier); - if(!UNNAMED_UNIONS) OUT("choice."); - OUT("%s), ", p); - if(v->marker) { - OUT("1, /* Optional element */\n"); - } else { - OUT("0,\n"); - } - INDENT(+1); - if(C99_MODE) OUT(".tag = "); - _print_tag(arg, v, NULL); - OUT(",\n"); - if(C99_MODE) OUT(".tag_mode = "); - if(v->tag.tag_class) { - if(v->tag.tag_mode == TM_IMPLICIT) - OUT("-1,\t/* IMPLICIT tag at current level */\n"); - else - OUT("+1,\t/* EXPLICIT tag at current level */\n"); - } else { - OUT("0,\n"); - } - if(C99_MODE) OUT(".type = "); - OUT("(void *)&asn1_DEF_%s,\n", - asn1c_type_name(arg, v, TNF_SAFE)); - if(C99_MODE) OUT(".name = "); - OUT("\"%s\"\n", v->Identifier); - OUT("},\n"); - INDENT(-1); + elements++; + _emit_member_table(arg, v); }); OUT("};\n"); @@ -810,8 +712,6 @@ asn1c_lang_C_type_CHOICE_def(arg_t *arg) { OUT("offsetof(struct %s, _ber_dec_ctx),\n", p); OUT("offsetof(struct %s, present),\n", p); OUT("sizeof(((struct %s *)0)->present),\n", p); - OUT("asn1_DEF_%s_elements,\n", p); - OUT("%d,\t/* Elements count */\n", elements); OUT("asn1_DEF_%s_tag2el,\n", p); OUT("%d,\t/* Count of tags in the map */\n", tag2el_count); OUT("%d\t/* Whether extensible */\n", @@ -838,6 +738,8 @@ asn1c_lang_C_type_CHOICE_def(arg_t *arg) { } OUT("%d,\t/* Tags to skip */\n", tags_impl_skip); OUT("%d,\t/* Whether CONSTRUCTED */\n", 1); + OUT("asn1_MBR_%s,\n", p); + OUT("%d,\t/* Elements count */\n", elements); OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p); ); OUT("};\n"); @@ -910,6 +812,8 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { if(expr->marker) OUT("\t/* %s */", (expr->marker==EM_OPTIONAL)?"OPTIONAL":"DEFAULT"); OUT("\n"); + + REDIR(OT_TYPE_DECLS); return 0; } @@ -951,17 +855,20 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { } OUT("%d,\t/* Tags to skip */\n", tags_impl_skip); OUT("-0,\t/* Unknown yet */\n"); + if(_expr_elements_count(arg, expr)) + OUT("0, 0,\t/* Defined elsewhere */\n"); + else + OUT("0, 0,\t/* No members */\n"); OUT("0\t/* No specifics */\n"); ); OUT("};\n"); OUT("\n"); + REDIR(OT_CODE); + /* * Constraint checking. */ - /* 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); @@ -990,37 +897,41 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { * Emit suicidal functions. */ - { /* * This function replaces certain fields from the definition * of a type with the corresponding fields from the basic type * (from which the current type is inherited). */ - char *type_name = asn1c_type_name(arg, expr, TNF_SAFE); OUT("/*\n"); - OUT(" * This type is implemented using %s,\n", type_name); + OUT(" * This type is implemented using %s,\n", + asn1c_type_name(arg, expr, TNF_SAFE)); OUT(" * so adjust the DEF appropriately.\n"); OUT(" */\n"); OUT("static void\n"); - OUT("inherit_TYPE_descriptor(asn1_TYPE_descriptor_t *td) {\n"); + p = MKID(expr->Identifier); + OUT("%s_inherit_TYPE_descriptor(asn1_TYPE_descriptor_t *td) {\n", p); INDENT(+1); - OUT("td->ber_decoder = asn1_DEF_%s.ber_decoder;\n", type_name); - OUT("td->der_encoder = asn1_DEF_%s.der_encoder;\n", type_name); - OUT("td->free_struct = asn1_DEF_%s.free_struct;\n", type_name); - OUT("td->print_struct = asn1_DEF_%s.print_struct;\n", type_name); - OUT("td->last_tag_form = asn1_DEF_%s.last_tag_form;\n", type_name); - OUT("td->specifics = asn1_DEF_%s.specifics;\n", type_name); + { + char *type_name = asn1c_type_name(arg, expr, TNF_SAFE); + OUT("td->ber_decoder = asn1_DEF_%s.ber_decoder;\n", type_name); + OUT("td->der_encoder = asn1_DEF_%s.der_encoder;\n", type_name); + OUT("td->free_struct = asn1_DEF_%s.free_struct;\n", type_name); + OUT("td->print_struct = asn1_DEF_%s.print_struct;\n", type_name); + OUT("td->last_tag_form = asn1_DEF_%s.last_tag_form;\n", type_name); + OUT("td->elements = asn1_DEF_%s.elements;\n", type_name); + OUT("td->elements_count = asn1_DEF_%s.elements_count;\n", type_name); + OUT("td->specifics = asn1_DEF_%s.specifics;\n", type_name); + } INDENT(-1); OUT("}\n"); OUT("\n"); - } p = MKID(expr->Identifier); OUT("ber_dec_rval_t\n"); OUT("%s_decode_ber(asn1_TYPE_descriptor_t *td,\n", p); INDENTED( OUT("\tvoid **structure, void *bufptr, size_t size, int tag_mode) {\n"); - OUT("inherit_TYPE_descriptor(td);\n"); + OUT("%s_inherit_TYPE_descriptor(td);\n", p); OUT("return td->ber_decoder(td, structure,\n"); OUT("\tbufptr, size, tag_mode);\n"); ); @@ -1033,7 +944,7 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { INDENTED( OUT("\tvoid *structure, int tag_mode, ber_tlv_tag_t tag,\n"); OUT("\tasn_app_consume_bytes_f *cb, void *app_key) {\n"); - OUT("inherit_TYPE_descriptor(td);\n"); + OUT("%s_inherit_TYPE_descriptor(td);\n", p); OUT("return td->der_encoder(td, structure, tag_mode, tag, cb, app_key);\n"); ); OUT("}\n"); @@ -1044,7 +955,7 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { OUT("%s_print(asn1_TYPE_descriptor_t *td, const void *struct_ptr,\n", p); INDENTED( OUT("\tint ilevel, asn_app_consume_bytes_f *cb, void *app_key) {\n"); - OUT("inherit_TYPE_descriptor(td);\n"); + OUT("%s_inherit_TYPE_descriptor(td);\n", p); OUT("return td->print_struct(td, struct_ptr, ilevel, cb, app_key);\n"); ); OUT("}\n"); @@ -1055,7 +966,7 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { OUT("%s_free(asn1_TYPE_descriptor_t *td,\n", p); INDENTED( OUT("\tvoid *struct_ptr, int contents_only) {\n"); - OUT("inherit_TYPE_descriptor(td);\n"); + OUT("%s_inherit_TYPE_descriptor(td);\n", p); OUT("td->free_struct(td, struct_ptr, contents_only);\n"); ); OUT("}\n"); @@ -1355,3 +1266,112 @@ emit_tags_vector(arg_t *arg, asn1p_expr_t *expr, int *tags_impl_skip, int choice return tags_count; } + +static int +_expr_elements_count(arg_t *arg, asn1p_expr_t *expr) { + asn1p_expr_t *topmost_parent; + asn1p_expr_t *v; + int elements = 0; + + topmost_parent = asn1f_find_terminal_type_ex(arg->asn, + arg->mod, expr, 0); + if(!topmost_parent) return 0; + + if(!(topmost_parent->expr_type & ASN_CONSTR_MASK)) + return 0; + + TQ_FOR(v, &(topmost_parent->members), next) { + if(v->expr_type != A1TC_EXTENSIBLE) + elements++; + } + + return elements; +} + +static int +_emit_member_table(arg_t *arg, asn1p_expr_t *expr) { + int save_target; + arg_t tmp_arg; + char *p; + + OUT("{ "); + if(expr->marker) { + asn1p_expr_t *tv; + int opts = 0; + for(tv = expr; tv && tv->marker; + tv = TQ_NEXT(tv, next), opts++) { + if(tv->expr_type == A1TC_EXTENSIBLE) + opts--; + } + OUT("%d, ", opts); + } else { + OUT("0, "); + } + if(expr->Identifier) { + OUT("offsetof(struct %s, ", MKID(arg->expr->Identifier)); + if(arg->expr->expr_type == ASN_CONSTR_CHOICE + && (!UNNAMED_UNIONS)) OUT("choice."); + OUT("%s),\n", MKID(expr->Identifier)); + } else { + assert(arg->expr->expr_type == ASN_CONSTR_SET_OF + || arg->expr->expr_type == ASN_CONSTR_SEQUENCE_OF); + OUT("0,\n"); + } + INDENT(+1); + if(C99_MODE) OUT(".tag = "); + _print_tag(arg, expr , NULL); + OUT(",\n"); + if(C99_MODE) OUT(".tag_mode = "); + if(expr->tag.tag_class) { + if(expr->tag.tag_mode == TM_IMPLICIT) + OUT("-1,\t/* IMPLICIT tag at current level */\n"); + else + OUT("+1,\t/* EXPLICIT tag at current level */\n"); + } else { + OUT("0,\n"); + } + if(C99_MODE) OUT(".type = "); + OUT("(void *)&asn1_DEF_%s,\n", + asn1c_type_name(arg, expr, TNF_SAFE)); + if(C99_MODE) OUT(".memb_constraints = "); + if(expr->constraints) { + p = MKID(expr->Identifier); + if(!expr->Identifier) + p = asn1c_type_name(arg, expr, TNF_SAFE); + OUT("memb_%s_constraint,\n", p); + } else { + OUT("0,\t/* Defer to actual type */\n"); + } + if(C99_MODE) OUT(".name = "); + OUT("\"%s\"\n", expr->Identifier ? expr->Identifier : ""); + OUT("},\n"); + INDENT(-1); + + if(!expr->constraints) + return 0; + + save_target = arg->target->target; + REDIR(OT_CODE); + + if(expr->Identifier) + p = MKID(expr->Identifier); + else + p = asn1c_type_name(arg, expr, TNF_SAFE); + OUT("static int\n"); + OUT("memb_%s_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,\n", p); + INDENT(+1); + OUT("\t\tasn_app_consume_bytes_f *app_errlog, void *app_key) {\n"); + tmp_arg = *arg; + tmp_arg.expr = expr; + if(asn1c_emit_constraint_checking_code(&tmp_arg) == 1) { + OUT("return td->check_constraints\n"); + OUT("\t(td, sptr, app_errlog, app_key);\n"); + } + INDENT(-1); + OUT("}\n"); + OUT("\n"); + + REDIR(save_target); + + return 0; +} diff --git a/libasn1compiler/asn1c_constraint.c b/libasn1compiler/asn1c_constraint.c index dd54224daec37ed67bbc287d4f6753db3bb8bcb4..cf5416b0cbe937de0adab272c98986a25c5990ef 100644 --- a/libasn1compiler/asn1c_constraint.c +++ b/libasn1compiler/asn1c_constraint.c @@ -1,9 +1,12 @@ #include "asn1c_internal.h" #include "asn1c_constraint.h" +#include "asn1c_misc.h" +#include "asn1c_out.h" #include <asn1fix_crange.h> /* constraint groker from libasn1fix */ #include <asn1fix_export.h> /* other exportable stuff from libasn1fix */ +static int asn1c_emit_constraint_tables(arg_t *arg, int got_size); 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); @@ -22,6 +25,7 @@ asn1c_emit_constraint_checking_code(arg_t *arg) { asn1p_expr_type_e etype; asn1p_constraint_t *ct; int got_something = 0; + int produce_st = 0; ct = expr->combined_constraints; if(ct == NULL) @@ -57,6 +61,24 @@ asn1c_emit_constraint_checking_code(arg_t *arg) { } } + /* + * Do we really need an "*st = sptr" pointer? + */ + switch(etype) { + case ASN_BASIC_INTEGER: + case ASN_BASIC_ENUMERATED: + if(!(arg->flags & A1C_USE_NATIVE_INTEGERS)) + produce_st = 1; + break; + case ASN_BASIC_OCTET_STRING: + produce_st = 1; + break; + default: + if(etype & ASN_STRING_MASK) + produce_st = 1; + break; + } + if(produce_st) OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier)); if(r_size || r_value) { @@ -96,6 +118,13 @@ asn1c_emit_constraint_checking_code(arg_t *arg) { if(r_size) emit_size_determination_code(arg, etype); + INDENT(-1); + REDIR(OT_CTABLES); + /* Emit FROM() tables */ + asn1c_emit_constraint_tables(arg, r_size?1:0); + REDIR(OT_CODE); + INDENT(+1); + /* * Here is an if() {} else {} constaint checking code. */ @@ -126,6 +155,12 @@ asn1c_emit_constraint_checking_code(arg_t *arg) { } if(!got_something) { OUT("1 /* No applicable constraints whatsoever */"); + OUT(") {\n"); + INDENT(-1); + INDENTED(OUT("/* Nothing is here. See below */\n")); + OUT("}\n"); + OUT("\n"); + return 1; } INDENT(-1); OUT(") {\n"); @@ -144,16 +179,19 @@ asn1c_emit_constraint_checking_code(arg_t *arg) { return 0; } -int -asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct) { +static int +asn1c_emit_constraint_tables(arg_t *arg, int got_size) { asn1_integer_t range_start; asn1_integer_t range_stop; asn1p_expr_type_e etype; asn1cnst_range_t *range; + asn1p_constraint_t *ct; + int utf8_full_alphabet_check = 0; + int max_table_size = 256; int table[256]; int use_table; - if(!ct) ct = arg->expr->combined_constraints; + ct = arg->expr->combined_constraints; if(!ct) return 0; etype = _find_terminal_type(arg); @@ -180,10 +218,21 @@ asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct) { * Check if we need a test table to check the alphabet. */ use_table = 1; - if((range_stop - range_start) > 255) + if(range->el_count == 0) { + /* + * It's better to have a short if() check + * than waste 4k of table space + */ use_table = 0; - if(range->el_count == 0) + } + if((range_stop - range_start) > 255) use_table = 0; + if(etype == ASN_STRING_UTF8String) { + if(range_stop >= 0x80) + use_table = 0; + else + max_table_size = 128; + } if(!ct->_compile_mark) ct->_compile_mark = ++global_compile_mark; @@ -203,15 +252,15 @@ asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct) { } for(v = r->left.value; v <= r->right.value; v++) { assert((v - range_start) >= 0); - assert((v - range_start) < 256); + assert((v - range_start) < max_table_size); 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; + OUT("static int permitted_alphabet_table_%d[%d] = {\n", + ct->_compile_mark, max_table_size); for(n = 0; n < untl; n++) { OUT("%d,", table[n]?1:0); if(!((n+1) % 16)) { @@ -238,11 +287,42 @@ asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct) { } OUT("};\n"); OUT("\n"); + } else if(etype == ASN_STRING_UTF8String) { + /* + * UTF8String type is a special case in many respects. + */ + assert(range_stop > 255); /* This one's unobvious */ + if(got_size) { + /* + * Size has been already determined. + * The UTF8String length checker also checks + * for the syntax validity, so we don't have + * to repeat this process twice. + */ + ct->_compile_mark = 0; /* Don't generate code */ + asn1constraint_range_free(range); + return 0; + } else { + utf8_full_alphabet_check = 1; + } + } else { + /* + * This permitted alphabet check will be + * expressed using conditional statements + * instead of table lookups. Table would be + * to large or otherwise inappropriate (too sparse?). + */ } OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n", ct->_compile_mark); - INDENT(+1); + INDENT(+1); + if(utf8_full_alphabet_check) { + OUT("if(UTF8String_length((UTF8String_t *)sptr, td->name, \n"); + OUT("\tapp_errlog, app_key) == -1)\n"); + OUT("\t\treturn 0; /* Alphabet (sic!) test failed. */\n"); + OUT("\n"); + } else { if(use_table) { OUT("int *table = permitted_alphabet_table_%d;\n", ct->_compile_mark); @@ -250,8 +330,9 @@ asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct) { } else { emit_alphabet_check_loop(arg, range); } - OUT("return 1;\n"); - INDENT(-1); + } + OUT("return 1;\n"); + INDENT(-1); OUT("}\n"); OUT("\n"); @@ -338,6 +419,7 @@ 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 generated_something = 0; int i; for(i = -1; i < range->el_count; i++) { @@ -381,9 +463,10 @@ emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varn (long long)r->right.value); } if(r != range) OUT(")"); + generated_something = 1; } - return 0; + return generated_something; } static int @@ -412,16 +495,18 @@ emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) { case ASN_CONSTR_SEQUENCE_OF: OUT("{ /* Determine the number of elements */\n"); INDENT(+1); - OUT("A_%s_OF(void) *list;\n", + OUT("const A_%s_OF(void) *list;\n", etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE"); - OUT("(void *)list = st;\n"); + OUT("(const void *)list = sptr;\n"); OUT("size = list->count;\n"); INDENT(-1); OUT("}\n"); break; + case ASN_BASIC_OCTET_STRING: + OUT("size = st->size;\n"); + break; default: - if((etype & ASN_STRING_MASK) - || etype == ASN_BASIC_OCTET_STRING) { + if(etype & ASN_STRING_MASK) { OUT("size = st->size;\n"); break; } else { @@ -446,7 +531,7 @@ emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype) { case ASN_BASIC_INTEGER: case ASN_BASIC_ENUMERATED: if(arg->flags & A1C_USE_NATIVE_INTEGERS) { - OUT("value = *(int *)st;\n"); + OUT("value = *(int *)sptr;\n"); } else { OUT("if(asn1_INTEGER2long(st, &value)) {\n"); INDENT(+1); @@ -458,7 +543,7 @@ emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype) { } break; case ASN_BASIC_BOOLEAN: - OUT("value = (*(int *)st) ? 1 : 0;\n"); + OUT("value = (*(int *)sptr) ? 1 : 0;\n"); break; default: WARNING("Value cannot be determined " diff --git a/libasn1compiler/asn1c_constraint.h b/libasn1compiler/asn1c_constraint.h index 481c0b342f68113eae5c29168721e40ffc518b6f..7c2ffa842e18501c3db477612c9183685338ce9f 100644 --- a/libasn1compiler/asn1c_constraint.h +++ b/libasn1compiler/asn1c_constraint.h @@ -1,7 +1,6 @@ #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 061b93638779ee357d164c71a341bebf5c9ceaef..e6b18522938d1a02eb3ba4dccc6d1dea214fcc6a 100644 --- a/libasn1compiler/asn1c_internal.h +++ b/libasn1compiler/asn1c_internal.h @@ -33,16 +33,9 @@ typedef struct arg_s { asn1p_module_t *mod; asn1p_expr_t *expr; - int indent_level; - int indented; int embed; } arg_t; -#include "asn1c_lang.h" /* Target language initialization */ -#include "asn1c_misc.h" /* Miscellaneous functions */ -#include "asn1c_out.h" /* Handle output during compilation */ -#include "asn1c_save.h" /* Save compiled output */ - /* * Logging. */ diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c index ee4369603f9ccda501d38df99fa94ac929a40b73..c30174bbf21f7b7522245b8ee1f42f4037dcd864 100644 --- a/libasn1compiler/asn1c_misc.c +++ b/libasn1compiler/asn1c_misc.c @@ -1,4 +1,6 @@ #include "asn1c_internal.h" +#include "asn1c_misc.h" + #include <asn1fix_export.h> /* diff --git a/libasn1compiler/asn1c_out.c b/libasn1compiler/asn1c_out.c index 3954916dafb23a1faa84396f8957dc366d85e140..fb41871153eda3de2de4a79d87901e0e94e23c92 100644 --- a/libasn1compiler/asn1c_out.c +++ b/libasn1compiler/asn1c_out.c @@ -1,4 +1,5 @@ #include "asn1c_internal.h" +#include "asn1c_out.h" /* * Add an elementary chunk of target language text @@ -6,6 +7,7 @@ */ int asn1c_compiled_output(arg_t *arg, const char *fmt, ...) { + struct compiler_stream_destination_s *dst; const char *p; int lf_found; va_list ap; @@ -20,6 +22,7 @@ asn1c_compiled_output(arg_t *arg, const char *fmt, ...) { assert(arg->target->target != OT_ASSERT); return -1; default: + dst = &arg->target->destination[arg->target->target]; break; } @@ -37,16 +40,16 @@ asn1c_compiled_output(arg_t *arg, const char *fmt, ...) { /* * Print out the indentation. */ - if(arg->indented == 0) { - int i = arg->indent_level; - arg->indented = 1; + if(dst->indented == 0) { + int i = dst->indent_level; + dst->indented = 1; while(i--) { ret = asn1c_compiled_output(arg, "\t"); if(ret == -1) return -1; } } if(lf_found) - arg->indented = 0; + dst->indented = 0; /* * Estimate necessary size. @@ -80,7 +83,7 @@ asn1c_compiled_output(arg_t *arg, const char *fmt, ...) { if(arg->target->target == OT_INCLUDES) { out_chunk_t *v; - TQ_FOR(v, &(arg->target->targets[OT_INCLUDES]), next) { + TQ_FOR(v, &dst->chunks, next) { if(m->len == v->len && !memcmp(m->buf, v->buf, m->len)) break; @@ -93,7 +96,7 @@ asn1c_compiled_output(arg_t *arg, const char *fmt, ...) { } } - TQ_ADD(&(arg->target->targets[arg->target->target]), m, next); + TQ_ADD(&dst->chunks, m, next); return 0; } diff --git a/libasn1compiler/asn1c_out.h b/libasn1compiler/asn1c_out.h index 51582d4c63874ed379e4b45db4e6e2a921025cfd..f604687b24c792ccd910b0efb2d3dc55dd6add53 100644 --- a/libasn1compiler/asn1c_out.h +++ b/libasn1compiler/asn1c_out.h @@ -19,15 +19,21 @@ typedef struct compiler_streams { OT_DEPS, /* Dependencies (other than #includes) */ OT_TYPE_DECLS, /* Type declarations */ OT_FUNC_DECLS, /* Function declarations */ - OT_STAT_DEFS, /* Static definitions */ + OT_CTABLES, /* Constraint tables */ OT_CODE, /* Some code */ + OT_STAT_DEFS, /* Static definitions */ OT_MAX } target; - TQ_HEAD(out_chunk_t) targets[OT_MAX]; + + struct compiler_stream_destination_s { + TQ_HEAD(out_chunk_t) chunks; + int indent_level; + int indented; + } destination[OT_MAX]; } compiler_streams_t; static char *_compiler_stream2str[] __attribute__ ((unused)) - = { "ASSERT", "INCLUDES", "DEPS", "TYPE-DECLS", "FUNC-DECLS", "STAT-DEFS", "CODE" }; + = { "ASSERT", "INCLUDES", "DEPS", "TYPE-DECLS", "FUNC-DECLS", "CTABLES", "CODE", "STAT-DEFS" }; int asn1c_compiled_output(arg_t *arg, const char *fmt, ...); @@ -38,19 +44,20 @@ int asn1c_compiled_output(arg_t *arg, const char *fmt, ...); /* Redirect output to a different stream. */ #define REDIR(foo) do { arg->target->target = foo; } while(0) - -#define INDENT(val) arg->indent_level += (val) -#define INDENTED(code) do { \ - INDENT(+1); \ - do { code; } while(0); \ - INDENT(-1); \ +#define INDENT_LEVEL \ + arg->target->destination[arg->target->target].indent_level +#define INDENT(val) INDENT_LEVEL += (val) +#define INDENTED(code) do { \ + INDENT(+1); \ + do { code; } while(0); \ + INDENT(-1); \ } while(0) -#define FLAT(code) do { \ - int _il = arg->indent_level; \ - arg->indent_level = 0; \ - do { code; } while(0); \ - arg->indent_level = _il; \ +#define FLAT(code) do { \ + int _il = INDENT_LEVEL; \ + INDENT_LEVEL = 0; \ + do { code; } while(0); \ + INDENT_LEVEL = _il; \ } while(0) #define EMBED(ev) do { \ @@ -68,11 +75,11 @@ int asn1c_compiled_output(arg_t *arg, const char *fmt, ...); /* Output a piece of text into a default stream */ #define OUT(fmt, args...) asn1c_compiled_output(arg, fmt, ##args) -#define OUT_NOINDENT(fmt, args...) do { \ - int _saved_indent = arg->indent_level; \ - arg->indent_level = 0; \ - OUT(fmt, ##args); \ - arg->indent_level = _saved_indent; \ +#define OUT_NOINDENT(fmt, args...) do { \ + int _saved_indent = INDENT_LEVEL; \ + INDENT_LEVEL = 0; \ + OUT(fmt, ##args); \ + INDENT_LEVEL = _saved_indent; \ } while(0) /* Generate #include line */ diff --git a/libasn1compiler/asn1c_save.c b/libasn1compiler/asn1c_save.c index 3c630538de33666a508f525ad0bf753063ce1771..add70e175fc5339cc5b25555d8b56ef7b8dc39bc 100644 --- a/libasn1compiler/asn1c_save.c +++ b/libasn1compiler/asn1c_save.c @@ -1,6 +1,10 @@ #include "asn1c_internal.h" #include "asn1c_compat.h" #include "asn1c_fdeps.h" +#include "asn1c_lang.h" +#include "asn1c_misc.h" +#include "asn1c_save.h" +#include "asn1c_out.h" static int asn1c_dump_streams(arg_t *arg, asn1c_fdeps_t *); static int asn1c_print_streams(arg_t *arg); @@ -114,14 +118,14 @@ asn1c_print_streams(arg_t *arg) { for(i = 1; i < OT_MAX; i++) { out_chunk_t *ot; - if(TQ_FIRST(&cs->targets[i]) == NULL) + if(TQ_FIRST(&cs->destination[i].chunks) == NULL) continue; printf("\n/*** <<< %s [%s] >>> ***/\n\n", _compiler_stream2str[i], expr->Identifier); - TQ_FOR(ot, &(cs->targets[i]), next) { + TQ_FOR(ot, &(cs->destination[i].chunks), next) { fwrite(ot->buf, ot->len, 1, stdout); } } @@ -178,18 +182,18 @@ asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *deps) { fprintf(fp_h, "#include <constr_TYPE.h>\n\n"); - TQ_FOR(ot, &(cs->targets[OT_INCLUDES]), next) { + TQ_FOR(ot, &(cs->destination[OT_INCLUDES].chunks), next) { asn1c_activate_dependency(deps, 0, ot->buf); fwrite(ot->buf, ot->len, 1, fp_h); } fprintf(fp_h, "\n"); - TQ_FOR(ot, &(cs->targets[OT_DEPS]), next) + TQ_FOR(ot, &(cs->destination[OT_DEPS].chunks), next) fwrite(ot->buf, ot->len, 1, fp_h); fprintf(fp_h, "\n"); - TQ_FOR(ot, &(cs->targets[OT_TYPE_DECLS]), next) + TQ_FOR(ot, &(cs->destination[OT_TYPE_DECLS].chunks), next) fwrite(ot->buf, ot->len, 1, fp_h); fprintf(fp_h, "\n"); - TQ_FOR(ot, &(cs->targets[OT_FUNC_DECLS]), next) + TQ_FOR(ot, &(cs->destination[OT_FUNC_DECLS].chunks), next) fwrite(ot->buf, ot->len, 1, fp_h); fprintf(fp_h, "\n#ifdef __cplusplus\n}\n#endif\n\n" @@ -197,12 +201,14 @@ asn1c_save_streams(arg_t *arg, asn1c_fdeps_t *deps) { header_id); fprintf(fp_c, "#include <%s.h>\n\n", expr->Identifier); /* Myself */ - TQ_FOR(ot, &(cs->targets[OT_STAT_DEFS]), next) + TQ_FOR(ot, &(cs->destination[OT_CTABLES].chunks), next) fwrite(ot->buf, ot->len, 1, fp_c); - TQ_FOR(ot, &(cs->targets[OT_CODE]), next) + TQ_FOR(ot, &(cs->destination[OT_CODE].chunks), next) + fwrite(ot->buf, ot->len, 1, fp_c); + TQ_FOR(ot, &(cs->destination[OT_STAT_DEFS].chunks), next) fwrite(ot->buf, ot->len, 1, fp_c); - assert(OT_MAX == 7); + assert(OT_MAX == 8); fclose(fp_c); fclose(fp_h); diff --git a/libasn1compiler/asn1compiler.c b/libasn1compiler/asn1compiler.c index 24e539a0844a0061eec4bd2371ebc7e58b8256c0..dd51156f9c814cba07a9cdc84fe70c3592ba9c85 100644 --- a/libasn1compiler/asn1compiler.c +++ b/libasn1compiler/asn1compiler.c @@ -1,4 +1,7 @@ #include "asn1c_internal.h" +#include "asn1c_lang.h" +#include "asn1c_out.h" +#include "asn1c_save.h" static void default_logger_cb(int, const char *fmt, ...); static int asn1c_compile_expr(arg_t *arg); @@ -73,7 +76,7 @@ asn1c_compile_expr(arg_t *arg) { type_cb = asn1_lang_map[expr->meta_type][expr->expr_type].type_cb; if(type_cb) { - if(arg->indent_level == 0) + if(arg->target->destination[OT_TYPE_DECLS].indent_level == 0) OUT("\n"); DEBUG("Compiling %s at line %d", @@ -134,7 +137,7 @@ asn1c_attach_streams(asn1p_expr_t *expr) { cs = expr->data; for(i = 0; i < OT_MAX; i++) { - TQ_INIT(&(cs->targets[i])); + TQ_INIT(&(cs->destination[i].chunks)); } return 0;