Blame src/asn1c/asn_codecs_prim.c

Packit 728676
/*-
Packit 728676
 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
Packit 728676
 * Redistribution and modifications are permitted subject to BSD license.
Packit 728676
 */
Packit 728676
#include <asn_internal.h>
Packit 728676
#include <asn_codecs_prim.h>
Packit 728676
#include <errno.h>
Packit 728676
Packit 728676
/*
Packit 728676
 * Decode an always-primitive type.
Packit 728676
 */
Packit 728676
asn_dec_rval_t
Packit 728676
ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
Packit 728676
	asn_TYPE_descriptor_t *td,
Packit 728676
	void **sptr, const void *buf_ptr, size_t size, int tag_mode) {
Packit 728676
	ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr;
Packit 728676
	asn_dec_rval_t rval;
Packit 728676
	ber_tlv_len_t length = 0; // =0 to avoid [incorrect] warning.
Packit 728676
Packit 728676
	/*
Packit 728676
	 * If the structure is not there, allocate it.
Packit 728676
	 */
Packit 728676
	if(st == NULL) {
Packit 728676
		st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st));
Packit 728676
		if(st == NULL) _ASN_DECODE_FAILED;
Packit 728676
		*sptr = (void *)st;
Packit 728676
	}
Packit 728676
Packit 728676
	ASN_DEBUG("Decoding %s as plain primitive (tm=%d)",
Packit 728676
		td->name, tag_mode);
Packit 728676
Packit 728676
	/*
Packit 728676
	 * Check tags and extract value length.
Packit 728676
	 */
Packit 728676
	rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size,
Packit 728676
			tag_mode, 0, &length, 0);
Packit 728676
	if(rval.code != RC_OK)
Packit 728676
		return rval;
Packit 728676
Packit 728676
	ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
Packit 728676
Packit 728676
	/*
Packit 728676
	 * Make sure we have this length.
Packit 728676
	 */
Packit 728676
	buf_ptr = ((const char *)buf_ptr) + rval.consumed;
Packit 728676
	size -= rval.consumed;
Packit 728676
	if(length > (ber_tlv_len_t)size) {
Packit 728676
		rval.code = RC_WMORE;
Packit 728676
		rval.consumed = 0;
Packit 728676
		return rval;
Packit 728676
	}
Packit 728676
Packit 728676
	st->size = (int)length;
Packit 728676
	/* The following better be optimized away. */
Packit 728676
	if(sizeof(st->size) != sizeof(length)
Packit 728676
			&& (ber_tlv_len_t)st->size != length) {
Packit 728676
		st->size = 0;
Packit 728676
		_ASN_DECODE_FAILED;
Packit 728676
	}
Packit 728676
Packit 728676
	st->buf = (uint8_t *)MALLOC(length + 1);
Packit 728676
	if(!st->buf) {
Packit 728676
		st->size = 0;
Packit 728676
		_ASN_DECODE_FAILED;
Packit 728676
	}
Packit 728676
Packit 728676
	memcpy(st->buf, buf_ptr, length);
Packit 728676
	st->buf[length] = '\0';		/* Just in case */
Packit 728676
Packit 728676
	rval.code = RC_OK;
Packit 728676
	rval.consumed += length;
Packit 728676
Packit 728676
	ASN_DEBUG("Took %ld/%ld bytes to encode %s",
Packit 728676
		(long)rval.consumed,
Packit 728676
		(long)length, td->name);
Packit 728676
Packit 728676
	return rval;
Packit 728676
}
Packit 728676
Packit 728676
/*
Packit 728676
 * Encode an always-primitive type using DER.
Packit 728676
 */
Packit 728676
asn_enc_rval_t
Packit 728676
der_encode_primitive(asn_TYPE_descriptor_t *td, void *sptr,
Packit 728676
	int tag_mode, ber_tlv_tag_t tag,
Packit 728676
	asn_app_consume_bytes_f *cb, void *app_key) {
Packit 728676
	asn_enc_rval_t erval;
Packit 728676
	ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
Packit 728676
Packit 728676
	ASN_DEBUG("%s %s as a primitive type (tm=%d)",
Packit 728676
		cb?"Encoding":"Estimating", td->name, tag_mode);
Packit 728676
Packit 728676
	erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag,
Packit 728676
		cb, app_key);
Packit 728676
	ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded);
Packit 728676
	if(erval.encoded == -1) {
Packit 728676
		erval.failed_type = td;
Packit 728676
		erval.structure_ptr = sptr;
Packit 728676
		return erval;
Packit 728676
	}
