aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2004-10-21 13:37:57 +0000
committerLev Walkin <vlm@lionet.info>2004-10-21 13:37:57 +0000
commit5f56091cc6419914855becc94a99a6926d195ca8 (patch)
treedf5c2b0eefb0ca58d5dddd51f8a6adc2cc52020a
parentb2cb57c6f494dff55b635e78a9c0ea22655b4a6a (diff)
XER decoding of a REAL
-rw-r--r--skeletons/REAL.c106
-rw-r--r--skeletons/REAL.h1
-rw-r--r--skeletons/tests/check-REAL.c70
3 files changed, 167 insertions, 10 deletions
diff --git a/skeletons/REAL.c b/skeletons/REAL.c
index c61f7233..ace2f14a 100644
--- a/skeletons/REAL.c
+++ b/skeletons/REAL.c
@@ -31,7 +31,7 @@ asn_TYPE_descriptor_t asn_DEF_REAL = {
asn_generic_no_constraint,
ber_decode_primitive,
der_encode_primitive,
- 0, /* Not implemented yet */
+ REAL_decode_xer,
REAL_encode_xer,
0, /* Use generic outmost tag fetcher */
asn_DEF_REAL_tags,
@@ -42,6 +42,23 @@ asn_TYPE_descriptor_t asn_DEF_REAL = {
0 /* No specifics */
};
+typedef enum specialRealValue {
+ SRV__NOT_A_NUMBER,
+ SRV__MINUS_INFINITY,
+ SRV__PLUS_INFINITY
+} specialRealValue_e;
+static struct specialRealValue_s {
+ char *string;
+ int length;
+ double dv;
+} specialRealValue[] = {
+#define SRV_SET(foo, val) { foo, sizeof(foo) - 1, val }
+ SRV_SET("<NOT-A-NUMBER/>", 0.0),
+ SRV_SET("<MINUS-INFINITY/>", -1.0),
+ SRV_SET("<PLUS-INFINITY/>", 1.0),
+#undef SRV_SET
+};
+
ssize_t
REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key) {
char local_buf[64];
@@ -55,16 +72,16 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key)
*/
/* fpclassify(3) is not portable yet */
if(isnan(d)) {
- buf = "<NOT-A-NUMBER/>";
- buflen = 15;
+ buf = specialRealValue[SRV__NOT_A_NUMBER].string;
+ buflen = specialRealValue[SRV__NOT_A_NUMBER].length;
return (cb(buf, buflen, app_key) < 0) ? -1 : buflen;
} else if(!finite(d)) {
if(copysign(1.0, d) < 0.0) {
- buf = "<MINUS-INFINITY/>";
- buflen = 17;
+ buf = specialRealValue[SRV__MINUS_INFINITY].string;
+ buflen = specialRealValue[SRV__MINUS_INFINITY].length;
} else {
- buf = "<PLUS-INFINITY/>";
- buflen = 16;
+ buf = specialRealValue[SRV__PLUS_INFINITY].string;
+ buflen = specialRealValue[SRV__PLUS_INFINITY].length;
}
return (cb(buf, buflen, app_key) < 0) ? -1 : buflen;
} else if(ilogb(d) <= -INT_MAX) {
@@ -99,12 +116,13 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key)
if(canonical) {
/*
* Transform the "[-]d.dddE+-dd" output into "[-]d.dddE[-]d"
+ * Check that snprintf() constructed the output correctly.
*/
char *dot, *E;
char *end = buf + buflen;
char *last_zero;
- dot = (buf[0] == '-') ? (buf + 2) : (buf + 1);
+ dot = (buf[0] == 0x2d /* '-' */) ? (buf + 2) : (buf + 1);
if(*dot >= 0x30) {
errno = EINVAL;
return -1; /* Not a dot, really */
@@ -116,7 +134,7 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key)
char *expptr = ++E;
char *s = expptr;
int sign;
- if(*expptr == '+') {
+ if(*expptr == 0x2b /* '+' */) {
/* Skip the "+" */
buflen -= 1;
sign = 0;
@@ -135,8 +153,12 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key)
}
if(*last_zero == 0x30) {
*last_zero = 0x45; /* E */
+ buflen -= s - (last_zero + 1);
s = last_zero + 1;
- if(sign) *s++ = '-';
+ if(sign) {
+ *s++ = 0x2d /* '-' */;
+ buflen++;
+ }
}
for(; expptr <= end; s++, expptr++)
*s = *expptr;
@@ -221,6 +243,69 @@ REAL_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
return er;
}
+
+/*
+ * Decode the chunk of XML text encoding REAL.
+ */
+static ssize_t
+REAL__xer_body_decode(REAL_t *st, void *chunk_buf, size_t chunk_size) {
+ double value;
+ char *xerdata = (char *)chunk_buf;
+ char *endptr = 0;
+ char *b;
+
+ if(!chunk_size) return -1;
+
+ /*
+ * Decode an XMLSpecialRealValue: <MINUS-INFINITY>, etc.
+ */
+ if(xerdata[0] == 0x3c /* '<' */) {
+ size_t i;
+ for(i = 0; i < sizeof(specialRealValue)
+ / sizeof(specialRealValue[0]); i++) {
+ struct specialRealValue_s *srv = &specialRealValue[i];
+ if(srv->length != chunk_size
+ || memcmp(srv->string, chunk_buf, chunk_size))
+ continue;
+
+ if(asn_double2REAL(st, srv->dv / real_zero))
+ return -1;
+
+ return chunk_size;
+ }
+ ASN_DEBUG("Unknown XMLSpecialRealValue");
+ return -1;
+ }
+
+ /*
+ * Copy chunk into the nul-terminated string, and run strtod.
+ */
+ b = MALLOC(chunk_size + 1);
+ if(!b) return -1;
+ memcpy(b, chunk_buf, chunk_size);
+ b[chunk_size] = 0;
+
+ value = strtod(b, &endptr);
+ free(b);
+ if(endptr == b) return -1;
+
+ if(asn_double2REAL(st, value))
+ return -1;
+
+ return endptr - b;
+}
+
+asn_dec_rval_t
+REAL_decode_xer(asn_codec_ctx_t *opt_codec_ctx,
+ asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname,
+ void *buf_ptr, size_t size) {
+
+ return xer_decode_primitive(opt_codec_ctx, td,
+ (ASN__PRIMITIVE_TYPE_t **)sptr, opt_mname,
+ buf_ptr, size, REAL__xer_body_decode);
+}
+
+
int
asn_REAL2double(const REAL_t *st, double *dbl_value) {
unsigned int octv;
@@ -344,6 +429,7 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
m = scalbn(m, 8) + *ptr;
}
+ if(0)
ASN_DEBUG("m=%.10f, scF=%d, bF=%d, expval=%d, ldexp()=%f, scalbn()=%f",
m, scaleF, baseF, expval,
ldexp(m, expval * baseF + scaleF),
diff --git a/skeletons/REAL.h b/skeletons/REAL.h
index 86ae40f0..114b7e56 100644
--- a/skeletons/REAL.h
+++ b/skeletons/REAL.h
@@ -13,6 +13,7 @@ typedef ASN__PRIMITIVE_TYPE_t REAL_t;
extern asn_TYPE_descriptor_t asn_DEF_REAL;
asn_struct_print_f REAL_print;
+xer_type_decoder_f REAL_decode_xer;
xer_type_encoder_f REAL_encode_xer;
/***********************************
diff --git a/skeletons/tests/check-REAL.c b/skeletons/tests/check-REAL.c
index d0bf3fca..094017d2 100644
--- a/skeletons/tests/check-REAL.c
+++ b/skeletons/tests/check-REAL.c
@@ -7,6 +7,7 @@
#include <der_encoder.c>
#include <xer_decoder.c>
#include <xer_support.c>
+#include <xer_encoder.c>
#include <constraints.c>
static char reconstructed[2][512];
@@ -142,6 +143,64 @@ check_buf(uint8_t *buf, size_t bufsize, double verify, const char *sample, const
check_str_repr(val, sample, canonical_sample);
}
+static void
+check_xer(int fuzzy, double orig_value) {
+ asn_enc_rval_t er;
+ asn_dec_rval_t rc;
+ REAL_t st;
+ REAL_t *newst0 = 0;
+ REAL_t *newst1 = 0;
+ double value0, value1;
+ int ret;
+
+ memset(&st, 0, sizeof(st));
+ ret = asn_double2REAL(&st, orig_value);
+ assert(ret == 0);
+
+ reconstr_lens[0] = 0;
+ reconstr_lens[1] = 0;
+ er = xer_encode(&asn_DEF_REAL, &st,
+ XER_F_BASIC, callback, 0);
+ assert(er.encoded == reconstr_lens[0]);
+ er = xer_encode(&asn_DEF_REAL, &st,
+ XER_F_CANONICAL, callback, (void *)1);
+ assert(er.encoded == reconstr_lens[1]);
+ reconstructed[0][reconstr_lens[0]] = 0;
+ reconstructed[1][reconstr_lens[1]] = 0;
+
+ printf("%f vs (%d)[%s] & (%d)%s",
+ orig_value,
+ reconstr_lens[1], reconstructed[1],
+ reconstr_lens[0], reconstructed[0]
+ );
+
+ rc = xer_decode(0, &asn_DEF_REAL, (void **)&newst0,
+ reconstructed[0], reconstr_lens[0]);
+ assert(rc.code == RC_OK);
+ assert(rc.consumed < reconstr_lens[0]);
+
+ rc = xer_decode(0, &asn_DEF_REAL, (void **)&newst1,
+ reconstructed[1], reconstr_lens[1]);
+ assert(rc.code == RC_OK);
+ assert(rc.consumed == reconstr_lens[1]);
+
+ ret = asn_REAL2double(newst0, &value0);
+ assert(ret == 0);
+ ret = asn_REAL2double(newst1, &value1);
+ assert(ret == 0);
+
+ assert(value0 == orig_value
+ || (isnan(value0) && isnan(orig_value))
+ || fuzzy);
+ assert(value1 == orig_value
+ || (isnan(value1) && isnan(orig_value)));
+
+ assert(newst0->size == st.size || fuzzy);
+ assert(newst1->size == st.size);
+ assert(fuzzy || memcmp(newst0->buf, st.buf, st.size) == 0);
+ assert(memcmp(newst1->buf, st.buf, st.size) == 0);
+}
+
int
main() {
REAL_t rn;
@@ -190,5 +249,16 @@ main() {
check_buf(buf_mo1, sizeof(buf_mo1), -3.14, "-3.14", "-3.14E0");
check_buf(buf_mo2, sizeof(buf_mo2), 3.14, "3.14", "3.14E0");
+
+ check_xer(0, zero/zero); /* "<NOT-A-NUMBER/>" */
+ check_xer(0, 1.0/zero); /* "<PLUS-INFINITY/>" */
+ check_xer(0, -1.0/zero); /* "<MINUS-INFINITY/>" */
+ check_xer(0, 1.0);
+ check_xer(0, -1.0);
+ check_xer(0, 1.5);
+ check_xer(0, 123);
+ check_xer(1, 0.0000000000000000000001);
+ check_xer(1, -0.0000000000000000000001);
+
return 0;
}