Logo Search packages:      
Sourcecode: biosig4c++ version File versions  Download package

asn_codecs_prim.c

/*-
 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
 * Redistribution and modifications are permitted subject to BSD license.
 */
#include <asn_internal.h>
#include <asn_codecs_prim.h>
#include <errno.h>

/*
 * Decode an always-primitive type.
 */
asn_dec_rval_t
ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
      asn_TYPE_descriptor_t *td,
      void **sptr, const void *buf_ptr, size_t size, int tag_mode) {
      ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr;
      asn_dec_rval_t rval;
      ber_tlv_len_t length;

      /*
       * If the structure is not there, allocate it.
       */
      if(st == NULL) {
            st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st));
            if(st == NULL) _ASN_DECODE_FAILED;
            *sptr = (void *)st;
      }

      ASN_DEBUG("Decoding %s as plain primitive (tm=%d)",
            td->name, tag_mode);

      /*
       * Check tags and extract value length.
       */
      rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size,
                  tag_mode, 0, &length, 0);
      if(rval.code != RC_OK)
            return rval;

      ASN_DEBUG("%s length is %d bytes", td->name, (int)length);

      /*
       * Make sure we have this length.
       */
      buf_ptr = ((const char *)buf_ptr) + rval.consumed;
      size -= rval.consumed;
      if(length > (ber_tlv_len_t)size) {
            rval.code = RC_WMORE;
            rval.consumed = 0;
            return rval;
      }

      st->size = (int)length;
      /* The following better be optimized away. */
      if(sizeof(st->size) != sizeof(length)
                  && (ber_tlv_len_t)st->size != length) {
            st->size = 0;
            _ASN_DECODE_FAILED;
      }

      st->buf = (uint8_t *)MALLOC(length + 1);
      if(!st->buf) {
            st->size = 0;
            _ASN_DECODE_FAILED;
      }

      memcpy(st->buf, buf_ptr, length);
      st->buf[length] = '\0';       /* Just in case */

      rval.code = RC_OK;
      rval.consumed += length;

      ASN_DEBUG("Took %ld/%ld bytes to encode %s",
            (long)rval.consumed,
            (long)length, td->name);

      return rval;
}

/*
 * Encode an always-primitive type using DER.
 */
asn_enc_rval_t
der_encode_primitive(asn_TYPE_descriptor_t *td, void *sptr,
      int tag_mode, ber_tlv_tag_t tag,
      asn_app_consume_bytes_f *cb, void *app_key) {
      asn_enc_rval_t erval;
      ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;

      ASN_DEBUG("%s %s as a primitive type (tm=%d)",
            cb?"Encoding":"Estimating", td->name, tag_mode);

      erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag,
            cb, app_key);
      ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded);
      if(erval.encoded == -1) {
            erval.failed_type = td;
            erval.structure_ptr = sptr;
            return erval;
      }

      if(cb && st->buf) {
            if(cb(st->buf, st->size, app_key) < 0) {
                  erval.encoded = -1;
                  erval.failed_type = td;
                  erval.structure_ptr = sptr;
                  return erval;
            }
      } else {
            assert(st->buf || st->size == 0);
      }

      erval.encoded += st->size;
      _ASN_ENCODED_OK(erval);
}

void
ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr,
            int contents_only) {
      ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;

      if(!td || !sptr)
            return;

      ASN_DEBUG("Freeing %s as a primitive type", td->name);

      if(st->buf)
            FREEMEM(st->buf);

      if(!contents_only)
            FREEMEM(st);
}


/*
 * Local internal type passed around as an argument.
 */
00138 struct xdp_arg_s {
      asn_TYPE_descriptor_t *type_descriptor;
      void *struct_key;
      xer_primitive_body_decoder_f *prim_body_decoder;
      int decoded_something;
      int want_more;
};


