Browse Source

Merge of branch namespace_generation

Leon Urbas 10 years ago
parent
commit
596f70813a

+ 4 - 0
.gitignore

@@ -16,6 +16,7 @@
 *.pyc
 *.gcno
 *.gcda
+.dirstamp
 /bin
 m4
 /autom4te.cache
@@ -37,6 +38,9 @@ config.log
 /configure
 /missing
 /html
+/doc/html/*
+/doc/Doxyfile
+/doc/doxyfile.stamp
 *~
 GIT_REVISION
 SVN_REVISION

+ 1 - 0
.travis.yml

@@ -15,6 +15,7 @@ addons:
     build_command: make
     branch_pattern: coverity_scan
 before_install:
+- sudo add-apt-repository ppa:libreoffice/ppa -y
 - sudo apt-get update -qq
 - sudo apt-get install -qq build-essential subversion git autoconf libtool texinfo
   python-lxml graphviz doxygen

+ 3 - 0
README.md

@@ -7,6 +7,9 @@ An open-source communication stack implementation of OPC UA (OPC Unified Archite
 [![Build Status](https://travis-ci.org/acplt/open62541.png?branch=master)](https://travis-ci.org/acplt/open62541)
 [![Coverity Scan Build Status](https://scan.coverity.com/projects/1864/badge.svg)](https://scan.coverity.com/projects/1864)
 
+### Documentation
+Documentation is generated from Doxygen annotations in the source code. The current version can be accessed at http://acplt.github.io/open62541/doxygen/.
+
 
 ## Getting dependencies
 ### Ubuntu

+ 18 - 17
doc/Doxyfile.in

@@ -242,7 +242,7 @@ TCL_SUBST              =
 # members will be omitted, etc.
 # The default value is: NO.
 
-OPTIMIZE_OUTPUT_FOR_C  = NO
+OPTIMIZE_OUTPUT_FOR_C  = YES
 
 # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
 # Python sources only. Doxygen will then generate output that is more tailored
@@ -371,7 +371,7 @@ INLINE_GROUPED_CLASSES = NO
 # Man pages) or section (for LaTeX and RTF).
 # The default value is: NO.
 
-INLINE_SIMPLE_STRUCTS  = NO
+INLINE_SIMPLE_STRUCTS  = YES
 
 # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
 # enum is documented as struct, union, or enum with the name of the typedef. So
@@ -382,7 +382,7 @@ INLINE_SIMPLE_STRUCTS  = NO
 # types are typedef'ed and only the typedef is referenced, never the tag name.
 # The default value is: NO.
 
-TYPEDEF_HIDES_STRUCT   = NO
+TYPEDEF_HIDES_STRUCT   = YES
 
 # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
 # cache is used to resolve symbols given their name and scope. Since this can be
@@ -649,7 +649,7 @@ SHOW_FILES             = YES
 # Folder Tree View (if specified).
 # The default value is: YES.
 
-SHOW_NAMESPACES        = YES
+SHOW_NAMESPACES        = NO
 
 # The FILE_VERSION_FILTER tag can be used to specify a program or script that
 # doxygen should invoke to get the current version for each file (typically from
@@ -774,7 +774,7 @@ INPUT_ENCODING         = UTF-8
 # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
 # *.qsf, *.as and *.js.
 
-FILE_PATTERNS          =
+FILE_PATTERNS          = *.h *.dox
 
 # The RECURSIVE tag can be used to specify whether or not subdirectories should
 # be searched for input files as well.
@@ -805,7 +805,7 @@ EXCLUDE_SYMLINKS       = NO
 # Note that the wildcards are matched against the file with absolute path, so to
 # exclude all test directories for example use the pattern */test/*
 
-EXCLUDE_PATTERNS       =
+EXCLUDE_PATTERNS       = */cov-int/*
 
 # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
 # (namespaces, classes, functions, etc.) that should be excluded from the
@@ -994,7 +994,7 @@ ALPHABETICAL_INDEX     = YES
 # Minimum value: 1, maximum value: 20, default value: 5.
 # This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
 
-COLS_IN_ALPHA_INDEX    = 5
+COLS_IN_ALPHA_INDEX    = 3
 
 # In case all classes in a project start with a common prefix, all classes will
 # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
@@ -1046,7 +1046,7 @@ HTML_FILE_EXTENSION    = .html
 # of the possible markers and block names see the documentation.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_HEADER            =
+HTML_HEADER            = style/header.html
 
 # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
 # generated HTML page. If the tag is left blank doxygen will generate a standard
@@ -1056,7 +1056,7 @@ HTML_HEADER            =
 # that doxygen normally uses.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_FOOTER            =
+HTML_FOOTER            = style/footer.html
 
 # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
 # sheet that is used by each HTML page. It can be used to fine-tune the look of
@@ -1068,7 +1068,7 @@ HTML_FOOTER            =
 # obsolete.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_STYLESHEET        =
+HTML_STYLESHEET        = style/doxygen.css
 
 # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
 # defined cascading style sheet that is included after the standard style sheets
@@ -1089,7 +1089,8 @@ HTML_EXTRA_STYLESHEET  =
 # files will be copied as-is; there are no commands or markers available.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_EXTRA_FILES       =
+HTML_EXTRA_FILES       = style/jquery-1.11.1.min.js \
+                         style/load-style.js
 
 # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
 # will adjust the colors in the stylesheet and background images according to
@@ -1135,7 +1136,7 @@ HTML_TIMESTAMP         = YES
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_DYNAMIC_SECTIONS  = NO
+HTML_DYNAMIC_SECTIONS  = YES
 
 # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
 # shown in the various tree structured indices initially; the user can expand
@@ -1478,7 +1479,7 @@ MATHJAX_CODEFILE       =
 # The default value is: YES.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-SEARCHENGINE           = YES
+SEARCHENGINE           = NO
 
 # When the SERVER_BASED_SEARCH tag is enabled the search engine will be
 # implemented using a web server instead of a web client using Javascript. There
@@ -1552,7 +1553,7 @@ EXTRA_SEARCH_MAPPINGS  =
 # If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
 # The default value is: YES.
 
-GENERATE_LATEX         = YES
+GENERATE_LATEX         = NO
 
 # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
 # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@@ -2025,7 +2026,7 @@ PERL_PATH              = /usr/bin/perl
 # powerful graphs.
 # The default value is: YES.
 
-CLASS_DIAGRAMS         = YES
+CLASS_DIAGRAMS         = NO
 
 # You can define message sequence charts within doxygen comments using the \msc
 # command. Doxygen will then run the mscgen tool (see:
@@ -2098,7 +2099,7 @@ DOT_FONTPATH           =
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
-CLASS_GRAPH            = YES
+CLASS_GRAPH            = NO
 
 # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
 # graph for each documented class showing the direct and indirect implementation
@@ -2107,7 +2108,7 @@ CLASS_GRAPH            = YES
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
-COLLABORATION_GRAPH    = YES
+COLLABORATION_GRAPH    = NO
 
 # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
 # groups, showing the direct groups dependencies.

+ 6 - 0
doc/mainpage.dox

@@ -0,0 +1,6 @@
+/**
+\mainpage Open62541 Developer Documentation
+
+This file should contain some high-level description and pointers for further reading.
+
+*/

File diff suppressed because it is too large
+ 336 - 0
doc/style/doxygen.css


+ 20 - 0
doc/style/footer.html

@@ -0,0 +1,20 @@
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+  <ul>
+    $navpath
+    <li class="footer">$generatedby
+    <a href="http://www.doxygen.org/index.html">
+    <img class="footer" src="doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
+  </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<address class="footer"><small>
+$generatedby &#160;<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/>
+</a> $doxygenversion
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+</body>
+</html>

+ 19 - 0
doc/style/header.html

@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
+<script type="text/javascript" src="dynsections.js"></script>
+<script type="text/javascript" src="load-style.js"></script>
+$treeview
+$search
+$mathjax
+<link href="doxygen.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+

File diff suppressed because it is too large
+ 4 - 0
doc/style/jquery-1.11.1.min.js


+ 57 - 0
doc/style/load-style.js

@@ -0,0 +1,57 @@
+$( document ).ready(function() {
+
+	$('#top > div > ul > li > a').wrapInner("<b></b>");
+
+	$("div.header").prepend("<h2></h2>");
+	$("div.header > h2").text($("div.title").text());
+	$("div.headertitle").remove();
+	$("#nav-path").remove();
+	
+	$("body").wrapInner("<div class='container'><div class='row'><div class='col-md-12'></div></div></div>");
+	$("ul.tablist").addClass("nav nav-pills nav-justified");
+	$("ul.tablist").css("margin-top", "0.5em");
+	$("ul.tablist").css("margin-bottom", "0.5em");
+	$("li.current").addClass("active");
+	$(".contents").wrapInner("<div class='panel panel-default' style='margin-top:1em;'><div class='panel-body'></div></div>");
+
+	$("iframe").attr("scrolling", "yes");
+	
+	$('img[src="ftv2ns.png"]').replaceWith('<span class="label label-danger">N</span> ');
+	$('img[src="ftv2cl.png"]').replaceWith('<span class="label label-danger">C</span> ');
+
+	// dirty workaround since doxygen 1.7 doesn't set table ids
+	$("table").each(function() {
+		if($(this).find("tbody > tr > td.indexkey").length > 0) {
+			$(this).addClass("table table-striped");
+		}
+	});
+	
+	$("table.params").addClass("table");
+	$("div.ingroups").wrapInner("<small></small>");
+	$("div.levels").css("margin", "0.5em");
+	$("div.levels > span").addClass("btn btn-default btn-xs");
+	$("div.levels > span").css("margin-right", "0.25em");
+	
+	$("table.directory").addClass("table table-striped");
+	$("div.summary > a").addClass("btn btn-default btn-xs");
+	$("table.fieldtable").addClass("table");
+	$(".fragment").addClass("well");
+	$(".memitem").addClass("panel panel-default");
+	$(".memproto").addClass("panel-heading");
+	$(".memdoc").addClass("panel-body");
+	$("span.mlabel").addClass("label label-info");
+	
+	$("table.memberdecls").addClass("table");
+	$("[class^=memitem]").addClass("active");
+	$("td.memSeparator").remove()
+	
+	$("div.ah").addClass("btn btn-default");
+	$("span.mlabels").addClass("pull-right");
+	$("table.mlabels").css("width", "100%")
+	$("td.mlabels-right").addClass("pull-right");
+
+	$("div.ttc").addClass("panel panel-info");
+	$("div.ttname").addClass("panel-heading");
+	$("div.ttdef,div.ttdoc,div.ttdeci").addClass("panel-body");
+});
+

File diff suppressed because it is too large
+ 172 - 893
examples/src/xml2ns0.c


+ 160 - 108
include/ua_basictypes.h

@@ -1,10 +1,3 @@
-/*
- * ua_basictypes.h
- *
- *  Created on: 13.03.2014
- *      Author: mrt
- */
-
 #ifndef OPCUA_BASICTYPES_H_
 #define OPCUA_BASICTYPES_H_
 
@@ -36,14 +29,12 @@ 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
-{
+typedef struct UA_ByteString {
 	UA_Int32 	length;
 	UA_Byte*	data;
-}
-UA_ByteString;
-
+} UA_ByteString;
 
 /* Function return values */
 #define UA_SUCCESS 0
@@ -91,10 +82,19 @@ 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 */
+struct XML_Stack;
+typedef char const * const XML_Attr;
+typedef char const * cstring;
+#define XML_STACK_MAX_DEPTH 10
+#define XML_STACK_MAX_CHILDREN 40
+typedef UA_Int32 (*XML_decoder)(struct XML_Stack* s, XML_Attr* attr, void* dst, UA_Boolean isStart);
+
 #define UA_TYPE_METHOD_PROTOTYPES(TYPE) \
 	UA_Int32 TYPE##_calcSize(TYPE const * ptr);							\
 	UA_Int32 TYPE##_encodeBinary(TYPE const * src, UA_Int32* pos, UA_ByteString * dst);	\
 	UA_Int32 TYPE##_decodeBinary(UA_ByteString const * src, UA_Int32* pos, TYPE * dst);	\
+	UA_Int32 TYPE##_decodeXML(struct XML_Stack* s, XML_Attr* attr, TYPE* dst, UA_Boolean isStart); \
 	UA_Int32 TYPE##_delete(TYPE * p);									\
 	UA_Int32 TYPE##_deleteMembers(TYPE * p);							\
 	UA_Int32 TYPE##_init(TYPE * p);										\
@@ -122,13 +122,12 @@ UA_Int32 TYPE##_delete(TYPE *p) { \
 }
 
 #define UA_TYPE_METHOD_COPY(TYPE) \
-UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst){ \
+UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst) { \
 	UA_Int32 retval = UA_SUCCESS; \
 	retval |= UA_memcpy(dst, src, TYPE##_calcSize(UA_NULL)); \
 	return retval; \
 }
 
-
 #define UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(TYPE) \
 UA_Int32 TYPE##_deleteMembers(TYPE * p) { return UA_SUCCESS; }
 
@@ -140,32 +139,49 @@ UA_Int32 TYPE##_decodeBinary(UA_ByteString const * src, UA_Int32* pos, TYPE *dst
 	return TYPE_AS##_decodeBinary(src,pos,(TYPE_AS*) dst); \
 }
 
+#define UA_TYPE_METHOD_DECODEXML_NOTIMPL(TYPE) \
+	UA_Int32 TYPE##_decodeXML(XML_Stack* s, XML_Attr* attr, TYPE* dst, _Bool isStart) { \
+		DBG_VERBOSE(printf(#TYPE "_decodeXML entered with dst=%p,isStart=%d\n", (void* ) dst, isStart)); \
+		return UA_ERR_NOT_IMPLEMENTED;\
+	}
+
+#define UA_TYPE_METHOD_DECODEXML_AS(TYPE,TYPE_AS) \
+	UA_Int32 TYPE##_decodeXML(struct XML_Stack* s, XML_Attr* attr, TYPE* dst, _Bool isStart) { \
+		return TYPE_AS##_decodeXML(s,attr,(TYPE_AS*) dst,isStart); \
+	}
+
 #define UA_TYPE_METHOD_ENCODEBINARY_AS(TYPE,TYPE_AS) \
 UA_Int32 TYPE##_encodeBinary(TYPE const * src, UA_Int32* pos, UA_ByteString *dst) { \
 	return TYPE_AS##_encodeBinary((TYPE_AS*) src,pos,dst); \
 }
 
 #define UA_TYPE_METHOD_INIT_AS(TYPE, TYPE_AS) \
-UA_Int32 TYPE##_init(TYPE * p){ \
+UA_Int32 TYPE##_init(TYPE * p) { \
 	return TYPE_AS##_init((TYPE_AS*)p); \
 }
 #define UA_TYPE_METHOD_COPY_AS(TYPE, TYPE_AS) \
 UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst) {return TYPE_AS##_copy((TYPE_AS*) src,(TYPE_AS*)dst); \
 }
 
+#define UA_TYPE_METHOD_PROTOTYPES_AS_WOXML(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_CALCSIZE_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_ENCODEBINARY_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_DECODEBINARY_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_DELETE_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_DELETEMEMBERS_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_INIT_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_COPY_AS(TYPE, TYPE_AS)
 
 #define UA_TYPE_METHOD_PROTOTYPES_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_CALCSIZE_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_ENCODEBINARY_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_DECODEBINARY_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_DELETE_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_DELETEMEMBERS_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_INIT_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_COPY_AS(TYPE, TYPE_AS)
+	UA_TYPE_METHOD_PROTOTYPES_AS_WOXML(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_DECODEXML_AS(TYPE, TYPE_AS)
 
+#define UA_TYPE_METHOD_PROTOTYPES_AS(TYPE, TYPE_AS) \
+UA_TYPE_METHOD_PROTOTYPES_AS_WOXML(TYPE, TYPE_AS) \
+UA_TYPE_METHOD_DECODEXML_AS(TYPE, TYPE_AS)
 
 #define UA_TYPE_METHOD_NEW_DEFAULT(TYPE) \
-UA_Int32 TYPE##_new(TYPE ** p){ \
+UA_Int32 TYPE##_new(TYPE ** p) { \
 	UA_Int32 retval = UA_SUCCESS;\
 	retval |= UA_alloc((void**)p, TYPE##_calcSize(UA_NULL));\
 	retval |= TYPE##_init(*p);\
@@ -173,15 +189,13 @@ UA_Int32 TYPE##_new(TYPE ** p){ \
 }
 
 #define UA_TYPE_METHOD_INIT_DEFAULT(TYPE) \
-UA_Int32 TYPE##_init(TYPE * p){ \
+UA_Int32 TYPE##_init(TYPE * p) { \
 	if(p==UA_NULL)return UA_ERROR;\
 	*p = (TYPE)0;\
 	return UA_SUCCESS;\
 }
 //#define UA_TYPE_COPY_METHOD_PROTOTYPE(TYPE) \  UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst);
 
-
-
 /*** Prototypes for basic types **/
 UA_TYPE_METHOD_PROTOTYPES (UA_Boolean)
 UA_TYPE_METHOD_PROTOTYPES (UA_Byte)
@@ -194,6 +208,7 @@ UA_TYPE_METHOD_PROTOTYPES (UA_Int64)
 UA_TYPE_METHOD_PROTOTYPES (UA_UInt64)
 UA_TYPE_METHOD_PROTOTYPES (UA_Float)
 UA_TYPE_METHOD_PROTOTYPES (UA_Double)
+
 /**
 * StatusCodeBinaryEncoding
 * Part: 6
@@ -210,43 +225,14 @@ UA_TYPE_METHOD_PROTOTYPES (UA_StatusCode)
 typedef float UA_IntegerId;
 UA_TYPE_METHOD_PROTOTYPES (UA_IntegerId)
 
-typedef struct UA_VTable {
-	UA_UInt32 ns0Id;
-	UA_Int32 (*calcSize)(void const * ptr);
-	UA_Int32 (*decodeBinary)(UA_ByteString const * src, UA_Int32* pos, void* dst);
-	UA_Int32 (*encodeBinary)(void const * src, UA_Int32* pos, UA_ByteString* dst);
-	UA_Int32 (*init)(void * p);
-	UA_Int32 (*new)(void ** p);
-	UA_Int32 (*copy)(void const *src,void *dst);
-	UA_Int32 (*delete)(void * p);
-	UA_Byte* name;
-} UA_VTable;
-
-/* VariantBinaryEncoding - Part: 6, Chapter: 5.2.2.16, Page: 22 */
-enum UA_VARIANT_ENCODINGMASKTYPE_enum
-{
-	UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3F,	// bits 0:5
-	UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS = (0x01 << 6), // bit 6
-	UA_VARIANT_ENCODINGMASKTYPE_ARRAY = ( 0x01 << 7) // bit 7
-};
-
-typedef struct UA_Variant {
-	UA_VTable* vt;		// internal entry into vTable
-	UA_Byte encodingMask; 	// Type of UA_Variant_EncodingMaskType_enum
-	UA_Int32 arrayLength;	// total number of elements
-	UA_Int32 arrayDimensionsLength;
-	UA_Int32 **arrayDimensions;
-	void** data;
-} UA_Variant;
-UA_TYPE_METHOD_PROTOTYPES (UA_Variant)
-
-/* String - Part: 6, Chapter: 5.2.2.4, Page: 16 */
-typedef struct UA_String
-{
+/** @brief String Object
+ *
+ *  String - Part: 6, Chapter: 5.2.2.4, Page: 16
+ */
+typedef struct UA_String {
 	UA_Int32 	length;
 	UA_Byte*	data;
-}
-UA_String;
+} UA_String;
 UA_TYPE_METHOD_PROTOTYPES (UA_String)
 //UA_Int32 UA_String_copy(UA_String const * src, UA_String* dst);
 UA_Int32 UA_String_copycstring(char const * src, UA_String* dst);
