Переглянути джерело

Merge branch 'master' of github.com:acplt/open62541 into module_ns

Conflicts:
	examples/src/generateSam.c
	include/ua_basictypes.h
	src/Makefile.am
	src/ua_list.h
	src/ua_xml.c
	src/ua_xml.h
	tools/generate_builtin.py
Julius Pfrommer 10 роки тому
батько
коміт
9020dcf596
13 змінених файлів з 1335 додано та 415 видалено
  1. 12 0
      README.md
  2. 116 44
      examples/src/generateSam.c
  3. 10 9
      src/Makefile.am
  4. 19 0
      src/ua_base64.h
  5. 1 2
      src/ua_list.h
  6. 3 2
      src/ua_namespace.c
  7. 673 354
      src/ua_xml.c
  8. 26 1
      src/ua_xml.h
  9. 154 0
      src/util/ua_base64.c
  10. 1 1
      tests/Makefile.am
  11. 118 0
      tests/check_base64.c
  12. 20 2
      tests/check_namespace.c
  13. 182 0
      tests/check_xml.c

+ 12 - 0
README.md

@@ -60,6 +60,18 @@ $ make all
 * Copy gtk+/share/aclocal/*.m4 files to MinGW/share/aclocal
 * Merge grk+ folder and MinGW\msys\1.0\ folder
 
+##### Get expat
+* start MinGW Installation Manager
+* choose all Packages, mark mingw32-expat and install
+
+##### Get Python and lxml:
+* download Python at https://python.org/downloads
+* install the executable
+* add the install directory (e. g. "c:\python27") to your windows path variable 
+* restart mingw console
+* install lxml by either downloading and installing http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml (choose the version which fits    to your python installation) or by following the instructions
+  given here: http://lxml.de/installation.html
+
 ##### Get git (IMPORTANT: get 1.8.4, since 1.8.5.2 has a bug):
 * http://code.google.com/p/msysgit/downloads/detail?name=Git-1.8.4-preview20130916.exe&can=2&q=
 

+ 116 - 44
examples/src/generateSam.c

@@ -7,47 +7,119 @@
 /** @brief we need a variable global to the module to make it possible for the visitors to access the namespace */
 static Namespace* theNamespace;
 
