mirror of https://gerrit.osmocom.org/asn1c
Support for canonical CANONICAL-XER ordering
This commit is contained in:
parent
ff1333afb1
commit
d519380089
|
@ -435,11 +435,11 @@ SET_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
|
|||
*/
|
||||
asn_enc_rval_t
|
||||
SET_encode_der(asn_TYPE_descriptor_t *td,
|
||||
void *ptr, int tag_mode, ber_tlv_tag_t tag,
|
||||
void *sptr, int tag_mode, ber_tlv_tag_t tag,
|
||||
asn_app_consume_bytes_f *cb, void *app_key) {
|
||||
asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics;
|
||||
size_t computed_size = 0;
|
||||
asn_enc_rval_t my_erval;
|
||||
asn_enc_rval_t er;
|
||||
int t2m_build_own = (specs->tag2el_count != td->elements_count);
|
||||
asn_TYPE_tag2member_t *t2m;
|
||||
int t2m_count;
|
||||
|
@ -451,12 +451,7 @@ SET_encode_der(asn_TYPE_descriptor_t *td,
|
|||
*/
|
||||
if(t2m_build_own) {
|
||||
(void *)t2m = alloca(td->elements_count * sizeof(t2m[0]));
|
||||
if(!t2m) { /* There are such platforms */
|
||||
my_erval.encoded = -1;
|
||||
my_erval.failed_type = td;
|
||||
my_erval.structure_ptr = ptr;
|
||||
return my_erval;
|
||||
}
|
||||
if(!t2m) _ASN_ENCODE_FAILED; /* There are such platforms */
|
||||
t2m_count = 0;
|
||||
} else {
|
||||
/*
|
||||
|
@ -472,14 +467,14 @@ SET_encode_der(asn_TYPE_descriptor_t *td,
|
|||
*/
|
||||
for(edx = 0; edx < td->elements_count; edx++) {
|
||||
asn_TYPE_member_t *elm = &td->elements[edx];
|
||||
asn_enc_rval_t erval;
|
||||
asn_enc_rval_t tmper;
|
||||
void *memb_ptr;
|
||||
|
||||
/*
|
||||
* Compute the length of the encoding of this member.
|
||||
*/
|
||||
if(elm->flags & ATF_POINTER) {
|
||||
memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
|
||||
memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
|
||||
if(!memb_ptr) {
|
||||
if(t2m_build_own) {
|
||||
t2m[t2m_count].el_no = edx;
|
||||
|
@ -489,14 +484,14 @@ SET_encode_der(asn_TYPE_descriptor_t *td,
|
|||
continue;
|
||||
}
|
||||
} else {
|
||||
memb_ptr = (void *)((char *)ptr + elm->memb_offset);
|
||||
memb_ptr = (void *)((char *)sptr + elm->memb_offset);
|
||||
}
|
||||
erval = elm->type->der_encoder(elm->type, memb_ptr,
|
||||
tmper = elm->type->der_encoder(elm->type, memb_ptr,
|
||||
elm->tag_mode, elm->tag,
|
||||
0, 0);
|
||||
if(erval.encoded == -1)
|
||||
return erval;
|
||||
computed_size += erval.encoded;
|
||||
if(tmper.encoded == -1)
|
||||
return tmper;
|
||||
computed_size += tmper.encoded;
|
||||
|
||||
/*
|
||||
* Remember the outmost tag of this member.
|
||||
|
@ -533,72 +528,74 @@ SET_encode_der(asn_TYPE_descriptor_t *td,
|
|||
* Encode the TLV for the sequence itself.
|
||||
*/
|
||||
ret = der_write_tags(td, computed_size, tag_mode, 1, tag, cb, app_key);
|
||||
if(ret == -1) {
|
||||
my_erval.encoded = -1;
|
||||
my_erval.failed_type = td;
|
||||
my_erval.structure_ptr = ptr;
|
||||
return my_erval;
|
||||
}
|
||||
my_erval.encoded = computed_size + ret;
|
||||
if(ret == -1) _ASN_ENCODE_FAILED;
|
||||
er.encoded = computed_size + ret;
|
||||
|
||||
if(!cb) return my_erval;
|
||||
if(!cb) return er;
|
||||
|
||||
/*
|
||||
* Encode all members.
|
||||
*/
|
||||
for(edx = 0; edx < td->elements_count; edx++) {
|
||||
asn_TYPE_member_t *elm;
|
||||
asn_enc_rval_t erval;
|
||||
asn_enc_rval_t tmper;
|
||||
void *memb_ptr;
|
||||
|
||||
/* Encode according to the tag order */
|
||||
elm = &td->elements[t2m[edx].el_no];
|
||||
|
||||
if(elm->flags & ATF_POINTER) {
|
||||
memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
|
||||
memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
|
||||
if(!memb_ptr) continue;
|
||||
} else {
|
||||
memb_ptr = (void *)((char *)ptr + elm->memb_offset);
|
||||
memb_ptr = (void *)((char *)sptr + elm->memb_offset);
|
||||
}
|
||||
erval = elm->type->der_encoder(elm->type, memb_ptr,
|
||||
tmper = elm->type->der_encoder(elm->type, memb_ptr,
|
||||
elm->tag_mode, elm->tag,
|
||||
cb, app_key);
|
||||
if(erval.encoded == -1)
|
||||
return erval;
|
||||
computed_size -= erval.encoded;
|
||||
if(tmper.encoded == -1)
|
||||
return tmper;
|
||||
computed_size -= tmper.encoded;
|
||||
}
|
||||
|
||||
if(computed_size != 0) {
|
||||
/*
|
||||
* Encoded size is not equal to the computed size.
|
||||
*/
|
||||
my_erval.encoded = -1;
|
||||
my_erval.failed_type = td;
|
||||
my_erval.structure_ptr = ptr;
|
||||
_ASN_ENCODE_FAILED;
|
||||
}
|
||||
|
||||
return my_erval;
|
||||
return er;
|
||||
}
|
||||
|
||||
asn_enc_rval_t
|
||||
SET_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
|
||||
int ilevel, enum xer_encoder_flags_e flags,
|
||||
asn_app_consume_bytes_f *cb, void *app_key) {
|
||||
asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics;
|
||||
asn_enc_rval_t er;
|
||||
int xcan = (flags & XER_F_CANONICAL);
|
||||
asn_TYPE_tag2member_t *t2m = specs->tag2el_cxer;
|
||||
int t2m_count = specs->tag2el_cxer_count;
|
||||
int edx;
|
||||
|
||||
if(!sptr)
|
||||
_ASN_ENCODE_FAILED;
|
||||
|
||||
assert(t2m_count == td->elements_count);
|
||||
|
||||
er.encoded = 0;
|
||||
|
||||
for(edx = 0; edx < td->elements_count; edx++) {
|
||||
for(edx = 0; edx < t2m_count; edx++) {
|
||||
asn_enc_rval_t tmper;
|
||||
asn_TYPE_member_t *elm = &td->elements[edx];
|
||||
asn_TYPE_member_t *elm;
|
||||
void *memb_ptr;
|
||||
const char *mname = elm->name;
|
||||
unsigned int mlen = strlen(elm->name);
|
||||
const char *mname;
|
||||
unsigned int mlen;
|
||||
|
||||
elm = &td->elements[t2m[edx].el_no];
|
||||
mname = elm->name;
|
||||
mlen = strlen(elm->name);
|
||||
|
||||
if(elm->flags & ATF_POINTER) {
|
||||
memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
|
||||
|
@ -624,6 +621,8 @@ SET_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
|
|||
if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1);
|
||||
|
||||
return er;
|
||||
cb_failed:
|
||||
_ASN_ENCODE_FAILED;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -18,10 +18,19 @@ typedef struct asn_SET_specifics_s {
|
|||
|
||||
/*
|
||||
* Tags to members mapping table (sorted).
|
||||
* Sometimes suitable for DER encoding (untagged CHOICE is present);
|
||||
* if so, tag2el_count will be greater than td->elements_count.
|
||||
*/
|
||||
asn_TYPE_tag2member_t *tag2el;
|
||||
int tag2el_count;
|
||||
|
||||
/*
|
||||
* Tags to members mapping table, second edition.
|
||||
* Suitable for CANONICAL-XER encoding.
|
||||
*/
|
||||
asn_TYPE_tag2member_t *tag2el_cxer;
|
||||
int tag2el_cxer_count;
|
||||
|
||||
/*
|
||||
* Extensions-related stuff.
|
||||
*/
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <asn_internal.h>
|
||||
#include <constr_SET_OF.h>
|
||||
#include <asn_SET_OF.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* Number of bytes left for this structure.
|
||||
|
@ -449,6 +450,43 @@ SET_OF_encode_der(asn_TYPE_descriptor_t *td, void *ptr,
|
|||
return erval;
|
||||
}
|
||||
|
||||
typedef struct xer_tmp_enc_s {
|
||||
void *buffer;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
} xer_tmp_enc_t;
|
||||
static int
|
||||
SET_OF_encode_xer_callback(const void *buffer, size_t size, void *key) {
|
||||
xer_tmp_enc_t *t = (xer_tmp_enc_t *)key;
|
||||
if(t->offset + size >= t->size) {
|
||||
size_t newsize = (t->size << 2) + size;
|
||||
void *p = REALLOC(t->buffer, newsize);
|
||||
if(!p) return -1;
|
||||
t->buffer = p;
|
||||
t->size = newsize;
|
||||
}
|
||||
memcpy((char *)t->buffer + t->offset, buffer, size);
|
||||
t->offset += size;
|
||||
return 0;
|
||||
}
|
||||
static int
|
||||
SET_OF_xer_order(const void *aptr, const void *bptr) {
|
||||
const xer_tmp_enc_t *a = (const xer_tmp_enc_t *)aptr;
|
||||
const xer_tmp_enc_t *b = (const xer_tmp_enc_t *)bptr;
|
||||
size_t minlen = a->offset;
|
||||
int ret;
|
||||
if(b->offset < minlen) minlen = b->offset;
|
||||
/* Well-formed UTF-8 has this nice lexicographical property... */
|
||||
ret = memcmp(a->buffer, b->buffer, minlen);
|
||||
if(ret != 0) return ret;
|
||||
if(a->offset == b->offset)
|
||||
return 0;
|
||||
if(a->offset == minlen)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
asn_enc_rval_t
|
||||
SET_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
|
||||
int ilevel, enum xer_encoder_flags_e flags,
|
||||
|
@ -461,19 +499,36 @@ SET_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
|
|||
? 0 : ((*element->name) ? element->name : element->type->name);
|
||||
size_t mlen = mname ? strlen(mname) : 0;
|
||||
int xcan = (flags & XER_F_CANONICAL);
|
||||
xer_tmp_enc_t *encs = 0;
|
||||
size_t encs_count = 0;
|
||||
void *original_app_key = app_key;
|
||||
asn_app_consume_bytes_f *original_cb = cb;
|
||||
int i;
|
||||
|
||||
if(!sptr) _ASN_ENCODE_FAILED;
|
||||
|
||||
(void *)list = sptr;
|
||||
|
||||
if(xcan) {
|
||||
encs = (xer_tmp_enc_t *)MALLOC(list->count * sizeof(encs[0]));
|
||||
if(!encs) _ASN_ENCODE_FAILED;
|
||||
cb = SET_OF_encode_xer_callback;
|
||||
}
|
||||
|
||||
er.encoded = 0;
|
||||
|
||||
(void *)list = sptr;
|
||||
for(i = 0; i < list->count; i++) {
|
||||
asn_enc_rval_t tmper;
|
||||
|
||||
void *memb_ptr = list->array[i];
|
||||
if(!memb_ptr) continue;
|
||||
|
||||
if(encs) {
|
||||
memset(&encs[encs_count], 0, sizeof(encs[0]));
|
||||
app_key = &encs[encs_count];
|
||||
encs_count++;
|
||||
}
|
||||
|
||||
if(mname) {
|
||||
if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel);
|
||||
_ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
|
||||
|
@ -481,7 +536,11 @@ SET_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
|
|||
|
||||
tmper = element->type->xer_encoder(element->type, memb_ptr,
|
||||
ilevel + 1, flags, cb, app_key);
|
||||
if(tmper.encoded == -1) return tmper;
|
||||
if(tmper.encoded == -1) {
|
||||
td = tmper.failed_type;
|
||||
sptr = tmper.structure_ptr;
|
||||
goto cb_failed;
|
||||
}
|
||||
|
||||
if(mname) {
|
||||
_ASN_CALLBACK3("</", 2, mname, mlen, ">", 1);
|
||||
|
@ -493,6 +552,37 @@ SET_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
|
|||
|
||||
if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1);
|
||||
|
||||
if(encs) {
|
||||
xer_tmp_enc_t *enc = encs;
|
||||
xer_tmp_enc_t *end = encs + encs_count;
|
||||
ssize_t control_size = 0;
|
||||
|
||||
cb = original_cb;
|
||||
app_key = original_app_key;
|
||||
qsort(encs, encs_count, sizeof(encs[0]), SET_OF_xer_order);
|
||||
|
||||
for(; enc < end; enc++) {
|
||||
_ASN_CALLBACK(enc->buffer, enc->offset);
|
||||
FREEMEM(enc->buffer);
|
||||
enc->buffer = 0;
|
||||
control_size += enc->offset;
|
||||
}
|
||||
assert(control_size == er.encoded);
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
cb_failed:
|
||||
er.encoded = -1;
|
||||
er.failed_type = td;
|
||||
er.structure_ptr = sptr;
|
||||
cleanup:
|
||||
if(encs) {
|
||||
while(encs_count-- > 0) {
|
||||
if(encs[encs_count].buffer)
|
||||
FREEMEM(encs[encs_count].buffer);
|
||||
}
|
||||
free(encs);
|
||||
}
|
||||
return er;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue