diff --git a/skeletons/ber_decoder.c b/skeletons/ber_decoder.c index ab8d671c..09211edc 100644 --- a/skeletons/ber_decoder.c +++ b/skeletons/ber_decoder.c @@ -54,7 +54,7 @@ ber_check_tags(asn1_TYPE_descriptor_t *head, ber_dec_ctx_t *ctx, /* * So what does all this tags_impl_skip stuff mean? - * Imagine two types, + * Imagine the two types, * A ::= [5] IMPLICIT T * B ::= [2] EXPLICIT T * Where T is defined as diff --git a/skeletons/constr_CHOICE.c b/skeletons/constr_CHOICE.c index 1ecbbce7..d1beff42 100644 --- a/skeletons/constr_CHOICE.c +++ b/skeletons/constr_CHOICE.c @@ -67,8 +67,8 @@ static inline void _set_present_idx(void *sptr, int offset, int size, int pres); */ static int _search4tag(const void *ap, const void *bp) { - const asn1_CHOICE_tag2member_t *a = ap; - const asn1_CHOICE_tag2member_t *b = bp; + const asn1_TYPE_tag2member_t *a = ap; + const asn1_TYPE_tag2member_t *b = bp; int a_class = BER_TAG_CLASS(a->el_tag); int b_class = BER_TAG_CLASS(b->el_tag); @@ -180,8 +180,8 @@ CHOICE_decode_ber(asn1_TYPE_descriptor_t *sd, } do { - asn1_CHOICE_tag2member_t *t2m; - asn1_CHOICE_tag2member_t key; + asn1_TYPE_tag2member_t *t2m; + asn1_TYPE_tag2member_t key; key.el_tag = tlv_tag; t2m = bsearch(&key, specs->tag2el, specs->tag2el_count, diff --git a/skeletons/constr_CHOICE.h b/skeletons/constr_CHOICE.h index 70766e9d..1308bd4a 100644 --- a/skeletons/constr_CHOICE.h +++ b/skeletons/constr_CHOICE.h @@ -15,16 +15,10 @@ typedef struct asn1_CHOICE_element_s { int optional; /* Whether the element is optional */ ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ - asn1_TYPE_descriptor_t - *type; /* Member type descriptor */ + asn1_TYPE_descriptor_t *type; /* Member type descriptor */ char *name; /* ASN.1 identifier of the element */ } asn1_CHOICE_element_t; -typedef struct asn1_CHOICE_tag2member_s { - ber_tlv_tag_t el_tag; /* Outmost tag of the member */ - int el_no; /* Index of the associated member, base 0 */ -} asn1_CHOICE_tag2member_t; - typedef struct asn1_CHOICE_specifics_s { /* * Target structure description. @@ -43,7 +37,7 @@ typedef struct asn1_CHOICE_specifics_s { /* * Tags to members mapping table. */ - asn1_CHOICE_tag2member_t *tag2el; + asn1_TYPE_tag2member_t *tag2el; int tag2el_count; /* diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c index 71689674..5c47df09 100644 --- a/skeletons/constr_SEQUENCE.c +++ b/skeletons/constr_SEQUENCE.c @@ -3,6 +3,7 @@ * Redistribution and modifications are permitted subject to BSD license. */ #include +#include /* * Number of bytes left for this structure. @@ -62,6 +63,35 @@ ( ((memb_idx) > (specs)->ext_after) \ &&((memb_idx) < (specs)->ext_before)) + +/* + * Tags are canonically sorted in the tag2element map. + */ +static int +_t2e_cmp(const void *ap, const void *bp) { + const asn1_TYPE_tag2member_t *a = ap; + const asn1_TYPE_tag2member_t *b = bp; + int a_class = BER_TAG_CLASS(a->el_tag); + int b_class = BER_TAG_CLASS(b->el_tag); + + if(a_class == b_class) { + ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); + ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); + + if(a_value == b_value) + return 0; + else if(a_value < b_value) + return -1; + else + return 1; + } else if(a_class < b_class) { + return -1; + } else { + return 1; + } +} + + /* * The decoder of the SEQUENCE type. */ @@ -151,6 +181,7 @@ SEQUENCE_decode_ber(asn1_TYPE_descriptor_t *sd, void *memb_ptr2; /* Pointer to that pointer */ ssize_t tag_len; /* Length of TLV's T */ int opt_edx_end; /* Next non-optional element */ + int use_bsearch; int n; if(ctx->step & 1) @@ -196,9 +227,15 @@ SEQUENCE_decode_ber(asn1_TYPE_descriptor_t *sd, /* * Find the next available type with this tag. */ + use_bsearch = 0; opt_edx_end = edx + elements[edx].optional + 1; if(opt_edx_end > specs->elements_count) opt_edx_end = specs->elements_count; /* Cap */ + else if(opt_edx_end - edx > 5) { + /* Limit the scope of linear search */ + opt_edx_end = edx + 5; + use_bsearch = 1; + } for(n = edx; n < opt_edx_end; n++) { if(BER_TAGS_EQUAL(tlv_tag, elements[n].tag)) { /* @@ -207,10 +244,39 @@ SEQUENCE_decode_ber(asn1_TYPE_descriptor_t *sd, * Reposition over the right element. */ edx = n; - ctx->step = 2 * edx; /* Remember! */ + ctx->step = 1 + 2 * edx; /* Remember! */ + goto microphase2; + } else if(elements[n].tag == (ber_tlv_tag_t)-1) { + use_bsearch = 1; break; } } + if(use_bsearch) { + /* + * Resorch to a binary search over + * sorted array of tags. + */ + asn1_TYPE_tag2member_t *t2m; + asn1_TYPE_tag2member_t key; + key.el_tag = tlv_tag; + t2m = bsearch(&key, specs->tag2el, specs->tag2el_count, + sizeof(specs->tag2el[0]), _t2e_cmp); + if(t2m && t2m->el_no >= edx) { + /* + * Rewind to the first element with that tag, + * `cause bsearch() does not guarantee order. + */ + while(t2m > specs->tag2el + && BER_TAGS_EQUAL(tlv_tag, + t2m[-1].el_tag) + && t2m[-1].el_no >= edx) + t2m++; + edx = t2m->el_no; + ctx->step = 1 + 2 * edx; + goto microphase2; + } + n = opt_edx_end; + } if(n == opt_edx_end) { /* * If tag is unknown, it may be either @@ -222,8 +288,9 @@ SEQUENCE_decode_ber(asn1_TYPE_descriptor_t *sd, if(!IN_EXTENSION_GROUP(specs, edx)) { ASN_DEBUG("Unexpected tag %s", ber_tlv_tag_string(tlv_tag)); - ASN_DEBUG("Expected tag %s%s", + ASN_DEBUG("Expected tag %s (%s)%s", ber_tlv_tag_string(elements[edx].tag), + elements[edx].name, elements[edx].optional ?" or alternatives":""); RETURN(RC_FAIL); @@ -389,6 +456,7 @@ SEQUENCE_decode_ber(asn1_TYPE_descriptor_t *sd, RETURN(RC_OK); } + /* * The DER encoder of the SEQUENCE type. */ @@ -574,7 +642,7 @@ SEQUENCE_constraint(asn1_TYPE_descriptor_t *td, const void *sptr, const void *memb_ptr; if(elm->optional) { - memb_ptr = *(const void **)((const char *)sptr + elm->memb_offset); + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); if(!memb_ptr) continue; } else { memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); diff --git a/skeletons/constr_SEQUENCE.h b/skeletons/constr_SEQUENCE.h index c15729ca..17754bb5 100644 --- a/skeletons/constr_SEQUENCE.h +++ b/skeletons/constr_SEQUENCE.h @@ -15,8 +15,7 @@ typedef struct asn1_SEQUENCE_element_s { int optional; /* Whether the element is optional */ ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ - asn1_TYPE_descriptor_t - *type; /* Member type descriptor */ + asn1_TYPE_descriptor_t *type; /* Member type descriptor */ char *name; /* ASN.1 identifier of the element */ } asn1_SEQUENCE_element_t; @@ -33,6 +32,12 @@ typedef struct asn1_SEQUENCE_specifics_s { asn1_SEQUENCE_element_t *elements; int elements_count; + /* + * Tags to members mapping table (sorted). + */ + asn1_TYPE_tag2member_t *tag2el; + int tag2el_count; + /* * Description of an extensions group. */ diff --git a/skeletons/constr_SET.c b/skeletons/constr_SET.c index d0cac1d0..0385722c 100644 --- a/skeletons/constr_SET.c +++ b/skeletons/constr_SET.c @@ -61,8 +61,8 @@ */ static int _t2e_cmp(const void *ap, const void *bp) { - const asn1_SET_tag2member_t *a = ap; - const asn1_SET_tag2member_t *b = bp; + const asn1_TYPE_tag2member_t *a = ap; + const asn1_TYPE_tag2member_t *b = bp; int a_class = BER_TAG_CLASS(a->el_tag); int b_class = BER_TAG_CLASS(b->el_tag); @@ -225,8 +225,8 @@ SET_decode_ber(asn1_TYPE_descriptor_t *sd, * but is not strongly anticipated either. */ } else { - asn1_SET_tag2member_t *t2m; - asn1_SET_tag2member_t key; + asn1_TYPE_tag2member_t *t2m; + asn1_TYPE_tag2member_t key; key.el_tag = tlv_tag; t2m = bsearch(&key, specs->tag2el, specs->tag2el_count, @@ -430,7 +430,7 @@ SET_encode_der(asn1_TYPE_descriptor_t *sd, size_t computed_size = 0; der_enc_rval_t my_erval; int t2m_build_own = (specs->tag2el_count != specs->elements_count); - asn1_SET_tag2member_t *t2m; + asn1_TYPE_tag2member_t *t2m; int t2m_count; ssize_t ret; int edx; diff --git a/skeletons/constr_SET.h b/skeletons/constr_SET.h index c0ac07f5..8cb3fa8d 100644 --- a/skeletons/constr_SET.h +++ b/skeletons/constr_SET.h @@ -15,19 +15,10 @@ typedef struct asn1_SET_element_s { int optional; /* Whether the element is optional */ ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ - asn1_TYPE_descriptor_t - *type; /* Member type descriptor */ + asn1_TYPE_descriptor_t *type; /* Member type descriptor */ char *name; /* ASN.1 identifier of the element */ } asn1_SET_element_t; -/* - * Map between the outmost tag of the element and the corresponding - * element's index. - */ -typedef struct asn1_SET_tag2member_s { - ber_tlv_tag_t el_tag; /* Outmost tag of the member */ - int el_no; /* Index of the associated member, base 0 */ -} asn1_SET_tag2member_t; typedef struct asn1_SET_specifics_s { /* @@ -46,7 +37,7 @@ typedef struct asn1_SET_specifics_s { /* * Tags to members mapping table (sorted). */ - asn1_SET_tag2member_t *tag2el; + asn1_TYPE_tag2member_t *tag2el; int tag2el_count; /* diff --git a/skeletons/constr_SET_OF.h b/skeletons/constr_SET_OF.h index 814774dc..e2c6d8fd 100644 --- a/skeletons/constr_SET_OF.h +++ b/skeletons/constr_SET_OF.h @@ -9,8 +9,7 @@ typedef struct asn1_SET_OF_element_s { ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ - asn1_TYPE_descriptor_t - *type; /* Member type descriptor */ + asn1_TYPE_descriptor_t *type; /* Member type descriptor */ } asn1_SET_OF_element_t; typedef struct asn1_SET_OF_specifics_s { diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h index c7cfb22b..5c001049 100644 --- a/skeletons/constr_TYPE.h +++ b/skeletons/constr_TYPE.h @@ -83,6 +83,16 @@ typedef struct asn1_TYPE_descriptor_s { void *specifics; } asn1_TYPE_descriptor_t; +/* + * BER tag to element number mapping. + */ +typedef struct asn1_TYPE_tag2member_s { + ber_tlv_tag_t el_tag; /* Outmost tag of the member */ + int el_no; /* Index of the associated member, base 0 */ +} asn1_TYPE_tag2member_t; + + + /* * This function is a wrapper around (td)->print_struct, which prints out * the contents of the target language's structure (struct_ptr) into the