SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / INTEGER_uper.c
diff --git a/e2sim/asn1c/INTEGER_uper.c b/e2sim/asn1c/INTEGER_uper.c
new file mode 100644 (file)
index 0000000..ed65385
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * 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 <INTEGER.h>
+
+asn_dec_rval_t
+INTEGER_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_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_dec_rval_t rval = { RC_OK, 0 };
+    INTEGER_t *st = (INTEGER_t *)*sptr;
+    const asn_per_constraint_t *ct;
+    int repeat;
+
+    (void)opt_codec_ctx;
+
+    if(!st) {
+        st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));
+        if(!st) ASN__DECODE_FAILED;
+    }
+
+    if(!constraints) constraints = td->encoding_constraints.per_constraints;
+    ct = constraints ? &constraints->value : 0;
+
+    if(ct && ct->flags & APC_EXTENSIBLE) {
+        int inext = per_get_few_bits(pd, 1);
+        if(inext < 0) ASN__DECODE_STARVED;
+        if(inext) ct = 0;
+    }
+
+    FREEMEM(st->buf);
+    st->buf = 0;
+    st->size = 0;
+    if(ct) {
+        if(ct->flags & APC_SEMI_CONSTRAINED) {
+            st->buf = (uint8_t *)CALLOC(1, 2);
+            if(!st->buf) ASN__DECODE_FAILED;
+            st->size = 1;
+        } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) {
+            size_t size = (ct->range_bits + 7) >> 3;
+            st->buf = (uint8_t *)MALLOC(1 + size + 1);
+            if(!st->buf) ASN__DECODE_FAILED;
+            st->size = size;
+        }
+    }
+
+    /* X.691-2008/11, #13.2.2, constrained whole number */
+    if(ct && ct->flags != APC_UNCONSTRAINED) {
+        /* #11.5.6 */
+        ASN_DEBUG("Integer with range %d bits", ct->range_bits);
+        if(ct->range_bits >= 0) {
+            if((size_t)ct->range_bits > 8 * sizeof(uintmax_t))
+                ASN__DECODE_FAILED;
+
+            if(specs && specs->field_unsigned) {
+                uintmax_t uvalue = 0;
+                if(uper_get_constrained_whole_number(pd,
+                    &uvalue, ct->range_bits))
+                    ASN__DECODE_STARVED;
+                ASN_DEBUG("Got value %lu + low %ld",
+                    uvalue, ct->lower_bound);
+                uvalue += ct->lower_bound;
+                if(asn_umax2INTEGER(st, uvalue))
+                    ASN__DECODE_FAILED;
+            } else {
+                uintmax_t uvalue = 0;
+                intmax_t svalue;
+                if(uper_get_constrained_whole_number(pd,
+                    &uvalue, ct->range_bits))
+                    ASN__DECODE_STARVED;
+                ASN_DEBUG("Got value %lu + low %ld",
+                uvalue, ct->lower_bound);
+                if(per_imax_range_unrebase(uvalue, ct->lower_bound,
+                                           ct->upper_bound, &svalue)
+                   || asn_imax2INTEGER(st, svalue)) {
+                    ASN__DECODE_FAILED;
+                }
+            }
+            return rval;
+        }
+    } else {
+        ASN_DEBUG("Decoding unconstrained integer %s", td->name);
+    }
+
+    /* X.691, #12.2.3, #12.2.4 */
+    do {
+        ssize_t len = 0;
+        void *p = NULL;
+        int ret = 0;
+
+        /* Get the PER length */
+        len = uper_get_length(pd, -1, 0, &repeat);
+        if(len < 0) ASN__DECODE_STARVED;
+
+        p = REALLOC(st->buf, st->size + len + 1);
+        if(!p) ASN__DECODE_FAILED;
+        st->buf = (uint8_t *)p;
+
+        ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len);
+        if(ret < 0) ASN__DECODE_STARVED;
+        st->size += len;
+    } while(repeat);
+    st->buf[st->size] = 0;  /* JIC */
+
+    /* #12.2.3 */
+    if(ct && ct->lower_bound) {
+        /*
+         * TODO: replace by in-place arithmetic.
+         */
+        long value = 0;
+        if(asn_INTEGER2long(st, &value))
+            ASN__DECODE_FAILED;
+        if(asn_imax2INTEGER(st, value + ct->lower_bound))
+            ASN__DECODE_FAILED;
+    }
+
+    return rval;
+}
+
+asn_enc_rval_t
+INTEGER_encode_uper(const asn_TYPE_descriptor_t *td,
+                    const asn_per_constraints_t *constraints, const void *sptr,
+                    asn_per_outp_t *po) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_enc_rval_t er = {0,0,0};
+    const INTEGER_t *st = (const INTEGER_t *)sptr;
+    const uint8_t *buf;
+    const uint8_t *end;
+    const asn_per_constraint_t *ct;
+    union {
+        intmax_t s;
+        uintmax_t u;
+    } value;
+
+    if(!st || st->size == 0) ASN__ENCODE_FAILED;
+
+    if(!constraints) constraints = td->encoding_constraints.per_constraints;
+    ct = constraints ? &constraints->value : 0;
+
+    er.encoded = 0;
+
+    if(ct) {
+        int inext = 0;
+        if(specs && specs->field_unsigned) {
+            if(asn_INTEGER2umax(st, &value.u))
+                ASN__ENCODE_FAILED;
+            /* Check proper range */
+            if(ct->flags & APC_SEMI_CONSTRAINED) {
+                if(value.u < (uintmax_t)ct->lower_bound)
+                    inext = 1;
+            } else if(ct->range_bits >= 0) {
+                if(value.u < (uintmax_t)ct->lower_bound
+                || value.u > (uintmax_t)ct->upper_bound)
+                    inext = 1;
+            }
+            ASN_DEBUG("Value %lu (%02x/%" ASN_PRI_SIZE ") lb %lu ub %lu %s",
+                      value.u, st->buf[0], st->size,
+                      ct->lower_bound, ct->upper_bound,
+                      inext ? "ext" : "fix");
+        } else {
+            if(asn_INTEGER2imax(st, &value.s))
+                ASN__ENCODE_FAILED;
+            /* Check proper range */
+            if(ct->flags & APC_SEMI_CONSTRAINED) {
+                if(value.s < ct->lower_bound)
+                    inext = 1;
+            } else if(ct->range_bits >= 0) {
+                if(value.s < ct->lower_bound
+                || value.s > ct->upper_bound)
+                    inext = 1;
+            }
+            ASN_DEBUG("Value %ld (%02x/%" ASN_PRI_SIZE ") lb %ld ub %ld %s",
+                      value.s, st->buf[0], st->size,
+                      ct->lower_bound, ct->upper_bound,
+                      inext ? "ext" : "fix");
+        }
+        if(ct->flags & APC_EXTENSIBLE) {
+            if(per_put_few_bits(po, inext, 1))
+                ASN__ENCODE_FAILED;
+            if(inext) ct = 0;
+        } else if(inext) {
+            ASN__ENCODE_FAILED;
+        }
+    }
+
+    /* X.691-11/2008, #13.2.2, test if constrained whole number */
+    if(ct && ct->range_bits >= 0) {
+        uintmax_t v;
+        /* #11.5.6 -> #11.3 */
+        if(specs && specs->field_unsigned) {
+            if(((uintmax_t)ct->lower_bound > (uintmax_t)(ct->upper_bound)
+            || (value.u < (uintmax_t)ct->lower_bound))
+            || (value.u > (uintmax_t)ct->upper_bound)) {
+                ASN_DEBUG("Value %lu to-be-encoded is outside the bounds [%lu, %lu]!",
+                          value.u, ct->lower_bound, ct->upper_bound);
+                ASN__ENCODE_FAILED;
+            }
+            v = value.u - (uintmax_t)ct->lower_bound;
+        } else {
+            if(per_imax_range_rebase(value.s, ct->lower_bound, ct->upper_bound, &v)) {
+                ASN__ENCODE_FAILED;
+            }
+        }
+        ASN_DEBUG("Encoding integer %lu with range %d bits",
+                  v, ct->range_bits);
+        if(uper_put_constrained_whole_number_u(po, v, ct->range_bits))
+            ASN__ENCODE_FAILED;
+        ASN__ENCODED_OK(er);
+    }
+
+    if(ct && ct->lower_bound) {
+        ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound);
+        /* TODO: adjust lower bound */
+        ASN__ENCODE_FAILED;
+    }
+
+    for(buf = st->buf, end = st->buf + st->size; buf < end;) {
+        int need_eom = 0;
+        ssize_t mayEncode = uper_put_length(po, end - buf, &need_eom);
+        if(mayEncode < 0)
+            ASN__ENCODE_FAILED;
+        if(per_put_many_bits(po, buf, 8 * mayEncode))
+            ASN__ENCODE_FAILED;
+        buf += mayEncode;
+        if(need_eom && uper_put_length(po, 0, 0)) ASN__ENCODE_FAILED;
+    }
+
+    ASN__ENCODED_OK(er);
+}