Commit 5f56091c authored by Lev Walkin's avatar Lev Walkin

XER decoding of a REAL

parent b2cb57c6
......@@ -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),
......
......@@ -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;
/***********************************
......
......@@ -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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment