osmo-cbc/src/sbcap/gen/constr_SET_OF.c

430 lines
11 KiB
C

/*
* Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>.
* All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
#include <asn_internal.h>
#include <constr_SET_OF.h>
asn_TYPE_operation_t asn_OP_SET_OF = {
SET_OF_free,
#if !defined(ASN_DISABLE_PRINT_SUPPORT)
SET_OF_print,
#else
0,
#endif /* !defined(ASN_DISABLE_PRINT_SUPPORT) */
SET_OF_compare,
SET_OF_copy,
#if !defined(ASN_DISABLE_BER_SUPPORT)
SET_OF_decode_ber,
SET_OF_encode_der,
#else
0,
0,
#endif /* !defined(ASN_DISABLE_BER_SUPPORT) */
#if !defined(ASN_DISABLE_XER_SUPPORT)
SET_OF_decode_xer,
SET_OF_encode_xer,
#else
0,
0,
#endif /* !defined(ASN_DISABLE_XER_SUPPORT) */
#if !defined(ASN_DISABLE_JER_SUPPORT)
SET_OF_decode_jer,
SET_OF_encode_jer,
#else
0,
0,
#endif /* !defined(ASN_DISABLE_JER_SUPPORT) */
#if !defined(ASN_DISABLE_OER_SUPPORT)
SET_OF_decode_oer,
SET_OF_encode_oer,
#else
0,
0,
#endif /* !defined(ASN_DISABLE_OER_SUPPORT) */
#if !defined(ASN_DISABLE_UPER_SUPPORT)
SET_OF_decode_uper,
SET_OF_encode_uper,
#else
0,
0,
#endif /* !defined(ASN_DISABLE_UPER_SUPPORT) */
#if !defined(ASN_DISABLE_APER_SUPPORT)
SET_OF_decode_aper,
SET_OF_encode_aper,
#else
0,
0,
#endif /* !defined(ASN_DISABLE_APER_SUPPORT) */
#if !defined(ASN_DISABLE_RFILL_SUPPORT)
SET_OF_random_fill,
#else
0,
#endif /* !defined(ASN_DISABLE_RFILL_SUPPORT) */
0 /* Use generic outmost tag fetcher */
};
/* 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;
if(el_buf->length + size > el_buf->allocated_size) {
size_t new_size = el_buf->allocated_size ? el_buf->allocated_size : 8;
void *p;
do {
new_size <<= 2;
} while(el_buf->length + size > new_size);
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 void assert_unused_bits(const struct _el_buffer* p) {
if(p->length) {
assert((p->buf[p->length-1] & ~(0xff << p->bits_unused)) == 0);
} else {
assert(p->bits_unused == 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;
size_t common_len;
int ret = 0;
if(a->length < b->length)
common_len = a->length;
else
common_len = b->length;
if (a->buf && b->buf) {
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. */
assert_unused_bits(a);
assert_unused_bits(b);
}
return ret;
}
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);
}
struct _el_buffer *
SET_OF__encode_sorted(const asn_TYPE_member_t *elm,
const asn_anonymous_set_ *list,
enum SET_OF__encode_method method) {
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 *encoding_el = &encoded_els[edx];
asn_enc_rval_t erval = {0,0,0};
if(!memb_ptr) break;
/*
* Encode the member into the prepared space.
*/
switch(method) {
#if !defined(ASN_DISABLE_BER_SUPPORT)
case SOES_DER:
erval = elm->type->op->der_encoder(elm->type, memb_ptr, 0, elm->tag,
_el_addbytes, encoding_el);
break;
#endif /* !defined(ASN_DISABLE_BER_SUPPORT) */
#if !defined(ASN_DISABLE_UPER_SUPPORT)
case SOES_CUPER:
erval = uper_encode(elm->type,
elm->encoding_constraints.per_constraints,
memb_ptr, _el_addbytes, encoding_el);
if(erval.encoded != -1) {
size_t extra_bits = erval.encoded % 8;
assert(encoding_el->length == (size_t)(erval.encoded + 7) / 8);
encoding_el->bits_unused = (8 - extra_bits) & 0x7;
}
break;
#endif /* !defined(ASN_DISABLE_UPER_SUPPORT) */
#if !defined(ASN_DISABLE_APER_SUPPORT)
case SOES_CAPER:
erval = aper_encode(elm->type,
elm->encoding_constraints.per_constraints,
memb_ptr, _el_addbytes, encoding_el);
if(erval.encoded != -1) {
size_t extra_bits = erval.encoded % 8;
assert(encoding_el->length == (size_t)(erval.encoded + 7) / 8);
encoding_el->bits_unused = (8 - extra_bits) & 0x7;
}
break;
#endif /* !defined(ASN_DISABLE_APER_SUPPORT) */
default:
assert(!"Unreachable");
break;
}
if(erval.encoded < 0) break;
}
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;
}
}
void
SET_OF_free(const asn_TYPE_descriptor_t *td, void *ptr,
enum asn_struct_free_method method) {
if(td && ptr) {
const asn_SET_OF_specifics_t *specs;
asn_TYPE_member_t *elm = td->elements;
asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr);
asn_struct_ctx_t *ctx; /* Decoder context */
int i;
/*
* Could not use set_of_empty() because of (*free)
* incompatibility.
*/
for(i = 0; i < list->count; i++) {
void *memb_ptr = list->array[i];
if(memb_ptr)
ASN_STRUCT_FREE(*elm->type, memb_ptr);
}
list->count = 0; /* No meaningful elements left */
asn_set_empty(list); /* Remove (list->array) */
specs = (const asn_SET_OF_specifics_t *)td->specifics;
ctx = (asn_struct_ctx_t *)((char *)ptr + specs->ctx_offset);
if(ctx->ptr) {
ASN_STRUCT_FREE(*elm->type, ctx->ptr);
ctx->ptr = 0;
}
switch(method) {
case ASFM_FREE_EVERYTHING:
FREEMEM(ptr);
break;
case ASFM_FREE_UNDERLYING:
break;
case ASFM_FREE_UNDERLYING_AND_RESET:
memset(ptr, 0, specs->struct_size);
break;
}
}
}
int
SET_OF_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
asn_app_constraint_failed_f *ctfailcb, void *app_key) {
const asn_TYPE_member_t *elm = td->elements;
asn_constr_check_f *constr;
const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr);
int i;
if(!sptr) {
ASN__CTFAIL(app_key, td, sptr,
"%s: value not given (%s:%d)",
td->name, __FILE__, __LINE__);
return -1;
}
constr = elm->encoding_constraints.general_constraints;
if(!constr) constr = elm->type->encoding_constraints.general_constraints;
/*
* Iterate over the members of an array.
* Validate each in turn, until one fails.
*/
for(i = 0; i < list->count; i++) {
const void *memb_ptr = list->array[i];
int ret;
if(!memb_ptr) continue;
ret = constr(elm->type, memb_ptr, ctfailcb, app_key);
if(ret) return ret;
}
return 0;
}
struct comparable_ptr {
const asn_TYPE_descriptor_t *td;
const void *sptr;
};
static int
SET_OF__compare_cb(const void *aptr, const void *bptr) {
const struct comparable_ptr *a = aptr;
const struct comparable_ptr *b = bptr;
assert(a->td == b->td);
return a->td->op->compare_struct(a->td, a->sptr, b->sptr);
}
int
SET_OF_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
const void *bptr) {
const asn_anonymous_set_ *a = _A_CSET_FROM_VOID(aptr);
const asn_anonymous_set_ *b = _A_CSET_FROM_VOID(bptr);
if(a && b) {
struct comparable_ptr *asorted;
struct comparable_ptr *bsorted;
ssize_t common_length;
ssize_t idx;
if(a->count == 0) {
if(b->count) return -1;
return 0;
} else if(b->count == 0) {
return 1;
}
asorted = MALLOC(a->count * sizeof(asorted[0]));
bsorted = MALLOC(b->count * sizeof(bsorted[0]));
if(!asorted || !bsorted) {
FREEMEM(asorted);
FREEMEM(bsorted);
return -1;
}
for(idx = 0; idx < a->count; idx++) {
asorted[idx].td = td->elements->type;
asorted[idx].sptr = a->array[idx];
}
for(idx = 0; idx < b->count; idx++) {
bsorted[idx].td = td->elements->type;
bsorted[idx].sptr = b->array[idx];
}
qsort(asorted, a->count, sizeof(asorted[0]), SET_OF__compare_cb);
qsort(bsorted, b->count, sizeof(bsorted[0]), SET_OF__compare_cb);
common_length = (a->count < b->count ? a->count : b->count);
for(idx = 0; idx < common_length; idx++) {
int ret = td->elements->type->op->compare_struct(
td->elements->type, asorted[idx].sptr, bsorted[idx].sptr);
if(ret) {
FREEMEM(asorted);
FREEMEM(bsorted);
return ret;
}
}
FREEMEM(asorted);
FREEMEM(bsorted);
if(idx < b->count) /* more elements in b */
return -1; /* a is shorter, so put it first */
if(idx < a->count) return 1;
} else if(!a) {
return -1;
} else if(!b) {
return 1;
}
return 0;
}
int
SET_OF_copy(const asn_TYPE_descriptor_t *td, void **aptr,
const void *bptr) {
if(!td) return -1;
const asn_SET_OF_specifics_t *specs =
(const asn_SET_OF_specifics_t *)td->specifics;
void *st = *aptr;
if(!bptr) {
if(*aptr) {
asn_set_empty(_A_SET_FROM_VOID(*aptr));
*aptr = 0;
}
return 0;
}
if(st == 0) {
st = *aptr = CALLOC(1, specs->struct_size);
if(st == 0) return -1;
}
asn_anonymous_set_ *a = _A_SET_FROM_VOID(*aptr);
const asn_anonymous_set_ *b = _A_CSET_FROM_VOID(bptr);
if(b->size) {
void *_new_arr;
_new_arr = REALLOC(a->array, b->size * sizeof(b->array[0]));
if(_new_arr) {
a->array = (void **)_new_arr;
a->size = b->size;
} else {
return -1;
}
a->count = b->count;
for(int i = 0; i < b->count; i++) {
void *bmemb = b->array[i];
if(bmemb) {
void *amemb = 0;
int ret;
ret = td->elements->type->op->copy_struct(
td->elements->type,
&amemb, bmemb);
if(ret != 0) return ret;
a->array[i] = amemb;
} else {
a->array[i] = 0;
}
}
}
return 0;
}