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 */
 /*************************/
-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();
     if(!currentTime)
         return UA_STATUSCODE_BADOUTOFMEMORY;
     *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;
 }
 
-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;
 }
 
@@ -51,28 +52,31 @@ static void printDeviceStatus(UA_Server *server, void *data) {
     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
        and return a copy of the data. */
     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;
 }
 
-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
        variantdata. */
-    data->dataPtr = UA_NULL;
-    data->arrayLength = -1;
+    value->value.arrayLength = -1;
+    value->value.dataPtr = NULL;
     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);
-    if(data->dataPtr != UA_NULL)
+    if(data->dataPtr)
         deviceStatus = *(UA_Int32*)data->dataPtr;
     pthread_rwlock_unlock(&deviceStatusLock);
     return UA_STATUSCODE_GOOD;
@@ -94,8 +98,7 @@ int main(int argc, char** argv) {
 
     // add node with the datetime data source
     UA_Variant *dateVariant = UA_Variant_new();
-    dateVariant->storageType = UA_VARIANT_DATASOURCE;
-    dateVariant->storage.datasource = (UA_VariantDataSource)
+    dateVariant->storage.datasource = (UA_DataSource)
         {.handle = UA_NULL,
          .read = readTimeData,
          .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,
                                                   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
     thread. */
 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_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;
 typedef struct UA_DataType UA_DataType; 
 
@@ -225,13 +202,11 @@ typedef struct {
                                        deleted at the end of this variant's lifecycle. It is not
                                        possible to overwrite borrowed data due to concurrent access.
                                        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;
-    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;
 
 /** @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) {
 	UA_Node_init((UA_Node*)p);
     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->accessLevel = 0;
     p->userAccessLevel = 0;
@@ -117,7 +118,8 @@ UA_VariableNode * UA_VariableNode_new(void) {
 
 void UA_VariableNode_deleteMembers(UA_VariableNode *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) {
@@ -128,7 +130,11 @@ void UA_VariableNode_delete(UA_VariableNode *p) {
 UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
     UA_VariableNode_init(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) {
         UA_VariableNode_deleteMembers(dst);
         return retval;

+ 9 - 2
src/server/ua_nodes.h

@@ -1,6 +1,7 @@
 #ifndef UA_NODES_H_
 #define UA_NODES_H_
 
+#include "ua_server.h"
 #include "ua_types_generated.h"
 #include "ua_types_encoding_binary.h"
 
@@ -33,8 +34,14 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
 
 typedef struct {
     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.
                              n = 0: the value is an array with one or more dimensions.
                              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();
     COPYNAMES(namespaceArray, "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
     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 *)(namespaceArray->value.storage.data.dataPtr))[1]);
+                          &((UA_String *)(namespaceArray->variable.variant.dataPtr))[1]);
     namespaceArray->valueRank = 1;
     namespaceArray->minimumSamplingInterval = 1.0;
     namespaceArray->historizing = UA_FALSE;
@@ -651,10 +652,10 @@ UA_Server * UA_Server_new(void) {
     *stateEnum = UA_SERVERSTATE_RUNNING;
     COPYNAMES(state, "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);
     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));

+ 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,
                                         const UA_NodeId *referenceTypeId) {
     UA_VariableNode *node = UA_VariableNode_new();
-    node->value = *value; // copy content
+    node->variable.variant = *value; // copy content
     UA_NodeId_copy(nodeId, &node->nodeId);
     UA_QualifiedName_copy(browseName, &node->browseName);
     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),
                  UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
     if(res.statusCode != UA_STATUSCODE_GOOD) {
-        UA_Variant_init(&node->value);
+        UA_Variant_init(&node->variable.variant);
         UA_VariableNode_delete(node);
     } else {
         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:
         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;
 
@@ -128,23 +141,27 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         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;
-            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;
 
@@ -364,22 +381,20 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
             }
 
             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;
             } 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
                 UA_VariableNode *newVn = (UA_VariableNode*)newNode();
                 if(!newVn) {
@@ -391,7 +406,7 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
                     deleteNode((UA_Node*)newVn);
                     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) {
                     deleteNode((UA_Node*)newVn);
                     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) {
-        vnode->value = attr.value;
+        vnode->variable.variant = 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)
 void UA_Variant_init(UA_Variant *p) {
     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;
 }
 
 UA_TYPE_DELETE_DEFAULT(UA_Variant)
 void UA_Variant_deleteMembers(UA_Variant *p) {
     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_Variant_init(dst);
     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;
-    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) {
         UA_Variant_deleteMembers(dst);
         UA_Variant_init(dst);
         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) {
             UA_Variant_deleteMembers(dst);
             UA_Variant_init(dst);
         }
     }
-    dstdata->arrayDimensionsSize = srcdata->arrayDimensionsSize;
+    dst->arrayDimensionsSize = src->arrayDimensionsSize;
 
     return retval;
 }
@@ -650,8 +642,8 @@ UA_StatusCode UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 noElement
         return UA_STATUSCODE_BADINTERNALERROR;
 
     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;
 }
 

+ 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) {
-    if(p->type == UA_NULL) // type is not set after init
+    if(!p->type) // type is not set after init
         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
-    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;
         arrayLength = 0; // for adding the extensionobject overhead...
     }
     else if(arrayLength == 1)
-        length += UA_calcSizeBinary(data->dataPtr, p->type);
+        length += UA_calcSizeBinary(p->dataPtr, p->type);
     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(p->type->typeIndex > 24 || !p->type->namespaceZero)
         length += 9 * arrayLength;  // overhead for extensionobjects: 4 byte nodeid + 1 byte
                                     // 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]);
-    
-    if(p->storageType == UA_VARIANT_DATASOURCE && p->storage.datasource.release != UA_NULL)
-        p->storage.datasource.release(p->storage.datasource.handle, &datasourceData);
-
     return length;
 }
 
 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)
         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_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);
 
     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);
 
     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.
     else {
         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_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);
         }
-        retval |= UA_encodeBinary(data->dataPtr, src->type, dst, offset);
+        retval |= UA_encodeBinary(src->dataPtr, src->type, dst, offset);
     }
 
     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);
-
-    if(src->storageType == UA_VARIANT_DATASOURCE && src->storage.datasource.release!=UA_NULL)
-        src->storage.datasource.release(src->storage.datasource.handle, &datasourceData);
-                     
     return retval;
 }
 
@@ -790,7 +762,6 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset,
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
-    UA_VariantData *data = &dst->storage.data;
     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,
@@ -808,29 +779,29 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset,
     const UA_DataType *dataType = &UA_TYPES[typeIndex];
 
     if(!isArray) {
-        if(!(data->dataPtr = UA_malloc(dataType->memSize)))
+        if(!(dst->dataPtr = UA_malloc(dataType->memSize)))
             return UA_STATUSCODE_BADOUTOFMEMORY;
-        retval |= UA_decodeBinary(src, offset, data->dataPtr, dataType);
+        retval |= UA_decodeBinary(src, offset, dst->dataPtr, dataType);
         if(retval) {
-            UA_free(data->dataPtr);
+            UA_free(dst->dataPtr);
             return retval;
         }
-        data->arrayLength = 1;
+        dst->arrayLength = 1;
     } else {
-        retval |= UA_Int32_decodeBinary(src, offset, &data->arrayLength);
+        retval |= UA_Int32_decodeBinary(src, offset, &dst->arrayLength);
         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)
-            data->arrayLength = -1; // for deleteMembers
+            dst->arrayLength = -1; // for deleteMembers
     }
 
     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)
-            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)
-            data->arrayLength = -1; // for deleteMembers
+            dst->arrayLength = -1; // for deleteMembers
     }
 
     dst->type = dataType;

+ 47 - 47
tests/check_builtin.c

@@ -278,9 +278,9 @@ START_TEST(UA_Variant_calcSizeFixedSizeArrayShallReturnEncodingSize) {
 	UA_Variant_init(&arg);
     arg.type = &UA_TYPES[UA_TYPES_INT32];
 #define ARRAY_LEN 8
-	arg.storage.data.arrayLength = ARRAY_LEN;
+	arg.arrayLength = ARRAY_LEN;
 	UA_Int32 *data[ARRAY_LEN];
-	arg.storage.data.dataPtr = (void *)data;
+	arg.dataPtr = (void *)data;
 
 	// when
 	UA_UInt32 encodingSize = UA_Variant_calcSizeBinary(&arg);
@@ -297,12 +297,12 @@ START_TEST(UA_Variant_calcSizeVariableSizeArrayShallReturnEncodingSize) {
 	UA_Variant_init(&arg);
 	arg.type = &UA_TYPES[UA_TYPES_STRING];
 #define ARRAY_LEN 3
-	arg.storage.data.arrayLength = ARRAY_LEN;
+	arg.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.storage.data.dataPtr   = (void *)strings;
+	arg.dataPtr   = (void *)strings;
 	// when
 	UA_UInt32 encodingSize = UA_Variant_calcSizeBinary(&arg);
 	// then
@@ -681,8 +681,8 @@ START_TEST(UA_Variant_decodeWithOutArrayFlagSetShallSetVTAndAllocateMemoryForArr
 	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_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
 	UA_Variant_deleteMembers(&dst);
 }
@@ -703,9 +703,9 @@ START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray)
 	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_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
 	UA_Variant_deleteMembers(&dst);
 }
@@ -1135,9 +1135,9 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithVariant) {
     src.hasVariant = UA_TRUE;
     src.hasServerTimestamp = UA_TRUE;
 	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;
-	src.value.storage.data.dataPtr = (void *)&vdata;
+	src.value.dataPtr = (void *)&vdata;
 
 	UA_Byte data[] = { 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_init(&value);
 	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.storage.data.arrayLength = 1;
+	value.arrayLength = 1;
 
 	//when
 	UA_Variant_copy(&value, &copiedValue);
 
 	//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++)
 		ck_assert_int_eq(copiedString.data[i], testString.data[i]);
 	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
-	((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(&copiedValue);
 }
@@ -1503,32 +1503,32 @@ START_TEST(UA_Variant_copyShallWorkOn1DArrayExample) {
 	UA_Variant_init(&value);
 	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];
 
 	//when
 	UA_Variant_copy(&value, &copiedValue);
 
 	//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);
 
 	for(UA_Int32 i = 0;i < 3;i++) {
 		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
 	UA_Variant_deleteMembers(&value);
@@ -1556,10 +1556,10 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 	UA_Variant_init(&value);
 	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];
 
 	//when
@@ -1567,28 +1567,28 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 
 	//then
 	//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, dim1);
 
 
 	//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, dim2);
 
 
 	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(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
 	UA_Variant_deleteMembers(&value);
@@ -1603,8 +1603,8 @@ START_TEST(UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject) {
 	varAttr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
 	UA_Variant_init(&varAttr.value);
 	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.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DATATYPE;
 	varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUE;
@@ -1638,7 +1638,7 @@ START_TEST(UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject) {
 	posDecode = 0;
 	UA_VariableAttributes_decodeBinary(&extensionObjectDecoded.body, &posDecode, &varAttrDecoded);
 	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
     UA_ExtensionObject_deleteMembers(&extensionObjectDecoded);