Ver código fonte

improve documentation, make array api more intuitive

Julius Pfrommer 10 anos atrás
pai
commit
6a0b6f5ab9

+ 5 - 5
examples/client.c

@@ -319,7 +319,7 @@ static UA_Int64 sendReadRequest(ConnectionInfo *connectionInfo, UA_Int32 nodeIds
 	UA_ReadRequest rq;
 	UA_ReadRequest_init(&rq);
 	rq.maxAge = 0;
-	UA_Array_new((void **)&rq.nodesToRead, nodeIds_size, &UA_TYPES[UA_TYPES_READVALUEID]);
+	rq.nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], nodeIds_size);
 	rq.nodesToReadSize = nodeIds_size;
 	for(UA_Int32 i=0;i<nodeIds_size;i++) {
 		UA_ReadValueId_init(&(rq.nodesToRead[i]));
@@ -347,7 +347,7 @@ static UA_Int64 sendReadRequest(ConnectionInfo *connectionInfo, UA_Int32 nodeIds
 
 	UA_DateTime tic = UA_DateTime_now();
 	UA_Int32 sendret = send(connectionInfo->socket, message->data, offset, 0);
-	UA_Array_delete(rq.nodesToRead,nodeIds_size,&UA_TYPES[UA_TYPES_READVALUEID]);
+	UA_Array_delete(rq.nodesToRead, &UA_TYPES[UA_TYPES_READVALUEID], nodeIds_size);
 	UA_ByteString_delete(message);
 
 	if (sendret < 0) {
@@ -502,7 +502,7 @@ int main(int argc, char *argv[]) {
 
 /* REQUEST START*/
     UA_NodeId *nodesToRead;
-    UA_Array_new((void**)&nodesToRead,nodesToReadSize,&UA_TYPES[UA_TYPES_NODEID]);
+    nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_NODEID], nodesToReadSize);
 
 	for(UA_UInt32 i = 0; i<nodesToReadSize; i++) {
 		if(alwaysSameNode)
@@ -516,7 +516,7 @@ int main(int argc, char *argv[]) {
 	UA_DateTime tic, toc;
 	UA_Double *timeDiffs;
 	UA_Int32 received;
-	UA_Array_new((void**)&timeDiffs,tries,&UA_TYPES[UA_TYPES_DOUBLE]);
+	timeDiffs = UA_Array_new(&UA_TYPES[UA_TYPES_DOUBLE], tries);
 	UA_Double sum = 0;
 
 	for(UA_UInt32 i = 0; i < tries; i++) {
@@ -576,7 +576,7 @@ int main(int argc, char *argv[]) {
 	fclose(fHandle);
 
 	UA_String_deleteMembers(&reply);
-	UA_Array_delete(nodesToRead,nodesToReadSize,&UA_TYPES[UA_TYPES_NODEID]);
+	UA_Array_delete(nodesToRead,&UA_TYPES[UA_TYPES_NODEID], nodesToReadSize);
     UA_free(timeDiffs);
 
 	return 0;

+ 139 - 9
include/ua_types.h

@@ -330,17 +330,25 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_DiagnosticInfo)
 #endif
 
 /* String */
+/** Copy a (zero terminated) char-array into a UA_String. Memory for the string data is
+    allocated. */
+UA_StatusCode UA_EXPORT UA_String_copycstring(char const *src, UA_String *dst);
+
+/** Printf a char-array into a UA_String. Memory for the string data is allocated. */
+UA_StatusCode UA_EXPORT UA_String_copyprintf(char const *fmt, UA_String *dst, ...);
+
+/** Compares two strings */
+UA_Boolean UA_EXPORT UA_String_equal(const UA_String *string1, const UA_String *string2);
+
 #define UA_STRING_NULL (UA_String) {-1, (UA_Byte*)0 }
 #define UA_STRING_ASSIGN(VARIABLE, STRING) do { \
         VARIABLE.length = sizeof(STRING)-1;     \
         VARIABLE.data   = (UA_Byte *)STRING; } while(0)
 
-UA_StatusCode UA_EXPORT UA_String_copycstring(char const *src, UA_String *dst);
-UA_StatusCode UA_EXPORT UA_String_copyprintf(char const *fmt, UA_String *dst, ...);
-UA_Boolean UA_EXPORT UA_String_equal(const UA_String *string1, const UA_String *string2);
-
 /* DateTime */
+/** Returns the current time */
 UA_DateTime UA_EXPORT UA_DateTime_now(void);
+
 typedef struct UA_DateTimeStruct {
     UA_Int16 nanoSec;
     UA_Int16 microSec;
@@ -352,32 +360,45 @@ typedef struct UA_DateTimeStruct {
     UA_Int16 month;
     UA_Int16 year;
 } UA_DateTimeStruct;
+
 UA_DateTimeStruct UA_EXPORT UA_DateTime_toStruct(UA_DateTime time);
 UA_StatusCode UA_EXPORT UA_DateTime_toString(UA_DateTime time, UA_String *timeString);
 
 /* Guid */
+/** Compares two guids */
 UA_Boolean UA_EXPORT UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
-/** Do not use for security-critical entropy! */
+    
+/** Returns a randomly generated guid. Do not use for security-critical entropy! */
 UA_Guid UA_EXPORT UA_Guid_random(UA_UInt32 *seed);
 
 /* ByteString */
-UA_Boolean UA_EXPORT UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2);
+#define UA_ByteString_equal(string1, string2) \
+    UA_String_equal((const UA_String*) string1, (const UA_String*)string2)
+
+/** Allocates memory of size length for the bytestring. The content is not set to zero. */
 UA_StatusCode UA_EXPORT UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length);
 
 /* NodeId */
+/** Compares two nodeids */
 UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
+
+/** Is the nodeid a null-nodeid? */
 UA_Boolean UA_EXPORT UA_NodeId_isNull(const UA_NodeId *p);
+
 #define UA_NODEID_ASSIGN(VARIABLE, NAMESPACE, NUMERICID) do {                 \
         VARIABLE.namespaceIndex = NAMESPACE;                                  \
         VARIABLE.identifierType = CPP_ONLY(UA_NodeId::)UA_NODEIDTYPE_NUMERIC; \
         VARIABLE.identifier.numeric = NUMERICID; } while(0);
+
 #define UA_NODEID_STATIC(NAMESPACE, NUMERICID) (UA_NodeId) {              \
     .namespaceIndex = NAMESPACE, .identifierType = UA_NODEIDTYPE_NUMERIC, \
     .identifier.numeric = NUMERICID }
+
 #define UA_NODEID_NULL UA_NODEID_STATIC(0,0)
 
 /* ExpandedNodeId */
 UA_Boolean UA_EXPORT UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
+
 #define UA_EXPANDEDNODEID_STATIC(NAMESPACE, NUMERICID) (UA_ExpandedNodeId) {             \
         .nodeId = {.namespaceIndex = NAMESPACE, .identifierType = UA_NODEIDTYPE_NUMERIC, \
                    .identifier.numeric = NUMERICID },                                    \
@@ -390,12 +411,58 @@ UA_StatusCode UA_EXPORT UA_QualifiedName_copycstring(char const *src, UA_Qualifi
         UA_STRING_ASSIGN(VARIABLE.name, STRING); } while(0)
 
 /* LocalizedText */
+/** Copy a (zero-terminated) char-array into the UA_LocalizedText. Memory for the string is
+    allocated. The locale is set to "en" by default. */
 UA_StatusCode UA_EXPORT UA_LocalizedText_copycstring(char const *src, UA_LocalizedText *dst);
 
 /* Variant */
+
+/**
+ * Set the variant to a scalar value that already resides in memory. The value takes on the
+ * lifecycle of the variant and is deleted with it.
+ *
+ * @param v The variant
+ * @param p A pointer to the data
+ * @param typeIndex The index of the datatype (from namespace 0) as defined in ua_types_generated.h.
+ * For example, typeIndex == UA_TYPES_INT32
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
 UA_StatusCode UA_EXPORT UA_Variant_setValue(UA_Variant *v, void *p, UA_UInt16 typeIndex);
+
+/**
+ * Set the variant to a scalar value that is copied from an existing variable.
+ *
+ * @param v The variant
+ * @param p A pointer to the data
+ * @param typeIndex The index of the datatype (from namespace 0) as defined in ua_types_generated.h.
+ * For example, typeIndex == UA_TYPES_INT32
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
 UA_StatusCode UA_EXPORT UA_Variant_copySetValue(UA_Variant *v, const void *p, UA_UInt16 typeIndex);
+
+/**
+ * Set the variant to an array that already resides in memory. The array takes on the lifecycle of
+ * the variant and is deleted with it.
+ *
+ * @param v The variant
+ * @param array A pointer to the array data
+ * @param noElements The size of the array
+ * @param typeIndex The index of the datatype (from namespace 0) as defined in ua_types_generated.h.
+ * For example, typeIndex == UA_TYPES_INT32
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
 UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 noElements, UA_UInt16 typeIndex);
+
+/**
+ * Set the variant to an array that is copied from an existing array.
+ *
+ * @param v The variant
+ * @param array A pointer to the array data
+ * @param noElements The size of the array
+ * @param typeIndex The index of the datatype (from namespace 0) as defined in ua_types_generated.h.
+ * For example, typeIndex == UA_TYPES_INT32
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
 UA_StatusCode UA_EXPORT UA_Variant_copySetArray(UA_Variant *v, const void *array, UA_Int32 noElements, UA_UInt16 typeIndex);
 
 /****************************/
@@ -433,10 +500,49 @@ struct UA_DataType {
     UA_DataTypeMember members[UA_MAX_TYPE_MEMBERS];
 };
 
+/**
+ * Allocates and initializes a variable of type dataType
+ *
+ * @param dataType The datatype description
+ * @return Returns the memory location of the variable or (void*)0 if no memory is available
+ */
 void UA_EXPORT * UA_new(const UA_DataType *dataType);
+
+/**
+ * Initializes a variable to default values
+ *
+ * @param p The memory location of the variable
+ * @param dataType The datatype description
+ */
 void UA_EXPORT UA_init(void *p, const UA_DataType *dataType);
+
+/**
+ * Copies the content of two variables. If copying fails (e.g. because no memory was available for
+ * an array), then dst is emptied and initialized to prevent memory leaks.
+ *
+ * @param src The memory location of the source variable
+ * @param dst The memory location of the destination variable
+ * @param dataType The datatype description
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
 UA_StatusCode UA_EXPORT UA_copy(const void *src, void *dst, const UA_DataType *dataType);
+
+/**
+ * Deletes the dynamically assigned content of a variable (e.g. a member-array). Afterwards, the
+ * variable can be safely deleted without causing memory leaks. But the variable is not initialized
+ * and may contain old data that is not memory-relevant.
+ *
+ * @param p The memory location of the variable
+ * @param dataType The datatype description of the variable
+ */
 void UA_EXPORT UA_deleteMembers(void *p, const UA_DataType *dataType);
+
+/**
+ * Deletes (frees) a variable and all of its content.
+ *
+ * @param p The memory location of the variable
+ * @param dataType The datatype description of the variable
+ */
 void UA_EXPORT UA_delete(void *p, const UA_DataType *dataType);
 
 /********************/
@@ -445,9 +551,33 @@ void UA_EXPORT UA_delete(void *p, const UA_DataType *dataType);
 
 #define MAX_ARRAY_SIZE 104857600 // arrays must be smaller than 100MB
 
-UA_StatusCode UA_EXPORT UA_Array_new(void **p, UA_Int32 noElements, const UA_DataType *dataType);
-UA_StatusCode UA_EXPORT UA_Array_copy(const void *src, UA_Int32 noElements, void **dst, const UA_DataType *dataType);
-void UA_EXPORT UA_Array_delete(void *p, UA_Int32 noElements, const UA_DataType *dataType);
+/**
+ * Allocates and initializes an array of variables of a specific type
+ *
+ * @param dataType The datatype description
+ * @return Returns the memory location of the variable or (void*)0 if no memory could be allocated
+ */
+void* UA_EXPORT UA_Array_new(const UA_DataType *dataType, UA_Int32 noElements);
+
+/**
+ * Allocates and copies an array. dst is set to (void*)0 if not enough memory is available.
+ *
+ * @param src The memory location of the souce array
+ * @param dst The memory location where the pointer to the destination array is written
+ * @param dataType The datatype of the array members
+ * @param noElements The size of the array
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_Array_copy(const void *src, void **dst, const UA_DataType *dataType, UA_Int32 noElements);
+
+/**
+ * Deletes an array.
+ *
+ * @param src The memory location of the array
+ * @param dataType The datatype of the array members
+ * @param noElements The size of the array
+ */
+void UA_EXPORT UA_Array_delete(void *p, const UA_DataType *dataType, UA_Int32 noElements);
 
 /** @} */
 

+ 3 - 3
src/server/ua_nodes.c

@@ -19,7 +19,7 @@ static void UA_Node_deleteMembers(UA_Node *p) {
 	UA_QualifiedName_deleteMembers(&p->browseName);
 	UA_LocalizedText_deleteMembers(&p->displayName);
 	UA_LocalizedText_deleteMembers(&p->description);
-	UA_Array_delete(p->references, p->referencesSize, &UA_TYPES[UA_TYPES_REFERENCENODE]);
+	UA_Array_delete(p->references, &UA_TYPES[UA_TYPES_REFERENCENODE], p->referencesSize);
 }
 
 static UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) {
@@ -33,8 +33,8 @@ static UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) {
 	dst->writeMask = src->writeMask;
 	dst->userWriteMask = src->userWriteMask;
 	dst->referencesSize = src->referencesSize;
-	retval |= UA_Array_copy(src->references, src->referencesSize, (void**)&dst->references,
-                            &UA_TYPES[UA_TYPES_REFERENCENODE]);
+	retval |= UA_Array_copy(src->references, (void**)&dst->references, &UA_TYPES[UA_TYPES_REFERENCENODE],
+                            src->referencesSize);
 	if(retval)
     	UA_Node_deleteMembers(dst);
 	return retval;

+ 2 - 3
src/server/ua_server.c

@@ -61,8 +61,7 @@ void UA_Server_delete(UA_Server *server) {
     UA_SessionManager_deleteMembers(&server->sessionManager);
     UA_NodeStore_delete(server->nodestore);
     UA_ByteString_deleteMembers(&server->serverCertificate);
-    UA_Array_delete(server->endpointDescriptions, server->endpointDescriptionsSize,
-                    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
+    UA_Array_delete(server->endpointDescriptions, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], server->endpointDescriptionsSize);
 #ifdef UA_MULTITHREADING
     pthread_cond_destroy(&server->dispatchQueue_condition); // so the workers don't spin if the queue is empty
     rcu_barrier(); // wait for all scheduled call_rcu work to complete
@@ -472,7 +471,7 @@ UA_Server * UA_Server_new(void) {
     COPYNAMES(namespaceArray, "NamespaceArray");
     namespaceArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_NAMESPACEARRAY;
     namespaceArray->nodeClass = UA_NODECLASS_VARIABLE;
-    UA_Array_new(&namespaceArray->value.storage.data.dataPtr, 2, &UA_TYPES[UA_TYPES_STRING]);
+    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->value.typeId.identifier.numeric = UA_TYPES_IDS[UA_TYPES_STRING];

+ 1 - 1
src/server/ua_server_addressspace.c

@@ -97,7 +97,7 @@ static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session
     new_refs[count].isInverse = !item->isForward;
     retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Array_delete(new_refs, ++count, &UA_TYPES[UA_TYPES_REFERENCENODE]);
+        UA_Array_delete(new_refs, &UA_TYPES[UA_TYPES_REFERENCENODE], ++count);
         newNode->references = UA_NULL;
         newNode->referencesSize = 0;
         deleteNode(newNode);

+ 6 - 8
src/server/ua_services_attribute.c

@@ -208,10 +208,9 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
         return;
     }
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToReadSize,
-                                        &UA_TYPES[UA_TYPES_DATAVALUE]);
-    if(retval != UA_STATUSCODE_GOOD) {
-        response->responseHeader.serviceResult = retval;
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_DATAVALUE], request->nodesToReadSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 
@@ -422,10 +421,9 @@ void Service_Write(UA_Server *server, UA_Session *session,
                    const UA_WriteRequest *request, UA_WriteResponse *response) {
     UA_assert(server != UA_NULL && session != UA_NULL && request != UA_NULL && response != UA_NULL);
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToWriteSize,
-                                        &UA_TYPES[UA_TYPES_STATUSCODE]);
-    if(retval) {
-        response->responseHeader.serviceResult = retval;
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_STATUSCODE], request->nodesToWriteSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 

+ 3 - 4
src/server/ua_services_nodemanagement.c

@@ -240,10 +240,9 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
         return;
     }
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToAddSize,
-                                        &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
-    if(retval) {
-        response->responseHeader.serviceResult = retval;
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_ADDNODESRESULT], request->nodesToAddSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 

