Parcourir la source

remove return int32 when no errors are possible. add datasource handling to variant.

Julius Pfrommer il y a 10 ans
Parent
commit
7830febf5a

+ 88 - 66
include/ua_types.h

@@ -40,7 +40,10 @@ extern "C" {
  *     returned pointer.
  *
  * - <type>_copy: Copies a datatype. This performs a deep copy that iterates
- *    over the members.
+ *    over the members. The copy function assumes that the target structure can
+ *    be overwritten (do a deleteMembers before if necessary). With one
+ *    exception: copying into a variant that points to an external datasource is
+ *    not permitted.
  *
  * - <type>_delete: Frees the memory where the datatype was stored.
  *
@@ -64,13 +67,13 @@ extern "C" {
 
 /* Boolean values and null */
 #define UA_TRUE (42 == 42)
-//#define TRUE UA_TRUE
 #define UA_FALSE (!UA_TRUE)
-//#define FALSE UA_FALSE
 
 /* Compare values */
-#define UA_EQUAL 0
-#define UA_NOT_EQUAL (!UA_EQUAL)
+typedef enum UA_EQUALITY {
+    UA_EQUAL,
+    UA_NOT_EQUAL
+} UA_EQUALITY;
 
 /** @brief A two-state logical value (true or false). */
 typedef _Bool UA_Boolean;
@@ -199,24 +202,50 @@ typedef struct UA_ExtensionObject {
 struct UA_VTable_Entry; // forwards declaration
 typedef struct UA_VTable_Entry UA_VTable_Entry;
 
+/* Variant */
+/** @defgroup variant Variant
+ *
+ * @brief Variants may contain (arrays of) any other datatype.
+ *
+ * For that, we provide a reference to the utility functions of the type as well
+ * as possible encoding by pointing an entry in the vtable of types. References
+ * may either contain a structure with the variants data, or a datasource where
+ * this structure may be obtained (using reference counting for async access).
+ */
+
+typedef struct UA_VariantData {
+    UA_Int32  arrayLength;        // total number of elements in the data-pointer
+    void     *dataPtr;
+    UA_Int32  arrayDimensionsLength;
+    UA_Int32 *arrayDimensions;
+} UA_VariantData;
+
+typedef struct UA_VariantDataSource {
+    const void *identifier; // whatever id the datasource uses internally. Some provide custom get/write/release functions and don't use this.
+    UA_Int32 (*get)(const void *identifier, const UA_VariantData **); // get the variantdata provided by the datasource. when it is no longer used, it has to be relased.
+    UA_Int32 (*set)(const void **identifier, const UA_VariantData *); // replace the variant data in the datasource. and replace the identifier in the variant for lookups. The VariantData pointer shall no longer be used afterwards
+    void (*release)(const void *identifier, const UA_VariantData *); // release data after every get when the request is finished. so we can have async access to data and free it when the reference count drops to zero
+    void (*delete)(const void *identifier);
+} UA_VariantDataSource;
+
 /** @brief A union of all of the types specified above.
  *
  * Variants store (arrays of) built-in types. If you want to store a more
  * complex (or self-defined) type, you have to use an UA_ExtensionObject.*/
 typedef struct UA_Variant {
-    UA_VTable_Entry *vt;          // internal entry into vTable
-    UA_Int32  arrayLength;        // total number of elements
-    void     *data;
-    UA_Int32  arrayDimensionsLength;
-    UA_Int32 *arrayDimensions;
+    UA_VTable_Entry *vt; // internal entry into vTable
+    enum {
+        UA_VARIANT_DATA,
+        UA_VARIANT_DATA_NODELETE, // do not free the data (e.g. because it is "borrowed" and points into a larger structure)
+        UA_VARIANT_DATASOURCE
+    } storageType;
+    union {
+        UA_VariantData       data;
+        UA_VariantDataSource datasource;
+    } storage;
 } UA_Variant;
 
-/* VariantBinaryEncoding - Part: 6, Chapter: 5.2.2.16, Page: 22 */
-enum UA_VARIANT_ENCODINGMASKTYPE_enum {
-    UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3F,            // bits 0:5
-    UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS  = (0x01 << 6),     // bit 6
-    UA_VARIANT_ENCODINGMASKTYPE_ARRAY       = (0x01 << 7)      // bit 7
-};
+/** @endgroup */
 
 /** @brief A data value with an associated status code and timestamps. */
 typedef struct UA_DataValue {
@@ -268,19 +297,19 @@ typedef void UA_InvalidType;
 /*************/
 
 #ifdef DEBUG
-#define UA_TYPE_PROTOTYPES(TYPE)                      \
+#define UA_TYPE_PROTOTYPES(TYPE)                                   \
     UA_Int32 UA_LIBEXPORT TYPE##_new(TYPE **p);                    \
-    UA_Int32 UA_LIBEXPORT TYPE##_init(TYPE * p);                   \
-    UA_Int32 UA_LIBEXPORT TYPE##_delete(TYPE * p);                 \
-    UA_Int32 UA_LIBEXPORT TYPE##_deleteMembers(TYPE * p);          \
+    void UA_LIBEXPORT     TYPE##_init(TYPE * p);                   \
+    void UA_LIBEXPORT     TYPE##_delete(TYPE * p);                 \
+    void UA_LIBEXPORT     TYPE##_deleteMembers(TYPE * p);          \
     UA_Int32 UA_LIBEXPORT TYPE##_copy(const TYPE *src, TYPE *dst); \
-    void     UA_LIBEXPORT TYPE##_print(const TYPE *p, FILE *stream);
+    void UA_LIBEXPORT     TYPE##_print(const TYPE *p, FILE *stream);
 #else
-#define UA_TYPE_PROTOTYPES(TYPE)             \
+#define UA_TYPE_PROTOTYPES(TYPE)                          \
     UA_Int32 UA_LIBEXPORT TYPE##_new(TYPE **p);           \
-    UA_Int32 UA_LIBEXPORT TYPE##_init(TYPE * p);          \
-    UA_Int32 UA_LIBEXPORT TYPE##_delete(TYPE * p);        \
-    UA_Int32 UA_LIBEXPORT TYPE##_deleteMembers(TYPE * p); \
+    void UA_LIBEXPORT     TYPE##_init(TYPE * p);          \
+    void UA_LIBEXPORT     TYPE##_delete(TYPE * p);        \
+    void UA_LIBEXPORT     TYPE##_deleteMembers(TYPE * p); \
     UA_Int32 UA_LIBEXPORT TYPE##_copy(const TYPE *src, TYPE *dst);
 #endif
 
@@ -320,7 +349,7 @@ UA_TYPE_PROTOTYPES(UA_InvalidType)
 
 UA_Int32 UA_LIBEXPORT UA_String_copycstring(char const *src, UA_String *dst);
 UA_Int32 UA_LIBEXPORT UA_String_copyprintf(char const *fmt, UA_String *dst, ...);
-UA_Int32 UA_LIBEXPORT UA_String_equal(const UA_String *string1, const UA_String *string2);
+UA_EQUALITY UA_LIBEXPORT UA_String_equal(const UA_String *string1, const UA_String *string2);
 #ifdef DEBUG
 void UA_LIBEXPORT UA_String_printf(char const *label, const UA_String *string);
 void UA_LIBEXPORT UA_String_printx(char const *label, const UA_String *string);
@@ -344,10 +373,10 @@ UA_DateTimeStruct UA_LIBEXPORT UA_DateTime_toStruct(UA_DateTime time);
 UA_Int32 UA_LIBEXPORT UA_DateTime_toString(UA_DateTime time, UA_String *timeString);
 
 /* Guid */
-UA_Int32 UA_LIBEXPORT UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
+UA_EQUALITY UA_LIBEXPORT UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
 
 /* ByteString */
-UA_Int32 UA_LIBEXPORT UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2);
+UA_EQUALITY UA_LIBEXPORT UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2);
 UA_Int32 UA_LIBEXPORT UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length);
 #ifdef DEBUG
 void UA_LIBEXPORT UA_ByteString_printf(char *label, const UA_ByteString *string);
@@ -356,7 +385,7 @@ void UA_LIBEXPORT UA_ByteString_printx_hex(char *label, const UA_ByteString *str
 #endif
 
 /* NodeId */
-UA_Int32 UA_LIBEXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
+UA_EQUALITY UA_LIBEXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
 UA_Boolean UA_LIBEXPORT UA_NodeId_isNull(const UA_NodeId *p);
 UA_Boolean UA_LIBEXPORT UA_NodeId_isBasicType(UA_NodeId const *id);
 
@@ -392,16 +421,10 @@ UA_Int32 UA_LIBEXPORT UA_LocalizedText_copycstring(char const *src, UA_Localized
 UA_Int32 UA_LIBEXPORT UA_Variant_copySetValue(UA_Variant *v, UA_VTable_Entry *vt, const void *value);
 UA_Int32 UA_LIBEXPORT UA_Variant_copySetArray(UA_Variant *v, UA_VTable_Entry *vt, UA_Int32 arrayLength, const void *array);
 
-/** @brief Allows to define variants whose payload will not be deleted. This is
-   achieved by a second vtable. The functionality can be used e.g. when
-   UA_VariableNodes point into a "father" structured object that is stored in an
-   UA_VariableNode itself. This is not possible for arrays so far. */
-UA_Int32 UA_LIBEXPORT UA_Variant_borrowSetValue(UA_Variant *v, UA_VTable_Entry *vt, const void *value);
-
 /* Array operations */
 UA_Int32 UA_LIBEXPORT UA_Array_new(void **p, UA_Int32 noElements, UA_VTable_Entry *vt);
-UA_Int32 UA_LIBEXPORT UA_Array_init(void *p, UA_Int32 noElements, UA_VTable_Entry *vt);
-UA_Int32 UA_LIBEXPORT UA_Array_delete(void *p, UA_Int32 noElements, UA_VTable_Entry *vt);
+void UA_LIBEXPORT UA_Array_init(void *p, UA_Int32 noElements, UA_VTable_Entry *vt);
+void UA_LIBEXPORT UA_Array_delete(void *p, UA_Int32 noElements, UA_VTable_Entry *vt);
 
 /* @brief The destination array is allocated according to noElements. */
 UA_Int32 UA_LIBEXPORT UA_Array_copy(const void *src, UA_Int32 noElements, UA_VTable_Entry *vt, void **dst);
@@ -428,10 +451,10 @@ struct UA_VTable_Entry {
     UA_NodeId  typeId;
     UA_Byte   *name;
     UA_Int32   (*new)(void **p);
-    UA_Int32   (*init)(void *p);
+    void       (*init)(void *p);
     UA_Int32   (*copy)(void const *src, void *dst);
-    UA_Int32   (*delete)(void *p);
-    UA_Int32   (*deleteMembers)(void *p);
+    void       (*delete)(void *p);
+    void       (*deleteMembers)(void *p);
 #ifdef DEBUG
     void       (*print)(const void *p, FILE *stream);
 #endif
@@ -459,50 +482,49 @@ typedef struct UA_VTable {
     UA_TYPE_NEW_DEFAULT(TYPE)            \
     UA_TYPE_COPY_DEFAULT(TYPE)           \
 
-#define UA_TYPE_NEW_DEFAULT(TYPE)                     \
-    UA_Int32 TYPE##_new(TYPE **p) {                   \
-        UA_Int32 retval = UA_SUCCESS;                 \
-        retval |= UA_alloc((void **)p, sizeof(TYPE)); \
-        retval |= TYPE##_init(*p);                    \
-        return retval;                                \
+#define UA_TYPE_NEW_DEFAULT(TYPE)                            \
+    UA_Int32 TYPE##_new(TYPE **p) {                          \
+        if(UA_alloc((void **)p, sizeof(TYPE)) != UA_SUCCESS) \
+            return UA_ERROR;                                 \
+        TYPE##_init(*p);                                     \
+        return UA_SUCCESS;                                   \
     }
 
-#define UA_TYPE_INIT_DEFAULT(TYPE)         \
-    UA_Int32 TYPE##_init(TYPE * p) {       \
-        if(p == UA_NULL) return UA_ERROR;  \
-        *p = (TYPE)0;                      \
-        return UA_SUCCESS;                 \
+#define UA_TYPE_INIT_DEFAULT(TYPE) \
+    void TYPE##_init(TYPE * p) {   \
+        if(!p) return;             \
+        *p = (TYPE)0;              \
     }
 
-#define UA_TYPE_INIT_AS(TYPE, TYPE_AS)       \
-    UA_Int32 TYPE##_init(TYPE * p) {         \
-        return TYPE_AS##_init((TYPE_AS *)p); \
+#define UA_TYPE_INIT_AS(TYPE, TYPE_AS) \
+    void TYPE##_init(TYPE * p) {       \
+        TYPE_AS##_init((TYPE_AS *)p);  \
     }
 
-#define UA_TYPE_DELETE_DEFAULT(TYPE)       \
-    UA_Int32 TYPE##_delete(TYPE *p) {      \
-        UA_Int32 retval = UA_SUCCESS;      \
-        retval |= TYPE##_deleteMembers(p); \
-        retval |= UA_free(p);              \
-        return retval;                     \
+#define UA_TYPE_DELETE_DEFAULT(TYPE) \
+    void TYPE##_delete(TYPE *p) {    \
+        if(!p) return;               \
+        TYPE##_deleteMembers(p);     \
+        UA_free(p);                  \
     }
 
 #define UA_TYPE_DELETE_AS(TYPE, TYPE_AS) \
-    UA_Int32 TYPE##_delete(TYPE * p) { return TYPE_AS##_delete((TYPE_AS *)p); }
+    void TYPE##_delete(TYPE * p) {       \
+        TYPE_AS##_delete((TYPE_AS *)p);  \
+    }
 
 #define UA_TYPE_DELETEMEMBERS_NOACTION(TYPE) \
