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