Packit 728676
Packit 728676
	if(cb && st->buf) {
Packit 728676
		if(cb(st->buf, st->size, app_key) < 0) {
Packit 728676
			erval.encoded = -1;
Packit 728676
			erval.failed_type = td;
Packit 728676
			erval.structure_ptr = sptr;
Packit 728676
			return erval;
Packit 728676
		}
Packit 728676
	} else {
Packit 728676
		assert(st->buf || st->size == 0);
Packit 728676
	}
Packit 728676
Packit 728676
	erval.encoded += st->size;
Packit 728676
	_ASN_ENCODED_OK(erval);
Packit 728676
}
Packit 728676
Packit 728676
void
Packit 728676
ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr,
Packit 728676
		int contents_only) {
Packit 728676
	ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
Packit 728676
Packit 728676
	if(!td || !sptr)
Packit 728676
		return;
Packit 728676
Packit 728676
	ASN_DEBUG("Freeing %s as a primitive type", td->name);
Packit 728676
Packit 728676
	if(st->buf)
Packit 728676
		FREEMEM(st->buf);
Packit 728676
Packit 728676
	if(!contents_only)
Packit 728676
		FREEMEM(st);
Packit 728676
}
Packit 728676
Packit 728676
Packit 728676
/*
Packit 728676
 * Local internal type passed around as an argument.
Packit 728676
 */
Packit 728676
struct xdp_arg_s {
Packit 728676
	asn_TYPE_descriptor_t *type_descriptor;
Packit 728676
	void *struct_key;
Packit 728676
	xer_primitive_body_decoder_f *prim_body_decoder;
Packit 728676
	int decoded_something;
Packit 728676
	int want_more;
Packit 728676
};
Packit 728676
Packit 728676
/*
Packit 728676
 * Since some kinds of primitive values can be encoded using value-specific
Packit 728676
 * tags (<MINUS-INFINITY>, <enum-element>, etc), the primitive decoder must
Packit 728676
 * be supplied with such tags to parse them as needed.
Packit 728676
 */
Packit 728676
static int
Packit 728676
xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) {
Packit 728676
	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
Packit 728676
	enum xer_pbd_rval bret;
Packit 728676
Packit 728676
	/*
Packit 728676
	 * The chunk_buf is guaranteed to start at '<'.
Packit 728676
	 */
Packit 728676
	assert(chunk_size && ((const char *)chunk_buf)[0] == 0x3c);
Packit 728676
Packit 728676
	/*
Packit 728676
	 * Decoding was performed once already. Prohibit doing it again.
Packit 728676
	 */
Packit 728676
	if(arg->decoded_something)
Packit 728676
		return -1;
Packit 728676
Packit 728676
	bret = arg->prim_body_decoder(arg->type_descriptor,
Packit 728676
		arg->struct_key, chunk_buf, chunk_size);
Packit 728676
	switch(bret) {
Packit 728676
	case XPBD_SYSTEM_FAILURE:
Packit 728676
	case XPBD_DECODER_LIMIT:
Packit 728676
	case XPBD_BROKEN_ENCODING:
Packit 728676
		break;
Packit 728676
	case XPBD_BODY_CONSUMED:
Packit 728676
		/* Tag decoded successfully */
Packit 728676
		arg->decoded_something = 1;
Packit 728676
		/* Fall through */
Packit 728676
	case XPBD_NOT_BODY_IGNORE:	/* Safe to proceed further */
Packit 728676
		return 0;
Packit 728676
	}
Packit 728676
Packit 728676
	return -1;
Packit 728676
}
Packit 728676
Packit 728676
static ssize_t
Packit 728676
xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
Packit 728676
	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
Packit 728676
	enum xer_pbd_rval bret;
Packit 728676
	size_t lead_wsp_size;
Packit 728676
Packit 728676
	if(arg->decoded_something) {
Packit 728676
		if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) {
Packit 728676
			/*
Packit 728676
			 * Example:
Packit 728676
			 * "<INTEGER>123 </INTEGER>"
Packit 728676
			 *                      ^- chunk_buf position.
Packit 728676
			 */
Packit 728676
			return chunk_size;
Packit 728676
		}
Packit 728676
		/*
Packit 728676
		 * Decoding was done once already. Prohibit doing it again.
Packit 728676
		 */
Packit 728676
		return -1;
Packit 728676
	}
Packit 728676
Packit 728676
	if(!have_more) {
Packit 728676
		/*
Packit 728676
		 * If we've received something like "1", we can't really
Packit 728676
		 * tell whether it is really `1` or `123`, until we know
Packit 728676
		 * that there is no more data coming.
Packit 728676
		 * The have_more argument will be set to 1 once something
Packit 728676
		 * like this is available to the caller of this callback:
Packit 728676
		 * "1
Packit 728676
		 */
Packit 728676
		arg->want_more = 1;
Packit 728676
		return -1;
Packit 728676
	}
