Ver código fonte

move datasource handling to the variable node

Julius Pfrommer 10 anos atrás
pai
commit
04574c8bcd

+ 23 - 20
examples/server_datasource.c

@@ -21,23 +21,24 @@
 /*************************/
 /*************************/
 /* Read-only data source */
 /* Read-only data source */
 /*************************/
 /*************************/
-static UA_StatusCode readTimeData(const void *handle, UA_VariantData *data) {
+static UA_StatusCode readTimeData(const void *handle, UA_DataValue *value) {
     UA_DateTime *currentTime = UA_DateTime_new();
     UA_DateTime *currentTime = UA_DateTime_new();
     if(!currentTime)
     if(!currentTime)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
     *currentTime = UA_DateTime_now();
     *currentTime = UA_DateTime_now();
-    data->arrayLength = 1;
-    data->dataPtr = currentTime;
-    data->arrayDimensionsSize = -1;
-    data->arrayDimensions = UA_NULL;
+    value->value.arrayLength = 1;
+    value->value.dataPtr = currentTime;
+    value->value.arrayDimensionsSize = -1;
+    value->value.arrayDimensions = NULL;
+    value->hasVariant = UA_TRUE;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-static void releaseTimeData(const void *handle, UA_VariantData *data) {
-    UA_DateTime_delete((UA_DateTime*)data->dataPtr);
+static void releaseTimeData(const void *handle, UA_DataValue *value) {
+    UA_DateTime_delete((UA_DateTime*)value->value.dataPtr);
 }
 }
 
 
-static UA_StatusCode writeTimeData(const void *handle, const UA_VariantData *data) {
+static UA_StatusCode writeTimeData(const void *handle, const UA_Variant *data) {
     return UA_STATUSCODE_BADINTERNALERROR;
     return UA_STATUSCODE_BADINTERNALERROR;
 }
 }
 
 
@@ -51,28 +52,31 @@ static void printDeviceStatus(UA_Server *server, void *data) {
     printf("Device Status: %i\n", deviceStatus);
     printf("Device Status: %i\n", deviceStatus);
 }
 }
 
 
-static UA_StatusCode readDeviceStatus(const void *handle, UA_VariantData *data) {
+static UA_StatusCode readDeviceStatus(const void *handle, UA_DataValue *value) {
     /* In order to reduce blocking time, we could alloc memory for every read
     /* In order to reduce blocking time, we could alloc memory for every read
        and return a copy of the data. */
        and return a copy of the data. */
     pthread_rwlock_rdlock(&deviceStatusLock);
     pthread_rwlock_rdlock(&deviceStatusLock);
-    data->arrayLength = 1;
-    data->dataPtr = &deviceStatus;
-    data->arrayDimensionsSize = -1;
-    data->arrayDimensions = UA_NULL;
+    value->value.arrayLength = 1;
+    value->value.dataPtr = &deviceStatus;
+    value->value.arrayDimensionsSize = -1;
+    value->value.arrayDimensions = NULL;
+    value->hasVariant = UA_TRUE;
+    value->sourceTimestamp = UA_DateTime_now();
+    value->hasSourceTimestamp = UA_TRUE;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-static void releaseDeviceStatus(const void *handle, UA_VariantData *data) {
+static void releaseDeviceStatus(const void *handle, UA_DataValue *value) {
     /* If we allocated memory for a specific read, free the content of the
     /* If we allocated memory for a specific read, free the content of the
        variantdata. */
        variantdata. */
-    data->dataPtr = UA_NULL;
-    data->arrayLength = -1;
+    value->value.arrayLength = -1;
+    value->value.dataPtr = NULL;
     pthread_rwlock_unlock(&deviceStatusLock);
     pthread_rwlock_unlock(&deviceStatusLock);
 }
 }
 
 
-static UA_StatusCode writeDeviceStatus(const void *handle, const UA_VariantData *data) {
+static UA_StatusCode writeDeviceStatus(const void *handle, const UA_Variant *data) {
     pthread_rwlock_wrlock(&deviceStatusLock);
     pthread_rwlock_wrlock(&deviceStatusLock);
-    if(data->dataPtr != UA_NULL)
+    if(data->dataPtr)
         deviceStatus = *(UA_Int32*)data->dataPtr;
         deviceStatus = *(UA_Int32*)data->dataPtr;
     pthread_rwlock_unlock(&deviceStatusLock);
     pthread_rwlock_unlock(&deviceStatusLock);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
@@ -94,8 +98,7 @@ int main(int argc, char** argv) {
 
 
     // add node with the datetime data source
     // add node with the datetime data source
     UA_Variant *dateVariant = UA_Variant_new();
     UA_Variant *dateVariant = UA_Variant_new();
-    dateVariant->storageType = UA_VARIANT_DATASOURCE;
-    dateVariant->storage.datasource = (UA_VariantDataSource)
+    dateVariant->storage.datasource = (UA_DataSource)
         {.handle = UA_NULL,
         {.handle = UA_NULL,
          .read = readTimeData,
          .read = readTimeData,
          .release = releaseTimeData,
          .release = releaseTimeData,

+ 14 - 0
include/ua_server.h

@@ -62,6 +62,20 @@ UA_StatusCode UA_EXPORT UA_Server_addVariableNode(UA_Server *server, UA_Variant
                                                   UA_QualifiedName *browseName, const UA_NodeId *parentNodeId,
                                                   UA_QualifiedName *browseName, const UA_NodeId *parentNodeId,
                                                   const UA_NodeId *referenceTypeId);
                                                   const UA_NodeId *referenceTypeId);
 
 
+/** @brief A datasource is the interface to interact with a local data provider.
+ *
+ *  Implementors of datasources need to provide functions for the callbacks in
+ *  this structure. After every read, the handle needs to be released to
+ *  indicate that the pointer is no longer accessed. As a rule, datasources are
+ *  never copied, but only their content. The only way to write into a
+ *  datasource is via the write-service. */
+typedef struct {
+    const void *handle;
+    UA_StatusCode (*read)(const void *handle, UA_DataValue *value);
+    void (*release)(const void *handle, UA_DataValue *value);
+    UA_StatusCode (*write)(const void *handle, const UA_Variant *data);
+} UA_DataSource;
+
 /** Work that is run in the main loop (singlethreaded) or dispatched to a worker
 /** Work that is run in the main loop (singlethreaded) or dispatched to a worker
     thread. */
     thread. */
 typedef struct UA_WorkItem {
 typedef struct UA_WorkItem {

+ 4 - 29
include/ua_types.h

@@ -188,29 +188,6 @@ typedef struct {
     UA_ByteString body; // contains either the bytestring or a pointer to the memory-object
     UA_ByteString body; // contains either the bytestring or a pointer to the memory-object
 } UA_ExtensionObject;
 } UA_ExtensionObject;
 
 
-/** @brief Pointers to data that is stored in memory. The "type" of the data is
-    stored in the variant itself. */
-typedef struct {
-    UA_Int32  arrayLength;        // total number of elements in the data-pointer
-    void     *dataPtr;
-    UA_Int32  arrayDimensionsSize;
-    UA_Int32 *arrayDimensions;
-} UA_VariantData;
-
-/** @brief A datasource is the interface to interact with a local data provider.
- *
- *  Implementors of datasources need to provide functions for the callbacks in
- *  this structure. After every read, the handle needs to be released to
- *  indicate that the pointer is no longer accessed. As a rule, datasources are
- *  never copied, but only their content. The only way to write into a
- *  datasource is via the write-service. */
-typedef struct {
-    const void *handle;
-    UA_StatusCode (*read)(const void *handle, UA_VariantData *data);
-    void (*release)(const void *handle, UA_VariantData *data);
-    UA_StatusCode (*write)(const void *handle, const UA_VariantData *data);
-} UA_VariantDataSource;
-
 struct UA_DataType;
 struct UA_DataType;
 typedef struct UA_DataType UA_DataType; 
 typedef struct UA_DataType UA_DataType; 
 
 
@@ -225,13 +202,11 @@ typedef struct {
                                        deleted at the end of this variant's lifecycle. It is not
                                        deleted at the end of this variant's lifecycle. It is not
                                        possible to overwrite borrowed data due to concurrent access.
                                        possible to overwrite borrowed data due to concurrent access.
                                        Use a custom datasource with a mutex. */
                                        Use a custom datasource with a mutex. */
-        UA_VARIANT_DATASOURCE /**< The data is provided externally. Call the functions in the
-                                   datasource to get a current version */
     } storageType;
     } storageType;
-    union {
-        UA_VariantData       data;
-        UA_VariantDataSource datasource;
-    } storage;
+    UA_Int32  arrayLength;  ///< the number of elements in the data-pointer
+    void     *dataPtr; ///< points to the scalar or array data
+    UA_Int32  arrayDimensionsSize; ///< the number of dimensions the data-array has
+    UA_Int32 *arrayDimensions; ///< the length of each dimension of the data-array
 } UA_Variant;
 } UA_Variant;
 
 
 /** @brief A data value with an associated status code and timestamps. */
 /** @brief A data value with an associated status code and timestamps. */

+ 9 - 3
src/server/ua_nodes.c

@@ -100,7 +100,8 @@ UA_StatusCode UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectType
 void UA_VariableNode_init(UA_VariableNode *p) {
 void UA_VariableNode_init(UA_VariableNode *p) {
 	UA_Node_init((UA_Node*)p);
 	UA_Node_init((UA_Node*)p);
     p->nodeClass = UA_NODECLASS_VARIABLE;
     p->nodeClass = UA_NODECLASS_VARIABLE;
-    UA_Variant_init(&p->value);
+    p->variableType = UA_VARIABLETYPE_VARIANT;
+    UA_Variant_init(&p->variable.variant);
     p->valueRank = -2; // scalar or array of any dimension
     p->valueRank = -2; // scalar or array of any dimension
     p->accessLevel = 0;
     p->accessLevel = 0;
     p->userAccessLevel = 0;
     p->userAccessLevel = 0;
@@ -117,7 +118,8 @@ UA_VariableNode * UA_VariableNode_new(void) {
 
 
 void UA_VariableNode_deleteMembers(UA_VariableNode *p) {
 void UA_VariableNode_deleteMembers(UA_VariableNode *p) {
     UA_Node_deleteMembers((UA_Node*)p);
     UA_Node_deleteMembers((UA_Node*)p);
-    UA_Variant_deleteMembers(&p->value);
+    if(p->variableType == UA_VARIABLETYPE_VARIANT)
+        UA_Variant_deleteMembers(&p->variable.variant);
 }
 }
 
 
 void UA_VariableNode_delete(UA_VariableNode *p) {
 void UA_VariableNode_delete(UA_VariableNode *p) {
@@ -128,7 +130,11 @@ void UA_VariableNode_delete(UA_VariableNode *p) {
 UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
 UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
     UA_VariableNode_init(dst);
     UA_VariableNode_init(dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-    retval = UA_Variant_copy(&src->value, &dst->value);
+    dst->variableType = src->variableType;
+    if(src->variableType == UA_VARIABLETYPE_VARIANT)
+        retval = UA_Variant_copy(&src->variable.variant, &dst->variable.variant);
+    else
+        dst->variable.dataSource = src->variable.dataSource;
     if(retval) {
     if(retval) {
         UA_VariableNode_deleteMembers(dst);
         UA_VariableNode_deleteMembers(dst);
         return retval;
         return retval;

+ 9 - 2
src/server/ua_nodes.h

@@ -1,6 +1,7 @@
 #ifndef UA_NODES_H_
 #ifndef UA_NODES_H_
 #define UA_NODES_H_
 #define UA_NODES_H_
 
 
+#include "ua_server.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_encoding_binary.h"
 
 
@@ -33,8 +34,14 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
 
 
 typedef struct {
 typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS
-    UA_Variant value;
-    // datatype is taken from the value
+    enum {
+        UA_VARIABLETYPE_VARIANT,
+        UA_VARIABLETYPE_DATASOURCE
+    } variableType;
+    union {
+        UA_Variant variant;
+        UA_DataSource dataSource;
+    } variable;
     UA_Int32 valueRank; /**< n >= 1: the value is an array with the specified number of dimensions.
     UA_Int32 valueRank; /**< n >= 1: the value is an array with the specified number of dimensions.
                              n = 0: the value is an array with one or more dimensions.
                              n = 0: the value is an array with one or more dimensions.
                              n = -1: the value is a scalar.
                              n = -1: the value is a scalar.

+ 10 - 9
src/server/ua_server.c

@@ -617,14 +617,15 @@ UA_Server * UA_Server_new(void) {
     UA_VariableNode *namespaceArray = UA_VariableNode_new();
     UA_VariableNode *namespaceArray = UA_VariableNode_new();
     COPYNAMES(namespaceArray, "NamespaceArray");
     COPYNAMES(namespaceArray, "NamespaceArray");
     namespaceArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_NAMESPACEARRAY;
     namespaceArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_NAMESPACEARRAY;
-    namespaceArray->value.storage.data.dataPtr = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
-    namespaceArray->value.storage.data.arrayLength = 2;
-    namespaceArray->value.type = &UA_TYPES[UA_TYPES_STRING];
+    namespaceArray->variableType = UA_VARIABLETYPE_VARIANT;
+    namespaceArray->variable.variant.dataPtr = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
+    namespaceArray->variable.variant.arrayLength = 2;
+    namespaceArray->variable.variant.type = &UA_TYPES[UA_TYPES_STRING];
     // Fixme: Insert the external namespaces
     // Fixme: Insert the external namespaces
     UA_String_copycstring("http://opcfoundation.org/UA/",
     UA_String_copycstring("http://opcfoundation.org/UA/",
-                          &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[0]);
+                          &((UA_String *)(namespaceArray->variable.variant.dataPtr))[0]);
     UA_String_copycstring("urn:myServer:myApplication",
     UA_String_copycstring("urn:myServer:myApplication",
-                          &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[1]);
+                          &((UA_String *)(namespaceArray->variable.variant.dataPtr))[1]);
     namespaceArray->valueRank = 1;
     namespaceArray->valueRank = 1;
     namespaceArray->minimumSamplingInterval = 1.0;
     namespaceArray->minimumSamplingInterval = 1.0;
     namespaceArray->historizing = UA_FALSE;
     namespaceArray->historizing = UA_FALSE;
@@ -651,10 +652,10 @@ UA_Server * UA_Server_new(void) {
     *stateEnum = UA_SERVERSTATE_RUNNING;
     *stateEnum = UA_SERVERSTATE_RUNNING;
     COPYNAMES(state, "State");
     COPYNAMES(state, "State");
     state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
     state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
-    state->value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
-    state->value.storage.data.arrayLength = 1;
-    state->value.storage.data.dataPtr = stateEnum; // points into the other object.
-    state->value.storageType = UA_VARIANT_DATA;
+    state->variableType = UA_VARIABLETYPE_VARIANT;
+    state->variable.variant.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
+    state->variable.variant.arrayLength = 1;
+    state->variable.variant.dataPtr = stateEnum; // points into the other object.
     UA_NodeStore_insert(server->nodestore, (UA_Node*)state, UA_NULL);
     UA_NodeStore_insert(server->nodestore, (UA_Node*)state, UA_NULL);
     ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS), UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT),
     ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS), UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT),
                      UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
                      UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));

+ 2 - 2
src/server/ua_server_addressspace.c

@@ -5,7 +5,7 @@ UA_StatusCode UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, UA
                                         UA_QualifiedName *browseName, const UA_NodeId *parentNodeId,
                                         UA_QualifiedName *browseName, const UA_NodeId *parentNodeId,
                                         const UA_NodeId *referenceTypeId) {
                                         const UA_NodeId *referenceTypeId) {
     UA_VariableNode *node = UA_VariableNode_new();
     UA_VariableNode *node = UA_VariableNode_new();
-    node->value = *value; // copy content
+    node->variable.variant = *value; // copy content
     UA_NodeId_copy(nodeId, &node->nodeId);
     UA_NodeId_copy(nodeId, &node->nodeId);
     UA_QualifiedName_copy(browseName, &node->browseName);
     UA_QualifiedName_copy(browseName, &node->browseName);
     UA_String_copy(&browseName->name, &node->displayName.text);
     UA_String_copy(&browseName->name, &node->displayName.text);
@@ -17,7 +17,7 @@ UA_StatusCode UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, UA
     ADDREFERENCE(res.addedNodeId, UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
     ADDREFERENCE(res.addedNodeId, UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
                  UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
                  UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
     if(res.statusCode != UA_STATUSCODE_GOOD) {
     if(res.statusCode != UA_STATUSCODE_GOOD) {
-        UA_Variant_init(&node->value);
+        UA_Variant_init(&node->variable.variant);
         UA_VariableNode_delete(node);
         UA_VariableNode_delete(node);
     } else {
     } else {
         UA_free(value);
         UA_free(value);

+ 54 - 39
src/server/ua_services_attribute.c

@@ -99,15 +99,28 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
 
 
     case UA_ATTRIBUTEID_VALUE:
     case UA_ATTRIBUTEID_VALUE:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = UA_Variant_copy(&((const UA_VariableNode *)node)->value, &v->value);
-        if(retval == UA_STATUSCODE_GOOD){
-            v->hasVariant = UA_TRUE;
-
-            v->hasSourceTimestamp = UA_TRUE;
-            v->sourceTimestamp = UA_DateTime_now();
-
-            v->hasServerTimestamp = UA_TRUE;
-            v->serverTimestamp = UA_DateTime_now();
+        {
+            const UA_VariableNode *vn = (const UA_VariableNode*)node;
+            if(vn->variableType == UA_VARIABLETYPE_VARIANT) {
+                retval = UA_Variant_copy(&vn->variable.variant, &v->value);
+                if(retval == UA_STATUSCODE_GOOD){
+                    v->hasVariant = UA_TRUE;
+                    v->hasServerTimestamp = UA_TRUE;
+                    v->serverTimestamp = UA_DateTime_now();
+                }
+            } else {
+                UA_DataValue val;
+                UA_DataValue_init(&val);
+                retval |= vn->variable.dataSource.read(vn->variable.dataSource.handle, &val);
+                if(retval != UA_STATUSCODE_GOOD)
+                    break;
+                retval |= UA_DataValue_copy(&val, v);
+                vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
+                if(retval != UA_STATUSCODE_GOOD)
+                    break;
+                v->hasServerTimestamp = UA_TRUE;
+                v->serverTimestamp = UA_DateTime_now();
+            }
         }
         }
         break;
         break;
 
 
@@ -128,23 +141,27 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         {
         {
-            const UA_VariantData *data = UA_NULL;
-            UA_VariantData datasourceData;
             const UA_VariableNode *vn = (const UA_VariableNode *)node;
             const UA_VariableNode *vn = (const UA_VariableNode *)node;
-            if(vn->value.storageType == UA_VARIANT_DATA || vn->value.storageType == UA_VARIANT_DATA_NODELETE)
-                data = &vn->value.storage.data;
-            else {
-				if(vn->value.storage.datasource.read == UA_NULL || (retval = vn->value.storage.datasource.read(vn->value.storage.datasource.handle,
-																   &datasourceData)) != UA_STATUSCODE_GOOD)
-						break;
-				data = &datasourceData;
+            if(vn->variableType == UA_VARIABLETYPE_VARIANT) {
+                retval = UA_Variant_copySetArray(&v->value, vn->variable.variant.arrayDimensions,
+                                                 vn->variable.variant.arrayDimensionsSize, UA_TYPES_INT32);
+                if(retval == UA_STATUSCODE_GOOD)
+                    v->hasVariant = UA_TRUE;
+            } else {
+                UA_DataValue val;
+                UA_DataValue_init(&val);
+                retval |= vn->variable.dataSource.read(vn->variable.dataSource.handle, &val);
+                if(retval != UA_STATUSCODE_GOOD)
+                    break;
+                if(!val.hasVariant) {
+                    vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
+                    retval = UA_STATUSCODE_BADNOTREADABLE;
+                    break;
+                }
+                retval = UA_Variant_copySetArray(&v->value, val.value.arrayDimensions,
+                                                 val.value.arrayDimensionsSize, UA_TYPES_INT32);
+                vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
             }
             }
-            retval = UA_Variant_copySetArray(&v->value, data->arrayDimensions, data->arrayDimensionsSize,
-                                             UA_TYPES_INT32);
-            if(retval == UA_STATUSCODE_GOOD)
-                v->hasVariant = UA_TRUE;
-            if(vn->value.storageType == UA_VARIANT_DATASOURCE && vn->value.storage.datasource.release != UA_NULL)
-                vn->value.storage.datasource.release(vn->value.storage.datasource.handle, &datasourceData);
         }
         }
         break;
         break;
 
 
@@ -364,22 +381,20 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
             }
             }
 
 
             const UA_VariableNode *vn = (const UA_VariableNode*)node;
             const UA_VariableNode *vn = (const UA_VariableNode*)node;
-            // has the wvalue a variant of the right type?
-            // array sizes are not checked yet..
-            if(!wvalue->value.hasVariant || !UA_NodeId_equal(&vn->value.type->typeId,  &wvalue->value.value.type->typeId)) {
-                retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-                break;
-            }
-
-            if(vn->value.storageType == UA_VARIANT_DATASOURCE) {
-            	if(vn->value.storage.datasource.write != UA_NULL){
-            		retval = vn->value.storage.datasource.write(vn->value.storage.datasource.handle,
-                                                            	&wvalue->value.value.storage.data);
-            	}else{
-            		retval = UA_STATUSCODE_BADINTERNALERROR;
-            	}
+            if(vn->variableType == UA_VARIABLETYPE_DATASOURCE) {
+                retval = vn->variable.dataSource.write(vn->variable.dataSource.handle,
+                                                       &wvalue->value.value);
                 done = UA_TRUE;
                 done = UA_TRUE;
             } else {
             } else {
+                // has the wvalue a variant of the right type?
+                // array sizes are not checked yet..
+                if(!wvalue->value.hasVariant ||
+                   !UA_NodeId_equal(&vn->variable.variant.type->typeId,
+                                    &wvalue->value.value.type->typeId)) {
+                    retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+                    break;
+                }
+
                 // could be a variable or variabletype node. They fit for the value.. member
                 // could be a variable or variabletype node. They fit for the value.. member
                 UA_VariableNode *newVn = (UA_VariableNode*)newNode();
                 UA_VariableNode *newVn = (UA_VariableNode*)newNode();
                 if(!newVn) {
                 if(!newVn) {
@@ -391,7 +406,7 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
                     deleteNode((UA_Node*)newVn);
                     deleteNode((UA_Node*)newVn);
                     break;
                     break;
                 }
                 }
-                retval = UA_Variant_copy(&wvalue->value.value, &newVn->value);
+                retval = UA_Variant_copy(&wvalue->value.value, &newVn->variable.variant);
                 if(retval != UA_STATUSCODE_GOOD) {
                 if(retval != UA_STATUSCODE_GOOD) {
                     deleteNode((UA_Node*)newVn);
                     deleteNode((UA_Node*)newVn);
                     break;
                     break;

+ 1 - 1
src/server/ua_services_nodemanagement.c

@@ -71,7 +71,7 @@ static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node *
     /* } */
     /* } */
 
 
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
-        vnode->value = attr.value;
+        vnode->variable.variant = attr.value;
         UA_Variant_init(&attr.value);
         UA_Variant_init(&attr.value);
     }
     }
 
 

+ 19 - 27
src/ua_types.c

@@ -572,24 +572,24 @@ UA_StatusCode UA_DataValue_copy(UA_DataValue const *src, UA_DataValue *dst) {
 UA_TYPE_NEW_DEFAULT(UA_Variant)
 UA_TYPE_NEW_DEFAULT(UA_Variant)
 void UA_Variant_init(UA_Variant *p) {
 void UA_Variant_init(UA_Variant *p) {
     p->storageType = UA_VARIANT_DATA;
     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.arrayDimensionsSize = -1;
+    p->arrayLength = -1;
+    p->dataPtr = UA_NULL;
+    p->arrayDimensions = UA_NULL;
+    p->arrayDimensionsSize = -1;
     p->type = UA_NULL;
     p->type = UA_NULL;
 }
 }
 
 
 UA_TYPE_DELETE_DEFAULT(UA_Variant)
 UA_TYPE_DELETE_DEFAULT(UA_Variant)
 void UA_Variant_deleteMembers(UA_Variant *p) {
 void UA_Variant_deleteMembers(UA_Variant *p) {
     if(p->storageType == UA_VARIANT_DATA) {
     if(p->storageType == UA_VARIANT_DATA) {
-        if(p->storage.data.dataPtr) {
-            UA_Array_delete(p->storage.data.dataPtr, p->type, p->storage.data.arrayLength);
-            p->storage.data.dataPtr = UA_NULL;
-            p->storage.data.arrayLength = 0;
+        if(p->dataPtr) {
+            UA_Array_delete(p->dataPtr, p->type, p->arrayLength);
+            p->dataPtr = UA_NULL;
+            p->arrayLength = -1;
         }
         }
-        if(p->storage.data.arrayDimensions) {
-            UA_free(p->storage.data.arrayDimensions);
-            p->storage.data.arrayDimensions = UA_NULL;
+        if(p->arrayDimensions) {
+            UA_free(p->arrayDimensions);
+            p->arrayDimensions = UA_NULL;
         }
         }
     }
     }
 }
 }
@@ -597,32 +597,24 @@ void UA_Variant_deleteMembers(UA_Variant *p) {
 UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
 UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
     UA_Variant_init(dst);
     UA_Variant_init(dst);
     dst->type = src->type;
     dst->type = src->type;
-    if(src->storageType == UA_VARIANT_DATASOURCE) {
-        dst->storageType = UA_VARIANT_DATASOURCE;
-        dst->storage = src->storage;
-        return UA_STATUSCODE_GOOD;
-    }
-    
-    UA_VariantData *dstdata = &dst->storage.data;
-    const UA_VariantData *srcdata = &src->storage.data;
     dst->storageType = UA_VARIANT_DATA;
     dst->storageType = UA_VARIANT_DATA;
-    UA_StatusCode retval = UA_Array_copy(srcdata->dataPtr, &dstdata->dataPtr, src->type, srcdata->arrayLength);
+    UA_StatusCode retval = UA_Array_copy(src->dataPtr, &dst->dataPtr, src->type, src->arrayLength);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Variant_deleteMembers(dst);
         UA_Variant_deleteMembers(dst);
         UA_Variant_init(dst);
         UA_Variant_init(dst);
         return retval;
         return retval;
     }
     }
-    dstdata->arrayLength = srcdata->arrayLength;
+    dst->arrayLength = src->arrayLength;
 
 
-    if(srcdata->arrayDimensions) {
-        retval |= UA_Array_copy(srcdata->arrayDimensions, (void **)&dstdata->arrayDimensions, &UA_TYPES[UA_TYPES_INT32],
-                                srcdata->arrayDimensionsSize);
+    if(src->arrayDimensions) {
+        retval |= UA_Array_copy(src->arrayDimensions, (void **)&dst->arrayDimensions,
+                                &UA_TYPES[UA_TYPES_INT32], src->arrayDimensionsSize);
         if(retval != UA_STATUSCODE_GOOD) {
         if(retval != UA_STATUSCODE_GOOD) {
             UA_Variant_deleteMembers(dst);
             UA_Variant_deleteMembers(dst);
             UA_Variant_init(dst);
             UA_Variant_init(dst);
         }
         }
     }
     }
-    dstdata->arrayDimensionsSize = srcdata->arrayDimensionsSize;
+    dst->arrayDimensionsSize = src->arrayDimensionsSize;
 
 
     return retval;
     return retval;
 }
 }
@@ -650,8 +642,8 @@ UA_StatusCode UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 noElement
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
 
 
     v->type = &UA_TYPES[typeIndex];
     v->type = &UA_TYPES[typeIndex];
-    v->storage.data.arrayLength = noElements;
-    v->storage.data.dataPtr = array;
+    v->arrayLength = noElements;
+    v->dataPtr = array;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 

+ 25 - 54
src/ua_types_encoding_binary.c

@@ -680,60 +680,36 @@ enum UA_VARIANT_ENCODINGMASKTYPE_enum {
 };
 };
 
 
 size_t UA_Variant_calcSizeBinary(UA_Variant const *p) {
 size_t UA_Variant_calcSizeBinary(UA_Variant const *p) {
-    if(p->type == UA_NULL) // type is not set after init
+    if(!p->type) // type is not set after init
         return 0;
         return 0;
-    const UA_VariantData *data;
-    UA_VariantData datasourceData;
-    if(p->storageType == UA_VARIANT_DATA || p->storageType == UA_VARIANT_DATA_NODELETE)
-        data = &p->storage.data;
-    else {
-        if(p->storage.datasource.read == UA_NULL || p->storage.datasource.read(p->storage.datasource.handle, &datasourceData) != UA_STATUSCODE_GOOD)
-            return 0;
-        data = &datasourceData;
-    }
-
     size_t length = sizeof(UA_Byte); //p->encodingMask
     size_t length = sizeof(UA_Byte); //p->encodingMask
-    UA_Int32 arrayLength = data->arrayLength;
-    if(arrayLength <= 0 || data->dataPtr == UA_NULL) {
+    UA_Int32 arrayLength = p->arrayLength;
+    if(arrayLength <= 0 || p->dataPtr == UA_NULL) {
         length += 4;
         length += 4;
         arrayLength = 0; // for adding the extensionobject overhead...
         arrayLength = 0; // for adding the extensionobject overhead...
     }
     }
     else if(arrayLength == 1)
     else if(arrayLength == 1)
-        length += UA_calcSizeBinary(data->dataPtr, p->type);
+        length += UA_calcSizeBinary(p->dataPtr, p->type);
     else
     else
-        length += UA_Array_calcSizeBinary(data->dataPtr, arrayLength, p->type);
+        length += UA_Array_calcSizeBinary(p->dataPtr, arrayLength, p->type);
         
         
     // if the type is not builtin, we encode it as an extensionobject
     // if the type is not builtin, we encode it as an extensionobject
     if(p->type->typeIndex > 24 || !p->type->namespaceZero)
     if(p->type->typeIndex > 24 || !p->type->namespaceZero)
         length += 9 * arrayLength;  // overhead for extensionobjects: 4 byte nodeid + 1 byte
         length += 9 * arrayLength;  // overhead for extensionobjects: 4 byte nodeid + 1 byte
                                     // encoding + 4 byte bytestring length
                                     // encoding + 4 byte bytestring length
-
-    if(arrayLength != 1 && data->arrayDimensions != UA_NULL)
-        length += UA_Array_calcSizeBinary(data->arrayDimensions, data->arrayDimensionsSize,
+    if(arrayLength != 1 && p->arrayDimensions != UA_NULL)
+        length += UA_Array_calcSizeBinary(p->arrayDimensions, p->arrayDimensionsSize,
                                           &UA_TYPES[UA_TYPES_INT32]);
                                           &UA_TYPES[UA_TYPES_INT32]);
-    
-    if(p->storageType == UA_VARIANT_DATASOURCE && p->storage.datasource.release != UA_NULL)
-        p->storage.datasource.release(p->storage.datasource.handle, &datasourceData);
-
     return length;
     return length;
 }
 }
 
 
 UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst, size_t *offset) {
 UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst, size_t *offset) {
-    const UA_VariantData  *data;
-    UA_VariantData datasourceData;
     if(!src->type)
     if(!src->type)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
-    if(src->storageType == UA_VARIANT_DATA)
-        data = &src->storage.data;
-    else {
-        if(src->storage.datasource.read == UA_NULL || src->storage.datasource.read(src->storage.datasource.handle, &datasourceData) != UA_STATUSCODE_GOOD)
-            return UA_STATUSCODE_BADENCODINGERROR;
-        data = &datasourceData;
-    }
     
     
     UA_Byte encodingByte = 0;
     UA_Byte encodingByte = 0;
-    UA_Boolean isArray = data->arrayLength != 1;  // a single element is not an array
-    UA_Boolean hasDimensions = isArray && data->arrayDimensions != UA_NULL;
+    UA_Boolean isArray = src->arrayLength != 1;  // a single element is not an array
+    UA_Boolean hasDimensions = isArray && src->arrayDimensions != UA_NULL;
     UA_Boolean isBuiltin = (src->type->namespaceZero && src->type->typeIndex <= 24);
     UA_Boolean isBuiltin = (src->type->namespaceZero && src->type->typeIndex <= 24);
 
 
     if(isArray) {
     if(isArray) {
@@ -750,8 +726,8 @@ UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst,
     UA_StatusCode retval = UA_Byte_encodeBinary(&encodingByte, dst, offset);
     UA_StatusCode retval = UA_Byte_encodeBinary(&encodingByte, dst, offset);
 
 
     if(isArray)
     if(isArray)
-        retval |= UA_Array_encodeBinary(data->dataPtr, data->arrayLength, src->type, dst, offset);
-    else if(!data->dataPtr)
+        retval |= UA_Array_encodeBinary(src->dataPtr, src->arrayLength, src->type, dst, offset);
+    else if(!src->dataPtr)
         retval = UA_STATUSCODE_BADENCODINGERROR; // an array can be empty. a single element must be present.
         retval = UA_STATUSCODE_BADENCODINGERROR; // an array can be empty. a single element must be present.
     else {
     else {
         if(!isBuiltin) {
         if(!isBuiltin) {
@@ -766,19 +742,15 @@ UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst,
         	}
         	}
             UA_Byte eoEncoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
             UA_Byte eoEncoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
             UA_Byte_encodeBinary(&eoEncoding, dst, offset);
             UA_Byte_encodeBinary(&eoEncoding, dst, offset);
-            UA_Int32 eoEncodingLength = UA_calcSizeBinary(data->dataPtr, src->type);
+            UA_Int32 eoEncodingLength = UA_calcSizeBinary(src->dataPtr, src->type);
             UA_Int32_encodeBinary(&eoEncodingLength, dst, offset);
             UA_Int32_encodeBinary(&eoEncodingLength, dst, offset);
         }
         }
-        retval |= UA_encodeBinary(data->dataPtr, src->type, dst, offset);
+        retval |= UA_encodeBinary(src->dataPtr, src->type, dst, offset);
     }
     }
 
 
     if(hasDimensions)
     if(hasDimensions)
-        retval |= UA_Array_encodeBinary(data->arrayDimensions, data->arrayDimensionsSize,
+        retval |= UA_Array_encodeBinary(src->arrayDimensions, src->arrayDimensionsSize,
                                         &UA_TYPES[UA_TYPES_INT32], dst, offset);
                                         &UA_TYPES[UA_TYPES_INT32], dst, offset);
-
-    if(src->storageType == UA_VARIANT_DATASOURCE && src->storage.datasource.release!=UA_NULL)
-        src->storage.datasource.release(src->storage.datasource.handle, &datasourceData);
-                     
     return retval;
     return retval;
 }
 }
 
 
@@ -790,7 +762,6 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset,
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;
 
 
-    UA_VariantData *data = &dst->storage.data;
     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_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,
@@ -808,29 +779,29 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset,
     const UA_DataType *dataType = &UA_TYPES[typeIndex];
     const UA_DataType *dataType = &UA_TYPES[typeIndex];
 
 
     if(!isArray) {
     if(!isArray) {
-        if(!(data->dataPtr = UA_malloc(dataType->memSize)))
+        if(!(dst->dataPtr = UA_malloc(dataType->memSize)))
             return UA_STATUSCODE_BADOUTOFMEMORY;
             return UA_STATUSCODE_BADOUTOFMEMORY;
-        retval |= UA_decodeBinary(src, offset, data->dataPtr, dataType);
+        retval |= UA_decodeBinary(src, offset, dst->dataPtr, dataType);
         if(retval) {
         if(retval) {
-            UA_free(data->dataPtr);
+            UA_free(dst->dataPtr);
             return retval;
             return retval;
         }
         }
-        data->arrayLength = 1;
+        dst->arrayLength = 1;
     } else {
     } else {
-        retval |= UA_Int32_decodeBinary(src, offset, &data->arrayLength);
+        retval |= UA_Int32_decodeBinary(src, offset, &dst->arrayLength);
         if(retval == UA_STATUSCODE_GOOD)
         if(retval == UA_STATUSCODE_GOOD)
-            retval |= UA_Array_decodeBinary(src, offset, data->arrayLength, &data->dataPtr, dataType);
+            retval |= UA_Array_decodeBinary(src, offset, dst->arrayLength, &dst->dataPtr, dataType);
         if(retval)
         if(retval)
-            data->arrayLength = -1; // for deleteMembers
+            dst->arrayLength = -1; // for deleteMembers
     }
     }
 
 
     if(hasDimensions && retval == UA_STATUSCODE_GOOD) {
     if(hasDimensions && retval == UA_STATUSCODE_GOOD) {
-        retval |= UA_Int32_decodeBinary(src, offset, &data->arrayDimensionsSize);
+        retval |= UA_Int32_decodeBinary(src, offset, &dst->arrayDimensionsSize);
         if(retval == UA_STATUSCODE_GOOD)
         if(retval == UA_STATUSCODE_GOOD)
-            retval |= UA_Array_decodeBinary(src, offset, data->arrayDimensionsSize,
-                                            &data->dataPtr, &UA_TYPES[UA_TYPES_INT32]);
+            retval |= UA_Array_decodeBinary(src, offset, dst->arrayDimensionsSize,
+                                            &dst->dataPtr, &UA_TYPES[UA_TYPES_INT32]);
         if(retval)
         if(retval)
-            data->arrayLength = -1; // for deleteMembers
+            dst->arrayLength = -1; // for deleteMembers
     }
     }
 
 
     dst->type = dataType;
     dst->type = dataType;

+ 47 - 47
tests/check_builtin.c

@@ -278,9 +278,9 @@ START_TEST(UA_Variant_calcSizeFixedSizeArrayShallReturnEncodingSize) {
 	UA_Variant_init(&arg);
 	UA_Variant_init(&arg);
     arg.type = &UA_TYPES[UA_TYPES_INT32];
     arg.type = &UA_TYPES[UA_TYPES_INT32];
 #define ARRAY_LEN 8
 #define ARRAY_LEN 8
-	arg.storage.data.arrayLength = ARRAY_LEN;
+	arg.arrayLength = ARRAY_LEN;
 	UA_Int32 *data[ARRAY_LEN];
 	UA_Int32 *data[ARRAY_LEN];
-	arg.storage.data.dataPtr = (void *)data;
+	arg.dataPtr = (void *)data;
 
 
 	// when
 	// when
 	UA_UInt32 encodingSize = UA_Variant_calcSizeBinary(&arg);
 	UA_UInt32 encodingSize = UA_Variant_calcSizeBinary(&arg);
@@ -297,12 +297,12 @@ START_TEST(UA_Variant_calcSizeVariableSizeArrayShallReturnEncodingSize) {
 	UA_Variant_init(&arg);
 	UA_Variant_init(&arg);
 	arg.type = &UA_TYPES[UA_TYPES_STRING];
 	arg.type = &UA_TYPES[UA_TYPES_STRING];
 #define ARRAY_LEN 3
 #define ARRAY_LEN 3
-	arg.storage.data.arrayLength = ARRAY_LEN;
+	arg.arrayLength = ARRAY_LEN;
 	UA_String strings[3];
 	UA_String strings[3];
 	strings[0] = (UA_String) {-1, UA_NULL };
 	strings[0] = (UA_String) {-1, UA_NULL };
 	strings[1] = (UA_String) {3, (UA_Byte *)"PLT" };
 	strings[1] = (UA_String) {3, (UA_Byte *)"PLT" };
 	strings[2] = (UA_String) {47, UA_NULL };
 	strings[2] = (UA_String) {47, UA_NULL };
-	arg.storage.data.dataPtr   = (void *)strings;
+	arg.dataPtr   = (void *)strings;
 	// when
 	// when
 	UA_UInt32 encodingSize = UA_Variant_calcSizeBinary(&arg);
 	UA_UInt32 encodingSize = UA_Variant_calcSizeBinary(&arg);
 	// then
 	// then
@@ -681,8 +681,8 @@ START_TEST(UA_Variant_decodeWithOutArrayFlagSetShallSetVTAndAllocateMemoryForArr
 	ck_assert_int_eq(pos, 5);
 	ck_assert_int_eq(pos, 5);
 	//ck_assert_ptr_eq((const void *)dst.type, (const void *)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
 	//ck_assert_ptr_eq((const void *)dst.type, (const void *)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
     ck_assert_int_eq((uintptr_t)dst.type, (uintptr_t)&UA_TYPES[UA_TYPES_INT32]); 
     ck_assert_int_eq((uintptr_t)dst.type, (uintptr_t)&UA_TYPES[UA_TYPES_INT32]); 
-	ck_assert_int_eq(dst.storage.data.arrayLength, 1);
-	ck_assert_int_eq(*(UA_Int32 *)dst.storage.data.dataPtr, 255);
+	ck_assert_int_eq(dst.arrayLength, 1);
+	ck_assert_int_eq(*(UA_Int32 *)dst.dataPtr, 255);
 	// finally
 	// finally
 	UA_Variant_deleteMembers(&dst);
 	UA_Variant_deleteMembers(&dst);
 }
 }
@@ -703,9 +703,9 @@ START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray)
 	ck_assert_int_eq(pos, 1+4+2*4);
 	ck_assert_int_eq(pos, 1+4+2*4);
 	//ck_assert_ptr_eq((const (void*))dst.type, (const void*)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
 	//ck_assert_ptr_eq((const (void*))dst.type, (const void*)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
     ck_assert_int_eq((uintptr_t)dst.type,(uintptr_t)&UA_TYPES[UA_TYPES_INT32]);
     ck_assert_int_eq((uintptr_t)dst.type,(uintptr_t)&UA_TYPES[UA_TYPES_INT32]);
-	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);
+	ck_assert_int_eq(dst.arrayLength, 2);
+	ck_assert_int_eq(((UA_Int32 *)dst.dataPtr)[0], 255);
+	ck_assert_int_eq(((UA_Int32 *)dst.dataPtr)[1], -1);
 	// finally
 	// finally
 	UA_Variant_deleteMembers(&dst);
 	UA_Variant_deleteMembers(&dst);
 }
 }
@@ -1135,9 +1135,9 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithVariant) {
     src.hasVariant = UA_TRUE;
     src.hasVariant = UA_TRUE;
     src.hasServerTimestamp = UA_TRUE;
     src.hasServerTimestamp = UA_TRUE;
 	src.value.type = &UA_TYPES[UA_TYPES_INT32];
 	src.value.type = &UA_TYPES[UA_TYPES_INT32];
-	src.value.storage.data.arrayLength  = 1; // one element (encoded as not an array)
+	src.value.arrayLength  = 1; // one element (encoded as not an array)
 	UA_Int32  vdata  = 45;
 	UA_Int32  vdata  = 45;
-	src.value.storage.data.dataPtr = (void *)&vdata;
+	src.value.dataPtr = (void *)&vdata;
 
 
 	UA_Byte data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	UA_Byte data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1464,25 +1464,25 @@ START_TEST(UA_Variant_copyShallWorkOnSingleValueExample) {
 	UA_Variant value, copiedValue;
 	UA_Variant value, copiedValue;
 	UA_Variant_init(&value);
 	UA_Variant_init(&value);
 	UA_Variant_init(&copiedValue);
 	UA_Variant_init(&copiedValue);
-	value.storage.data.dataPtr = UA_malloc(sizeof(UA_String));
-	*((UA_String*)value.storage.data.dataPtr) = testString;
+	value.dataPtr = UA_malloc(sizeof(UA_String));
+	*((UA_String*)value.dataPtr) = testString;
     value.type = &UA_TYPES[UA_TYPES_STRING];
     value.type = &UA_TYPES[UA_TYPES_STRING];
-	value.storage.data.arrayLength = 1;
+	value.arrayLength = 1;
 
 
 	//when
 	//when
 	UA_Variant_copy(&value, &copiedValue);
 	UA_Variant_copy(&value, &copiedValue);
 
 
 	//then
 	//then
-	UA_String copiedString = *(UA_String*)(copiedValue.storage.data.dataPtr);
+	UA_String copiedString = *(UA_String*)(copiedValue.dataPtr);
 	for(UA_Int32 i = 0;i < 5;i++)
 	for(UA_Int32 i = 0;i < 5;i++)
 		ck_assert_int_eq(copiedString.data[i], testString.data[i]);
 		ck_assert_int_eq(copiedString.data[i], testString.data[i]);
 	ck_assert_int_eq(copiedString.length, testString.length);
 	ck_assert_int_eq(copiedString.length, testString.length);
 
 
-	ck_assert_int_eq(value.storage.data.arrayDimensionsSize, copiedValue.storage.data.arrayDimensionsSize);
-	ck_assert_int_eq(value.storage.data.arrayLength, copiedValue.storage.data.arrayLength);
+	ck_assert_int_eq(value.arrayDimensionsSize, copiedValue.arrayDimensionsSize);
+	ck_assert_int_eq(value.arrayLength, copiedValue.arrayLength);
 
 
 	//finally
 	//finally
-	((UA_String*)value.storage.data.dataPtr)->data = UA_NULL; // the string is statically allocated. do not free it.
+	((UA_String*)value.dataPtr)->data = UA_NULL; // the string is statically allocated. do not free it.
 	UA_Variant_deleteMembers(&value);
 	UA_Variant_deleteMembers(&value);
 	UA_Variant_deleteMembers(&copiedValue);
 	UA_Variant_deleteMembers(&copiedValue);
 }
 }
@@ -1503,32 +1503,32 @@ START_TEST(UA_Variant_copyShallWorkOn1DArrayExample) {
 	UA_Variant_init(&value);
 	UA_Variant_init(&value);
 	UA_Variant_init(&copiedValue);
 	UA_Variant_init(&copiedValue);
 
 
-	value.storage.data.arrayLength = 3;
-	value.storage.data.dataPtr = (void *)srcArray;
-	value.storage.data.arrayDimensionsSize = 1;
-	value.storage.data.arrayDimensions = dimensions;
+	value.arrayLength = 3;
+	value.dataPtr = (void *)srcArray;
+	value.arrayDimensionsSize = 1;
+	value.arrayDimensions = dimensions;
 	value.type = &UA_TYPES[UA_TYPES_STRING];
 	value.type = &UA_TYPES[UA_TYPES_STRING];
 
 
 	//when
 	//when
 	UA_Variant_copy(&value, &copiedValue);
 	UA_Variant_copy(&value, &copiedValue);
 
 
 	//then
 	//then
-	UA_Int32 i1 = value.storage.data.arrayDimensions[0];
-	UA_Int32 i2 = copiedValue.storage.data.arrayDimensions[0];
+	UA_Int32 i1 = value.arrayDimensions[0];
+	UA_Int32 i2 = copiedValue.arrayDimensions[0];
 	ck_assert_int_eq(i1, i2);
 	ck_assert_int_eq(i1, i2);
 
 
 	for(UA_Int32 i = 0;i < 3;i++) {
 	for(UA_Int32 i = 0;i < 3;i++) {
 		for(UA_Int32 j = 0;j < 6;j++) {
 		for(UA_Int32 j = 0;j < 6;j++) {
-			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.dataPtr)[i].data[j],
+					((UA_String *)copiedValue.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 *)value.dataPtr)[i].length,
+				((UA_String *)copiedValue.dataPtr)[i].length);
 	}
 	}
-	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.storage.data.arrayDimensionsSize, copiedValue.storage.data.arrayDimensionsSize);
-	ck_assert_int_eq(value.storage.data.arrayLength, copiedValue.storage.data.arrayLength);
+	ck_assert_int_eq(((UA_String *)copiedValue.dataPtr)[0].data[2], 'o');
+	ck_assert_int_eq(((UA_String *)copiedValue.dataPtr)[0].data[3], 'p');
+	ck_assert_int_eq(value.arrayDimensionsSize, copiedValue.arrayDimensionsSize);
+	ck_assert_int_eq(value.arrayLength, copiedValue.arrayLength);
 
 
 	//finally
 	//finally
 	UA_Variant_deleteMembers(&value);
 	UA_Variant_deleteMembers(&value);
@@ -1556,10 +1556,10 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 	UA_Variant_init(&value);
 	UA_Variant_init(&value);
 	UA_Variant_init(&copiedValue);
 	UA_Variant_init(&copiedValue);
 
 
-	value.storage.data.arrayLength = 6;
-	value.storage.data.dataPtr     = srcArray;
-	value.storage.data.arrayDimensionsSize = 2;
-	value.storage.data.arrayDimensions       = dimensions;
+	value.arrayLength = 6;
+	value.dataPtr     = srcArray;
+	value.arrayDimensionsSize = 2;
+	value.arrayDimensions     = dimensions;
 	value.type = &UA_TYPES[UA_TYPES_INT32];
 	value.type = &UA_TYPES[UA_TYPES_INT32];
 
 
 	//when
 	//when
@@ -1567,28 +1567,28 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 
 
 	//then
 	//then
 	//1st dimension
 	//1st dimension
-	UA_Int32 i1 = value.storage.data.arrayDimensions[0];
-	UA_Int32 i2 = copiedValue.storage.data.arrayDimensions[0];
+	UA_Int32 i1 = value.arrayDimensions[0];
+	UA_Int32 i2 = copiedValue.arrayDimensions[0];
 	ck_assert_int_eq(i1, i2);
 	ck_assert_int_eq(i1, i2);
 	ck_assert_int_eq(i1, dim1);
 	ck_assert_int_eq(i1, dim1);
 
 
 
 
 	//2nd dimension
 	//2nd dimension
-	i1 = value.storage.data.arrayDimensions[1];
-	i2 = copiedValue.storage.data.arrayDimensions[1];
+	i1 = value.arrayDimensions[1];
+	i2 = copiedValue.arrayDimensions[1];
 	ck_assert_int_eq(i1, i2);
 	ck_assert_int_eq(i1, i2);
 	ck_assert_int_eq(i1, dim2);
 	ck_assert_int_eq(i1, dim2);
 
 
 
 
 	for(UA_Int32 i = 0;i < 6;i++) {
 	for(UA_Int32 i = 0;i < 6;i++) {
-		i1 = ((UA_Int32 *)value.storage.data.dataPtr)[i];
-		i2 = ((UA_Int32 *)copiedValue.storage.data.dataPtr)[i];
+		i1 = ((UA_Int32 *)value.dataPtr)[i];
+		i2 = ((UA_Int32 *)copiedValue.dataPtr)[i];
 		ck_assert_int_eq(i1, i2);
 		ck_assert_int_eq(i1, i2);
 		ck_assert_int_eq(i2, i);
 		ck_assert_int_eq(i2, i);
 	}
 	}
 
 
-	ck_assert_int_eq(value.storage.data.arrayDimensionsSize, copiedValue.storage.data.arrayDimensionsSize);
-	ck_assert_int_eq(value.storage.data.arrayLength, copiedValue.storage.data.arrayLength);
+	ck_assert_int_eq(value.arrayDimensionsSize, copiedValue.arrayDimensionsSize);
+	ck_assert_int_eq(value.arrayLength, copiedValue.arrayLength);
 
 
 	//finally
 	//finally
 	UA_Variant_deleteMembers(&value);
 	UA_Variant_deleteMembers(&value);
@@ -1603,8 +1603,8 @@ START_TEST(UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject) {
 	varAttr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
 	varAttr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
 	UA_Variant_init(&varAttr.value);
 	UA_Variant_init(&varAttr.value);
 	varAttr.value.type = &UA_TYPES[UA_TYPES_INT32];
 	varAttr.value.type = &UA_TYPES[UA_TYPES_INT32];
-	varAttr.value.storage.data.dataPtr = &val;
-	varAttr.value.storage.data.arrayLength = 1;
+	varAttr.value.dataPtr = &val;
+	varAttr.value.arrayLength = 1;
 	varAttr.userWriteMask = 41;
 	varAttr.userWriteMask = 41;
 	varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DATATYPE;
 	varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DATATYPE;
 	varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUE;
 	varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUE;
@@ -1638,7 +1638,7 @@ START_TEST(UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject) {
 	posDecode = 0;
 	posDecode = 0;
 	UA_VariableAttributes_decodeBinary(&extensionObjectDecoded.body, &posDecode, &varAttrDecoded);
 	UA_VariableAttributes_decodeBinary(&extensionObjectDecoded.body, &posDecode, &varAttrDecoded);
 	ck_assert_uint_eq(41, varAttrDecoded.userWriteMask);
 	ck_assert_uint_eq(41, varAttrDecoded.userWriteMask);
-	ck_assert_int_eq(1, varAttrDecoded.value.storage.data.arrayLength);
+	ck_assert_int_eq(1, varAttrDecoded.value.arrayLength);
 
 
     // finally
     // finally
     UA_ExtensionObject_deleteMembers(&extensionObjectDecoded);
     UA_ExtensionObject_deleteMembers(&extensionObjectDecoded);