@@ -263,19 +249,17 @@ UA_Int32 UA_ByteString_compare(const UA_ByteString *string1, const UA_ByteString
 UA_Int32 UA_ByteString_newMembers(UA_ByteString* p, UA_Int32 length);
 extern UA_ByteString UA_ByteString_securityPoliceNone;
 
-/** LocalizedTextBinaryEncoding - Part: 6, Chapter: 5.2.2.14, Page: 21 */
-enum UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_enum
-{
+/* LocalizedTextBinaryEncoding - Part: 6, Chapter: 5.2.2.14, Page: 21 */
+enum UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_enum {
 	UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE = 0x01,
 	UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT = 0x02
 };
-typedef struct UA_LocalizedText
-{
+
+typedef struct UA_LocalizedText {
 	UA_Byte encodingMask;
 	UA_String locale;
 	UA_String text;
-}
-UA_LocalizedText;
+} UA_LocalizedText;
 UA_TYPE_METHOD_PROTOTYPES (UA_LocalizedText)
 
 UA_Int32 UA_LocalizedText_copycstring(char const * src, UA_LocalizedText* dst);
@@ -284,8 +268,7 @@ void UA_ByteString_printx(char* label, const UA_ByteString* string);
 void UA_ByteString_printx_hex(char* label, const UA_ByteString* string);
 
 /* GuidType - Part: 6, Chapter: 5.2.2.6 Page: 17 */
-typedef struct UA_Guid
-{
+typedef struct UA_Guid {
 	UA_UInt32 data1;
 	UA_UInt16 data2;
 	UA_UInt16 data3;
@@ -299,8 +282,7 @@ typedef UA_Int64 UA_DateTime; //100 nanosecond resolution
 UA_TYPE_METHOD_PROTOTYPES (UA_DateTime)
 
 UA_DateTime UA_DateTime_now();
-typedef struct UA_DateTimeStruct
-{
+typedef struct UA_DateTimeStruct {
 	UA_Int16 nanoSec;
 	UA_Int16 microSec;
 	UA_Int16 milliSec;
@@ -314,77 +296,149 @@ typedef struct UA_DateTimeStruct
 UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime time);
 UA_Int32 UA_DateTime_toString(UA_DateTime time, UA_String* timeString);
 
-
-typedef struct UA_NodeId
-{
+typedef struct UA_NodeId {
 	UA_Byte   encodingByte; //enum BID_NodeIdEncodingValuesType
 	UA_UInt16 namespace;
-
-    union
-    {
+    union {
         UA_UInt32 numeric;
         UA_String string;
         UA_Guid guid;
         UA_ByteString byteString;
-    }
-    identifier;
+    } identifier;
 } UA_NodeId;
 UA_TYPE_METHOD_PROTOTYPES (UA_NodeId)
 
 UA_Int32 UA_NodeId_compare(const UA_NodeId *n1, const UA_NodeId *n2);
 void UA_NodeId_printf(char* label, const UA_NodeId* node);
+UA_Boolean UA_NodeId_isNull(const UA_NodeId* p);
 
-/** XmlElement - Part: 6, Chapter: 5.2.2.8, Page: 17 */
-typedef struct UA_XmlElement
-{
+/* XmlElement - Part: 6, Chapter: 5.2.2.8, Page: 17 */
+typedef struct UA_XmlElement {
 	//TODO Überlegung ob man es direkt als ByteString speichert oder als String
 	UA_ByteString data;
 } UA_XmlElement;
 UA_TYPE_METHOD_PROTOTYPES (UA_XmlElement)
 
-
 /* ExpandedNodeId - Part: 6, Chapter: 5.2.2.10, Page: 19 */
 // 62541-6 Chapter 5.2.2.9, Table 5
 #define UA_NODEIDTYPE_NAMESPACE_URI_FLAG 0x80
 #define UA_NODEIDTYPE_SERVERINDEX_FLAG   0x40
 #define UA_NODEIDTYPE_MASK (~(UA_NODEIDTYPE_NAMESPACE_URI_FLAG | UA_NODEIDTYPE_SERVERINDEX_FLAG))
-typedef struct UA_ExpandedNodeId
-{
+typedef struct UA_ExpandedNodeId {
 	UA_NodeId nodeId;
 	UA_String namespaceUri;
 	UA_UInt32 serverIndex;
-}
-UA_ExpandedNodeId;
+} UA_ExpandedNodeId;
 UA_TYPE_METHOD_PROTOTYPES(UA_ExpandedNodeId)
+UA_Boolean UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId* p);
 
-
+/* IdentifierType */
 typedef UA_Int32 UA_IdentifierType;
 UA_TYPE_METHOD_PROTOTYPES(UA_IdentifierType)
 
-
 /* ExtensionObjectBinaryEncoding - Part: 6, Chapter: 5.2.2.15, Page: 21 */
 typedef struct UA_ExtensionObject {
 	UA_NodeId typeId;
 	UA_Byte encoding; //Type of the enum UA_ExtensionObjectEncodingMaskType
-	UA_ByteString body;
+	UA_ByteString body; // contains either the bytestring or a pointer to the memory-object
 } UA_ExtensionObject;
 UA_TYPE_METHOD_PROTOTYPES(UA_ExtensionObject)
 
-enum UA_ExtensionObject_EncodingMaskType_enum
-{
-	UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED = 	0x00,
+enum UA_ExtensionObject_EncodingMaskType_enum {
+	UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED =   0x00,
 	UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING = 	0x01,
-	UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISXML = 	0x02
+	UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISXML =         0x02
 };
 
 /* QualifiedNameBinaryEncoding - Part: 6, Chapter: 5.2.2.13, Page: 20 */
 typedef struct UA_QualifiedName {
 	UA_UInt16 namespaceIndex;
-	UA_UInt16 reserved;
+	/*UA_UInt16 reserved; removed by Sten since unclear origin*/
 	UA_String name;
 } UA_QualifiedName;
 UA_TYPE_METHOD_PROTOTYPES(UA_QualifiedName)
 
+/* XML Decoding */
+
+/** @brief A readable shortcut for NodeIds. A list of aliases is intensively used in the namespace0-xml-files */
+typedef struct UA_NodeSetAlias {
+	UA_String alias;
+	UA_String value;
+} UA_NodeSetAlias;
+UA_TYPE_METHOD_PROTOTYPES (UA_NodeSetAlias)
+
+/** @brief UA_NodeSetAliases - a list of aliases */
+typedef struct UA_NodeSetAliases {
+	UA_Int32 size;
+	UA_NodeSetAlias** aliases;
+} UA_NodeSetAliases;
+UA_TYPE_METHOD_PROTOTYPES (UA_NodeSetAliases)
+
+typedef struct XML_child {
+	cstring name;
+	UA_Int32 length;
+	UA_Int32 type;
+	XML_decoder elementHandler;
+	void* obj;
+} XML_child;
+
+typedef struct XML_Parent {
+	cstring name;
+	int textAttribIdx; // -1 - not set
+	cstring textAttrib;
+	int activeChild; // -1 - no active child
+	int len; // -1 - empty set
+	XML_child children[XML_STACK_MAX_CHILDREN];
+} XML_Parent;
+
+typedef struct XML_Stack {
+	int depth;
+	XML_Parent parent[XML_STACK_MAX_DEPTH];
+	UA_NodeSetAliases* aliases; // shall point to the aliases of the NodeSet after reading
+} XML_Stack;
+
+typedef struct UA_VTable {
+	UA_Byte* name;
+	UA_UInt32 ns0Id;
+	UA_Int32 (*calcSize)(void const * ptr);
+	UA_Int32 (*decodeBinary)(UA_ByteString const * src, UA_Int32* pos, void* dst);
+	UA_Int32 (*encodeBinary)(void const * src, UA_Int32* pos, UA_ByteString* dst);
+	UA_Int32 (*decodeXML)(XML_Stack* s, XML_Attr* attr, void* dst, UA_Boolean isStart);
+	UA_Int32 (*init)(void * p);
+	UA_Int32 (*new)(void ** p);
+	UA_Int32 (*copy)(void const *src,void *dst);
+	UA_Int32 (*delete)(void * p);
+	UA_UInt32 memSize; // size of the struct only in memory (no dynamic components)
+} UA_VTable;
+
+/* VariantBinaryEncoding - Part: 6, Chapter: 5.2.2.16, Page: 22 */
+enum UA_VARIANT_ENCODINGMASKTYPE_enum {
+	UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3F,	// bits 0:5
+	UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS =  (0x01 << 6), // bit 6
+	UA_VARIANT_ENCODINGMASKTYPE_ARRAY =       (0x01 << 7) // bit 7
+};
+
+typedef struct UA_Variant {
+	UA_VTable* vt;		// internal entry into vTable
+	UA_Byte encodingMask; 	// Type of UA_Variant_EncodingMaskType_enum
+	UA_Int32 arrayLength;	// total number of elements
+	UA_Int32 arrayDimensionsLength;
+	UA_Int32 **arrayDimensions;
+	void** data;
+} UA_Variant;
+UA_TYPE_METHOD_PROTOTYPES (UA_Variant)
+
+UA_Int32 UA_Variant_copySetValue(UA_Variant *v, UA_Int32 type, const void* data);
+UA_Int32 UA_Variant_copySetArray(UA_Variant *v, UA_Int32 type_id, UA_Int32 arrayLength, UA_UInt32 elementSize, const void* array);
+
+/**
+   @brief Functions UA_Variant_borrowSetValue and ..Array allow to define
+ variants whose payload will not be deleted. This is achieved by a second
+ vtable. The functionality can be used e.g. when UA_VariableNodes point into a
+ "father" structured object that is stored in an UA_VariableNode itself. */
+UA_Int32 UA_Variant_borrowSetValue(UA_Variant *v, UA_Int32 type, const void* data); // Take care not to free the data before the variant.
+UA_Int32 UA_Variant_borrowSetArray(UA_Variant *v, UA_Int32 type, UA_Int32 arrayLength, const void* data); // Take care not to free the data before the variant.
+
 /* DataValue - Part: 6, Chapter: 5.2.2.17, Page: 23 */
 typedef struct UA_DataValue {
 	UA_Byte encodingMask;
@@ -398,10 +452,9 @@ typedef struct UA_DataValue {
 UA_TYPE_METHOD_PROTOTYPES(UA_DataValue)
 
 /** 62541-6, §5.2.2.17, Table 15 */
-enum UA_DATAVALUE_ENCODINGMASKTYPE_enum
-{
-	UA_DATAVALUE_ENCODINGMASK_VARIANT = 	0x01,
-	UA_DATAVALUE_ENCODINGMASK_STATUSCODE = 	0x02,
+enum UA_DATAVALUE_ENCODINGMASKTYPE_enum {
+	UA_DATAVALUE_ENCODINGMASK_VARIANT = 	        0x01,
+	UA_DATAVALUE_ENCODINGMASK_STATUSCODE = 	        0x02,
 	UA_DATAVALUE_ENCODINGMASK_SOURCETIMESTAMP = 	0x04,
 	UA_DATAVALUE_ENCODINGMASK_SERVERTIMESTAMP = 	0x08,
 	UA_DATAVALUE_ENCODINGMASK_SOURCEPICOSECONDS = 	0x10,
@@ -421,14 +474,13 @@ typedef struct UA_DiagnosticInfo {
 } UA_DiagnosticInfo;
 UA_TYPE_METHOD_PROTOTYPES(UA_DiagnosticInfo)
 
-enum UA_DIAGNOSTICINFO_ENCODINGMASKTYPE_enum
-{
-	UA_DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID = 			0x01,
-	UA_DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE = 			0x02,
-	UA_DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT = 		0x04,
-	UA_DIAGNOSTICINFO_ENCODINGMASK_LOCALE = 				0x08,
-	UA_DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO = 		0x10,
-	UA_DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE = 	0x20,
+enum UA_DIAGNOSTICINFO_ENCODINGMASKTYPE_enum {
+	UA_DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID = 		 0x01,
+	UA_DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE = 		     0x02,
+	UA_DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT = 	     0x04,
+	UA_DIAGNOSTICINFO_ENCODINGMASK_LOCALE = 			 0x08,
+	UA_DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO =      0x10,
+	UA_DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE =     0x20,
 	UA_DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO = 0x40
 };
 

+ 24 - 4
include/ua_list.h

@@ -2,10 +2,30 @@
 #define UA_LIST_H_
 
 #include "opcua.h"
-
-/*
- * Double Linked Lists
- */
+#include <stddef.h> /* Needed for sys/queue.h */
+#include <sys/queue.h>
+
+
+/**********************/
+/* Singly Linked List */
+/**********************/
+
+#define UA_SLIST_HEAD(name, type) SLIST_HEAD(name, type)
+#define UA_SLIST_HEAD_INITIALIZER(head) SLIST_HEAD_INITILIZER(head)
+#define UA_SLIST_ENTRY(type) SLIST_ENTRY(type)
+#define UA_SLIST_INIT(head) SLIST_INIT(head)
+#define UA_SLIST_INSERT_AFTER(slistelm, elm, field) SLIST_INSERT_AFTER(slistelm, elm, field)
+#define UA_SLIST_INSERT_HEAD(head, elm, field) SLIST_INSERT_HEAD(head, elm, field)
+#define UA_SLIST_REMOVE_HEAD(head, field) SLIST_REMOVE_HEAD(head, field)
+#define UA_SLIST_REMOVE(head, elm, type, field) SLIST_REMOVE(head, elm, type, field)
+#define UA_SLIST_FOREACH(var, head, field) SLIST_FOREACH(var, head, field)
+#define UA_SLIST_EMPTY(head) SLIST_EMPTY(head)
+#define UA_SLIST_FIRST(head) SLIST_FIRST(head)
+#define UA_SLIST_NEXT(elm, field) SLIST_NEXT(elm, field)
+
+/**********************/
+/* Doubly Linked List */
+/**********************/
 
 typedef void (*UA_list_PayloadVisitor)(void* payload);
 

+ 17 - 72
src/Makefile.am

@@ -1,78 +1,24 @@
-#optimization levels depending on debug
 AM_CFLAGS = $(GLOBAL_AM_CFLAGS) -I$(top_builddir)/include -I$(top_builddir)/src -I. -I$(top_builddir)/src/util
-
-
 TOOL_DIR = ../tools
-#__top_builddir__bin_stackTest_out_SOURCES =	opcuaServer.c\
-#											opcua_builtInDatatypes.c\
-#											opcua_binaryEncDec.c\
-#											ua_transportLayer.c\
-#											opcua_builtInDatatypes.h\
-#											opcua_binaryEncDec.h\
-#											ua_transportLayer.h\
-#											opcua_advancedDatatypes.h\
-#											opcua_types.h\
-#											opcua_connectionHelper.h\
-#											tcp_layer.h
-
-#lib_LTLIBRARIES = libstack.la
-#libstack_la_SOURCES = ua_transportLayer.c\
-#					  ua_transportLayer.h\
-#					  opcua_advancedDatatypes.h\
-#					  opcua_connectionHelper.h	
 lib_LTLIBRARIES = libopen62541.la
 libopen62541_la_LDFLAGS = -avoid-version -no-undefined
-#libopen62541_la_SOURCES = 			opcua.c\
-#						ua_basictypes.c\
-#						ua_namespace_0.c\
-#						ua_transportLayer.c\
-#						ua_secureLayer.c\
-#						tcp_layer.c\
-#						ua_transportLayer.h\
-#						opcua_connectionHelper.h\
-#						opcua_encodingLayer.h\
-#						ua_secureLayer.h\
-#						tcp_layer.h\
-#						util/ua_list.c\
-#						util/ua_indexedList.c\
-#						ua_stackInternalTypes.c\
-#						ua_namespace.h\
-#						ua_namespace.c
-
-#libopen62541_ladir = $(top_builddir)/include . $(top_builddir)/src . $(top_builddir)/src/util					
-
-#libopen62541_la_HEADERS = opcua.h\
-#						ua_basictypes.h\
-#						ua_namespace.h\
-#						ua_transportLayer.h\
-#						opcua_connectionHelper.h\
-#						opcua_encodingLayer.h\
-#						ua_secureLayer.h\
-#						ua_namespace.h\
-#						ua_connection.h\
-#						ua_stackInternalTypes.h\
-#						ua_list.h\
-#						ua_indexedList.h
-
-libopen62541_la_SOURCES = opcua.c\
-						ua_basictypes.c\
-						ua_namespace_0.c\
-						util/ua_list.c\
-						util/ua_indexedList.c\
-						ua_transport.c\
-						ua_transport_binary.c\
-						ua_transport_binary_secure.c\
-						ua_namespace.c\
-						ua_services_attribute.c\
-						ua_services_session.c\
-						ua_services_discovery.c\
-						ua_services_securechannel.c\
-						ua_services_view.c\
-						ua_application.c
-
-#bin_PROGRAMS= $(top_builddir)/bin/open62541.out
-#__top_builddir__bin_libOpen62541_out_SOURCES = opcuaServer.c
-#libOpen62541_la_LIBADD = ../lib/libOpen62541.la		  										
+libopen62541_la_SOURCES = opcua.c \
+						  ua_basictypes.c \
+						  ua_namespace_0.c \
+						  util/ua_list.c \
+						  util/ua_indexedList.c \
+						  ua_transport.c \
+						  ua_transport_binary.c \
+						  ua_transport_binary_secure.c \
+						  ua_namespace.c \
+						  ua_services_attribute.c \
+						  ua_services_session.c \
+						  ua_services_discovery.c \
+						  ua_services_securechannel.c \
+						  ua_services_nodemanagement.c \
+						  ua_services_view.c \
+						  ua_application.c \
+						  ua_xml.c
 
 .PHONY: convenience-link clean-convenience-link
 
@@ -99,4 +45,3 @@ clean-convenience-link:
 all-local: convenience-link
 
 clean-local: clean-convenience-link
-

+ 3 - 6
src/ua_application.c

@@ -27,15 +27,12 @@ UA_Node* create_node_ns0(UA_Int32 class, UA_Int32 nodeClass, UA_Int32 const id,
 #define C2UA_STRING(s) (UA_String) { sizeof(s)-1, (UA_Byte*) s }
 void appMockup_init() {
 	// create namespaces
+	// TODO: A table that maps the namespaceUris to Ids
 	Namespace* ns0;
-	Namespace_create(&ns0,100);
-	ns0->namespaceId = 0;
-	ns0->namespaceUri = C2UA_STRING("http://opcfoundation.org/UA/");
+	Namespace_new(&ns0, 100, 0); //C2UA_STRING("http://opcfoundation.org/UA/"));
 
 	Namespace* local;
-	Namespace_create(&local,100);
-	local->namespaceId = 1;
-	local->namespaceUri = C2UA_STRING("http://localhost:16664/open62541/");
+	Namespace_new(&local, 100, 1); //C2UA_STRING("http://localhost:16664/open62541/"));
 
 	// add to list of namespaces
 	UA_indexedList_init(appMockup.namespaces);

+ 129 - 15
src/ua_basictypes.c

@@ -8,7 +8,7 @@
 
 static inline UA_Int32 UA_VTable_isValidType(UA_Int32 type) {
 	if(type < 0 /* UA_BOOLEAN */ || type > 271 /* UA_INVALID */)
-		return UA_ERROR;
+		return UA_ERR_INVALID_VALUE;
 	return UA_SUCCESS;
 }
 
@@ -188,6 +188,26 @@ UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(UA_Boolean)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Boolean)
 UA_TYPE_METHOD_COPY(UA_Boolean)
 
+UA_Int32 UA_Boolean_copycstring(cstring src, UA_Boolean* dst) {
+	*dst = UA_FALSE;
+	if (0 == strncmp(src, "true", 4) || 0 == strncmp(src, "TRUE", 4)) {
+		*dst = UA_TRUE;
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_Boolean_decodeXML(XML_Stack* s, XML_Attr* attr, UA_Boolean* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_Boolean entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_Boolean_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		UA_Boolean_copycstring((cstring) attr[1], dst);
+	}
+	return UA_SUCCESS;
+}
+
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_Byte)
 UA_TYPE_START_ENCODEBINARY(UA_Byte)
 	dst->data[(*pos)++] = *src;
@@ -201,6 +221,8 @@ UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(UA_Byte)
 UA_TYPE_METHOD_INIT_DEFAULT(UA_Byte)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Byte)
 UA_TYPE_METHOD_COPY(UA_Byte)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Byte)
+
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_SByte)
 UA_TYPE_START_ENCODEBINARY(UA_SByte)
 	dst->data[(*pos)++] = *src;
@@ -213,6 +235,7 @@ UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(UA_SByte)
 UA_TYPE_METHOD_INIT_DEFAULT(UA_SByte)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_SByte)
 UA_TYPE_METHOD_COPY(UA_SByte)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_SByte)
 
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_UInt16)
 UA_TYPE_START_ENCODEBINARY(UA_UInt16)
@@ -228,6 +251,7 @@ UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(UA_UInt16)
 UA_TYPE_METHOD_INIT_DEFAULT(UA_UInt16)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_UInt16)
 UA_TYPE_METHOD_COPY(UA_UInt16)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_UInt16)
 
 /** UA_Int16 - signed integer, 2 bytes */
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_Int16)
@@ -281,6 +305,7 @@ UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(UA_UInt32)
 UA_TYPE_METHOD_INIT_DEFAULT(UA_UInt32)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_UInt32)
 UA_TYPE_METHOD_COPY(UA_UInt32)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_UInt32)
 
 /** UA_Int64 - signed integer, 8 bytes */
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_Int64)
@@ -309,6 +334,7 @@ UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(UA_Int64)
 UA_TYPE_METHOD_INIT_DEFAULT(UA_Int64)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Int64)
 UA_TYPE_METHOD_COPY(UA_Int64)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Int64)
 
 /** UA_UInt64 - unsigned integer, 8 bytes */
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_UInt64)
@@ -331,6 +357,7 @@ UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(UA_UInt64)
 UA_TYPE_METHOD_INIT_DEFAULT(UA_UInt64)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_UInt64)
 UA_TYPE_METHOD_COPY(UA_UInt64)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_UInt64)
 
 /** UA_Float - IEE754 32bit float with biased exponent */
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_Float)
@@ -368,8 +395,9 @@ UA_Int32 UA_Float_init(UA_Float * p){
 }
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Float)
 UA_TYPE_METHOD_COPY(UA_Float)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Float)
 