Packit 728676
Packit 728676
	lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size);
Packit 728676
	chunk_buf = (const char *)chunk_buf + lead_wsp_size;
Packit 728676
	chunk_size -= lead_wsp_size;
Packit 728676
Packit 728676
	bret = arg->prim_body_decoder(arg->type_descriptor,
Packit 728676
		arg->struct_key, chunk_buf, chunk_size);
Packit 728676
	switch(bret) {
Packit 728676
	case XPBD_SYSTEM_FAILURE:
Packit 728676
	case XPBD_DECODER_LIMIT:
Packit 728676
	case XPBD_BROKEN_ENCODING:
Packit 728676
		break;
Packit 728676
	case XPBD_BODY_CONSUMED:
Packit 728676
		/* Tag decoded successfully */
Packit 728676
		arg->decoded_something = 1;
Packit 728676
		/* Fall through */
Packit 728676
	case XPBD_NOT_BODY_IGNORE:	/* Safe to proceed further */
Packit 728676
		return lead_wsp_size + chunk_size;
Packit 728676
	}
Packit 728676
Packit 728676
	return -1;
Packit 728676
}
Packit 728676
Packit 728676
Packit 728676
asn_dec_rval_t
Packit 728676
xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx,
Packit 728676
	asn_TYPE_descriptor_t *td,
Packit 728676
	void **sptr,
Packit 728676
	size_t struct_size,
Packit 728676
	const char *opt_mname,
Packit 728676
	const void *buf_ptr, size_t size,
Packit 728676
	xer_primitive_body_decoder_f *prim_body_decoder
Packit 728676
) {
Packit 728676
	const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
Packit 728676
	asn_struct_ctx_t s_ctx;
Packit 728676
	struct xdp_arg_s s_arg;
Packit 728676
	asn_dec_rval_t rc;
Packit 728676
Packit 728676
	/*
Packit 728676
	 * Create the structure if does not exist.
Packit 728676
	 */
Packit 728676
	if(!*sptr) {
Packit 728676
		*sptr = CALLOC(1, struct_size);
Packit 728676
		if(!*sptr) _ASN_DECODE_FAILED;
Packit 728676
	}
Packit 728676
Packit 728676
	memset(&s_ctx, 0, sizeof(s_ctx));
Packit 728676
	s_arg.type_descriptor = td;
Packit 728676
	s_arg.struct_key = *sptr;
Packit 728676
	s_arg.prim_body_decoder = prim_body_decoder;
Packit 728676
	s_arg.decoded_something = 0;
Packit 728676
	s_arg.want_more = 0;
Packit 728676
Packit 728676
	rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
Packit 728676
		xml_tag, buf_ptr, size,
Packit 728676
		xer_decode__unexpected_tag, xer_decode__primitive_body);
Packit 728676
	switch(rc.code) {
Packit 728676
	case RC_OK:
Packit 728676
		if(!s_arg.decoded_something) {
Packit 728676
			char ch;
Packit 728676
			ASN_DEBUG("Primitive body is not recognized, "
Packit 728676
				"supplying empty one");
Packit 728676
			/*
Packit 728676
			 * Decoding opportunity has come and gone.
Packit 728676
			 * Where's the result?
Packit 728676
			 * Try to feed with empty body, see if it eats it.
Packit 728676
			 */
Packit 728676
			if(prim_body_decoder(s_arg.type_descriptor,
Packit 728676
				s_arg.struct_key, &ch, 0)
Packit 728676
					!= XPBD_BODY_CONSUMED) {
Packit 728676
				/*
Packit 728676
				 * This decoder does not like empty stuff.
Packit 728676
				 */
Packit 728676
				_ASN_DECODE_FAILED;
Packit 728676
			}
Packit 728676
		}
Packit 728676
		break;
Packit 728676
	case RC_WMORE:
Packit 728676
		/*
Packit 728676
		 * Redo the whole thing later.
Packit 728676
		 * We don't have a context to save intermediate parsing state.
Packit 728676
		 */
Packit 728676
		rc.consumed = 0;
Packit 728676
		break;
Packit 728676
	case RC_FAIL:
Packit 728676
		rc.consumed = 0;
Packit 728676
		if(s_arg.want_more)
Packit 728676
			rc.code = RC_WMORE;
Packit 728676
		else
Packit 728676
			_ASN_DECODE_FAILED;
Packit 728676
		break;
Packit 728676
	}
Packit 728676
	return rc;
Packit 728676
}
Packit 728676