/* * Don't look into this file. First, because it's a mess, and second, because * it's a brain of the compiler, and you don't wanna mess with brains do you? ;) */ #include "asn1c_internal.h" #include "asn1c_C.h" #include /* exportable stuff from libasn1fix */ static int asn1c_lang_C_type_SEQUENCE_def(arg_t *arg); static int asn1c_lang_C_type_SET_def(arg_t *arg); static int asn1c_lang_C_type_CHOICE_def(arg_t *arg); static int asn1c_lang_C_type_SEx_OF_def(arg_t *arg, int seq_of); static int _print_tag(arg_t *arg, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag_p); 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); typedef struct tag2el_s { struct asn1p_type_tag_s el_tag; int el_no; asn1p_expr_t *from_expr; } tag2el_t; 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); #define C99_MODE (arg->flags & A1C_NO_C99) #define UNNAMED_UNIONS (arg->flags & A1C_UNNAMED_UNIONS) #define PCTX_DEF INDENTED( \ OUT("\n"); \ OUT("/* Context for parsing across buffer boundaries */\n"); \ OUT("ber_dec_ctx_t _ber_dec_ctx;\n")); #define DEPENDENCIES do { \ int saved_target = arg->target->target; \ int saved_indent = arg->indent_level; \ int comment_printed = 0; \ REDIR(OT_DEPS); \ arg->indent_level = 0; \ TQ_FOR(v, &(expr->members), next) { \ if((!(v->expr_type & ASN_CONSTR_MASK) \ && v->expr_type > ASN_CONSTR_MASK) \ || v->meta_type == AMT_TYPEREF) { \ if(!comment_printed++) \ OUT("/* Dependencies for %s */\n", \ asn1c_type_name(arg, expr, TNF_UNMODIFIED)); \ OUT("#include <%s.h>\n", \ asn1c_type_name(arg, v, TNF_INCLUDE)); \ } \ } \ if(expr->expr_type == ASN_CONSTR_SET_OF) \ OUT("#include \n"); \ if(expr->expr_type == ASN_CONSTR_SEQUENCE_OF) \ OUT("#include \n"); \ OUT("\n"); \ REDIR(saved_target); \ INDENT(saved_indent); \ } while(0) #define MKID(id) asn1c_make_identifier(0, (id), 0) int asn1c_lang_C_type_ENUMERATED(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; REDIR(OT_DEPS); OUT("typedef enum %s {\n", MKID(expr->Identifier)); TQ_FOR(v, &(expr->members), next) { switch(v->expr_type) { case A1TC_UNIVERVAL: OUT("\t%s\t= %lld,\n", asn1c_make_identifier(0, expr->Identifier, v->Identifier, 0), v->value->value.v_integer); break; case A1TC_EXTENSIBLE: OUT("\t/*\n"); OUT("\t * Enumeration is extensible\n"); OUT("\t */\n"); break; default: return -1; } } OUT("} %s_e;\n", MKID(expr->Identifier)); return asn1c_lang_C_type_SIMPLE_TYPE(arg); } int asn1c_lang_C_type_INTEGER(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; REDIR(OT_DEPS); if(TQ_FIRST(&(expr->members))) { OUT("typedef enum %s {\n", MKID(expr->Identifier)); TQ_FOR(v, &(expr->members), next) { switch(v->expr_type) { case A1TC_UNIVERVAL: OUT("\t%s\t= %lld,\n", asn1c_make_identifier(0, expr->Identifier, v->Identifier, 0), v->value->value.v_integer); break; default: return -1; } } OUT("} %s_e;\n", MKID(expr->Identifier)); } return asn1c_lang_C_type_SIMPLE_TYPE(arg); } int asn1c_lang_C_type_SEQUENCE(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; int comp_mode = 0; /* {root,ext=1,root,root,...} */ DEPENDENCIES; if(arg->embed) { OUT("struct %s {\n", MKID(expr->Identifier)); } else { OUT("typedef struct %s {\n", MKID(expr->Identifier)); } TQ_FOR(v, &(expr->members), next) { if(v->expr_type == A1TC_EXTENSIBLE) { if(comp_mode < 3) comp_mode++; } if(comp_mode == 1 && !v->marker) v->marker = EM_OPTIONAL; EMBED(v); } PCTX_DEF; OUT("} %s%s", expr->marker?"*":"", MKID(expr->Identifier)); if(arg->embed) OUT(";\n"); else OUT("_t;\n"); return asn1c_lang_C_type_SEQUENCE_def(arg); } static int asn1c_lang_C_type_SEQUENCE_def(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; int elements; /* Number of elements */ int tags_impl_skip = 0; int comp_mode = 0; /* {root,ext=1,root,root,...} */ int ext_start = -1; int ext_stop = -1; char *p; REDIR(OT_STAT_DEFS); OUT("#include \n"); OUT("\n"); /* * 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); elements = 0; INDENTED(TQ_FOR(v, &(expr->members), next) { if(v->expr_type == A1TC_EXTENSIBLE) { if((++comp_mode) == 1) ext_start = elements - 1; else 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); }); OUT("};\n"); p = MKID(expr->Identifier); OUT("static ber_tlv_tag_t asn1_DEF_%s_tags[] = {\n", p); INDENTED( if(expr->tag.tag_class) { _print_tag(arg, expr, &expr->tag); if(expr->tag.tag_mode != TM_EXPLICIT) tags_impl_skip++; } if(!expr->tag.tag_class || (expr->meta_type == AMT_TYPE && expr->tag.tag_mode == TM_EXPLICIT)) { struct asn1p_type_tag_s tag; if(expr->tag.tag_class) OUT(",\n"); tag.tag_class = TC_UNIVERSAL; tag.tag_mode = TM_IMPLICIT; tag.tag_value = expr_type2uclass_value[expr->expr_type]; _print_tag(arg, expr, &tag); } OUT("\n"); ); OUT("};\n"); OUT("static asn1_SEQUENCE_specifics_t asn1_DEF_%s_specs = {\n", p); 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("%d,\t/* Start extensions */\n", ext_start); OUT("%d\t/* Stop extensions */\n", (ext_stopIdentifier); OUT("SEQUENCE_constraint,\n"); OUT("SEQUENCE_decode_ber,\n"); OUT("SEQUENCE_encode_der,\n"); OUT("SEQUENCE_print,\n"); OUT("SEQUENCE_free,\n"); OUT("0,\t/* Use generic outmost tag fetcher */\n"); OUT("asn1_DEF_%s_tags,\n", p); OUT("sizeof(asn1_DEF_%s_tags)\n", p); OUT("\t/sizeof(asn1_DEF_%s_tags[0]),\n", p); OUT("%d,\t/* Tags to skip */\n", tags_impl_skip); OUT("%d,\t/* Whether CONSTRUCTED */\n", 1); OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p); ); OUT("};\n"); OUT("\n"); REDIR(OT_DEPS); OUT("#include \n"); OUT("\n"); if(!arg->embed) OUT("extern asn1_TYPE_descriptor_t asn1_DEF_%s;\n", p); REDIR(OT_TYPE_DECLS); return 0; } int asn1c_lang_C_type_SEQUENCE_OF(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; DEPENDENCIES; if(arg->embed) { OUT("struct %s {\n", MKID(expr->Identifier)); } else { OUT("typedef struct %s {\n", MKID(expr->Identifier)); } TQ_FOR(v, &(expr->members), next) { INDENTED(OUT("A_SEQUENCE_OF(%s) list;\n", asn1c_type_name(arg, v, TNF_RSAFE))); } PCTX_DEF; OUT("} %s%s", expr->marker?"*":"", MKID(expr->Identifier)); if(arg->embed) OUT(";\n"); else OUT("_t;\n"); /* * SET OF/SEQUENCE OF definition, SEQUENCE OF mode. */ return asn1c_lang_C_type_SEx_OF_def(arg, 1); } int asn1c_lang_C_type_SET(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; long mcount; char *id; int comp_mode = 0; /* {root,ext=1,root,root,...} */ DEPENDENCIES; REDIR(OT_DEPS); OUT("\n"); OUT("/*\n"); OUT(" * Method of determining the components presence\n"); OUT(" */\n"); mcount = 0; OUT("enum %s_PR_e {\n", MKID(expr->Identifier)); TQ_FOR(v, &(expr->members), next) { if(v->expr_type == A1TC_EXTENSIBLE) continue; INDENTED( id = MKID(expr->Identifier); OUT("%s_PR_", id); id = MKID(v->Identifier); OUT("%s,\t/* Member %s is present */\n", id, id) ); mcount++; } OUT("};\n"); REDIR(OT_TYPE_DECLS); if(arg->embed) { OUT("struct %s {\n", MKID(expr->Identifier)); } else { OUT("typedef struct %s {\n", MKID(expr->Identifier)); } TQ_FOR(v, &(expr->members), next) { if(v->expr_type == A1TC_EXTENSIBLE) { if(comp_mode < 3) comp_mode++; } if(comp_mode == 1 && !v->marker) v->marker = EM_OPTIONAL; EMBED(v); } INDENTED( id = MKID(expr->Identifier); OUT("\n"); OUT("/* Presence bitmask: ASN_SET_ISPRESENT(p%s, %s_PR_x) */\n", id, id); OUT("unsigned int _presence_map\n"); OUT("\t[((%ld+(8*sizeof(unsigned int))-1)/(8*sizeof(unsigned int)))];\n", mcount); ); PCTX_DEF; OUT("} %s%s", expr->marker?"*":"", MKID(expr->Identifier)); if(arg->embed) OUT(";\n"); else OUT("_t;\n"); return asn1c_lang_C_type_SET_def(arg); } /* * Compare tags according to their canonical order. * Canonical order: [UNIVERSAL] [APPLICATION] [] [PRIVATE] * As you see, the class is encoded using the two lowest bits. */ static arg_t *_ctc_arg; static int _canonical_tags_cmp(const void *ap, const void *bp) __attribute__ ((unused)); static int _canonical_tags_cmp(const void *ap, const void *bp) { asn1p_expr_t *a, *b; struct asn1p_type_tag_s ta, tb; (const asn1p_expr_t *)a = *(const asn1p_expr_t * const *)ap; (const asn1p_expr_t *)b = *(const asn1p_expr_t * const *)bp; if(asn1f_fetch_tag(_ctc_arg->asn, _ctc_arg->mod, a, &ta) || asn1f_fetch_tag(_ctc_arg->asn, _ctc_arg->mod, b, &tb)) return 0; if(ta.tag_class == tb.tag_class) { if(ta.tag_value == tb.tag_value) return 0; else if(ta.tag_value < tb.tag_value) return -1; else return 1; } else if(ta.tag_class < tb.tag_class) { return -1; } else { return 1; } } static int _tag2el_cmp(const void *ap, const void *bp) { const tag2el_t *a = ap; const tag2el_t *b = bp; const struct asn1p_type_tag_s *ta = &a->el_tag; const struct asn1p_type_tag_s *tb = &b->el_tag; if(ta->tag_class == tb->tag_class) { if(ta->tag_value == tb->tag_value) return 0; else if(ta->tag_value < tb->tag_value) return -1; else return 1; } else if(ta->tag_class < tb->tag_class) { return -1; } else { return 1; } } static int asn1c_lang_C_type_SET_def(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; int elements; int tags_impl_skip = 0; int comp_mode = 0; /* {root,ext=1,root,root,...} */ int extensible = 0; tag2el_t *tag2el = NULL; int tag2el_count = 0; char *p; /* * Fetch every inner tag from the tag to elements map. */ if(_fill_tag2el_map(arg, &tag2el, &tag2el_count, -1)) { if(tag2el) free(tag2el); return -1; } else { /* * Sort the map according to canonical order of their tags. */ _ctc_arg = arg; qsort(tag2el, tag2el_count, sizeof(*tag2el), _tag2el_cmp); } REDIR(OT_STAT_DEFS); OUT("#include \n"); OUT("\n"); /* * 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); 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); }); OUT("};\n"); p = MKID(expr->Identifier); OUT("static ber_tlv_tag_t asn1_DEF_%s_tags[] = {\n", p); INDENTED( if(expr->tag.tag_class) { _print_tag(arg, expr, &expr->tag); if(expr->tag.tag_mode != TM_EXPLICIT) tags_impl_skip++; } if(!expr->tag.tag_class || (expr->meta_type == AMT_TYPE && expr->tag.tag_mode == TM_EXPLICIT)) { struct asn1p_type_tag_s tag; if(expr->tag.tag_class) OUT(",\n"); tag.tag_class = TC_UNIVERSAL; tag.tag_mode = TM_IMPLICIT; tag.tag_value = expr_type2uclass_value[expr->expr_type]; _print_tag(arg, expr, &tag); } OUT("\n"); ); OUT("};\n"); /* * Tags to elements map. */ p = MKID(expr->Identifier); OUT("static asn1_SET_tag2member_t asn1_DEF_%s_tag2el[] = {\n", p); if(tag2el_count) { int i; for(i = 0; i < tag2el_count; i++) { OUT(" { "); _print_tag(arg, expr, &tag2el[i].el_tag); OUT(", "); OUT("%d ", tag2el[i].el_no); OUT("}, /* %s at %d */\n", tag2el[i].from_expr->Identifier, tag2el[i].from_expr->_lineno ); } } OUT("};\n"); /* * Emit a map of mandatory elements. */ OUT("static uint8_t asn1_DEF_%s_mmap", p); OUT("[(%d + (8 * sizeof(unsigned int)) - 1) / 8]", elements); OUT(" = {\n", p); INDENTED( if(elements) { int delimit = 0; int el = 0; TQ_FOR(v, &(expr->members), next) { if(v->expr_type == A1TC_EXTENSIBLE) continue; if(delimit) { OUT(",\n"); delimit = 0; } else if(el) { OUT(" | "); } OUT("(%d << %d)", v->marker?0:1, 7 - (el % 8)); if(el && (el % 8) == 0) delimit = 1; el++; } } else { OUT("0"); } ); OUT("\n"); OUT("};\n"); OUT("static asn1_SET_specifics_t asn1_DEF_%s_specs = {\n", p); INDENTED( 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", extensible); OUT("(unsigned int *)asn1_DEF_%s_mmap\t/* Mandatory elements map */\n", p); ); OUT("};\n"); OUT("asn1_TYPE_descriptor_t asn1_DEF_%s = {\n", p); INDENTED( OUT("\"%s\",\n", expr->Identifier); OUT("SET_constraint,\n"); OUT("SET_decode_ber,\n"); OUT("SET_encode_der,\n"); OUT("SET_print,\n"); OUT("SET_free,\n"); OUT("0,\t/* Use generic outmost tag fetcher */\n"); OUT("asn1_DEF_%s_tags,\n", p); OUT("sizeof(asn1_DEF_%s_tags)\n", p); OUT("\t/sizeof(asn1_DEF_%s_tags[0]),\n", p); OUT("%d,\t/* Tags to skip */\n", tags_impl_skip); OUT("%d,\t/* Whether CONSTRUCTED */\n", 1); OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p); ); OUT("};\n"); OUT("\n"); REDIR(OT_DEPS); OUT("#include \n"); OUT("\n"); if(!arg->embed) OUT("extern asn1_TYPE_descriptor_t asn1_DEF_%s;\n", p); REDIR(OT_TYPE_DECLS); return 0; } int asn1c_lang_C_type_SET_OF(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; DEPENDENCIES; if(arg->embed) { OUT("struct %s {\n", MKID(expr->Identifier)); } else { OUT("typedef struct %s {\n", MKID(expr->Identifier)); } TQ_FOR(v, &(expr->members), next) { INDENTED(OUT("A_SET_OF(%s) list;\n", asn1c_type_name(arg, v, TNF_RSAFE))); } PCTX_DEF; OUT("} %s%s", expr->marker?"*":"", MKID(expr->Identifier)); if(arg->embed) OUT(";\n"); else OUT("_t;\n"); /* * SET OF/SEQUENCE OF definition, SET OF mode. */ return asn1c_lang_C_type_SEx_OF_def(arg, 0); } static int asn1c_lang_C_type_SEx_OF_def(arg_t *arg, int seq_of) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; int tags_impl_skip = 0; char *p; REDIR(OT_DEPS); if(seq_of) { OUT("#include \n"); } else { OUT("#include \n"); OUT("\n"); } REDIR(OT_STAT_DEFS); /* * 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); INDENTED(OUT("{ "); 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); ); OUT("};\n"); p = MKID(expr->Identifier); OUT("static ber_tlv_tag_t asn1_DEF_%s_tags[] = {\n", p); INDENTED( if(expr->tag.tag_class) { _print_tag(arg, expr, &expr->tag); if(expr->tag.tag_mode != TM_EXPLICIT) tags_impl_skip++; } if(!expr->tag.tag_class || (expr->meta_type == AMT_TYPE && expr->tag.tag_mode == TM_EXPLICIT)) { struct asn1p_type_tag_s tag; if(expr->tag.tag_class) OUT(",\n"); tag.tag_class = TC_UNIVERSAL; tag.tag_mode = TM_IMPLICIT; tag.tag_value = expr_type2uclass_value[expr->expr_type]; _print_tag(arg, expr, &tag); } OUT("\n"); ); OUT("};\n"); OUT("static asn1_SET_OF_specifics_t asn1_DEF_%s_specs = {\n", p); 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); INDENTED( OUT("\"%s\",\n", expr->Identifier); if(seq_of) { OUT("SEQUENCE_OF_constraint,\n"); OUT("SEQUENCE_OF_decode_ber,\n"); OUT("SEQUENCE_OF_encode_der,\n"); OUT("SEQUENCE_OF_print,\n"); OUT("SEQUENCE_OF_free,\n"); } else { OUT("SET_OF_constraint,\n"); OUT("SET_OF_decode_ber,\n"); OUT("SET_OF_encode_der,\n"); OUT("SET_OF_print,\n"); OUT("SET_OF_free,\n"); } OUT("0,\t/* Use generic outmost tag fetcher */\n"); OUT("asn1_DEF_%s_tags,\n", p); OUT("sizeof(asn1_DEF_%s_tags)\n", p); OUT("\t/sizeof(asn1_DEF_%s_tags[0]),\n", p); OUT("%d,\t/* Tags to skip */\n", tags_impl_skip); OUT("%d,\t/* Whether CONSTRUCTED */\n", 1); OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p); ); OUT("};\n"); OUT("\n"); REDIR(OT_DEPS); if(!arg->embed) OUT("extern asn1_TYPE_descriptor_t asn1_DEF_%s;\n", p); REDIR(OT_TYPE_DECLS); return 0; } int asn1c_lang_C_type_CHOICE(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; char *p; DEPENDENCIES; p = MKID(expr->Identifier); if(arg->embed) { OUT("struct %s {\n", p); } else { OUT("typedef struct %s {\n", p); } INDENTED( OUT("enum {\n"); INDENTED( OUT("%s_PR_NOTHING,\t" "/* No components present */\n", p); TQ_FOR(v, &(expr->members), next) { if(v->expr_type == A1TC_EXTENSIBLE) continue; p = MKID(expr->Identifier); OUT("%s_PR_", p); p = MKID(v->Identifier); OUT("%s,\n", p, p); } ); OUT("} present;\n"); OUT("union {\n", p); TQ_FOR(v, &(expr->members), next) { EMBED(v); } if(UNNAMED_UNIONS) OUT("};\n"); else OUT("} choice;\n"); ); PCTX_DEF; OUT("} %s%s", expr->marker?"*":"", MKID(expr->Identifier)); if(arg->embed) OUT(";\n"); else OUT("_t;\n"); return asn1c_lang_C_type_CHOICE_def(arg); } static int asn1c_lang_C_type_CHOICE_def(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; int elements; /* Number of elements */ int tags_impl_skip = 0; int comp_mode = 0; /* {root,ext=1,root,root,...} */ int extensible = 0; tag2el_t *tag2el = NULL; int tag2el_count = 0; char *p; /* * Fetch every inner tag from the tag to elements map. */ if(_fill_tag2el_map(arg, &tag2el, &tag2el_count, -1)) { if(tag2el) free(tag2el); return -1; } else { /* * Sort the map according to canonical order of their tags. */ _ctc_arg = arg; qsort(tag2el, tag2el_count, sizeof(*tag2el), _tag2el_cmp); } REDIR(OT_STAT_DEFS); OUT("#include \n"); OUT("\n"); /* * 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); 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); }); OUT("};\n"); p = MKID(expr->Identifier); OUT("static ber_tlv_tag_t asn1_DEF_%s_tags[] = {\n", p); if(arg->embed) { /* * Our parent structure has already taken this into account. */ } else { INDENTED( if(expr->tag.tag_class) { _print_tag(arg, expr, &expr->tag); if(expr->tag.tag_mode != TM_EXPLICIT) tags_impl_skip++; } OUT("\n"); ); } OUT("};\n"); /* * Tags to elements map. */ p = MKID(expr->Identifier); OUT("static asn1_CHOICE_tag2member_t asn1_DEF_%s_tag2el[] = {\n", p); if(tag2el_count) { int i; for(i = 0; i < tag2el_count; i++) { OUT(" { "); _print_tag(arg, expr, &tag2el[i].el_tag); OUT(", "); OUT("%d ", tag2el[i].el_no); OUT("}, /* %s at %d */\n", tag2el[i].from_expr->Identifier, tag2el[i].from_expr->_lineno ); } } OUT("};\n"); OUT("static asn1_CHOICE_specifics_t asn1_DEF_%s_specs = {\n", p); INDENTED( OUT("sizeof(struct %s),\n", p); 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", extensible); ); OUT("};\n"); OUT("asn1_TYPE_descriptor_t asn1_DEF_%s = {\n", p); INDENTED( OUT("\"%s\",\n", expr->Identifier); OUT("CHOICE_constraint,\n"); OUT("CHOICE_decode_ber,\n"); OUT("CHOICE_encode_der,\n"); OUT("CHOICE_print,\n"); OUT("CHOICE_free,\n"); OUT("CHOICE_outmost_tag,\n"); OUT("asn1_DEF_%s_tags,\n", p); OUT("sizeof(asn1_DEF_%s_tags)\n", p); OUT("\t/sizeof(asn1_DEF_%s_tags[0]),\n", p); OUT("%d,\t/* Tags to skip */\n", tags_impl_skip); OUT("%d,\t/* Whether CONSTRUCTED */\n", 1); OUT("&asn1_DEF_%s_specs\t/* Additional specs */\n", p); ); OUT("};\n"); OUT("\n"); REDIR(OT_DEPS); if(!arg->embed) OUT("extern asn1_TYPE_descriptor_t asn1_DEF_%s;\n", p); REDIR(OT_TYPE_DECLS); return 0; } int asn1c_lang_C_type_REFERENCE(arg_t *arg) { asn1p_ref_t *ref; ref = arg->expr->reference; if(ref->components[ref->comp_count-1].name[0] == '&') { asn1p_module_t *mod; asn1p_expr_t *extract; arg_t tmp; int ret; extract = asn1f_class_access_ex(arg->asn, arg->mod, arg->expr, ref, &mod); if(extract == NULL) return -1; extract = asn1p_expr_clone(extract); if(extract) { if(extract->Identifier) free(extract->Identifier); extract->Identifier = strdup(arg->expr->Identifier); if(extract->Identifier == NULL) { asn1p_expr_free(extract); return -1; } } else { return -1; } tmp = *arg; tmp.asn = arg->asn; tmp.mod = mod; tmp.expr = extract; ret = arg->default_cb(&tmp); asn1p_expr_free(extract); return ret; } return asn1c_lang_C_type_SIMPLE_TYPE(arg); } int asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { asn1p_expr_t *expr = arg->expr; int tags_impl_skip = 0; char *p; if(arg->embed) { REDIR(OT_TYPE_DECLS); OUT("%s\t", asn1c_type_name(arg, arg->expr, expr->marker?TNF_RSAFE:TNF_CTYPE)); OUT("%s", expr->marker?"*":" "); OUT("%s;", MKID(expr->Identifier)); if(expr->marker) OUT("\t/* %s */", (expr->marker==EM_OPTIONAL)?"OPTIONAL":"DEFAULT"); OUT("\n"); return 0; } REDIR(OT_DEPS); OUT("#include <%s.h>\n", asn1c_type_name(arg, expr, TNF_INCLUDE)); REDIR(OT_TYPE_DECLS); OUT("typedef %s\t", asn1c_type_name(arg, arg->expr, TNF_CTYPE)); OUT("%s", expr->marker?"*":" "); OUT("%s_t;\n", MKID(expr->Identifier)); OUT("\n"); REDIR(OT_STAT_DEFS); p = MKID(expr->Identifier); OUT("static ber_tlv_tag_t asn1_DEF_%s_tags[] = {\n", p); INDENTED( if(expr->tag.tag_class) { _print_tag(arg, expr, &expr->tag); if(expr->tag.tag_mode != TM_EXPLICIT) tags_impl_skip++; } if(!expr->tag.tag_class || (expr->meta_type == AMT_TYPE && expr->tag.tag_mode == TM_EXPLICIT)) { struct asn1p_type_tag_s tag; if(expr->tag.tag_class) OUT(",\n"); tag.tag_class = TC_UNIVERSAL; tag.tag_mode = TM_IMPLICIT; tag.tag_value = expr_type2uclass_value[expr->expr_type]; _print_tag(arg, expr, &tag); } OUT("\n"); ); OUT("};\n"); OUT("asn1_TYPE_descriptor_t asn1_DEF_%s = {\n", p); INDENTED( OUT("\"%s\",\n", expr->Identifier); OUT("%s_constraint,\n", p); OUT("%s_decode_ber,\n", p); OUT("%s_encode_der,\n", p); OUT("%s_print,\n", p); OUT("%s_free,\n", p); OUT("0,\t/* Use generic outmost tag fetcher */\n"); OUT("asn1_DEF_%s_tags,\n", p); OUT("sizeof(asn1_DEF_%s_tags)\n", p); OUT("\t/sizeof(asn1_DEF_%s_tags[0]),\n", p); OUT("%d,\t/* Tags to skip */\n", tags_impl_skip); OUT("-0\t/* Unknown yet */\n"); ); OUT("};\n"); OUT("\n"); /* * Constraint checking. */ if(expr->constraints) /* Emit tables with FROM() constraints */ emit_alphabet_tables(arg, expr->constraints, 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); 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 { 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"); OUT("\n"); /* * 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(" * so adjust the DEF appropriately.\n"); OUT(" */\n"); OUT("static void\n"); OUT("inherit_TYPE_descriptor(asn1_TYPE_descriptor_t *td) {\n"); 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); 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("return td->ber_decoder(td, structure,\n"); OUT("\tbufptr, size, tag_mode);\n"); ); OUT("}\n"); OUT("\n"); p = MKID(expr->Identifier); OUT("der_enc_rval_t\n"); OUT("%s_encode_der(asn1_TYPE_descriptor_t *td,\n", p); 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("return td->der_encoder(td, structure, tag_mode, tag, cb, app_key);\n"); ); OUT("}\n"); OUT("\n"); p = MKID(expr->Identifier); OUT("int\n"); 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("return td->print_struct(td, struct_ptr, ilevel, cb, app_key);\n"); ); OUT("}\n"); OUT("\n"); p = MKID(expr->Identifier); OUT("void\n"); 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("td->free_struct(td, struct_ptr, contents_only);\n"); ); OUT("}\n"); OUT("\n"); REDIR(OT_FUNC_DECLS); p = MKID(expr->Identifier); OUT("extern asn1_TYPE_descriptor_t asn1_DEF_%s;\n", p); OUT("asn_constr_check_f %s_constraint;\n", p); OUT("ber_type_decoder_f %s_decode_ber;\n", p); OUT("der_type_encoder_f %s_encode_der;\n", p); OUT("asn_struct_print_f %s_print;\n", p); OUT("asn_struct_free_f %s_free;\n", p); return 0; } int asn1c_lang_C_type_EXTENSIBLE(arg_t *arg) { OUT("/*\n"); OUT(" * This type is extensible,\n"); OUT(" * possible extensions are below.\n"); OUT(" */\n"); return 0; } static int _print_tag(arg_t *arg, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag_p) { struct asn1p_type_tag_s tag; if(tag_p) { tag = *tag_p; } else { if(asn1f_fetch_tag(arg->asn, arg->mod, expr, &tag)) { OUT("-1 /* Ambiguous tag (CHOICE?) */"); return 0; } } OUT("("); switch(tag.tag_class) { case TC_UNIVERSAL: OUT("ASN_TAG_CLASS_UNIVERSAL"); break; case TC_APPLICATION: OUT("ASN_TAG_CLASS_APPLICATION"); break; case TC_CONTEXT_SPECIFIC: OUT("ASN_TAG_CLASS_CONTEXT"); break; case TC_PRIVATE: OUT("ASN_TAG_CLASS_PRIVATE"); break; case TC_NOCLASS: break; } OUT(" | (%lld << 2))", tag.tag_value); return 0; } /* * For constructed types, number of external tags may be greater than * number of elements in the type because of CHOICE type. * T ::= SET { -- Three possible tags: * a INTEGER, -- One tag is here... * b Choice1 -- ... and two more tags are there. * } * Choice1 ::= CHOICE { * s1 IA5String, * s2 ObjectDescriptor * } */ static int _fill_tag2el_map(arg_t *arg, tag2el_t **tag2el, int *count, int el_no) { asn1p_expr_t *expr = arg->expr; arg_t tmparg = *arg; asn1p_expr_t *v; int element = 0; TQ_FOR(v, &(expr->members), next) { if(v->expr_type == A1TC_EXTENSIBLE) continue; tmparg.expr = v; if(_add_tag2el_member(&tmparg, tag2el, count, (el_no==-1)?element:el_no)) { return -1; } element++; } return 0; } static int _add_tag2el_member(arg_t *arg, tag2el_t **tag2el, int *count, int el_no) { struct asn1p_type_tag_s tag; int ret; assert(el_no >= 0); ret = asn1f_fetch_tag(arg->asn, arg->mod, arg->expr, &tag); if(ret == 0) { void *p; p = realloc(*tag2el, sizeof(tag2el_t) * ((*count) + 1)); if(p) *tag2el = p; else return -1; DEBUG("Found tag for %s: %ld", arg->expr->Identifier, (long)tag.tag_value); (*tag2el)[*count].el_tag = tag; (*tag2el)[*count].el_no = el_no; (*tag2el)[*count].from_expr = arg->expr; (*count)++; return 0; } DEBUG("Searching tag in complex expression %s:%x at line %d", arg->expr->Identifier, arg->expr->expr_type, arg->expr->_lineno); /* * Iterate over members of CHOICE type. */ if(arg->expr->expr_type == ASN_CONSTR_CHOICE) { return _fill_tag2el_map(arg, tag2el, count, el_no); } if(arg->expr->expr_type == A1TC_REFERENCE) { arg_t tmp = *arg; asn1p_expr_t *expr; expr = asn1f_lookup_symbol_ex(tmp.asn, &tmp.mod, tmp.expr, arg->expr->reference); if(expr) { tmp.expr = expr; return _add_tag2el_member(&tmp, tag2el, count, el_no); } else { FATAL("Cannot dereference %s at line %d", arg->expr->Identifier, arg->expr->_lineno); return -1; } } DEBUG("No tag for %s at line %d", arg->expr->Identifier, arg->expr->_lineno); return -1; } 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("%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(\"%%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(\"%%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("#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(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("%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 { WARNING("Size operation is not defined for %s", ASN_EXPR_TYPE2STR(etype)); OUT("#warning Size operation not defined!\n"); 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: OUT("if(asn1_INTEGER2long(st, &value)) {\n"); INDENT(+1); OUT("_ASN_ERRLOG(\"%%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); assert(expr); return expr->expr_type; }