diff options
author | Lev Walkin <vlm@lionet.info> | 2004-10-21 13:37:57 +0000 |
---|---|---|
committer | Lev Walkin <vlm@lionet.info> | 2004-10-21 13:37:57 +0000 |
commit | 5f56091cc6419914855becc94a99a6926d195ca8 (patch) | |
tree | df5c2b0eefb0ca58d5dddd51f8a6adc2cc52020a | |
parent | b2cb57c6f494dff55b635e78a9c0ea22655b4a6a (diff) |
XER decoding of a REAL
-rw-r--r-- | skeletons/REAL.c | 106 | ||||
-rw-r--r-- | skeletons/REAL.h | 1 | ||||
-rw-r--r-- | skeletons/tests/check-REAL.c | 70 |
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; } |