text: /*
   * 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 <OPEN_TYPE.h>
  #include <constr_CHOICE.h>
  #include <per_opentype.h>
  #include <errno.h>
  
  asn_TYPE_operation_t asn_OP_OPEN_TYPE = {
      OPEN_TYPE_free,
      OPEN_TYPE_print,
      OPEN_TYPE_compare,
      OPEN_TYPE_decode_ber,
      OPEN_TYPE_encode_der,
      OPEN_TYPE_decode_xer,
      OPEN_TYPE_encode_xer,
  #ifdef ASN_DISABLE_OER_SUPPORT
      0,
      0, /* No OER support, use "-gen-OER" to enable */
  #else
      OPEN_TYPE_decode_oer,
      OPEN_TYPE_encode_oer,
  #endif
  #ifdef ASN_DISABLE_PER_SUPPORT
      0,
      0,
      0,
      0,
  #else
      OPEN_TYPE_decode_uper,
      OPEN_TYPE_encode_uper,
      OPEN_TYPE_decode_aper,
      OPEN_TYPE_encode_aper,
  #endif
      0, /* Random fill is not supported for open type */
      0  /* Use generic outmost tag fetcher */
  };
  
  #undef ADVANCE
  #define ADVANCE(num_bytes)                                                     \
    do {                                                                         \
      size_t num = num_bytes;                                                    \
      ptr        = ((const char*) ptr) + num;                                    \
      size -= num;                                                               \
      consumed_myself += num;                                                    \
    } while (0)
  
  asn_dec_rval_t OPEN_TYPE_ber_get(
      const asn_codec_ctx_t* opt_codec_ctx, const asn_TYPE_descriptor_t* td,
      void* sptr, const asn_TYPE_member_t* elm, const void* ptr, size_t size) {
    size_t consumed_myself = 0;
    asn_type_selector_result_t selected;
    void* memb_ptr;   /* Pointer to the member */
    void** memb_ptr2; /* Pointer to that pointer */
    void* inner_value;
    asn_dec_rval_t rv;
  
    if (!(elm->flags & ATF_OPEN_TYPE)) {
      ASN__DECODE_FAILED;
    }
  
    if (!elm->type_selector) {
      ASN_DEBUG(
          "Type selector is not defined for Open Type %s->%s->%s", td->name,
          elm->name, elm->type->name);
      ASN__DECODE_FAILED;
    }
  
    selected = elm->type_selector(td, sptr);
    if (!selected.presence_index) {
      ASN__DECODE_FAILED;
    }
  
    /* Fetch the pointer to this member */
    if (elm->flags & ATF_POINTER) {
      memb_ptr2 = (void**) ((char*) sptr + elm->memb_offset);
    } else {
      memb_ptr  = (char*) sptr + elm->memb_offset;
      memb_ptr2 = &memb_ptr;
    }
    if (*memb_ptr2 != NULL) {
      /* Make sure we reset the structure first before encoding */
      if (CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0) != 0) {
        ASN__DECODE_FAILED;
      }
    }
  
    inner_value = (char*) *memb_ptr2 +
                  elm->type->elements[selected.presence_index - 1].memb_offset;
  
    ASN_DEBUG("presence %d\n", selected.presence_index);
  
    rv = selected.type_descriptor->op->ber_decoder(
        opt_codec_ctx, selected.type_descriptor, &inner_value, ptr, size,
        elm->tag_mode);
    ADVANCE(rv.consumed);
    rv.consumed = 0;
    switch (rv.code) {
      case RC_OK:
        if (CHOICE_variant_set_presence(
                elm->type, *memb_ptr2, selected.presence_index) == 0) {
          rv.code     = RC_OK;
          rv.consumed = consumed_myself;
          return rv;
        } else {
          /* Oh, now a full-blown failure failure */
        }
        /* Fall through */
      case RC_FAIL:
        rv.consumed = consumed_myself;
        /* Fall through */
      case RC_WMORE:
        break;
    }
  
    if (*memb_ptr2) {
      if (elm->flags & ATF_POINTER) {
        ASN_STRUCT_FREE(*selected.type_descriptor, inner_value);
        *memb_ptr2 = NULL;
      } else {
        ASN_STRUCT_RESET(*selected.type_descriptor, inner_value);
      }
    }
    return rv;
  }
  
  asn_dec_rval_t OPEN_TYPE_xer_get(
      const asn_codec_ctx_t* opt_codec_ctx, const asn_TYPE_descriptor_t* td,
      void* sptr, const asn_TYPE_member_t* elm, const void* ptr, size_t size) {
    size_t consumed_myself = 0;
    asn_type_selector_result_t selected;
    void* memb_ptr;   /* Pointer to the member */
    void** memb_ptr2; /* Pointer to that pointer */
    void* inner_value;
    asn_dec_rval_t rv;
  
    int xer_context = 0;
    ssize_t ch_size;
    pxer_chunk_type_e ch_type;
  
    if (!(elm->flags & ATF_OPEN_TYPE)) {
      ASN__DECODE_FAILED;
    }
  
    if (!elm->type_selector) {
      ASN_DEBUG(
          "Type selector is not defined for Open Type %s->%s->%s", td->name,
          elm->name, elm->type->name);
      ASN__DECODE_FAILED;
    }
  
    selected = elm->type_selector(td, sptr);
    if (!selected.presence_index) {
      ASN__DECODE_FAILED;
    }
  
    /* Fetch the pointer to this member */
    assert(elm->flags == ATF_OPEN_TYPE);
    if (elm->flags & ATF_POINTER) {
      memb_ptr2 = (void**) ((char*) sptr + elm->memb_offset);
    } else {
      memb_ptr  = (char*) sptr + elm->memb_offset;
      memb_ptr2 = &memb_ptr;
    }
    if (*memb_ptr2 != NULL) {
      /* Make sure we reset the structure first before encoding */
      if (CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0) != 0) {
        ASN__DECODE_FAILED;
      }
    }
  
    /*
     * Confirm wrapper.
     */
    for (;;) {
      ch_size = xer_next_token(&xer_context, ptr, size, &ch_type);
      if (ch_size < 0) {
        ASN__DECODE_FAILED;
      } else {
        switch (ch_type) {
          case PXER_WMORE:
            ASN__DECODE_STARVED;
          case PXER_COMMENT:
          case PXER_TEXT:
            ADVANCE(ch_size);
            continue;
          case PXER_TAG:
            break;
        }
        break;
      }
    }
  
    /*
     * Wrapper value confirmed.
     */
    switch (xer_check_tag(ptr, ch_size, elm->name)) {
      case XCT_OPENING:
        ADVANCE(ch_size);
        break;
      case XCT_BROKEN:
      default:
        ASN__DECODE_FAILED;
    }
  
    inner_value = (char*) *memb_ptr2 +
                  elm->type->elements[selected.presence_index - 1].memb_offset;
  
    rv = selected.type_descriptor->op->xer_decoder(
        opt_codec_ctx, selected.type_descriptor, &inner_value, NULL, ptr, size);
    ADVANCE(rv.consumed);
    rv.consumed = 0;
    switch (rv.code) {
      case RC_OK:
        if (CHOICE_variant_set_presence(
                elm->type, *memb_ptr2, selected.presence_index) == 0) {
          break;
        } else {
          rv.code = RC_FAIL;
        }
        /* Fall through */
      case RC_FAIL:
        /* Point to a best position where failure occurred */
        rv.consumed = consumed_myself;
        /* Fall through */
      case RC_WMORE:
        /* Wrt. rv.consumed==0:
         * In case a genuine RC_WMORE, the whole Open Type decoding
         * will have to be restarted.
         */
        if (*memb_ptr2) {
          if (elm->flags & ATF_POINTER) {
            ASN_STRUCT_FREE(*selected.type_descriptor, inner_value);
            *memb_ptr2 = NULL;
          } else {
            ASN_STRUCT_RESET(*selected.type_descriptor, inner_value);
          }
        }
        return rv;
    }
  
    /*
     * Finalize wrapper.
     */
    for (;;) {
      ch_size = xer_next_token(&xer_context, ptr, size, &ch_type);
      if (ch_size < 0) {
        ASN__DECODE_FAILED;
      } else {
        switch (ch_type) {
          case PXER_WMORE:
            ASN__DECODE_STARVED;
          case PXER_COMMENT:
          case PXER_TEXT:
            ADVANCE(ch_size);
            continue;
          case PXER_TAG:
            break;
        }
        break;
      }
    }
  
    /*
     * Wrapper value confirmed.
     */
    switch (xer_check_tag(ptr, ch_size, elm->name)) {
      case XCT_CLOSING:
        ADVANCE(ch_size);
        break;
      case XCT_BROKEN:
      default:
        ASN__DECODE_FAILED;
    }
  
    rv.consumed += consumed_myself;
  
    return rv;
  }
  
  #ifndef ASN_DISABLE_PER_SUPPORT
  
  asn_dec_rval_t OPEN_TYPE_uper_get(
      const asn_codec_ctx_t* opt_codec_ctx, const asn_TYPE_descriptor_t* td,
      void* sptr, const asn_TYPE_member_t* elm, asn_per_data_t* pd) {
    asn_type_selector_result_t selected;
    void* memb_ptr;   /* Pointer to the member */
    void** memb_ptr2; /* Pointer to that pointer */
    void* inner_value;
    asn_dec_rval_t rv;
  
    if (!(elm->flags & ATF_OPEN_TYPE)) {
      ASN__DECODE_FAILED;
    }
  
    if (!elm->type_selector) {
      ASN_DEBUG(
          "Type selector is not defined for Open Type %s->%s->%s", td->name,
          elm->name, elm->type->name);
      ASN__DECODE_FAILED;
    }
  
    selected = elm->type_selector(td, sptr);
    if (!selected.presence_index) {
      ASN__DECODE_FAILED;
    }
  
    /* Fetch the pointer to this member */
    assert(elm->flags == ATF_OPEN_TYPE);
    if (elm->flags & ATF_POINTER) {
      memb_ptr2 = (void**) ((char*) sptr + elm->memb_offset);
    } else {
      memb_ptr  = (char*) sptr + elm->memb_offset;
      memb_ptr2 = &memb_ptr;
    }
    if (*memb_ptr2 != NULL) {
      /* Make sure we reset the structure first before encoding */
      if (CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0) != 0) {
        ASN__DECODE_FAILED;
      }
    }
  
    inner_value = (char*) *memb_ptr2 +
                  elm->type->elements[selected.presence_index - 1].memb_offset;
  
    rv = uper_open_type_get(
        opt_codec_ctx, selected.type_descriptor, NULL, &inner_value, pd);
    switch (rv.code) {
      case RC_OK:
        if (CHOICE_variant_set_presence(
                elm->type, *memb_ptr2, selected.presence_index) == 0) {
          break;
        } else {
          rv.code = RC_FAIL;
        }
        /* Fall through */
      case RC_WMORE:
      case RC_FAIL:
        if (*memb_ptr2) {
          if (elm->flags & ATF_POINTER) {
            ASN_STRUCT_FREE(*selected.type_descriptor, inner_value);
            *memb_ptr2 = NULL;
          } else {
            ASN_STRUCT_RESET(*selected.type_descriptor, inner_value);
          }
        }
    }
    return rv;
  }
  
  asn_enc_rval_t OPEN_TYPE_encode_uper(
      const asn_TYPE_descriptor_t* td, const asn_per_constraints_t* constraints,
      const void* sptr, asn_per_outp_t* po) {
    const void* memb_ptr;   /* Pointer to the member */
    asn_TYPE_member_t* elm; /* CHOICE's element */
    asn_enc_rval_t er;
    unsigned present;
  
    (void) constraints;
  
    present = CHOICE_variant_get_presence(td, sptr);
    if (present == 0 || present > td->elements_count) {
      ASN__ENCODE_FAILED;
    } else {
      present--;
    }
  
    ASN_DEBUG("Encoding %s OPEN TYPE element %d", td->name, present);
  
    elm = &td->elements[present];
    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 (uper_open_type_put(elm->type, NULL, memb_ptr, po) < 0) {
      ASN__ENCODE_FAILED;
    }
  
    er.encoded = 0;
    ASN__ENCODED_OK(er);
  }
  
  asn_dec_rval_t OPEN_TYPE_aper_get(
      const asn_codec_ctx_t* opt_codec_ctx, const asn_TYPE_descriptor_t* td,
      void* sptr, const asn_TYPE_member_t* elm, asn_per_data_t* pd) {
    asn_type_selector_result_t selected;
    void* memb_ptr;   /* Pointer to the member */
    void** memb_ptr2; /* Pointer to that pointer */
    void* inner_value;
    asn_dec_rval_t rv;
  
    if (!(elm->flags & ATF_OPEN_TYPE)) {
      ASN__DECODE_FAILED;
    }
  
    if (!elm->type_selector) {
      ASN_DEBUG(
          "Type selector is not defined for Open Type %s->%s->%s", td->name,
          elm->name, elm->type->name);
      ASN__DECODE_FAILED;
    }
  
    selected = elm->type_selector(td, sptr);
    if (!selected.presence_index) {
      ASN__DECODE_FAILED;
    }
  
    /* Fetch the pointer to this member */
    assert(elm->flags == ATF_OPEN_TYPE);
    if (elm->flags & ATF_POINTER) {
      memb_ptr2 = (void**) ((char*) sptr + elm->memb_offset);
    } else {
      memb_ptr  = (char*) sptr + elm->memb_offset;
      memb_ptr2 = &memb_ptr;
    }
    if (*memb_ptr2 != NULL) {
      /* Make sure we reset the structure first before encoding */
      if (CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0) != 0) {
        ASN__DECODE_FAILED;
      }
    }
  
    inner_value = (char*) *memb_ptr2 +
                  elm->type->elements[selected.presence_index - 1].memb_offset;
  
    rv = aper_open_type_get(
        opt_codec_ctx, selected.type_descriptor, NULL, &inner_value, pd);
    switch (rv.code) {
      case RC_OK:
        if (CHOICE_variant_set_presence(
                elm->type, *memb_ptr2, selected.presence_index) == 0) {
          break;
        } else {
          rv.code = RC_FAIL;
        }
        /* Fall through */
      case RC_WMORE:
      case RC_FAIL:
        if (*memb_ptr2) {
          if (elm->flags & ATF_POINTER) {
            ASN_STRUCT_FREE(*selected.type_descriptor, inner_value);
            *memb_ptr2 = NULL;
          } else {
            ASN_STRUCT_RESET(*selected.type_descriptor, inner_value);
          }
        }
    }
    return rv;
  }
  
  asn_enc_rval_t OPEN_TYPE_encode_aper(
      const asn_TYPE_descriptor_t* td, const asn_per_constraints_t* constraints,
      const void* sptr, asn_per_outp_t* po) {
    const void* memb_ptr;   /* Pointer to the member */
    asn_TYPE_member_t* elm; /* CHOICE's element */
    asn_enc_rval_t er;
    unsigned present;
  
    (void) constraints;
  
    present = CHOICE_variant_get_presence(td, sptr);
    if (present == 0 || present > td->elements_count) {
      ASN__ENCODE_FAILED;
    } else {
      present--;
    }
  
    ASN_DEBUG("Encoding %s OPEN TYPE element %d", td->name, present);
  
    elm = &td->elements[present];
    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 (aper_open_type_put(elm->type, NULL, memb_ptr, po) < 0) {
      ASN__ENCODE_FAILED;
    }
  
    er.encoded = 0;
    ASN__ENCODED_OK(er);
  }
  
  #endif /* ASN_DISABLE_PER_SUPPORT */
  