-/** UA_Float - IEEE754 64bit float with biased exponent*/
+/** UA_Double - IEEE754 64bit float with biased exponent*/
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_Double)
 // FIXME: Implement NaN, Inf and Zero(s)
 UA_Byte UA_DOUBLE_ZERO[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
@@ -408,6 +436,7 @@ UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(UA_Double)
 UA_TYPE_METHOD_INIT_DEFAULT(UA_Double)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Double)
 UA_TYPE_METHOD_COPY(UA_Double)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Double)
 
 /** UA_String */
 UA_Int32 UA_String_calcSize(UA_String const * string) {
@@ -637,7 +666,7 @@ UA_Int32 UA_Guid_compare(const UA_Guid *g1, const UA_Guid *g2) {
 	return memcmp(g1, g2, sizeof(UA_Guid));
 }
 
-UA_Int32 UA_Guid_init(UA_Guid* p){
+UA_Int32 UA_Guid_init(UA_Guid* p) {
 	if(p==UA_NULL)return UA_ERROR;
 	p->data1 = 0;
 	p->data2 = 0;
@@ -645,14 +674,17 @@ UA_Int32 UA_Guid_init(UA_Guid* p){
 	memset(p->data4,8,sizeof(UA_Byte));
 	return UA_SUCCESS;
 }
+
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Guid)
-UA_Int32 UA_Guid_copy(UA_Guid const *src, UA_Guid *dst)
-{
+
+UA_Int32 UA_Guid_copy(UA_Guid const *src, UA_Guid *dst) {
 	UA_Int32 retval = UA_SUCCESS;
 	retval |= UA_alloc((void**)&dst,UA_Guid_calcSize(UA_NULL));
 	retval |= UA_memcpy((void*)dst,(void*)src,UA_Guid_calcSize(UA_NULL));
 	return retval;
 }
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Guid)
+
 UA_Int32 UA_LocalizedText_calcSize(UA_LocalizedText const * p) {
 	UA_Int32 length = 0;
 	if (p==UA_NULL) {
@@ -920,6 +952,7 @@ UA_Int32 UA_NodeId_compare(const UA_NodeId *n1, const UA_NodeId *n2) {
 	}
 	return UA_NOT_EQUAL;
 }
+
 UA_Int32 UA_NodeId_init(UA_NodeId* p){
 	if(p==UA_NULL)return UA_ERROR;
 	p->encodingByte = UA_NODEIDTYPE_TWOBYTE;
@@ -927,6 +960,7 @@ UA_Int32 UA_NodeId_init(UA_NodeId* p){
 	memset(&(p->identifier),0,sizeof(p->identifier));
 	return UA_SUCCESS;
 }
+
 UA_TYPE_METHOD_NEW_DEFAULT(UA_NodeId)
 UA_Int32 UA_NodeId_copy(UA_NodeId const *src, UA_NodeId *dst)
 {
@@ -953,14 +987,39 @@ UA_Int32 UA_NodeId_copy(UA_NodeId const *src, UA_NodeId *dst)
 	}
 	return retval;
 }
+
+UA_Boolean UA_NodeId_isNull(const UA_NodeId* p) {
+	switch (p->encodingByte & UA_NODEIDTYPE_MASK) {
+	case UA_NODEIDTYPE_TWOBYTE:
+		if(p->identifier.numeric != 0) return UA_FALSE;
+		break;
+	case UA_NODEIDTYPE_FOURBYTE:
+	case UA_NODEIDTYPE_NUMERIC:
+		if(p->namespace != 0 || p->identifier.numeric != 0) return UA_FALSE;
+		break;
+	case UA_NODEIDTYPE_STRING:
+		if(p->namespace != 0 || p->identifier.string.length != 0) return UA_FALSE;
+		break;
+	case UA_NODEIDTYPE_GUID:
+		if(p->namespace != 0 || memcmp(&p->identifier.guid, (char[sizeof(UA_Guid)]){0}, sizeof(UA_Guid)) != 0) return UA_FALSE;
+		break;
+	case UA_NODEIDTYPE_BYTESTRING:
+		if(p->namespace != 0 || p->identifier.byteString.length != 0) return UA_FALSE;
+		break;
+	default:
+		return UA_FALSE;
+	}
+	return UA_TRUE;
+}
+
 UA_Int32 UA_ExpandedNodeId_calcSize(UA_ExpandedNodeId const * p) {
 	UA_Int32 length = 0;
 	if (p == UA_NULL) {
 		length = sizeof(UA_ExpandedNodeId);
 	} else {
-		length = UA_NodeId_calcSize(&(p->nodeId));
+		length = UA_NodeId_calcSize(&p->nodeId);
 		if (p->nodeId.encodingByte & UA_NODEIDTYPE_NAMESPACE_URI_FLAG) {
-			length += UA_String_calcSize(&(p->namespaceUri)); //p->namespaceUri
+			length += UA_String_calcSize(&p->namespaceUri); //p->namespaceUri
 		}
 		if (p->nodeId.encodingByte & UA_NODEIDTYPE_SERVERINDEX_FLAG) {
 			length += sizeof(UA_UInt32); //p->serverIndex
@@ -968,6 +1027,7 @@ UA_Int32 UA_ExpandedNodeId_calcSize(UA_ExpandedNodeId const * p) {
 	}
 	return length;
 }
+
 UA_TYPE_START_ENCODEBINARY(UA_ExpandedNodeId)
 	retval |= UA_NodeId_encodeBinary(&(src->nodeId),pos,dst);
 	if (src->nodeId.encodingByte & UA_NODEIDTYPE_NAMESPACE_URI_FLAG) {
@@ -1017,6 +1077,10 @@ UA_Int32 UA_ExpandedNodeId_copy(UA_ExpandedNodeId const *src, UA_ExpandedNodeId
 	return retval;
 }
 
+UA_Boolean UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId* p) {
+	return UA_NodeId_isNull(&p->nodeId);
+}
+
 UA_Int32 UA_ExtensionObject_calcSize(UA_ExtensionObject const * p) {
 	UA_Int32 length = 0;
 	if (p == UA_NULL) {
@@ -1043,8 +1107,11 @@ UA_TYPE_START_ENCODEBINARY(UA_ExtensionObject)
 	case UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED:
 		break;
 	case UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING:
+		// FIXME: This code is valid for numeric nodeIds in ns0 only!
+		retval |= UA_[UA_ns0ToVTableIndex(src->typeId.identifier.numeric)].encodeBinary(src->body.data,pos,dst);
+		break;
 	case UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISXML:
-		retval |= UA_ByteString_encodeBinary(&(src->body),pos,dst);
+		perror("UA_ExtensionObject_encodeBinary - requested encoding of body as XML not yet supported!");
 		break;
 	}
 UA_TYPE_END_XXCODEBINARY
@@ -1239,7 +1306,10 @@ UA_Int32 UA_DiagnosticInfo_copy(UA_DiagnosticInfo const  *src, UA_DiagnosticInfo
 
 	return retval;
 }
-UA_TYPE_METHOD_PROTOTYPES_AS(UA_DateTime,UA_Int64)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_DiagnosticInfo)
+
+UA_TYPE_METHOD_PROTOTYPES_AS_WOXML(UA_DateTime,UA_Int64)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_DateTime)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_DateTime)
 
 #include <sys/time.h>
@@ -1305,15 +1375,19 @@ UA_TYPE_METHOD_NEW_DEFAULT(UA_XmlElement)
 UA_TYPE_METHOD_PROTOTYPES_AS(UA_IntegerId, UA_Int32)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_IntegerId)
 
-UA_TYPE_METHOD_PROTOTYPES_AS(UA_StatusCode, UA_UInt32)
+UA_TYPE_METHOD_PROTOTYPES_AS_WOXML(UA_StatusCode, UA_UInt32)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_StatusCode)
+UA_Int32 UA_StatusCode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_StatusCode* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_StatusCode_decodeXML entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	return UA_ERR_NOT_IMPLEMENTED;
+}
 
 /** QualifiedName - Part 4, Chapter
  * but see Part 6, Chapter 5.2.2.13 for Binary Encoding
  */
 UA_Int32 UA_QualifiedName_calcSize(UA_QualifiedName const * p) {
 	UA_Int32 length = 0;
-	if (p == NULL) return sizeof(UA_QualifiedName);
+	if (p == UA_NULL) return sizeof(UA_QualifiedName);
 	length += sizeof(UA_UInt16); //qualifiedName->namespaceIndex
 	// length += sizeof(UA_UInt16); //qualifiedName->reserved
 	length += UA_String_calcSize(&(p->name)); //qualifiedName->name
@@ -1347,7 +1421,7 @@ UA_Int32 UA_QualifiedName_init(UA_QualifiedName * p){
 	if(p==UA_NULL)return UA_ERROR;
 	UA_String_init(&(p->name));
 	p->namespaceIndex=0;
-	p->reserved=0;
+	//p->reserved=0;
 	return UA_SUCCESS;
 }
 UA_TYPE_METHOD_NEW_DEFAULT(UA_QualifiedName)
@@ -1357,7 +1431,7 @@ UA_Int32 UA_QualifiedName_copy(UA_QualifiedName const *src, UA_QualifiedName *ds
 	retval |= UA_alloc((void**)&dst,UA_QualifiedName_calcSize(UA_NULL));
 	retval |= UA_String_copy(&(src->name),&(dst->name));
 	retval |= UA_UInt16_copy(&(src->namespaceIndex),&(dst->namespaceIndex));
-	retval |= UA_UInt16_copy(&(src->reserved),&(dst->reserved));
+	//retval |= UA_UInt16_copy(&(src->reserved),&(dst->reserved));
 	return retval;
 
 }
@@ -1365,12 +1439,12 @@ UA_Int32 UA_QualifiedName_copy(UA_QualifiedName const *src, UA_QualifiedName *ds
 UA_Int32 UA_Variant_calcSize(UA_Variant const * p) {
 	UA_Int32 length = 0;
 	if (p == UA_NULL) return sizeof(UA_Variant);
-	UA_UInt32 ns0Id = p->encodingMask & 0x1F; // Bits 1-5
+	UA_UInt32 builtinNs0Id = p->encodingMask & 0x3F; // Bits 0-5
 	UA_Boolean isArray = p->encodingMask & (0x01 << 7); // Bit 7
 	UA_Boolean hasDimensions = p->encodingMask & (0x01 << 6); // Bit 6
 	UA_Int32 i;
 
-	if (p->vt == UA_NULL || ns0Id != p->vt->ns0Id) {
+	if (p->vt == UA_NULL || builtinNs0Id != p->vt->ns0Id) {
 		return UA_ERR_INCONSISTENT;
 	}
 	length += sizeof(UA_Byte); //p->encodingMask
@@ -1529,6 +1603,43 @@ UA_Int32 UA_Variant_copy(UA_Variant const *src, UA_Variant *dst)
 	return retval;
 }
 
+UA_Int32 UA_Variant_borrowSetValue(UA_Variant *v, UA_Int32 type_id, const void* value) {
+	v->encodingMask = type_id & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK;
+	if(UA_VTable_isValidType(type_id) != UA_SUCCESS) return UA_INVALIDTYPE;
+	v->vt = &UA_noDelete_[type_id];
+	v->data = (void*) value;
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_Variant_copySetValue(UA_Variant *v, UA_Int32 type_id, const void* value) {
+	v->encodingMask = type_id & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK;
+	if(UA_VTable_isValidType(type_id) != UA_SUCCESS) return UA_INVALIDTYPE;
+	v->vt = &UA_[type_id];
+	return v->vt->copy(value, v->data);
+}
+
+UA_Int32 UA_Variant_borrowSetArray(UA_Variant *v, UA_Int32 type_id, UA_Int32 arrayLength, const void* array) {
+	v->encodingMask = (type_id & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) | UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
+	if(UA_VTable_isValidType(type_id) != UA_SUCCESS) return UA_INVALIDTYPE;
+	v->vt = &UA_noDelete_[type_id];
+	v->arrayLength = arrayLength;
+	v->data = (void*) array;
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_Variant_copySetArray(UA_Variant *v, UA_Int32 type_id, UA_Int32 arrayLength, UA_UInt32 elementSize, const void* array) {
+	v->encodingMask = (type_id & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) | UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
+	if(UA_VTable_isValidType(type_id) != UA_SUCCESS) return UA_INVALIDTYPE;
+	v->vt = &UA_[type_id];
+	v->arrayLength = arrayLength;
+	void *new_arr;
+	UA_Int32 retval = UA_SUCCESS;
+	retval |= UA_alloc(&new_arr, arrayLength * elementSize);
+	retval |= UA_memcpy(new_arr, array, arrayLength * elementSize);
+	v->data = new_arr;
+	return UA_SUCCESS;
+}
+
 //TODO: place this define at the server configuration
 #define MAX_PICO_SECONDS 1000
 UA_Int32 UA_DataValue_decodeBinary(UA_ByteString const * src, UA_Int32* pos, UA_DataValue* dst) {
@@ -1644,6 +1755,8 @@ UA_Int32 UA_DataValue_copy(UA_DataValue const *src, UA_DataValue *dst){
 
 	return retval;
 }
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_DataValue)
+
 /* UA_InvalidType - internal type necessary to handle inited Variants correctly */
 UA_Int32 UA_InvalidType_calcSize(UA_InvalidType const * p) {
 	return 0;
@@ -1673,3 +1786,4 @@ UA_Int32 UA_InvalidType_copy(UA_InvalidType const* src, UA_InvalidType *dst) {
 UA_Int32 UA_InvalidType_new(UA_InvalidType** p) {
 	return UA_ERR_INVALID_VALUE;
 }
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_InvalidType)

+ 108 - 155
src/ua_namespace.c

@@ -6,15 +6,24 @@
 /* Internal (not exported) functionality */
 /*****************************************/
 
-UA_Int32 Namespace_TransactionContext_init(Namespace_TransactionContext * tc) {
-	return UA_list_init((UA_list_List *) tc);
-}
+struct Namespace_Entry {
+	UA_UInt64 status;	/* 2 bits status | 14 bits checkout count | 48 bits timestamp */
+	const UA_Node *node;	/* Nodes are immutable. It is not recommended to change nodes in place */
+};
+
+struct Namespace_Entry_Lock {
+	Namespace_Entry *entry;
+};
+
+/* The tombstone (entry.node == 0x01) indicates that an entry was deleted at the position in the
+   hash-map. This is information is used to decide whether the entire table shall be rehashed so
+   that entries are found faster. */
+#define ENTRY_EMPTY UA_NULL
+#define ENTRY_TOMBSTONE 0x01
 
 /* The central data structure is a hash-map of UA_Node objects. Entry lookup via Algorithm D from
    Knuth's TAOCP (no linked lists here). Table of primes and mod-functions are from libiberty
-   (licensed under LGPL) */
-
-typedef UA_UInt32 hash_t;
+   (licensed under LGPL) */ typedef UA_UInt32 hash_t;
 struct prime_ent {
 	hash_t prime;
 	hash_t inv;
@@ -183,105 +192,80 @@ static inline hash_t mod_m2(hash_t h, const Namespace * ns) {
 	return 1 + mod_1(h, p->prime - 2, p->inv_m2, p->shift);
 }
 
-static inline void clear_slot(Namespace * ns, Namespace_Entry * slot) {
-	if(slot->node == UA_NULL)
+static inline void clear_entry(Namespace * ns, Namespace_Entry * entry) {
+	if(entry->node == UA_NULL)
 		return;
 
-#ifdef MULTITHREADING
-	pthread_rwlock_wrlock((pthread_rwlock_t *) slot->lock);	/* Get write lock. */
-#endif
-
-	switch (slot->node->nodeClass) {
+	switch (entry->node->nodeClass) {
 	case UA_NODECLASS_OBJECT:
-		UA_ObjectNode_delete((UA_ObjectNode *) slot->node);
+		UA_ObjectNode_delete((UA_ObjectNode *) entry->node);
 		break;
 	case UA_NODECLASS_VARIABLE:
-		UA_VariableNode_delete((UA_VariableNode *) slot->node);
+		UA_VariableNode_delete((UA_VariableNode *) entry->node);
 		break;
 	case UA_NODECLASS_METHOD:
-		UA_MethodNode_delete((UA_MethodNode *) slot->node);
+		UA_MethodNode_delete((UA_MethodNode *) entry->node);
 		break;
 	case UA_NODECLASS_OBJECTTYPE:
-		UA_ObjectTypeNode_delete((UA_ObjectTypeNode *) slot->node);
+		UA_ObjectTypeNode_delete((UA_ObjectTypeNode *) entry->node);
 		break;
 	case UA_NODECLASS_VARIABLETYPE:
-		UA_VariableTypeNode_delete((UA_VariableTypeNode *) slot->node);
+		UA_VariableTypeNode_delete((UA_VariableTypeNode *) entry->node);
 		break;
 	case UA_NODECLASS_REFERENCETYPE:
-		UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *) slot->node);
+		UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *) entry->node);
 		break;
 	case UA_NODECLASS_DATATYPE:
-		UA_DataTypeNode_delete((UA_DataTypeNode *) slot->node);
+		UA_DataTypeNode_delete((UA_DataTypeNode *) entry->node);
 		break;
 	case UA_NODECLASS_VIEW:
-		UA_ViewNode_delete((UA_ViewNode *) slot->node);
+		UA_ViewNode_delete((UA_ViewNode *) entry->node);
 		break;
 	default:
 		break;
 	}
-	slot->node = UA_NULL;
-
-#ifdef MULTITHREADING
-	pthread_rwlock_destroy((pthread_rwlock_t *) slot->lock);
-	UA_free(slot->lock);
-#endif
-
+	entry->node = UA_NULL;
 }
 
-static inline UA_Int32 find_slot(const Namespace * ns, Namespace_Entry ** slot, const UA_NodeId * nodeid) {
+/* Returns UA_SUCCESS if an entry was found. Otherwise, UA_ERROR is returned and the "entry"
+   argument points to the first free entry under the NodeId. */
+static inline UA_Int32 find_entry(const Namespace * ns, const UA_NodeId * nodeid, Namespace_Entry ** entry) {
 	hash_t h = hash(nodeid);
-	hash_t index, hash2;
-	UA_UInt32 size;
-	Namespace_Entry *entry;
-
-	size = ns->size;
-	index = mod(h, ns);
+	hash_t index = mod(h, ns);
+	UA_UInt32 size = ns->size;
+	Namespace_Entry *e = &ns->entries[index];
 
-	entry = &ns->entries[index];
-	if(entry == UA_NULL)
+	if(e->node == UA_NULL) {
+		*entry = e;
 		return UA_ERROR;
-	if(UA_NodeId_compare(&entry->node->nodeId, nodeid) == UA_EQUAL) {
-		*slot = entry;
+	}
+
+	if(UA_NodeId_compare(&e->node->nodeId, nodeid) == UA_EQUAL) {
+		*entry = e;
 		return UA_SUCCESS;
 	}
 
-	hash2 = mod_m2(h, ns);
+	hash_t hash2 = mod_m2(h, ns);
 	for(;;) {
 		index += hash2;
 		if(index >= size)
 			index -= size;
 
-		entry = &ns->entries[index];
-		if(entry == UA_NULL)
+		e = &ns->entries[index];
+
+		if(e->node == UA_NULL) {
+			*entry = e;
 			return UA_ERROR;
-		if(UA_NodeId_compare(&entry->node->nodeId, nodeid) == UA_EQUAL) {
-			*slot = entry;
+		}
+
+		if(UA_NodeId_compare(&e->node->nodeId, nodeid) == UA_EQUAL) {
+			*entry = e;
 			return UA_SUCCESS;
 		}
 	}
-	return UA_SUCCESS;
-}
-
-/* Always returns an empty slot. This is inevitable if the entries are not completely full. */
-static Namespace_Entry *find_empty_slot(const Namespace * ns, hash_t h) {
-	hash_t index = mod(h, ns);
-	UA_UInt32 size = ns->size;
-	Namespace_Entry *slot = &ns->entries[index];
-
-	if(slot->node == UA_NULL)
-		return slot;
 
-	hash_t hash2 = mod_m2(h, ns);
-	for(;;) {
-		index += hash2;
-		if(index >= size)
-			index -= size;
-
-		slot = &ns->entries[index];
-		if(slot->node == UA_NULL)
-			return slot;
-	}
-	return UA_NULL;
+	/* NOTREACHED */
+	return UA_SUCCESS;
 }
 
 /* The following function changes size of memory allocated for the entries and repeatedly inserts
@@ -316,8 +300,9 @@ static UA_Int32 expand(Namespace * ns) {
 	Namespace_Entry *p = oentries;
 	do {
 		if(p->node != UA_NULL) {
-			Namespace_Entry *q = find_empty_slot(ns, hash(&p->node->nodeId));
-			*q = *p;
+			Namespace_Entry *e;
+			find_entry(ns, &p->node->nodeId, &e);	/* We know this returns an empty entry here */
+			*e = *p;
 		}
 		p++;
 	} while(p < olimit);
@@ -330,29 +315,23 @@ static UA_Int32 expand(Namespace * ns) {
 /* Exported functions */
 /**********************/
 
-UA_Int32 Namespace_create(Namespace ** result, UA_UInt32 size) {
-	Namespace *ns = UA_NULL;
-	UA_UInt32 sizePrimeIndex = higher_prime_index(size);
-	size = prime_tab[sizePrimeIndex].prime;
-
+UA_Int32 Namespace_new(Namespace ** result, UA_UInt32 size, UA_UInt32 namespaceId) {
+	Namespace *ns;
 	if(UA_alloc((void **)&ns, sizeof(Namespace)) != UA_SUCCESS)
 		return UA_ERR_NO_MEMORY;
 
+	UA_UInt32 sizePrimeIndex = higher_prime_index(size);
+	size = prime_tab[sizePrimeIndex].prime;
 	if(UA_alloc((void **)&ns->entries, sizeof(Namespace_Entry) * size) != UA_SUCCESS) {
 		UA_free(ns);
 		return UA_ERR_NO_MEMORY;
 	}
 
-	/**
-	   set entries to zero:
-	   ns->entries[i].lock = UA_NUll;
-	   ns->entries[i].node = UA_NULL;
-	*/
+	/* set entries to zero */
 	memset(ns->entries, 0, size * sizeof(Namespace_Entry));
 
-	ns->size = size;
-	ns->count = 0;
-	ns->sizePrimeIndex = sizePrimeIndex;
+	*ns = (Namespace) {
+	namespaceId, ns->entries, size, 0, sizePrimeIndex};
 	*result = ns;
 	return UA_SUCCESS;
 }
@@ -361,7 +340,7 @@ static void Namespace_clear(Namespace * ns) {
 	UA_UInt32 size = ns->size;
 	Namespace_Entry *entries = ns->entries;
 	for(UA_UInt32 i = 0; i < size; i++)
-		clear_slot(ns, &entries[i]);
+		clear_entry(ns, &entries[i]);
 	ns->count = 0;
 }
 
@@ -386,110 +365,80 @@ void Namespace_delete(Namespace * ns) {
 	UA_free(ns);
 }
 
-UA_Int32 Namespace_insert(Namespace * ns, UA_Node * node) {
+UA_Int32 Namespace_insert(Namespace * ns, const UA_Node * node) {
 	if(ns->size * 3 <= ns->count * 4) {
 		if(expand(ns) != UA_SUCCESS)
 			return UA_ERROR;
 	}
 
-	hash_t h = hash(&node->nodeId);
-	Namespace_Entry *slot = find_empty_slot(ns, h);
+	Namespace_Entry *entry;
+	UA_Int32 found = find_entry(ns, &node->nodeId, &entry);
 
-#ifdef MULTITHREADING
-	if(UA_alloc((void **)&slot->lock, sizeof(pthread_rwlock_t)) != UA_SUCCESS)
-		return UA_ERR_NO_MEMORY;
-	pthread_rwlock_init((pthread_rwlock_t *) slot->lock, NULL);
-#endif
+	if(found == UA_SUCCESS)
+		return UA_ERROR;	/* There is already an entry for that nodeid */
 
-	slot->node = node;
+	entry->node = node;
 	ns->count++;
 	return UA_SUCCESS;
 }
 
-UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, UA_Node const **result, Namespace_Lock ** lock) {
-	Namespace_Entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return UA_ERROR;
-
-#ifdef MULTITHREADING
-	if(pthread_rwlock_rdlock((pthread_rwlock_t *) slot->lock) != 0)
-		return UA_ERROR;
-	*lock = slot->lock;
-#endif
-
-	*result = slot->node;
-	return UA_SUCCESS;
-}
+UA_Int32 Namespace_insertUnique(Namespace * ns, UA_Node * node) {
+	if(ns->size * 3 <= ns->count * 4) {
+		if(expand(ns) != UA_SUCCESS)
+			return UA_ERROR;
+	}
+	// find unoccupied numeric nodeid
+	node->nodeId.namespace = ns->namespaceId;
+	node->nodeId.encodingByte = UA_NODEIDTYPE_NUMERIC;
+	node->nodeId.identifier.numeric = ns->count;
 
-UA_Int32 Namespace_getWritable(const Namespace * ns, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock) {
-	Namespace_Entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return UA_ERROR;
+	hash_t h = hash(&node->nodeId);
+	hash_t hash2 = mod_m2(h, ns);
+	UA_UInt32 size = ns->size;
 
-#ifdef MULTITHREADING
-	if(pthread_rwlock_wrlock((pthread_rwlock_t *) slot->lock) != 0)
-		return UA_ERROR;
-	*lock = slot->lock;
-#endif
+	// advance integer (hash) until a free entry is found
+	Namespace_Entry *entry = UA_NULL;
+	while(1) {
+		if(find_entry(ns, &node->nodeId, &entry) != UA_SUCCESS)
+			break;
+		node->nodeId.identifier.numeric += hash2;
+		if(node->nodeId.identifier.numeric >= size)
+			node->nodeId.identifier.numeric -= size;
+	}
 
-	*result = slot->node;
+	entry->node = node;
+	ns->count++;
 	return UA_SUCCESS;
 }
 
-#ifdef MULTITHREADING
-static inline void release_context_walker(void *lock) {
-	pthread_rwlock_unlock(lock);
+UA_Int32 Namespace_contains(const Namespace * ns, const UA_NodeId * nodeid) {
+	Namespace_Entry *entry;
+	return find_entry(ns, nodeid, &entry);
 }
-#endif
 
-UA_Int32 Namespace_transactionGet(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** const result, Namespace_Lock ** lock) {
-	Namespace_Entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
+UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, const UA_Node **result,
+					   Namespace_Entry_Lock ** lock) {
+	Namespace_Entry *entry;
+	if(find_entry(ns, nodeid, &entry) != UA_SUCCESS)
 		return UA_ERROR;
 
-#ifdef MULTITHREADING
-	if(pthread_rwlock_tryrdlock((pthread_rwlock_t *) slot->lock) != 0) {
-		/* Transaction failed. Release all acquired locks and bail out. */
-		UA_list_destroy((UA_list_List *) tc, release_context_walker);
-		return UA_ERROR;
-	}
-	UA_list_addPayloadToBack((UA_list_List *) tc, slot->lock);
-	*lock = slot->lock;
-#endif
-
-	*result = slot->node;
+	*result = entry->node;
 	return UA_SUCCESS;
 }
 
-UA_Int32 Namespace_transactionGetWritable(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock) {
-	Namespace_Entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
+UA_Int32 Namespace_remove(Namespace * ns, const UA_NodeId * nodeid) {
+	Namespace_Entry *entry;
+	if(find_entry(ns, nodeid, &entry) != UA_SUCCESS)
 		return UA_ERROR;
 
-#ifdef MULTITHREADING
-	if(pthread_rwlock_trywrlock((pthread_rwlock_t *) slot->lock) != 0) {
-		/* Transaction failed. Release all acquired locks and bail out. */
-		UA_list_destroy((UA_list_List *) tc, release_context_walker);
-		return UA_ERROR;
-	}
-	UA_list_addPayloadToBack((UA_list_List *) tc, slot->lock);
-	*lock = slot->lock;
-#endif
-
-	*result = slot->node;
-	return UA_SUCCESS;
-}
-
-void Namespace_remove(Namespace * ns, UA_NodeId * nodeid) {
-	Namespace_Entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return;
 	// TODO: Check if deleting the node makes the Namespace inconsistent.
-	clear_slot(ns, slot);
+	clear_entry(ns, entry);
 
 	/* Downsize the hashmap if it is very empty */
 	if(ns->count * 8 < ns->size && ns->size > 32)
 		expand(ns);
+
+	return UA_SUCCESS;
 }
 
 UA_Int32 Namespace_iterate(const Namespace * ns, Namespace_nodeVisitor visitor) {
@@ -501,3 +450,7 @@ UA_Int32 Namespace_iterate(const Namespace * ns, Namespace_nodeVisitor visitor)
 	}
 	return UA_SUCCESS;
 }
+
+void Namespace_Entry_Lock_release(Namespace_Entry_Lock * lock) {
+	;
+}

+ 32 - 50
src/ua_namespace.h

@@ -9,47 +9,31 @@
 #define _XOPEN_SOURCE 500
 #define __USE_UNIX98
 #include <pthread.h>
-typedef struct pthread_rwlock_t Namespace_Lock;
-#else
-typedef void Namespace_Lock;
 #endif
 
-static inline void Namespace_Lock_release(Namespace_Lock * lock) {
-#ifdef MULTITHREADING
-	pthread_rwlock_unlock((pthread_rwlock_t *) lock);
-#endif
-}
-
-/* Poor-man's transactions: If we need multiple locks and at least one of them is a writelock
-   ("transaction"), a deadlock can be introduced in conjunction with a second thread.
-
-   Convention: All nodes in a transaction (read and write) must be locked before the first write.
-   If one write-lock cannot be acquired immediately, bail out and restart the transaction. A
-   Namespace_TransactionContext is currently only a linked list of the acquired locks. More advanced
-   transaction mechanisms will be established once the runtime behavior can be observed. */
-typedef UA_list_List Namespace_TransactionContext;
-UA_Int32 Namespace_TransactionContext_init(Namespace_TransactionContext * tc);
-
-/* Each namespace is a hash-map of NodeIds to Nodes. Every entry in the hashmap consists of a
-   pointer to a read-write lock and a pointer to the Node. */
-typedef struct Namespace_Entry {
-#ifdef MULTITHREADING
-	Namespace_Lock *lock;	/* locks are heap-allocated */
-#endif
-	UA_Node *node;
-} Namespace_Entry;
+/** @brief Namespace entries point to an UA_Node. But the actual data structure
+	is opaque outside of ua_namespace.c */
+struct Namespace_Entry;
+typedef struct Namespace_Entry Namespace_Entry;
 
+/** @brief Namespace datastructure. It mainly serves as a hashmap to UA_Nodes. */
 typedef struct Namespace {
-	UA_Int32 namespaceId;
-	UA_String namespaceUri;
+	UA_UInt32 namespaceId;
 	Namespace_Entry *entries;
 	UA_UInt32 size;
 	UA_UInt32 count;
 	UA_UInt32 sizePrimeIndex;	/* Current size, as an index into the table of primes.  */
 } Namespace;
 
+/** Namespace locks indicate that a thread currently operates on an entry. */
+struct Namespace_Entry_Lock;
+typedef struct Namespace_Entry_Lock Namespace_Entry_Lock;
+
+/** @brief Release a lock on a namespace entry. */
+void Namespace_Entry_Lock_release(Namespace_Entry_Lock * lock);
+
 /** @brief Create a new namespace */
-UA_Int32 Namespace_create(Namespace ** result, UA_UInt32 size);
+UA_Int32 Namespace_new(Namespace ** result, UA_UInt32 size, UA_UInt32 namespaceId);
 
 /** @brief Delete all nodes in the namespace */
 void Namespace_empty(Namespace * ns);
@@ -57,33 +41,31 @@ void Namespace_empty(Namespace * ns);
 /** @brief Delete the namespace and all nodes in it */
 void Namespace_delete(Namespace * ns);
 
-/** @brief Insert a new node into the namespace */
-UA_Int32 Namespace_insert(Namespace * ns, UA_Node * node);
+/** @brief Insert a new node into the namespace. Abort an entry with the same
+	NodeId is already present */
+UA_Int32 Namespace_insert(Namespace * ns, const UA_Node * node);
+
+/** @brief Insert a new node or replace an existing node if an entry has the same NodeId. */
+UA_Int32 Namespace_insertOrReplace(Namespace * ns, const UA_Node * node);
+
+/** @brief Find an unused (numeric) NodeId in the namespace and insert the node.
+	The node is modified to contain the new nodeid after insertion. */
+UA_Int32 Namespace_insertUnique(Namespace * ns, UA_Node * node);
 
 /** @brief Remove a node from the namespace */
-void Namespace_remove(Namespace * ns, UA_NodeId * nodeid);
+UA_Int32 Namespace_remove(Namespace * ns, const UA_NodeId * nodeid);
+
+/** @brief Tests whether the namespace contains an entry for a given NodeId */
+UA_Int32 Namespace_contains(const Namespace * ns, const UA_NodeId * nodeid);
 
 /** @brief Retrieve a node (read-only) from the namespace. Nodes are identified
 	by their NodeId. After the Node is no longer used, the lock needs to be
 	released. */
-UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, UA_Node const **result, Namespace_Lock ** lock);
-
-/** @brief Retrieve a node (read and write) from the namespace. Nodes are
-	identified by their NodeId. After the Node is no longer used, the lock needs
-	to be released. */
-UA_Int32 Namespace_getWritable(Namespace const *ns, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock);
-
-/** @brief Retrieve a node (read-only) as part of a transaction. If multiples
-	nodes are to be retrieved as part of a transaction, the transaction context
-	needs to be specified. */
-UA_Int32 Namespace_transactionGet(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** const result, Namespace_Lock ** lock);
-
-/** @brief Retrieve a node (read and write) as part of a transaction. If
-	multiples nodes are to be retrieved as part of a transaction, the
-	transaction context needs to be specified. */
-UA_Int32 Namespace_transactionGetWritable(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock);
+UA_Int32 Namespace_get(const Namespace *ns, const UA_NodeId * nodeid, const UA_Node **result,
+					   Namespace_Entry_Lock ** lock);
 
-typedef void (*Namespace_nodeVisitor) (UA_Node const *node);
+/** @brief A function that can be evaluated on all entries in a namespace via Namespace_iterate */
+typedef void (*Namespace_nodeVisitor) (const UA_Node *node);
 
 /** @brief Iterate over all nodes in a namespace */
 UA_Int32 Namespace_iterate(const Namespace * ns, Namespace_nodeVisitor visitor);

+ 28 - 2
src/ua_services.h

@@ -1,3 +1,9 @@
+/**
+ * @file ua_services.h
+ *
+ * @brief Defines the method signatures for all the standard defined services.
+ */
+
 #ifndef UA_SERVICES_H_
 #define UA_SERVICES_H_
 
@@ -5,6 +11,14 @@
 #include "ua_application.h"
 #include "ua_transport_binary_secure.h"
 
+/**
+ * @defgroup services Services
+ *
+ * @brief This module describes all the services used to communicate in in OPC UA.
+ *
+ * @{
+ */
+
 /**
  * @name Discovery Service Set
  *
@@ -90,7 +104,11 @@ UA_Int32 Service_CloseSession(SL_Channel *channel, const UA_CloseSessionRequest
  *
  * @{
  */
-// Service_AddNodes
+
+/**
+ * @brief This Service is used to add one or more Nodes into the AddressSpace hierarchy.
+ */
+UA_Int32 Service_AddNodes(SL_Channel *channel, const UA_AddNodesRequest *request, UA_AddNodesResponse *response);
 // Service_AddReferences
 // Service_DeleteNodes
 // Service_DeleteReferences
@@ -111,12 +129,18 @@ UA_Int32 Service_CloseSession(SL_Channel *channel, const UA_CloseSessionRequest
  * also supports a primitive filtering capability.
  */ 
 UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA_BrowseResponse *response);
+
+/**
+ * @brief This Service is used to translate textual node paths to their respective ids.
+ */
+UA_Int32 Service_TranslateBrowsePathsToNodeIds(SL_Channel *channel, const UA_TranslateBrowsePathsToNodeIdsRequest *request, UA_TranslateBrowsePathsToNodeIdsResponse *response);
 // Service_BrowseNext
-// Service_TranslateBrowsePathsRoNodeIds
+// Service_TranslateBrowsePathsToNodeIds
 // Service_RegisterNodes
 // Service_UnregisterNodes
 /** @} */
 
+
 /* Part 4: 5.9 Query Service Set */
 /**
  * @name Query Service Set
@@ -209,4 +233,6 @@ UA_Int32 Service_CreateMonitoredItems(SL_Channel *channel, const UA_CreateMonito
 // Service_DeleteSubscription
 /** @} */
 
+/** @} */ // end of group
+
 #endif

+ 107 - 85
src/ua_services_attribute.c

@@ -26,163 +26,185 @@ enum UA_AttributeId {
 	UA_ATTRIBUTEID_USEREXECUTABLE = 22
 };
 
-static UA_DataValue * service_read_node(Application *app, const UA_ReadValueId *id) {
-	UA_DataValue *v; UA_DataValue_new(&v);
-	
-	DBG(printf("service_read_node - entered with ns=%d,id=%d,attr=%i\n",id->nodeId.namespace, id->nodeId.identifier.numeric, id->attributeId));
+#define CHECK_NODECLASS(CLASS) do {									\
+		if((node->nodeClass & (CLASS)) != 0x00) {					\
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;		\
+			v->status = UA_STATUSCODE_BADNOTREADABLE;				\
+		}															\
+		break;														\
+	} while(0)
+
+static UA_DataValue *service_read_node(Application * app, const UA_ReadValueId * id) {
+	UA_DataValue *v;
+	UA_DataValue_new(&v);
+
+	DBG(printf("service_read_node - entered with ns=%d,id=%d,attr=%i\n", id->nodeId.namespace, id->nodeId.identifier.numeric, id->attributeId));
 	Namespace *ns = UA_indexedList_findValue(app->namespaces, id->nodeId.namespace);
 
-	if (ns == UA_NULL) {
-		DBG_VERBOSE(printf("service_read_node - unknown namespace %d\n",id->nodeId.namespace));
+	if(ns == UA_NULL) {
+		DBG_VERBOSE(printf("service_read_node - unknown namespace %d\n", id->nodeId.namespace));
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
 		return v;
 	}
-	DBG_VERBOSE(UA_String_printf(",namespaceUri=",&(ns->namespaceUri)));
-	
+	DBG_VERBOSE(UA_String_printf(",namespaceUri=", &(ns->namespaceUri)));
+
 	UA_Node const *node = UA_NULL;
-	Namespace_Lock *lock = UA_NULL;
-	DBG_VERBOSE(UA_NodeId_printf("service_read_node - search for ",&(id->nodeId)));
+	Namespace_Entry_Lock *lock = UA_NULL;
+
+	DBG_VERBOSE(UA_NodeId_printf("service_read_node - search for ", &(id->nodeId)));
 	UA_Int32 result = Namespace_get(ns, &(id->nodeId), &node, &lock);
 	if(result != UA_SUCCESS || node == UA_NULL) {
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
 		return v;
 	}
-	DBG_VERBOSE(UA_NodeId_printf("service_read_node - found node=",&(node->nodeId)));
+	DBG_VERBOSE(UA_NodeId_printf("service_read_node - found node=", &(node->nodeId)));
 
-	switch(id->attributeId) {
+	UA_Int32 retval = UA_SUCCESS;
+
+	switch (id->attributeId) {
 	case UA_ATTRIBUTEID_NODEID:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_NODEID, &node->nodeId);
 		break;
 	case UA_ATTRIBUTEID_NODECLASS:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_UINT32, &node->nodeClass);
 		break;
 	case UA_ATTRIBUTEID_BROWSENAME:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_QUALIFIEDNAME, &node->browseName);
 		break;
 	case UA_ATTRIBUTEID_DISPLAYNAME:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_LOCALIZEDTEXT, &node->displayName);
 		break;
 	case UA_ATTRIBUTEID_DESCRIPTION:
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNOTREADABLE;
 		break;
 	case UA_ATTRIBUTEID_WRITEMASK:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_UINT32, &node->writeMask);
 		break;
 	case UA_ATTRIBUTEID_USERWRITEMASK:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_UINT32, &node->userWriteMask);
 		break;
 	case UA_ATTRIBUTEID_ISABSTRACT:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_ReferenceTypeNode *) node)->isAbstract);
 		break;
 	case UA_ATTRIBUTEID_SYMMETRIC:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_ReferenceTypeNode *) node)->symmetric);
 		break;
 	case UA_ATTRIBUTEID_INVERSENAME:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_LOCALIZEDTEXT, &((UA_ReferenceTypeNode *) node)->inverseName);
 		break;
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VIEW);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_ViewNode *) node)->containsNoLoops);
 		break;
 	case UA_ATTRIBUTEID_EVENTNOTIFIER:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VIEW);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BYTE, &((UA_ViewNode *) node)->eventNotifier);
 		break;
 	case UA_ATTRIBUTEID_VALUE:
-		if (node->nodeClass != UA_NODECLASS_VARIABLE) {
-			v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-			v->status = UA_STATUSCODE_BADNOTREADABLE;
-			break;
-		}
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE | UA_DATAVALUE_ENCODINGMASK_VARIANT;
-		v->status = UA_STATUSCODE_GOOD;
-
-		// be careful not to release the node before encoding the message
-
-		UA_VariableNode * vn = (UA_VariableNode*) node;
-		// FIXME: delete will be called later on on on all the members of v, so essentially
-		// the item's data will be removed from the namespace-object. We would need
-		// something like a deep copy function just as we have it for the strings
-		// UA_Variant_copy(UA_Variant* src, UA_Variant* dst);
-
-		// FIXME: mockup code - we know that for 2255 we simply need to copy the array
-		if (node->nodeId.identifier.numeric == 2255) {
-			v->value = vn->value;
-			UA_Array_copy((void const*const*)vn->value.data,vn->value.arrayLength,UA_ns0ToVTableIndex(vn->value.vt->ns0Id),(void***)&v->value.data);
-		} else {
-			v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-			v->status = UA_STATUSCODE_BADNOTREADABLE;
-		}
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		// TODO: Ensure that the borrowed value is not freed prematurely (multithreading)
+		retval |= UA_Variant_borrowSetValue(&v->value, UA_VARIANT, &((UA_VariableNode *) node)->value);
 		break;
 	case UA_ATTRIBUTEID_DATATYPE:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_NODEID, &((UA_VariableTypeNode *) node)->dataType);
 		break;
 	case UA_ATTRIBUTEID_VALUERANK:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_INT32, &((UA_VariableTypeNode *) node)->valueRank);
 		break;
 	case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		UA_Variant_copySetArray(&v->value, UA_UINT32, ((UA_VariableTypeNode *) node)->arrayDimensionsSize, sizeof(UA_UInt32),
+								&((UA_VariableTypeNode *) node)->arrayDimensions);
 		break;
 	case UA_ATTRIBUTEID_ACCESSLEVEL:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BYTE, &((UA_VariableNode *) node)->accessLevel);
 		break;
 	case UA_ATTRIBUTEID_USERACCESSLEVEL:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BYTE, &((UA_VariableNode *) node)->userAccessLevel);
 		break;
 	case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_DOUBLE, &((UA_VariableNode *) node)->minimumSamplingInterval);
 		break;
 	case UA_ATTRIBUTEID_HISTORIZING:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_VariableNode *) node)->historizing);
 		break;
 	case UA_ATTRIBUTEID_EXECUTABLE:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_METHOD);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_MethodNode *) node)->executable);
 		break;
 	case UA_ATTRIBUTEID_USEREXECUTABLE:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_METHOD);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_MethodNode *) node)->userExecutable);
 		break;
 	default:
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		break;
 	}
-	Namespace_Lock_release(lock);
+
+	Namespace_Entry_Lock_release(lock);
+
+	if(retval != UA_SUCCESS) {
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
+		v->status = UA_STATUSCODE_BADNOTREADABLE;
+	}
+
 	return v;
 }
 
-UA_Int32 Service_Read(SL_Channel *channel, const UA_ReadRequest *request, UA_ReadResponse *response ) {
-	if(channel->session == UA_NULL || channel->session->application == UA_NULL) return UA_ERROR; // TODO: Return error message
+UA_Int32 Service_Read(SL_Channel * channel, const UA_ReadRequest * request, UA_ReadResponse * response) {
+	if(channel->session == UA_NULL || channel->session->application == UA_NULL)
+		return UA_ERROR;	// TODO: Return error message
+
+	int readsize = request->nodesToReadSize;
+	/* NothingTodo */
+	if(readsize <= 0) {
+		response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+		response->resultsSize = 0;
+		return UA_SUCCESS;
+	}
 
-	int readsize = request->nodesToReadSize > 0 ? request->nodesToReadSize : 0;
 	response->resultsSize = readsize;
-	UA_alloc((void **)&response->results, sizeof(void *)*readsize);
-	for(int i=0;i<readsize;i++) {
-		DBG_VERBOSE(printf("service_read - attributeId=%d\n",request->nodesToRead[i]->attributeId));
-		DBG_VERBOSE(UA_NodeId_printf("service_read - nodeId=",&(request->nodesToRead[i]->nodeId)));
+	UA_alloc((void **)&response->results, sizeof(void *) * readsize);
+	for(int i = 0; i < readsize; i++) {
+		DBG_VERBOSE(printf("service_read - attributeId=%d\n", request->nodesToRead[i]->attributeId));
+		DBG_VERBOSE(UA_NodeId_printf("service_read - nodeId=", &(request->nodesToRead[i]->nodeId)));
 		response->results[i] = service_read_node(channel->session->application, request->nodesToRead[i]);
 	}
+	response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
 	response->diagnosticInfosSize = -1;
 	return UA_SUCCESS;
 }
-

+ 90 - 0
src/ua_services_nodemanagement.c

@@ -0,0 +1,90 @@
+#include "ua_services.h"
+#include "ua_statuscodes.h"
+#include "ua_namespace.h"
+
+#define CHECKED_ACTION(ACTION, CLEAN_UP, GOTO) do {	\
+	status |= ACTION; \
+	if(status != UA_SUCCESS) { \
+		CLEAN_UP; \
+		goto GOTO; \
+	} } while(0) \
+
+static UA_AddNodesResult * addSingleNode(Application *app, UA_AddNodesItem *item) {
+	UA_AddNodesResult *result;
+	UA_AddNodesResult_new(&result);
+
+	Namespace *parent_ns = UA_indexedList_findValue(app->namespaces, item->parentNodeId.nodeId.namespace);
+	// TODO: search for namespaceUris and not only ns-ids.
+	if(parent_ns == UA_NULL) {
+		result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
+		return result;
+	}
+
+	Namespace *ns = UA_NULL;
+	UA_Boolean nodeid_isnull = UA_NodeId_isNull(&item->requestedNewNodeId.nodeId);
+
+	if(nodeid_isnull) ns = parent_ns;
+	else ns = UA_indexedList_findValue(app->namespaces, item->requestedNewNodeId.nodeId.namespace);
+
+	if(ns == UA_NULL || item->requestedNewNodeId.nodeId.namespace == 0) {
+		result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
+		return result;
+	}
+
+	UA_Int32 status = UA_SUCCESS;
+	const UA_Node *parent;
+	Namespace_Entry_Lock *parent_lock = UA_NULL;
+
+	CHECKED_ACTION(Namespace_get(parent_ns, &item->parentNodeId.nodeId, &parent, &parent_lock),
+				   result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID, ret);
+
+	if(!nodeid_isnull && Namespace_contains(ns, &item->requestedNewNodeId.nodeId)) {
+		result->statusCode = UA_STATUSCODE_BADNODEIDEXISTS;
+		goto ret;
+	}
+
+	/**
+	   TODO:
+
+	   1) Check for the remaining conditions 
+	   Bad_ReferenceTypeIdInvalid  See Table 166 for the description of this result code.
+	   Bad_ReferenceNotAllowed  The reference could not be created because it violates constraints imposed by the data model.
+	   Bad_NodeClassInvalid  See Table 166 for the description of this result code.
+	   Bad_BrowseNameInvalid  See Table 166 for the description of this result code.
+	   Bad_BrowseNameDuplicated  The browse name is not unique among nodes that share the same relationship with the parent.
+	   Bad_NodeAttributesInvalid  The node Attributes are not valid for the node class.
+	   Bad_TypeDefinitionInvalid  See Table 166 for the description of this result code.
+	   Bad_UserAccessDenied  See Table 165 for the description of this result code
+
+	   2) Parse the UA_Node from the ExtensionObject
+	   3) Create a new entry in the namespace
+	   4) Add the reference to the parent.
+	 */
+
+ ret:
+	Namespace_Entry_Lock_release(parent_lock);
+	return result;
+}
+
+UA_Int32 Service_AddNodes(SL_Channel *channel, const UA_AddNodesRequest *request, UA_AddNodesResponse *response) {
+	if(channel->session == UA_NULL || channel->session->application == UA_NULL)
+		return UA_ERROR;	// TODO: Return error message
+
+	int nodestoaddsize = request->nodesToAddSize;
+	if(nodestoaddsize <= 0) {
+		response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+		response->resultsSize = 0;
+		return UA_SUCCESS;
+	}
+
+	response->resultsSize = nodestoaddsize;
+	UA_alloc((void **)&response->results, sizeof(void *) * nodestoaddsize);
+	for(int i = 0; i < nodestoaddsize; i++) {
+		DBG_VERBOSE(UA_QualifiedName_printf("service_addnodes - name=", &(request->nodesToAdd[i]->browseName)));
+		response->results[i] = addSingleNode(channel->session->application, request->nodesToAdd[i]);
+	}
+	response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
+	response->diagnosticInfosSize = -1;
+	return UA_SUCCESS;
+	
+}

+ 22 - 0
src/ua_services_view.c

@@ -1,4 +1,5 @@
 #include "ua_services.h"
+#include "ua_statuscodes.h"
 
 UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA_BrowseResponse *response) {
 	UA_Int32 retval = UA_SUCCESS;
@@ -9,3 +10,24 @@ UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA
 	}
 	return retval;
 }
+
+UA_Int32 Service_TranslateBrowsePathsToNodeIds(SL_Channel *channel, const UA_TranslateBrowsePathsToNodeIdsRequest *request, UA_TranslateBrowsePathsToNodeIdsResponse *response)
+{
+	UA_Int32 retval = UA_SUCCESS;
+
+	DBG_VERBOSE(printf("TranslateBrowsePathsToNodeIdsService - %i path(s)", request->browsePathsSize));
+	//Allocate space for a correct answer
+	UA_Array_new((void***)&(response->results),request->browsePathsSize,UA_BROWSEPATHRESULT);
+
+	response->resultsSize = request->browsePathsSize;
+
+	UA_BrowsePathResult* path;
+	for(UA_Int32 i = 0;i<request->browsePathsSize;i++){
+		UA_BrowsePathResult_new(&path);
+		//FIXME: implement
+		path->statusCode = UA_STATUSCODE_BADQUERYTOOCOMPLEX;
+		(response->results[i]) = path;
+	}
+
+	return retval;
+}

+ 0 - 1
src/ua_transport_binary.h

@@ -3,7 +3,6 @@
 #include <stdio.h>
 
 #include "opcua.h"
-#include "ua_transport_binary.h"
 
 //transport errors begin at 1000
 #define UA_ERROR_MULTIPLE_HEL 1000

+ 4 - 0
src/ua_transport_binary_secure.c

@@ -147,6 +147,10 @@ UA_Int32 SL_handleRequest(SL_Channel *channel, const UA_ByteString* msg, UA_Int3
 		INVOKE_SERVICE(Read);
 	    responsetype = UA_READRESPONSE_NS0;
 	}