static int
xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) {
      struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
      enum xer_pbd_rval bret;

      if(arg->decoded_something) {
            if(xer_is_whitespace(chunk_buf, chunk_size))
                  return 0;   /* Skip it. */
            /*
             * Decoding was done once already. Prohibit doing it again.
             */
            return -1;
      }

      bret = arg->prim_body_decoder(arg->type_descriptor,
            arg->struct_key, chunk_buf, chunk_size);
      switch(bret) {
      case XPBD_SYSTEM_FAILURE:
      case XPBD_DECODER_LIMIT:
      case XPBD_BROKEN_ENCODING:
            break;
      case XPBD_BODY_CONSUMED:
            /* Tag decoded successfully */
            arg->decoded_something = 1;
            /* Fall through */
      case XPBD_NOT_BODY_IGNORE:    /* Safe to proceed further */
            return 0;
      }

      return -1;
}

static ssize_t
xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
      struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
      enum xer_pbd_rval bret;

      if(arg->decoded_something) {
            if(xer_is_whitespace(chunk_buf, chunk_size))
                  return chunk_size;
            /*
             * Decoding was done once already. Prohibit doing it again.
             */
            return -1;
      }

      if(!have_more) {
            /*
             * If we've received something like "1", we can't really
             * tell whether it is really `1` or `123`, until we know
             * that there is no more data coming.
             * The have_more argument will be set to 1 once something
             * like this is available to the caller of this callback:
             * "1<tag_start..."
             */
            arg->want_more = 1;
            return -1;
      }

      bret = arg->prim_body_decoder(arg->type_descriptor,
            arg->struct_key, chunk_buf, chunk_size);
      switch(bret) {
      case XPBD_SYSTEM_FAILURE:
      case XPBD_DECODER_LIMIT:
      case XPBD_BROKEN_ENCODING:
            break;
      case XPBD_BODY_CONSUMED:
            /* Tag decoded successfully */
            arg->decoded_something = 1;
            /* Fall through */
      case XPBD_NOT_BODY_IGNORE:    /* Safe to proceed further */
            return chunk_size;
      }

      return -1;
}


asn_dec_rval_t
xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
      asn_TYPE_descriptor_t *td,
      void **sptr,
      size_t struct_size,
      const char *opt_mname,
      const void *buf_ptr, size_t size,
      xer_primitive_body_decoder_f *prim_body_decoder
) {
      const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
      asn_struct_ctx_t s_ctx;
      struct xdp_arg_s s_arg;
      asn_dec_rval_t rc;

      /*
       * Create the structure if does not exist.
       */
      if(!*sptr) {
            *sptr = CALLOC(1, struct_size);
            if(!*sptr) _ASN_DECODE_FAILED;
      }

      memset(&s_ctx, 0, sizeof(s_ctx));
      s_arg.type_descriptor = td;
      s_arg.struct_key = *sptr;
      s_arg.prim_body_decoder = prim_body_decoder;
      s_arg.decoded_something = 0;
      s_arg.want_more = 0;

      rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
            xml_tag, buf_ptr, size,
            xer_decode__unexpected_tag, xer_decode__body);
      switch(rc.code) {
      case RC_OK:
            if(!s_arg.decoded_something) {
                  char ch;
                  ASN_DEBUG("Primitive body is not recognized, "
                        "supplying empty one");
                  /*
                   * Decoding opportunity has come and gone.
                   * Where's the result?
                   * Try to feed with empty body, see if it eats it.
                   */
                  if(prim_body_decoder(s_arg.type_descriptor,
                        s_arg.struct_key, &ch, 0)
                              != XPBD_BODY_CONSUMED) {
                        /*
                         * This decoder does not like empty stuff.
                         */
                        _ASN_DECODE_FAILED;
                  }
            }
            break;
      case RC_WMORE:
            /*
             * Redo the whole thing later.
             * We don't have a context to save intermediate parsing state.
             */
            rc.consumed = 0;
            break;
      case RC_FAIL:
            rc.consumed = 0;
            if(s_arg.want_more)
                  rc.code = RC_WMORE;
            else
                  _ASN_DECODE_FAILED;
            break;
      }
      return rc;
}


Generated by  Doxygen 1.6.0   Back to index