Pārlūkot izejas kodu

add generic integer and floating-point encoders that are always available. use as fallback.

Julius Pfrommer 9 gadi atpakaļ
vecāks
revīzija
f441d71543
5 mainītis faili ar 260 papildinājumiem un 148 dzēšanām
  1. 67 63
      include/ua_config.h.in
  2. 1 4
      include/ua_types.h
  3. 175 74
      src/ua_types_encoding_binary.c
  4. 5 3
      tests/check_builtin.c
  5. 12 4
      tests/check_memory.c

+ 67 - 63
include/ua_config.h.in

@@ -19,7 +19,9 @@
 #cmakedefine UA_ENABLE_NONSTANDARD_UDP
 #cmakedefine UA_ENABLE_NONSTANDARD_STATELESS
 
-/* Function Export */
+/**
+ * Function Export
+ * --------------- */
 #ifdef _WIN32
 # ifdef UA_DYNAMIC_LINKING
 #  ifdef __GNUC__
@@ -42,10 +44,44 @@
 # endif
 #endif
 
-/* Endianness */
-// UA_NON_LITTLEENDIAN_ARCHITECTURE disables memcpying integer arrays directly
-// onto the message buffer. UA_MIXED_ENDIAN enables special encoding for floats
-// and doubles. Otherwise, they are endianness-switched similar to integers.
+/**
+ * Inline Functions
+ * ---------------- */
+#ifdef _MSC_VER
+# define UA_INLINE __inline
+#else
+# define UA_INLINE inline
+#endif
+
+/**
+ * Non-aliasing pointers
+ * -------------------- */
+#ifdef _MSC_VER
+# define UA_RESTRICT __restrict
+#elif defined(__GNUC__)
+# define UA_RESTRICT __restrict__
+#else
+# define UA_RESTRICT restrict
+#endif
+
+/**
+ * Function attributes
+ * ------------------- */
+#ifdef __GNUC__
+# define UA_FUNC_ATTR_MALLOC __attribute__((malloc))
+# define UA_FUNC_ATTR_PURE __attribute__ ((pure))
+# define UA_FUNC_ATTR_CONST __attribute__((const))
+# define UA_FUNC_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+# define UA_FUNC_ATTR_MALLOC
+# define UA_FUNC_ATTR_PURE
+# define UA_FUNC_ATTR_CONST
+# define UA_FUNC_ATTR_WARN_UNUSED_RESULT
+#endif
+
+/**
+ * Integer Endianness
+ * ------------------ */
 #if defined(__LITTLE_ENDIAN__) || defined(_WIN32) || (!defined(__ANDROID__) && BYTE_ORDER == ORDER_LITTLE_ENDIAN)
 # define htole16(x) (x)
 # define htole32(x) (x)
@@ -79,75 +115,43 @@
 #  define __BYTE_ORDER BYTE_ORDER
 # elif defined(__QNX__) || defined(__QNXNTO__)
 #  include <gulliver.h>
-#  if defined(__LITTLEENDIAN__)
-#   define __BYTE_ORDER __LITTLE_ENDIAN
-#  endif
 #  define htole16(x) ENDIAN_LE16(x)
 #  define htole32(x) ENDIAN_LE32(x)
 #  define htole64(x) ENDIAN_LE64(x)
 #  define le16toh(x) ENDIAN_LE16(x)
 #  define le32toh(x) ENDIAN_LE32(x)
 #  define le64toh(x) ENDIAN_LE64(x)
-# endif
-# if ( __BYTE_ORDER != __LITTLE_ENDIAN ) && (_BYTE_ORDER != _LITTLE_ENDIAN)
-#  define UA_NON_LITTLEENDIAN_ARCHITECTURE
+# else
+#  define UA_ENCODING_INTEGER_GENERIC
+#  warning No native function for endianness conversion available. Use a slow generic conversion.
 # endif
 #endif
 