+ 10 - 14
src/server/ua_services_view.c

@@ -132,7 +132,7 @@ static UA_StatusCode findRelevantReferenceTypes(UA_NodeStore *ns, const UA_NodeI
     } while(++currentIndex <= currentLastIndex && retval == UA_STATUSCODE_GOOD);
 
     if(retval)
-        UA_Array_delete(typeArray, currentLastIndex, &UA_TYPES[UA_TYPES_NODEID]);
+        UA_Array_delete(typeArray, &UA_TYPES[UA_TYPES_NODEID], currentLastIndex);
     else {
         *referenceTypes = typeArray;
         *referenceTypesSize = currentLastIndex + 1;
@@ -167,7 +167,7 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
     if(!parentNode) {
         browseResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
         if(!returnAll)
-            UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesSize, &UA_TYPES[UA_TYPES_NODEID]);
+            UA_Array_delete(relevantReferenceTypes, &UA_TYPES[UA_TYPES_NODEID], relevantReferenceTypesSize);
         return;
     }
 
@@ -202,8 +202,7 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
             if(fillReferenceDescription(ns, currentNode, &parentNode->references[i],
                                         browseDescription->resultMask,
                                         &browseResult->references[currentRefs]) != UA_STATUSCODE_GOOD) {
-                UA_Array_delete(browseResult->references, currentRefs,
-                                &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]);
+                UA_Array_delete(browseResult->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], currentRefs);
                 currentRefs = 0;
                 browseResult->references = UA_NULL;
                 browseResult->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