-/** @brief check if VariableNode is root by searching for parent and checking if this is not a VariableNode */
-_Bool UA_VariableNode_isRoot(const UA_VariableNode* node) {
-	UA_Int32 i;
-	for (i = 0; i < node->referencesSize; i++ ) {
-		UA_Int32 refId = node->references[i].referenceTypeId.identifier.numeric;
-		UA_Int32 isInverse = node->references[i].isInverse;
+UA_Int32 UA_Node_getParent(const UA_Node* node, const UA_Node** parent) {
+	UA_Int32 i = 0;
+	DBG(printf("// UA_Node_getParent - node={i=%d}",UA_NodeId_getIdentifier(&(node->nodeId))));
+	// FIXME: the data model is crap! we should have a single memory location which holds the parent NodeId
+	for (; i < node->referencesSize; i++ ) {
+		UA_Int32 refId = UA_NodeId_getIdentifier(&(node->references[i]->referenceTypeId));
+		UA_Int32 isInverse = node->references[i]->isInverse;
 		if (isInverse && (refId == 47 || refId == 46)) {
-			Namespace_Entry_Lock* lock;
-			const UA_Node* parent;
+			Namespace_Entry_Lock* lock = UA_NULL;
 			UA_Int32 retval;
-			retval = Namespace_get(theNamespace, &(node->references[i].targetId.nodeId),&parent,&lock);
-			if (retval != UA_SUCCESS || parent == UA_NULL || parent->nodeClass == UA_NODECLASS_VARIABLE) {
-				if (node->nodeId.identifier.numeric == 2007) {
-					printf("strange 2007 not included retval=%d,parentId=%d,parent=%p\n, ",retval,node->references[i].targetId.nodeId.identifier.numeric,(void*)parent);
-				}
-				Namespace_Entry_Lock_release(lock);
-				return UA_FALSE;
-			}
+			retval = Namespace_get(theNamespace, &(node->references[i].targetId.nodeId),parent,&lock);
 			Namespace_Entry_Lock_release(lock);
+			if (retval == UA_SUCCESS) {
+				DBG(printf(" has parent={i=%d}\n",UA_NodeId_getIdentifier(&((*parent)->nodeId))));
+			} else {
+				DBG(printf(" has non-existing parent={i=%d}\n",UA_NodeId_getIdentifier(&(node->references[i]->targetId.nodeId))));
+			}
+			return retval;
 		}
 	}
-	return UA_TRUE;
+	// there is no parent, we are root
+	DBG(printf(" is root\n"));
+	*parent = UA_NULL;
+	return UA_SUCCESS;
+}
+
+/** @brief recurse down to root and return root node */
+UA_Int32 UA_Node_getRoot(const UA_Node* node, const UA_Node** root) {
+	UA_Int32 retval = UA_SUCCESS;
+	const UA_Node* parent = UA_NULL;
+	if ( (retval = UA_Node_getParent(node,&parent)) == UA_SUCCESS ) {
+		if (parent != UA_NULL) {	// recurse down to root node
+			retval = UA_Node_getRoot(parent,root);
+		} else {					// node is root, terminate recursion
+			*root = node;
+		}
+	}
+	return retval;
 }
 
+/** @brief check if VariableNode needs a memory object. This is the
+ * case if the parent is of type object and the root is type object
+ **/
+_Bool UA_VariableNode_needsObject(const UA_VariableNode* node) {
+	const UA_Node* parent = UA_NULL;
+	if ( UA_Node_getParent((UA_Node*)node,&parent) == UA_SUCCESS ) {
+		if (parent == UA_NULL)
+			return UA_TRUE;
+		if (parent->nodeClass == UA_NODECLASS_OBJECT ) {
+			const UA_Node* root;
+			if (UA_Node_getRoot(parent,&root) == UA_SUCCESS)
+				if (root == UA_NULL || root->nodeClass == UA_NODECLASS_OBJECT )
+					return UA_TRUE;
+		}
+	}
+	return UA_FALSE;
+}
+
+/** @brief recurse down to root and get full qualified name */
+UA_Int32 UA_Node_getPath(const UA_Node* node, UA_list_List* list) {
+	UA_Int32 retval = UA_SUCCESS;
+	const UA_Node* parent = UA_NULL;
+	if ( (retval = UA_Node_getParent(node,&parent)) == UA_SUCCESS ) {
+		if (parent != UA_NULL) {
+			// recurse down to root node
+			UA_Int32 retval = UA_Node_getPath(parent,list);
+			// and add our own name when we come back
+			if (retval == UA_SUCCESS) {
+				UA_list_addPayloadToBack(list,(void*)&(node->browseName.name));
+				DBG(printf("// UA_Node_getPath - add id={i=%d},class=%d",UA_NodeId_getIdentifier(&(node->nodeId)),node->nodeClass));
+				DBG(UA_String_printf(",name=",&(node->browseName.name)));
+			}
+		} else {
+			// node is root, terminate recursion by adding own name
+			UA_list_addPayloadToBack(list,(void*)&node->browseName.name);
+			DBG(printf("// UA_Node_getPath - add id={i=%d},class=%d",UA_NodeId_getIdentifier(&(node->nodeId)),node->nodeClass));
+			DBG(UA_String_printf(",name=",&(node->browseName.name)));
+		}
+	}
+	return retval;
+}
+
+
 /** @brief some macros to lowercase the first character without copying around */
 #define F_cls "%c%.*s"
 #define LC_cls(str) tolower((str).data[0]), (str).length-1, &((str).data[1])
 
+void listPrintName(void * payload) {
+	UA_ByteString* name = (UA_ByteString*) payload;
+	if (name->length > 0) {
+		printf("_" F_cls, LC_cls(*name));
+	}
+}
 
-/** @brief declares all the top level objects in the server's application memory
- * FIXME: shall add only top level objects, i.e. those that have no parents
- */
+/** @brief declares all the top level objects in the server's application memory */
 void sam_declareAttribute(UA_Node const * node) {
-	if (node->nodeClass == UA_NODECLASS_VARIABLE && UA_VariableNode_isRoot((UA_VariableNode*)node)) {
-		UA_VariableNode* vn = (UA_VariableNode*) node;
-		printf("\t%s " F_cls "; // i=%d\n", UA_.types[UA_ns0ToVTableIndex(&vn->dataType)].name, LC_cls(node->browseName.name), node->nodeId.identifier.numeric);
+	if (node->nodeClass == UA_NODECLASS_VARIABLE && UA_VariableNode_needsObject((UA_VariableNode*)node)) {
+		UA_list_List list; UA_list_init(&list);
+		UA_Int32 retval = UA_Node_getPath(node,&list);
+		if (retval == UA_SUCCESS) {
+			UA_VariableNode* vn = (UA_VariableNode*) node;
+			printf("\t%s ", UA_.types[UA_ns0ToVTableIndex(vn->typeId)].name);
+			UA_list_iteratePayload(&list,listPrintName);
+			printf("; // i=%d\n", node->nodeId.identifier.numeric);
+		} else {
+			printf("// could not determine path for i=%d\n",node->nodeId.identifier.numeric);
+		}
+		UA_list_destroy(&list,UA_NULL);
 	}
 }
 
 /** @brief declares all the buffers for string variables
- * FIXME: traverse down to top level objects and create a unique name such as cstr_serverState_buildInfo_version
+ * FIXME: shall traverse down to the root object and create a unique name such as cstr_serverState_buildInfo_version
  */
 void sam_declareBuffer(UA_Node const * node) {
 	if (node != UA_NULL && node->nodeClass == UA_NODECLASS_VARIABLE) {
@@ -188,25 +260,25 @@ pattern p[] = {
 };
 
 int main(int argc, char** argv) {
-	/* if (argc != 2) { */
-	/* 	printf("usage: %s filename\n",argv[0]); */
-	/* } else { */
-	/* 	Namespace* ns; */
-	/* 	if (Namespace_loadFromFile(&ns,0,"ROOT",argv[1]) != UA_SUCCESS) { */
-	/* 		printf("error loading file {%s}\n", argv[1]); */
-	/* 	} else { */
-	/* 		theNamespace = ns; */
-	/* 		for (pattern* pi = &p[0]; pi->s != UA_NULL || pi->v != UA_NULL; ++pi) { */
-	/* 			if (pi->s) { */
-	/* 				printf("%s",pi->s); */
-	/* 			} */
-	/* 			if (pi->v) { */
-	/* 				Namespace_iterate(ns, pi->v); */
-	/* 			} */
-	/* 		} */
-	/* 		// FIXME: crashes with a seg fault */
-	/* 		// Namespace_delete(ns); */
-	/* 	} */
-	/* } */
+	if (argc != 2) {
+		printf("usage: %s filename\n",argv[0]);
+	} else {
+		Namespace* ns;
+		if (Namespace_loadFromFile(&ns,0,"ROOT",argv[1]) != UA_SUCCESS) {
+			printf("error loading file {%s}\n", argv[1]);
+		} else {
+			theNamespace = ns;
+			for (pattern* pi = &p[0]; pi->s != UA_NULL || pi->v != UA_NULL; ++pi) {
+				if (pi->s) {
+					printf("%s",pi->s);
+				}
+				if (pi->v) {
+					Namespace_iterate(ns, pi->v);
+				}
+			}
+			// FIXME: crashes with a seg fault
+			// Namespace_delete(ns);
+		}
+	}
 	return 0;
 }

+ 10 - 9
src/Makefile.am

@@ -12,6 +12,7 @@ libopen62541_la_SOURCES = ua_types.c \
 						  ua_namespace_0.c \
 						  util/ua_list.c \
 						  util/ua_indexedList.c \
+						  util/ua_base64.c \
 						  ua_transport.c \
 						  ua_transport_binary.c \
 						  ua_transport_binary_secure.c \
@@ -33,21 +34,21 @@ generate_namespace_0: $(SCHEMA_DIR)/NodeIds.csv $(TOOL_DIR)/generate_namespace.p
 
 .PHONY: convenience-link clean-convenience-link generate_types generate_namespace_0
 
-convenience-link: $(lib_LTLIBRARIES) 
-	@test -e $(top_builddir)/lib || mkdir $(top_builddir)/lib
+convenience-link: $(lib_LTLIBRARIES)
+	@test -e "$(top_builddir)/lib" || mkdir "$(top_builddir)/lib"
 	@for soname in `echo | $(EGREP) "^dlname=" $^ | $(SED) -e "s|^dlname='\(.*\)'|\1|"`; do  \
 		echo "$$soname: creating convenience link from $(abs_builddir)/.libs to $(top_builddir)/lib"; \
 		rm -f $(top_builddir)/lib/$$soname ; \
-		test -e $(abs_builddir)/.libs/$$soname && \
-		cd $(top_builddir)/lib && \
-		$(LN_S) $(abs_builddir)/.libs/$$soname $$soname || true;\
+		test -e "$(abs_builddir)/.libs/$$soname" && \
+		cd "$(top_builddir)/lib" && \
+		$(LN_S) "$(abs_builddir)/.libs/$$soname" "$$soname" || true;\
 	done
 	@for aname in `echo | $(EGREP) "^dlname=" $^ | $(SED) -e "s|^dlname='\(.*\)\.\(.*\)'|\1\.a|"`; do  \
 		echo "$$aname: creating convenience link from $(abs_builddir)/.libs to $(top_builddir)/lib"; \
-		rm -f $(top_builddir)/lib/$$aname ; \
-		test -e $(abs_builddir)/.libs/$$aname && \
-		cd $(top_builddir)/lib && \
-		$(LN_S) $(abs_builddir)/.libs/$$aname $$aname || true;\
+		rm -f "$(top_builddir)/lib/$$aname" ; \
+		test -e "$(abs_builddir)/.libs/$$aname" && \
+		cd "$(top_builddir)/lib" && \
+		$(LN_S) "$(abs_builddir)/.libs/$$aname" "$$aname" || true;\
 	done
 
 clean-convenience-link:

+ 19 - 0
src/ua_base64.h

@@ -0,0 +1,19 @@
+/*
+ * ua_base64.h
+ *
+ *  Created on: Jun 10, 2014
+ *      Author: sten
+ */
+
+#ifndef UA_BASE64_H_
+#define UA_BASE64_H_
+
+#include "ua_basictypes.h"
+
+/** @brief calculates the exact size for the binary data that is encoded in base64 encoded string */
+UA_Int32 UA_base64_getDecodedSize(UA_String* const base64EncodedData);
+
+/** @brief decodes base64 encoded string into target, target should be at least of the size returned by UA_base64_getDecodedSizeUB */
+UA_Int32 UA_base64_decode(UA_String* const base64EncodedData, UA_Byte* target);
+
+#endif /* UA_BASE64_H_ */

+ 1 - 2
src/ua_list.h

@@ -1,10 +1,9 @@
 #ifndef UA_LIST_H_
 #define UA_LIST_H_
 
+#include "ua_types.h"
 #include <stddef.h> /* Needed for sys/queue.h */
 #include <sys/queue.h>
-#include "ua_types.h"
-
 
 /**********************/
 /* Singly Linked List */

+ 3 - 2
src/ua_namespace.c

@@ -188,7 +188,8 @@ static inline hash_t mod(hash_t h, const Namespace * ns) {
 }
 
 static inline hash_t mod_m2(hash_t h, const Namespace * ns) {
-	const struct prime_ent *p = &prime_tab[ns->sizePrimeIndex];
+	const struct prime_ent *p = &prime_tab[ns->sizePrimeIndex];	// eventually return the namespace object that has been allocated in UA_NodeSet_init
+
 	return 1 + mod_1(h, p->prime - 2, p->inv_m2, p->shift);
 }
 
@@ -415,7 +416,7 @@ UA_Int32 Namespace_insertUnique(Namespace * ns, UA_Node * node) {
 
 UA_Int32 Namespace_contains(const Namespace * ns, const UA_NodeId * nodeid) {
 	Namespace_Entry *entry;
-	return find_entry(ns, nodeid, &entry);
+	return (find_entry(ns, nodeid, &entry) == UA_SUCCESS ? UA_TRUE : UA_FALSE);
 }
 
 UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, const UA_Node **result,

Різницю між файлами не показано, бо вона завелика
+ 673 - 354
src/ua_xml.c


+ 26 - 1
src/ua_xml.h

@@ -77,6 +77,32 @@ UA_Int32 UA_TypedArray_new(UA_TypedArray **p);
 UA_Int32 UA_TypedArray_setType(UA_TypedArray *p, UA_Int32 type);
 UA_Int32 UA_TypedArray_decodeXML(XML_Stack *s, XML_Attr *attr, UA_TypedArray *dst, UA_Boolean isStart);
 
+UA_Int32 UA_NodeSetAlias_init(UA_NodeSetAlias* p);
+UA_Int32 UA_NodeSetAlias_new(UA_NodeSetAlias** p);
+UA_Int32 UA_NodeSetAlias_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSetAlias* dst, _Bool isStart);
+
+UA_Int32 UA_NodeSetAliases_init(UA_NodeSetAliases* p);
+UA_Int32 UA_NodeSetAliases_new(UA_NodeSetAliases** p);
+UA_Int32 UA_NodeSetAliases_println(cstring label, UA_NodeSetAliases *p);
+UA_Int32 UA_NodeSetAliases_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSetAliases* dst, _Bool isStart);
+
+typedef struct UA_NodeSet {
+	Namespace* ns;
+	UA_NodeSetAliases aliases;
+} UA_NodeSet;
+
+/** @brief init typed array with size=-1 and an UA_INVALIDTYPE */
+UA_Int32 UA_NodeSet_init(UA_NodeSet* p, UA_UInt32 nsid);
+UA_Int32 UA_NodeSet_new(UA_NodeSet** p, UA_UInt32 nsid);
+UA_Int32 UA_NodeId_copycstring(cstring src, UA_NodeId* dst, UA_NodeSetAliases* aliases);
+UA_Int32 UA_NodeSet_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSet* dst, _Bool isStart);
+
+UA_Int32 UA_ExpandedNodeId_copycstring(cstring src, UA_ExpandedNodeId* dst, UA_NodeSetAliases* aliases);
+
+void XML_Stack_init(XML_Stack* p, UA_UInt32 nsid, cstring name);
+void XML_Stack_print(XML_Stack* s);
+>>>>>>> 1c491aac41da6e3cbd906b5bb0b0905a0e66431c
+
 /** @brief add a reference to a handler (@see XML_Stack_addChildHandler) for text data
  *
  * Assume a XML structure such as
@@ -118,7 +144,6 @@ UA_Int32 XML_isSpace(cstring s, int len);
 void XML_Stack_handleText(void *data, const char *txt, int len);
 void XML_Stack_endElement(void *data, const char *el);
 
-
 UA_Int32 UA_Text_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_Byte **dst, _Bool isStart);
 UA_Int32 UA_NodeId_copycstring(cstring src, UA_NodeId *dst, UA_NodeSetAliases *aliases);
 UA_Int32 UA_TypedArray_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_TypedArray *dst, _Bool isStart);

+ 154 - 0
src/util/ua_base64.c

@@ -0,0 +1,154 @@
+/*
+begin library headers
+*/
+
+/*
+cdecode.h - c header for a base64 decoding algorithm
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+#ifndef BASE64_CDECODE_H
+#define BASE64_CDECODE_H
+
+typedef enum
+{
+	step_a, step_b, step_c, step_d
+} base64_decodestep;
+
+typedef struct
+{
+	base64_decodestep step;
+	char plainchar;
+} base64_decodestate;
+
+void base64_init_decodestate(base64_decodestate* state_in);
+
+int base64_decode_value(char value_in);
+
+int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in);
+
+#endif /* BASE64_CDECODE_H */
+
+/*
+end library headers
+*/
+
+#include "ua_base64.h"
+
+UA_Int32 UA_base64_getDecodedSize(UA_String* const base64EncodedData){
+	//note that base64-encoded data length is always divisible by 4
+	UA_Int32 temp = base64EncodedData->length * 3 / 4;
+
+	//subtract padding
+	if(base64EncodedData->data[base64EncodedData->length-1] == '=') {
+		temp--;
+		if(base64EncodedData->data[base64EncodedData->length-2] == '=') {
+			temp--;
+		}
+	}
+
+	return temp;
+}
+
+UA_Int32 UA_base64_decode(UA_String* const base64EncodedData, UA_Byte* target){
+	if(target == UA_NULL){
+		return UA_ERROR;
+	}
+	base64_decodestate state;
+	base64_init_decodestate(&state);
+	//FIXME: The (void*)(char*) was was perfomed to get rid of "differ in signedness" warnings. Can be a potential problem since the library code expects 'char' but we have 'unsigned char' in UA_String
+	base64_decode_block((void*)(char*)(base64EncodedData->data), base64EncodedData->length, (void*)(char*)target, &state);
+	return UA_NO_ERROR;
+}
+
+/*
+begin library code
+*/
+
+/*
+cdecoder.c - c source to a base64 decoding algorithm implementation
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+int base64_decode_value(char value_in)
+{
+	static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
+	static const char decoding_size = sizeof(decoding);
+	value_in -= 43;
+	if (value_in < 0 || value_in > decoding_size) return -1;
+	return decoding[(int)value_in];
+}
+
+void base64_init_decodestate(base64_decodestate* state_in)
+{
+	state_in->step = step_a;
+	state_in->plainchar = 0;
+}
+
+int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in)
+{
+	const char* codechar = code_in;
+	char* plainchar = plaintext_out;
+	char fragment;
+	
+	*plainchar = state_in->plainchar;
+	
+	switch (state_in->step)
+	{
+		while (1)
+		{
+	case step_a:
+			do {
+				if (codechar == code_in+length_in)
+				{
+					state_in->step = step_a;
+					state_in->plainchar = *plainchar;
+					return plainchar - plaintext_out;
+				}
+				fragment = (char)base64_decode_value(*codechar++);
+			} while (fragment < 0);
+			*plainchar    = (fragment & 0x03f) << 2;
+	case step_b:
+			do {
+				if (codechar == code_in+length_in)
+				{
+					state_in->step = step_b;
+					state_in->plainchar = *plainchar;
+					return plainchar - plaintext_out;
+				}
+				fragment = (char)base64_decode_value(*codechar++);
+			} while (fragment < 0);
+			*plainchar++ |= (fragment & 0x030) >> 4;
+			*plainchar    = (fragment & 0x00f) << 4;
+	case step_c:
+			do {
+				if (codechar == code_in+length_in)
+				{
+					state_in->step = step_c;
+					state_in->plainchar = *plainchar;
+					return plainchar - plaintext_out;
+				}
+				fragment = (char)base64_decode_value(*codechar++);
+			} while (fragment < 0);
+			*plainchar++ |= (fragment & 0x03c) >> 2;
+			*plainchar    = (fragment & 0x003) << 6;
+	case step_d:
+			do {
+				if (codechar == code_in+length_in)
+				{
+					state_in->step = step_d;
+					state_in->plainchar = *plainchar;
+					return plainchar - plaintext_out;
+				}
+				fragment = (char)base64_decode_value(*codechar++);
+			} while (fragment < 0);
+			*plainchar++   |= (fragment & 0x03f);
+		}
+	}
+	/* control should not reach here */
+	return plainchar - plaintext_out;
+}
+

+ 1 - 1
tests/Makefile.am

@@ -3,7 +3,7 @@ TESTS=
 UNIT_TESTS=
 check_PROGRAMS=
 
-UNIT_TESTS += check_stack check_list check_indexedList check_builtin check_namespace check_memory check_services_view
+UNIT_TESTS += check_stack check_list check_indexedList check_builtin check_namespace check_memory check_services_view check_xml check_base64
 TESTS += $(UNIT_TESTS)
 check_PROGRAMS += $(UNIT_TESTS)
 

+ 118 - 0
tests/check_base64.c

@@ -0,0 +1,118 @@
+#include <stdlib.h> // EXIT_SUCCESS
+#include "ua_base64.h"
+
+#include "check.h"
+
+
+START_TEST(base64_test_2padding)
+{
+
+	//this is base64'd ASCII string "open62541!"
+	UA_String encodedString = {16, (UA_Byte*)"b3BlbjYyNTQxIQ=="};
+
+	//assure that we allocate exactly 10 bytes
+	ck_assert_int_eq(UA_base64_getDecodedSize(&encodedString), 10);
+
+	UA_Byte* decodedData = (UA_Byte*)malloc(UA_base64_getDecodedSize(&encodedString));
+
+	UA_base64_decode(&encodedString, decodedData);
+
+	//check the string
+	ck_assert_int_eq(decodedData[0], 'o');
+	ck_assert_int_eq(decodedData[1], 'p');
+	ck_assert_int_eq(decodedData[2], 'e');
+	ck_assert_int_eq(decodedData[3], 'n');
+	ck_assert_int_eq(decodedData[4], '6');
+	ck_assert_int_eq(decodedData[5], '2');
+	ck_assert_int_eq(decodedData[6], '5');
+	ck_assert_int_eq(decodedData[7], '4');
+	ck_assert_int_eq(decodedData[8], '1');
+	ck_assert_int_eq(decodedData[9], '!');
+
+	free(decodedData);
+}
+END_TEST
+
+START_TEST(base64_test_1padding)
+{
+
+	//this is base64'd ASCII string "open62541!!"
+	UA_String encodedString = {16, (UA_Byte*)"b3BlbjYyNTQxISE="};
+
+	//assure that we allocate exactly 11 bytes
+	ck_assert_int_eq(UA_base64_getDecodedSize(&encodedString), 11);
+
+	UA_Byte* decodedData = (UA_Byte*)malloc(UA_base64_getDecodedSize(&encodedString));
+
+	UA_base64_decode(&encodedString, decodedData);
+
+	//check the string
+	ck_assert_int_eq(decodedData[0], 'o');
+	ck_assert_int_eq(decodedData[1], 'p');
+	ck_assert_int_eq(decodedData[2], 'e');
+	ck_assert_int_eq(decodedData[3], 'n');
+	ck_assert_int_eq(decodedData[4], '6');
+	ck_assert_int_eq(decodedData[5], '2');
+	ck_assert_int_eq(decodedData[6], '5');
+	ck_assert_int_eq(decodedData[7], '4');
+	ck_assert_int_eq(decodedData[8], '1');
+	ck_assert_int_eq(decodedData[9], '!');
+	ck_assert_int_eq(decodedData[10], '!');
+
+	free(decodedData);
+}
+END_TEST
+
+START_TEST(base64_test_0padding)
+{
+
+	//this is base64'd ASCII string "open62541"
+	UA_String encodedString = {12, (UA_Byte*)"b3BlbjYyNTQx"};
+
+	//assure that we allocate exactly 9 bytes
+	ck_assert_int_eq(UA_base64_getDecodedSize(&encodedString), 9);
+
+	UA_Byte* decodedData = (UA_Byte*)malloc(UA_base64_getDecodedSize(&encodedString));
+
+	UA_base64_decode(&encodedString, decodedData);
+
+	//check the string
+	ck_assert_int_eq(decodedData[0], 'o');
+	ck_assert_int_eq(decodedData[1], 'p');
+	ck_assert_int_eq(decodedData[2], 'e');
+	ck_assert_int_eq(decodedData[3], 'n');
+	ck_assert_int_eq(decodedData[4], '6');
+	ck_assert_int_eq(decodedData[5], '2');
+	ck_assert_int_eq(decodedData[6], '5');
+	ck_assert_int_eq(decodedData[7], '4');
+	ck_assert_int_eq(decodedData[8], '1');
+
+	free(decodedData);
+}
+END_TEST
+
+Suite*base64_testSuite(void)
+{
+	Suite *s = suite_create("base64_test");
+	TCase *tc_core = tcase_create("Core");
+	tcase_add_test(tc_core, base64_test_2padding);
+	tcase_add_test(tc_core, base64_test_1padding);
+	tcase_add_test(tc_core, base64_test_0padding);
+	suite_add_tcase(s,tc_core);
+	return s;
+}
+
+int main (void)
+{
+	int number_failed = 0;
+
+	Suite* s = base64_testSuite();
+	SRunner* sr = srunner_create(s);
+	srunner_run_all(sr,CK_NORMAL);
+	number_failed += srunner_ntests_failed(sr);
+	srunner_free(sr);
+
+	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+
+}
+

+ 20 - 2
tests/check_namespace.c

@@ -27,6 +27,21 @@ UA_Int32 createNode(UA_Node** p, UA_Int16 nsid, UA_Int32 id) {
 	return UA_SUCCESS;
 }
 
+START_TEST(confirmExistenceInNamespaceWithSingleEntry) {
+	// given
+	Namespace *ns;
+	Namespace_new(&ns, 512, 0);
+	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
+	UA_Int32 retval;
+	// when
+	retval = Namespace_contains(ns,&(n1->nodeId));
+	// then
+	ck_assert_int_eq(retval, UA_TRUE);
+	// finally
+	Namespace_delete(ns);
+}
+END_TEST
+
 START_TEST(findNodeInNamespaceWithSingleEntry) {
 	// given
 	Namespace *ns;
@@ -140,7 +155,8 @@ START_TEST(findNodeInExpandedNamespace) {
 	Namespace *ns;
 	Namespace_new(&ns, 10, 0);
 	UA_Node* n;
-	for (UA_Int32 i=0; i<200; i++) {
+	UA_Int32 i=0;
+	for (; i<200; i++) {
 		createNode(&n,0,i); Namespace_insert(ns,n);
 	}
 	const UA_Node* nr = UA_NULL;
@@ -163,7 +179,8 @@ START_TEST(iterateOverExpandedNamespaceShallNotVisitEmptyNodes) {
 	Namespace *ns;
 	Namespace_new(&ns, 10, 0);
 	UA_Node* n;
-	for (UA_Int32 i=0; i<200; i++) {
+	UA_Int32 i=0;
+	for (; i<200; i++) {
 		createNode(&n,0,i); Namespace_insert(ns,n);
 	}
 	// when
@@ -212,6 +229,7 @@ Suite * namespace_suite (void) {
 	suite_add_tcase (s, tc_cd);
 
 	TCase* tc_find = tcase_create ("Find");
+	tcase_add_test (tc_find, confirmExistenceInNamespaceWithSingleEntry);
 	tcase_add_test (tc_find, findNodeInNamespaceWithSingleEntry);
 	tcase_add_test (tc_find, findNodeInNamespaceWithTwoEntries);
 	tcase_add_test (tc_find, findNodeInNamespaceWithSeveralEntries);

+ 182 - 0
tests/check_xml.c

@@ -0,0 +1,182 @@
+/****************************************************************************
+ Name        : check_xml.c
+ Author      : uleon @ open62541
+ Version     : 0.1
+ Copyright   : Your copyright notice
+ Description : test cases to check different aspects of the
+ xml-processing
+
+
+*****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ua_xml.h"
+
+#include "check.h"
+
+START_TEST(parseNumericNodeIdWithoutNsIdShallYieldNs0NodeId)
+{
+	// given
+	char txt[] = "i=2";
+	UA_NodeId nodeId = { (UA_Byte) 0, (UA_UInt16) 0, { 0 } };
+
+	// when
+	UA_Int32 retval = UA_NodeId_copycstring(txt,&nodeId,UA_NULL);
+
+	// then
+	ck_assert_int_eq(retval,UA_SUCCESS);
+	ck_assert_int_eq(nodeId.encodingByte,UA_NODEIDTYPE_FOURBYTE);
+	ck_assert_int_eq(nodeId.namespace,0);
+	ck_assert_int_eq(nodeId.identifier.numeric,2);
+
+	// finally
+}
+END_TEST
+
+START_TEST(parseNumericNodeIdWithNsShallYieldNodeIdWithNs)
+{
+	// given
+	char txt[] = "ns=1;i=2";
+	UA_NodeId nodeId = { (UA_Byte) 0, (UA_UInt16) 0, { 0 } };
+
+	// when
+	UA_Int32 retval = UA_NodeId_copycstring(txt,&nodeId,UA_NULL);
+
+	// then
+	ck_assert_int_eq(retval,UA_SUCCESS);
+	ck_assert_int_eq(nodeId.encodingByte,UA_NODEIDTYPE_FOURBYTE);
+	ck_assert_int_eq(nodeId.namespace,1);
+	ck_assert_int_eq(nodeId.identifier.numeric,2);
+
+	// finally
+}
+END_TEST
+
+START_TEST(loadUserNamespaceWithSingleProcessVariableShallSucceed)
+{
+	// given
+	char xml[]=
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+"<UANodeSet>"
+	"<UAVariable NodeId=\"ns=1;i=2\" BrowseName=\"X1\" DataType=\"i=6\">"
+		"<DisplayName>Integer Variable</DisplayName>"
+		"<References>"
+			"<Reference ReferenceType=\"i=40\">i=63</Reference>"
+		"</References>"
+	"</UAVariable>"
+"</UANodeSet>";
+	Namespace *ns;
+	UA_NodeId nodeId;
+	UA_Int32 retval;
+
+	// when
+	retval = Namespace_loadFromString(&ns,1,"ROOT",xml);
+
+	// then
+	ck_assert_int_eq(retval,UA_SUCCESS);
+	ck_assert_ptr_ne(ns,UA_NULL);
+
+	UA_NodeId_copycstring("ns=1;i=2",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_TRUE);
+
+	const UA_Node* nr = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
+	retval = Namespace_get(ns,&nodeId,&nr,&nl);
+	ck_assert_int_eq(retval,UA_SUCCESS);
+	ck_assert_ptr_ne(nr,UA_NULL);
+	ck_assert_int_eq(nr->references[0]->referenceTypeId.identifier.numeric,40);
+	ck_assert_int_eq(nr->references[0]->targetId.nodeId.identifier.numeric,63);
+
+
+	UA_NodeId_copycstring("i=2",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_FALSE);
+
+	// finally
+	Namespace_delete(ns);
+}
+END_TEST
+
+START_TEST(loadUserNamespaceWithSingleProcessVariableAndAliasesShallSucceed)
+{
+	// given
+	char xml[]=
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+"<UANodeSet>"
+	"<Aliases>"
+		"<Alias Alias=\"Int32\">i=6</Alias>"
+		"<Alias Alias=\"HasTypeDefinition\">i=40</Alias>"
+	"</Aliases>"
+	"<UAVariable NodeId=\"ns=1;i=4\" BrowseName=\"X1\" DataType=\"Int32\">"
+		"<DisplayName>Integer Variable</DisplayName>"
+		"<References>"
+			"<Reference ReferenceType=\"HasTypeDefinition\">i=63</Reference>"
+		"</References>"
+	"</UAVariable>"
+"</UANodeSet>";
+	Namespace *ns;
+	UA_NodeId nodeId;
+	UA_Int32 retval;
+
+	// when
+	retval = Namespace_loadFromString(&ns,1,"ROOT",xml);
+
+	// then
+	ck_assert_ptr_ne(ns,UA_NULL);
+	ck_assert_int_eq(retval,UA_SUCCESS);
+
+	UA_NodeId_copycstring("ns=1;i=4",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_TRUE);
+
+	const UA_Node* nr = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
+	retval = Namespace_get(ns,&nodeId,&nr,&nl);
+	ck_assert_int_eq(retval,UA_SUCCESS);
+	ck_assert_ptr_ne(nr,UA_NULL);
+	ck_assert_int_eq(nr->references[0]->referenceTypeId.identifier.numeric,40);
+	ck_assert_int_eq(nr->references[0]->targetId.nodeId.identifier.numeric,63);
+
+	UA_NodeId_copycstring("ns=1;i=2",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_FALSE);
+
+	UA_NodeId_copycstring("ns=2;i=4",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_FALSE);
+
+	UA_NodeId_copycstring("i=4",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_FALSE);
+
+	// finally
+	Namespace_delete(ns);
+}
+END_TEST
+
+Suite* testSuite()
+{
+	Suite *s = suite_create("XML Test");
+	TCase *tc_core = tcase_create("Core");
+
+	tcase_add_test(tc_core, parseNumericNodeIdWithoutNsIdShallYieldNs0NodeId);
+	tcase_add_test(tc_core, parseNumericNodeIdWithNsShallYieldNodeIdWithNs);
+	tcase_add_test(tc_core, loadUserNamespaceWithSingleProcessVariableShallSucceed);
+	tcase_add_test(tc_core, loadUserNamespaceWithSingleProcessVariableAndAliasesShallSucceed);
+	suite_add_tcase(s,tc_core);
+	return s;
+}
+
+int main (void)
+{
+	int number_failed = 0;
+
+	Suite *s;
+	SRunner *sr;
+
+	s = testSuite();
+	sr = srunner_create(s);
+	srunner_set_fork_status(sr, CK_NOFORK);
+	srunner_run_all(sr,CK_NORMAL);
+	number_failed += srunner_ntests_failed(sr);
+	srunner_free(sr);
+
+	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}