XMLValueList support
git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@708 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index db289cb..de856d8 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -1,5 +1,6 @@
/*-
- * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Copyright (c) 2003, 2004, 2005 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
#include <asn_internal.h>
@@ -92,11 +93,15 @@
return der_encode_primitive(td, sptr, tag_mode, tag, cb, app_key);
}
+static const asn_INTEGER_enum_map_t *INTEGER__map_value2enum(asn_INTEGER_specifics_t *specs, long value);
+static const asn_INTEGER_enum_map_t *INTEGER__map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop);
+
/*
* INTEGER specific human-readable output.
*/
static ssize_t
-INTEGER__dump(const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key) {
+INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) {
+ asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
char scratch[32]; /* Enough for 64-bit integer */
uint8_t *buf = st->buf;
uint8_t *buf_end = st->buf + st->size;
@@ -105,10 +110,6 @@
char *p;
int ret;
- if(st->size == 0) {
- return (cb("0", 1, app_key) < 0) ? -1 : 1;
- }
-
/*
* Advance buf pointer until the start of the value's body.
* This will make us able to process large integers using simple case,
@@ -126,12 +127,49 @@
/* Simple case: the integer size is small */
if((size_t)(buf_end - buf) <= sizeof(accum)) {
- accum = (*buf & 0x80) ? -1 : 0;
- for(; buf < buf_end; buf++)
- accum = (accum << 8) | *buf;
- ret = snprintf(scratch, sizeof(scratch), "%ld", accum);
- assert(ret > 0 && ret < (int)sizeof(scratch));
- return (cb(scratch, ret, app_key) < 0) ? -1 : ret;
+ const asn_INTEGER_enum_map_t *el;
+ size_t scrsize;
+ char *scr;
+
+ if(buf == buf_end) {
+ accum = 0;
+ } else {
+ accum = (*buf & 0x80) ? -1 : 0;
+ for(; buf < buf_end; buf++)
+ accum = (accum << 8) | *buf;
+ }
+
+ el = INTEGER__map_value2enum(specs, accum);
+ if(el) {
+ scrsize = el->enum_len + 32;
+ scr = (char *)alloca(scrsize);
+ if(plainOrXER == 0)
+ ret = snprintf(scr, scrsize,
+ "%ld (%s)", accum, el->enum_name);
+ else
+ ret = snprintf(scr, scrsize,
+ "<%s/>", el->enum_name);
+ } else if(plainOrXER && specs && specs->strict_enumeration) {
+ ASN_DEBUG("ASN.1 forbids dealing with "
+ "unknown value of ENUMERATED type");
+ errno = EPERM;
+ return -1;
+ } else {
+ scrsize = sizeof(scratch);
+ scr = scratch;
+ ret = snprintf(scr, scrsize, "%ld", accum);
+ }
+ assert(ret > 0 && (size_t)ret < scrsize);
+ return (cb(scr, ret, app_key) < 0) ? -1 : ret;
+ } else if(plainOrXER && specs && specs->strict_enumeration) {
+ /*
+ * Here and earlier, we cannot encode the ENUMERATED values
+ * if there is no corresponding identifier.
+ */
+ ASN_DEBUG("ASN.1 forbids dealing with "
+ "unknown value of ENUMERATED type");
+ errno = EPERM;
+ return -1;
}
/* Output in the long xx:yy:zz... format */
@@ -171,22 +209,97 @@
if(!st && !st->buf)
ret = cb("<absent>", 8, app_key);
else
- ret = INTEGER__dump(st, cb, app_key);
+ ret = INTEGER__dump(td, st, cb, app_key, 0);
return (ret < 0) ? -1 : 0;
}
+struct e2v_key {
+ const char *start;
+ const char *stop;
+ asn_INTEGER_enum_map_t *vemap;
+ unsigned int *evmap;
+};
+static int
+INTEGER__compar_enum2value(const void *kp, const void *am) {
+ const struct e2v_key *key = (const struct e2v_key *)kp;
+ const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;
+ const char *ptr, *end, *name;
+
+ /* Remap the element (sort by different criterion) */
+ el = key->vemap + key->evmap[el - key->vemap];
+
+ /* Compare strings */
+ for(ptr = key->start, end = key->stop, name = el->enum_name;
+ ptr < end; ptr++, name++) {
+ if(*ptr != *name)
+ return *(const unsigned char *)ptr
+ - *(const unsigned char *)name;
+ }
+ return name[0] ? -1 : 0;
+}
+
+static const asn_INTEGER_enum_map_t *
+INTEGER__map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) {
+ int count = specs ? specs->map_count : 0;
+ struct e2v_key key;
+ const char *lp;
+
+ if(!count) return NULL;
+
+ /* Guaranteed: assert(lstart < lstop); */
+ /* Figure out the tag name */
+ for(lstart++, lp = lstart; lp < lstop; lp++) {
+ switch(*lp) {
+ case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */
+ case 0x2f: /* '/' */ case 0x3e: /* '>' */
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+ if(lp == lstop) return NULL; /* No tag found */
+ lstop = lp;
+
+ key.start = lstart;
+ key.stop = lstop;
+ key.vemap = specs->value2enum;
+ key.evmap = specs->enum2value;
+ return (asn_INTEGER_enum_map_t *)bsearch(&key, specs->value2enum, count,
+ sizeof(specs->value2enum[0]), INTEGER__compar_enum2value);
+}
+
+static int
+INTEGER__compar_value2enum(const void *kp, const void *am) {
+ long a = *(const long *)kp;
+ const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;
+ long b = el->nat_value;
+ if(a < b) return -1;
+ else if(a == b) return 0;
+ else return 1;
+}
+
+static const asn_INTEGER_enum_map_t *
+INTEGER__map_value2enum(asn_INTEGER_specifics_t *specs, long value) {
+ int count = specs ? specs->map_count : 0;
+ if(!count) return 0;
+ return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum,
+ count, sizeof(specs->value2enum[0]),
+ INTEGER__compar_value2enum);
+}
+
/*
* Decode the chunk of XML text encoding INTEGER.
*/
static ssize_t
-INTEGER__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) {
+INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, void *chunk_buf, size_t chunk_size) {
INTEGER_t *st = (INTEGER_t *)sptr;
long sign = 1;
long value;
- char *lp;
- char *lstart = (char *)chunk_buf;
- char *lstop = lstart + chunk_size;
+ const char *lp;
+ const char *lstart = (const char *)chunk_buf;
+ const char *lstop = lstart + chunk_size;
enum {
ST_SKIPSPACE,
ST_WAITDIGITS,
@@ -194,8 +307,8 @@
} state = ST_SKIPSPACE;
/*
- * We may receive a tag here. But we aren't ready to deal with it yet.
- * So, just use stroul()-like code and serialize the result.
+ * We may have received a tag here. It will be processed inline.
+ * Use strtoul()-like code and serialize the result.
*/
for(value = 0, lp = lstart; lp < lstop; lp++) {
int lv = *lp;
@@ -242,6 +355,22 @@
}
}
continue;
+ case 0x3c: /* '<' */
+ if(state == ST_SKIPSPACE) {
+ const asn_INTEGER_enum_map_t *el;
+ el = INTEGER__map_enum2value(
+ (asn_INTEGER_specifics_t *)
+ td->specifics, lstart, lstop);
+ if(el) {
+ ASN_DEBUG("Found \"%s\" => %ld",
+ el->enum_name, el->nat_value);
+ state = ST_DIGITS;
+ value = el->nat_value;
+ break;
+ }
+ ASN_DEBUG("Unknown identifier for INTEGER");
+ }
+ return -1;
}
break;
}
@@ -280,7 +409,7 @@
if(!st && !st->buf)
_ASN_ENCODE_FAILED;
- er.encoded = INTEGER__dump(st, cb, app_key);
+ er.encoded = INTEGER__dump(td, st, cb, app_key, 1);
if(er.encoded < 0) _ASN_ENCODE_FAILED;
return er;