SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / constr_SEQUENCE_xer.c
diff --git a/e2sim/asn1c/constr_SEQUENCE_xer.c b/e2sim/asn1c/constr_SEQUENCE_xer.c
new file mode 100644 (file)
index 0000000..c6475f7
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * 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_SEQUENCE.h>
+#include <OPEN_TYPE.h>
+
+/*
+ * Return a standardized complex structure.
+ */
+#undef RETURN
+#define RETURN(_code)                     \
+    do {                                  \
+        rval.code = _code;                \
+        rval.consumed = consumed_myself;  \
+        return rval;                      \
+    } while(0)
+
+/*
+ * Check whether we are inside the extensions group.
+ */
+#define IN_EXTENSION_GROUP(specs, memb_idx)                \
+    ((specs)->first_extension >= 0                         \
+     && (unsigned)(specs)->first_extension <= (memb_idx))
+
+#undef XER_ADVANCE
+#define XER_ADVANCE(num_bytes)            \
+    do {                                  \
+        size_t num = (num_bytes);         \
+        ptr = ((const char *)ptr) + num;  \
+        size -= num;                      \
+        consumed_myself += num;           \
+    } while(0)
+
+/*
+ * Decode the XER (XML) data.
+ */
+asn_dec_rval_t
+SEQUENCE_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
+                    const asn_TYPE_descriptor_t *td, void **struct_ptr,
+                    const char *opt_mname, const void *ptr, size_t size) {
+    /*
+     * Bring closer parts of structure description.
+     */
+    const asn_SEQUENCE_specifics_t *specs
+        = (const asn_SEQUENCE_specifics_t *)td->specifics;
+    asn_TYPE_member_t *elements = td->elements;
+    const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
+
+    /*
+     * ... and parts of the structure being constructed.
+     */
+    void *st = *struct_ptr;  /* Target structure. */
+    asn_struct_ctx_t *ctx;   /* Decoder context */
+
+    asn_dec_rval_t rval;          /* Return value from a decoder */
+    ssize_t consumed_myself = 0;  /* Consumed bytes from ptr */
+    size_t edx;                   /* Element index */
+
+    /*
+     * Create the target structure if it is not present already.
+     */
+    if(st == 0) {
+        st = *struct_ptr = CALLOC(1, specs->struct_size);
+        if(st == 0) RETURN(RC_FAIL);
+    }
+
+    /*
+     * Restore parsing context.
+     */
+    ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
+
+
+    /*
+     * Phases of XER/XML processing:
+     * Phase 0: Check that the opening tag matches our expectations.
+     * Phase 1: Processing body and reacting on closing tag.
+     * Phase 2: Processing inner type.
+     * Phase 3: Skipping unknown extensions.
+     * Phase 4: PHASED OUT
+     */
+    for(edx = ctx->step; ctx->phase <= 3;) {
+        pxer_chunk_type_e ch_type;  /* XER chunk type */
+        ssize_t ch_size;            /* Chunk size */
+        xer_check_tag_e tcv;        /* Tag check value */
+        asn_TYPE_member_t *elm;
+
+        /*
+         * Go inside the inner member of a sequence.
+         */
+        if(ctx->phase == 2) {
+            asn_dec_rval_t tmprval;
+            void *memb_ptr_dontuse;  /* Pointer to the member */
+            void **memb_ptr2;        /* Pointer to that pointer */
+
+            elm = &td->elements[edx];
+
+            if(elm->flags & ATF_POINTER) {
+                /* Member is a pointer to another structure */
+                memb_ptr2 = (void **)((char *)st + elm->memb_offset);
+            } else {
+                memb_ptr_dontuse = (char *)st + elm->memb_offset;
+                memb_ptr2 = &memb_ptr_dontuse;  /* Only use of memb_ptr_dontuse */
+            }
+
+            if(elm->flags & ATF_OPEN_TYPE) {
+                tmprval = OPEN_TYPE_xer_get(opt_codec_ctx, td, st, elm, ptr, size);
+            } else {
+                /* Invoke the inner type decoder, m.b. multiple times */
+                tmprval = elm->type->op->xer_decoder(opt_codec_ctx,
+                                                     elm->type, memb_ptr2, elm->name,
+                                                     ptr, size);
+            }
+            XER_ADVANCE(tmprval.consumed);
+            if(tmprval.code != RC_OK)
+                RETURN(tmprval.code);
+            ctx->phase = 1;  /* Back to body processing */
+            ctx->step = ++edx;
+            ASN_DEBUG("XER/SEQUENCE phase => %d, step => %d",
+                ctx->phase, ctx->step);
+            /* Fall through */
+        }
+
+        /*
+         * Get the next part of the XML stream.
+         */
+        ch_size = xer_next_token(&ctx->context, ptr, size,
+            &ch_type);
+        if(ch_size == -1) {
+            RETURN(RC_FAIL);
+        } else {
+            switch(ch_type) {
+            case PXER_WMORE:
+                RETURN(RC_WMORE);
+            case PXER_COMMENT:  /* Got XML comment */
+            case PXER_TEXT:  /* Ignore free-standing text */
+                XER_ADVANCE(ch_size);  /* Skip silently */
+                continue;
+            case PXER_TAG:
+                break;  /* Check the rest down there */
+            }
+        }
+
+        tcv = xer_check_tag(ptr, ch_size, xml_tag);
+        ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d [%s]",
+                  tcv, ctx->phase, xml_tag);
+
+        /* Skip the extensions section */
+        if(ctx->phase == 3) {
+            switch(xer_skip_unknown(tcv, &ctx->left)) {
+            case -1:
+                ctx->phase = 4;
+                RETURN(RC_FAIL);
+            case 0:
+                XER_ADVANCE(ch_size);
+                continue;
+            case 1:
+                XER_ADVANCE(ch_size);
+                ctx->phase = 1;
+                continue;
+            case 2:
+                ctx->phase = 1;
+                break;
+            }
+        }
+
+        switch(tcv) {
+        case XCT_CLOSING:
+            if(ctx->phase == 0) break;
+            ctx->phase = 0;
+            /* Fall through */
+        case XCT_BOTH:
+            if(ctx->phase == 0) {
+                if(edx >= td->elements_count ||
+                   /* Explicit OPTIONAL specs reaches the end */
+                   (edx + elements[edx].optional == td->elements_count) ||
+                   /* All extensions are optional */
+                   IN_EXTENSION_GROUP(specs, edx)) {
+                    XER_ADVANCE(ch_size);
+                    ctx->phase = 4;  /* Phase out */
+                    RETURN(RC_OK);
+                } else {
+                    ASN_DEBUG("Premature end of XER SEQUENCE");
+                    RETURN(RC_FAIL);
+                }
+            }
+            /* Fall through */
+        case XCT_OPENING:
+            if(ctx->phase == 0) {
+                XER_ADVANCE(ch_size);
+                ctx->phase = 1;  /* Processing body phase */
+                continue;
+            }
+            /* Fall through */
+        case XCT_UNKNOWN_OP:
+        case XCT_UNKNOWN_BO:
+
+            ASN_DEBUG("XER/SEQUENCE: tcv=%d, ph=%d, edx=%" ASN_PRI_SIZE "",
+                      tcv, ctx->phase, edx);
+            if(ctx->phase != 1) {
+                break;  /* Really unexpected */
+            }
+
+            if(edx < td->elements_count) {
+                /*
+                 * Search which member corresponds to this tag.
+                 */
+                size_t n;
+                size_t edx_end = edx + elements[edx].optional + 1;
+                if(edx_end > td->elements_count)
+                    edx_end = td->elements_count;
+                for(n = edx; n < edx_end; n++) {
+                    elm = &td->elements[n];
+                    tcv = xer_check_tag(ptr, ch_size, elm->name);
+                    switch(tcv) {
+                    case XCT_BOTH:
+                    case XCT_OPENING:
+                        /*
+                         * Process this member.
+                         */
+                        ctx->step = edx = n;
+                        ctx->phase = 2;
+                        break;
+                    case XCT_UNKNOWN_OP:
+                    case XCT_UNKNOWN_BO:
+                        continue;
+                    default:
+                        n = edx_end;
+                        break;  /* Phase out */
+                    }
+                    break;
+                }
+                if(n != edx_end)
+                    continue;
+            } else {
+                ASN_DEBUG("Out of defined members: %" ASN_PRI_SIZE "/%u",
+                          edx, td->elements_count);
+            }
+
+            /* It is expected extension */
+            if(IN_EXTENSION_GROUP(specs,
+                edx + (edx < td->elements_count
+                    ? elements[edx].optional : 0))) {
+                ASN_DEBUG("Got anticipated extension at %" ASN_PRI_SIZE "",
+                          edx);
+                /*
+                 * Check for (XCT_BOTH or XCT_UNKNOWN_BO)
+                 * By using a mask. Only record a pure
+                 * <opening> tags.
+                 */
+                if(tcv & XCT_CLOSING) {
+                    /* Found </extension> without body */
+                } else {
+                    ctx->left = 1;
+                    ctx->phase = 3;  /* Skip ...'s */
+                }
+                XER_ADVANCE(ch_size);
+                continue;
+            }
+
+            /* Fall through */
+        default:
+            break;
+        }
+
+        ASN_DEBUG("Unexpected XML tag in SEQUENCE [%c%c%c%c%c%c]",
+                  size>0?((const char *)ptr)[0]:'.',
+                  size>1?((const char *)ptr)[1]:'.',
+                  size>2?((const char *)ptr)[2]:'.',
+                  size>3?((const char *)ptr)[3]:'.',
+                  size>4?((const char *)ptr)[4]:'.',
+                  size>5?((const char *)ptr)[5]:'.');
+        break;
+    }
+
+    ctx->phase = 4;  /* "Phase out" on hard failure */
+    RETURN(RC_FAIL);
+}
+
+asn_enc_rval_t
+SEQUENCE_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
+                    int ilevel, enum xer_encoder_flags_e flags,
+                    asn_app_consume_bytes_f *cb, void *app_key) {
+    asn_enc_rval_t er = {0,0,0};
+    int xcan = (flags & XER_F_CANONICAL);
+    asn_TYPE_descriptor_t *tmp_def_val_td = 0;
+    void *tmp_def_val = 0;
+    size_t edx;
+
+    if(!sptr) ASN__ENCODE_FAILED;
+
+    er.encoded = 0;
+
+    for(edx = 0; edx < td->elements_count; edx++) {
+        asn_enc_rval_t tmper = {0,0,0};
+        asn_TYPE_member_t *elm = &td->elements[edx];
+        const void *memb_ptr;
+        const char *mname = elm->name;
+        unsigned int mlen = strlen(mname);
+
+        if(elm->flags & ATF_POINTER) {
+            memb_ptr =
+                *(const void *const *)((const char *)sptr + elm->memb_offset);
+            if(!memb_ptr) {
+                assert(tmp_def_val == 0);
+                if(elm->default_value_set) {
+                    if(elm->default_value_set(&tmp_def_val)) {
+                        ASN__ENCODE_FAILED;
+                    } else {
+                        memb_ptr = tmp_def_val;
+                        tmp_def_val_td = elm->type;
+                    }
+                } else if(elm->optional) {
+                    continue;
+                } else {
+                    /* Mandatory element is missing */
+                    ASN__ENCODE_FAILED;
+                }
+            }
+        } else {
+            memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
+        }
+
+        if(!xcan) ASN__TEXT_INDENT(1, ilevel);
+        ASN__CALLBACK3("<", 1, mname, mlen, ">", 1);
+
+        /* Print the member itself */
+        tmper = elm->type->op->xer_encoder(elm->type, memb_ptr, ilevel + 1,
+                                           flags, cb, app_key);
+        if(tmp_def_val) {
+            ASN_STRUCT_FREE(*tmp_def_val_td, tmp_def_val);
+            tmp_def_val = 0;
+        }
+        if(tmper.encoded == -1) return tmper;
+        er.encoded += tmper.encoded;
+
+        ASN__CALLBACK3("</", 2, mname, mlen, ">", 1);
+    }
+
+    if(!xcan) ASN__TEXT_INDENT(1, ilevel - 1);
+
+    ASN__ENCODED_OK(er);
+cb_failed:
+    if(tmp_def_val) ASN_STRUCT_FREE(*tmp_def_val_td, tmp_def_val);
+    ASN__ENCODE_FAILED;
+}