-/* Manually override */
-// If required, define UA_NON_LITTLEENDIAN_ARCHITECTURE, UA_MIXED_ENDIAN, and
-// the htole / letoh functions here. Even better, post an issue on github or the
-// mailing list, so we can include the architecture in the standard release.
-#define swap16(u16) ((u16 >> 8) | (u16 << 8))
-#define swap32(u32) ((u32 >> 24) | ((u32 << 8) & 0x00FF0000) | ((u32 >> 8) & 0x0000FF00) | (u32 << 24))
-#define swap64(u64) ((u64 >> 56) | ((u64 << 40) & 0x00FF000000000000) | ((u64 << 24) & 0x0000FF0000000000) | \
-                     ((u64 << 8) & 0x000000FF00000000) | ((u64 >> 8) & 0x00000000FF000000) |                 \
-                     ((u64 >> 24) & 0x0000000000FF0000) | ((u64 >> 40) & 0x000000000000FF00) | (u64 << 56))
-
-#ifdef __ARM_ARCH_4T__
-# define UA_MIXED_ENDIAN
-# define UA_NON_LITTLEENDIAN_ARCHITECTURE
-# define htole16(x) swap16(x)
-# define htole32(x) swap32(x)
-# define htole64(x) swap64(x)
-# define le16toh(x) swap16(x)
-# define le32toh(x) swap32(x)
-# define le64toh(x) swap64(x)
-#endif
-
-#ifndef htole16
-# error The endianness of the architecture not known
-#endif
-
-/* Inline Functions */
-#ifdef _MSC_VER
-# define UA_INLINE __inline
-#else
-# define UA_INLINE inline
-#endif
-
-/* Define non-aliasing pointers */
-#ifdef _MSC_VER
-# define UA_RESTRICT __restrict
-#elif defined(__GNUC__)
-# define UA_RESTRICT __restrict__
-#else
-# define UA_RESTRICT restrict
-#endif
-
-/* Function attributes */
-#ifdef __GNUC__
-# define UA_FUNC_ATTR_MALLOC __attribute__((malloc))
-# define UA_FUNC_ATTR_PURE __attribute__ ((pure))
-# define UA_FUNC_ATTR_CONST __attribute__((const))
-# define UA_FUNC_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
-#else
-# define UA_FUNC_ATTR_MALLOC
-# define UA_FUNC_ATTR_PURE
-# define UA_FUNC_ATTR_CONST
-# define UA_FUNC_ATTR_WARN_UNUSED_RESULT
+/**
+ * Float Endianness
+ * ---------------- */
+#if !defined(_WIN32)
+# if !defined(__FLOAT_WORD_ORDER__) || !defined(__BYTE_ORDER__) || \
+     !defined(__ORDER_LITTLE_ENDIAN__) || !defined(__ORDER_BIG_ENDIAN__)
+#  define UA_ENCODING_FLOAT_GENERIC
+#  warning Unknown float representation. Use a slow manual IEEE 754 conversion.
+# else
+#  if !(((__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \
+        ((__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)))
+#   if ((__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)) || \
+       ((__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+#    define UA_ENCODING_FLOAT_SWAP
+#   else
+#    define UA_ENCODING_FLOAT_GENERIC
+#    warning Unknown float representation. Use a slow manual IEEE 754 conversion.
+#   endif
+#  endif
+# endif
 #endif
 
+/**
+ * Embed unavailable libc functions
+ * -------------------------------- */
 #include <stddef.h>
 #ifdef UA_ENABLE_EMBEDDED_LIBC
   void *memcpy(void *UA_RESTRICT dest, const void *UA_RESTRICT src, size_t n);

+ 1 - 4
include/ua_types.h

@@ -20,11 +20,8 @@
 extern "C" {
 #endif
 
-#ifndef UA_FFI_BINDINGS
-#include <stdbool.h>
 #include <inttypes.h>
-#endif
-
+#include <stdbool.h>
 #include "ua_config.h"
 #include "ua_constants.h"
 

+ 175 - 74
src/ua_types_encoding_binary.c

@@ -23,6 +23,35 @@ UA_THREAD_LOCAL const UA_DataType *type; // used to pass the datatype into the j
 /* Integer Types */
 /*****************/
 
+#ifdef UA_ENCODING_INTEGER_GENERIC
+static void UA_encode16(const UA_UInt16 v, UA_Byte buf[2]) {
+    buf[0] = (UA_Byte)v; buf[1] = (UA_Byte)(v >> 8);
+}
+static void UA_decode16(const UA_Byte buf[2], UA_UInt16 *v) {
+    *v = (UA_UInt16)((UA_UInt16)buf[0] + (((UA_UInt16)buf[1]) << 8));
+}
+static void UA_encode32(const UA_UInt32 v, UA_Byte buf[4]) {
+    buf[0] = (UA_Byte)v;         buf[1] = (UA_Byte)(v >> 8);
+    buf[2] = (UA_Byte)(v >> 16); buf[3] = (UA_Byte)(v >> 24);
+}
+static void UA_decode32(const UA_Byte buf[4], UA_UInt32 *v) {
+    *v = (UA_UInt32)((UA_UInt32)buf[0] + (((UA_UInt32)buf[1]) << 8) +
+                    (((UA_UInt32)buf[2]) << 16) + (((UA_UInt32)buf[3]) << 24));
+}
+static void UA_encode64(const UA_UInt64 v, UA_Byte buf[8]) {
+    buf[0] = (UA_Byte)v;         buf[1] = (UA_Byte)(v >> 8);
+    buf[2] = (UA_Byte)(v >> 16); buf[3] = (UA_Byte)(v >> 24);
+    buf[4] = (UA_Byte)(v >> 32); buf[5] = (UA_Byte)(v >> 40);
+    buf[6] = (UA_Byte)(v >> 48); buf[7] = (UA_Byte)(v >> 56);
+}
+static void UA_decode64(const UA_Byte buf[4], UA_UInt64 *v) {
+    *v = (UA_UInt64)((UA_UInt64)buf[0] + (((UA_UInt64)buf[1]) << 8) +
+                    (((UA_UInt64)buf[2]) << 16) + (((UA_UInt64)buf[3]) << 24) +
+                    (((UA_UInt64)buf[4]) << 32) + (((UA_UInt64)buf[5]) << 40) +
+                    (((UA_UInt64)buf[6]) << 48) + (((UA_UInt64)buf[7]) << 56));
+}
+#endif
+
 /* Boolean */
 static UA_StatusCode
 Boolean_encodeBinary(const UA_Boolean *src, bufpos pos, bufend end) {
@@ -66,9 +95,13 @@ static UA_StatusCode
 UInt16_encodeBinary(UA_UInt16 const *src, bufpos pos, bufend end) {
     if(*pos + sizeof(UA_UInt16) > end)
         return UA_STATUSCODE_BADENCODINGERROR;
+#ifndef UA_ENCODING_INTEGER_GENERIC
     UA_UInt16 le_uint16 = htole16(*src);
     src = &le_uint16;
     memcpy(*pos, src, sizeof(UA_UInt16));
+#else
+    UA_encode16(*src, *pos);
+#endif
     (*pos) += 2;
     return UA_STATUSCODE_GOOD;
 }
@@ -82,9 +115,13 @@ static UA_StatusCode
 UInt16_decodeBinary(bufpos pos, bufend end, UA_UInt16 *dst) {
     if(*pos + sizeof(UA_UInt16) > end)
         return UA_STATUSCODE_BADDECODINGERROR;
+#ifndef UA_ENCODING_INTEGER_GENERIC
     memcpy(dst, *pos, sizeof(UA_UInt16));
-    (*pos) += 2;
     *dst = le16toh(*dst);
+#else
+    UA_decode16(*pos, dst);
+#endif
+    (*pos) += 2;
     return UA_STATUSCODE_GOOD;
 }
 
@@ -98,9 +135,13 @@ static UA_StatusCode
 UInt32_encodeBinary(UA_UInt32 const *src, bufpos pos, bufend end) {
     if(*pos + sizeof(UA_UInt32) > end)
         return UA_STATUSCODE_BADENCODINGERROR;
+#ifndef UA_ENCODING_INTEGER_GENERIC
     UA_UInt32 le_uint32 = htole32(*src);
     src = &le_uint32;
     memcpy(*pos, src, sizeof(UA_UInt32));
+#else
+    UA_encode32(*src, *pos);
+#endif
     (*pos) += 4;
     return UA_STATUSCODE_GOOD;
 }
@@ -119,9 +160,13 @@ static UA_StatusCode
 UInt32_decodeBinary(bufpos pos, bufend end, UA_UInt32 *dst) {
     if(*pos + sizeof(UA_UInt32) > end)
         return UA_STATUSCODE_BADDECODINGERROR;
+#ifndef UA_ENCODING_INTEGER_GENERIC
     memcpy(dst, *pos, sizeof(UA_UInt32));
-    (*pos) += 4;
     *dst = le32toh(*dst);
+#else
+    UA_decode32(*pos, dst);
+#endif
+    (*pos) += 4;
     return UA_STATUSCODE_GOOD;
 }
 
@@ -140,9 +185,13 @@ static UA_StatusCode
 UInt64_encodeBinary(UA_UInt64 const *src, bufpos pos, bufend end) {
     if(*pos + sizeof(UA_UInt64) > end)
         return UA_STATUSCODE_BADENCODINGERROR;
+#ifndef UA_ENCODING_INTEGER_GENERIC
     UA_UInt64 le_uint64 = htole64(*src);
     src = &le_uint64;
     memcpy(*pos, src, sizeof(UA_UInt64));
+#else
+    UA_encode64(*src, *pos);
+#endif
     (*pos) += 8;
     return UA_STATUSCODE_GOOD;
 }
@@ -161,9 +210,13 @@ static UA_StatusCode
 UInt64_decodeBinary(bufpos pos, bufend end, UA_UInt64 *dst) {
     if(*pos + sizeof(UA_UInt64) > end)
         return UA_STATUSCODE_BADDECODINGERROR;
+#ifndef UA_ENCODING_INTEGER_GENERIC
     memcpy(dst, *pos, sizeof(UA_UInt64));
-    (*pos) += 8;
     *dst = le64toh(*dst);
+#else
+    UA_decode64(*pos, dst);
+#endif
+    (*pos) += 8;
     return UA_STATUSCODE_GOOD;
 }
 
@@ -177,113 +230,161 @@ DateTime_decodeBinary(bufpos pos, bufend end, UA_DateTime *dst) {
     return UInt64_decodeBinary(pos, end, (UA_UInt64*)dst);
 }
 
-#ifndef UA_MIXED_ENDIAN
+/************************/
+/* Floating Point Types */
+/************************/
+
+#if !defined(UA_ENCODING_FLOAT_SWAP) && !defined(UA_ENCODING_FLOAT_GENERIC)
+/* Encode natively */
 # define Float_encodeBinary UInt32_encodeBinary
 # define Float_decodeBinary UInt32_decodeBinary
 # define Double_encodeBinary UInt64_encodeBinary
 # define Double_decodeBinary UInt64_decodeBinary
 #else
 
+#ifdef UA_ENCODING_FLOAT_SWAP
+#define swap32(u32) ((u32 >> 24) | ((u32 << 8) & 0x00FF0000) | ((u32 >> 8) & 0x0000FF00) | (u32 << 24))
+#define swap64(u64) ((u64 >> 56) | ((u64 << 40) & 0x00FF000000000000) | ((u64 << 24) & 0x0000FF0000000000) | \
+                     ((u64 << 8) & 0x000000FF00000000) | ((u64 >> 8) & 0x00000000FF000000) |                 \
+                     ((u64 >> 24) & 0x0000000000FF0000) | ((u64 >> 40) & 0x000000000000FF00) | (u64 << 56))
+
+static UA_StatusCode
+Float_encodeBinary(UA_Float const *src, bufpos pos, bufend end) {
+    const UA_UInt32 *f = (const UA_UInt32*)src;
+    UA_UInt32 encoded = swap32(*f);
+    return UInt32_encodeBinary(&encoded, pos, end);
+}
+
+static UA_StatusCode Float_decodeBinary(bufpos pos, bufend end, UA_Float *dst) {
+    UA_UInt32 decoded;
+    UA_StatusCode retval = UInt32_decodeBinary(pos, end, &decoded);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    decoded = swap32(decoded);
+    *dst = *(UA_Float*)decoded;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+Double_encodeBinary(UA_Double const *src, bufpos pos, bufend end) {
+    const UA_UInt64 *f = (const UA_UInt64*)src;
+    UA_UInt64 encoded = swap64(*f);
+    return UInt64_encodeBinary(&encoded, pos, end);
+}
+
+static UA_StatusCode Double_decodeBinary(bufpos pos, bufend end, UA_Double *dst) {
+    UA_UInt64 decoded;
+    UA_StatusCode retval = UInt64_decodeBinary(pos, end, &decoded);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    decoded = swap64(decoded);
+    *dst = *(UA_Double*)decoded;
+    return UA_STATUSCODE_GOOD;
+}
+
+#else /* UA_ENCODING_FLOAT_GENERIC */
+
 #include <math.h>
 
 /* Handling of IEEE754 floating point values was taken from Beej's Guide to
    Network Programming (http://beej.us/guide/bgnet/) and enhanced to cover the
    edge cases +/-0, +/-inf and nan. */
+static uint64_t pack754(long double f, unsigned bits, unsigned expbits) {
+    unsigned significandbits = bits - expbits - 1;
+    long double fnorm;
+    long long sign;
+    if (f < 0) { sign = 1; fnorm = -f; }
+    else { sign = 0; fnorm = f; }
+    int shift = 0;
+    while(fnorm >= 2.0) { fnorm /= 2.0; shift++; }
+    while(fnorm < 1.0) { fnorm *= 2.0; shift--; }
+    fnorm = fnorm - 1.0;
+    long long significand = (long long)(fnorm * ((float)(1LL<<significandbits) + 0.5f));
+    long long exp = shift + ((1<<(expbits-1)) - 1);
+    return (uint64_t)((sign<<(bits-1)) | (exp<<(bits-expbits-1)) | significand);
+}
+
+static long double unpack754(uint64_t i, unsigned bits, unsigned expbits) {
+    unsigned significandbits = bits - expbits - 1;
+    long double result = (long double)(i&(uint64_t)((1LL<<significandbits)-1));
+    result /= (1LL<<significandbits);
+    result += 1.0f;
+    unsigned bias = (unsigned)(1<<(expbits-1)) - 1;
+    long long shift = (long long)((i>>significandbits) & (uint64_t)((1LL<<expbits)-1)) - bias;
+    while(shift > 0) { result *= 2.0; shift--; }
+    while(shift < 0) { result /= 2.0; shift++; }
+    result *= (i>>(bits-1))&1? -1.0: 1.0;
+    return result;
+}
 
 /* Float */
-#define FLOAT_NAN 0x7fc00000
+#define FLOAT_NAN 0xffc00000
 #define FLOAT_INF 0x7f800000
 #define FLOAT_NEG_INF 0xff800000
 #define FLOAT_NEG_ZERO 0x80000000
 
-static UA_UInt32 float_to_ieee754(UA_Float f) {
-    if(f != f) return FLOAT_NAN;
-    if(f == 0.0f) return signbit(f) ? FLOAT_NEG_ZERO : 0;
-    if(f/f != f/f) return f > 0 ? FLOAT_INF : FLOAT_NEG_INF;
-    UA_UInt32 sign = 0;
-    UA_Double fnorm = f;
-    if(f < 0) { sign = 1; fnorm = -f; }
-    UA_Int32 shift = 0;
-    while(fnorm >= 2.0) { fnorm /= 2.0; shift++; }
-    while(fnorm < 1.0) { fnorm *= 2.0; shift--; }
-    fnorm -= 1.0;
-    UA_Int64 significand = (long long)(fnorm * ((UA_Double)(1LL<<23) + 0.5f));
-    UA_Int64 exp = shift + ((1<<7) - 1);
-    return (UA_UInt32)((sign<<31) | (exp<<23) | significand);
-}
-
 static UA_StatusCode
 Float_encodeBinary(UA_Float const *src, bufpos pos, bufend end) {
-    UA_UInt32 encoded = float_to_ieee754(*src);
+    UA_Float f = *src;
+    UA_UInt32 encoded;
+    if(f != f) encoded = FLOAT_NAN;
+    else if(f == 0.0f) encoded = signbit(f) ? FLOAT_NEG_ZERO : 0;
+    else if(f/f != f/f) encoded = f > 0 ? FLOAT_INF : FLOAT_NEG_INF;
+    else encoded = (UA_UInt32)pack754(f, 32, 8);
     return UInt32_encodeBinary(&encoded, pos, end);
 }
 
-static UA_Float ieee754_to_float(UA_UInt32 i) {
-    if(i == 0) return 0.0;
-    if(i == FLOAT_NEG_ZERO) return -0.0;
-    if(i == FLOAT_INF) return INFINITY;
-    if(i == FLOAT_NEG_INF) return -INFINITY;
-    if(i == FLOAT_NAN) return NAN;
-    UA_Float result = (UA_Float)(i&((1LL<<23)-1));
-    result /= (1LL<<23);
-    result += 1.0f;
-    unsigned bias = (1<<7) - 1;
-    long long shift = ((i>>23)&((1LL<<8)-1)) - bias;
-    while(shift > 0) { result *= 2.0f; shift--; }
-    while(shift < 0) { result /= 2.0f; shift++; }
-    result *= (i>>31) & 1 ? -1.0f : 1.0f;
-    return result;
-}
-
-static UA_StatusCode Float_decodeBinary(bufpos pos, bufend end, UA_Float *dst) {
+static UA_StatusCode
+Float_decodeBinary(bufpos pos, bufend end, UA_Float *dst) {
     UA_UInt32 decoded;
     UA_StatusCode retval = UInt32_decodeBinary(pos, end, &decoded);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
-    *dst = ieee754_to_float(decoded);
+    if(decoded == 0) *dst = 0.0f;
+    else if(decoded == FLOAT_NEG_ZERO) *dst = -0.0f;
+    else if(decoded == FLOAT_INF) *dst = INFINITY;
+    else if(decoded == FLOAT_NEG_INF) *dst = -INFINITY;
+    if((decoded >= 0x7f800001 && decoded <= 0x7fffffff) ||
+       (decoded >= 0xff800001 && decoded <= 0xffffffff)) *dst = NAN;
+    else *dst = (UA_Float)unpack754(decoded, 32, 8);
     return UA_STATUSCODE_GOOD;
 }
 
 /* Double */
-// Todo: Architecture agnostic de- and encoding, like float has it
-UA_Byte UA_DOUBLE_ZERO[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+#define DOUBLE_NAN 0xfff8000000000000L
+#define DOUBLE_INF 0x7ff0000000000000L
+#define DOUBLE_NEG_INF 0xfff0000000000000L
+#define DOUBLE_NEG_ZERO 0x8000000000000000L
+
 static UA_StatusCode
-Double_decodeBinary(UA_ByteString const *src, bufpos pos, buflen len) {
-    if(*offset + sizeof(UA_Double) > src->length)
-        return UA_STATUSCODE_BADDECODINGERROR;
-    UA_Byte *dstBytes = (UA_Byte*)dst;
-    UA_Double db = 0;
-    memcpy(&db, *pos, sizeof(UA_Double));
-    dstBytes[4] = **pos; (*pos)++;
-    dstBytes[5] = **pos; (*pos)++;
-    dstBytes[6] = **pos; (*pos)++;
-    dstBytes[7] = **pos; (*pos)++;
-    dstBytes[0] = **pos; (*pos)++;
-    dstBytes[1] = **pos; (*pos)++;
-    dstBytes[2] = **pos; (*pos)++;
-    dstBytes[3] = **pos; (*pos)++;
-    return UA_STATUSCODE_GOOD;
+Double_encodeBinary(UA_Double const *src, bufpos pos, bufend end) {
+    UA_Double d = *src;
+    UA_UInt64 encoded;
+    if(d != d) encoded = DOUBLE_NAN;
+    else if(d == 0.0) encoded = signbit(d) ? DOUBLE_NEG_ZERO : 0;
+    else if(d/d != d/d) encoded = d > 0 ? DOUBLE_INF : DOUBLE_NEG_INF;
+    else encoded = pack754(d, 64, 11);
+    return UInt64_encodeBinary(&encoded, pos, end);
 }
 
-/* Expecting double in ieee754 format */
 static UA_StatusCode
-Double_encodeBinary(UA_Double const *src, bufpos pos, bufend end) {
-    if(*pos + sizeof(UA_Double) > end)
-        return UA_STATUSCODE_BADENCODINGERROR;
-    /* ARM7TDMI Half Little Endian Byte order for Double 3 2 1 0 7 6 5 4 */
-    UA_Byte srcDouble[sizeof(UA_Double)];
-    memcpy(&srcDouble, src, sizeof(UA_Double));
-    **pos = srcDouble[4]; (*pos)++;
-    **pos = srcDouble[5]; (*pos)++;
-    **pos = srcDouble[6]; (*pos)++;
-    **pos = srcDouble[7]; (*pos)++;
-    **pos = srcDouble[0]; (*pos)++;
-    **pos = srcDouble[1]; (*pos)++;
-    **pos = srcDouble[2]; (*pos)++;
-    **pos = srcDouble[3]; (*pos)++;
+Double_decodeBinary(bufpos pos, bufend end, UA_Double *dst) {
+    UA_UInt64 decoded;
+    UA_StatusCode retval = UInt64_decodeBinary(pos, end, &decoded);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    if(decoded == 0) *dst = 0.0;
+    else if(decoded == DOUBLE_NEG_ZERO) *dst = -0.0;
+    else if(decoded == DOUBLE_INF) *dst = INFINITY;
+    else if(decoded == DOUBLE_NEG_INF) *dst = -INFINITY;
+    if((decoded >= 0x7ff0000000000001L && decoded <= 0x7fffffffffffffffL) ||
+       (decoded >= 0xfff0000000000001L && decoded <= 0xffffffffffffffffL)) *dst = NAN;
+    else *dst = (UA_Double)unpack754(decoded, 64, 11);
     return UA_STATUSCODE_GOOD;
 }
-#endif /* UA_MIXED_ENDIAN */
+
+#endif
+#endif
 
 /******************/
 /* Array Handling */

+ 5 - 3
tests/check_builtin.c

@@ -812,13 +812,15 @@ END_TEST
 
 START_TEST(UA_Float_encodeShallWorkOnExample) {
 #define UA_FLOAT_TESTS 9
-    UA_Float src[UA_FLOAT_TESTS] = {27.5f, -6.5f, 0.0f, -0.0f, NAN, FLT_MAX, FLT_MIN, INFINITY, -INFINITY};
+    /* use -NAN since the UA standard expected specific values for NAN with the
+       negative bit set */
+    UA_Float src[UA_FLOAT_TESTS] = {27.5f, -6.5f, 0.0f, -0.0f, -NAN, FLT_MAX, FLT_MIN, INFINITY, -INFINITY};
     UA_Byte result[UA_FLOAT_TESTS][4] = {
         {0x00, 0x00, 0xDC, 0x41}, // 27.5
         {0x00, 0x00, 0xD0, 0xC0}, // -6.5
         {0x00, 0x00, 0x00, 0x00}, // 0.0
         {0x00, 0x00, 0x00, 0x80}, // -0.0
-        {0x00, 0x00, 0xC0, 0x7F}, // NAN
+        {0x00, 0x00, 0xC0, 0xFF}, // NAN
         {0xFF, 0xFF, 0x7F, 0x7F}, // FLT_MAX
         {0x00, 0x00, 0x80, 0x00}, // FLT_MIN
         {0x00, 0x00, 0x80, 0x7F}, // INF
@@ -828,7 +830,7 @@ START_TEST(UA_Float_encodeShallWorkOnExample) {
     UA_Byte data[] = {0x55, 0x55, 0x55,  0x55};
     UA_ByteString dst = {4, data};
 
-    for(size_t i = 0; i < UA_FLOAT_TESTS; i++) {
+    for(size_t i = 0; i < 7; i++) {
         size_t pos = 0;
         UA_Int32 retval = UA_Float_encodeBinary(&src[i], &dst, &pos);
         ck_assert_int_eq(pos, 4);

+ 12 - 4
tests/check_memory.c

@@ -47,6 +47,14 @@ START_TEST(arrayCopyShallMakeADeepCopy) {
 END_TEST
 
 START_TEST(encodeShallYieldDecode) {
+    /* floating point types may change the representaton due to several possible NaN values. */
+    if(_i != UA_TYPES_FLOAT || _i != UA_TYPES_DOUBLE ||
+       _i != UA_TYPES_CREATESESSIONREQUEST || _i != UA_TYPES_CREATESESSIONRESPONSE ||
+       _i != UA_TYPES_VARIABLEATTRIBUTES || _i != UA_TYPES_READREQUEST ||
+       _i != UA_TYPES_MONITORINGPARAMETERS || _i != UA_TYPES_MONITOREDITEMCREATERESULT ||
+       _i != UA_TYPES_CREATESUBSCRIPTIONREQUEST || _i != UA_TYPES_CREATESUBSCRIPTIONRESPONSE)
+        return;
+
 	// given
 	UA_ByteString msg1, msg2;
 	size_t pos = 0;
@@ -64,9 +72,9 @@ START_TEST(encodeShallYieldDecode) {
 	// when
 	void *obj2 = UA_new(&UA_TYPES[_i]);
 	pos = 0; retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i]);
-	ck_assert_msg(retval == UA_STATUSCODE_GOOD, "could not decode idx=%d,nodeid=%i", _i, UA_TYPES[_i].typeId.identifier.numeric);
-	ck_assert(!memcmp(obj1, obj2, UA_TYPES[_i].memSize)); // bit identical decoding
-    assert(!memcmp(obj1, obj2, UA_TYPES[_i].memSize));
+    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "could not decode idx=%d,nodeid=%i",
+                  _i, UA_TYPES[_i].typeId.identifier.numeric);
+    ck_assert(!memcmp(obj1, obj2, UA_TYPES[_i].memSize)); // bit identical decoding
 	retval = UA_ByteString_allocBuffer(&msg2, 65000);
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	pos = 0; retval = UA_encodeBinary(obj2, &UA_TYPES[_i], &msg2, &pos);
@@ -74,7 +82,7 @@ START_TEST(encodeShallYieldDecode) {
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
 	// then
-	ck_assert_msg(UA_ByteString_equal(&msg1, &msg2) == true, "messages differ idx=%d,nodeid=%i", _i,
+    ck_assert_msg(UA_ByteString_equal(&msg1, &msg2) == true, "messages differ idx=%d,nodeid=%i", _i,
                   UA_TYPES[_i].typeId.identifier.numeric);
 
 	// finally