+	else if(serviceid == UA_TRANSLATEBROWSEPATHSTONODEIDSREQUEST_NS0) {
+		INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
+	    responsetype = UA_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE_NS0;
+	}
 	else {
 		printf("SL_processMessage - unknown request, namespace=%d, request=%d\n", serviceRequestType.namespace,serviceRequestType.identifier.numeric);
 		retval = UA_ERROR;

+ 0 - 1
src/ua_transport_binary_secure.h

@@ -3,7 +3,6 @@
 #include "opcua.h"
 #include "ua_transport.h"
 #include "ua_transport_binary.h"
-#include "ua_transport_binary_secure.h"
 
 typedef struct {
 	UA_UInt32 secureChannelId;

+ 972 - 0
src/ua_xml.c

@@ -0,0 +1,972 @@
+/*
+ * ua_xml.c
+ *
+ *  Created on: 03.05.2014
+ *      Author: mrt
+ */
+
+#include "ua_xml.h"
+
+UA_Int32 UA_TypedArray_init(UA_TypedArray* p) {
+	p->size = -1;
+	p->vt = &UA_[UA_INVALIDTYPE];
+	p->elements = UA_NULL;
+	return UA_SUCCESS;
+}
+UA_Int32 UA_TypedArray_new(UA_TypedArray** p) {
+	UA_alloc((void** )p, sizeof(UA_TypedArray));
+	UA_TypedArray_init(*p);
+	return UA_SUCCESS;
+}
+UA_Int32 UA_TypedArray_setType(UA_TypedArray* p, UA_Int32 type) {
+	UA_Int32 retval = UA_ERR_INVALID_VALUE;
+	if (type >= UA_BOOLEAN && type <= UA_INVALIDTYPE) {
+		p->vt = &UA_[type];
+		retval = UA_SUCCESS;
+	}
+	return retval;
+}
+
+// FIXME: We might want to have these classes and their methods
+// defined in opcua.h via generate_builtin and the plugin-concept
+// or in ua_basictypes.c
+
+UA_Int32 UA_NodeSetAlias_init(UA_NodeSetAlias* p) {
+	UA_String_init(&(p->alias));
+	UA_String_init(&(p->value));
+	return UA_SUCCESS;
+}
+UA_Int32 UA_NodeSetAlias_new(UA_NodeSetAlias** p) {
+	UA_alloc((void** )p, sizeof(UA_NodeSetAlias));
+	UA_NodeSetAlias_init(*p);
+	return UA_SUCCESS;
+}
+UA_Int32 UA_NodeSetAliases_init(UA_NodeSetAliases* p) {
+	p->size = -1;
+	p->aliases = UA_NULL;
+	return UA_SUCCESS;
+}
+UA_Int32 UA_NodeSetAliases_new(UA_NodeSetAliases** p) {
+	UA_alloc((void** )p, sizeof(UA_NodeSetAliases));
+	UA_NodeSetAliases_init(*p);
+	return UA_SUCCESS;
+}
+UA_Int32 UA_NodeSetAliases_println(cstring label, UA_NodeSetAliases *p) {
+	UA_Int32 i;
+	for (i = 0; i < p->size; i++) {
+		UA_NodeSetAlias* a = p->aliases[i];
+		printf("%s{addr=%p", label, (void*) a);
+		if (a) {
+			printf(",alias='%.*s', value='%.*s'", a->alias.length, a->alias.data, a->value.length, a->value.data);
+		}
+		printf("}\n");
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_NodeSet_init(UA_NodeSet* p, UA_UInt32 nsid) {
+	Namespace_new(&(p->ns), 100, nsid);
+	p->aliases.size = -1;
+	p->aliases.aliases = UA_NULL;
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_NodeSet_new(UA_NodeSet** p, UA_UInt32 nsid) {
+	UA_alloc((void** )p, sizeof(UA_NodeSet));
+	UA_NodeSet_init(*p, nsid);
+	return UA_SUCCESS;
+}
+UA_Int32 UA_NodeId_copycstring(cstring src, UA_NodeId* dst, UA_NodeSetAliases* aliases) {
+	dst->encodingByte = UA_NODEIDTYPE_FOURBYTE;
+	dst->namespace = 0;
+	dst->identifier.numeric = 0;
+	// FIXME: assumes i=nnnn
+	if (src[1] == '=') {
+		dst->identifier.numeric = atoi(&src[2]);
+	} else {
+		UA_Int32 i;
+		for (i = 0; i < aliases->size && dst->identifier.numeric == 0; ++i) {
+			if (0
+					== strncmp((char const*) src, (char const*) aliases->aliases[i]->alias.data,
+							aliases->aliases[i]->alias.length)) {
+				dst->identifier.numeric = atoi((char const*) &(aliases->aliases[i]->value.data[2]));
+			}
+		}
+	}
+	DBG_VERBOSE(printf("UA_NodeId_copycstring src=%s,id=%d\n", src, dst->identifier.numeric));
+	return UA_SUCCESS;
+}
+
+
+UA_Int32 UA_ReferenceNode_println(cstring label, UA_ReferenceNode *a) {
+	printf("%s{referenceType=%d, target=%d, isInverse=%d}\n",
+			label,
+			a->referenceTypeId.identifier.numeric,
+			a->targetId.nodeId.identifier.numeric,
+			a->isInverse);
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_ExpandedNodeId_copycstring(cstring src, UA_ExpandedNodeId* dst, UA_NodeSetAliases* aliases) {
+	dst->nodeId.encodingByte = UA_NODEIDTYPE_FOURBYTE;
+	dst->nodeId.namespace = 0;
+	dst->nodeId.identifier.numeric = 0;
+	UA_NodeId_copycstring(src, &(dst->nodeId), aliases);
+	DBG_VERBOSE(printf("UA_ExpandedNodeId_copycstring src=%s,id=%d\n", src, dst->nodeId.identifier.numeric));
+	return UA_SUCCESS;
+}
+
+void XML_Stack_init(XML_Stack* p, cstring name) {
+	unsigned int i, j;
+	p->depth = 0;
+	for (i = 0; i < XML_STACK_MAX_DEPTH; i++) {
+		p->parent[i].name = UA_NULL;
+		p->parent[i].len = 0;
+		p->parent[i].activeChild = -1;
+		p->parent[i].textAttrib = UA_NULL;
+		p->parent[i].textAttribIdx = -1;
+		for (j = 0; j < XML_STACK_MAX_CHILDREN; j++) {
+			p->parent[i].children[j].name = UA_NULL;
+			p->parent[i].children[j].length = -1;
+			p->parent[i].children[j].elementHandler = UA_NULL;
+			p->parent[i].children[j].type = UA_INVALIDTYPE;
+			p->parent[i].children[j].obj = UA_NULL;
+		}
+	}
+	p->parent[0].name = name;
+}
+
+char path_buffer[1024];
+char * XML_Stack_path(XML_Stack* s) {
+	UA_Int32 i;
+	char *p = &path_buffer[0];
+	for (i = 0; i <= s->depth; i++) {
+		strcpy(p, s->parent[i].name);
+		p += strlen(s->parent[i].name);
+		*p = '/';
+		p++;
+	}
+	*p=0;
+	return &path_buffer[0];
+}
+
+void XML_Stack_print(XML_Stack* s) {
+	printf("%s", XML_Stack_path(s));
+}
+
+
+// FIXME: we might want to calculate textAttribIdx from a string and the information given on the stack
+void XML_Stack_handleTextAsElementOf(XML_Stack* p, cstring textAttrib, unsigned int textAttribIdx) {
+	p->parent[p->depth].textAttrib = textAttrib;
+	p->parent[p->depth].textAttribIdx = textAttribIdx;
+}
+
+void XML_Stack_addChildHandler(XML_Stack* p, cstring name, UA_Int32 length, XML_decoder handler, UA_Int32 type, void* dst) {
+	unsigned int len = p->parent[p->depth].len;
+	p->parent[p->depth].children[len].name = name;
+	p->parent[p->depth].children[len].length = length;
+	p->parent[p->depth].children[len].elementHandler = handler;
+	p->parent[p->depth].children[len].type = type;
+	p->parent[p->depth].children[len].obj = dst;
+	p->parent[p->depth].len++;
+}
+
+UA_Int32 UA_Int16_copycstring(cstring src, UA_Int16* dst) {
+	*dst = atoi(src);
+	return UA_SUCCESS;
+}
+UA_Int32 UA_UInt16_copycstring(cstring src, UA_UInt16* dst) {
+	*dst = atoi(src);
+	return UA_SUCCESS;
+}
+UA_Int32 UA_Int16_decodeXML(XML_Stack* s, XML_Attr* attr, UA_Int16* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_Int32 entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_Int16_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		UA_Int16_copycstring((cstring) attr[1], dst);
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_Int32_decodeXML(XML_Stack* s, XML_Attr* attr, UA_Int32* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_Int32 entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_Int32_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		*dst = atoi(attr[1]);
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_Text_decodeXML(XML_Stack* s, XML_Attr* attr, UA_Byte** dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_String entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_alloc((void**)&dst,sizeof(void*));
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("Data", attr[i], strlen("Data"))) {
+				char* tmp;
+				UA_alloc((void**)&tmp,strlen(attr[i+1])+1);
+				strncpy(tmp,attr[i+1],strlen(attr[i+1]));
+				tmp[strlen(attr[i+1])] = 0;
+				*dst = (UA_Byte*) tmp;
+			} else {
+				printf("UA_Text_decodeXML - Unknown attribute - name=%s, value=%s\n", attr[i], attr[i+1]);
+			}
+		}
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_String_decodeXML(XML_Stack* s, XML_Attr* attr, UA_String* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_String entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_String_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "Data", strlen("Data"), (XML_decoder) UA_Text_decodeXML, UA_BYTE, &(dst->data));
+		XML_Stack_addChildHandler(s, "Length", strlen("Length"), (XML_decoder) UA_Int32_decodeXML, UA_INT32, &(dst->length));
+		XML_Stack_handleTextAsElementOf(s, "Data", 0);
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("Data", attr[i], strlen("Data"))) {
+				UA_String_copycstring(attr[i + 1], dst);
+			} else {
+				printf("UA_String_decodeXML - Unknown attribute - name=%s, value=%s\n", attr[i], attr[i+1]);
+			}
+		}
+	} else {
+		switch (s->parent[s->depth - 1].activeChild) {
+		case 0:
+			if (dst != UA_NULL && dst->data != UA_NULL && dst->length == -1) {
+				dst->length = strlen((char const*)dst->data);
+			}
+			break;
+		}
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_NodeId_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeId* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_NodeId entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_NodeId_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "Namespace", strlen("Namespace"), (XML_decoder) UA_Int16_decodeXML, UA_INT16, &(dst->namespace));
+		XML_Stack_addChildHandler(s, "Numeric", strlen("Numeric"), (XML_decoder) UA_Int32_decodeXML, UA_INT32, &(dst->identifier.numeric));
+		XML_Stack_addChildHandler(s, "Identifier", strlen("Identifier"), (XML_decoder) UA_String_decodeXML, UA_STRING, UA_NULL);
+		XML_Stack_handleTextAsElementOf(s, "Data", 2);
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("Namespace", attr[i], strlen("Namespace"))) {
+				dst->namespace = atoi(attr[i + 1]);
+			} else if (0 == strncmp("Numeric", attr[i], strlen("Numeric"))) {
+				dst->identifier.numeric = atoi(attr[i + 1]);
+				dst->encodingByte = UA_NODEIDTYPE_FOURBYTE;
+			} else {
+				printf("UA_NodeId_decodeXML - Unknown attribute name=%s, value=%s\n", attr[i], attr[i+1]);
+			}
+		}
+	} else {
+		if (s->parent[s->depth - 1].activeChild == 2) {
+			UA_NodeId_copycstring((cstring)((UA_String*)attr)->data,dst,s->aliases);
+		}
+	}
+	return UA_SUCCESS;
+}
+UA_Int32 UA_ExpandedNodeId_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ExpandedNodeId* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_ExpandedNodeId entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_ExpandedNodeId_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "NodeId", strlen("NodeId"), (XML_decoder) UA_NodeId_decodeXML, UA_NODEID, &(dst->nodeId));
+		XML_Stack_addChildHandler(s, "Namespace", strlen("Namespace"),(XML_decoder) UA_Int16_decodeXML, UA_INT16, &(dst->nodeId.namespace));
+		XML_Stack_addChildHandler(s, "Numeric", strlen("Numeric"),(XML_decoder) UA_Int32_decodeXML, UA_INT32,
+				&(dst->nodeId.identifier.numeric));
+		XML_Stack_addChildHandler(s, "Id", strlen("Id"),(XML_decoder) UA_String_decodeXML, UA_STRING, UA_NULL);
+		XML_Stack_handleTextAsElementOf(s, "Data", 3);
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("Namespace", attr[i], strlen("Namespace"))) {
+				UA_UInt16_copycstring((cstring) attr[i + 1], &(dst->nodeId.namespace));
+			} else if (0 == strncmp("Numeric", attr[i], strlen("Numeric"))) {
+				UA_NodeId_copycstring((cstring) attr[i + 1], &(dst->nodeId), s->aliases);
+			} else if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
+				UA_NodeId_copycstring((cstring) attr[i + 1], &(dst->nodeId), s->aliases);
+			} else {
+				printf("UA_ExpandedNodeId_decodeXML - unknown attribute name=%s, value=%s\n", attr[i], attr[i+1]);
+			}
+		}
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_LocalizedText_decodeXML(XML_Stack* s, XML_Attr* attr, UA_LocalizedText* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_LocalizedText entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_LocalizedText_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		// s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "Text", strlen("Text"), (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->text));
+		XML_Stack_addChildHandler(s, "Locale", strlen("Locale"), (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->locale));
+		XML_Stack_handleTextAsElementOf(s, "Data", 0);
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("Text", attr[i], strlen("Text"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->text));
+				dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else if (0 == strncmp("Locale", attr[i], strlen("Locale"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->locale));
+				dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
+			} else {
+				perror("Unknown attribute");
+			}
+		}
+	} else {
+		switch (s->parent[s->depth - 1].activeChild) {
+		case 0:
+			dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			break;
+		case 1:
+			dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
+			break;
+		default:
+			break;
+		}
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_QualifiedName_decodeXML(XML_Stack* s, XML_Attr* attr, UA_QualifiedName* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_QualifiedName entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_QualifiedName_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "Name", strlen("Name"), (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->name));
+		XML_Stack_addChildHandler(s, "NamespaceIndex", strlen("NamespaceIndex"), (XML_decoder) UA_Int16_decodeXML, UA_STRING,
+				&(dst->namespaceIndex));
+		XML_Stack_handleTextAsElementOf(s, "Data", 0);
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("NamespaceIndex", attr[i], strlen("NamespaceIndex"))) {
+				dst->namespaceIndex = atoi(attr[i + 1]);
+			} else if (0 == strncmp("Name", attr[i], strlen("Name"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->name));
+			} else {
+				perror("Unknown attribute");
+			}
+		}
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_ReferenceNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ReferenceNode* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_ReferenceNode_decodeXML entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	if (isStart) {
+		// create if necessary
+		if (dst == UA_NULL) {
+			UA_ReferenceNode_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		// set handlers
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "ReferenceType", strlen("ReferenceType"),(XML_decoder) UA_NodeId_decodeXML, UA_STRING,
+				&(dst->referenceTypeId));
+		XML_Stack_addChildHandler(s, "IsForward", strlen("IsForward"), (XML_decoder) UA_Boolean_decodeXML, UA_STRING, &(dst->isInverse));
+		XML_Stack_addChildHandler(s, "Target", strlen("Target"), (XML_decoder) UA_ExpandedNodeId_decodeXML, UA_STRING, &(dst->targetId));
+		XML_Stack_handleTextAsElementOf(s, "NodeId", 2);
+
+		// set attributes
+		UA_Int32 i;
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("ReferenceType", attr[i], strlen("ReferenceType"))) {
+				UA_NodeId_copycstring(attr[i + 1], &(dst->referenceTypeId), s->aliases);
+			} else if (0 == strncmp("IsForward", attr[i], strlen("IsForward"))) {
+				UA_Boolean_copycstring(attr[i + 1], &(dst->isInverse));
+			} else if (0 == strncmp("Target", attr[i], strlen("Target"))) {
+				UA_ExpandedNodeId_copycstring(attr[i + 1], &(dst->targetId), s->aliases);
+			} else {
+				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
+			}
+		}
+	}
+	return UA_SUCCESS;
+}
+
+
+UA_Int32 UA_TypedArray_decodeXML(XML_Stack* s, XML_Attr* attr, UA_TypedArray* dst, _Bool isStart) {
+	UA_Int32 type = s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].type;
+	cstring names  = s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].name;
+	DBG_VERBOSE(printf("UA_TypedArray_decodeXML - entered with dst=%p,isStart=%d,type={%d,%s},name=%s\n", (void* ) dst, isStart,type,UA_[type].name, names));
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_TypedArray_new(&dst);
+			UA_TypedArray_setType(dst, type);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = dst;
+		}
+		// need to map from ArrayName to member name
+		// References - Reference
+		// Aliases - Alias
+		// ListOfXX - XX
+		UA_Int32 length = 0;
+		if (0 == strncmp("ListOf",names,strlen("ListOf"))) {
+			names = &names[strlen("ListOf")];
+			length = strlen(names);
+		} else if ( 0 == strncmp("References",names,strlen("References"))){
+			length = strlen(names) - 1;
+		} else if ( 0 == strncmp("Aliases",names,strlen("Aliases"))){
+			length = strlen(names) - 2;
+		}
+		DBG(printf("UA_TypedArray_decodeXML - add handler for {%.*s}\n", length, names));
+		XML_Stack_addChildHandler(s, names, length, (XML_decoder) UA_[type].decodeXML, type, UA_NULL);
+	} else {
+		// sub element is ready, add to array
+		if (dst->size < 0 || dst->size == 0) {
+			dst->size = 1;
+			UA_alloc((void** )&(dst->elements), dst->size * sizeof(void*));
+			DBG(printf("UA_TypedArray_decodeXML - allocate elements:dst=%p, aliases=%p, size=%d\n", (void* )dst, (void* )(dst->elements),dst->size));
+		} else {
+			dst->size++;
+			dst->elements = realloc(dst->elements, dst->size * sizeof(void*));
+			DBG(printf("UA_TypedArray_decodeXML - reallocate elements:dst=%p, aliases=%p, size=%d\n", (void* )dst,(void* )(dst->elements), dst->size));
+		}
+		// index starts with 0, therefore size-1
+		DBG_VERBOSE(printf("UA_TypedArray_decodeXML - assign element[%d], src=%p\n", dst->size - 1, (void* )attr));
+		dst->elements[dst->size - 1] = (void*) attr;
+		DBG_VERBOSE(printf("UA_TypedArray_decodeXML - clear %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;
+}
+
+
+UA_Int32 UA_DataTypeNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_DataTypeNode* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+
+	if (isStart) {
+		// create a new object if called with UA_NULL
+		if (dst == UA_NULL) {
+			UA_DataTypeNode_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
+		XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
+		XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"),(XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME, &(dst->description));
+		XML_Stack_addChildHandler(s, "IsAbstract", strlen("IsAbstract"),(XML_decoder) UA_Boolean_decodeXML, UA_BOOLEAN, &(dst->description));
+		XML_Stack_addChildHandler(s, "References", strlen("References"),(XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE, UA_NULL);
+
+		// set missing default attributes
+		dst->nodeClass = UA_NODECLASS_DATATYPE;
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
+				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
+			} else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
+				dst->browseName.namespaceIndex = 0;
+			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
+				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else if (0 == strncmp("IsAbstract", attr[i], strlen("IsAbstract"))) {
+				UA_Boolean_copycstring(attr[i + 1], &(dst->isAbstract));
+				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->description.text));
+				dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else {
+				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
+			}
+		}
+	} else {
+		switch (s->parent[s->depth - 1].activeChild) {
+		case 4: // References
+			if (attr != UA_NULL) {
+				UA_TypedArray* array = (UA_TypedArray *) attr;
+				DBG_VERBOSE(printf("finished aliases: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
+				dst->referencesSize = array->size;
+				dst->references = (UA_ReferenceNode**) array->elements;
+			}
+		break;
+		}
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_ObjectNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ObjectNode* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_ObjectNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+
+	if (isStart) {
+		// create a new object if called with UA_NULL
+		if (dst == UA_NULL) {
+			UA_ObjectNode_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+
+		// s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
+		XML_Stack_addChildHandler(s, "Description", strlen("Description"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
+		// FIXME: no idea how to handle SymbolicName automatically. Seems to me that it is the "real" BrowseName
+		//		XML_Stack_addChildHandler(s, "BrowseName", (XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME,&(dst->browseName));
+		XML_Stack_addChildHandler(s, "SymbolicName", strlen("SymbolicName"), (XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME,&(dst->browseName));
+		XML_Stack_addChildHandler(s, "References", strlen("References"), (XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE, UA_NULL);
+
+		// set missing default attributes
+		dst->nodeClass = UA_NODECLASS_DATATYPE;
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
+				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
+			} else if (0 == strncmp("SymbolicName", attr[i], strlen("SymboliName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
+				dst->browseName.namespaceIndex = 0;
+			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
+				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->description.text));
+				dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else {
+				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
+			}
+		}
+	} else {
+		if (s->parent[s->depth - 1].activeChild == 3 && attr != UA_NULL ) { // References Array
+			UA_TypedArray* array = (UA_TypedArray*) attr;
+			DBG(printf("UA_ObjectNode_decodeXML finished references: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
+			dst->referencesSize = array->size;
+			dst->references = (UA_ReferenceNode**) array->elements;
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
+		}
+	}
+	return UA_SUCCESS;
+}
+
+
+UA_Int32 UA_Variant_decodeXML(XML_Stack* s, XML_Attr* attr, UA_Variant* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_Variant entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+
+	if (isStart) {
+		// create a new object if called with UA_NULL
+		if (dst == UA_NULL) {
+			UA_Variant_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "ListOfExtensionObject", strlen("ListOfExtensionObject"), (XML_decoder) UA_TypedArray_decodeXML, UA_EXTENSIONOBJECT, UA_NULL);
+		XML_Stack_addChildHandler(s, "ListOfLocalizedText", strlen("ListOfLocalizedText"), (XML_decoder) UA_TypedArray_decodeXML, UA_LOCALIZEDTEXT, UA_NULL);
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			{
+				DBG_ERR(XML_Stack_print(s));
+				DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
+			}
+		}
+	} else {
+		if (s->parent[s->depth - 1].activeChild == 0 && attr != UA_NULL ) { // ExtensionObject
+			UA_TypedArray* array = (UA_TypedArray*) attr;
+			DBG_VERBOSE(printf("UA_Variant_decodeXML - finished array: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
+			dst->arrayLength = array->size;
+			dst->data = array->elements;
+			dst->vt = &UA_[UA_EXTENSIONOBJECT];
+			dst->encodingMask = UA_EXTENSIONOBJECT_NS0 & UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
+		} else if (s->parent[s->depth - 1].activeChild == 1 && attr != UA_NULL ) { // LocalizedText
+			UA_TypedArray* array = (UA_TypedArray*) attr;
+			DBG_VERBOSE(printf("UA_Variant_decodeXML - finished array: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
+			dst->arrayLength = array->size;
+			dst->data = array->elements;
+			dst->vt = &UA_[UA_LOCALIZEDTEXT];
+			dst->encodingMask = UA_LOCALIZEDTEXT_NS0 & UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
+		}
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_ExtensionObject_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ExtensionObject* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_ExtensionObject entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+
+	if (isStart) {
+		// create a new object if called with UA_NULL
+		if (dst == UA_NULL) {
+			UA_ExtensionObject_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "TypeId", strlen("TypeId"), (XML_decoder) UA_NodeId_decodeXML, UA_NODEID, &(dst->typeId));
+		// XML_Stack_addChildHandler(s, "Body", strlen("Body"), (XML_decoder) UA_Body_decodeXML, UA_LOCALIZEDTEXT, UA_NULL);
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			{
+				DBG_ERR(XML_Stack_print(s));
+				DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
+			}
+		}
+	}
+	return UA_SUCCESS;
+}
+
+_Bool UA_NodeId_isBuiltinType(UA_NodeId* nodeid) {
+	return (nodeid->namespace == 0 &&
+			nodeid->identifier.numeric >= UA_BOOLEAN_NS0 &&
+			nodeid->identifier.numeric <= UA_DIAGNOSTICINFO_NS0
+			);
+}
+
+UA_Int32 UA_VariableNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_VariableNode* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_VariableNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+
+	if (isStart) {
+		// create a new object if called with UA_NULL
+		if (dst == UA_NULL) {
+			UA_VariableNode_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT,
+				&(dst->displayName));
+		XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT,
+				&(dst->description));
+		XML_Stack_addChildHandler(s, "DataType", strlen("DataType"),(XML_decoder) UA_NodeId_decodeXML, UA_NODEID, &(dst->dataType));
+		XML_Stack_addChildHandler(s, "ValueRank", strlen("ValueRank"),(XML_decoder) UA_Int32_decodeXML, UA_INT32, &(dst->valueRank));
+		XML_Stack_addChildHandler(s, "Value", strlen("Value"),(XML_decoder) UA_Variant_decodeXML, UA_VARIANT, &(dst->value));
+		XML_Stack_addChildHandler(s, "References", strlen("References"), (XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE,
+		UA_NULL);
+
+		// set missing default attributes
+		dst->nodeClass = UA_NODECLASS_VARIABLE;
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
+				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
+			} else if (0 == strncmp("DataType", attr[i], strlen("DataType"))) {
+				UA_NodeId_copycstring(attr[i + 1], &(dst->dataType), s->aliases);
+				if (UA_NodeId_isBuiltinType(&(dst->dataType))) {
+					dst->value.encodingMask = dst->dataType.identifier.numeric;
+					dst->value.vt = &UA_[UA_ns0ToVTableIndex(dst->dataType.identifier.numeric)];
+				} else {
+					dst->value.encodingMask = UA_EXTENSIONOBJECT_NS0;
+					dst->value.vt = &UA_[UA_EXTENSIONOBJECT];
+				}
+			} else if (0 == strncmp("ValueRank", attr[i], strlen("ValueRank"))) {
+				dst->valueRank = atoi(attr[i + 1]);
+			} else if (0 == strncmp("ParentNodeId", attr[i], strlen("ParentNodeId"))) {
+				// FIXME: I do not know what to do with this parameter
+			} else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
+				dst->browseName.namespaceIndex = 0;
+			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
+				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->description.text));
+				dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else {
+				DBG_ERR(XML_Stack_print(s));
+				DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
+			}
+		}
+	} else {
+		if (s->parent[s->depth - 1].activeChild == 5 && attr != UA_NULL) {
+			UA_TypedArray* array = (UA_TypedArray*) attr;
+			DBG(printf("UA_VariableNode_decodeXML - finished references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
+			dst->referencesSize = array->size;
+			dst->references = (UA_ReferenceNode**) array->elements;
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
+		}
+	}
+	return UA_SUCCESS;
+}
+
+void print_node(UA_Node const * node) {
+	if (node != UA_NULL) {
+		UA_NodeId_printf("node.nodeId=", &(node->nodeId));
+		printf("\t.browseName='%.*s'\n", node->browseName.name.length, node->browseName.name.data);
+		printf("\t.displayName='%.*s'\n", node->displayName.text.length, node->displayName.text.data);
+		printf("\t.description='%.*s%s'\n", node->description.text.length > 40 ? 40 : node->description.text.length,
+				node->description.text.data, node->description.text.length > 40 ? "..." : "");
+		printf("\t.nodeClass=%d\n", node->nodeClass);
+		printf("\t.writeMask=%d\n", node->writeMask);
+		printf("\t.userWriteMask=%d\n", node->userWriteMask);
+		printf("\t.references.size=%d\n", node->referencesSize);
+		UA_Int32 i;
+		for (i=0;i<node->referencesSize;i++) {
+			printf("\t\t.element[%d]", i);
+			UA_ReferenceNode_println("=",node->references[i]);
+		}
+		switch (node->nodeClass) {
+		case UA_NODECLASS_VARIABLE: {
+			UA_VariableNode const * p = (UA_VariableNode const *) node;
+			printf("\t----- UA_VariableNode ----- \n");
+			UA_NodeId_printf("\t.dataType=", &(p->dataType));
+			printf("\t.valueRank=%d\n", p->valueRank);
+			printf("\t.accessLevel=%d\n", p->accessLevel);
+			printf("\t.userAccessLevel=%d\n", p->userAccessLevel);
+			printf("\t.arrayDimensionsSize=%d\n", p->arrayDimensionsSize);
+			printf("\t.minimumSamplingInterval=%f\n", p->minimumSamplingInterval);
+			printf("\t.historizing=%d\n", p->historizing);
+			printf("\t----- UA_Variant ----- \n");
+			printf("\t.value.type.name=%s\n", p->value.vt->name);
+			printf("\t.value.array.length=%d\n", p->value.arrayLength);
+			UA_Int32 i;
+			for (i=0;i<p->value.arrayLength;i++) {
+				printf("\t.value.array.element[%d]=%p", i, p->value.data[i]);
+				if (p->value.vt->ns0Id == UA_LOCALIZEDTEXT_NS0) {
+					UA_LocalizedText* ltp = (UA_LocalizedText*) p->value.data[i];
+					printf(",enc=%d,locale={%d,{%.*s}},text={%d,{%.*s}}",ltp->encodingMask,ltp->locale.length,ltp->locale.length,ltp->locale.data,ltp->text.length,ltp->text.length,ltp->text.data);
+				}
+				printf("\n");
+			}
+		}
+			break;
+		// case UA_NODECLASS_DATATYPE:
+		default:
+			break;
+		}
+	}
+}
+
+UA_Int32 UA_NodeSetAlias_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSetAlias* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_NodeSetAlias entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	if (isStart) {
+		// create if necessary
+		if (dst == UA_NULL) {
+			UA_NodeSetAlias_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		// set handlers
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "Alias", strlen("Alias"), (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->alias));
+		XML_Stack_addChildHandler(s, "Value", strlen("Value"), (XML_decoder) UA_String_decodeXML, UA_STRING, &(dst->value));
+		XML_Stack_handleTextAsElementOf(s, "Data", 1);
+
+		// set attributes
+		UA_Int32 i;
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("Alias", attr[i], strlen("Alias"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->alias));
+			} else if (0 == strncmp("Value", attr[i], strlen("Value"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->value));
+			} else {
+				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;
+}
+
+UA_Int32 UA_NodeSetAliases_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSetAliases* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_NodeSetALiases entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_NodeSetAliases_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "Alias", strlen("Alias"), (XML_decoder) UA_NodeSetAlias_decodeXML, UA_INVALIDTYPE, UA_NULL);
+	} else {
+		// sub element is ready, add to array
+		if (dst->size < 0 || dst->size == 0) {
+			dst->size = 1;
+			UA_alloc((void** )&(dst->aliases), dst->size * sizeof(UA_NodeSetAlias*));
+			DBG_VERBOSE(
+					printf("allocate aliases:dst=%p, aliases=%p, size=%d\n", (void* )dst, (void* )(dst->aliases),
+							dst->size));
+		} else {
+			dst->size++;
+			dst->aliases = realloc(dst->aliases, dst->size * sizeof(UA_NodeSetAlias*));
+			DBG_VERBOSE(
+					printf("reallocate aliases:dst=%p, aliases=%p, size=%d\n", (void* )dst, (void* )(dst->aliases),
+							dst->size));
+		}
+		// index starts with 0, therefore size-1
+		DBG_VERBOSE(printf("assign alias:dst=%p, src=%p\n", (void* )dst->aliases[dst->size - 1], (void* )attr));
+		dst->aliases[dst->size - 1] = (UA_NodeSetAlias*) attr;
+		DBG_VERBOSE(printf("UA_NodeSetAliases 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;
+}
+
+UA_Int32 UA_NodeSet_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSet* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_NodeSet entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	if (isStart) {
+		if (dst == UA_NULL) {
+			UA_NodeSet_new(&dst, 99); // we don't really need the namespaceid for this..'
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "Aliases", strlen("Aliases"), (XML_decoder) UA_NodeSetAliases_decodeXML, UA_INVALIDTYPE,
+				&(dst->aliases));
+		XML_Stack_addChildHandler(s, "UADataType", strlen("UADataType"), (XML_decoder) UA_DataTypeNode_decodeXML, UA_DATATYPENODE, UA_NULL);
+		XML_Stack_addChildHandler(s, "UAVariable", strlen("UAVariable"), (XML_decoder) UA_VariableNode_decodeXML, UA_VARIABLENODE, UA_NULL);
+		XML_Stack_addChildHandler(s, "UAObject", strlen("UAObject"), (XML_decoder) UA_ObjectNode_decodeXML, UA_OBJECTNODE, UA_NULL);
+	} else {
+		if (s->parent[s->depth - 1].activeChild == 0 && attr != UA_NULL) {
+			UA_NodeSetAliases* aliases = (UA_NodeSetAliases*) attr;
+			DBG(printf("UA_NodeSet_decodeXML - finished aliases: aliases=%p, size=%d\n",(void*)aliases,(aliases==UA_NULL)?-1:aliases->size));
+			s->aliases = aliases;
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
+		} else if (s->parent[s->depth - 1].activeChild >= 1 &&  s->parent[s->depth - 1].activeChild <= 3 && attr != UA_NULL) {
+			UA_Node* node = (UA_Node*) attr;
+			DBG(printf("UA_NodeSet_decodeXML - finished node: node=%p\n", (void* )node));
+			Namespace_insert(dst->ns, node);
+			DBG(printf("UA_NodeSet_decodeXML - Inserting "));
+			DBG(print_node(node));
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
+		}
+	}
+	return UA_SUCCESS;
+}
+
+/** lookup if element is a known child of parent, if yes go for it otherwise ignore */
+void XML_Stack_startElement(void * data, const char *el, const char **attr) {
+	XML_Stack* s = (XML_Stack*) data;
+	int i;
+
+// scan expected children
+	XML_Parent* cp = &s->parent[s->depth];
+	for (i = 0; i < cp->len; i++) {
+		if (0 == strncmp(cp->children[i].name, el, cp->children[i].length)) {
+			DBG_VERBOSE(XML_Stack_print(s));
+			DBG_VERBOSE(printf("%s - processing\n", el));
+
+			cp->activeChild = i;
+
+			s->depth++;
+			s->parent[s->depth].name = el;
+			s->parent[s->depth].len = 0;
+			s->parent[s->depth].textAttribIdx = -1;
+			s->parent[s->depth].activeChild = -1;
+
+			// finally call the elementHandler and return
+			cp->children[i].elementHandler(data, attr, cp->children[i].obj, TRUE);
+			return;
+		}
+	}
+// if we come here we rejected the processing of el
+	DBG_VERBOSE(XML_Stack_print(s));
+	DBG_VERBOSE(printf("%s - rejected\n", el));
+	s->depth++;
+	s->parent[s->depth].name = el;
+// this should be sufficient to reject the children as well
+	s->parent[s->depth].len = 0;
+}
+
+UA_Int32 XML_isSpace(cstring s, int len) {
+	int i;
+	for (i = 0; i < len; i++) {
+		if (!isspace(s[i])) {
+			return UA_FALSE;
+		}
+	}
+	return UA_TRUE;
+}
+
+/* simulates startElement, endElement behaviour */
+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);
+		} else {
+			DBG_VERBOSE(XML_Stack_print(s));
+			DBG_VERBOSE(printf("textData - ignore text data '%.*s'\n", len, txt));
+		}
+	}
+}
+
+/** 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!
+	if (s->depth > 1) {
+		// inform parents elementHandler that everything is done
+		XML_Parent* cp = &(s->parent[s->depth - 1]);
+		XML_Parent* cpp = &(s->parent[s->depth - 2]);
+		if (cpp->activeChild >= 0 && cp->activeChild >= 0) {
+			DBG_VERBOSE(XML_Stack_print(s));
+			DBG_VERBOSE(
+					printf(" - inform pop %s, arg=%p\n", cpp->children[cpp->activeChild].name,
+							(void* ) cp->children[cp->activeChild].obj));
+			cpp->children[cpp->activeChild].elementHandler(s, (XML_Attr*) cp->children[cp->activeChild].obj,
+					cpp->children[cpp->activeChild].obj, FALSE);
+		}
+		// reset
+		cp->activeChild = -1;
+	}
+	s->depth--;
+}

+ 107 - 0
src/ua_xml.h

@@ -0,0 +1,107 @@
+/*
+ * ua_xml.h
+ *
+ *  Created on: 03.05.2014
+ *      Author: mrt
+ */
+
+#ifndef __UA_XML_H__
+#define __UA_XML_H__
+
+#include <expat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // strlen
+#include <ctype.h> // isspace
+#include <unistd.h> // read
+
+#include "opcua.h"
+#include "ua_namespace.h"
+
+UA_Int32 UA_Boolean_copycstring(cstring src, UA_Boolean* dst);
+UA_Int32 UA_Int16_copycstring(cstring src, UA_Int16* dst);
+UA_Int32 UA_UInt16_copycstring(cstring src, UA_UInt16* dst) ;
+UA_Boolean UA_NodeId_isBuiltinType(UA_NodeId* nodeid);
+void print_node(UA_Node const * node);
+
+/** @brief an object to hold a typed array */
+typedef struct UA_TypedArray {
+	UA_Int32 size;
+	UA_VTable* vt;
+	void** elements;
+} UA_TypedArray;
+
+/** @brief init typed array with size=-1 and an UA_INVALIDTYPE */
+UA_Int32 UA_TypedArray_init(UA_TypedArray* p);
+
+/** @brief allocate memory for the array header only */
+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, _Bool 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, cstring name);
+void XML_Stack_print(XML_Stack* s);
+
+/** @brief add a reference to a handler (@see XML_Stack_addChildHandler) for text data
+ *
+ * Assume a XML structure such as
+ *     <LocalizedText>
+ *          <Locale></Locale>
+ *          <Text>Server</Text>
+ *     </LocalizedText>
+ * which might be abbreviated as
+ *     <LocalizedText>Server</LocalizedText>
+ *
+ * We would add two (@ref XML_Stack_addChildHandler), one for Locale (index 0) and one for Text (index 1),
+ * both to be handled by (@ref UA_String_decodeXML) with elements "Data" and "Length". To handle the
+ * abbreviation we add
+ *   	XML_Stack_handleTextAsElementOf(s,"Data",1)
+ *
+ * @param[in] s the stack
+ * @param[in] textAttrib the name of the element of the handler at position textAttribIdx
+ * @param[in] textAttribIdx the index of the handler
+ */
+void XML_Stack_handleTextAsElementOf(XML_Stack* p, cstring textAttrib, unsigned int textAttribIdx);
+
+/** @brief make a handler known to the XML-stack on the current level
+ *
+ * The current level is given by s->depth, the maximum number of children is a predefined constant.
+ * A combination of type=UA_INVALIDTYPE and dst=UA_NULL is valid for special handlers only
+ *
+ * @param[in] s the stack
+ * @param[in] name the name of the element
+ * @param[in] nameLength the length of the element name
+ * @param[in] handler the decoder routine for this element
+ * @param[in] type the open62541-type of the element, UA_INVALIDTYPE if not in the VTable
+ * @param[out] dst the address of the object for the data, handlers will allocate object if UA_NULL
+ */
+void XML_Stack_addChildHandler(XML_Stack* p, cstring name, UA_Int32 nameLength, XML_decoder handler, UA_Int32 type, void* dst);
+
+void XML_Stack_startElement(void * data, const char *el, const char **attr);
+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);
+
+#endif // __UA_XML_H__

+ 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
+UNIT_TESTS += check_stack check_list check_indexedList check_builtin check_namespace check_memory check_services_view
 TESTS += $(UNIT_TESTS)
 check_PROGRAMS += $(UNIT_TESTS)
 

+ 5 - 5
tests/check_namespace.c

@@ -7,7 +7,7 @@
 
 START_TEST(test_Namespace) {
 	Namespace *ns = UA_NULL;
-	Namespace_create(&ns, 512);
+	Namespace_new(&ns, 512, 99);
 	Namespace_delete(ns);
 }
 END_TEST
@@ -23,10 +23,10 @@ UA_Int32 createNode(UA_Node** p, UA_Int16 nsid, UA_Int32 id) {
 START_TEST(findNodeInNamespaceWithSingleEntry) {
 	// given
 	Namespace *ns;
-	Namespace_create(&ns, 512);
+	Namespace_new(&ns, 512, 99);
 	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
 	const UA_Node* nr = UA_NULL;
-	Namespace_Lock* nl = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
 	UA_Int32 retval;
 	// when
 	retval = Namespace_get(ns,&(n1->nodeId),&nr,&nl);
@@ -41,12 +41,12 @@ END_TEST
 START_TEST(findNodeInNamespaceWithTwoEntries) {
 	// given
 	Namespace *ns;
-	Namespace_create(&ns, 512);
+	Namespace_new(&ns, 512, 99);
 	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
 	UA_Node* n2; createNode(&n2,0,2255); Namespace_insert(ns,n2);
 
 	const UA_Node* nr = UA_NULL;
-	Namespace_Lock* nl = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
 	UA_Int32 retval;
 	// when
 	retval = Namespace_get(ns,&(n2->nodeId),&nr,&nl);

+ 65 - 0
tests/check_services_view.c

@@ -0,0 +1,65 @@
+/*
+ ============================================================================
+ Name        : check_stack.c
+ Author      :
+ Version     :
+ Copyright   : Your copyright notice
+ Description :
+ ============================================================================
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "opcua.h"
+#include "ua_services.h"
+#include "ua_statuscodes.h"
+#include "check.h"
+
+
+
+START_TEST(Service_TranslateBrowsePathsToNodeIds_SmokeTest)
+{
+	UA_TranslateBrowsePathsToNodeIdsRequest* request;
+	UA_TranslateBrowsePathsToNodeIdsRequest_new(&request);
+
+	UA_TranslateBrowsePathsToNodeIdsResponse* response;
+	UA_TranslateBrowsePathsToNodeIdsResponse_new(&response);
+
+	request->browsePathsSize = 1;
+	UA_Array_new((void***)&(request->browsePaths),request->browsePathsSize,UA_BROWSEPATH);
+
+	Service_TranslateBrowsePathsToNodeIds(UA_NULL,request,response);
+
+	ck_assert_int_eq(response->resultsSize,request->browsePathsSize);
+	ck_assert_int_eq(response->results[0]->statusCode,UA_STATUSCODE_BADQUERYTOOCOMPLEX);
+}
+END_TEST
+
+Suite* testSuite_Service_TranslateBrowsePathsToNodeIds()
+{
+	Suite *s = suite_create("Service_TranslateBrowsePathsToNodeIds");
+	TCase *tc_core = tcase_create("Core");
+	tcase_add_test(tc_core, Service_TranslateBrowsePathsToNodeIds_SmokeTest);
+	suite_add_tcase(s,tc_core);
+	return s;
+}
+
+int main (void)
+{
+	int number_failed = 0;
+
+	Suite *s;
+	SRunner *sr;
+
+
+	s = testSuite_Service_TranslateBrowsePathsToNodeIds();
+	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;
+}
+
+

+ 409 - 108
tests/check_stack.c

@@ -1,135 +1,450 @@
-/*
- ============================================================================
+/****************************************************************************
  Name        : check_stack.c
- Author      :
- Version     :
+ Author      : uleon @ open62541
+ Version     : 0.1
  Copyright   : Your copyright notice
- Description :
- ============================================================================
- */
+ Description : test cases to check different aspects of the
+ stack indication-response behavior w/o any network aspects
+
+
+```
+ Client            Server
+
+request  o--__
+              --> indication        +
+                                    | <---
+            __--o response          +
+confirm. <--
+```
+*****************************************************************************/
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #include "opcua.h"
 #include "ua_transport.h"
+#include "ua_transport_binary.h"
+#include "ua_transport_binary_secure.h"
 #include "check.h"
 
+#define MAXMSG 512
+#define BUFFER_SIZE 8192
 
-/*
-START_TEST(test_getPacketType_validParameter)
-{
+/** @brief this structure holds all the information for the stack test fixture */
+typedef struct stackTestFixture {
+	/** @brief the actual buffer to receive the response msg */
+	UA_Byte respMsgBuffer[BUFFER_SIZE];
+	/** @brief the management structure (initialized to point to respMsgBuffer in create */
+	UA_ByteString respMsg;
+	/** @brief the management data structure for the fake connection */
+	TL_Connection connection;
+} stackTestFixture;
 
-	char buf[] = {'C','L','O'};
-	UA_Int32 pos = 0;
-	UA_ByteString msg;
 
-	msg.data = buf;
-	msg.length = 3;
+/** @brief the maximum number of parallel fixtures.
+ * ( MAX_FIXTURES needs to match the number of bytes of fixturesMap )*/
+#define MAX_FIXTURES 32
+/** @brief this map marks the slots in fixtures as free (bit=0) or in use (bit=1) */
+UA_Int32 fixturesMap = 0;
+/** @brief the array of pointers to the fixtures */
+stackTestFixture* fixtures[MAX_FIXTURES];
 
-	ck_assert_int_eq(TL_getPacketType(&msg, &pos),packetType_CLO);
+/** @brief search first free handle, set and return */
+UA_Int32 stackTestFixture_getAndMarkFreeHandle() {
+	UA_Int32 freeFixtureHandle = 0;
+
+	for (freeFixtureHandle=0;freeFixtureHandle < MAX_FIXTURES;++freeFixtureHandle) {
+		if (!(fixturesMap & (1 << freeFixtureHandle))) { // when free
+			fixturesMap |= (1 << freeFixtureHandle); // then set
+			return freeFixtureHandle;
+		}
+	}
+	return UA_ERR_NO_MEMORY;
+}
+/** @brief clear bit in fixture map */
+UA_Int32 stackTestFixture_markHandleAsFree(UA_Int32 fixtureHandle) {
+	if (fixtureHandle >= 0 && fixtureHandle < MAX_FIXTURES) {
+		fixturesMap &= ~ (1 << fixtureHandle); // clear bit
+		return UA_SUCCESS;
+	}
+	return UA_ERR_INVALID_VALUE;
 }
-END_TEST
-*/
 
+/** @brief get a handle to a free slot and create a new stackTestFixture */
+UA_Int32 stackTestFixture_create(TL_Writer writerCallback) {
+	UA_UInt32 fixtureHandle = stackTestFixture_getAndMarkFreeHandle();
+	if (fixtureHandle < MAX_FIXTURES) {
+		UA_alloc((void**)&fixtures[fixtureHandle], sizeof(stackTestFixture));
+		stackTestFixture* fixture = fixtures[fixtureHandle];
+		fixture->respMsg.data = fixture->respMsgBuffer;
+		fixture->respMsg.length = 0;
+		fixture->connection.connectionState = CONNECTIONSTATE_CLOSED;
+		fixture->connection.writerCallback = writerCallback;
+		fixture->connection.localConf.maxChunkCount = 1;
+		fixture->connection.localConf.maxMessageSize = BUFFER_SIZE;
+		fixture->connection.localConf.protocolVersion = 0;
+		fixture->connection.localConf.recvBufferSize = BUFFER_SIZE;
+		fixture->connection.localConf.recvBufferSize = BUFFER_SIZE;
+		fixture->connection.connectionHandle = fixtureHandle;
+	}
+	return fixtureHandle;
+}
+/** @brief free the allocated memory of the stackTestFixture associated with the handle */
+UA_Int32 stackTestFixture_delete(UA_UInt32 fixtureHandle) {
+	if (fixtureHandle < MAX_FIXTURES) {
+		UA_free(fixtures[fixtureHandle]);
+		stackTestFixture_markHandleAsFree(fixtureHandle);
+		return UA_SUCCESS;
+	}
+	return UA_ERR_INVALID_VALUE;
+}
 
-/*
-START_TEST(decodeRequestHeader_test_validParameter)
-{
-		char testMessage = {0x00,0x00,0x72,0xf1,0xdc,0xc9,0x87,0x0b,
+/** @brief return the fixture associated with the handle */
+stackTestFixture* stackTestFixture_getFixture(UA_UInt32 fixtureHandle) {
+	if (fixtureHandle < MAX_FIXTURES && ( fixturesMap & (1 << fixtureHandle)))
+			return fixtures[fixtureHandle];
+	return UA_NULL;
+}
 
-							0xcf,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
-							0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,
-							0x00,0x00,0x00,0x00,0x00};
-		UA_ByteString rawMessage;
-		rawMessage.data = &testMessage;
-		rawMessage.length = 29;
-		Int32 position = 0;
-		T_RequestHeader requestHeader;
-		decodeRequestHeader(rawMessage,&position,&requestHeader);
+/** @brief write message provided in the gather buffers to the buffer of the fixture */
+UA_Int32 responseMsg(struct TL_Connection * c, UA_ByteString const ** gather_buf, UA_Int32 gather_len) {
+	UA_Int32 retval = UA_SUCCESS;
+	UA_UInt32 total_len = 0;
 
-		ck_assert_int_eq(requestHeader.authenticationToken.EncodingByte,0);
+	stackTestFixture* fixture = stackTestFixture_getFixture(c->connectionHandle);
 
-		ck_assert_int_eq(requestHeader.returnDiagnostics,0);
+	for (UA_Int32 i=0; i<gather_len && retval == UA_SUCCESS; ++i) {
+		if (total_len + gather_buf[i]->length < BUFFER_SIZE) {
+			memcpy(&(fixture->respMsg.data[total_len]),gather_buf[i]->data,gather_buf[i]->length);
+			total_len += gather_buf[i]->length;
+		} else {
+			retval = UA_ERR_NO_MEMORY;
+		}
+	}
+	fixture->respMsg.length = total_len;
+	return UA_SUCCESS;
+}
 
-		ck_assert_int_eq(requestHeader.authenticationToken.EncodingByte,0);
+void indicateMsg(UA_Int32 handle, UA_ByteString *slMessage) {
+	TL_Process(&(stackTestFixture_getFixture(handle)->connection), slMessage);
+}
 
+UA_Byte pkt_HEL[] = {
+            0x48, 0x45, 0x4c, 0x46, 0x39, 0x00, /*   HELF9. */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x01, 0x88, 0x13, 0x00, 0x00, 0x19, 0x00, /* ........ */
+0x00, 0x00, 0x6f, 0x70, 0x63, 0x2e, 0x74, 0x63, /* ..opc.tc */
+0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x30, 0x2e, 0x30, /* p://10.0 */
+0x2e, 0x35, 0x34, 0x2e, 0x37, 0x37, 0x3a, 0x34, /* .54.77:4 */
+0x38, 0x34, 0x32                                /* 842 */
+};
+UA_Byte pkt_OPN[] = {
+            0x4f, 0x50, 0x4e, 0x46, 0x85, 0x00, /*   OPNF.. */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, /* ....../. */
+0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, /* ..http:/ */
+0x2f, 0x6f, 0x70, 0x63, 0x66, 0x6f, 0x75, 0x6e, /* /opcfoun */
+0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6f, /* dation.o */
+0x72, 0x67, 0x2f, 0x55, 0x41, 0x2f, 0x53, 0x65, /* rg/UA/Se */
+0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x50, 0x6f, /* curityPo */
+0x6c, 0x69, 0x63, 0x79, 0x23, 0x4e, 0x6f, 0x6e, /* licy#Non */
+0x65, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* e....... */
+0xff, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* .3...... */
+0x00, 0x01, 0x00, 0xbe, 0x01, 0x00, 0x00, 0x40, /* .......@ */
+0xaf, 0xfc, 0xe8, 0xa1, 0x76, 0xcf, 0x01, 0x00, /* ....v... */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* ........ */
+0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, /* ........ */
+0x00, 0x00, 0x00, 0x80, 0xee, 0x36, 0x00        /* .....6. */
+};
+
+UA_Byte pkt_MSG_CreateSession[] = {
+0x4d, 0x53, 0x47, 0x46, 0xb4, 0x05, 0x00, 0x00, /* MSGF.... */
+0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* QQ...... */  // assumes fixed secureChannelID=25 !
+0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, /* 4....... */
+0x01, 0x00, 0xcd, 0x01, 0x00, 0x00, 0x50, 0xd6, /* ......P. */
+0xfc, 0xe8, 0xa1, 0x76, 0xcf, 0x01, 0x01, 0x00, /* ...v.... */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* ........ */
+0xff, 0xff, 0x10, 0x27, 0x00, 0x00, 0x00, 0x00, /* ...'.... */
+0x00, 0x2d, 0x00, 0x00, 0x00, 0x75, 0x72, 0x6e, /* .-...urn */
+0x3a, 0x6d, 0x72, 0x74, 0x2d, 0x56, 0x69, 0x72, /* :mrt-Vir */
+0x74, 0x75, 0x61, 0x6c, 0x42, 0x6f, 0x78, 0x3a, /* tualBox: */
+0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x41, /* UnifiedA */
+0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x6f, /* utomatio */
+0x6e, 0x3a, 0x55, 0x61, 0x45, 0x78, 0x70, 0x65, /* n:UaExpe */
+0x72, 0x74, 0x1e, 0x00, 0x00, 0x00, 0x75, 0x72, /* rt....ur */
+0x6e, 0x3a, 0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, /* n:Unifie */
+0x64, 0x41, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, /* dAutomat */
+0x69, 0x6f, 0x6e, 0x3a, 0x55, 0x61, 0x45, 0x78, /* ion:UaEx */
+0x70, 0x65, 0x72, 0x74, 0x02, 0x1b, 0x00, 0x00, /* pert.... */
+0x00, 0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, /* .Unified */
+0x20, 0x41, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, /*  Automat */
+0x69, 0x6f, 0x6e, 0x20, 0x55, 0x61, 0x45, 0x78, /* ion UaEx */
+0x70, 0x65, 0x72, 0x74, 0x01, 0x00, 0x00, 0x00, /* pert.... */
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* ........ */
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, /* ........ */
+0x19, 0x00, 0x00, 0x00, 0x6f, 0x70, 0x63, 0x2e, /* ....opc. */
+0x74, 0x63, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x30, /* tcp://10 */
+0x2e, 0x30, 0x2e, 0x35, 0x34, 0x2e, 0x37, 0x37, /* .0.54.77 */
+0x3a, 0x34, 0x38, 0x34, 0x32, 0x2d, 0x00, 0x00, /* :4842-.. */
+0x00, 0x75, 0x72, 0x6e, 0x3a, 0x6d, 0x72, 0x74, /* .urn:mrt */
+0x2d, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, /* -Virtual */
+0x42, 0x6f, 0x78, 0x3a, 0x55, 0x6e, 0x69, 0x66, /* Box:Unif */
+0x69, 0x65, 0x64, 0x41, 0x75, 0x74, 0x6f, 0x6d, /* iedAutom */
+0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x55, 0x61, /* ation:Ua */
+0x45, 0x78, 0x70, 0x65, 0x72, 0x74, 0x20, 0x00, /* Expert . */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x72, 0x04, 0x00, 0x00, 0x30, 0x82, /* ..r...0. */
+0x04, 0x6e, 0x30, 0x82, 0x03, 0xd7, 0xa0, 0x03, /* .n0..... */
+0x02, 0x01, 0x02, 0x02, 0x04, 0x53, 0x1b, 0x10, /* .....S.. */
+0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, /* .0...*.H */
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, /* ........ */
+0x30, 0x81, 0x93, 0x31, 0x0b, 0x30, 0x09, 0x06, /* 0..1.0.. */
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, /* .U....DE */
+0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, /* 1.0...U. */
+0x08, 0x13, 0x08, 0x41, 0x6e, 0x79, 0x77, 0x68, /* ...Anywh */
+0x65, 0x72, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, /* ere1.0.. */
+0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x41, 0x6e, /* .U....An */
+0x79, 0x77, 0x68, 0x65, 0x72, 0x65, 0x31, 0x13, /* ywhere1. */
+0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, /* 0...U... */
+0x0a, 0x54, 0x55, 0x20, 0x44, 0x72, 0x65, 0x73, /* .TU Dres */
+0x64, 0x65, 0x6e, 0x31, 0x36, 0x30, 0x34, 0x06, /* den1604. */
+0x03, 0x55, 0x04, 0x0b, 0x13, 0x2d, 0x43, 0x68, /* .U...-Ch */
+0x61, 0x69, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, /* air for  */
+0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, /* Process  */
+0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, /* Control  */
+0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, /* Systems  */
+0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, /* Engineer */
+0x69, 0x6e, 0x67, 0x31, 0x11, 0x30, 0x0f, 0x06, /* ing1.0.. */
+0x03, 0x55, 0x04, 0x03, 0x13, 0x08, 0x55, 0x61, /* .U....Ua */
+0x45, 0x78, 0x70, 0x65, 0x72, 0x74, 0x30, 0x1e, /* Expert0. */
+0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x30, 0x38, /* ..140308 */
+0x31, 0x32, 0x34, 0x34, 0x31, 0x35, 0x5a, 0x17, /* 124415Z. */
+0x0d, 0x31, 0x34, 0x30, 0x33, 0x30, 0x38, 0x31, /* .1403081 */
+0x33, 0x34, 0x34, 0x31, 0x35, 0x5a, 0x30, 0x81, /* 34415Z0. */
+0x93, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, /* .1.0...U */
+0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x31, 0x11, /* ....DE1. */
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, /* 0...U... */
+0x08, 0x41, 0x6e, 0x79, 0x77, 0x68, 0x65, 0x72, /* .Anywher */
+0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, /* e1.0...U */
+0x04, 0x07, 0x13, 0x08, 0x41, 0x6e, 0x79, 0x77, /* ....Anyw */
+0x68, 0x65, 0x72, 0x65, 0x31, 0x13, 0x30, 0x11, /* here1.0. */
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x54, /* ..U....T */
+0x55, 0x20, 0x44, 0x72, 0x65, 0x73, 0x64, 0x65, /* U Dresde */
+0x6e, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, /* n1604..U */
+0x04, 0x0b, 0x13, 0x2d, 0x43, 0x68, 0x61, 0x69, /* ...-Chai */
+0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x50, 0x72, /* r for Pr */
+0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x43, 0x6f, /* ocess Co */
+0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x53, 0x79, /* ntrol Sy */
+0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x45, 0x6e, /* stems En */
+0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, /* gineerin */
+0x67, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, /* g1.0...U */
+0x04, 0x03, 0x13, 0x08, 0x55, 0x61, 0x45, 0x78, /* ....UaEx */
+0x70, 0x65, 0x72, 0x74, 0x30, 0x81, 0x9f, 0x30, /* pert0..0 */
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, /* ...*.H.. */
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, /* ........ */
+0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, /* ..0..... */
+0x00, 0xb3, 0xb3, 0xc9, 0x97, 0xb7, 0x4f, 0x6d, /* ......Om */
+0x6f, 0x72, 0x48, 0xe2, 0x5f, 0x8c, 0x89, 0x0f, /* orH._... */
+0xc3, 0x47, 0x17, 0x4c, 0xd2, 0x8c, 0x2a, 0x85, /* .G.L..*. */
+0xf6, 0x80, 0xb1, 0x9e, 0xf4, 0x90, 0xff, 0x0f, /* ........ */
+0xff, 0x42, 0x74, 0x75, 0xcd, 0xd5, 0xe0, 0x8f, /* .Btu.... */
+0x7f, 0xa1, 0x41, 0x86, 0x83, 0xcf, 0x2c, 0xef, /* ..A...,. */
+0xbd, 0xb7, 0xbf, 0x50, 0xa9, 0x5c, 0xfa, 0x39, /* ...P.\.9 */
+0x84, 0xbb, 0x7e, 0xc9, 0x7e, 0x5b, 0xc8, 0x1b, /* ..~.~[.. */
+0x19, 0xfc, 0x31, 0x05, 0xa9, 0x0c, 0x31, 0x3c, /* ..1...1< */
+0x1a, 0x86, 0x50, 0x17, 0x45, 0x0a, 0xfd, 0xfe, /* ..P.E... */
+0xa0, 0xc4, 0x88, 0x93, 0xff, 0x1c, 0xf3, 0x60, /* .......` */
+0x06, 0xc6, 0xdf, 0x7c, 0xc6, 0xcd, 0x95, 0x7d, /* ...|...} */
+0xf8, 0x3b, 0x7a, 0x53, 0x15, 0xbb, 0x2e, 0xcf, /* .;zS.... */
+0xd1, 0x63, 0xae, 0x5a, 0x30, 0x48, 0x67, 0x5f, /* .c.Z0Hg_ */
+0xa8, 0x30, 0x7f, 0x35, 0xe4, 0x43, 0x94, 0xa3, /* .0.5.C.. */
+0xc1, 0xfe, 0x69, 0xcd, 0x5c, 0xd7, 0x88, 0xc0, /* ..i.\... */
+0xa5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, /* ........ */
+0x01, 0xcb, 0x30, 0x82, 0x01, 0xc7, 0x30, 0x0c, /* ..0...0. */
+0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, /* ..U..... */
+0x04, 0x02, 0x30, 0x00, 0x30, 0x50, 0x06, 0x09, /* ..0.0P.. */
+0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, /* `.H...B. */
+0x0d, 0x04, 0x43, 0x16, 0x41, 0x22, 0x47, 0x65, /* ..C.A"Ge */
+0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, /* nerated  */
+0x77, 0x69, 0x74, 0x68, 0x20, 0x55, 0x6e, 0x69, /* with Uni */
+0x66, 0x69, 0x65, 0x64, 0x20, 0x41, 0x75, 0x74, /* fied Aut */
+0x6f, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, /* omation  */
+0x55, 0x41, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, /* UA Base  */
+0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x20, /* Library  */
+0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4f, 0x70, /* using Op */
+0x65, 0x6e, 0x53, 0x53, 0x4c, 0x22, 0x30, 0x1d, /* enSSL"0. */
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, /* ..U..... */
+0x14, 0x37, 0x39, 0x34, 0x93, 0xa2, 0x65, 0xef, /* .794..e. */
+0xb9, 0xd4, 0x71, 0x21, 0x4b, 0x77, 0xdb, 0x28, /* ..q!Kw.( */
+0xc8, 0xfa, 0x03, 0xfe, 0x05, 0x30, 0x81, 0xc3, /* .....0.. */
+0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xbb, /* ..U.#... */
+0x30, 0x81, 0xb8, 0x80, 0x14, 0x37, 0x39, 0x34, /* 0....794 */
+0x93, 0xa2, 0x65, 0xef, 0xb9, 0xd4, 0x71, 0x21, /* ..e...q! */
+0x4b, 0x77, 0xdb, 0x28, 0xc8, 0xfa, 0x03, 0xfe, /* Kw.(.... */
+0x05, 0xa1, 0x81, 0x99, 0xa4, 0x81, 0x96, 0x30, /* .......0 */
+0x81, 0x93, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, /* ..1.0... */
+0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x31, /* U....DE1 */
+0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x08, /* .0...U.. */
+0x13, 0x08, 0x41, 0x6e, 0x79, 0x77, 0x68, 0x65, /* ..Anywhe */
+0x72, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, /* re1.0... */
+0x55, 0x04, 0x07, 0x13, 0x08, 0x41, 0x6e, 0x79, /* U....Any */
+0x77, 0x68, 0x65, 0x72, 0x65, 0x31, 0x13, 0x30, /* where1.0 */
+0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, /* ...U.... */
+0x54, 0x55, 0x20, 0x44, 0x72, 0x65, 0x73, 0x64, /* TU Dresd */
+0x65, 0x6e, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, /* en1604.. */
+0x55, 0x04, 0x0b, 0x13, 0x2d, 0x43, 0x68, 0x61, /* U...-Cha */
+0x69, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x50, /* ir for P */
+0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x43, /* rocess C */
+0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x53, /* ontrol S */
+0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x45, /* ystems E */
+0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, /* ngineeri */
+0x6e, 0x67, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, /* ng1.0... */
+0x55, 0x04, 0x03, 0x13, 0x08, 0x55, 0x61, 0x45, /* U....UaE */
+0x78, 0x70, 0x65, 0x72, 0x74, 0x82, 0x04, 0x53, /* xpert..S */
+0x1b, 0x10, 0x9f, 0x30, 0x0e, 0x06, 0x03, 0x55, /* ...0...U */
+0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, /* ........ */
+0x02, 0x02, 0xf4, 0x30, 0x20, 0x06, 0x03, 0x55, /* ...0 ..U */
+0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, /* .%.....0 */
+0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, /* ...+.... */
+0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, /* .....+.. */
+0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x4e, 0x06, /* .....0N. */
+0x03, 0x55, 0x1d, 0x11, 0x04, 0x47, 0x30, 0x45, /* .U...G0E */
+0x86, 0x2d, 0x75, 0x72, 0x6e, 0x3a, 0x6d, 0x72, /* .-urn:mr */
+0x74, 0x2d, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, /* t-Virtua */
+0x6c, 0x42, 0x6f, 0x78, 0x3a, 0x55, 0x6e, 0x69, /* lBox:Uni */
+0x66, 0x69, 0x65, 0x64, 0x41, 0x75, 0x74, 0x6f, /* fiedAuto */
+0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x55, /* mation:U */
+0x61, 0x45, 0x78, 0x70, 0x65, 0x72, 0x74, 0x82, /* aExpert. */
+0x0e, 0x6d, 0x72, 0x74, 0x2d, 0x56, 0x69, 0x72, /* .mrt-Vir */
+0x74, 0x75, 0x61, 0x6c, 0x42, 0x6f, 0x78, 0x87, /* tualBox. */
+0x04, 0xc0, 0xa8, 0x02, 0x73, 0x30, 0x0d, 0x06, /* ....s0.. */
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, /* .*.H.... */
+0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, /* ........ */
+0x77, 0x2c, 0x9c, 0x23, 0x60, 0x13, 0x3f, 0xa5, /* w,.#`.?. */
+0xc8, 0xb3, 0x20, 0x27, 0x64, 0xda, 0x7f, 0xaa, /* .. 'd... */
+0xc5, 0x86, 0xfa, 0xd7, 0x24, 0x2e, 0xbe, 0xa0, /* ....$... */
+0xfc, 0x49, 0x8f, 0xc0, 0xef, 0xfb, 0x9a, 0xe6, /* .I...... */
+0x50, 0xe6, 0xb3, 0x53, 0x91, 0x91, 0x89, 0xd3, /* P..S.... */
+0x5a, 0xa5, 0xc9, 0x9c, 0xf6, 0x7b, 0x8f, 0x93, /* Z....{.. */
+0xb4, 0x98, 0xc3, 0x92, 0x26, 0x49, 0x8a, 0x96, /* ....&I.. */
+0x6e, 0x8f, 0xf5, 0x93, 0x48, 0x90, 0x9e, 0x7e, /* n...H..~ */
+0x1d, 0xad, 0x63, 0xbb, 0x5e, 0x1c, 0x0c, 0x86, /* ..c.^... */
+0x2d, 0xce, 0xe2, 0xe1, 0x87, 0x8d, 0x4c, 0x4b, /* -.....LK */
+0x89, 0x24, 0x77, 0xff, 0x62, 0x95, 0xf7, 0xec, /* .$w.b... */
+0x16, 0x7c, 0x8a, 0x1e, 0x4d, 0x89, 0xcb, 0x3d, /* .|..M..= */
+0xc8, 0xc0, 0x7c, 0x12, 0x5a, 0x29, 0xf2, 0xe7, /* ..|.Z).. */
+0x68, 0xf9, 0xb9, 0x85, 0xe5, 0xc0, 0x46, 0xac, /* h.....F. */
+0x89, 0xdb, 0xd0, 0x87, 0xaa, 0xa1, 0x7a, 0x73, /* ......zs */
+0x71, 0xcc, 0x8e, 0x01, 0x80, 0xf3, 0x07, 0x70, /* q......p */
+0x00, 0x00, 0x00, 0x00, 0x80, 0x4f, 0x32, 0x41, /* .....O2A */
+0xff, 0xff, 0xff, 0xff                          /* .... */
+};
+
+START_TEST(emptyIndicationShallYieldNoResponse)
+{
+	// given
+	UA_Int32 handle = stackTestFixture_create(responseMsg);
+	UA_ByteString message = { -1, (UA_Byte*) UA_NULL };
+
+	// when
+	indicateMsg(handle, &message);
+
+	// then
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.length,0);
+
+	// finally
+	stackTestFixture_delete(handle);
 }
 END_TEST
-*/
 
-START_TEST(encode_builtInDatatypeArray_test_String)
+
+START_TEST(validHELIndicationShallYieldACKResponse)
 {
-	UA_Int32 noElements = 2;
-	UA_ByteString s1 = { 6, (UA_Byte*) "OPC UA" };
-	UA_ByteString s2 = { -1, UA_NULL };
-	UA_ByteString* array[] = { &s1, &s2	};
-	UA_Int32 pos = 0;
-	UA_Byte buf[256];
-	UA_ByteString dst = { sizeof(buf), buf };
-	UA_Byte result[] = {
-			0x02, 0x00, 0x00, 0x00,		// noElements
-			0x06, 0x00, 0x00, 0x00,		// s1.Length
-			'O', 'P', 'C', ' ', 'U', 'A', // s1.Data
-			0xFF, 0xFF, 0xFF, 0xFF		// s2.Length
-	};
-
-	UA_Array_encodeBinary((void const**)array, noElements, UA_BYTESTRING, &pos, &dst);
-
-	// check size
-	ck_assert_int_eq(pos, 4 + 4 + 6 + 4);
-	ck_assert_int_eq(pos, sizeof(result));
-	// check result
-	ck_assert_int_eq(buf[0],result[0]);
-	ck_assert_int_eq(buf[1],result[1]);
-	ck_assert_int_eq(buf[2],result[2]);
-	ck_assert_int_eq(buf[3],result[3]);
-	ck_assert_int_eq(buf[4],result[4]);
-	ck_assert_int_eq(buf[5],result[5]);
-	ck_assert_int_eq(buf[6],result[6]);
-	ck_assert_int_eq(buf[7],result[7]);
-	ck_assert_int_eq(buf[8],result[8]);
-	ck_assert_int_eq(buf[9],result[9]);
-	ck_assert_int_eq(buf[10],result[10]);
-	ck_assert_int_eq(buf[11],result[11]);
-	ck_assert_int_eq(buf[12],result[12]);
-	ck_assert_int_eq(buf[13],result[13]);
-	ck_assert_int_eq(buf[14],result[14]);
-	ck_assert_int_eq(buf[15],result[15]);
-	ck_assert_int_eq(buf[16],result[16]);
-	ck_assert_int_eq(buf[17],result[17]);
+	// given
+	UA_Int32 handle = stackTestFixture_create(responseMsg);
+	UA_ByteString message_001 = { sizeof(pkt_HEL), pkt_HEL };
+
+	// when
+	indicateMsg(handle, &message_001);
+
+	// then
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.length,28);
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[0],'A');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[1],'C');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[2],'K');
+
+	// finally
+	stackTestFixture_delete(handle);
 }
 END_TEST
 