-    UA_Int32 TYPE##_deleteMembers(TYPE * p) { return UA_SUCCESS; }
+    void TYPE##_deleteMembers(TYPE * p) { return; }
 
 #define UA_TYPE_DELETEMEMBERS_AS(TYPE, TYPE_AS) \
-    UA_Int32 TYPE##_deleteMembers(TYPE * p) { return TYPE_AS##_deleteMembers((TYPE_AS *)p); }
+    void TYPE##_deleteMembers(TYPE * p) { TYPE_AS##_deleteMembers((TYPE_AS *)p); }
 
 /* Use only when the type has no arrays. Otherwise, implement deep copy */
 #define UA_TYPE_COPY_DEFAULT(TYPE)                             \
     UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst) {         \
         if(src == UA_NULL || dst == UA_NULL) return UA_ERROR;  \
-        { UA_Int32 retval = UA_SUCCESS;                        \
-          retval |= UA_memcpy(dst, src, sizeof(TYPE));         \
-          return retval;    }                                  \
+        *dst = *src;                                           \
+        return UA_SUCCESS;                                     \
     }
 
 #define UA_TYPE_COPY_AS(TYPE, TYPE_AS)                         \

+ 11 - 12
src/server/ua_server.c

@@ -34,8 +34,8 @@ void UA_Server_init(UA_Server *server, UA_String *endpointUrl) {
     // fill the UA_borrowed_ table that has been declaed in ua_namespace.c
     for(UA_Int32 i = 0;i < SIZE_UA_VTABLE;i++) {
         UA_borrowed_.types[i] = UA_.types[i];
-        UA_borrowed_.types[i].delete = (UA_Int32 (*)(void *))phantom_delete;
-        UA_borrowed_.types[i].deleteMembers = (UA_Int32 (*)(void *))phantom_delete;
+        UA_borrowed_.types[i].delete = (void (*)(void *))phantom_delete;
+        UA_borrowed_.types[i].deleteMembers = (void (*)(void *))phantom_delete;
     }
 
     UA_NodeStore_new(&server->nodestore);
@@ -469,12 +469,11 @@ void UA_Server_init(UA_Server *server, UA_String *endpointUrl) {
     UA_QualifiedName_copycstring("NodeStoreArray", &namespaceArray->browseName);
     UA_LocalizedText_copycstring("NodeStoreArray", &namespaceArray->displayName);
     UA_LocalizedText_copycstring("NodeStoreArray", &namespaceArray->description);
-    UA_Array_new((void **)&namespaceArray->value.data, 2, &UA_.types[UA_STRING]);
+    UA_Array_new((void **)&namespaceArray->value.storage.data.dataPtr, 2, &UA_.types[UA_STRING]);
     namespaceArray->value.vt = &UA_.types[UA_STRING];
-    namespaceArray->value.arrayLength = 2;
-    UA_String_copycstring("http://opcfoundation.org/UA/", &((UA_String *)((namespaceArray->value).data))[0]);
-    UA_String_copycstring("http://localhost:16664/open62541/",
-                          &((UA_String *)(((namespaceArray)->value).data))[1]);
+    namespaceArray->value.storage.data.arrayLength = 2;
+    UA_String_copycstring("http://opcfoundation.org/UA/", &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[0]);
+    UA_String_copycstring("http://localhost:16664/open62541/", &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[1]);
     namespaceArray->arrayDimensionsSize = 1;
     UA_UInt32 *dimensions = UA_NULL;
     UA_alloc((void **)&dimensions, sizeof(UA_UInt32));
@@ -508,8 +507,8 @@ void UA_Server_init(UA_Server *server, UA_String *endpointUrl) {
     status->secondsTillShutdown     = 99999999;
     UA_LocalizedText_copycstring("because", &status->shutdownReason);
     serverstatus->value.vt          = &UA_.types[UA_SERVERSTATUSDATATYPE]; // gets encoded as an extensionobject
-    serverstatus->value.arrayLength = 1;
-    serverstatus->value.data        = status;
+    serverstatus->value.storage.data.arrayLength = 1;
+    serverstatus->value.storage.data.dataPtr        = status;
     UA_NodeStore_insert(server->nodestore, (UA_Node**)&serverstatus, UA_NODESTORE_INSERT_UNIQUE);
 
     // State (Component of ServerStatus)
@@ -521,9 +520,9 @@ void UA_Server_init(UA_Server *server, UA_String *endpointUrl) {
     UA_LocalizedText_copycstring("State", &state->displayName);
     UA_LocalizedText_copycstring("State", &state->description);
     state->value.vt = &UA_borrowed_.types[UA_SERVERSTATE];
-    state->value.arrayDimensionsLength = 1; // added to ensure encoding in readreponse
-    state->value.arrayLength = 1;
-    state->value.data = &status->state; // points into the other object.
+    state->value.storage.data.arrayDimensionsLength = 1; // added to ensure encoding in readreponse
+    state->value.storage.data.arrayLength = 1;
+    state->value.storage.data.dataPtr = &status->state; // points into the other object.
     UA_NodeStore_insert(server->nodestore, (UA_Node**)&state, UA_NODESTORE_INSERT_UNIQUE);
 
     //TODO: free(namespaceArray->value.data) later or forget it

+ 11 - 15
src/ua_securechannel.c

@@ -3,30 +3,26 @@
 #include "ua_securechannel.h"
 #include "util/ua_util.h"
 
-UA_Int32 UA_SecureChannel_init(UA_SecureChannel *channel) {
+void UA_SecureChannel_init(UA_SecureChannel *channel) {
     UA_AsymmetricAlgorithmSecurityHeader_init(&channel->clientAsymAlgSettings);
     UA_AsymmetricAlgorithmSecurityHeader_init(&channel->serverAsymAlgSettings);
     UA_ByteString_init(&channel->clientNonce);
     UA_ByteString_init(&channel->serverNonce);
     channel->connection = UA_NULL;
     channel->session    = UA_NULL;
-    return UA_SUCCESS;
 }
 
-UA_Int32 UA_SecureChannel_deleteMembers(UA_SecureChannel *channel) {
-    UA_Int32 retval = UA_SUCCESS;
-    retval |= UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->serverAsymAlgSettings);
-    retval |= UA_ByteString_deleteMembers(&channel->serverNonce);
-    retval |= UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->clientAsymAlgSettings);
-    retval |= UA_ByteString_deleteMembers(&channel->clientNonce);
-    retval |= UA_ChannelSecurityToken_deleteMembers(&channel->securityToken);
-    return retval;
+void UA_SecureChannel_deleteMembers(UA_SecureChannel *channel) {
+    UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->serverAsymAlgSettings);
+    UA_ByteString_deleteMembers(&channel->serverNonce);
+    UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->clientAsymAlgSettings);
+    UA_ByteString_deleteMembers(&channel->clientNonce);
+    UA_ChannelSecurityToken_deleteMembers(&channel->securityToken);
 }
-UA_Int32 UA_SecureChannel_delete(UA_SecureChannel *channel) {
-    UA_Int32 retval = UA_SUCCESS;
-    retval |= UA_SecureChannel_deleteMembers(channel);
-    retval |= UA_free(channel);
-    return retval;
+
+void UA_SecureChannel_delete(UA_SecureChannel *channel) {
+    UA_SecureChannel_deleteMembers(channel);
+    UA_free(channel);
 }
 
 UA_Boolean UA_SecureChannel_compare(UA_SecureChannel *sc1, UA_SecureChannel *sc2) {

+ 3 - 3
src/ua_securechannel.h

@@ -28,9 +28,9 @@ struct UA_SecureChannel {
     UA_Session    *session;
 };
 
-UA_Int32 UA_SecureChannel_init(UA_SecureChannel *channel);
-UA_Int32 UA_SecureChannel_deleteMembers(UA_SecureChannel *channel);
-UA_Int32 UA_SecureChannel_delete(UA_SecureChannel *channel);
+void UA_SecureChannel_init(UA_SecureChannel *channel);
+void UA_SecureChannel_deleteMembers(UA_SecureChannel *channel);
+void UA_SecureChannel_delete(UA_SecureChannel *channel);
 UA_Boolean UA_SecureChannel_compare(UA_SecureChannel *sc1, UA_SecureChannel *sc2);
 
 UA_Int32 UA_SecureChannel_generateNonce(UA_ByteString *nonce);

+ 8 - 15
src/ua_session.c

@@ -39,10 +39,8 @@ UA_Int32 UA_Session_generateToken(UA_NodeId *newToken) {
     return retval;
 }
 
-UA_Int32 UA_Session_init(UA_Session *session) {
-    if(!session)
-        return UA_ERROR;
-
+void UA_Session_init(UA_Session *session) {
+    if(!session) return;
     UA_ApplicationDescription_init(&session->clientDescription);
     UA_NodeId_init(&session->authenticationToken);
     UA_NodeId_init(&session->sessionId);
@@ -52,24 +50,19 @@ UA_Int32 UA_Session_init(UA_Session *session) {
     session->timeout = 0;
     UA_DateTime_init(&session->validTill);
     session->channel = UA_NULL;
-    return UA_SUCCESS;
 }
 
-UA_Int32 UA_Session_deleteMembers(UA_Session *session) {
-    UA_Int32 retval = UA_SUCCESS;
+void UA_Session_deleteMembers(UA_Session *session) {
     UA_ApplicationDescription_deleteMembers(&session->clientDescription);
-    retval |= UA_NodeId_deleteMembers(&session->authenticationToken);
-    retval |= UA_NodeId_deleteMembers(&session->sessionId);
-    retval |= UA_String_deleteMembers(&session->sessionName);
+    UA_NodeId_deleteMembers(&session->authenticationToken);
+    UA_NodeId_deleteMembers(&session->sessionId);
+    UA_String_deleteMembers(&session->sessionName);
     session->channel = UA_NULL;
-    return retval;
 }
 
-UA_Int32 UA_Session_delete(UA_Session *session) {
-    UA_Int32 retval = UA_SUCCESS;
+void UA_Session_delete(UA_Session *session) {
     UA_Session_deleteMembers(session);
-    retval |= UA_free(session);
-    return retval;
+    UA_free(session);
 }
 
 UA_Boolean UA_Session_compare(UA_Session *session1, UA_Session *session2) {

+ 3 - 3
src/ua_session.h

@@ -23,9 +23,9 @@ struct UA_Session {
 };
 
 UA_Int32 UA_Session_new(UA_Session **session);
-UA_Int32 UA_Session_init(UA_Session *session);
-UA_Int32 UA_Session_delete(UA_Session *session);
-UA_Int32 UA_Session_deleteMembers(UA_Session *session);
+void UA_Session_init(UA_Session *session);
+void UA_Session_delete(UA_Session *session);
+void UA_Session_deleteMembers(UA_Session *session);
 
 /** Compares two session objects */
 UA_Boolean UA_Session_compare(UA_Session *session1, UA_Session *session2);

+ 186 - 217
src/ua_types.c

@@ -17,10 +17,9 @@
 #include "ua_namespace_0.h"
 
 /* Boolean */
-UA_Int32 UA_Boolean_init(UA_Boolean *p) {
-    if(p == UA_NULL) return UA_ERROR;
+void UA_Boolean_init(UA_Boolean *p) {
+    if(!p) return;
     *p = UA_FALSE;
-    return UA_SUCCESS;
 }
 
 UA_TYPE_DELETE_DEFAULT(UA_Boolean)
@@ -129,35 +128,30 @@ void UA_Double_print(const UA_Double *p, FILE *stream) {
 
 /* String */
 UA_TYPE_NEW_DEFAULT(UA_String)
-UA_Int32 UA_String_init(UA_String *p) {
-    if(p == UA_NULL) return UA_ERROR;
+void UA_String_init(UA_String *p) {
+    if(!p) return;
     p->length = -1;
     p->data   = UA_NULL;
-    return UA_SUCCESS;
 }
 
 UA_TYPE_DELETE_DEFAULT(UA_String)
-UA_Int32 UA_String_deleteMembers(UA_String *p) {
-    UA_Int32 retval = UA_SUCCESS;
-    if(p != UA_NULL && p->length > 0 && p->data != UA_NULL) {
-        retval |= UA_free(p->data);
-        retval |= UA_String_init(p);
+void UA_String_deleteMembers(UA_String *p) {
+    if(p && p->length > 0 && p->data != UA_NULL) {
+        UA_free(p->data);
+        UA_String_init(p);
     }
-    return retval;
 }
 
 UA_Int32 UA_String_copy(UA_String const *src, UA_String *dst) {
     UA_Int32 retval = UA_SUCCESS;
-    if(src == UA_NULL || dst == UA_NULL) return UA_ERROR;
-    dst->data   = UA_NULL;
-    dst->length = -1;
+    if(!src || !dst) return UA_ERROR;
     if(src->length > 0) {
         retval |= UA_alloc((void **)&dst->data, src->length);
-        if(retval == UA_SUCCESS) {
-            retval     |= UA_memcpy((void *)dst->data, src->data, src->length);
-            dst->length = src->length;
-        }
+        if(retval != UA_SUCCESS)
+            return retval;
+        UA_memcpy((void *)dst->data, src->data, src->length);
     }
+    dst->length = src->length;
     return retval;
 }
 
@@ -179,7 +173,7 @@ UA_Int32 UA_String_copycstring(char const *src, UA_String *dst) {
     if(dst->length > 0) {
         retval |= UA_alloc((void **)&dst->data, dst->length);
         if(retval == UA_SUCCESS)
-            retval |= UA_memcpy((void *)dst->data, src, dst->length);
+            UA_memcpy((void *)dst->data, src, dst->length);
     }
     return retval;
 }
@@ -206,25 +200,20 @@ UA_Int32 UA_String_copyprintf(char const *fmt, UA_String *dst, ...) {
         dst->length = ( len > UA_STRING_COPYPRINTF_BUFSIZE ? UA_STRING_COPYPRINTF_BUFSIZE : len );
         retval     |= UA_alloc((void **)&dst->data, dst->length);
         if(retval == UA_SUCCESS)
-            retval |= UA_memcpy((void *)dst->data, src, dst->length);
+            UA_memcpy((void *)dst->data, src, dst->length);
     }
     return retval;
 }
 
-UA_Int32 UA_String_equal(const UA_String *string1, const UA_String *string2) {
-    UA_Int32 retval;
-    if(string1->length == 0 && string2->length == 0)
-        retval = UA_EQUAL;
-    else if(string1->length == -1 && string2->length == -1)
-        retval = UA_EQUAL;
-    else if(string1->length != string2->length)
-        retval = UA_NOT_EQUAL;
-    else {
-        // casts are needed to overcome signed warnings
-        UA_Int32 is = strncmp((char const *)string1->data, (char const *)string2->data, string1->length);
-        retval = (is == 0) ? UA_EQUAL : UA_NOT_EQUAL;
-    }
-    return retval;
+UA_EQUALITY UA_String_equal(const UA_String *string1, const UA_String *string2) {
+    if(string1->length <= 0 && string2->length <= 0)
+        return UA_EQUAL;
+    if(string1->length != string2->length)
+        return UA_NOT_EQUAL;
+
+    // casts are needed to overcome signed warnings
+    UA_Int32 is = strncmp((char const *)string1->data, (char const *)string2->data, string1->length);
+    return (is == 0) ? UA_EQUAL : UA_NOT_EQUAL;
 }
 
 #ifdef DEBUG
@@ -334,29 +323,27 @@ UA_Int32 UA_DateTime_toString(UA_DateTime time, UA_String *timeString) {
 
 /* Guid */
 UA_TYPE_DELETE_DEFAULT(UA_Guid)
-UA_Int32 UA_Guid_deleteMembers(UA_Guid *p) {
-    return UA_SUCCESS;
-}
+UA_TYPE_DELETEMEMBERS_NOACTION(UA_Guid)
 
-UA_Int32 UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2) {
-    return memcmp(g1, g2, sizeof(UA_Guid));
+UA_EQUALITY UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2) {
+    if(memcmp(g1, g2, sizeof(UA_Guid)) == 0)
+        return UA_EQUAL;
+    return UA_NOT_EQUAL;
 }
 
-UA_Int32 UA_Guid_init(UA_Guid *p) {
-    if(p == UA_NULL) return UA_ERROR;
+void UA_Guid_init(UA_Guid *p) {
+    if(!p) return;
     p->data1 = 0;
     p->data2 = 0;
     p->data3 = 0;
     memset(p->data4, 0, sizeof(UA_Byte)*8);
-    return UA_SUCCESS;
 }
 
 UA_TYPE_NEW_DEFAULT(UA_Guid)
 UA_Int32 UA_Guid_copy(UA_Guid const *src, UA_Guid *dst) {
-    UA_Int32 retval = UA_SUCCESS;
     if(src == UA_NULL || dst == UA_NULL) return UA_ERROR;
-    retval |= UA_memcpy((void *)dst, (void *)src, sizeof(UA_Guid));
-    return retval;
+    UA_memcpy((void *)dst, (void *)src, sizeof(UA_Guid));
+    return UA_SUCCESS;
 }
 
 #ifdef DEBUG
@@ -370,7 +357,7 @@ void UA_Guid_print(const UA_Guid *p, FILE *stream) {
 
 /* ByteString */
 UA_TYPE_AS(UA_ByteString, UA_String)
-UA_Int32 UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2) {
+UA_EQUALITY UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2) {
     return UA_String_equal((const UA_String *)string1, (const UA_String *)string2);
 }
 
@@ -399,7 +386,7 @@ UA_ByteString UA_ByteString_securityPoliceNone =
 
 UA_Int32 UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length) {
     UA_Int32 retval = UA_SUCCESS;
-    if((retval |= UA_alloc((void **)&p->data, length)) == UA_SUCCESS)
+    if(length > 0 && (retval |= UA_alloc((void **)&p->data, length)) == UA_SUCCESS)
         p->length = length;
     else {
         p->length = -1;
@@ -412,12 +399,11 @@ UA_Int32 UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length) {
 UA_TYPE_AS(UA_XmlElement, UA_ByteString)
 
 /* NodeId */
-UA_Int32 UA_NodeId_init(UA_NodeId *p) {
-    if(p == UA_NULL) return UA_ERROR;
+void UA_NodeId_init(UA_NodeId *p) {
+    if(!p) return;
     p->identifierType = UA_NODEIDTYPE_NUMERIC;
     p->namespaceIndex = 0;
     memset(&p->identifier, 0, sizeof(p->identifier));
-    return UA_SUCCESS;
 }
 
 UA_TYPE_NEW_DEFAULT(UA_NodeId)
@@ -455,28 +441,25 @@ UA_Boolean UA_NodeId_isBasicType(UA_NodeId const *id) {
 }
 
 UA_TYPE_DELETE_DEFAULT(UA_NodeId)
-UA_Int32 UA_NodeId_deleteMembers(UA_NodeId *p) {
-    UA_Int32 retval = UA_SUCCESS;
-    if(p == UA_NULL) return retval;
+void UA_NodeId_deleteMembers(UA_NodeId *p) {
+    if(!p) return;
 
     switch(p->identifierType) {
     case UA_NODEIDTYPE_NUMERIC:
         // nothing to do
         break;
-
     case UA_NODEIDTYPE_STRING: // Table 6, second entry
-        retval |= UA_String_deleteMembers(&p->identifier.string);
+        UA_String_deleteMembers(&p->identifier.string);
         break;
 
     case UA_NODEIDTYPE_GUID: // Table 6, third entry
-        retval |= UA_Guid_deleteMembers(&p->identifier.guid);
+        UA_Guid_deleteMembers(&p->identifier.guid);
         break;
 
     case UA_NODEIDTYPE_BYTESTRING: // Table 6, "OPAQUE"
-        retval |= UA_ByteString_deleteMembers(&p->identifier.byteString);
+        UA_ByteString_deleteMembers(&p->identifier.byteString);
         break;
     }
-    return retval;
 }
 
 #ifdef DEBUG
@@ -534,7 +517,7 @@ void UA_NodeId_print(const UA_NodeId *p, FILE *stream) {
 }
 #endif
 
-UA_Int32 UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2) {
+UA_EQUALITY UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2) {
     if(n1 == UA_NULL || n2 == UA_NULL || n1->namespaceIndex != n2->namespaceIndex)
         return UA_NOT_EQUAL;
 
@@ -584,20 +567,17 @@ UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
 
 /* ExpandedNodeId */
 UA_TYPE_DELETE_DEFAULT(UA_ExpandedNodeId)
-UA_Int32 UA_ExpandedNodeId_deleteMembers(UA_ExpandedNodeId *p) {
-    UA_Int32 retval = UA_SUCCESS;
-    if(p == UA_NULL) return retval;
-    retval |= UA_NodeId_deleteMembers(&p->nodeId);
-    retval |= UA_String_deleteMembers(&p->namespaceUri);
-    return retval;
+void UA_ExpandedNodeId_deleteMembers(UA_ExpandedNodeId *p) {
+    if(!p) return;
+    UA_NodeId_deleteMembers(&p->nodeId);
+    UA_String_deleteMembers(&p->namespaceUri);
 }
 
-UA_Int32 UA_ExpandedNodeId_init(UA_ExpandedNodeId *p) {
-    if(p == UA_NULL) return UA_ERROR;
+void UA_ExpandedNodeId_init(UA_ExpandedNodeId *p) {
+    if(!p) return;
     UA_NodeId_init(&p->nodeId);
     UA_String_init(&p->namespaceUri);
     p->serverIndex = 0;
-    return UA_SUCCESS;
 }
 
 UA_TYPE_NEW_DEFAULT(UA_ExpandedNodeId)
@@ -632,18 +612,15 @@ UA_TYPE_AS(UA_StatusCode, UA_UInt32)
 
 /* QualifiedName */
 UA_TYPE_DELETE_DEFAULT(UA_QualifiedName)
-UA_Int32 UA_QualifiedName_deleteMembers(UA_QualifiedName *p) {
-    UA_Int32 retval = UA_SUCCESS;
-    if(p == UA_NULL) return retval;
-    retval |= UA_String_deleteMembers(&p->name);
-    return retval;
+void UA_QualifiedName_deleteMembers(UA_QualifiedName *p) {
+    if(!p) return;
+    UA_String_deleteMembers(&p->name);
 }
 
-UA_Int32 UA_QualifiedName_init(UA_QualifiedName *p) {
-    if(p == UA_NULL) return UA_ERROR;
+void UA_QualifiedName_init(UA_QualifiedName *p) {
+    if(!p) return;
     UA_String_init(&p->name);
     p->namespaceIndex = 0;
-    return UA_SUCCESS;
 }
 
 UA_TYPE_NEW_DEFAULT(UA_QualifiedName)
@@ -681,19 +658,16 @@ void UA_QualifiedName_printf(char const *label, const UA_QualifiedName *qn) {
 
 /* LocalizedText */
 UA_TYPE_DELETE_DEFAULT(UA_LocalizedText)
-UA_Int32 UA_LocalizedText_deleteMembers(UA_LocalizedText *p) {
-    UA_Int32 retval = UA_SUCCESS;
-    if(p == UA_NULL) return UA_SUCCESS;
-    retval |= UA_String_deleteMembers(&p->locale);
-    retval |= UA_String_deleteMembers(&p->text);
-    return retval;
+void UA_LocalizedText_deleteMembers(UA_LocalizedText *p) {
+    if(!p) return;
+    UA_String_deleteMembers(&p->locale);
+    UA_String_deleteMembers(&p->text);
 }
 
-UA_Int32 UA_LocalizedText_init(UA_LocalizedText *p) {
-    if(p == UA_NULL) return UA_ERROR;
+void UA_LocalizedText_init(UA_LocalizedText *p) {
+    if(!p) return;
     UA_String_init(&p->locale);
     UA_String_init(&p->text);
-    return UA_SUCCESS;
 }
 
 UA_TYPE_NEW_DEFAULT(UA_LocalizedText)
@@ -710,8 +684,8 @@ UA_Int32 UA_LocalizedText_copycstring(char const *src, UA_LocalizedText *dst) {
 
 UA_Int32 UA_LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedText *dst) {
     UA_Int32 retval = UA_SUCCESS;
-    if(src == UA_NULL || dst == UA_NULL) return UA_ERROR;
-    retval |= UA_LocalizedText_init(dst);
+    if(!src || !dst) return UA_ERROR;
+    UA_LocalizedText_init(dst);
     retval |= UA_String_copy(&src->locale, &dst->locale);
     if(retval != UA_SUCCESS) return retval;
     retval |= UA_String_copy(&src->text, &dst->text);
@@ -731,20 +705,17 @@ void UA_LocalizedText_print(const UA_LocalizedText *p, FILE *stream) {
 
 /* ExtensionObject */
 UA_TYPE_DELETE_DEFAULT(UA_ExtensionObject)
-UA_Int32 UA_ExtensionObject_deleteMembers(UA_ExtensionObject *p) {
-    UA_Int32 retval = UA_SUCCESS;
-    if(p == UA_NULL) return retval;
-    retval |= UA_NodeId_deleteMembers(&p->typeId);
-    retval |= UA_ByteString_deleteMembers(&p->body);
-    return retval;
+void UA_ExtensionObject_deleteMembers(UA_ExtensionObject *p) {
+    if(!p) return;
+    UA_NodeId_deleteMembers(&p->typeId);
+    UA_ByteString_deleteMembers(&p->body);
 }
 
-UA_Int32 UA_ExtensionObject_init(UA_ExtensionObject *p) {
-    if(p == UA_NULL) return UA_ERROR;
+void UA_ExtensionObject_init(UA_ExtensionObject *p) {
+    if(!p) return;
     UA_NodeId_init(&p->typeId);
     p->encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED;
     UA_ByteString_init(&p->body);
-    return UA_SUCCESS;
 }
 
 UA_TYPE_NEW_DEFAULT(UA_ExtensionObject)
@@ -775,15 +746,13 @@ void UA_ExtensionObject_print(const UA_ExtensionObject *p, FILE *stream) {
 
 /* DataValue */
 UA_TYPE_DELETE_DEFAULT(UA_DataValue)
-UA_Int32 UA_DataValue_deleteMembers(UA_DataValue *p) {
-    UA_Int32 retval = UA_SUCCESS;
-    if(p == UA_NULL) return retval;
+void UA_DataValue_deleteMembers(UA_DataValue *p) {
+    if(!p) return;
     UA_Variant_deleteMembers(&p->value);
-    return retval;
 }
 
-UA_Int32 UA_DataValue_init(UA_DataValue *p) {
-    if(p == UA_NULL) return UA_ERROR;
+void UA_DataValue_init(UA_DataValue *p) {
+    if(!p) return;
     p->encodingMask      = 0;
     p->serverPicoseconds = 0;
     UA_DateTime_init(&p->serverTimestamp);
@@ -791,7 +760,6 @@ UA_Int32 UA_DataValue_init(UA_DataValue *p) {
     UA_DateTime_init(&p->sourceTimestamp);
     UA_StatusCode_init(&p->status);
     UA_Variant_init(&p->value);
-    return UA_SUCCESS;
 }
 
 UA_TYPE_NEW_DEFAULT(UA_DataValue)
@@ -831,53 +799,108 @@ void UA_DataValue_print(const UA_DataValue *p, FILE *stream) {
 
 /* Variant */
 UA_TYPE_DELETE_DEFAULT(UA_Variant)
-UA_Int32 UA_Variant_deleteMembers(UA_Variant *p) {
-    UA_Int32   retval = UA_SUCCESS;
-    UA_Boolean hasDimensions;
-    if(p == UA_NULL) return retval;
-
-    hasDimensions = p->arrayDimensions != UA_NULL;
+void UA_Variant_deleteMembers(UA_Variant *p) {
+    if(p->storageType == UA_VARIANT_DATA) {
+        if(p->storage.data.dataPtr != UA_NULL) {
+            if(p->storage.data.arrayLength == 1)
+                p->vt->delete(p->storage.data.dataPtr);
+            else
+                UA_Array_delete(p->storage.data.dataPtr, p->storage.data.arrayLength, p->vt);
+            p->storage.data.dataPtr = UA_NULL;
+        }
 
-    if(p->data != UA_NULL) {
-        if(p->arrayLength == 1)
-            retval |= p->vt->delete(p->data);
-        else
-            retval |= UA_Array_delete(p->data, p->arrayLength, p->vt);
-        p->data = UA_NULL;
+        if(p->storage.data.arrayDimensions) {
+            UA_free(p->storage.data.arrayDimensions);
+            p->storage.data.arrayDimensions = UA_NULL;
+        }
+        return;
     }
-    if(hasDimensions) {
-        UA_free(p->arrayDimensions);
-        p->arrayDimensions = UA_NULL;
+
+    if(p->storageType == UA_VARIANT_DATASOURCE) {
+        p->storage.datasource.delete(p->storage.datasource.identifier);
     }
-    return retval;
 }
 
-UA_Int32 UA_Variant_init(UA_Variant *p) {
-    if(p == UA_NULL) return UA_ERROR;
-    p->arrayLength = -1;  // no element, p->data == UA_NULL
-    p->data        = UA_NULL;
-    p->arrayDimensions       = UA_NULL;
-    p->arrayDimensionsLength = -1;
+UA_TYPE_NEW_DEFAULT(UA_Variant)
+void UA_Variant_init(UA_Variant *p) {
+    if(!p) return;
+    p->storageType = UA_VARIANT_DATA;
+    p->storage.data.arrayLength = -1;  // no element, p->data == UA_NULL
+    p->storage.data.dataPtr        = UA_NULL;
+    p->storage.data.arrayDimensions       = UA_NULL;
+    p->storage.data.arrayDimensionsLength = -1;
     p->vt = &UA_.types[UA_INVALIDTYPE];
-    return UA_SUCCESS;
 }
 
-UA_TYPE_NEW_DEFAULT(UA_Variant)
+/** It is not allowed to copy into a variant that points to an external data source. */
 UA_Int32 UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
+    if(!src || !dst || dst->storageType == UA_VARIANT_DATASOURCE) return UA_ERROR;
     UA_Int32 retval = UA_SUCCESS;
-    if(src == UA_NULL || dst == UA_NULL)
-        return UA_ERROR;
+
+    UA_VariantData *dstdata = &dst->storage.data;
+    const UA_VariantData *srcdata;
+    if(src->storageType == UA_VARIANT_DATA || src->storageType == UA_VARIANT_DATA_NODELETE)
+        srcdata = &src->storage.data;
+    else {
+        retval |= src->storage.datasource.get(src->storage.datasource.identifier, &srcdata);
+        if(retval != UA_SUCCESS)
+            return retval;
+    }
+
+    // now copy from srcdata to dstdata.
     dst->vt = src->vt;
-    retval |= UA_Int32_copy(&src->arrayLength, &dst->arrayLength);
-    retval |= UA_Int32_copy(&src->arrayDimensionsLength, &dst->arrayDimensionsLength);
-    retval |=  UA_Array_copy(src->data, src->arrayLength, src->vt, &dst->data);
-    UA_Boolean hasDimensions = src->arrayDimensions != UA_NULL;
-    if(hasDimensions)
-        retval |= UA_Array_copy(src->arrayDimensions, src->arrayDimensionsLength,
-                                &UA_.types[UA_INT32], (void **)&dst->arrayDimensions);
+    retval |= UA_Array_copy(srcdata->dataPtr, srcdata->arrayLength, src->vt, &dstdata->dataPtr);
+    if(retval != UA_SUCCESS)
+        goto clean_up;
+    dstdata->arrayLength = srcdata->arrayLength;
+    if(srcdata->arrayDimensions != UA_NULL) {
+        retval |= UA_Array_copy(srcdata->arrayDimensions, srcdata->arrayDimensionsLength, &UA_.types[UA_INT32], (void **)&dstdata->arrayDimensions);
+        if(retval != UA_SUCCESS)
+            goto clean_up2;
+        dstdata->arrayDimensionsLength = srcdata->arrayDimensionsLength;
+    }
+
+    // release the src variant if necessary
+    if(src->storageType == UA_VARIANT_DATASOURCE)
+        src->storage.datasource.release(src->storage.datasource.identifier, srcdata);
+
+    return retval;
+
+    // clean ups are falling through to the "lower levels"
+ clean_up2:
+    if(dstdata->arrayDimensions != UA_NULL)
+        UA_Array_delete(dstdata->dataPtr, dstdata->arrayLength, src->vt);
+    
+ clean_up:
+    if(src->storageType == UA_VARIANT_DATASOURCE)
+        src->storage.datasource.release(src->storage.datasource.identifier, srcdata);
+
     return retval;
 }
 
+/** Copies data into a variant. The target variant has always a storagetype UA_VARIANT_DATA */
+UA_Int32 UA_Variant_copySetValue(UA_Variant *v, UA_VTable_Entry *vt, const void *value) {
+    if(v == UA_NULL || vt == UA_NULL || value == UA_NULL)
+        return UA_ERROR;
+    UA_Variant_init(v);
+    v->vt = vt;
+    v->storage.data.arrayLength = 1; // no array but a single entry
+    UA_Int32 retval = UA_SUCCESS;
+    retval |= vt->new(&v->storage.data.dataPtr);
+    if(retval == UA_SUCCESS)
+        retval |= vt->copy(value, v->storage.data.dataPtr);
+    return retval;
+}
+UA_Int32 UA_Variant_copySetArray(UA_Variant *v, UA_VTable_Entry *vt, UA_Int32 arrayLength,
+                                 const void *array) {
+    if(v == UA_NULL || vt == UA_NULL || array == UA_NULL)
+        return UA_ERROR;
+    UA_Variant_init(v);
+    v->vt = vt;
+    v->storage.data.arrayLength = arrayLength;
+    return UA_Array_copy(array, arrayLength, vt, &v->storage.data.dataPtr);
+}
+
 #ifdef DEBUG
 void UA_Variant_print(const UA_Variant *p, FILE *stream) {
     if(p == UA_NULL || stream == UA_NULL) return;
@@ -900,55 +923,19 @@ void UA_Variant_print(const UA_Variant *p, FILE *stream) {
 }
 #endif
 
-UA_Int32 UA_Variant_copySetValue(UA_Variant *v, UA_VTable_Entry *vt, const void *value) {
-    if(v == UA_NULL || vt == UA_NULL || value == UA_NULL)
-        return UA_ERROR;
-    UA_Variant_init(v);
-    v->vt = vt;
-    v->arrayLength = 1; // no array but a single entry
-    UA_Int32 retval = UA_SUCCESS;
-    retval |= vt->new(&v->data);
-    if(retval == UA_SUCCESS)
-        retval |= vt->copy(value, v->data);
-    return retval;
-}
-
-UA_Int32 UA_Variant_copySetArray(UA_Variant *v, UA_VTable_Entry *vt, UA_Int32 arrayLength,
-                                 const void *array) {
-    if(v == UA_NULL || vt == UA_NULL || array == UA_NULL)
-        return UA_ERROR;
-    UA_Variant_init(v);
-    v->vt = vt;
-    v->arrayLength = arrayLength;
-    return UA_Array_copy(array, arrayLength, vt, &v->data);
-}
-
-UA_Int32 UA_Variant_borrowSetValue(UA_Variant *v, UA_VTable_Entry *vt, const void *value) {
-    if(v == UA_NULL || vt == UA_NULL || value == UA_NULL)
-        return UA_ERROR;
-    UA_Variant_init(v);
-    v->vt   = &UA_borrowed_.types[UA_ns0ToVTableIndex(&vt->typeId)];
-    v->arrayLength = 1; // no array but a single entry
-    v->data = (void *)value;
-    return UA_SUCCESS;
-}
-
 /* DiagnosticInfo */
 UA_TYPE_DELETE_DEFAULT(UA_DiagnosticInfo)
-UA_Int32 UA_DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p) {
-    UA_Int32 retval = UA_SUCCESS;
-    if(p == UA_NULL) return retval;
-    if((p->encodingMask & UA_DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO) && p->innerDiagnosticInfo !=
-       UA_NULL) {
-        retval |= UA_DiagnosticInfo_delete(p->innerDiagnosticInfo);
-        retval |= UA_String_deleteMembers(&p->additionalInfo);
+void UA_DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p) {
+    if(!p) return;
+    UA_String_deleteMembers(&p->additionalInfo);
+    if((p->encodingMask & UA_DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO) && p->innerDiagnosticInfo) {
+        UA_DiagnosticInfo_delete(p->innerDiagnosticInfo);
         p->innerDiagnosticInfo = UA_NULL;
     }
-    return retval;
 }
 
-UA_Int32 UA_DiagnosticInfo_init(UA_DiagnosticInfo *p) {
-    if(p == UA_NULL) return UA_ERROR;
+void UA_DiagnosticInfo_init(UA_DiagnosticInfo *p) {
+    if(!p) return;
     UA_String_init(&p->additionalInfo);
     p->encodingMask = 0;
     p->innerDiagnosticInfo = UA_NULL;
@@ -957,7 +944,6 @@ UA_Int32 UA_DiagnosticInfo_init(UA_DiagnosticInfo *p) {
     p->localizedText       = 0;
     p->namespaceUri        = 0;
     p->symbolicId          = 0;
-    return UA_SUCCESS;
 }
 
 UA_TYPE_NEW_DEFAULT(UA_DiagnosticInfo)
@@ -1009,20 +995,16 @@ void UA_DiagnosticInfo_print(const UA_DiagnosticInfo *p, FILE *stream) {
 #endif
 
 /* InvalidType */
-UA_Int32 UA_InvalidType_free(UA_InvalidType *p) {
-    return UA_ERR_INVALID_VALUE;
-}
-
-UA_Int32 UA_InvalidType_delete(UA_InvalidType *p) {
-    return UA_ERR_INVALID_VALUE;
+void UA_InvalidType_delete(UA_InvalidType *p) {
+    return;
 }
 
-UA_Int32 UA_InvalidType_deleteMembers(UA_InvalidType *p) {
-    return UA_ERR_INVALID_VALUE;
+void UA_InvalidType_deleteMembers(UA_InvalidType *p) {
+    return;
 }
 
-UA_Int32 UA_InvalidType_init(UA_InvalidType *p) {
-    return UA_ERR_INVALID_VALUE;
+void UA_InvalidType_init(UA_InvalidType *p) {
+    return;
 }
 
 UA_Int32 UA_InvalidType_copy(UA_InvalidType const *src, UA_InvalidType *dst) {
@@ -1065,42 +1047,29 @@ UA_Int32 UA_Array_new(void **p, UA_Int32 noElements, UA_VTable_Entry *vt) {
     if(retval != UA_SUCCESS)
         return retval;
 
-    retval = UA_Array_init(*p, noElements, vt);
-    if(retval != UA_SUCCESS) {
-        UA_free(*p);
-        *p = UA_NULL;
-    }
-    return retval;
+    UA_Array_init(*p, noElements, vt);
+    return UA_SUCCESS;
 }
 
-UA_Int32 UA_Array_init(void *p, UA_Int32 noElements, UA_VTable_Entry *vt) {
-    UA_Int32 retval = UA_SUCCESS;
-    if(p == UA_NULL || vt == UA_NULL)
-        return UA_ERROR;
-    char     *cp      = (char *)p; // so compilers allow pointer arithmetic
+void UA_Array_init(void *p, UA_Int32 noElements, UA_VTable_Entry *vt) {
+    if(!p || !vt) return;
+    char *cp = (char *)p; // so compilers allow pointer arithmetic
     UA_UInt32 memSize = vt->memSize;
-    for(UA_Int32 i = 0;i < noElements && retval == UA_SUCCESS;i++) {
-        retval |= vt->init(cp);
-        cp     += memSize;
+    for(UA_Int32 i = 0;i<noElements;i++) {
+        vt->init(cp);
+        cp += memSize;
     }
-    return retval;
 }
 
-UA_Int32 UA_Array_delete(void *p, UA_Int32 noElements, UA_VTable_Entry *vt) {
-    if(p == UA_NULL)
-        return UA_SUCCESS;
-    if(vt == UA_NULL)
-        return UA_ERROR;
-
+void UA_Array_delete(void *p, UA_Int32 noElements, UA_VTable_Entry *vt) {
+    if(!p || !vt || noElements <= 0) return;
     char     *cp      = (char *)p; // so compilers allow pointer arithmetic
     UA_UInt32 memSize = vt->memSize;
-    UA_Int32  retval  = UA_SUCCESS;
-    for(UA_Int32 i = 0;i < noElements;i++) {
-        retval |= vt->deleteMembers(cp);
-        cp     += memSize;
+    for(UA_Int32 i = 0;i<noElements;i++) {
+        vt->deleteMembers(cp);
+        cp += memSize;
     }
     UA_free(p);
-    return retval;
 }
 
 UA_Int32 UA_Array_copy(const void *src, UA_Int32 noElements, UA_VTable_Entry *vt, void **dst) {

+ 87 - 65
src/ua_types_encoding_binary.c

@@ -166,7 +166,7 @@ UA_Int32 UA_Array_decodeBinary(const UA_ByteString *src, UA_UInt32 *offset, UA_I
 UA_TYPE_CALCSIZEBINARY_SIZEOF(UA_Boolean)
 UA_TYPE_ENCODEBINARY(UA_Boolean,
                      UA_Boolean tmpBool = ((*src > 0) ? UA_TRUE : UA_FALSE);
-                     memcpy(&dst->data[(*offset)++], &tmpBool, sizeof(UA_Boolean)); )
+                     UA_memcpy(&dst->data[(*offset)++], &tmpBool, sizeof(UA_Boolean)); )
 UA_TYPE_DECODEBINARY(UA_Boolean,
                      *dst = ((UA_Boolean)(src->data[(*offset)++]) > (UA_Byte)0) ? UA_TRUE : UA_FALSE; )
 
@@ -335,7 +335,7 @@ UA_Int32 UA_String_encodeBinary(UA_String const *src, UA_ByteString *dst, UA_UIn
 
     retval |= UA_Int32_encodeBinary(&src->length, dst, offset);
     if(src->length > 0) {
-        retval  |= UA_memcpy(&dst->data[*offset], src->data, src->length);
+        UA_memcpy(&dst->data[*offset], src->data, src->length);
         *offset += src->length;
     }
     return retval;
@@ -353,8 +353,7 @@ UA_Int32 UA_String_decodeBinary(UA_ByteString const *src, UA_UInt32 *offset, UA_
         dst->data   = UA_NULL;
     } else {
         CHECKED_DECODE(UA_alloc((void **)&dst->data, dst->length), dst->length = -1);
-        CHECKED_DECODE(UA_memcpy(dst->data, &src->data[*offset], dst->length), UA_free(
-                           dst->data); dst->data = UA_NULL; dst->length = -1);
+        UA_memcpy(dst->data, &src->data[*offset], dst->length);
         *offset += dst->length;
     }
     return retval;
@@ -653,7 +652,7 @@ UA_TYPE_ENCODEBINARY(UA_LocalizedText,
 
 UA_Int32 UA_LocalizedText_decodeBinary(UA_ByteString const *src, UA_UInt32 *offset, UA_LocalizedText *dst) {
     UA_Int32 retval       = UA_SUCCESS;
-    retval |= UA_LocalizedText_init(dst);
+    UA_LocalizedText_init(dst);
     UA_Byte  encodingMask = 0;
     CHECKED_DECODE(UA_Byte_decodeBinary(src, offset, &encodingMask),; );
     if(encodingMask & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE)
@@ -818,42 +817,48 @@ UA_Int32 UA_DataValue_calcSizeBinary(UA_DataValue const *p) {
  * Officially, only builtin types are contained in a variant.
  *
  * Every ExtensionObject incurrs an overhead of 4 byte (nodeid) + 1 byte (encoding) */
+
+/* VariantBinaryEncoding - Part: 6, Chapter: 5.2.2.16, Page: 22 */
+enum UA_VARIANT_ENCODINGMASKTYPE_enum {
+    UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3F,            // bits 0:5
+    UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS  = (0x01 << 6),     // bit 6
+    UA_VARIANT_ENCODINGMASKTYPE_ARRAY       = (0x01 << 7)      // bit 7
+};
+
 UA_Int32 UA_Variant_calcSizeBinary(UA_Variant const *p) {
+    if(!p || !p->vt) return 0;
     UA_Int32   arrayLength, length;
-    UA_Boolean isArray, hasDimensions, isBuiltin;
-    if(p == UA_NULL)
-        return sizeof(UA_Variant);
-
-    if(p->vt == UA_NULL)
-        return UA_ERR_INCONSISTENT;
-    arrayLength = p->arrayLength;
-    if(p->data == UA_NULL)
+    const UA_VariantData  *data;
+    if(p->storageType == UA_VARIANT_DATA)
+        data = &p->storage.data;
+    else {
+        if(p->storage.datasource.get(p->storage.datasource.identifier, &data) != UA_SUCCESS)
+            return 0;
+    }
+        
+    arrayLength = data->arrayLength;
+    if(data->dataPtr == UA_NULL)
         arrayLength = -1;
 
-    isArray       = arrayLength != 1; // a single element is not an array
-    hasDimensions = isArray && p->arrayDimensions != UA_NULL;
-    isBuiltin     = is_builtin(&p->vt->typeId);
-
     length = sizeof(UA_Byte); //p->encodingMask
-    if(isArray) {
+    if(arrayLength != 1) {
         // array length + the array itself
-        length += UA_Array_calcSizeBinary(arrayLength, p->vt, p->data);
+        length += UA_Array_calcSizeBinary(arrayLength, p->vt, data->dataPtr);
     } else {
-        length += p->vt->encodings[UA_ENCODING_BINARY].calcSize(p->data);
-        if(!isBuiltin)
+        length += p->vt->encodings[UA_ENCODING_BINARY].calcSize(data->dataPtr);
+        if(!is_builtin(&p->vt->typeId))
             length += 9;  // 4 byte nodeid + 1 byte encoding + 4 byte bytestring length
     }
 
-    if(hasDimensions) {
-        if(isBuiltin)
-            length += UA_Array_calcSizeBinary(p->arrayDimensionsLength, &UA_.types[UA_INT32],
-                                              p->arrayDimensions);
+    if(arrayLength != 1 && data->arrayDimensions != UA_NULL) {
+        if(is_builtin(&p->vt->typeId))
+            length += UA_Array_calcSizeBinary(data->arrayDimensionsLength, &UA_.types[UA_INT32], data->arrayDimensions);
         else
-            length +=
-                UA_Array_calcSizeBinary_asExtensionObject(p->arrayDimensionsLength, &UA_.types[UA_INT32],
-                                                          p->arrayDimensions);
+            length += UA_Array_calcSizeBinary_asExtensionObject(data->arrayDimensionsLength, &UA_.types[UA_INT32], data->arrayDimensions);
     }
-
+    
+    if(p->storageType == UA_VARIANT_DATASOURCE)
+        p->storage.datasource.release(p->storage.datasource.identifier, data);
 
     return length;
 }
@@ -864,13 +869,20 @@ UA_TYPE_ENCODEBINARY(UA_Variant,
                      UA_Boolean hasDimensions;
                      UA_Boolean isBuiltin;
 
-                     if(src == UA_NULL || src->vt == UA_NULL || src->vt->typeId.namespaceIndex != 0)
+                     if(src == UA_NULL || src->vt == UA_NULL)
                          return UA_ERROR;
 
-                     isArray       = src->arrayLength != 1;  // a single element is not an array
-                     hasDimensions = isArray && src->arrayDimensions != UA_NULL;
-                     isBuiltin = is_builtin(
-                         &src->vt->typeId);
+                     const UA_VariantData  *data;
+                     if(src->storageType == UA_VARIANT_DATA)
+                         data = &src->storage.data;
+                     else {
+                         if(src->storage.datasource.get(src->storage.datasource.identifier, &data) != UA_SUCCESS)
+                             return UA_ERROR;
+                     }
+
+                     isArray       = data->arrayLength != 1;  // a single element is not an array
+                     hasDimensions = isArray && data->arrayDimensions != UA_NULL;
+                     isBuiltin = is_builtin(&src->vt->typeId);
 
                      encodingByte = 0;
                      if(isArray) {
@@ -880,16 +892,15 @@ UA_TYPE_ENCODEBINARY(UA_Variant,
                      }
 
                      if(isBuiltin)
-                         encodingByte |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK &
-                                         (UA_Byte)src->vt->typeId.identifier.numeric;
+                         encodingByte |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (UA_Byte)src->vt->typeId.identifier.numeric;
                      else
                          encodingByte |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (UA_Byte)22;  // ExtensionObject
 
                      retval |= UA_Byte_encodeBinary(&encodingByte, dst, offset);
 
                      if(isArray)
-                         retval |= UA_Array_encodeBinary(src->data, src->arrayLength, src->vt, dst, offset);
-                     else if(src->data == UA_NULL)
+                         retval |= UA_Array_encodeBinary(data->dataPtr, data->arrayLength, src->vt, dst, offset);
+                     else if(data->dataPtr == UA_NULL)
                          retval = UA_ERROR;           // an array can be empty. a single element must be present.
                      else {
                          if(!isBuiltin) {
@@ -897,58 +908,69 @@ UA_TYPE_ENCODEBINARY(UA_Variant,
                              UA_NodeId_encodeBinary(&src->vt->typeId, dst, offset);
                              UA_Byte eoEncoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
                              UA_Byte_encodeBinary(&eoEncoding, dst, offset);
-                             UA_Int32 eoEncodingLength =
-                                 src->vt->encodings[UA_ENCODING_BINARY].calcSize(src->data);
+                             UA_Int32 eoEncodingLength = src->vt->encodings[UA_ENCODING_BINARY].calcSize(data->dataPtr);
                              UA_Int32_encodeBinary(&eoEncodingLength, dst, offset);
                          }
-                         retval |= src->vt->encodings[UA_ENCODING_BINARY].encode(src->data, dst, offset);
+                         retval |= src->vt->encodings[UA_ENCODING_BINARY].encode(data->dataPtr, dst, offset);
                      }
 
                      if(hasDimensions) {
                          if(isBuiltin)
-                             retval |= UA_Array_encodeBinary(src->arrayDimensions, src->arrayDimensionsLength,
-                                                             &UA_.types[UA_INT32], dst, offset);
+                             retval |= UA_Array_encodeBinary(data->arrayDimensions, data->arrayDimensionsLength, &UA_.types[UA_INT32], dst, offset);
                          else
-                             retval |= UA_Array_encodeBinary_asExtensionObject(src->arrayDimensions,
-                                                                               src->arrayDimensionsLength,
-                                                                               &UA_.types[UA_INT32], dst,
-                                                                               offset);
+                             retval |= UA_Array_encodeBinary_asExtensionObject(data->arrayDimensions, data->arrayDimensionsLength, &UA_.types[UA_INT32], dst, offset);
                      }
+
+                     if(src->storageType == UA_VARIANT_DATASOURCE)
+                         src->storage.datasource.release(src->storage.datasource.identifier, data);
+                     
                      )
 
-/* For decoding, we read extensionobects as is. */
+/* For decoding, we read extensionobects as is. The resulting variant always has the storagetype UA_VARIANT_DATA. */
 UA_Int32 UA_Variant_decodeBinary(UA_ByteString const *src, UA_UInt32 *offset, UA_Variant *dst) {
     UA_Int32 retval = UA_SUCCESS;
     UA_Variant_init(dst);
+    UA_VariantData *data = &dst->storage.data;
 
     UA_Byte encodingByte;
-    CHECKED_DECODE(UA_Byte_decodeBinary(src, offset, &encodingByte),; );
+    retval |= UA_Byte_decodeBinary(src, offset, &encodingByte);
+    if(retval != UA_SUCCESS)
+        return retval;
 
-    UA_Boolean isArray       = encodingByte & UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
+    UA_Boolean isArray = encodingByte & UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
     UA_Boolean hasDimensions = isArray && (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS);
-
-    UA_NodeId typeid = { .namespaceIndex     = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
+    UA_NodeId typeid = { .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
                          .identifier.numeric = encodingByte & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK };
     UA_Int32 typeNs0Id = UA_ns0ToVTableIndex(&typeid );
     dst->vt = &UA_.types[typeNs0Id];
 
-    if(isArray) {
-        CHECKED_DECODE(UA_Int32_decodeBinary(src, offset, &dst->arrayLength),; );
-        CHECKED_DECODE(UA_Array_decodeBinary(src, offset, dst->arrayLength, dst->vt,
-                                             &dst->data), UA_Variant_deleteMembers(dst));
+    if(!isArray) {
+        if(UA_alloc(&data->dataPtr, dst->vt->memSize) != UA_SUCCESS) return UA_ERROR;
+        retval |= dst->vt->encodings[UA_ENCODING_BINARY].decode(src, offset, data->dataPtr);
+        if(retval != UA_SUCCESS) {
+            UA_free(data->dataPtr);
+            return retval;
+        }
+        data->arrayLength = 1;
     } else {
-        dst->arrayLength = 1;
-        UA_alloc(&dst->data, dst->vt->memSize);
-        dst->vt->encodings[UA_ENCODING_BINARY].decode(src, offset, dst->data);
+        retval |= UA_Int32_decodeBinary(src, offset, &data->arrayLength);
+        if(retval == UA_SUCCESS)
+            retval |= UA_Array_decodeBinary(src, offset, data->arrayLength, dst->vt, &data->dataPtr);
+        if(retval != UA_SUCCESS)
+            data->arrayLength = -1; // for deleteMembers
     }
 
-    //decode the dimension field array if present
-    if(hasDimensions) {
-        UA_Int32_decodeBinary(src, offset, &dst->arrayDimensionsLength);
-        CHECKED_DECODE(UA_Array_decodeBinary(src, offset, dst->arrayDimensionsLength,
-                                             &UA_.types[UA_INT32],
-                                             &dst->data), UA_Variant_deleteMembers(dst));
+    if(hasDimensions && retval == UA_SUCCESS) {
+        retval |= UA_Int32_decodeBinary(src, offset, &data->arrayDimensionsLength);
+        if(retval == UA_SUCCESS)
+            retval |= UA_Array_decodeBinary(src, offset, data->arrayDimensionsLength, &UA_.types[UA_INT32], &data->dataPtr);
+        if(retval != UA_SUCCESS)
+            data->arrayLength = -1; // for deleteMembers
     }
+
+    if(retval != UA_SUCCESS)
+        UA_Variant_deleteMembers(dst);
+
     return retval;
 }
 

+ 1 - 7
src/util/ua_util.c

@@ -5,10 +5,4 @@
 extern INLINE UA_Int32 _UA_free(void *ptr, char *pname, char *f, UA_Int32 l);
 extern INLINE UA_Int32 _UA_alloc(void **ptr, UA_Int32 size, char *pname, char *sname, char *f, UA_Int32 l);
 extern INLINE UA_Int32 _UA_alloca(void **ptr, UA_Int32 size, char *pname, char *sname, char *f, UA_Int32 l);
-
-UA_Int32 UA_memcpy(void *dst, void const *src, UA_Int32 size) {
-    if(dst == UA_NULL) return UA_ERR_INVALID_VALUE;
-    DBG_VERBOSE(printf("UA_memcpy - %p;%p;%d\n", dst, src, size));
-    memcpy(dst, src, size);
-    return UA_SUCCESS;
-}
+extern INLINE void UA_memcpy(void *dst, void const *src, UA_Int32 size);

+ 4 - 1
src/util/ua_util.h

@@ -70,7 +70,10 @@ INLINE UA_Int32 _UA_alloca(void **ptr, UA_Int32 size, char *pname, char *sname,
     return UA_SUCCESS;
 }
 
-UA_Int32 UA_memcpy(void *dst, void const *src, UA_Int32 size);
+INLINE void UA_memcpy(void *dst, void const *src, UA_Int32 size) {
+    DBG_VERBOSE(printf("UA_memcpy - %p;%p;%d\n", dst, src, size));
+    memcpy(dst, src, size);
+}
 
 #define UA_free(ptr) _UA_free(ptr, # ptr, __FILE__, __LINE__)
 #define UA_alloc(ptr, size) _UA_alloc(ptr, size, # ptr, # size, __FILE__, __LINE__)

+ 49 - 52
tests/check_builtin.c

@@ -7,6 +7,13 @@
 #include "util/ua_util.h"
 #include "check.h"
 
+/* copied here from encoding_binary.c */
+enum UA_VARIANT_ENCODINGMASKTYPE_enum {
+    UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3F,            // bits 0:5
+    UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS  = (0x01 << 6),     // bit 6
+    UA_VARIANT_ENCODINGMASKTYPE_ARRAY       = (0x01 << 7)      // bit 7
+};
+
 START_TEST(UA_Boolean_calcSizeWithNullArgumentShallReturnStorageSize) {
 	// given
 	UA_Boolean *arg = UA_NULL;
@@ -260,15 +267,6 @@ START_TEST(UA_DataValue_calcSizeWithNullArgumentShallReturnStorageSize) {
 	ck_assert_int_eq(storageSize, sizeof(UA_DataValue));
 }
 END_TEST
-START_TEST(UA_Variant_calcSizeWithNullArgumentShallReturnStorageSize) {
-	// given
-	UA_Variant *arg = UA_NULL;
-	// when
-	UA_UInt32   storageSize = UA_Variant_calcSizeBinary(arg);
-	// then
-	ck_assert_int_eq(storageSize, sizeof(UA_Variant));
-}
-END_TEST
 START_TEST(UA_DiagnosticInfo_calcSizeShallWorkOnExample) {
 	// given
 	UA_DiagnosticInfo diagnosticInfo;
@@ -477,9 +475,9 @@ START_TEST(UA_Variant_calcSizeFixedSizeArrayShallReturnEncodingSize) {
 	UA_Variant_init(&arg);
 	arg.vt = &UA_.types[UA_INT32];
 #define ARRAY_LEN 8
-	arg.arrayLength = ARRAY_LEN;
+	arg.storage.data.arrayLength = ARRAY_LEN;
 	UA_Int32 *data[ARRAY_LEN];
-	arg.data = (void *)data;
+	arg.storage.data.dataPtr = (void *)data;
 
 	// when
 	UA_UInt32 encodingSize = UA_Variant_calcSizeBinary(&arg);
@@ -495,12 +493,12 @@ START_TEST(UA_Variant_calcSizeVariableSizeArrayShallReturnEncodingSize) {
 	UA_Variant_init(&arg);
 	arg.vt = &UA_.types[UA_STRING];
 #define ARRAY_LEN 3
-	arg.arrayLength = ARRAY_LEN;
+	arg.storage.data.arrayLength = ARRAY_LEN;
 	UA_String strings[3];
 	strings[0] = (UA_String) {-1, UA_NULL };
 	strings[1] = (UA_String) {3, (UA_Byte *)"PLT" };
 	strings[2] = (UA_String) {47, UA_NULL };
-	arg.data   = (void *)strings;
+	arg.storage.data.dataPtr   = (void *)strings;
 	// when
 	UA_UInt32 encodingSize = UA_Variant_calcSizeBinary(&arg);
 	// then
@@ -865,8 +863,8 @@ START_TEST(UA_Variant_decodeWithOutArrayFlagSetShallSetVTAndAllocateMemoryForArr
 	ck_assert_int_eq(retval, UA_SUCCESS);
 	ck_assert_int_eq(pos, 5);
 	ck_assert_ptr_eq(dst.vt, &UA_.types[UA_INT32]);
-	ck_assert_int_eq(dst.arrayLength, 1);
-	ck_assert_int_eq(*(UA_Int32 *)dst.data, 255);
+	ck_assert_int_eq(dst.storage.data.arrayLength, 1);
+	ck_assert_int_eq(*(UA_Int32 *)dst.storage.data.dataPtr, 255);
 	// finally
 	UA_Variant_deleteMembers(&dst);
 }
@@ -887,9 +885,9 @@ START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray)
 	ck_assert_int_eq(retval, UA_SUCCESS);
 	ck_assert_int_eq(pos, 1+4+2*4);
 	ck_assert_ptr_eq(dst.vt, &UA_.types[UA_INT32]);
-	ck_assert_int_eq(dst.arrayLength, 2);
-	ck_assert_int_eq(((UA_Int32 *)dst.data)[0], 255);
-	ck_assert_int_eq(((UA_Int32 *)dst.data)[1], -1);
+	ck_assert_int_eq(dst.storage.data.arrayLength, 2);
+	ck_assert_int_eq(((UA_Int32 *)dst.storage.data.dataPtr)[0], 255);
+	ck_assert_int_eq(((UA_Int32 *)dst.storage.data.dataPtr)[1], -1);
 	// finally
 	UA_Variant_deleteMembers(&dst);
 }
@@ -1310,9 +1308,9 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithVariant) {
 	src.encodingMask       = UA_DATAVALUE_ENCODINGMASK_VARIANT | UA_DATAVALUE_ENCODINGMASK_SERVERTIMESTAMP; //Variant & SourvePicoseconds
 	UA_Variant_init(&src.value);
 	src.value.vt           = &UA_.types[UA_INT32];
-	src.value.arrayLength  = 1; // one element (encoded as not an array)
+	src.value.storage.data.arrayLength  = 1; // one element (encoded as not an array)
 	UA_Int32  vdata  = 45;
-	src.value.data = (void *)&vdata;
+	src.value.storage.data.dataPtr = (void *)&vdata;
 
 	UA_Byte data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 		               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1675,25 +1673,25 @@ START_TEST(UA_Variant_copyShallWorkOnSingleValueExample) {
 	UA_Variant value, copiedValue;
 	UA_Variant_init(&value);
 	UA_Variant_init(&copiedValue);
-	UA_alloc((void**)&value.data, sizeof(UA_String));
-	*((UA_String*)value.data) = testString;
+	UA_alloc((void**)&value.storage.data.dataPtr, sizeof(UA_String));
+	*((UA_String*)value.storage.data.dataPtr) = testString;
 	value.vt = &UA_.types[UA_STRING];
-	value.arrayLength = 1;
+	value.storage.data.arrayLength = 1;
 
 	//when
 	UA_Variant_copy(&value, &copiedValue);
 
 	//then
-	UA_String copiedString = *(UA_String*)(copiedValue.data);
+	UA_String copiedString = *(UA_String*)(copiedValue.storage.data.dataPtr);
 	for(UA_Int32 i = 0;i < 5;i++)
 		ck_assert_int_eq(copiedString.data[i], testString.data[i]);
 	ck_assert_int_eq(copiedString.length, testString.length);
 
-	ck_assert_int_eq(value.arrayDimensionsLength, copiedValue.arrayDimensionsLength);
-	ck_assert_int_eq(value.arrayLength, copiedValue.arrayLength);
+	ck_assert_int_eq(value.storage.data.arrayDimensionsLength, copiedValue.storage.data.arrayDimensionsLength);
+	ck_assert_int_eq(value.storage.data.arrayLength, copiedValue.storage.data.arrayLength);
 
 	//finally
-	((UA_String*)value.data)->data = UA_NULL; // the string is statically allocated. do not free it.
+	((UA_String*)value.storage.data.dataPtr)->data = UA_NULL; // the string is statically allocated. do not free it.
 	UA_Variant_deleteMembers(&value);
 	UA_Variant_deleteMembers(&copiedValue);
 }
@@ -1714,30 +1712,30 @@ START_TEST(UA_Variant_copyShallWorkOn1DArrayExample) {
 	UA_Variant_init(&value);
 	UA_Variant_init(&copiedValue);
 
-	value.arrayLength = 3;
-	value.data        = (void **)srcArray;
-	value.arrayDimensionsLength = 1;
-	value.arrayDimensions       = dimensions;
+	value.storage.data.arrayLength = 3;
+	value.storage.data.dataPtr        = (void **)srcArray;
+	value.storage.data.arrayDimensionsLength = 1;
+	value.storage.data.arrayDimensions       = dimensions;
 	value.vt = &UA_.types[UA_STRING];
 
 	//when
 	UA_Variant_copy(&value, &copiedValue);
 
 	//then
-	UA_Int32 i1 = value.arrayDimensions[0];
-	UA_Int32 i2 = copiedValue.arrayDimensions[0];
+	UA_Int32 i1 = value.storage.data.arrayDimensions[0];
+	UA_Int32 i2 = copiedValue.storage.data.arrayDimensions[0];
 	ck_assert_int_eq(i1, i2);
 
 	for(UA_Int32 i = 0;i < 3;i++) {
 		for(UA_Int32 j = 0;j < 6;j++)
-			ck_assert_int_eq(((UA_String *)value.data)[i].data[j], ((UA_String *)copiedValue.data)[i].data[j]);
-		ck_assert_int_eq(((UA_String *)value.data)[i].length, ((UA_String *)copiedValue.data)[i].length);
+			ck_assert_int_eq(((UA_String *)value.storage.data.dataPtr)[i].data[j], ((UA_String *)copiedValue.storage.data.dataPtr)[i].data[j]);
+		ck_assert_int_eq(((UA_String *)value.storage.data.dataPtr)[i].length, ((UA_String *)copiedValue.storage.data.dataPtr)[i].length);
 	}
-	ck_assert_int_eq(((UA_String *)copiedValue.data)[0].data[2], 'o');
-	ck_assert_int_eq(((UA_String *)copiedValue.data)[0].data[3], 'p');
+	ck_assert_int_eq(((UA_String *)copiedValue.storage.data.dataPtr)[0].data[2], 'o');
+	ck_assert_int_eq(((UA_String *)copiedValue.storage.data.dataPtr)[0].data[3], 'p');
 
-	ck_assert_int_eq(value.arrayDimensionsLength, copiedValue.arrayDimensionsLength);
-	ck_assert_int_eq(value.arrayLength, copiedValue.arrayLength);
+	ck_assert_int_eq(value.storage.data.arrayDimensionsLength, copiedValue.storage.data.arrayDimensionsLength);
+	ck_assert_int_eq(value.storage.data.arrayLength, copiedValue.storage.data.arrayLength);
 
 	//finally
 	UA_Variant_deleteMembers(&value);
@@ -1766,10 +1764,10 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 	UA_Variant_init(&value);
 	UA_Variant_init(&copiedValue);
 
-	value.arrayLength = 6;
-	value.data        = (void **)srcArray;
-	value.arrayDimensionsLength = 2;
-	value.arrayDimensions       = dimensions;
+	value.storage.data.arrayLength = 6;
+	value.storage.data.dataPtr        = (void **)srcArray;
+	value.storage.data.arrayDimensionsLength = 2;
+	value.storage.data.arrayDimensions       = dimensions;
 	value.vt = &UA_.types[UA_INT32];
 
 	//when
@@ -1777,28 +1775,28 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 
 	//then
 	//1st dimension
-	UA_Int32 i1 = value.arrayDimensions[0];
-	UA_Int32 i2 = copiedValue.arrayDimensions[0];
+	UA_Int32 i1 = value.storage.data.arrayDimensions[0];
+	UA_Int32 i2 = copiedValue.storage.data.arrayDimensions[0];
 	ck_assert_int_eq(i1, i2);
 	ck_assert_int_eq(i1, dim1);
 
 
 	//2nd dimension
-	i1 = value.arrayDimensions[1];
-	i2 = copiedValue.arrayDimensions[1];
+	i1 = value.storage.data.arrayDimensions[1];
+	i2 = copiedValue.storage.data.arrayDimensions[1];
 	ck_assert_int_eq(i1, i2);
 	ck_assert_int_eq(i1, dim2);
 
 
 	for(UA_Int32 i = 0;i < 6;i++) {
-		i1 = ((UA_Int32 *)value.data)[i];
-		i2 = ((UA_Int32 *)copiedValue.data)[i];
+		i1 = ((UA_Int32 *)value.storage.data.dataPtr)[i];
+		i2 = ((UA_Int32 *)copiedValue.storage.data.dataPtr)[i];
 		ck_assert_int_eq(i1, i2);
 		ck_assert_int_eq(i2, i);
 	}
 
-	ck_assert_int_eq(value.arrayDimensionsLength, copiedValue.arrayDimensionsLength);
-	ck_assert_int_eq(value.arrayLength, copiedValue.arrayLength);
+	ck_assert_int_eq(value.storage.data.arrayDimensionsLength, copiedValue.storage.data.arrayDimensionsLength);
+	ck_assert_int_eq(value.storage.data.arrayLength, copiedValue.storage.data.arrayLength);
 
 	//finally
 	UA_Variant_deleteMembers(&value);
@@ -1835,7 +1833,6 @@ Suite *testSuite_builtin(void) {
 	tcase_add_test(tc_calcSize, UA_ExtensionObject_calcSizeWithNullArgumentShallReturnStorageSize);
 	tcase_add_test(tc_calcSize, UA_DataValue_calcSizeShallWorkOnExample);
 	tcase_add_test(tc_calcSize, UA_DataValue_calcSizeWithNullArgumentShallReturnStorageSize);
-	tcase_add_test(tc_calcSize, UA_Variant_calcSizeWithNullArgumentShallReturnStorageSize);
 	tcase_add_test(tc_calcSize, UA_DiagnosticInfo_calcSizeShallWorkOnExample);
 	tcase_add_test(tc_calcSize, UA_DiagnosticInfo_calcSizeWithNullArgumentShallReturnStorageSize);
 	tcase_add_test(tc_calcSize, UA_String_calcSizeShallReturnEncodingSize);

+ 1 - 1
tests/check_memory.c

@@ -16,7 +16,7 @@ START_TEST(newAndEmptyObjectShallBeDeleted) {
 #ifdef DEBUG //no print functions if not in debug mode
 	UA_.types[_i].print(obj, stdout);
 #endif
-	retval |= UA_.types[_i].delete(obj);
+	UA_.types[_i].delete(obj);
 	// then
 	ck_assert_int_eq(retval, UA_SUCCESS);
 }

+ 20 - 21
tools/generate_builtin.py

@@ -163,7 +163,7 @@ def createStructured(element):
 
     # 4) CalcSizeBinary
     printc('''UA_Int32 %(name)s_calcSizeBinary(%(name)s const * ptr) {
-    if(ptr==UA_NULL) return sizeof(%(name)s);
+    if(!ptr) return 0;
     return 0''')
     has_fixed_size = True
     for n,t in membermap.iteritems():
@@ -200,7 +200,7 @@ def createStructured(element):
             printc('\tretval |= UA_Int32_decodeBinary(src,offset,&dst->%(n)sSize);')
             printc('\tretval |= UA_Array_decodeBinary(src,offset,dst->%(n)sSize,&UA_.types[' +
                    t[0:t.find("*")].upper() + '],(void**)&dst->%(n)s);')
-            printc('\tif(retval != UA_SUCCESS) { dst->%(n)sSize = -1; }') # arrays clean up internally. But the size needs to be set here for the eventual deleteMembers.
+            printc('\tif(retval != UA_SUCCESS) { dst->%(n)sSize = -1; %(name)s_deleteMembers(dst); return retval;}') # arrays clean up internally. But the size needs to be set here for the eventual deleteMembers.
         else:
             printc('\tretval |= %(t)s_decodeBinary(src,offset,&dst->%(n)s);')
     printc("\tif(retval != UA_SUCCESS) %(name)s_deleteMembers(dst);")
@@ -213,35 +213,31 @@ UA_TYPE_METHOD_ENCODEXML_NOTIMPL(%(name)s)
 UA_TYPE_METHOD_DECODEXML_NOTIMPL(%(name)s)''')
     
     # 8) Delete
-    printc('''UA_Int32 %(name)s_delete(%(name)s *p) {
-	UA_Int32 retval = UA_SUCCESS;
-	retval |= %(name)s_deleteMembers(p);
-	retval |= UA_free(p);
-	return retval;\n}\n''')
+    printc('''void %(name)s_delete(%(name)s *p) {
+	%(name)s_deleteMembers(p);
+	UA_free(p);\n}\n''')
 	
     # 9) DeleteMembers
-    printc('''UA_Int32 %(name)s_deleteMembers(%(name)s *p) {
-    UA_Int32 retval = UA_SUCCESS;''')
+    printc('''void %(name)s_deleteMembers(%(name)s *p) {''')
     for n,t in membermap.iteritems():
         if not t in fixed_size: # dynamic size on the wire
             if t.find("*") != -1:
-		printc("\tretval |= UA_Array_delete((void*)p->%(n)s,p->%(n)sSize,&UA_.types[" +
+		printc("\tUA_Array_delete((void*)p->%(n)s,p->%(n)sSize,&UA_.types[" +
                        t[0:t.find("*")].upper()+"]);")
             else:
-		printc('\tretval |= %(t)s_deleteMembers(&p->%(n)s);')
-    printc("\treturn retval;\n}\n")
+		printc('\t%(t)s_deleteMembers(&p->%(n)s);')
+    printc("\n}\n")
 
     # 10) Init
-    printc('''UA_Int32 %(name)s_init(%(name)s *p) {
-    if(!p) return UA_ERROR;
-    UA_Int32 retval = UA_SUCCESS;''')
+    printc('''void %(name)s_init(%(name)s *p) {
+    if(!p) return;''')
     for n,t in membermap.iteritems():
         if t.find("*") != -1:
             printc('\tp->%(n)sSize = 0;')
             printc('\tp->%(n)s = UA_NULL;')
         else:
-            printc('\tretval |= %(t)s_init(&p->%(n)s);')
-    printc("\treturn retval;\n}\n")
+            printc('\t%(t)s_init(&p->%(n)s);')
+    printc("\n}\n")
 
     # 11) New
     printc("UA_TYPE_NEW_DEFAULT(%(name)s)")
@@ -250,15 +246,18 @@ UA_TYPE_METHOD_DECODEXML_NOTIMPL(%(name)s)''')
     printc('''UA_Int32 %(name)s_copy(const %(name)s *src,%(name)s *dst) {
 	UA_Int32 retval = UA_SUCCESS;
     if(src == UA_NULL || dst == UA_NULL) return UA_ERROR;''')
-    printc("\tmemcpy(dst, src, sizeof(%(name)s));")
+    printc("\t%(name)s_init(dst);")
     for n,t in membermap.iteritems():
         if t.find("*") != -1:
-            printc('\tdst->%(n)s = src->%(n)s;')
-            printc("\tretval |= UA_Array_copy(src->%(n)s, src->%(n)sSize,&UA_.types[" +
-                      t[0:t.find("*")].upper()+"],(void**)&dst->%(n)s);")
+            printc('\tdst->%(n)sSize = src->%(n)sSize;')
+            printc("\tretval |= UA_Array_copy(src->%(n)s, src->%(n)sSize,&UA_.types[" + t[0:t.find("*")].upper() + "],(void**)&dst->%(n)s);")
             continue
         if not t in fixed_size: # there are members of variable size    
             printc('\tretval |= %(t)s_copy(&src->%(n)s,&dst->%(n)s);')
+            continue
+        printc("\tdst->%(n)s = src->%(n)s;")
+    printc('''if(retval != UA_SUCCESS)
+    %(name)s_deleteMembers(dst);''')
     printc("\treturn retval;\n}\n")
 
     # 13) Print

+ 3 - 3
tools/generate_namespace.py

@@ -167,10 +167,10 @@ for row in rows:
     printc("\t{.typeId={.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric=" + row[1] + "}" + 
           ",\n.name=(UA_Byte*)&\"%(name)s\"" +
           ",\n.new=(UA_Int32(*)(void **))%(name)s_new" +
-          ",\n.init=(UA_Int32(*)(void *))%(name)s_init"+
+          ",\n.init=(void(*)(void *))%(name)s_init"+
           ",\n.copy=(UA_Int32(*)(void const * ,void*))%(name)s_copy" +
-          ",\n.delete=(UA_Int32(*)(void *))%(name)s_delete" +
-          ",\n.deleteMembers=(UA_Int32(*)(void *))%(name)s_deleteMembers" +
+          ",\n.delete=(void(*)(void *))%(name)s_delete" +
+          ",\n.deleteMembers=(void(*)(void *))%(name)s_deleteMembers" +
           ",\n#ifdef DEBUG //FIXME: seems to be okay atm, however a pointer to a noop function would be more safe" + 
           "\n.print=(void(*)(const void *, FILE *))%(name)s_print," +
           "\n#endif" +