diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c index 5ce58fcc..ea0b63b3 100644 --- a/skeletons/constr_SET_OF.c +++ b/skeletons/constr_SET_OF.c @@ -271,42 +271,130 @@ SET_OF_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, struct _el_buffer { uint8_t *buf; size_t length; - size_t size; + size_t allocated_size; + unsigned bits_unused; }; /* Append bytes to the above structure */ static int _el_addbytes(const void *buffer, size_t size, void *el_buf_ptr) { - struct _el_buffer *el_buf = (struct _el_buffer *)el_buf_ptr; + struct _el_buffer *el_buf = (struct _el_buffer *)el_buf_ptr; - if(el_buf->length + size > el_buf->size) - return -1; + if(el_buf->length + size > el_buf->allocated_size) { + size_t new_size; + void *p; - memcpy(el_buf->buf + el_buf->length, buffer, size); + new_size = el_buf->allocated_size ? 2 * el_buf->allocated_size : 16; - el_buf->length += size; - return 0; + p = REALLOC(el_buf->buf, new_size); + if(p) { + el_buf->buf = p; + el_buf->allocated_size = new_size; + } else { + return -1; + } + } + + memcpy(el_buf->buf + el_buf->length, buffer, size); + + el_buf->length += size; + return 0; } static int _el_buf_cmp(const void *ap, const void *bp) { - const struct _el_buffer *a = (const struct _el_buffer *)ap; - const struct _el_buffer *b = (const struct _el_buffer *)bp; - int ret; - size_t common_len; + const struct _el_buffer *a = (const struct _el_buffer *)ap; + const struct _el_buffer *b = (const struct _el_buffer *)bp; + size_t common_len; + int ret; - if(a->length < b->length) - common_len = a->length; - else - common_len = b->length; + if(a->length < b->length) + common_len = a->length; + else + common_len = b->length; - ret = memcmp(a->buf, b->buf, common_len); - if(ret == 0) { - if(a->length < b->length) - ret = -1; - else if(a->length > b->length) - ret = 1; + ret = memcmp(a->buf, b->buf, common_len); + if(ret == 0) { + if(a->length < b->length) + ret = -1; + else if(a->length > b->length) + ret = 1; + /* Ignore unused bits. */ + if(a->length) { + assert((a->buf[a->length-1] & ~(0xff << a->bits_unused)) == 0); + assert((b->buf[b->length-1] & ~(0xff << b->bits_unused)) == 0); + } else { + assert(a->bits_unused == 0); + assert(b->bits_unused == 0); + } + } + + return ret; +} + +static void +SET_OF__encode_sorted_free(struct _el_buffer *el_buf, size_t count) { + size_t i; + + for(i = 0; i < count; i++) { + FREEMEM(el_buf[i].buf); + } + + FREEMEM(el_buf); +} + +enum SET_OF__encode_method { + SOES_DER +}; + +static struct _el_buffer * +SET_OF__encode_sorted(const asn_TYPE_member_t *elm, + const asn_anonymous_set_ *list, + enum SET_OF__encode_method method) { + static struct _el_buffer *encoded_els; + int edx; + + encoded_els = + (struct _el_buffer *)CALLOC(list->count, sizeof(encoded_els[0])); + if(encoded_els == NULL) { + return NULL; + } + + /* + * Encode all members. + */ + for(edx = 0; edx < list->count; edx++) { + const void *memb_ptr = list->array[edx]; + struct _el_buffer *encoded_el = &encoded_els[edx]; + asn_enc_rval_t erval; + + if(!memb_ptr) break; + + /* + * Encode the member into the prepared space. + */ + switch(method) { + case SOES_DER: + erval = elm->type->op->der_encoder(elm->type, memb_ptr, 0, elm->tag, + _el_addbytes, encoded_el); + break; + default: + assert(!"Unreachable"); + break; + } + if(erval.encoded < 0) break; } - return ret; + if(edx == list->count) { + /* + * Sort the encoded elements according to their encoding. + */ + qsort(encoded_els, list->count, sizeof(encoded_els[0]), _el_buf_cmp); + + return encoded_els; + } else { + SET_OF__encode_sorted_free(encoded_els, edx); + return NULL; + } } + /* * The DER encoder of the SET OF type. */ @@ -315,134 +403,78 @@ SET_OF_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key) { const asn_TYPE_member_t *elm = td->elements; - const asn_TYPE_descriptor_t *elm_type = elm->type; - der_type_encoder_f *der_encoder = elm_type->op->der_encoder; const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); size_t computed_size = 0; - ssize_t encoding_size = 0; - struct _el_buffer *encoded_els; - ssize_t eels_count = 0; - size_t max_encoded_len = 1; - asn_enc_rval_t erval; - int ret; - int edx; + ssize_t encoding_size = 0; + struct _el_buffer *encoded_els; + int edx; ASN_DEBUG("Estimating size for SET OF %s", td->name); - /* - * Gather the length of the underlying members sequence. - */ - for(edx = 0; edx < list->count; edx++) { - void *memb_ptr = list->array[edx]; - if(!memb_ptr) continue; - erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, 0, 0); - if(erval.encoded == -1) - return erval; - computed_size += erval.encoded; + /* + * Gather the length of the underlying members sequence. + */ + for(edx = 0; edx < list->count; edx++) { + void *memb_ptr = list->array[edx]; + asn_enc_rval_t erval; - /* Compute maximum encoding's size */ - if(max_encoded_len < (size_t)erval.encoded) - max_encoded_len = erval.encoded; + if(!memb_ptr) ASN__ENCODE_FAILED; + + erval = + elm->type->op->der_encoder(elm->type, memb_ptr, 0, elm->tag, 0, 0); + if(erval.encoded == -1) return erval; + computed_size += erval.encoded; } - /* - * Encode the TLV for the sequence itself. - */ - encoding_size = der_write_tags(td, computed_size, tag_mode, 1, tag, - cb, app_key); - if(encoding_size == -1) { - erval.encoded = -1; - erval.failed_type = td; - erval.structure_ptr = sptr; - return erval; - } - computed_size += encoding_size; - if(!cb || list->count == 0) { - erval.encoded = computed_size; - ASN__ENCODED_OK(erval); - } - - /* - * DER mandates dynamic sorting of the SET OF elements - * according to their encodings. Build an array of the - * encoded elements. - */ - encoded_els = - (struct _el_buffer *)MALLOC(list->count * sizeof(encoded_els[0])); - if(encoded_els == NULL) { + /* + * Encode the TLV for the sequence itself. + */ + encoding_size = + der_write_tags(td, computed_size, tag_mode, 1, tag, cb, app_key); + if(encoding_size < 0) { ASN__ENCODE_FAILED; } + computed_size += encoding_size; + + if(!cb || list->count == 0) { + asn_enc_rval_t erval; + erval.encoded = computed_size; + ASN__ENCODED_OK(erval); + } ASN_DEBUG("Encoding members of %s SET OF", td->name); - /* - * Encode all members. - */ - for(edx = 0; edx < list->count; edx++) { - const void *memb_ptr = list->array[edx]; - struct _el_buffer *encoded_el = &encoded_els[eels_count]; + /* + * DER mandates dynamic sorting of the SET OF elements + * according to their encodings. Build an array of the + * encoded elements. + */ + encoded_els = SET_OF__encode_sorted(elm, list, SOES_DER); - if(!memb_ptr) continue; + /* + * Report encoded elements to the application. + * Dispose of temporary sorted members table. + */ + for(edx = 0; edx < list->count; edx++) { + struct _el_buffer *encoded_el = &encoded_els[edx]; + /* Report encoded chunks to the application */ + if(cb(encoded_el->buf, encoded_el->length, app_key) < 0) { + break; + } else { + encoding_size += encoded_el->length; + } + } - /* - * Prepare space for encoding. - */ - encoded_el->buf = (uint8_t *)MALLOC(max_encoded_len); - if(encoded_el->buf) { - encoded_el->length = 0; - encoded_el->size = max_encoded_len; - } else { - for(edx--; edx >= 0; edx--) - FREEMEM(encoded_els[edx].buf); - FREEMEM(encoded_els); - ASN__ENCODE_FAILED; - } + SET_OF__encode_sorted_free(encoded_els, list->count); - /* - * Encode the member into the prepared space. - */ - erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, - _el_addbytes, encoded_el); - if(erval.encoded == -1) { - for(; edx >= 0; edx--) - FREEMEM(encoded_els[edx].buf); - FREEMEM(encoded_els); - return erval; - } - encoding_size += erval.encoded; - eels_count++; - } - - /* - * Sort the encoded elements according to their encoding. - */ - qsort(encoded_els, eels_count, sizeof(encoded_els[0]), _el_buf_cmp); - - /* - * Report encoded elements to the application. - * Dispose of temporary sorted members table. - */ - ret = 0; - for(edx = 0; edx < eels_count; edx++) { - struct _el_buffer *encoded_el = &encoded_els[edx]; - /* Report encoded chunks to the application */ - if(ret == 0 - && cb(encoded_el->buf, encoded_el->length, app_key) < 0) - ret = -1; - FREEMEM(encoded_el->buf); - } - FREEMEM(encoded_els); - - if(ret || computed_size != (size_t)encoding_size) { - /* - * Standard callback failed, or - * encoded size is not equal to the computed size. - */ - ASN__ENCODE_FAILED; - } else { - erval.encoded = computed_size; + if(edx == list->count) { + assert(computed_size == (size_t)encoding_size); + asn_enc_rval_t erval; + erval.encoded = computed_size; ASN__ENCODED_OK(erval); + } else { + ASN__ENCODE_FAILED; } }