-/**Suite *testSuite_getPacketType(void)
+START_TEST(validOpeningSequenceShallCreateChannel)
 {
-	Suite *s = suite_create("getPacketType");
-	TCase *tc_core = tcase_create("Core");
-	tcase_add_test(tc_core,test_getPacketType_validParameter);
-	suite_add_tcase(s,tc_core);
-	return s;
-}**/
+	// given
+	UA_Int32 handle = stackTestFixture_create(responseMsg);
+
+	UA_ByteString message_001 = { sizeof(pkt_HEL), pkt_HEL };
+	UA_ByteString message_002 = { sizeof(pkt_OPN), pkt_OPN };
+
+	// when
+	indicateMsg(handle, &message_001);
+	indicateMsg(handle, &message_002);
+
+	// then
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[0],'O');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[1],'P');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[2],'N');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->connection.connectionState, CONNECTIONSTATE_ESTABLISHED);
+
+	// finally
+	stackTestFixture_delete(handle);
+}
+END_TEST
 
-Suite* testSuite_encode_builtInDatatypeArray()
+START_TEST(validCreateSessionShallCreateSession)
 {
-	Suite *s = suite_create("encode_builtInDatatypeArray");
-	TCase *tc_core = tcase_create("Core");
-	tcase_add_test(tc_core, encode_builtInDatatypeArray_test_String);
-	suite_add_tcase(s,tc_core);
-	return s;
+	// given
+	UA_Int32 handle = stackTestFixture_create(responseMsg);
+
+	UA_ByteString message_001 = { sizeof(pkt_HEL), pkt_HEL };
+	UA_ByteString message_002 = { sizeof(pkt_OPN), pkt_OPN };
+	UA_ByteString message_003 = { sizeof(pkt_MSG_CreateSession), pkt_MSG_CreateSession };
+
+	// when
+	indicateMsg(handle, &message_001);
+	indicateMsg(handle, &message_002);
+	UA_Int32 pos = 8;
+	UA_UInt32 secureChannelId = stackTestFixture_getFixture(handle)->connection.secureChannel->securityToken.secureChannelId;
+	UA_UInt32_encodeBinary(&secureChannelId,&pos,&message_003);
+	indicateMsg(handle, &message_003);
+
+	// then
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[0],'M');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[1],'S');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[2],'G');
+	ck_assert_ptr_ne(stackTestFixture_getFixture(handle)->connection.secureChannel, UA_NULL);
+
+	// finally
+	stackTestFixture_delete(handle);
 }
