Browse Source

solved #80

had to extract include/ua_types from include/ua_basictypes to prevent
circular dependencies.
Leon Urbas 10 years ago
parent
commit
b2cb2bf866
5 changed files with 139 additions and 94 deletions
  1. 5 63
      include/ua_basictypes.h
  2. 1 1
      include/ua_list.h
  3. 66 0
      include/ua_types.h
  4. 50 30
      src/ua_xml.c
  5. 17 0
      tests/check_xml.c

+ 5 - 63
include/ua_basictypes.h

@@ -1,68 +1,8 @@
 #ifndef OPCUA_BASICTYPES_H_
 #define OPCUA_BASICTYPES_H_
 
-#include <stdint.h>
-
-#define DBG_VERBOSE(expression) // omit debug code
-#define DBG_ERR(expression) // omit debug code
-#define DBG(expression) // omit debug code
-#if defined(DEBUG) 		// --enable-debug=(yes|verbose)
-# undef DBG
-# define DBG(expression) expression
-# undef DBG_ERR
-# define DBG_ERR(expression) expression
-# if defined(VERBOSE) 	// --enable-debug=verbose
-#  undef DBG_VERBOSE
-#  define DBG_VERBOSE(expression) expression
-# endif
-#endif
-
-/* Basic types */
-typedef _Bool UA_Boolean;
-typedef uint8_t UA_Byte;
-typedef int8_t UA_SByte;
-typedef int16_t UA_Int16;
-typedef uint16_t UA_UInt16;
-typedef int32_t UA_Int32;
-typedef uint32_t UA_UInt32;
-typedef int64_t UA_Int64;
-typedef uint64_t UA_UInt64;
-typedef float UA_Float;
-typedef double UA_Double;
-
-/* ByteString - Part: 6, Chapter: 5.2.2.7, Page: 17 */
-typedef struct UA_ByteString {
-	UA_Int32 	length;
-	UA_Byte*	data;
-} UA_ByteString;
-
-/* Function return values */
-#define UA_SUCCESS 0
-#define UA_NO_ERROR UA_SUCCESS
-#define UA_ERROR (0x01 << 31)
-#define UA_ERR_INCONSISTENT  (UA_ERROR | (0x01 << 1))
-#define UA_ERR_INVALID_VALUE (UA_ERROR | (0x01 << 2))
-#define UA_ERR_NO_MEMORY     (UA_ERROR | (0x01 << 3))
-#define UA_ERR_NOT_IMPLEMENTED (UA_ERROR | (0x01 << 4))
-
-/* Boolean values and null */
-#define UA_TRUE (42==42)
-#define TRUE UA_TRUE
-#define UA_FALSE (!UA_TRUE)
-#define FALSE UA_FALSE
-
-/* Compare values */
-#define UA_EQUAL 0
-#define UA_NOT_EQUAL (!UA_EQUAL)
-
-/* heap memory functions */
-#define UA_NULL ((void*)0)
-extern void const * UA_alloc_lastptr;
-#define UA_free(ptr) _UA_free(ptr,#ptr,__FILE__,__LINE__)
-UA_Int32 _UA_free(void * ptr,char*,char*,int);
-UA_Int32 UA_memcpy(void *dst, void const *src, int size);
-#define UA_alloc(ptr,size) _UA_alloc(ptr,size,#ptr,#size,__FILE__,__LINE__)
-UA_Int32 _UA_alloc(void ** dst, int size,char*,char*,char*,int);
+#include "ua_types.h"
+#include "ua_list.h"
 
 /* Stop decoding at the first failure. Free members that were already allocated.
    It is assumed that retval is already defined. */
@@ -82,7 +22,7 @@ UA_Int32 UA_Array_init(void **p,UA_Int32 noElements, UA_Int32 type);
 UA_Int32 UA_Array_new(void ***p,UA_Int32 noElements, UA_Int32 type);
 UA_Int32 UA_Array_copy(void const * const *src,UA_Int32 noElements, UA_Int32 type, void ***dst);
 
-/* XML prelimiaries */
+/* XML preliminaries */
 struct XML_Stack;
 typedef char const * const XML_Attr;
 typedef char const * cstring;
@@ -387,6 +327,8 @@ typedef struct XML_Parent {
 	int textAttribIdx; // -1 - not set
 	cstring textAttrib;
 	int activeChild; // -1 - no active child
+	int totalGatherLength;
+	UA_list_List textGatherList;
 	int len; // -1 - empty set
 	XML_child children[XML_STACK_MAX_CHILDREN];
 } XML_Parent;

+ 1 - 1
include/ua_list.h

@@ -1,7 +1,7 @@
 #ifndef UA_LIST_H_
 #define UA_LIST_H_
 
-#include "opcua.h"
+#include "ua_types.h"
 #include <stddef.h> /* Needed for sys/queue.h */
 #include <sys/queue.h>
 

+ 66 - 0
include/ua_types.h

