Commit afcc891c authored by Lev Walkin's avatar Lev Walkin

add OER binary32 and binary64 IEEE-754 formats for native REAL type

parent cb5e1c7c
......@@ -1872,6 +1872,14 @@ emit_single_member_OER_constraint_value(arg_t *arg, asn1cnst_range_t *range) {
if(range->incompatible || range->not_OER_visible) {
OUT("{ 0, 0 }");
} else if(expr_get_type(arg, arg->expr) == ASN_BASIC_REAL) {
if(range->narrowing == NARROW_FLOAT32) {
OUT("{ sizeof(float), 0 }");
} else if(range->narrowing == NARROW_FLOAT64) {
OUT("{ sizeof(double), 0 }");
} else {
OUT("{ 0, 0 }");
}
} else if(range->left.type == ARE_VALUE && range->left.value >= 0
&& range->right.type == ARE_MAX) {
OUT("{ 0, 1 }");
......
......@@ -78,40 +78,12 @@ asn_TYPE_descriptor_t asn_DEF_NativeReal = {
0 /* No specifics */
};
static double
NativeReal__get_double(const asn_TYPE_descriptor_t *td, const void *ptr) {
const asn_NativeReal_specifics_t *specs =
(const asn_NativeReal_specifics_t *)td->specifics;
size_t float_size = specs ? specs->float_size : sizeof(double);
if(float_size == sizeof(float)) {
return *(const float *)ptr;
} else {
return *(const double *)ptr;
}
}
static ssize_t /* Returns -1 or float size. */
NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr, double d) {
const asn_NativeReal_specifics_t *specs =
(const asn_NativeReal_specifics_t *)td->specifics;
size_t float_size = specs ? specs->float_size : sizeof(double);
void *native;
if(!(native = *sptr)) {
native = (*sptr = CALLOC(1, float_size));
if(!native) {
return -1;
}
}
if(float_size == sizeof(float)) {
*(float *)native = d;
} else {
*(double *)native = d;
}
return float_size;
}
static double NativeReal__get_double(const asn_TYPE_descriptor_t *td,
const void *ptr);
static ssize_t NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr,
double d);
static void NativeReal__network_swap(size_t float_size, const void *srcp,
uint8_t *dst);
/*
* Decode REAL type.
......@@ -302,30 +274,61 @@ 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) {
double d = NativeReal__get_double(td, sptr);
asn_enc_rval_t er = { 0, 0, 0 };
ssize_t len_len;
REAL_t tmp;
asn_enc_rval_t er = {0, 0, 0};
if(!constraints) constraints = td->encoding_constraints.oer_constraints;
if(constraints && constraints->value.width != 0) {
/* X.696 IEEE 754 binary32 and binary64 encoding */
uint8_t scratch[sizeof(double)];
const asn_NativeReal_specifics_t *specs =
(const asn_NativeReal_specifics_t *)td->specifics;
size_t wire_size = constraints->value.width;
if(specs ? (wire_size == specs->float_size)
: (wire_size == sizeof(double))) {
/*
* Our representation matches the wire, modulo endianness.
* That was the whole point of compact encoding!
*/
} else {
assert(wire_size == sizeof(double)
|| specs && specs->float_size == wire_size);
ASN__ENCODE_FAILED;
}
/* Prepare a temporary clean structure */
memset(&tmp, 0, sizeof(tmp));
/*
* The X.696 standard doesn't specify endianness, neither is IEEE 754.
* So we assume the network format is big endian.
*/
NativeReal__network_swap(wire_size, sptr, scratch);
if(cb(scratch, wire_size, app_key) < 0) {
ASN__ENCODE_FAILED;
} else {
er.encoded = wire_size;
ASN__ENCODED_OK(er);
}
} else {
double d = NativeReal__get_double(td, sptr);
ssize_t len_len;
REAL_t tmp;
(void)td;
(void)constraints; /* Constraints are unused in OER */
/* Prepare a temporary clean structure */
memset(&tmp, 0, sizeof(tmp));
if(asn_double2REAL(&tmp, d)) {
ASN__ENCODE_FAILED;
}
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);
/* 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);
}
}
}
......@@ -340,7 +343,38 @@ NativeReal_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
size_t real_body_len;
(void)opt_codec_ctx;
(void)constraints; /* Constraints are unused in OER */
if(!constraints) constraints = td->encoding_constraints.oer_constraints;
if(constraints && constraints->value.width != 0) {
/* X.696 IEEE 754 binary32 and binary64 encoding */
uint8_t scratch[sizeof(double)];
size_t wire_size = constraints->value.width;
if(size < wire_size)
ASN__DECODE_STARVED;
/*
* The X.696 standard doesn't specify endianness, neither is IEEE 754.
* So we assume the network format is big endian.
*/
NativeReal__network_swap(wire_size, ptr, scratch);
switch(wire_size) {
case sizeof(double):
if(NativeReal__set(td, sptr, *(const double *)scratch) < 0)
ASN__DECODE_FAILED;
break;
case sizeof(float):
if(NativeReal__set(td, sptr, *(const float *)scratch) < 0)
ASN__DECODE_FAILED;
break;
default:
ASN__DECODE_FAILED;
}
ok.consumed = wire_size;
return ok;
}
len_len = oer_fetch_length(ptr, size, &real_body_len);
if(len_len < 0) ASN__DECODE_FAILED;
......@@ -541,3 +575,99 @@ NativeReal_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
result_ok.length = float_set_size;
return result_ok;
}
/*
* Local helper functions.
*/
static double
NativeReal__get_double(const asn_TYPE_descriptor_t *td, const void *ptr) {
const asn_NativeReal_specifics_t *specs =
(const asn_NativeReal_specifics_t *)td->specifics;
size_t float_size = specs ? specs->float_size : sizeof(double);
if(float_size == sizeof(float)) {
return *(const float *)ptr;
} else {
return *(const double *)ptr;
}
}
static ssize_t /* Returns -1 or float size. */
NativeReal__set(const asn_TYPE_descriptor_t *td, void **sptr, double d) {
const asn_NativeReal_specifics_t *specs =
(const asn_NativeReal_specifics_t *)td->specifics;
size_t float_size = specs ? specs->float_size : sizeof(double);
void *native;
if(!(native = *sptr)) {
native = (*sptr = CALLOC(1, float_size));
if(!native) {
return -1;
}
}
if(float_size == sizeof(float)) {
*(float *)native = d;
} else {
*(double *)native = d;
}
return float_size;
}
/*
* Swap bytes from/to network, if local is little-endian.
* Unused endianness sections are likely removed at compile phase.
*/
static void
NativeReal__network_swap(size_t float_size, const void *srcp, uint8_t *dst) {
const uint8_t *src = srcp;
double test = -0.0;
int float_big_endian = *(const char *)&test != 0;
/* In lieu of static_assert(sizeof(double) == 8) */
static const char sizeof_double_is_8_a[sizeof(double)-7] CC_NOTUSED;
static const char sizeof_double_is_8_b[9-sizeof(double)] CC_NOTUSED;
/* In lieu of static_assert(sizeof(sizeof) == 4) */
static const char sizeof_float_is_4_a[sizeof(float)-3] CC_NOTUSED;
static const char sizeof_float_is_4_b[5-sizeof(float)] CC_NOTUSED;
switch(float_size) {
case sizeof(double):
assert(sizeof(double) == 8);
if(float_big_endian) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
dst[4] = src[4];
dst[5] = src[5];
dst[6] = src[6];
dst[7] = src[7];
} else {
dst[0] = src[7];
dst[1] = src[6];
dst[2] = src[5];
dst[3] = src[4];
dst[4] = src[3];
dst[5] = src[2];
dst[6] = src[1];
dst[7] = src[0];
}
return;
case sizeof(float):
assert(sizeof(float) == 4);
if(float_big_endian) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
} else {
dst[0] = src[3];
dst[1] = src[2];
dst[2] = src[1];
dst[3] = src[0];
}
return;
}
}
......@@ -18,7 +18,7 @@ extern "C" {
#endif
typedef struct asn_NativeReal_specifics_s {
unsigned float_size; /* 4 for 'float', 8 for 'double'. */
unsigned float_size; /* sizeof(float) or sizeof(double) */
} asn_NativeReal_specifics_t;
extern asn_TYPE_descriptor_t asn_DEF_NativeReal;
......
......@@ -179,7 +179,7 @@ Indirect_IEEE_binary32_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
/*** <<< CTDEFS [Indirect-IEEE-binary32] >>> ***/
static asn_oer_constraints_t asn_OER_type_Indirect_IEEE_binary32_constr_1 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(float), 0 },
-1};
/*** <<< STAT-DEFS [Indirect-IEEE-binary32] >>> ***/
......@@ -257,7 +257,7 @@ IEEE_binary32_w_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
/*** <<< CTDEFS [IEEE-binary32-w] >>> ***/
static asn_oer_constraints_t asn_OER_type_IEEE_binary32_w_constr_1 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(float), 0 },
-1};
/*** <<< STAT-DEFS [IEEE-binary32-w] >>> ***/
......@@ -335,7 +335,7 @@ IEEE_binary32_0w_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
/*** <<< CTDEFS [IEEE-binary32-0w] >>> ***/
static asn_oer_constraints_t asn_OER_type_IEEE_binary32_0w_constr_1 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(float), 0 },
-1};
/*** <<< STAT-DEFS [IEEE-binary32-0w] >>> ***/
......@@ -413,7 +413,7 @@ IEEE_binary32_w0_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
/*** <<< CTDEFS [IEEE-binary32-w0] >>> ***/
static asn_oer_constraints_t asn_OER_type_IEEE_binary32_w0_constr_1 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(float), 0 },
-1};
/*** <<< STAT-DEFS [IEEE-binary32-w0] >>> ***/
......@@ -490,7 +490,7 @@ IEEE_binary64_w_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
/*** <<< CTDEFS [IEEE-binary64-w] >>> ***/
static asn_oer_constraints_t asn_OER_type_IEEE_binary64_w_constr_1 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(double), 0 },
-1};
/*** <<< STAT-DEFS [IEEE-binary64-w] >>> ***/
......@@ -564,7 +564,7 @@ IEEE_binary64_0w_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
/*** <<< CTDEFS [IEEE-binary64-0w] >>> ***/
static asn_oer_constraints_t asn_OER_type_IEEE_binary64_0w_constr_1 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(double), 0 },
-1};
/*** <<< STAT-DEFS [IEEE-binary64-0w] >>> ***/
......@@ -638,7 +638,7 @@ IEEE_binary64_w0_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
/*** <<< CTDEFS [IEEE-binary64-w0] >>> ***/
static asn_oer_constraints_t asn_OER_type_IEEE_binary64_w0_constr_1 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(double), 0 },
-1};
/*** <<< STAT-DEFS [IEEE-binary64-w0] >>> ***/
......@@ -794,16 +794,16 @@ ieee_binary32_w0_5_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
/*** <<< CTDEFS [Test] >>> ***/
static asn_oer_constraints_t asn_OER_type_indirect_ieee_binary32_constr_2 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(float), 0 },
-1};
static asn_oer_constraints_t asn_OER_type_ieee_binary32_w_constr_3 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(float), 0 },
-1};
static asn_oer_constraints_t asn_OER_type_ieee_binary32_0w_constr_4 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(float), 0 },
-1};
static asn_oer_constraints_t asn_OER_type_ieee_binary32_w0_constr_5 CC_NOTUSED = {
{ 0, 0 },
{ sizeof(float), 0 },
-1};
/*** <<< STAT-DEFS [Test] >>> ***/
......
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