+END_TEST
 
-/*
-Suite* TL_<TESTSUITENAME>(void)
+Suite* testSuite()
 {
-	Suite *s = suite_create("<TESTSUITENAME>");
+	Suite *s = suite_create("Stack Test");
 	TCase *tc_core = tcase_create("Core");
-	tcase_add_test(tc_core,<TEST_NAME>);
+	tcase_add_test(tc_core, emptyIndicationShallYieldNoResponse);
+	tcase_add_test(tc_core, validHELIndicationShallYieldACKResponse);
+	tcase_add_test(tc_core, validOpeningSequenceShallCreateChannel);
+	tcase_add_test(tc_core, validCreateSessionShallCreateSession);
 	suite_add_tcase(s,tc_core);
 	return s;
 }
-*/
-
 
 int main (void)
 {
@@ -138,27 +453,13 @@ int main (void)
 	Suite *s;
 	SRunner *sr;
 
-	/* s = testSuite_getPacketType();
-	sr = srunner_create(s);
-	srunner_run_all(sr,CK_NORMAL);
-	number_failed = srunner_ntests_failed(sr);
-	srunner_free(sr); */
-
-	s = testSuite_encode_builtInDatatypeArray();
+	s = testSuite();
 	sr = srunner_create(s);
 	srunner_run_all(sr,CK_NORMAL);
 	number_failed += srunner_ntests_failed(sr);
 	srunner_free(sr);
 
-	/* <TESTSUITE_TEMPLATE>
-	s =  <TESTSUITENAME>;
-	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;
-
 }
 
 

+ 142 - 144
tools/generate_builtin.py

@@ -8,30 +8,24 @@ import re
 from lxml import etree
 
 if len(sys.argv) != 3:
-    print("Usage: python generate_builtin.py <path/to/Opc.Ua.Types.bsd> <outfile w/o extension>", file=sys.stdout)
-    exit(0)
+	print("Usage: python generate_builtin.py <path/to/Opc.Ua.Types.bsd> <outfile w/o extension>", file=sys.stdout)
+	exit(0)
 
 # types that are coded manually 
 exclude_types = set(["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
-                    "Int64", "UInt64", "Float", "Double", "String", "DateTime", "Guid",
-                    "ByteString", "XmlElement", "NodeId", "ExpandedNodeId", "StatusCode", 
-                    "QualifiedName", "LocalizedText", "ExtensionObject", "DataValue",
-                     "Variant", "DiagnosticInfo", "IntegerId"])
-
-elementary_size = dict()
-elementary_size["Boolean"] = 1;
-elementary_size["SByte"] = 1;
-elementary_size["Byte"] = 1;
-elementary_size["Int16"] = 2;
-elementary_size["UInt16"] = 2;
-elementary_size["Int32"] = 4;
-elementary_size["UInt32"] = 4;
-elementary_size["Int64"] = 8;
-elementary_size["UInt64"] = 8;
-elementary_size["Float"] = 4;
-elementary_size["Double"] = 8;
-elementary_size["DateTime"] = 8;
-elementary_size["StatusCode"] = 4;
+					"Int64", "UInt64", "Float", "Double", "String", "DateTime", "Guid",
+					"ByteString", "XmlElement", "NodeId", "ExpandedNodeId", "StatusCode", 
+					"QualifiedName", "LocalizedText", "ExtensionObject", "DataValue",
+					 "Variant", "DiagnosticInfo", "IntegerId"])
+
+# do not forget to get rid of these excludes once it works
+exclude_xml_decode = set(["UA_ReferenceNode", "UA_ObjectNode", "UA_VariableNode", "UA_DataTypeNode"])
+
+elementary_size = {"Boolean":1, "SByte":1, "Byte":1, "Int16":2, "UInt16":2, "Int32":4, "UInt32":4,
+                   "Int64":8, "UInt64":8, "Float":4, "Double":8, "DateTime":8, "StatusCode":4}
+
+# do not forget to get rid of these excludes once it works
+exclude_xml_decode = set(["UA_ReferenceNode", "UA_ObjectNode", "UA_VariableNode", "UA_DataTypeNode"])
 
 enum_types = []
 structured_types = []
@@ -44,36 +38,31 @@ def skipType(name):
     if re.search("NodeId$", name) != None:
         return True
     return False
-
+    
 def stripTypename(tn):
-    return tn[tn.find(":")+1:]
+	return tn[tn.find(":")+1:]
 
-def camlCase2AdaCase(item):
-    (newitem, n) = re.subn("(?<!^)(?<![A-Z])([A-Z])", "_\\1", item)
-    return newitem
-    
 def camlCase2CCase(item):
-    if item in ["Float","Double"]:
-        return "my" + item
-    return item[:1].lower() + item[1:] if item else ''
+	if item in ["Float","Double"]:
+		return "my" + item
+	return item[:1].lower() + item[1:] if item else ''
 
-# are the prerequisites in place? if not, postpone.
+# are the types we need already in place? if not, postpone.
 def printableStructuredType(element):
-    for child in element:
-        if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
-            typename = stripTypename(child.get("TypeName"))
-            if typename not in printed_types:
-                return False
-    return True
-
-# There three types of types in the bsd file:
+	for child in element:
+		if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
+			typename = stripTypename(child.get("TypeName"))
+			if typename not in printed_types:
+				return False
+	return True
+
+# There are three types of types in the bsd file:
 # StructuredType, EnumeratedType OpaqueType
 
-def createEnumerated(element):
+def createEnumerated(element):	
     valuemap = OrderedDict()
     name = "UA_" + element.get("Name")
     enum_types.append(name)
-    print("\n/** @name UA_" + name + " */", end='\n', file=fh)
     for child in element:
         if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
             print("/** @brief " + child.text + " */", end='\n', file=fh)
@@ -91,6 +80,7 @@ def createEnumerated(element):
     print("UA_TYPE_METHOD_INIT_AS("+name+", UA_UInt32)", end='\n', file=fc)
     print("UA_TYPE_METHOD_COPY_AS("+name+", UA_UInt32)",'\n', file=fc)  
     print("UA_TYPE_METHOD_NEW_DEFAULT("+name+")\n", end='\n', file=fc)
+    print("UA_TYPE_METHOD_DECODEXML_NOTIMPL("+name+")", end='\n', file=fc)
     return
     
 def createStructured(element):
@@ -100,9 +90,9 @@ def createStructured(element):
 
     lengthfields = set()
     for child in element:
-        if child.get("LengthField"):
-            lengthfields.add(child.get("LengthField"))
-    
+		if child.get("LengthField"):
+			lengthfields.add(child.get("LengthField"))
+	
     for child in element:
         if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
             print("/** @brief " + child.text + " */", end='\n', file=fh)
@@ -116,26 +106,21 @@ def createStructured(element):
             else:
                 valuemap[childname] = typename
 
-    # if "Response" in name[len(name)-9:]:
-    #    print("type " + name + " is new Response_Base with "),
-    # elif "Request" in name[len(name)-9:]:
-    #    print ("type " + name + " is new Request_Base with "),
-    # else:
-    #    print ("type " + name + " is new UA_Builtin with "),
     print("typedef struct " + name + " {", end='\n', file=fh)
     if len(valuemap) == 0:
-        typename = stripTypename(element.get("BaseType"))
-        childname = camlCase2CCase(typename)
-        valuemap[childname] = typename 
+		typename = stripTypename(element.get("BaseType"))
+		childname = camlCase2CCase(typename)
+		valuemap[childname] = typename 
     for n,t in valuemap.iteritems():
-        if t.find("**") != -1:
-            print("\t" + "UA_Int32 " + n + "Size;", end='\n', file=fh)
-        print("\t" + "UA_" + t + " " + n + ";", end='\n', file=fh)
+		if t.find("**") != -1:
+			print("\t" + "UA_Int32 " + n + "Size;", end='\n', file=fh)
+		print("\t" + "UA_" + t + " " + n + ";", end='\n', file=fh)
     print("} " + name + ";", end='\n', file=fh)
 
     print("UA_Int32 " + name + "_calcSize(" + name + " const* ptr);", end='\n', file=fh)
     print("UA_Int32 " + name + "_encodeBinary(" + name + " const* src, UA_Int32* pos, UA_ByteString* dst);", end='\n', file=fh)
     print("UA_Int32 " + name + "_decodeBinary(UA_ByteString const* src, UA_Int32* pos, " + name + "* dst);", end='\n', file=fh)
+    print("UA_Int32 " + name + "_decodeXML(XML_Stack* s, XML_Attr* attr, " + name + "* dst, _Bool isStart);", end='\n', file=fh)
     print("UA_Int32 " + name + "_delete("+ name + "* p);", end='\n', file=fh)
     print("UA_Int32 " + name + "_deleteMembers(" + name + "* p);", end='\n', file=fh)
     print("UA_Int32 " + name + "_init("+ name + " * p);", end='\n', file=fh)
@@ -146,41 +131,41 @@ def createStructured(element):
     print("\n\tif(ptr==UA_NULL){return sizeof("+ name +");}", end='', file=fc)
     print("\n\treturn 0", end='', file=fc)
 
-    # code _calcSize
+	# code _calcSize
     for n,t in valuemap.iteritems():
-        if t in elementary_size:
-            print('\n\t + sizeof(UA_' + t + ") // " + n, end='', file=fc)
-        else:
-            if t in enum_types:
-                print('\n\t + 4 //' + n, end='', file=fc) # enums are all 32 bit
-            elif t.find("**") != -1:
-		print("\n\t + 0 //" + n + "Size is included in UA_Array_calcSize", end='', file=fc),
-		print("\n\t + UA_Array_calcSize(ptr->" + n + "Size, UA_" + t[0:t.find("*")].upper() + ", (void const**) ptr->" + n +")", end='', file=fc)
-            elif t.find("*") != -1:
-                print('\n\t + ' + "UA_" + t[0:t.find("*")] + "_calcSize(ptr->" + n + ')', end='', file=fc)
-            else:
-                print('\n\t + ' + "UA_" + t + "_calcSize(&(ptr->" + n + '))', end='', file=fc)
+		if t in elementary_size:
+			print('\n\t + sizeof(UA_' + t + ") // " + n, end='', file=fc)
+		else:
+			if t in enum_types:
+				print('\n\t + 4 //' + n, end='', file=fc) # enums are all 32 bit
+			elif t.find("**") != -1:
+				print("\n\t + 0 //" + n + "Size is included in UA_Array_calcSize", end='', file=fc),
+				print("\n\t + UA_Array_calcSize(ptr->" + n + "Size, UA_" + t[0:t.find("*")].upper() + ", (void const**) ptr->" + n +")", end='', file=fc)
+			elif t.find("*") != -1:
+				print('\n\t + ' + "UA_" + t[0:t.find("*")] + "_calcSize(ptr->" + n + ')', end='', file=fc)
+			else:
+				print('\n\t + ' + "UA_" + t + "_calcSize(&(ptr->" + n + '))', end='', file=fc)
 
     print("\n\t;\n}\n", end='\n', file=fc)
 
     print("UA_Int32 "+name+"_encodeBinary("+name+" const * src, UA_Int32* pos, UA_ByteString* dst) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
-    # code _encode
+	# code _encode
     for n,t in valuemap.iteritems():
-        if t in elementary_size:
-            print('\tretval |= UA_'+t+'_encodeBinary(&(src->'+n+'),pos,dst);', end='\n', file=fc)
-        else:
-            if t in enum_types:
-                print('\tretval |= UA_'+t+'_encodeBinary(&(src->'+n+'),pos,dst);', end='\n', file=fc)
-            elif t.find("**") != -1:
-                print('\t//retval |= UA_Int32_encodeBinary(&(src->'+n+'Size),pos,dst); // encode size managed by UA_Array_encodeBinary', end='\n', file=fc)
-		print("\tretval |= UA_Array_encodeBinary((void const**) (src->"+n+"),src->"+n+"Size, UA_" + t[0:t.find("*")].upper()+",pos,dst);", end='\n', file=fc)
-            elif t.find("*") != -1:
-                print('\tretval |= UA_' + t[0:t.find("*")] + "_encodeBinary(src->" + n + ',pos,dst);', end='\n', file=fc)
-            else:
-                print('\tretval |= UA_'+t+"_encodeBinary(&(src->"+n+"),pos,dst);", end='\n', file=fc)
+		if t in elementary_size:
+			print('\tretval |= UA_'+t+'_encodeBinary(&(src->'+n+'),pos,dst);', end='\n', file=fc)
+		else:
+			if t in enum_types:
+				print('\tretval |= UA_'+t+'_encodeBinary(&(src->'+n+'),pos,dst);', end='\n', file=fc)
+			elif t.find("**") != -1:
+				print('\t//retval |= UA_Int32_encodeBinary(&(src->'+n+'Size),pos,dst); // encode size managed by UA_Array_encodeBinary', end='\n', file=fc)
+				print("\tretval |= UA_Array_encodeBinary((void const**) (src->"+n+"),src->"+n+"Size, UA_" + t[0:t.find("*")].upper()+",pos,dst);", end='\n', file=fc)
+			elif t.find("*") != -1:
+				print('\tretval |= UA_' + t[0:t.find("*")] + "_encodeBinary(src->" + n + ',pos,dst);', end='\n', file=fc)
+			else:
+				print('\tretval |= UA_'+t+"_encodeBinary(&(src->"+n+"),pos,dst);", end='\n', file=fc)
     print("\treturn retval;\n}\n", end='\n', file=fc)
 
-    # code _decode
+	# code _decodeBinary
     print("UA_Int32 "+name+"_decodeBinary(UA_ByteString const * src, UA_Int32* pos, " + name + "* dst) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
     print('\t'+name+'_init(dst);', end='\n', file=fc)
     for n,t in valuemap.iteritems():
@@ -191,10 +176,13 @@ def createStructured(element):
                 print('\tCHECKED_DECODE(UA_'+t+'_decodeBinary(src,pos,&(dst->'+n+')), '+name+'_deleteMembers(dst));', end='\n', file=fc)
             elif t.find("**") != -1:
             	# decode size
-		print('\tCHECKED_DECODE(UA_Int32_decodeBinary(src,pos,&(dst->'+n+'Size)), '+name+'_deleteMembers(dst)); // decode size', end='\n', file=fc)
+		print('\tCHECKED_DECODE(UA_Int32_decodeBinary(src,pos,&(dst->'+n+'Size)), ' +
+                      name + '_deleteMembers(dst)); // decode size', end='\n', file=fc)
 		# allocate memory for array
-		print("\tCHECKED_DECODE(UA_Array_new((void***)&dst->"+n+", dst->"+n+"Size, UA_"+t[0:t.find("*")].upper()+"), dst->"+n+" = UA_NULL; "+name+'_deleteMembers(dst));', end='\n', file=fc)
-		print("\tCHECKED_DECODE(UA_Array_decodeBinary(src,dst->"+n+"Size, UA_" + t[0:t.find("*")].upper()+",pos,(void *** const) (&dst->"+n+")), "+name+'_deleteMembers(dst));', end='\n', file=fc)
+		print("\tCHECKED_DECODE(UA_Array_new((void***)&dst->"+n+", dst->"+n+"Size, UA_"+t[0:t.find("*")].upper()+"), dst->" +
+                      n + " = UA_NULL; "+name+'_deleteMembers(dst));', end='\n', file=fc)
+		print("\tCHECKED_DECODE(UA_Array_decodeBinary(src,dst->"+n+"Size, UA_" + t[0:t.find("*")].upper() +
+                      ",pos,(void *** const) (&dst->"+n+")), "+name+'_deleteMembers(dst));', end='\n', file=fc)
             elif t.find("*") != -1:
 		#allocate memory using new
 		print('\tCHECKED_DECODE(UA_'+ t[0:t.find("*")] +"_new(&(dst->" + n + ")), "+name+'_deleteMembers(dst));', end='\n', file=fc)
@@ -202,6 +190,12 @@ def createStructured(element):
             else:
                 print('\tCHECKED_DECODE(UA_'+t+"_decodeBinary(src,pos,&(dst->"+n+")), "+name+'_deleteMembers(dst));', end='\n', file=fc)
     print("\treturn retval;\n}\n", end='\n', file=fc)
+ 
+    if not name in exclude_xml_decode:
+        print("UA_Int32 "+name+"_decodeXML(XML_Stack* s, XML_Attr* attr, " + name + "* dst, _Bool isStart)", end='\n', file=fc)
+        print('''{
+        DBG_VERBOSE(printf("'''+name+'''_decodeXML entered with dst=%p,isStart=%d\\n", (void* ) dst, isStart));
+        return UA_ERR_NOT_IMPLEMENTED;}''', end='\n', file=fc)
     
     # code _delete and _deleteMembers
     print('UA_Int32 '+name+'_delete('+name+'''* p) {
@@ -209,13 +203,13 @@ def createStructured(element):
 	retval |= '''+name+'''_deleteMembers(p);
 	retval |= UA_free(p);
 	return retval;
-    }''', end='\n', file=fc)
-    
+}''', end='\n', file=fc)
+	
     print("UA_Int32 "+name+"_deleteMembers(" + name + "* p) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
     for n,t in valuemap.iteritems():
         if t not in elementary_size:
             if t.find("**") != -1:
-		print("\tretval |= UA_Array_delete((void***)&p->"+n+",p->"+n+"Size,UA_"+t[0:t.find("*")].upper()+"); p->"+n+" = UA_NULL;", end='\n', file=fc) #not tested
+		print("\tretval |= UA_Array_delete((void***)&p->"+n+",p->"+n+"Size,UA_"+t[0:t.find("*")].upper()+"); p->"+n+" = UA_NULL;", end='\n', file=fc)
             elif t.find("*") != -1:
 		print('\tretval |= UA_' + t[0:t.find("*")] + "_delete(p->"+n+");", end='\n', file=fc)
             else:
@@ -223,26 +217,26 @@ def createStructured(element):
 		
     print("\treturn retval;\n}\n", end='\n', file=fc)
 
-    # code _init
+	# code _init
     print("UA_Int32 "+name+"_init(" + name + " * p) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
     for n,t in valuemap.iteritems():
-        if t in elementary_size:
-            print('\tretval |= UA_'+t+'_init(&(p->'+n+'));', end='\n', file=fc)
-        else:
-            if t in enum_types:
-                print('\tretval |= UA_'+t+'_init(&(p->'+n+'));', end='\n', file=fc)
-            elif t.find("**") != -1:
+		if t in elementary_size:
+			print('\tretval |= UA_'+t+'_init(&(p->'+n+'));', end='\n', file=fc)
+		else:
+			if t in enum_types:
+				print('\tretval |= UA_'+t+'_init(&(p->'+n+'));', end='\n', file=fc)
+			elif t.find("**") != -1:
 				print('\tp->'+n+'Size=0;', end='\n', file=fc)
 				print("\tp->"+n+"=UA_NULL;", end='\n', file=fc)
-            elif t.find("*") != -1:
+			elif t.find("*") != -1:
 				print("\tp->"+n+"=UA_NULL;", end='\n', file=fc)
-            else:
-                print('\tretval |= UA_'+t+"_init(&(p->"+n+"));", end='\n', file=fc)
+			else:
+				print('\tretval |= UA_'+t+"_init(&(p->"+n+"));", end='\n', file=fc)
     print("\treturn retval;\n}\n", end='\n', file=fc)
 
-    # code _new
+	# code _new
     print("UA_TYPE_METHOD_NEW_DEFAULT(" + name + ")", end='\n', file=fc)
-    # code _copy
+	# code _copy
     print("UA_Int32 "+name+"_copy(" + name + " * src," + name + " * dst) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
     for n,t in valuemap.iteritems():
         if t in elementary_size:
@@ -252,13 +246,14 @@ def createStructured(element):
                 print('\tretval |= UA_'+t+'_copy(&(src->'+n+'),&(dst->'+n+'));', end='\n', file=fc)
             elif t.find("**") != -1:
                 print('\tretval |= UA_Int32_copy(&(src->'+n+'Size),&(dst->'+n+'Size)); // size of following array', end='\n', file=fc)
-		print("\tretval |= UA_Array_copy((void const* const*) (src->"+n+"), src->"+n+"Size," + "UA_"+t[0:t.find("*")].upper()+",(void***)&(dst->"+n+"));", end='\n', file=fc)
+		print("\tretval |= UA_Array_copy((void const* const*) (src->"+n+"), src->"+n+"Size," + "UA_" +
+                      t[0:t.find("*")].upper()+",(void***)&(dst->"+n+"));", end='\n', file=fc)
             elif t.find("*") != -1:
                 print('\tretval |= UA_' + t[0:t.find("*")] + '_copy(src->' + n + ',dst->' + n + ');', end='\n', file=fc)
             else:
                 print('\tretval |= UA_'+t+"_copy(&(src->"+n+"),&(dst->" + n + '));', end='\n', file=fc)
     print("\treturn retval;\n}\n", end='\n', file=fc)
-    
+	
 def createOpaque(element):
     name = "UA_" + element.get("Name")
     print("\n/** @name UA_" + name + " */", end='\n', file=fh)
@@ -271,51 +266,55 @@ def createOpaque(element):
     print("UA_TYPE_METHOD_CALCSIZE_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_ENCODEBINARY_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_DECODEBINARY_AS("+name+", UA_ByteString)", end='\n', file=fc)
+    print("UA_TYPE_METHOD_DECODEXML_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_DELETE_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_DELETEMEMBERS_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_INIT_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_COPY_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_NEW_DEFAULT("+name+")\n", end='\n', file=fc)
 
-    return
-
 ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
 tree = etree.parse(sys.argv[1])
 types = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
 
 fh = open(sys.argv[2] + ".hgen",'w');
 fc = open(sys.argv[2] + ".cgen",'w');
-print('''/**********************************************************
- * '''+sys.argv[2]+'''.cgen -- do not modify
- **********************************************************
+
+print('''/**
+ * @file '''+sys.argv[2]+'''.h
+ *
+ * @brief Autogenerated data types defined in the UA standard
+ *
  * Generated from '''+sys.argv[1]+''' with script '''+sys.argv[0]+'''
  * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser()+''' at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
- **********************************************************/
- 
+ */
+
+#ifndef OPCUA_H_
+#define OPCUA_H_
+
+#include "ua_basictypes.h"
+#include "ua_namespace_0.h"''', end='\n', file=fh);
+
+print('''/**
+ * @file '''+sys.argv[2]+'''.c
+ *
+ * @brief Autogenerated function implementations to manage the data types defined in the UA standard
+ *
+ * Generated from '''+sys.argv[1]+''' with script '''+sys.argv[0]+'''
+ * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser()+''' at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
+ */
+
 #include "''' + sys.argv[2] + '.h"', end='\n', file=fc);
 
 # types for which we create a vector type
 arraytypes = set()
 fields = tree.xpath("//opc:Field", namespaces=ns)
 for field in fields:
-    if field.get("LengthField"):
-        arraytypes.add(stripTypename(field.get("TypeName")))
+	if field.get("LengthField"):
+		arraytypes.add(stripTypename(field.get("TypeName")))
 
 deferred_types = OrderedDict()
 
-print('''/**********************************************************
- * '''+sys.argv[2]+'''.hgen -- do not modify
- **********************************************************
- * Generated from '''+sys.argv[1]+''' with script '''+sys.argv[0]+'''
- * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser()+''' at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
- **********************************************************/
-
-#ifndef OPCUA_H_
-#define OPCUA_H_
-
-#include "ua_basictypes.h"
-#include "ua_namespace_0.h"''', end='\n', file=fh);
-
 #plugin handling
 import os
 files = [f for f in os.listdir('.') if os.path.isfile(f) and f[-3:] == ".py" and f[:7] == "plugin_"]
@@ -333,24 +332,24 @@ for f in files:
 #end plugin handling
 
 for element in types:
-    name = element.get("Name")
-    if skipType(name):
-        continue
-        
-    if element.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
-        createEnumerated(element)
-        printed_types.add(name)
-    elif element.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
-        if printableStructuredType(element):
-            createStructured(element)
-            structured_types.append(name)
-            printed_types.add(name)
-        else: # the record contains types that were not yet detailed
-            deferred_types[name] = element
-            continue
-    elif element.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
-        createOpaque(element)
-        printed_types.add(name)
+	name = element.get("Name")
+	if skipType(name):
+		continue
+		
+	if element.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
+		createEnumerated(element)
+		printed_types.add(name)
+	elif element.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
+		if printableStructuredType(element):
+			createStructured(element)
+			structured_types.append(name)
+			printed_types.add(name)
+		else: # the record contains types that were not yet detailed
+			deferred_types[name] = element
+			continue
+	elif element.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
+		createOpaque(element)
+		printed_types.add(name)
 
 for name, element in deferred_types.iteritems():
 	if name in plugin_types:
@@ -364,4 +363,3 @@ for name, element in deferred_types.iteritems():
 print('#endif /* OPCUA_H_ */', end='\n', file=fh)
 fh.close()
 fc.close()
-

+ 86 - 72
tools/generate_namespace.py

@@ -2,20 +2,15 @@ from __future__ import print_function
 import sys
 import platform
 import getpass
-from collections import OrderedDict
 import time
-import re
-import csv
-from itertools import tee
 
 if len(sys.argv) != 3:
-    print("Usage: python generate_namespace.py <path/to/NodeIds.csv> <outfile w/o extension>", file=sys.stdout)
-    exit(0)
+	print("Usage: python generate_namespace.py <path/to/NodeIds.csv> <outfile w/o extension>", file=sys.stdout)
+	exit(0)
 
 # types that are to be excluded
-exclude_kind = set(["Object","ObjectType","Variable","Method","ReferenceType"])
-exclude_types = set(["Number", 
-    "Integer", "UInteger", "Enumeration",
+exclude_kinds = set(["Object","ObjectType","Variable","Method","ReferenceType"])
+exclude_types = set(["Number", "Integer", "UInteger", "Enumeration",
 	"Image", "ImageBMP", "ImageGIF", "ImageJPG", "ImagePNG",
 	"References", "BaseVariableType", "BaseDataVariableType", 
 	"PropertyType", "DataTypeDescriptionType", "DataTypeDictionaryType", "NamingRuleType",
@@ -34,21 +29,14 @@ exclude_types = set(["Number",
 	"YArrayItemType", "XYArrayItemType", "ImageItemType", "CubeItemType", "NDimensionArrayItemType"
 	])
 	
-def skipKind(name):
-    if name in exclude_kind:
-        return True
-    return False
-    
-def skipType(name):
-    if name in exclude_types:
-        return True
-    return False
-
 f = open(sys.argv[1])
-rows1, rows2, rows3 = tee(csv.reader(f), 3)
+input_str = f.read() + "\nInvalidType,0,DataType"
+input_str = input_str.replace('\r','')
+rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
+f.close()
 
-fh = open(sys.argv[2] + ".hgen",'w');
-fc = open(sys.argv[2] + ".cgen",'w');
+fh = open(sys.argv[2] + ".hgen",'w')
+fc = open(sys.argv[2] + ".cgen",'w')
 
 print('''/**********************************************************
  * '''+sys.argv[2]+'''.hgen -- do not modify
@@ -60,11 +48,27 @@ print('''/**********************************************************
 #ifndef OPCUA_NAMESPACE_0_H_
 #define OPCUA_NAMESPACE_0_H_
 
-#include "opcua.h"  // definition of UA_VTable and basic UA_Types
+#include "ua_basictypes.h"  // definition of UA_VTable and basic UA_Types
 
+/**
+ * @brief maps namespace zero nodeId to index into UA_VTable
+ *
+ * @param[in] ns0Id The namespace zero nodeId
+ *
+ * @retval UA_ERR_INVALID_VALUE whenever ns0Id could not be mapped
+ * @retval the corresponding index into UA_VTable
+ */
 UA_Int32 UA_ns0ToVTableIndex(UA_Int32 id);
 extern UA_VTable UA_[]; 
 
+static UA_Int32 phantom_delete(void * p) { return UA_SUCCESS; }
+extern UA_VTable UA_noDelete_[];
+
+/**
+ * @brief the set of possible indices into UA_VTable
+ *
+ * Enumerated type to define the types that the open62541 stack can handle
+ */
 enum UA_VTableIndex_enum {''', end='\n', file=fh)
 
 print('''/**********************************************************
@@ -76,77 +80,87 @@ print('''/**********************************************************
  
 #include "opcua.h"
 
-UA_Int32 UA_ns0ToVTableIndex(UA_Int32 id) {
-    UA_Int32 retval = UA_ERR_INVALID_VALUE;
-    switch (id) { ''', end='\n',file=fc)
+UA_Int32 UA_ns0ToVTableIndex(UA_Int32 ns0Id) {
+	UA_Int32 retval = UA_ERR_INVALID_VALUE;
+	switch (ns0Id) { ''', end='\n',file=fc)
 
 i = 0
-for row in rows1:
-    if skipKind(row[2]):
-	continue
-
-    if skipType(row[0]):
-	continue
-	
+for row in rows:
+    if row[0] == "" or row[0] in exclude_types or row[2] in exclude_kinds:
+        continue
     if row[0] == "BaseDataType":
     	name = "UA_Variant"
     elif row[0] == "Structure":
-    	name = "UA_ExtensionObject" 
-    else:	
-	name = "UA_" + row[0]
+        name = "UA_ExtensionObject"
+    else:
+        name = "UA_" + row[0]
 	
-    print("\t"+name.upper()+"="+str(i)+",", file=fh)
+    print("\t"+name.upper()+" = "+str(i)+",", file=fh)
     print('\tcase '+row[1]+': retval='+name.upper()+'; break; //'+row[2], file=fc)
     i = i+1
 
-print('\tUA_INVALIDTYPE = '+str(i)+'\n};\n', file=fh)
-print('''\tcase 0: retval=UA_INVALIDTYPE; break;
+print("};\n", file=fh)
+print('''
     }
     return retval;
 }
 
 UA_VTable UA_[] = {''', file=fc)
 
-for row in rows2:
-    if skipKind(row[2]):
-	continue
+for row in rows:
+    if row[0] == "" or row[0] in exclude_types or row[2] in exclude_kinds:
+        continue
+    if row[0] == "BaseDataType":
+    	name = "UA_Variant"
+    elif row[0] == "Structure":
+        name = "UA_ExtensionObject"
+    else:
+        name = "UA_" + row[0]
 
-    if skipType(row[0]):
-	continue
+    print('#define '+name.upper()+'_NS0 '+row[1], file=fh)
 
+    print("\t{" +
+          '(UA_Byte*)"'+ name +'",' +
+          row[1] + 
+          ",(UA_Int32(*)(void const*))"+ name +"_calcSize" + 
+          ",(UA_Int32(*)(UA_ByteString const*,UA_Int32*,void*))"+ name + "_decodeBinary" +
+          ",(UA_Int32(*)(void const*,UA_Int32*,UA_ByteString*))"+ name +"_encodeBinary"+
+          ",(UA_Int32(*)(XML_Stack*,XML_Attr*,void*,_Bool))"+ name + "_decodeXML" +
+          ",(UA_Int32(*)(void *))" + name + "_init" +
+          ",(UA_Int32(*)(void **))" + name + "_new" +
+	  ",(UA_Int32(*)(void const * ,void*))" + name + "_copy" +
+          ",(UA_Int32(*)(void *))" + name + "_delete" +
+          (",sizeof(" + name + ")" if (name != "UA_InvalidType") else ",0") +
+          "},",end='\n',file=fc) 
+
+print("};\n\nUA_VTable UA_noDelete_[] = {", end='\n', file=fc)
+
+for row in rows:
+    if row[0] == "" or row[0] in exclude_types or row[2] in exclude_kinds:
+        continue
     if row[0] == "BaseDataType":
-    	name = "UA_Variant"
+        name = "UA_Variant"
     elif row[0] == "Structure":
-    	name = "UA_ExtensionObject" 
+        name = "UA_ExtensionObject"
     else:	
 	name = "UA_" + row[0]
 
-    print('#define '+name.upper()+'_NS0 '+row[1], file=fh)
-
-    print("\t{" + row[1] + 
-          ",(UA_Int32(*)(void const*))"+name+"_calcSize" + 
-          ",(UA_Int32(*)(UA_ByteString const*,UA_Int32*,void*))"+name+ "_decodeBinary" +
-          ",(UA_Int32(*)(void const*,UA_Int32*,UA_ByteString*))"+name+"_encodeBinary"+
-          ",(UA_Int32(*)(void *))"+name+"_init"+
-          ",(UA_Int32(*)(void **))"+name+"_new"+
-	  ",(UA_Int32(*)(void const * ,void*))"+name+"_copy"+
-          ",(UA_Int32(*)(void *))"+name+"_delete"+
-          ',(UA_Byte*)"'+name+'"},',end='\n',file=fc) 
-name = "UA_InvalidType"
-print("\t{0" + 
-          ",(UA_Int32(*)(void const*))"+name+"_calcSize" + 
-          ",(UA_Int32(*)(UA_ByteString const*,UA_Int32*,void*))"+name+ "_decodeBinary" +
-          ",(UA_Int32(*)(void const*,UA_Int32*,UA_ByteString*))"+name+"_encodeBinary"+
-          ",(UA_Int32(*)(void *))"+name+"_init"+
-          ",(UA_Int32(*)(void **))"+name+"_new"+
-	  ",(UA_Int32(*)(void const *, void *))"+name+"_copy"+
-          ",(UA_Int32(*)(void *))"+name+"_delete"+
-          ',(UA_Byte*)"'+name+'"}',end='\n',file=fc)
+    print("\t{" +
+          '(UA_Byte*)"' + name + '",' +
+          row[1] + 
+          ",(UA_Int32(*)(void const*))" + name + "_calcSize" + 
+          ",(UA_Int32(*)(UA_ByteString const*,UA_Int32*,void*))" + name + "_decodeBinary" +
+          ",(UA_Int32(*)(void const*,UA_Int32*,UA_ByteString*))" + name + "_encodeBinary"+
+          ",(UA_Int32(*)(XML_Stack*,XML_Attr*,void*,_Bool))" + name + "_decodeXML" +
+          ",(UA_Int32(*)(void *))" + name + "_init" +
+          ",(UA_Int32(*)(void **))" + name + "_new" +
+	  ",(UA_Int32(*)(void const * ,void*))" + name + "_copy" +
+          ",(UA_Int32(*)(void *))phantom_delete" +
+          (",sizeof(" + name + ")" if (name != "UA_InvalidType") else ",0") +
+          "},",end='\n',file=fc)
 print("};", end='\n', file=fc) 
-print('#define '+name.upper()+'_NS0 0', file=fh)
-print('#endif /* OPCUA_NAMESPACE_0_H_ */', end='\n', file=fh)
+
+print('\n#endif /* OPCUA_NAMESPACE_0_H_ */', end='\n', file=fh)
+
 fh.close()
 fc.close()
-f.close()
-
-2222

+ 1 - 2
tools/indent.sh

@@ -12,7 +12,7 @@ fi
 # E.g. when indenting to the opening braces of an argument list.
 
 indent \
---line-length160 \
+--line-length120 \
 --comment-line-length100 \
 --indent-level4 \
 --use-tabs \
@@ -43,7 +43,6 @@ indent \
 --declaration-comment-column0 \
 --format-all-comments \
 --line-comments-indentation0 \
---blank-lines-before-block-comments \
 --space-special-semicolon \
 $@