@@ -221,7 +220,7 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
 
     UA_NodeStore_release(parentNode);
     if(!returnAll)
-        UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesSize, &UA_TYPES[UA_TYPES_NODEID]);
+        UA_Array_delete(relevantReferenceTypes, &UA_TYPES[UA_TYPES_NODEID], relevantReferenceTypesSize);
 }
 
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
@@ -231,14 +230,12 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
         return;
     }
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToBrowseSize,
-                                        &UA_TYPES[UA_TYPES_BROWSERESULT]);
-    if(retval) {
-        response->responseHeader.serviceResult = retval;
+   response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], request->nodesToBrowseSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 
-
     /* ### Begin External Namespaces */
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToBrowseSize);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * request->nodesToBrowseSize);
@@ -279,10 +276,9 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
         return;
     }
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->browsePathsSize,
-                                        &UA_TYPES[UA_TYPES_BROWSEPATHRESULT]);
-    if(retval) {
-        response->responseHeader.serviceResult = retval;
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSEPATHRESULT], request->browsePathsSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 

+ 49 - 35
src/ua_types.c

@@ -288,11 +288,6 @@ UA_StatusCode UA_Guid_copy(UA_Guid const *src, UA_Guid *dst) {
 }
 
 /* ByteString */
-UA_Boolean UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2) {
-    return UA_String_equal((const UA_String *)string1, (const UA_String *)string2);
-}
-
-/** Creates a ByteString of the indicated length. The content is not set to zero. */
 UA_StatusCode UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length) {
     if(length > 0) {
         if(!(p->data = UA_malloc((UA_UInt32)length)))
@@ -339,8 +334,10 @@ UA_StatusCode UA_NodeId_copy(UA_NodeId const *src, UA_NodeId *dst) {
     }
     dst->namespaceIndex = src->namespaceIndex;
     dst->identifierType = src->identifierType;
-    if(retval)
+    if(retval) {
         UA_NodeId_deleteMembers(dst);
+        UA_NodeId_init(dst);
+    }
     return retval;
 }
 
@@ -439,8 +436,10 @@ UA_StatusCode UA_ExpandedNodeId_copy(UA_ExpandedNodeId const *src, UA_ExpandedNo
     UA_StatusCode retval = UA_NodeId_copy(&src->nodeId, &dst->nodeId);
     retval |= UA_String_copy(&src->namespaceUri, &dst->namespaceUri);
     dst->serverIndex = src->serverIndex;
-    if(retval)
+    if(retval) {
         UA_ExpandedNodeId_deleteMembers(dst);
+        UA_ExpandedNodeId_init(dst);
+    }
     return retval;
 }
 
@@ -465,8 +464,10 @@ UA_TYPE_NEW_DEFAULT(UA_QualifiedName)
 UA_StatusCode UA_QualifiedName_copy(UA_QualifiedName const *src, UA_QualifiedName *dst) {
     UA_StatusCode retval = UA_String_copy(&src->name, &dst->name);
     dst->namespaceIndex = src->namespaceIndex;
-    if(retval)
+    if(retval) {
         UA_QualifiedName_deleteMembers(dst);
+        UA_QualifiedName_init(dst);
+    }
     return retval;
 
 }
@@ -502,8 +503,10 @@ UA_StatusCode UA_LocalizedText_copycstring(char const *src, UA_LocalizedText *ds
 UA_StatusCode UA_LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedText *dst) {
     UA_StatusCode retval = UA_String_copy(&src->locale, &dst->locale);
     retval |= UA_String_copy(&src->text, &dst->text);
-    if(retval)
+    if(retval) {
         UA_LocalizedText_deleteMembers(dst);
+        UA_LocalizedText_init(dst);
+    }
     return retval;
 }
 
@@ -525,8 +528,10 @@ UA_StatusCode UA_ExtensionObject_copy(UA_ExtensionObject const *src, UA_Extensio
     UA_StatusCode retval = UA_ByteString_copy(&src->body, &dst->body);
     retval |= UA_NodeId_copy(&src->typeId, &dst->typeId);
     dst->encoding = src->encoding;
-    if(retval)
+    if(retval) {
         UA_ExtensionObject_deleteMembers(dst);
+        UA_ExtensionObject_init(dst);
+    }
     return retval;
 }
 
@@ -556,8 +561,10 @@ UA_StatusCode UA_DataValue_copy(UA_DataValue const *src, UA_DataValue *dst) {
     dst->serverPicoseconds = src->serverPicoseconds;
     dst->sourcePicoseconds = src->sourcePicoseconds;
     dst->status = src->status;
-    if(retval)
+    if(retval) {
         UA_DataValue_deleteMembers(dst);
+        UA_DataValue_init(dst);
+    }
     return retval;
 }
 
@@ -578,7 +585,7 @@ void UA_Variant_deleteMembers(UA_Variant *p) {
     UA_NodeId_deleteMembers(&p->typeId);
     if(p->storageType == UA_VARIANT_DATA) {
         if(p->storage.data.dataPtr) {
-            UA_Array_delete(p->storage.data.dataPtr, p->storage.data.arrayLength, p->type);
+            UA_Array_delete(p->storage.data.dataPtr, p->type, p->storage.data.arrayLength);
             p->storage.data.dataPtr = UA_NULL;
             p->storage.data.arrayLength = 0;
         }
@@ -604,18 +611,21 @@ UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
     UA_VariantData *dstdata = &dst->storage.data;
     const UA_VariantData *srcdata = &src->storage.data;
     dst->storageType = UA_VARIANT_DATA;
-    retval |= UA_Array_copy(srcdata->dataPtr, srcdata->arrayLength, &dstdata->dataPtr, src->type);
+    retval |= UA_Array_copy(srcdata->dataPtr, &dstdata->dataPtr, src->type, srcdata->arrayLength);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Variant_deleteMembers(dst);
+        UA_Variant_init(dst);
         return retval;
     }
     dstdata->arrayLength = srcdata->arrayLength;
 
     if(srcdata->arrayDimensions) {
-        retval |= UA_Array_copy(srcdata->arrayDimensions, srcdata->arrayDimensionsSize,
-                                (void **)&dstdata->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
-        if(retval != UA_STATUSCODE_GOOD)
+        retval |= UA_Array_copy(srcdata->arrayDimensions, (void **)&dstdata->arrayDimensions, &UA_TYPES[UA_TYPES_INT32],
+                                srcdata->arrayDimensionsSize);
+        if(retval != UA_STATUSCODE_GOOD) {
             UA_Variant_deleteMembers(dst);
+            UA_Variant_init(dst);
+        }
     }
     dstdata->arrayDimensionsSize = srcdata->arrayDimensionsSize;
 
@@ -656,7 +666,7 @@ UA_StatusCode UA_Variant_copySetArray(UA_Variant *v, const void *array, UA_Int32
     if(typeIndex >= UA_TYPES_COUNT)
         return UA_STATUSCODE_BADINTERNALERROR;
     void *new;
-    UA_StatusCode retval = UA_Array_copy(array, noElements, &new, &UA_TYPES[typeIndex]);
+    UA_StatusCode retval = UA_Array_copy(array, &new, &UA_TYPES[typeIndex], noElements);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     return UA_Variant_setArray(v, new, noElements, typeIndex);
@@ -699,8 +709,10 @@ UA_StatusCode UA_DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_Diagnostic
     dst->localizedText = src->localizedText;
     dst->namespaceUri = src->namespaceUri;
     dst->symbolicId = src->symbolicId;
-    if(retval)
+    if(retval) {
         UA_DiagnosticInfo_deleteMembers(dst);
+        UA_DiagnosticInfo_init(dst);
+    }
     return retval;
 }
 
@@ -832,9 +844,10 @@ UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *dataType) {
             const UA_Int32 noElements = *((const UA_Int32*)ptrs);
             ptrs += sizeof(UA_Int32) + (member->padding & 0x07);
             ptrd += sizeof(UA_Int32) + (member->padding & 0x07);
-            retval = UA_Array_copy(*(void* const*)ptrs, noElements, (void**)ptrd, memberType);
+            retval = UA_Array_copy(*(void* const*)ptrs, (void**)ptrd, memberType, noElements);
             if(retval != UA_STATUSCODE_GOOD) {
                 UA_deleteMembers(dst, dataType);
+                UA_init(dst, dataType);
                 return retval;
             }
             *dstNoElements = noElements;
@@ -849,6 +862,7 @@ UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *dataType) {
             retval = UA_copy((const void*)ptrs, (void*)ptrd, memberType);
             if(retval != UA_STATUSCODE_GOOD) {
                 UA_deleteMembers(dst, dataType);
+                UA_init(dst, dataType);
                 return retval;
             }
             ptrs += memberType->memSize;
@@ -916,8 +930,10 @@ UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *dataType) {
         ptrs += memberType->memSize;
         ptrd += memberType->memSize;
     }
-    if(retval != UA_STATUSCODE_GOOD)
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_deleteMembers(dst, dataType);
+        UA_init(dst, dataType);
+    }
     return retval;
 }
 