@@ -0,0 +1,66 @@
+#ifndef OPCUA_TYPES_H_
+#define OPCUA_TYPES_H_
+
+#include <stdint.h>
+
+#define DBG_VERBOSE(expression) // omit debug code
+#define DBG_ERR(expression) // omit debug code
+#define DBG(expression) // omit debug code
+#if defined(DEBUG) 		// --enable-debug=(yes|verbose)
+# undef DBG
+# define DBG(expression) expression
+# undef DBG_ERR
+# define DBG_ERR(expression) expression
+# if defined(VERBOSE) 	// --enable-debug=verbose
+#  undef DBG_VERBOSE
+#  define DBG_VERBOSE(expression) expression
+# endif
+#endif
+
+/* Basic types */
+typedef _Bool UA_Boolean;
+typedef uint8_t UA_Byte;
+typedef int8_t UA_SByte;
+typedef int16_t UA_Int16;
+typedef uint16_t UA_UInt16;
+typedef int32_t UA_Int32;
+typedef uint32_t UA_UInt32;
+typedef int64_t UA_Int64;
+typedef uint64_t UA_UInt64;
+typedef float UA_Float;
+typedef double UA_Double;
+
+/* ByteString - Part: 6, Chapter: 5.2.2.7, Page: 17 */
+typedef struct UA_ByteString {
+	UA_Int32 	length;
+	UA_Byte*	data;
+} UA_ByteString;
+
+/* Function return values */
+#define UA_SUCCESS 0
+#define UA_NO_ERROR UA_SUCCESS
+#define UA_ERROR (0x01 << 31)
+#define UA_ERR_INCONSISTENT  (UA_ERROR | (0x01 << 1))
+#define UA_ERR_INVALID_VALUE (UA_ERROR | (0x01 << 2))
+#define UA_ERR_NO_MEMORY     (UA_ERROR | (0x01 << 3))
+#define UA_ERR_NOT_IMPLEMENTED (UA_ERROR | (0x01 << 4))
+
+/* Boolean values and null */
+#define UA_TRUE (42==42)
+#define TRUE UA_TRUE
+#define UA_FALSE (!UA_TRUE)
+#define FALSE UA_FALSE
+
+/* Compare values */
+#define UA_EQUAL 0
+#define UA_NOT_EQUAL (!UA_EQUAL)
+
+/* heap memory functions */
+#define UA_NULL ((void*)0)
+extern void const * UA_alloc_lastptr;
+#define UA_free(ptr) _UA_free(ptr,#ptr,__FILE__,__LINE__)
+UA_Int32 _UA_free(void * ptr,char*,char*,int);
+UA_Int32 UA_memcpy(void *dst, void const *src, int size);
+#define UA_alloc(ptr,size) _UA_alloc(ptr,size,#ptr,#size,__FILE__,__LINE__)
+UA_Int32 _UA_alloc(void ** dst, int size,char*,char*,char*,int);
+#endif

+ 50 - 30
src/ua_xml.c

@@ -143,6 +143,8 @@ void XML_Stack_init(XML_Stack* p, UA_UInt32 nsid, cstring name) {
 		p->parent[i].activeChild = -1;
 		p->parent[i].textAttrib = UA_NULL;
 		p->parent[i].textAttribIdx = -1;
+		p->parent[i].totalGatherLength = -1;
+		UA_list_init(&(p->parent[i].textGatherList));
 		for (j = 0; j < XML_STACK_MAX_CHILDREN; j++) {
 			p->parent[i].children[j].name = UA_NULL;
 			p->parent[i].children[j].length = -1;
@@ -947,11 +949,6 @@ UA_Int32 UA_NodeSetAlias_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSetAlias
 				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
 			}
 		}
-	} else {
-		// sub element is ready
-// TODO: It is a design flaw that we need to do this here, isn't it?
-//		DBG_VERBOSE(printf("UA_NodeSetAlias clears %p\n", (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
-//		s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
 	}
 	return UA_SUCCESS;
 }
@@ -1066,44 +1063,67 @@ UA_Int32 XML_isSpace(cstring s, int len) {
 	return UA_TRUE;
 }
 
