SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / constr_CHOICE_uper.c
diff --git a/e2sim/asn1c/constr_CHOICE_uper.c b/e2sim/asn1c/constr_CHOICE_uper.c
new file mode 100644 (file)
index 0000000..77aab6d
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <constr_CHOICE.h>
+#include <uper_opentype.h>
+
+asn_dec_rval_t
+CHOICE_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
+                   const asn_TYPE_descriptor_t *td,
+                   const asn_per_constraints_t *constraints, void **sptr,
+                   asn_per_data_t *pd) {
+    const asn_CHOICE_specifics_t *specs =
+        (const asn_CHOICE_specifics_t *)td->specifics;
+    asn_dec_rval_t rv;
+    const asn_per_constraint_t *ct;
+    asn_TYPE_member_t *elm;  /* CHOICE's element */
+    void *memb_ptr;
+    void **memb_ptr2;
+    void *st = *sptr;
+    int value;
+
+    if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
+        ASN__DECODE_FAILED;
+
+    /*
+     * Create the target structure if it is not present already.
+     */
+    if(!st) {
+        st = *sptr = CALLOC(1, specs->struct_size);
+        if(!st) ASN__DECODE_FAILED;
+    }
+
+    if(constraints) ct = &constraints->value;
+    else if(td->encoding_constraints.per_constraints) ct = &td->encoding_constraints.per_constraints->value;
+    else ct = 0;
+
+    if(ct && ct->flags & APC_EXTENSIBLE) {
+        value = per_get_few_bits(pd, 1);
+        if(value < 0) ASN__DECODE_STARVED;
+        if(value) ct = 0;  /* Not restricted */
+    }
+
+    if(ct && ct->range_bits >= 0) {
+        value = per_get_few_bits(pd, ct->range_bits);
+        if(value < 0) ASN__DECODE_STARVED;
+        ASN_DEBUG("CHOICE %s got index %d in range %d",
+                  td->name, value, ct->range_bits);
+        if(value > ct->upper_bound)
+            ASN__DECODE_FAILED;
+    } else {
+        if(specs->ext_start == -1)
+            ASN__DECODE_FAILED;
+        value = uper_get_nsnnwn(pd);
+        if(value < 0) ASN__DECODE_STARVED;
+        value += specs->ext_start;
+        if((unsigned)value >= td->elements_count)
+            ASN__DECODE_FAILED;
+    }
+
+    /* Adjust if canonical order is different from natural order */
+    if(specs->from_canonical_order) {
+        ASN_DEBUG("CHOICE presence from wire %d", value);
+        value = specs->from_canonical_order[value];
+        ASN_DEBUG("CHOICE presence index effective %d", value);
+    }
+
+    /* Set presence to be able to free it later */
+    _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1);
+
+    elm = &td->elements[value];
+    if(elm->flags & ATF_POINTER) {
+        /* Member is a pointer to another structure */
+        memb_ptr2 = (void **)((char *)st + elm->memb_offset);
+    } else {
+        memb_ptr = (char *)st + elm->memb_offset;
+        memb_ptr2 = &memb_ptr;
+    }
+    ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name);
+
+    if(ct && ct->range_bits >= 0) {
+        rv = elm->type->op->uper_decoder(opt_codec_ctx, elm->type,
+                                         elm->encoding_constraints.per_constraints,
+                                         memb_ptr2, pd);
+    } else {
+        rv = uper_open_type_get(opt_codec_ctx, elm->type,
+                                elm->encoding_constraints.per_constraints,
+                                memb_ptr2, pd);
+    }
+
+    if(rv.code != RC_OK)
+        ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d",
+                  elm->name, td->name, rv.code);
+    return rv;
+}
+
+asn_enc_rval_t
+CHOICE_encode_uper(const asn_TYPE_descriptor_t *td,
+                   const asn_per_constraints_t *constraints, const void *sptr,
+                   asn_per_outp_t *po) {
+    const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
+    asn_TYPE_member_t *elm;  /* CHOICE's element */
+    const asn_per_constraint_t *ct;
+    const void *memb_ptr;
+    unsigned present;
+    int present_enc;
+
+    if(!sptr) ASN__ENCODE_FAILED;
+
+    ASN_DEBUG("Encoding %s as CHOICE", td->name);
+
+    if(constraints) ct = &constraints->value;
+    else if(td->encoding_constraints.per_constraints)
+        ct = &td->encoding_constraints.per_constraints->value;
+    else ct = 0;
+
+    present = _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
+
+    /*
+     * If the structure was not initialized properly, it cannot be encoded:
+     * can't deduce what to encode in the choice type.
+     */
+    if(present == 0 || present > td->elements_count)
+        ASN__ENCODE_FAILED;
+    else
+        present--;
+
+    ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present);
+
+    /* Adjust if canonical order is different from natural order */
+    if(specs->to_canonical_order)
+        present_enc = specs->to_canonical_order[present];
+    else
+        present_enc = present;
+
+    if(ct && ct->range_bits >= 0) {
+        if(present_enc < ct->lower_bound
+        || present_enc > ct->upper_bound) {
+            if(ct->flags & APC_EXTENSIBLE) {
+                ASN_DEBUG(
+                    "CHOICE member %d (enc %d) is an extension (%ld..%ld)",
+                    present, present_enc, ct->lower_bound, ct->upper_bound);
+                if(per_put_few_bits(po, 1, 1))
+                    ASN__ENCODE_FAILED;
+            } else {
+                ASN__ENCODE_FAILED;
+            }
+            ct = 0;
+        }
+    }
+    if(ct && ct->flags & APC_EXTENSIBLE) {
+        ASN_DEBUG("CHOICE member %d (enc %d) is not an extension (%ld..%ld)",
+                  present, present_enc, ct->lower_bound, ct->upper_bound);
+        if(per_put_few_bits(po, 0, 1))
+            ASN__ENCODE_FAILED;
+    }
+
+
+    elm = &td->elements[present];
+    ASN_DEBUG("CHOICE member \"%s\" %d (as %d)", elm->name, present,
+              present_enc);
+    if(elm->flags & ATF_POINTER) {
+        /* Member is a pointer to another structure */
+        memb_ptr =
+            *(const void *const *)((const char *)sptr + elm->memb_offset);
+        if(!memb_ptr) ASN__ENCODE_FAILED;
+    } else {
+        memb_ptr = (const char *)sptr + elm->memb_offset;
+    }
+
+    if(ct && ct->range_bits >= 0) {
+        if(per_put_few_bits(po, present_enc, ct->range_bits))
+            ASN__ENCODE_FAILED;
+
+        return elm->type->op->uper_encoder(
+            elm->type, elm->encoding_constraints.per_constraints, memb_ptr, po);
+    } else {
+        asn_enc_rval_t rval = {0,0,0};
+        if(specs->ext_start == -1) ASN__ENCODE_FAILED;
+        if(uper_put_nsnnwn(po, present_enc - specs->ext_start))
+            ASN__ENCODE_FAILED;
+        if(uper_open_type_put(elm->type,
+                              elm->encoding_constraints.per_constraints,
+                              memb_ptr, po))
+            ASN__ENCODE_FAILED;
+        rval.encoded = 0;
+        ASN__ENCODED_OK(rval);
+    }
+}