@@ -938,7 +954,7 @@ void UA_deleteMembers(void *p, const UA_DataType *dataType) {
             ptr += (member->padding >> 3);
             UA_Int32 noElements = *((UA_Int32*)ptr);
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
-            UA_Array_delete(*(void**)ptr, noElements, memberType);
+            UA_Array_delete(*(void**)ptr, memberType, noElements);
             ptr += sizeof(void*);
             continue;
         }
@@ -999,28 +1015,26 @@ void UA_delete(void *p, const UA_DataType *dataType) {
 /* Array Handling */
 /******************/
 
-UA_StatusCode UA_Array_new(void **p, UA_Int32 noElements, const UA_DataType *dataType) {
-    if(noElements <= 0) {
-        *p = UA_NULL;
-        return UA_STATUSCODE_BADINTERNALERROR;
-    }
+void* UA_Array_new(const UA_DataType *dataType, UA_Int32 noElements) {
+    if(noElements <= 0)
+        return UA_NULL;
 
     if((UA_Int32)dataType->memSize * noElements < 0 || dataType->memSize * noElements > MAX_ARRAY_SIZE )
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+        return UA_NULL;
 
-    *p = malloc(dataType->memSize * (size_t)noElements);
-    if(!p)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+    void *p = malloc(dataType->memSize * (size_t)noElements);
+    if(!p || dataType->fixedSize) // datatypes of fixed size are not initialized.
+        return p;
 
-    uintptr_t ptr = (uintptr_t)*p;
+    uintptr_t ptr = (uintptr_t)p;
     for(int i = 0; i<noElements; i++) {
         UA_init((void*)ptr, dataType);
         ptr += dataType->memSize;
     }
-    return UA_STATUSCODE_GOOD;
+    return p;
 }
 
-UA_StatusCode UA_Array_copy(const void *src, UA_Int32 noElements, void **dst, const UA_DataType *dataType) {
+UA_StatusCode UA_Array_copy(const void *src, void **dst, const UA_DataType *dataType, UA_Int32 noElements) {
     if(noElements <= 0) {
         *dst = UA_NULL;
         return UA_STATUSCODE_GOOD;
@@ -1044,12 +1058,12 @@ UA_StatusCode UA_Array_copy(const void *src, UA_Int32 noElements, void **dst, co
     }
 
     if(retval != UA_STATUSCODE_GOOD)
-        UA_Array_delete(*dst, noElements, dataType);
+        UA_Array_delete(*dst, dataType, noElements);
         
     return retval;
 }
 
-void UA_Array_delete(void *p, UA_Int32 noElements, const UA_DataType *dataType) {
+void UA_Array_delete(void *p, const UA_DataType *dataType, UA_Int32 noElements) {
     if(noElements <= 0 || !p)
         return;
 

+ 1 - 1
src/ua_types_encoding_binary.c

@@ -1255,6 +1255,6 @@ UA_StatusCode UA_Array_decodeBinary(const UA_ByteString *src, size_t *offset, UA
         ptr += dataType->memSize;
     }
     if(retval != UA_STATUSCODE_GOOD)
-        UA_Array_delete(*dst, i, dataType);
+        UA_Array_delete(*dst, dataType, i);
     return retval;
 }

+ 8 - 12
tests/check_builtin.c

@@ -1254,7 +1254,7 @@ START_TEST(UA_Array_copyByteArrayShallWorkOnExample) {
 	testString.length  = 5;
 
 	//when
-	UA_Array_copy((const void *)testString.data, 5, (void **)&dstArray, &UA_TYPES[UA_TYPES_BYTE]);
+	UA_Array_copy((const void *)testString.data, (void **)&dstArray, &UA_TYPES[UA_TYPES_BYTE], 5);
 	//then
 	for(i = 0;i < size;i++)
 		ck_assert_int_eq(testString.data[i], dstArray[i]);
@@ -1269,15 +1269,14 @@ END_TEST
 START_TEST(UA_Array_copyUA_StringShallWorkOnExample) {
 	// given
 	UA_Int32   i, j;
-	UA_String *srcArray;
-	UA_Array_new((void**)&srcArray, 3, &UA_TYPES[UA_TYPES_STRING]);
+	UA_String *srcArray = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 3);
 	UA_String *dstArray;
 
 	UA_String_copycstring("open", &srcArray[0]);
 	UA_String_copycstring("62541", &srcArray[1]);
 	UA_String_copycstring("opc ua", &srcArray[2]);
 	//when
-	UA_Array_copy((const void *)srcArray, 3, (void **)&dstArray, &UA_TYPES[UA_TYPES_STRING]);
+	UA_Array_copy((const void *)srcArray, (void **)&dstArray, &UA_TYPES[UA_TYPES_STRING], 3);
 	//then
 	for(i = 0;i < 3;i++) {
 		for(j = 0;j < 3;j++)
@@ -1285,8 +1284,8 @@ START_TEST(UA_Array_copyUA_StringShallWorkOnExample) {
 		ck_assert_int_eq(srcArray[i].length, dstArray[i].length);
 	}
 	//finally
-	UA_Array_delete(srcArray, 3, &UA_TYPES[UA_TYPES_STRING]);
-	UA_Array_delete(dstArray, 3, &UA_TYPES[UA_TYPES_STRING]);
+	UA_Array_delete(srcArray, &UA_TYPES[UA_TYPES_STRING], 3);
+	UA_Array_delete(dstArray, &UA_TYPES[UA_TYPES_STRING], 3);
 }
 END_TEST
 
@@ -1492,8 +1491,7 @@ END_TEST
 
 START_TEST(UA_Variant_copyShallWorkOn1DArrayExample) {
 	// given
-	UA_String *srcArray;
-	UA_Array_new((void**)&srcArray, 3, &UA_TYPES[UA_TYPES_STRING]);
+	UA_String *srcArray = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 3);
 	UA_String_copycstring("__open", &srcArray[0]);
 	UA_String_copycstring("_62541", &srcArray[1]);
 	UA_String_copycstring("opc ua", &srcArray[2]);
@@ -1541,8 +1539,7 @@ END_TEST
 
 START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 	// given
-	UA_Int32 *srcArray;
-	UA_Array_new((void**)&srcArray, 6, &UA_TYPES[UA_TYPES_INT32]);
+	UA_Int32 *srcArray = UA_Array_new(&UA_TYPES[UA_TYPES_INT32], 6);
 	srcArray[0] = 0;
 	srcArray[1] = 1;
 	srcArray[2] = 2;
@@ -1550,8 +1547,7 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 	srcArray[4] = 4;
 	srcArray[5] = 5;
 
-	UA_Int32 *dimensions;
-	UA_Array_new((void**)&dimensions, 2, &UA_TYPES[UA_TYPES_INT32]);
+	UA_Int32 *dimensions = UA_Array_new(&UA_TYPES[UA_TYPES_INT32], 2);
 	UA_Int32 dim1 = 3;
 	UA_Int32 dim2 = 2;
 	dimensions[0] = dim1;

+ 2 - 2
tests/check_memory.c

@@ -26,7 +26,7 @@ START_TEST(arrayCopyShallMakeADeepCopy) {
 	a1[2] = (UA_String){3, (UA_Byte*)"ccc"};
 	// when
 	UA_String *a2;
-	UA_Int32   retval = UA_Array_copy((const void *)a1, 3, (void **)&a2, &UA_TYPES[UA_TYPES_STRING]);
+	UA_Int32   retval = UA_Array_copy((const void *)a1, (void **)&a2, &UA_TYPES[UA_TYPES_STRING], 3);
 	// then
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(a1[0].length, 1);
@@ -42,7 +42,7 @@ START_TEST(arrayCopyShallMakeADeepCopy) {
 	ck_assert_int_eq(a1[1].data[0], a2[1].data[0]);
 	ck_assert_int_eq(a1[2].data[0], a2[2].data[0]);
 	// finally
-	UA_Array_delete((void *)a2, 3, &UA_TYPES[UA_TYPES_STRING]);
+	UA_Array_delete((void *)a2, &UA_TYPES[UA_TYPES_STRING], 3);
 }
 END_TEST