-/* simulates startElement, endElement behaviour */
+/* gather text */
 void XML_Stack_handleText(void * data, const char *txt, int len) {
 	XML_Stack* s = (XML_Stack*) data;
 
 	if (len > 0 && !XML_isSpace(txt, len)) {
-		XML_Parent* cp = &(s->parent[s->depth]);
-		if (cp->textAttribIdx >= 0) {
-			cp->activeChild = cp->textAttribIdx;
-			char* buf; // need to copy txt to add 0 as string terminator
-			UA_alloc((void** )&buf, len + 1);
-			strncpy(buf, txt, len);
-			buf[len] = 0;
-			XML_Attr attr[3] = { cp->textAttrib, buf, UA_NULL };
-			DBG(printf("handleText @ %s calls start elementHandler %s with dst=%p, buf={%s}\n", XML_Stack_path(s),cp->children[cp->activeChild].name, cp->children[cp->activeChild].obj, buf));
-			cp->children[cp->activeChild].elementHandler(s, attr, cp->children[cp->activeChild].obj, TRUE);
-			// FIXME: The indices of this call are simply wrong
-			// DBG_VERBOSE(printf("handleText calls finish elementHandler %s with dst=%p, attr=(nil)\n", cp->children[cp->activeChild].name, cp->children[cp->activeChild].obj));
-			// cp->children[cp->activeChild].elementHandler(s, UA_NULL, cp->children[cp->activeChild].obj, FALSE);
-
-			if (s->parent[s->depth-1].activeChild > 0) {
-				// FIXME: actually we'd like to have something like the following, won't we?
-				// XML_Stack_endElement(data, cp->children[cp->activeChild].name);
-				XML_child* c = &(s->parent[s->depth-1].children[s->parent[s->depth-1].activeChild]);
-				c->elementHandler(s, UA_NULL, c->obj, FALSE);
-			}
-			UA_free(buf);
+		XML_Parent* cp = &(s->parent[s->depth]); // determine current element
+		UA_ByteString src = { len+1, (UA_Byte*) txt };
+		UA_ByteString *dst;
+		UA_ByteString_new(&dst);	// alloc dst
+		UA_ByteString_copy(&src,dst); // alloc dst->data and copy txt
+		dst->data[len] = 0; // add terminating zero to handle single line efficiently
+		UA_list_addPayloadToBack(&(cp->textGatherList), (void*) dst);
+		if (cp->totalGatherLength == -1) {
+			cp->totalGatherLength = len;
 		} else {
-			DBG_VERBOSE(XML_Stack_print(s));
-			DBG_VERBOSE(printf("textData - ignore text data '%.*s'\n", len, txt));
+			cp->totalGatherLength += len;
 		}
 	}
 }
 
+char* theGatherBuffer;
+void textGatherListTotalLength(void* payload) {
+	UA_ByteString* b = (UA_ByteString*) payload;
+	UA_ByteString_printf("\t",b);
+	UA_memcpy(theGatherBuffer,b->data,b->length-1); // remove trailing zero
+	theGatherBuffer += (b->length-1);
+}
 /** if we are an activeChild of a parent we call the child-handler */
 void XML_Stack_endElement(void *data, const char *el) {
 	XML_Stack* s = (XML_Stack*) data;
 
-// the parent of the parent (pop) of the element knows the elementHandler, therefore depth-2!
+	XML_Parent* ce = &(s->parent[s->depth]);
+	if (ce->textAttribIdx >= 0 && ce->totalGatherLength > 0 ) {
+		ce->activeChild = ce->textAttribIdx;
+		char* buf;
+		if (UA_list_getFirst(&(ce->textGatherList)) == UA_list_getLast(&(ce->textGatherList)) ) {
+			buf = (char*) ((UA_ByteString*) UA_list_getFirst(&(ce->textGatherList))->payload)->data;
+		} else {
+			printf("XML_Stack_endElement - more than one text snippet with total length=%d:\n",ce->totalGatherLength);
+			UA_alloc((void**)&theGatherBuffer,ce->totalGatherLength+1);
+			buf = theGatherBuffer;
+			UA_list_iteratePayload(&(ce->textGatherList), textGatherListTotalLength);
+			buf[ce->totalGatherLength] = 0;
+			printf("XML_Stack_endElement - gatherBuffer %s:\n",buf);
+		}
+		XML_Attr attr[3] = { ce->textAttrib, buf, UA_NULL };
+		DBG(printf("handleText @ %s calls start elementHandler %s with dst=%p, buf={%s}\n", XML_Stack_path(s),ce->children[ce->activeChild].name, ce->children[ce->activeChild].obj, buf));
+		ce->children[ce->activeChild].elementHandler(s, attr, ce->children[ce->activeChild].obj, TRUE);
+		if (s->parent[s->depth-1].activeChild > 0) {
+			XML_child* c = &(s->parent[s->depth-1].children[s->parent[s->depth-1].activeChild]);
+			c->elementHandler(s, UA_NULL, c->obj, FALSE);
+		}
+		if (UA_list_getFirst(&(ce->textGatherList)) != UA_list_getLast(&(ce->textGatherList)) ) {
+			UA_free(buf);
+		}
+		UA_list_destroy(&(ce->textGatherList),(UA_list_PayloadVisitor) UA_ByteString_delete);
+		UA_list_init(&(ce->textGatherList)); // don't know if destroy leaves the list in usable state...
+		ce->totalGatherLength = -1;
+	}
+
+	// the parent of the parent (pop) of the element knows the elementHandler, therefore depth-2!
 	if (s->depth > 1) {
 		// inform parents elementHandler that everything is done
 		XML_Parent* cp = &(s->parent[s->depth - 1]);

+ 17 - 0
tests/check_xml.c

@@ -81,6 +81,15 @@ START_TEST(loadUserNamespaceWithSingleProcessVariableShallSucceed)
 	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);
 
@@ -120,6 +129,14 @@ START_TEST(loadUserNamespaceWithSingleProcessVariableAndAliasesShallSucceed)
 	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);