Commit ab1d1e1e authored by Lev Walkin's avatar Lev Walkin

OER support and randomized testing for the REAL (floating point) type

parent 68619bf6
/*- /*-
* Copyright (c) 2004, 2006 Lev Walkin <vlm@lionet.info>. All rights reserved. * Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license. * Redistribution and modifications are permitted subject to BSD license.
*/ */
/* /*
...@@ -51,8 +51,8 @@ asn_TYPE_operation_t asn_OP_NativeReal = { ...@@ -51,8 +51,8 @@ asn_TYPE_operation_t asn_OP_NativeReal = {
0, 0,
0, 0,
#else #else
0, NativeReal_decode_oer,
0, NativeReal_encode_oer,
#endif /* ASN_DISABLE_OER_SUPPORT */ #endif /* ASN_DISABLE_OER_SUPPORT */
#ifdef ASN_DISABLE_PER_SUPPORT #ifdef ASN_DISABLE_PER_SUPPORT
0, 0,
...@@ -82,8 +82,8 @@ asn_TYPE_descriptor_t asn_DEF_NativeReal = { ...@@ -82,8 +82,8 @@ asn_TYPE_descriptor_t asn_DEF_NativeReal = {
*/ */
asn_dec_rval_t asn_dec_rval_t
NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
asn_TYPE_descriptor_t *td, asn_TYPE_descriptor_t *td, void **dbl_ptr,
void **dbl_ptr, const void *buf_ptr, size_t size, int tag_mode) { const void *buf_ptr, size_t size, int tag_mode) {
double *Dbl = (double *)*dbl_ptr; double *Dbl = (double *)*dbl_ptr;
asn_dec_rval_t rval; asn_dec_rval_t rval;
ber_tlv_len_t length; ber_tlv_len_t length;
...@@ -101,16 +101,14 @@ NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, ...@@ -101,16 +101,14 @@ NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
} }
} }
ASN_DEBUG("Decoding %s as REAL (tm=%d)", ASN_DEBUG("Decoding %s as REAL (tm=%d)", td->name, tag_mode);
td->name, tag_mode);
/* /*
* Check tags. * Check tags.
*/ */
rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, tag_mode, 0,
tag_mode, 0, &length, 0); &length, 0);
if(rval.code != RC_OK) if(rval.code != RC_OK) return rval;
return rval;
ASN_DEBUG("%s length is %d bytes", td->name, (int)length); ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
...@@ -131,51 +129,35 @@ NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, ...@@ -131,51 +129,35 @@ NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
* If overflow occured, return with RC_FAIL. * If overflow occured, return with RC_FAIL.
*/ */
{ {
uint8_t scratch[24]; /* Longer than %.16f in decimal */
REAL_t tmp; REAL_t tmp;
union {
const void *constbuf;
void *nonconstbuf;
} unconst_buf;
double d; double d;
int ret;
unconst_buf.constbuf = buf_ptr; if(length < sizeof(scratch)) {
tmp.buf = (uint8_t *)unconst_buf.nonconstbuf; tmp.buf = scratch;
tmp.size = length; tmp.size = length;
} else {
if(length < (ber_tlv_len_t)size) { /* This rarely happens: impractically long value */
int ret; tmp.buf = CALLOC(1, length + 1);
uint8_t saved_byte = tmp.buf[tmp.size];
tmp.buf[tmp.size] = '\0';
ret = asn_REAL2double(&tmp, &d);
tmp.buf[tmp.size] = saved_byte;
if(ret) {
rval.code = RC_FAIL;
rval.consumed = 0;
return rval;
}
} else if(length < 48 /* Enough for longish %f value. */) {
tmp.buf = alloca(length + 1);
tmp.size = length; tmp.size = length;
memcpy(tmp.buf, buf_ptr, length); if(!tmp.buf) {
tmp.buf[tmp.size] = '\0';
if(asn_REAL2double(&tmp, &d)) {
rval.code = RC_FAIL; rval.code = RC_FAIL;
rval.consumed = 0; rval.consumed = 0;
return rval; return rval;
} }
} else { }
/* This should probably never happen: impractically long value */
tmp.buf = CALLOC(1, length + 1); memcpy(tmp.buf, buf_ptr, length);
tmp.size = length; tmp.buf[length] = '\0';
if(tmp.buf) memcpy(tmp.buf, buf_ptr, length);
if(!tmp.buf || asn_REAL2double(&tmp, &d)) { ret = asn_REAL2double(&tmp, &d);
FREEMEM(tmp.buf); if(tmp.buf != scratch) FREEMEM(tmp.buf);
if(ret) {
rval.code = RC_FAIL; rval.code = RC_FAIL;
rval.consumed = 0; rval.consumed = 0;
return rval; return rval;
} }
FREEMEM(tmp.buf);
}
*Dbl = d; *Dbl = d;
} }
...@@ -183,8 +165,8 @@ NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx, ...@@ -183,8 +165,8 @@ NativeReal_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
rval.code = RC_OK; rval.code = RC_OK;
rval.consumed += length; rval.consumed += length;
ASN_DEBUG("Took %ld/%ld bytes to encode %s (%f)", ASN_DEBUG("Took %ld/%ld bytes to encode %s (%f)", (long)rval.consumed,
(long)rval.consumed, (long)length, td->name, *Dbl); (long)length, td->name, *Dbl);
return rval; return rval;
} }
...@@ -298,6 +280,107 @@ NativeReal_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -298,6 +280,107 @@ NativeReal_encode_uper(asn_TYPE_descriptor_t *td,
#endif /* ASN_DISABLE_PER_SUPPORT */ #endif /* ASN_DISABLE_PER_SUPPORT */
#ifndef ASN_DISABLE_OER_SUPPORT
/*
* Encode as Canonical OER.
*/
asn_enc_rval_t
NativeReal_encode_oer(asn_TYPE_descriptor_t *td,
const asn_oer_constraints_t *constraints, void *sptr,
asn_app_consume_bytes_f *cb, void *app_key) {
asn_enc_rval_t er = { 0, 0, 0 };
ssize_t len_len;
const double *d = sptr;
REAL_t tmp;
/* Prepare a temporary clean structure */
memset(&tmp, 0, sizeof(tmp));
(void)td;
(void)constraints; /* Constraints are unused in OER */
if(asn_double2REAL(&tmp, *d)) {
ASN__ENCODE_FAILED;
}
/* Encode a fake REAL */
len_len = oer_serialize_length(tmp.size, cb, app_key);
if(len_len < 0 || cb(tmp.buf, tmp.size, app_key) < 0) {
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
ASN__ENCODE_FAILED;
} else {
er.encoded = len_len + tmp.size;
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp);
ASN__ENCODED_OK(er);
}
}
asn_dec_rval_t
NativeReal_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
asn_TYPE_descriptor_t *td,
const asn_oer_constraints_t *constraints, void **sptr,
const void *ptr, size_t size) {
asn_dec_rval_t ok = {RC_OK, 0};
double *st;
double d;
ssize_t len_len;
size_t real_body_len;
(void)opt_codec_ctx;
(void)td;
(void)constraints; /* Constraints are unused in OER */
len_len = oer_fetch_length(ptr, size, &real_body_len);
if(len_len < 0) ASN__DECODE_FAILED;
if(len_len == 0) ASN__DECODE_STARVED;
ptr = (const char *)ptr + len_len;
size -= len_len;
if(real_body_len > size) ASN__DECODE_STARVED;
{
uint8_t scratch[24]; /* Longer than %.16f in decimal */
REAL_t tmp;
int ret;
if(real_body_len < sizeof(scratch)) {
tmp.buf = scratch;
tmp.size = real_body_len;
} else {
/* This rarely happens: impractically long value */
tmp.buf = CALLOC(1, real_body_len + 1);
tmp.size = real_body_len;
if(!tmp.buf) {
ASN__DECODE_FAILED;
}
}
memcpy(tmp.buf, ptr, real_body_len);
tmp.buf[real_body_len] = '\0';
ret = asn_REAL2double(&tmp, &d);
if(tmp.buf != scratch) FREEMEM(tmp.buf);
if(ret) {
ASN_DEBUG("REAL decoded in %zu bytes, but can't convert t double",
real_body_len);
ASN__DECODE_FAILED;
}
}
if(!(st = *sptr)) {
st = (double *)(*sptr = CALLOC(1, sizeof(*st)));
if(!st) ASN__DECODE_FAILED;
}
*st = d;
ok.consumed = len_len + real_body_len;
return ok;
}
#endif /* ASN_DISABLE_OER_SUPPORT */
/* /*
* Decode the chunk of XML text encoding REAL. * Decode the chunk of XML text encoding REAL.
*/ */
...@@ -426,10 +509,18 @@ asn_random_fill_result_t ...@@ -426,10 +509,18 @@ asn_random_fill_result_t
NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
const asn_encoding_constraints_t *constraints, const asn_encoding_constraints_t *constraints,
size_t max_length) { size_t max_length) {
asn_random_fill_result_t result_ok = {ARFILL_OK, 1}; asn_random_fill_result_t result_ok = {ARFILL_OK, sizeof(double)};
asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
static const double values[] = {0, -0.0, -1, 1, INFINITY, -INFINITY, NAN}; static const double values[] = {
0, -0.0, -1, 1, -M_E, M_E, -3.14, 3.14, -M_PI, M_PI, -255, 255,
/* 2^51 */
-2251799813685248.0, 2251799813685248.0,
/* 2^52 */
-4503599627370496.0, 4503599627370496.0,
/* 2^100 */
-1267650600228229401496703205376.0, 1267650600228229401496703205376.0,
-MAXFLOAT, MAXFLOAT, INFINITY, -INFINITY, NAN};
double *st; double *st;
double d; double d;
...@@ -451,6 +542,5 @@ NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, ...@@ -451,6 +542,5 @@ NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
*st = d; *st = d;
result_ok.length = sizeof(double);
return result_ok; return result_ok;
} }
...@@ -25,10 +25,12 @@ asn_struct_print_f NativeReal_print; ...@@ -25,10 +25,12 @@ asn_struct_print_f NativeReal_print;
asn_struct_compare_f NativeReal_compare; asn_struct_compare_f NativeReal_compare;
ber_type_decoder_f NativeReal_decode_ber; ber_type_decoder_f NativeReal_decode_ber;
der_type_encoder_f NativeReal_encode_der; der_type_encoder_f NativeReal_encode_der;
xer_type_decoder_f NativeReal_decode_xer;
xer_type_encoder_f NativeReal_encode_xer;
per_type_decoder_f NativeReal_decode_uper; per_type_decoder_f NativeReal_decode_uper;
per_type_encoder_f NativeReal_encode_uper; per_type_encoder_f NativeReal_encode_uper;
oer_type_decoder_f NativeReal_decode_oer;
oer_type_encoder_f NativeReal_encode_oer;
xer_type_decoder_f NativeReal_decode_xer;
xer_type_encoder_f NativeReal_encode_xer;
asn_random_fill_f NativeReal_random_fill; asn_random_fill_f NativeReal_random_fill;
#define NativeReal_constraint asn_generic_no_constraint #define NativeReal_constraint asn_generic_no_constraint
......
...@@ -127,7 +127,7 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key) ...@@ -127,7 +127,7 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key)
char local_buf[64]; char local_buf[64];
char *buf = local_buf; char *buf = local_buf;
ssize_t buflen = sizeof(local_buf); ssize_t buflen = sizeof(local_buf);
const char *fmt = canonical?"%.15E":"%.15f"; const char *fmt = canonical ? "%.17E" /* Precise */ : "%.15f" /* Pleasant*/;
ssize_t ret; ssize_t ret;
/* /*
...@@ -522,7 +522,6 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { ...@@ -522,7 +522,6 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
return -1; return -1;
} }
/* 1. By contract, an input buffer should be '\0'-terminated. /* 1. By contract, an input buffer should be '\0'-terminated.
* OCTET STRING decoder ensures that, as is asn_double2REAL(). * OCTET STRING decoder ensures that, as is asn_double2REAL().
* 2. ISO 6093 specifies COMMA as a possible decimal separator. * 2. ISO 6093 specifies COMMA as a possible decimal separator.
...@@ -574,7 +573,7 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { ...@@ -574,7 +573,7 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
*/ */
{ {
double m; double m;
int expval; /* exponent value */ int32_t expval; /* exponent value */
unsigned int elen; /* exponent value length, in octets */ unsigned int elen; /* exponent value length, in octets */
int scaleF; int scaleF;
int baseF; int baseF;
...@@ -615,6 +614,10 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { ...@@ -615,6 +614,10 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
/* Fetch the multibyte exponent */ /* Fetch the multibyte exponent */
expval = (int)(*(int8_t *)ptr); expval = (int)(*(int8_t *)ptr);
if(elen >= sizeof(expval)-1) {
errno = ERANGE;
return -1;
}
end = ptr + elen + 1; end = ptr + elen + 1;
for(ptr++; ptr < end; ptr++) for(ptr++; ptr < end; ptr++)
expval = (expval * 256) + *ptr; expval = (expval * 256) + *ptr;
...@@ -627,8 +630,8 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { ...@@ -627,8 +630,8 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
m = ldexp(m, 8) + *ptr; m = ldexp(m, 8) + *ptr;
if(0) if(0)
ASN_DEBUG("m=%.10f, scF=%d, bF=%d, expval=%d, ldexp()=%f, ldexp()=%f\n", ASN_DEBUG("m=%.10f [%08llx], scF=%d, bF=%d, expval=%d, ldexp()=%f, ldexp()=%f\n",
m, scaleF, baseF, expval, m, *(uint64_t*)&m, scaleF, baseF, expval,
ldexp(m, expval * baseF + scaleF), ldexp(m, expval * baseF + scaleF),
ldexp(m, scaleF) * pow(pow(2, baseF), expval) ldexp(m, scaleF) * pow(pow(2, baseF), expval)
); );
...@@ -636,7 +639,7 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { ...@@ -636,7 +639,7 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
/* /*
* (S * N * 2^F) * B^E * (S * N * 2^F) * B^E
* Essentially: * Essentially:
m = ldexp(m, scaleF) * pow(pow(2, base), expval); m = ldexp(m, scaleF) * pow(pow(2, baseF), expval);
*/ */
m = ldexp(m, expval * baseF + scaleF); m = ldexp(m, expval * baseF + scaleF);
if(asn_isfinite(m)) { if(asn_isfinite(m)) {
...@@ -856,7 +859,15 @@ REAL_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, ...@@ -856,7 +859,15 @@ REAL_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
asn_random_fill_result_t result_ok = {ARFILL_OK, 1}; asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
static const double values[] = {0, -0.0, -1, 1, INFINITY, -INFINITY, NAN}; static const double values[] = {
0, -0.0, -1, 1, -M_E, M_E, -3.14, 3.14, -M_PI, M_PI, -255, 255,
/* 2^51 */
-2251799813685248.0, 2251799813685248.0,
/* 2^52 */
-4503599627370496.0, 4503599627370496.0,
/* 2^100 */
-1267650600228229401496703205376.0, 1267650600228229401496703205376.0,
-MAXFLOAT, MAXFLOAT, INFINITY, -INFINITY, NAN};
REAL_t *st; REAL_t *st;
double d; double d;
...@@ -887,3 +898,4 @@ REAL_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, ...@@ -887,3 +898,4 @@ REAL_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
result_ok.length = st->size; result_ok.length = st->size;
return result_ok; return result_ok;
} }
-- Test the REAL (floating point) type.
T ::= REAL
-- Test encoding/decoding/transcoding of everything concerning the BIT STRING.
T ::= BIT STRING { foo(0) }
T ::= BIT STRING { foo(0) } (SIZE(0..1))
T ::= BIT STRING { foo(0) } (SIZE(1))
T ::= BIT STRING { foo(0) } (SIZE(1..MAX))
T ::= BIT STRING { foo(0) } (SIZE(1..2))
T ::= BIT STRING { foo(0) } (SIZE(2))
T ::= BIT STRING { foo(0) } (SIZE(2,...))
T ::= BIT STRING { foo(0), bar(65535) }
T ::= BIT STRING { foo(0), bar(65535) } (SIZE(0..16))
T ::= BIT STRING { foo(0), bar(65535) } (SIZE(16))
T ::= BIT STRING { foo(0), bar(2147483647) }
T ::= BIT STRING { foo(0), bar(2147483647) } (SIZE(1..MAX))
T ::= BIT STRING { foo(2147483648), bar(0), baz(2147483647) }
T ::= BIT STRING { foo(2147483648), baz(2147483647) }
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(32))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(31,...))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..32))
T ::= BIT STRING { foo(2147483648), baz(2147483647) } (SIZE(0..31,...))
T ::= BIT STRING { foo(0) } (SIZE(65535)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65536)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65537)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65535,...)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65536,...)) -- RMAX=65540
T ::= BIT STRING { foo(0) } (SIZE(65537,...)) -- RMAX=65540
-- Test encoding/decoding/transcoding of a primitive byte string type
T ::= OCTET STRING
T ::= OCTET STRING ("Value Constraint")
T ::= OCTET STRING (SIZE(0))
T ::= OCTET STRING (SIZE(0,...))
T ::= OCTET STRING (SIZE(1))
T ::= OCTET STRING (SIZE(1,...))
T ::= OCTET STRING (SIZE(2))
T ::= OCTET STRING (SIZE(2,...))
T ::= OCTET STRING (SIZE(1..2))
T ::= OCTET STRING (SIZE(1..2,...))
T ::= OCTET STRING (SIZE(1..127))
T ::= OCTET STRING (SIZE(1..128))
T ::= OCTET STRING (SIZE(1..129))
T ::= OCTET STRING (SIZE(64000)) -- RMAX=64000, #11.9.3.3
T ::= OCTET STRING (SIZE(32000..32002)) -- RMAX=33000
T ::= OCTET STRING (SIZE(65530..65535)) -- RMAX=65536
T ::= OCTET STRING (SIZE(65530..65536)) -- RMAX=65536
T ::= OCTET STRING (SIZE(65535..65550)) -- RMAX=66000
-- Test encoding/decoding/transcoding of a simple string type
T ::= VisibleString
T ::= VisibleString ("Value Constraint")
T ::= VisibleString (SIZE(0))
T ::= VisibleString (SIZE(0,...))
T ::= VisibleString (SIZE(1))
T ::= VisibleString (SIZE(1)) (FROM("A".."B"))
T ::= VisibleString (SIZE(1,...))
T ::= VisibleString (SIZE(2))
T ::= VisibleString (SIZE(2,...))
T ::= VisibleString (SIZE(1..2))
T ::= VisibleString (SIZE(1..2,...))
T ::= VisibleString (SIZE(4..6,...)) (FROM("A".."B"))
T ::= VisibleString (SIZE(1..MAX)) (FROM("A".."B"))
T ::= VisibleString (SIZE(1..127))
T ::= VisibleString (SIZE(1..128))
T ::= VisibleString (SIZE(1..129))
T ::= VisibleString (SIZE(5) INTERSECTION FROM("A".."Z"))
T ::= VisibleString (SIZE(4..6) INTERSECTION (FROM("A".."B")))
T ::= VisibleString (SIZE(4..6,...) INTERSECTION (FROM("A".."B")))
T ::= VisibleString (SIZE(64000)) -- RMAX=64000, #11.9.3.3
T ::= VisibleString (SIZE(32000..32002)) -- RMAX=33000
T ::= VisibleString (SIZE(32000..32002)) (FROM("A".."B")) -- RMAX=33000
T ::= VisibleString (SIZE(32000..32002,...)) (FROM("A".."B")) -- RMAX=33000
T ::= VisibleString (SIZE(65530..65535)) -- RMAX=65536
T ::= VisibleString (SIZE(65530..65536)) -- RMAX=65536
T ::= VisibleString (SIZE(65535..65550)) -- RMAX=66000
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