Browse Source

Merge of branch namespace_generation

Leon Urbas 10 years ago
parent
commit
596f70813a

+ 4 - 0
.gitignore

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

+ 1 - 0
.travis.yml

@@ -15,6 +15,7 @@ addons:
     build_command: make
     build_command: make
     branch_pattern: coverity_scan
     branch_pattern: coverity_scan
 before_install:
 before_install:
+- sudo add-apt-repository ppa:libreoffice/ppa -y
 - sudo apt-get update -qq
 - sudo apt-get update -qq
 - sudo apt-get install -qq build-essential subversion git autoconf libtool texinfo
 - sudo apt-get install -qq build-essential subversion git autoconf libtool texinfo
   python-lxml graphviz doxygen
   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)
 [![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)
 [![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
 ## Getting dependencies
 ### Ubuntu
 ### Ubuntu

+ 18 - 17
doc/Doxyfile.in

@@ -242,7 +242,7 @@ TCL_SUBST              =
 # members will be omitted, etc.
 # members will be omitted, etc.
 # The default value is: NO.
 # 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
 # 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
 # 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).
 # Man pages) or section (for LaTeX and RTF).
 # The default value is: NO.
 # 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
 # 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
 # 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.
 # types are typedef'ed and only the typedef is referenced, never the tag name.
 # The default value is: NO.
 # 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
 # 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
 # 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).
 # Folder Tree View (if specified).
 # The default value is: YES.
 # 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
 # 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
 # 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,
 # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
 # *.qsf, *.as and *.js.
 # *.qsf, *.as and *.js.
 
 
-FILE_PATTERNS          =
+FILE_PATTERNS          = *.h *.dox
 
 
 # The RECURSIVE tag can be used to specify whether or not subdirectories should
 # The RECURSIVE tag can be used to specify whether or not subdirectories should
 # be searched for input files as well.
 # 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
 # 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 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
 # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
 # (namespaces, classes, functions, etc.) that should be excluded from the
 # (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.
 # Minimum value: 1, maximum value: 20, default value: 5.
 # This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
 # 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
 # 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
 # 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.
 # of the possible markers and block names see the documentation.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 # 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
 # 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
 # generated HTML page. If the tag is left blank doxygen will generate a standard
@@ -1056,7 +1056,7 @@ HTML_HEADER            =
 # that doxygen normally uses.
 # that doxygen normally uses.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 # 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
 # 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
 # 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.
 # obsolete.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 # 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-
 # 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
 # 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.
 # 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.
 # 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
 # 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
 # will adjust the colors in the stylesheet and background images according to
@@ -1135,7 +1136,7 @@ HTML_TIMESTAMP         = YES
 # The default value is: NO.
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 # 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
 # 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
 # shown in the various tree structured indices initially; the user can expand
@@ -1478,7 +1479,7 @@ MATHJAX_CODEFILE       =
 # The default value is: YES.
 # The default value is: YES.
 # This tag requires that the tag GENERATE_HTML is set to 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
 # 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
 # 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.
 # If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
 # The default value is: YES.
 # 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
 # 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
 # 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.
 # powerful graphs.
 # The default value is: YES.
 # The default value is: YES.
 
 
-CLASS_DIAGRAMS         = YES
+CLASS_DIAGRAMS         = NO
 
 
 # You can define message sequence charts within doxygen comments using the \msc
 # You can define message sequence charts within doxygen comments using the \msc
 # command. Doxygen will then run the mscgen tool (see:
 # command. Doxygen will then run the mscgen tool (see:
@@ -2098,7 +2099,7 @@ DOT_FONTPATH           =
 # The default value is: YES.
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to 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
 # 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
 # graph for each documented class showing the direct and indirect implementation
@@ -2107,7 +2108,7 @@ CLASS_GRAPH            = YES
 # The default value is: YES.
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to 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
 # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
 # groups, showing the direct groups dependencies.
 # 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_
 #ifndef OPCUA_BASICTYPES_H_
 #define OPCUA_BASICTYPES_H_
 #define OPCUA_BASICTYPES_H_
 
 
@@ -36,14 +29,12 @@ typedef int64_t UA_Int64;
 typedef uint64_t UA_UInt64;
 typedef uint64_t UA_UInt64;
 typedef float UA_Float;
 typedef float UA_Float;
 typedef double UA_Double;
 typedef double UA_Double;
+
 /* ByteString - Part: 6, Chapter: 5.2.2.7, Page: 17 */
 /* ByteString - Part: 6, Chapter: 5.2.2.7, Page: 17 */
-typedef struct UA_ByteString
-{
+typedef struct UA_ByteString {
 	UA_Int32 	length;
 	UA_Int32 	length;
 	UA_Byte*	data;
 	UA_Byte*	data;
-}
-UA_ByteString;
-
+} UA_ByteString;
 
 
 /* Function return values */
 /* Function return values */
 #define UA_SUCCESS 0
 #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_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);
 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) \
 #define UA_TYPE_METHOD_PROTOTYPES(TYPE) \
 	UA_Int32 TYPE##_calcSize(TYPE const * ptr);							\
 	UA_Int32 TYPE##_calcSize(TYPE const * ptr);							\
 	UA_Int32 TYPE##_encodeBinary(TYPE const * src, UA_Int32* pos, UA_ByteString * dst);	\
 	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##_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##_delete(TYPE * p);									\
 	UA_Int32 TYPE##_deleteMembers(TYPE * p);							\
 	UA_Int32 TYPE##_deleteMembers(TYPE * p);							\
 	UA_Int32 TYPE##_init(TYPE * p);										\
 	UA_Int32 TYPE##_init(TYPE * p);										\
@@ -122,13 +122,12 @@ UA_Int32 TYPE##_delete(TYPE *p) { \
 }
 }
 
 
 #define UA_TYPE_METHOD_COPY(TYPE) \
 #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; \
 	UA_Int32 retval = UA_SUCCESS; \
 	retval |= UA_memcpy(dst, src, TYPE##_calcSize(UA_NULL)); \
 	retval |= UA_memcpy(dst, src, TYPE##_calcSize(UA_NULL)); \
 	return retval; \
 	return retval; \
 }
 }
 
 
-
 #define UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(TYPE) \
 #define UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(TYPE) \
 UA_Int32 TYPE##_deleteMembers(TYPE * p) { return UA_SUCCESS; }
 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); \
 	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) \
 #define UA_TYPE_METHOD_ENCODEBINARY_AS(TYPE,TYPE_AS) \
 UA_Int32 TYPE##_encodeBinary(TYPE const * src, UA_Int32* pos, UA_ByteString *dst) { \
 UA_Int32 TYPE##_encodeBinary(TYPE const * src, UA_Int32* pos, UA_ByteString *dst) { \
 	return TYPE_AS##_encodeBinary((TYPE_AS*) src,pos,dst); \
 	return TYPE_AS##_encodeBinary((TYPE_AS*) src,pos,dst); \
 }
 }
 
 
 #define UA_TYPE_METHOD_INIT_AS(TYPE, TYPE_AS) \
 #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); \
 	return TYPE_AS##_init((TYPE_AS*)p); \
 }
 }
 #define UA_TYPE_METHOD_COPY_AS(TYPE, TYPE_AS) \
 #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); \
 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) \
 #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) \
 #define UA_TYPE_METHOD_NEW_DEFAULT(TYPE) \
-UA_Int32 TYPE##_new(TYPE ** p){ \
+UA_Int32 TYPE##_new(TYPE ** p) { \
 	UA_Int32 retval = UA_SUCCESS;\
 	UA_Int32 retval = UA_SUCCESS;\
 	retval |= UA_alloc((void**)p, TYPE##_calcSize(UA_NULL));\
 	retval |= UA_alloc((void**)p, TYPE##_calcSize(UA_NULL));\
 	retval |= TYPE##_init(*p);\
 	retval |= TYPE##_init(*p);\
@@ -173,15 +189,13 @@ UA_Int32 TYPE##_new(TYPE ** p){ \
 }
 }
 
 
 #define UA_TYPE_METHOD_INIT_DEFAULT(TYPE) \
 #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;\
 	if(p==UA_NULL)return UA_ERROR;\
 	*p = (TYPE)0;\
 	*p = (TYPE)0;\
 	return UA_SUCCESS;\
 	return UA_SUCCESS;\
 }
 }
 //#define UA_TYPE_COPY_METHOD_PROTOTYPE(TYPE) \  UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst);
 //#define UA_TYPE_COPY_METHOD_PROTOTYPE(TYPE) \  UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst);
 
 
-
-
 /*** Prototypes for basic types **/
 /*** Prototypes for basic types **/
 UA_TYPE_METHOD_PROTOTYPES (UA_Boolean)
 UA_TYPE_METHOD_PROTOTYPES (UA_Boolean)
 UA_TYPE_METHOD_PROTOTYPES (UA_Byte)
 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_UInt64)
 UA_TYPE_METHOD_PROTOTYPES (UA_Float)
 UA_TYPE_METHOD_PROTOTYPES (UA_Float)
 UA_TYPE_METHOD_PROTOTYPES (UA_Double)
 UA_TYPE_METHOD_PROTOTYPES (UA_Double)
+
 /**
 /**
 * StatusCodeBinaryEncoding
 * StatusCodeBinaryEncoding
 * Part: 6
 * Part: 6
@@ -210,43 +225,14 @@ UA_TYPE_METHOD_PROTOTYPES (UA_StatusCode)
 typedef float UA_IntegerId;
 typedef float UA_IntegerId;
 UA_TYPE_METHOD_PROTOTYPES (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_Int32 	length;
 	UA_Byte*	data;
 	UA_Byte*	data;
-}
-UA_String;
+} UA_String;
 UA_TYPE_METHOD_PROTOTYPES (UA_String)
 UA_TYPE_METHOD_PROTOTYPES (UA_String)
 //UA_Int32 UA_String_copy(UA_String const * src, UA_String* dst);
 //UA_Int32 UA_String_copy(UA_String const * src, UA_String* dst);
 UA_Int32 UA_String_copycstring(char 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);
 UA_Int32 UA_ByteString_newMembers(UA_ByteString* p, UA_Int32 length);
 extern UA_ByteString UA_ByteString_securityPoliceNone;
 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_LOCALE = 0x01,
 	UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT = 0x02
 	UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT = 0x02
 };
 };
-typedef struct UA_LocalizedText
-{
+
+typedef struct UA_LocalizedText {
 	UA_Byte encodingMask;
 	UA_Byte encodingMask;
 	UA_String locale;
 	UA_String locale;
 	UA_String text;
 	UA_String text;
-}
-UA_LocalizedText;
+} UA_LocalizedText;
 UA_TYPE_METHOD_PROTOTYPES (UA_LocalizedText)
 UA_TYPE_METHOD_PROTOTYPES (UA_LocalizedText)
 
 
 UA_Int32 UA_LocalizedText_copycstring(char const * src, UA_LocalizedText* dst);
 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);
 void UA_ByteString_printx_hex(char* label, const UA_ByteString* string);
 
 
 /* GuidType - Part: 6, Chapter: 5.2.2.6 Page: 17 */
 /* GuidType - Part: 6, Chapter: 5.2.2.6 Page: 17 */
-typedef struct UA_Guid
-{
+typedef struct UA_Guid {
 	UA_UInt32 data1;
 	UA_UInt32 data1;
 	UA_UInt16 data2;
 	UA_UInt16 data2;
 	UA_UInt16 data3;
 	UA_UInt16 data3;
@@ -299,8 +282,7 @@ typedef UA_Int64 UA_DateTime; //100 nanosecond resolution
 UA_TYPE_METHOD_PROTOTYPES (UA_DateTime)
 UA_TYPE_METHOD_PROTOTYPES (UA_DateTime)
 
 
 UA_DateTime UA_DateTime_now();
 UA_DateTime UA_DateTime_now();
-typedef struct UA_DateTimeStruct
-{
+typedef struct UA_DateTimeStruct {
 	UA_Int16 nanoSec;
 	UA_Int16 nanoSec;
 	UA_Int16 microSec;
 	UA_Int16 microSec;
 	UA_Int16 milliSec;
 	UA_Int16 milliSec;
@@ -314,77 +296,149 @@ typedef struct UA_DateTimeStruct
 UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime time);
 UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime time);
 UA_Int32 UA_DateTime_toString(UA_DateTime time, UA_String* timeString);
 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_Byte   encodingByte; //enum BID_NodeIdEncodingValuesType
 	UA_UInt16 namespace;
 	UA_UInt16 namespace;
-
-    union
-    {
+    union {
         UA_UInt32 numeric;
         UA_UInt32 numeric;
         UA_String string;
         UA_String string;
         UA_Guid guid;
         UA_Guid guid;
         UA_ByteString byteString;
         UA_ByteString byteString;
-    }
-    identifier;
+    } identifier;
 } UA_NodeId;
 } UA_NodeId;
 UA_TYPE_METHOD_PROTOTYPES (UA_NodeId)
 UA_TYPE_METHOD_PROTOTYPES (UA_NodeId)
 
 
 UA_Int32 UA_NodeId_compare(const UA_NodeId *n1, const UA_NodeId *n2);
 UA_Int32 UA_NodeId_compare(const UA_NodeId *n1, const UA_NodeId *n2);
 void UA_NodeId_printf(char* label, const UA_NodeId* node);
 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
 	//TODO Überlegung ob man es direkt als ByteString speichert oder als String
 	UA_ByteString data;
 	UA_ByteString data;
 } UA_XmlElement;
 } UA_XmlElement;
 UA_TYPE_METHOD_PROTOTYPES (UA_XmlElement)
 UA_TYPE_METHOD_PROTOTYPES (UA_XmlElement)
 
 
-
 /* ExpandedNodeId - Part: 6, Chapter: 5.2.2.10, Page: 19 */
 /* ExpandedNodeId - Part: 6, Chapter: 5.2.2.10, Page: 19 */
 // 62541-6 Chapter 5.2.2.9, Table 5
 // 62541-6 Chapter 5.2.2.9, Table 5
 #define UA_NODEIDTYPE_NAMESPACE_URI_FLAG 0x80
 #define UA_NODEIDTYPE_NAMESPACE_URI_FLAG 0x80
 #define UA_NODEIDTYPE_SERVERINDEX_FLAG   0x40
 #define UA_NODEIDTYPE_SERVERINDEX_FLAG   0x40
 #define UA_NODEIDTYPE_MASK (~(UA_NODEIDTYPE_NAMESPACE_URI_FLAG | UA_NODEIDTYPE_SERVERINDEX_FLAG))
 #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_NodeId nodeId;
 	UA_String namespaceUri;
 	UA_String namespaceUri;
 	UA_UInt32 serverIndex;
 	UA_UInt32 serverIndex;
-}
-UA_ExpandedNodeId;
+} UA_ExpandedNodeId;
 UA_TYPE_METHOD_PROTOTYPES(UA_ExpandedNodeId)
 UA_TYPE_METHOD_PROTOTYPES(UA_ExpandedNodeId)
+UA_Boolean UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId* p);
 
 
-
+/* IdentifierType */
 typedef UA_Int32 UA_IdentifierType;
 typedef UA_Int32 UA_IdentifierType;
 UA_TYPE_METHOD_PROTOTYPES(UA_IdentifierType)
 UA_TYPE_METHOD_PROTOTYPES(UA_IdentifierType)
 
 
-
 /* ExtensionObjectBinaryEncoding - Part: 6, Chapter: 5.2.2.15, Page: 21 */
 /* ExtensionObjectBinaryEncoding - Part: 6, Chapter: 5.2.2.15, Page: 21 */
 typedef struct UA_ExtensionObject {
 typedef struct UA_ExtensionObject {
 	UA_NodeId typeId;
 	UA_NodeId typeId;
 	UA_Byte encoding; //Type of the enum UA_ExtensionObjectEncodingMaskType
 	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_ExtensionObject;
 UA_TYPE_METHOD_PROTOTYPES(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_BODYISBYTESTRING = 	0x01,
-	UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISXML = 	0x02
+	UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISXML =         0x02
 };
 };
 
 
 /* QualifiedNameBinaryEncoding - Part: 6, Chapter: 5.2.2.13, Page: 20 */
 /* QualifiedNameBinaryEncoding - Part: 6, Chapter: 5.2.2.13, Page: 20 */
 typedef struct UA_QualifiedName {
 typedef struct UA_QualifiedName {
 	UA_UInt16 namespaceIndex;
 	UA_UInt16 namespaceIndex;
-	UA_UInt16 reserved;
+	/*UA_UInt16 reserved; removed by Sten since unclear origin*/
 	UA_String name;
 	UA_String name;
 } UA_QualifiedName;
 } UA_QualifiedName;
 UA_TYPE_METHOD_PROTOTYPES(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 */
 /* DataValue - Part: 6, Chapter: 5.2.2.17, Page: 23 */
 typedef struct UA_DataValue {
 typedef struct UA_DataValue {
 	UA_Byte encodingMask;
 	UA_Byte encodingMask;
@@ -398,10 +452,9 @@ typedef struct UA_DataValue {
 UA_TYPE_METHOD_PROTOTYPES(UA_DataValue)
 UA_TYPE_METHOD_PROTOTYPES(UA_DataValue)
 
 
 /** 62541-6, §5.2.2.17, Table 15 */
 /** 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_SOURCETIMESTAMP = 	0x04,
 	UA_DATAVALUE_ENCODINGMASK_SERVERTIMESTAMP = 	0x08,
 	UA_DATAVALUE_ENCODINGMASK_SERVERTIMESTAMP = 	0x08,
 	UA_DATAVALUE_ENCODINGMASK_SOURCEPICOSECONDS = 	0x10,
 	UA_DATAVALUE_ENCODINGMASK_SOURCEPICOSECONDS = 	0x10,
@@ -421,14 +474,13 @@ typedef struct UA_DiagnosticInfo {
 } UA_DiagnosticInfo;
 } UA_DiagnosticInfo;
 UA_TYPE_METHOD_PROTOTYPES(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
 	UA_DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO = 0x40
 };
 };
 
 

+ 24 - 4
include/ua_list.h

@@ -2,10 +2,30 @@
 #define UA_LIST_H_
 #define UA_LIST_H_
 
 
 #include "opcua.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);
 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
 AM_CFLAGS = $(GLOBAL_AM_CFLAGS) -I$(top_builddir)/include -I$(top_builddir)/src -I. -I$(top_builddir)/src/util
-
-
 TOOL_DIR = ../tools
 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
 lib_LTLIBRARIES = libopen62541.la
 libopen62541_la_LDFLAGS = -avoid-version -no-undefined
 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
 .PHONY: convenience-link clean-convenience-link
 
 
@@ -99,4 +45,3 @@ clean-convenience-link:
 all-local: convenience-link
 all-local: convenience-link
 
 
 clean-local: clean-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 }
 #define C2UA_STRING(s) (UA_String) { sizeof(s)-1, (UA_Byte*) s }
 void appMockup_init() {
 void appMockup_init() {
 	// create namespaces
 	// create namespaces
+	// TODO: A table that maps the namespaceUris to Ids
 	Namespace* ns0;
 	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* 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
 	// add to list of namespaces
 	UA_indexedList_init(appMockup.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) {
 static inline UA_Int32 UA_VTable_isValidType(UA_Int32 type) {
 	if(type < 0 /* UA_BOOLEAN */ || type > 271 /* UA_INVALID */)
 	if(type < 0 /* UA_BOOLEAN */ || type > 271 /* UA_INVALID */)
-		return UA_ERROR;
+		return UA_ERR_INVALID_VALUE;
 	return UA_SUCCESS;
 	return UA_SUCCESS;
 }
 }
 
 
@@ -188,6 +188,26 @@ UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(UA_Boolean)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Boolean)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Boolean)
 UA_TYPE_METHOD_COPY(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_METHOD_CALCSIZE_SIZEOF(UA_Byte)
 UA_TYPE_START_ENCODEBINARY(UA_Byte)
 UA_TYPE_START_ENCODEBINARY(UA_Byte)
 	dst->data[(*pos)++] = *src;
 	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_INIT_DEFAULT(UA_Byte)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Byte)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Byte)
 UA_TYPE_METHOD_COPY(UA_Byte)
 UA_TYPE_METHOD_COPY(UA_Byte)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Byte)
+
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_SByte)
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_SByte)
 UA_TYPE_START_ENCODEBINARY(UA_SByte)
 UA_TYPE_START_ENCODEBINARY(UA_SByte)
 	dst->data[(*pos)++] = *src;
 	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_INIT_DEFAULT(UA_SByte)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_SByte)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_SByte)
 UA_TYPE_METHOD_COPY(UA_SByte)
 UA_TYPE_METHOD_COPY(UA_SByte)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_SByte)
 
 
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_UInt16)
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_UInt16)
 UA_TYPE_START_ENCODEBINARY(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_INIT_DEFAULT(UA_UInt16)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_UInt16)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_UInt16)
 UA_TYPE_METHOD_COPY(UA_UInt16)
 UA_TYPE_METHOD_COPY(UA_UInt16)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_UInt16)
 
 
 /** UA_Int16 - signed integer, 2 bytes */
 /** UA_Int16 - signed integer, 2 bytes */
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_Int16)
 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_INIT_DEFAULT(UA_UInt32)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_UInt32)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_UInt32)
 UA_TYPE_METHOD_COPY(UA_UInt32)
 UA_TYPE_METHOD_COPY(UA_UInt32)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_UInt32)
 
 
 /** UA_Int64 - signed integer, 8 bytes */
 /** UA_Int64 - signed integer, 8 bytes */
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_Int64)
 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_INIT_DEFAULT(UA_Int64)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Int64)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Int64)
 UA_TYPE_METHOD_COPY(UA_Int64)
 UA_TYPE_METHOD_COPY(UA_Int64)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Int64)
 
 
 /** UA_UInt64 - unsigned integer, 8 bytes */
 /** UA_UInt64 - unsigned integer, 8 bytes */
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_UInt64)
 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_INIT_DEFAULT(UA_UInt64)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_UInt64)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_UInt64)
 UA_TYPE_METHOD_COPY(UA_UInt64)
 UA_TYPE_METHOD_COPY(UA_UInt64)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_UInt64)
 
 
 /** UA_Float - IEE754 32bit float with biased exponent */
 /** UA_Float - IEE754 32bit float with biased exponent */
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_Float)
 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_NEW_DEFAULT(UA_Float)
 UA_TYPE_METHOD_COPY(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)
 UA_TYPE_METHOD_CALCSIZE_SIZEOF(UA_Double)
 // FIXME: Implement NaN, Inf and Zero(s)
 // FIXME: Implement NaN, Inf and Zero(s)
 UA_Byte UA_DOUBLE_ZERO[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 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_INIT_DEFAULT(UA_Double)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Double)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Double)
 UA_TYPE_METHOD_COPY(UA_Double)
 UA_TYPE_METHOD_COPY(UA_Double)
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Double)
 
 
 /** UA_String */
 /** UA_String */
 UA_Int32 UA_String_calcSize(UA_String const * 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));
 	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;
 	if(p==UA_NULL)return UA_ERROR;
 	p->data1 = 0;
 	p->data1 = 0;
 	p->data2 = 0;
 	p->data2 = 0;
@@ -645,14 +674,17 @@ UA_Int32 UA_Guid_init(UA_Guid* p){
 	memset(p->data4,8,sizeof(UA_Byte));
 	memset(p->data4,8,sizeof(UA_Byte));
 	return UA_SUCCESS;
 	return UA_SUCCESS;
 }
 }
+
 UA_TYPE_METHOD_NEW_DEFAULT(UA_Guid)
 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;
 	UA_Int32 retval = UA_SUCCESS;
 	retval |= UA_alloc((void**)&dst,UA_Guid_calcSize(UA_NULL));
 	retval |= UA_alloc((void**)&dst,UA_Guid_calcSize(UA_NULL));
 	retval |= UA_memcpy((void*)dst,(void*)src,UA_Guid_calcSize(UA_NULL));
 	retval |= UA_memcpy((void*)dst,(void*)src,UA_Guid_calcSize(UA_NULL));
 	return retval;
 	return retval;
 }
 }
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Guid)
+
 UA_Int32 UA_LocalizedText_calcSize(UA_LocalizedText const * p) {
 UA_Int32 UA_LocalizedText_calcSize(UA_LocalizedText const * p) {
 	UA_Int32 length = 0;
 	UA_Int32 length = 0;
 	if (p==UA_NULL) {
 	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;
 	return UA_NOT_EQUAL;
 }
 }
+
 UA_Int32 UA_NodeId_init(UA_NodeId* p){
 UA_Int32 UA_NodeId_init(UA_NodeId* p){
 	if(p==UA_NULL)return UA_ERROR;
 	if(p==UA_NULL)return UA_ERROR;
 	p->encodingByte = UA_NODEIDTYPE_TWOBYTE;
 	p->encodingByte = UA_NODEIDTYPE_TWOBYTE;
@@ -927,6 +960,7 @@ UA_Int32 UA_NodeId_init(UA_NodeId* p){
 	memset(&(p->identifier),0,sizeof(p->identifier));
 	memset(&(p->identifier),0,sizeof(p->identifier));
 	return UA_SUCCESS;
 	return UA_SUCCESS;
 }
 }
+
 UA_TYPE_METHOD_NEW_DEFAULT(UA_NodeId)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_NodeId)
 UA_Int32 UA_NodeId_copy(UA_NodeId const *src, UA_NodeId *dst)
 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;
 	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 UA_ExpandedNodeId_calcSize(UA_ExpandedNodeId const * p) {
 	UA_Int32 length = 0;
 	UA_Int32 length = 0;
 	if (p == UA_NULL) {
 	if (p == UA_NULL) {
 		length = sizeof(UA_ExpandedNodeId);
 		length = sizeof(UA_ExpandedNodeId);
 	} else {
 	} else {
-		length = UA_NodeId_calcSize(&(p->nodeId));
+		length = UA_NodeId_calcSize(&p->nodeId);
 		if (p->nodeId.encodingByte & UA_NODEIDTYPE_NAMESPACE_URI_FLAG) {
 		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) {
 		if (p->nodeId.encodingByte & UA_NODEIDTYPE_SERVERINDEX_FLAG) {
 			length += sizeof(UA_UInt32); //p->serverIndex
 			length += sizeof(UA_UInt32); //p->serverIndex
@@ -968,6 +1027,7 @@ UA_Int32 UA_ExpandedNodeId_calcSize(UA_ExpandedNodeId const * p) {
 	}
 	}
 	return length;
 	return length;
 }
 }
+
 UA_TYPE_START_ENCODEBINARY(UA_ExpandedNodeId)
 UA_TYPE_START_ENCODEBINARY(UA_ExpandedNodeId)
 	retval |= UA_NodeId_encodeBinary(&(src->nodeId),pos,dst);
 	retval |= UA_NodeId_encodeBinary(&(src->nodeId),pos,dst);
 	if (src->nodeId.encodingByte & UA_NODEIDTYPE_NAMESPACE_URI_FLAG) {
 	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;
 	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 UA_ExtensionObject_calcSize(UA_ExtensionObject const * p) {
 	UA_Int32 length = 0;
 	UA_Int32 length = 0;
 	if (p == UA_NULL) {
 	if (p == UA_NULL) {
@@ -1043,8 +1107,11 @@ UA_TYPE_START_ENCODEBINARY(UA_ExtensionObject)
 	case UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED:
 	case UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED:
 		break;
 		break;
 	case UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING:
 	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:
 	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;
 		break;
 	}
 	}
 UA_TYPE_END_XXCODEBINARY
 UA_TYPE_END_XXCODEBINARY
@@ -1239,7 +1306,10 @@ UA_Int32 UA_DiagnosticInfo_copy(UA_DiagnosticInfo const  *src, UA_DiagnosticInfo
 
 
 	return retval;
 	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)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_DateTime)
 
 
 #include <sys/time.h>
 #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_PROTOTYPES_AS(UA_IntegerId, UA_Int32)
 UA_TYPE_METHOD_NEW_DEFAULT(UA_IntegerId)
 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_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
 /** QualifiedName - Part 4, Chapter
  * but see Part 6, Chapter 5.2.2.13 for Binary Encoding
  * but see Part 6, Chapter 5.2.2.13 for Binary Encoding
  */
  */
 UA_Int32 UA_QualifiedName_calcSize(UA_QualifiedName const * p) {
 UA_Int32 UA_QualifiedName_calcSize(UA_QualifiedName const * p) {
 	UA_Int32 length = 0;
 	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->namespaceIndex
 	// length += sizeof(UA_UInt16); //qualifiedName->reserved
 	// length += sizeof(UA_UInt16); //qualifiedName->reserved
 	length += UA_String_calcSize(&(p->name)); //qualifiedName->name
 	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;
 	if(p==UA_NULL)return UA_ERROR;
 	UA_String_init(&(p->name));
 	UA_String_init(&(p->name));
 	p->namespaceIndex=0;
 	p->namespaceIndex=0;
-	p->reserved=0;
+	//p->reserved=0;
 	return UA_SUCCESS;
 	return UA_SUCCESS;
 }
 }
 UA_TYPE_METHOD_NEW_DEFAULT(UA_QualifiedName)
 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_alloc((void**)&dst,UA_QualifiedName_calcSize(UA_NULL));
 	retval |= UA_String_copy(&(src->name),&(dst->name));
 	retval |= UA_String_copy(&(src->name),&(dst->name));
 	retval |= UA_UInt16_copy(&(src->namespaceIndex),&(dst->namespaceIndex));
 	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;
 	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 UA_Variant_calcSize(UA_Variant const * p) {
 	UA_Int32 length = 0;
 	UA_Int32 length = 0;
 	if (p == UA_NULL) return sizeof(UA_Variant);
 	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 isArray = p->encodingMask & (0x01 << 7); // Bit 7
 	UA_Boolean hasDimensions = p->encodingMask & (0x01 << 6); // Bit 6
 	UA_Boolean hasDimensions = p->encodingMask & (0x01 << 6); // Bit 6
 	UA_Int32 i;
 	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;
 		return UA_ERR_INCONSISTENT;
 	}
 	}
 	length += sizeof(UA_Byte); //p->encodingMask
 	length += sizeof(UA_Byte); //p->encodingMask
@@ -1529,6 +1603,43 @@ UA_Int32 UA_Variant_copy(UA_Variant const *src, UA_Variant *dst)
 	return retval;
 	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
 //TODO: place this define at the server configuration
 #define MAX_PICO_SECONDS 1000
 #define MAX_PICO_SECONDS 1000
 UA_Int32 UA_DataValue_decodeBinary(UA_ByteString const * src, UA_Int32* pos, UA_DataValue* dst) {
 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;
 	return retval;
 }
 }
+UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_DataValue)
+
 /* UA_InvalidType - internal type necessary to handle inited Variants correctly */
 /* UA_InvalidType - internal type necessary to handle inited Variants correctly */
 UA_Int32 UA_InvalidType_calcSize(UA_InvalidType const * p) {
 UA_Int32 UA_InvalidType_calcSize(UA_InvalidType const * p) {
 	return 0;
 	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) {
 UA_Int32 UA_InvalidType_new(UA_InvalidType** p) {
 	return UA_ERR_INVALID_VALUE;
 	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 */
 /* 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
 /* 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
    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 {
 struct prime_ent {
 	hash_t prime;
 	hash_t prime;
 	hash_t inv;
 	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);
 	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;
 		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:
 	case UA_NODECLASS_OBJECT:
-		UA_ObjectNode_delete((UA_ObjectNode *) slot->node);
+		UA_ObjectNode_delete((UA_ObjectNode *) entry->node);
 		break;
 		break;
 	case UA_NODECLASS_VARIABLE:
 	case UA_NODECLASS_VARIABLE:
-		UA_VariableNode_delete((UA_VariableNode *) slot->node);
+		UA_VariableNode_delete((UA_VariableNode *) entry->node);
 		break;
 		break;
 	case UA_NODECLASS_METHOD:
 	case UA_NODECLASS_METHOD:
-		UA_MethodNode_delete((UA_MethodNode *) slot->node);
+		UA_MethodNode_delete((UA_MethodNode *) entry->node);
 		break;
 		break;
 	case UA_NODECLASS_OBJECTTYPE:
 	case UA_NODECLASS_OBJECTTYPE:
-		UA_ObjectTypeNode_delete((UA_ObjectTypeNode *) slot->node);
+		UA_ObjectTypeNode_delete((UA_ObjectTypeNode *) entry->node);
 		break;
 		break;
 	case UA_NODECLASS_VARIABLETYPE:
 	case UA_NODECLASS_VARIABLETYPE:
-		UA_VariableTypeNode_delete((UA_VariableTypeNode *) slot->node);
+		UA_VariableTypeNode_delete((UA_VariableTypeNode *) entry->node);
 		break;
 		break;
 	case UA_NODECLASS_REFERENCETYPE:
 	case UA_NODECLASS_REFERENCETYPE:
-		UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *) slot->node);
+		UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *) entry->node);
 		break;
 		break;
 	case UA_NODECLASS_DATATYPE:
 	case UA_NODECLASS_DATATYPE:
-		UA_DataTypeNode_delete((UA_DataTypeNode *) slot->node);
+		UA_DataTypeNode_delete((UA_DataTypeNode *) entry->node);
 		break;
 		break;
 	case UA_NODECLASS_VIEW:
 	case UA_NODECLASS_VIEW:
-		UA_ViewNode_delete((UA_ViewNode *) slot->node);
+		UA_ViewNode_delete((UA_ViewNode *) entry->node);
 		break;
 		break;
 	default:
 	default:
 		break;
 		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 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;
 		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;
 	}
 	}
 
 
-	hash2 = mod_m2(h, ns);
+	hash_t hash2 = mod_m2(h, ns);
 	for(;;) {
 	for(;;) {
 		index += hash2;
 		index += hash2;
 		if(index >= size)
 		if(index >= size)
 			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;
 			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;
 		}
 		}
 	}
 	}
-	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
 /* 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;
 	Namespace_Entry *p = oentries;
 	do {
 	do {
 		if(p->node != UA_NULL) {
 		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++;
 		p++;
 	} while(p < olimit);
 	} while(p < olimit);
@@ -330,29 +315,23 @@ static UA_Int32 expand(Namespace * ns) {
 /* Exported functions */
 /* 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)
 	if(UA_alloc((void **)&ns, sizeof(Namespace)) != UA_SUCCESS)
 		return UA_ERR_NO_MEMORY;
 		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) {
 	if(UA_alloc((void **)&ns->entries, sizeof(Namespace_Entry) * size) != UA_SUCCESS) {
 		UA_free(ns);
 		UA_free(ns);
 		return UA_ERR_NO_MEMORY;
 		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));
 	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;
 	*result = ns;
 	return UA_SUCCESS;
 	return UA_SUCCESS;
 }
 }
@@ -361,7 +340,7 @@ static void Namespace_clear(Namespace * ns) {
 	UA_UInt32 size = ns->size;
 	UA_UInt32 size = ns->size;
 	Namespace_Entry *entries = ns->entries;
 	Namespace_Entry *entries = ns->entries;
 	for(UA_UInt32 i = 0; i < size; i++)
 	for(UA_UInt32 i = 0; i < size; i++)
-		clear_slot(ns, &entries[i]);
+		clear_entry(ns, &entries[i]);
 	ns->count = 0;
 	ns->count = 0;
 }
 }
 
 
@@ -386,110 +365,80 @@ void Namespace_delete(Namespace * ns) {
 	UA_free(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(ns->size * 3 <= ns->count * 4) {
 		if(expand(ns) != UA_SUCCESS)
 		if(expand(ns) != UA_SUCCESS)
 			return UA_ERROR;
 			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++;
 	ns->count++;
 	return UA_SUCCESS;
 	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;
 	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;
 		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;
 	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;
 		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.
 	// 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 */
 	/* Downsize the hashmap if it is very empty */
 	if(ns->count * 8 < ns->size && ns->size > 32)
 	if(ns->count * 8 < ns->size && ns->size > 32)
 		expand(ns);
 		expand(ns);
+
+	return UA_SUCCESS;
 }
 }
 
 
 UA_Int32 Namespace_iterate(const Namespace * ns, Namespace_nodeVisitor visitor) {
 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;
 	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 _XOPEN_SOURCE 500
 #define __USE_UNIX98
 #define __USE_UNIX98
 #include <pthread.h>
 #include <pthread.h>
-typedef struct pthread_rwlock_t Namespace_Lock;
-#else
-typedef void Namespace_Lock;
 #endif
 #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 {
 typedef struct Namespace {
-	UA_Int32 namespaceId;
-	UA_String namespaceUri;
+	UA_UInt32 namespaceId;
 	Namespace_Entry *entries;
 	Namespace_Entry *entries;
 	UA_UInt32 size;
 	UA_UInt32 size;
 	UA_UInt32 count;
 	UA_UInt32 count;
 	UA_UInt32 sizePrimeIndex;	/* Current size, as an index into the table of primes.  */
 	UA_UInt32 sizePrimeIndex;	/* Current size, as an index into the table of primes.  */
 } Namespace;
 } 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 */
 /** @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 */
 /** @brief Delete all nodes in the namespace */
 void Namespace_empty(Namespace * ns);
 void Namespace_empty(Namespace * ns);
@@ -57,33 +41,31 @@ void Namespace_empty(Namespace * ns);
 /** @brief Delete the namespace and all nodes in it */
 /** @brief Delete the namespace and all nodes in it */
 void Namespace_delete(Namespace * ns);
 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 */
 /** @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
 /** @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
 	by their NodeId. After the Node is no longer used, the lock needs to be
 	released. */
 	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 */
 /** @brief Iterate over all nodes in a namespace */
 UA_Int32 Namespace_iterate(const Namespace * ns, Namespace_nodeVisitor visitor);
 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_
 #ifndef UA_SERVICES_H_
 #define UA_SERVICES_H_
 #define UA_SERVICES_H_
 
 
@@ -5,6 +11,14 @@
 #include "ua_application.h"
 #include "ua_application.h"
 #include "ua_transport_binary_secure.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
  * @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_AddReferences
 // Service_DeleteNodes
 // Service_DeleteNodes
 // Service_DeleteReferences
 // Service_DeleteReferences
@@ -111,12 +129,18 @@ UA_Int32 Service_CloseSession(SL_Channel *channel, const UA_CloseSessionRequest
  * also supports a primitive filtering capability.
  * also supports a primitive filtering capability.
  */ 
  */ 
 UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA_BrowseResponse *response);
 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_BrowseNext
-// Service_TranslateBrowsePathsRoNodeIds
+// Service_TranslateBrowsePathsToNodeIds
 // Service_RegisterNodes
 // Service_RegisterNodes
 // Service_UnregisterNodes
 // Service_UnregisterNodes
 /** @} */
 /** @} */
 
 
+
 /* Part 4: 5.9 Query Service Set */
 /* Part 4: 5.9 Query Service Set */
 /**
 /**
  * @name Query Service Set
  * @name Query Service Set
@@ -209,4 +233,6 @@ UA_Int32 Service_CreateMonitoredItems(SL_Channel *channel, const UA_CreateMonito
 // Service_DeleteSubscription
 // Service_DeleteSubscription
 /** @} */
 /** @} */
 
 
+/** @} */ // end of group
+
 #endif
 #endif

+ 107 - 85
src/ua_services_attribute.c

@@ -26,163 +26,185 @@ enum UA_AttributeId {
 	UA_ATTRIBUTEID_USEREXECUTABLE = 22
 	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);
 	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->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
 		return v;
 		return v;
 	}
 	}
-	DBG_VERBOSE(UA_String_printf(",namespaceUri=",&(ns->namespaceUri)));
-	
+	DBG_VERBOSE(UA_String_printf(",namespaceUri=", &(ns->namespaceUri)));
+
 	UA_Node const *node = UA_NULL;
 	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);
 	UA_Int32 result = Namespace_get(ns, &(id->nodeId), &node, &lock);
 	if(result != UA_SUCCESS || node == UA_NULL) {
 	if(result != UA_SUCCESS || node == UA_NULL) {
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
 		return v;
 		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:
 	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;
 		break;
 	case UA_ATTRIBUTEID_NODECLASS:
 	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;
 		break;
 	case UA_ATTRIBUTEID_BROWSENAME:
 	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;
 		break;
 	case UA_ATTRIBUTEID_DISPLAYNAME:
 	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;
 		break;
 	case UA_ATTRIBUTEID_DESCRIPTION:
 	case UA_ATTRIBUTEID_DESCRIPTION:
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNOTREADABLE;
 		v->status = UA_STATUSCODE_BADNOTREADABLE;
 		break;
 		break;
 	case UA_ATTRIBUTEID_WRITEMASK:
 	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;
 		break;
 	case UA_ATTRIBUTEID_USERWRITEMASK:
 	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;
 		break;
 	case UA_ATTRIBUTEID_ISABSTRACT:
 	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;
 		break;
 	case UA_ATTRIBUTEID_SYMMETRIC:
 	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;
 		break;
 	case UA_ATTRIBUTEID_INVERSENAME:
 	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;
 		break;
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
 	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;
 		break;
 	case UA_ATTRIBUTEID_EVENTNOTIFIER:
 	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;
 		break;
 	case UA_ATTRIBUTEID_VALUE:
 	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;
 		break;
 	case UA_ATTRIBUTEID_DATATYPE:
 	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;
 		break;
 	case UA_ATTRIBUTEID_VALUERANK:
 	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;
 		break;
 	case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
 	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;
 		break;
 	case UA_ATTRIBUTEID_ACCESSLEVEL:
 	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;
 		break;
 	case UA_ATTRIBUTEID_USERACCESSLEVEL:
 	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;
 		break;
 	case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
 	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;
 		break;
 	case UA_ATTRIBUTEID_HISTORIZING:
 	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;
 		break;
 	case UA_ATTRIBUTEID_EXECUTABLE:
 	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;
 		break;
 	case UA_ATTRIBUTEID_USEREXECUTABLE:
 	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;
 		break;
 	default:
 	default:
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		v->status = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		break;
 		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;
 	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;
 	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->results[i] = service_read_node(channel->session->application, request->nodesToRead[i]);
 	}
 	}
+	response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
 	response->diagnosticInfosSize = -1;
 	response->diagnosticInfosSize = -1;
 	return UA_SUCCESS;
 	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_services.h"
+#include "ua_statuscodes.h"
 
 
 UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA_BrowseResponse *response) {
 UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA_BrowseResponse *response) {
 	UA_Int32 retval = UA_SUCCESS;
 	UA_Int32 retval = UA_SUCCESS;
@@ -9,3 +10,24 @@ UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA
 	}
 	}
 	return retval;
 	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 <stdio.h>
 
 
 #include "opcua.h"
 #include "opcua.h"
-#include "ua_transport_binary.h"
 
 
 //transport errors begin at 1000
 //transport errors begin at 1000
 #define UA_ERROR_MULTIPLE_HEL 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);
 		INVOKE_SERVICE(Read);
 	    responsetype = UA_READRESPONSE_NS0;
 	    responsetype = UA_READRESPONSE_NS0;
 	}
 	}
+	else if(serviceid == UA_TRANSLATEBROWSEPATHSTONODEIDSREQUEST_NS0) {
+		INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
+	    responsetype = UA_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE_NS0;
+	}
 	else {
 	else {
 		printf("SL_processMessage - unknown request, namespace=%d, request=%d\n", serviceRequestType.namespace,serviceRequestType.identifier.numeric);
 		printf("SL_processMessage - unknown request, namespace=%d, request=%d\n", serviceRequestType.namespace,serviceRequestType.identifier.numeric);
 		retval = UA_ERROR;
 		retval = UA_ERROR;

+ 0 - 1
src/ua_transport_binary_secure.h

@@ -3,7 +3,6 @@
 #include "opcua.h"
 #include "opcua.h"
 #include "ua_transport.h"
 #include "ua_transport.h"
 #include "ua_transport_binary.h"
 #include "ua_transport_binary.h"
-#include "ua_transport_binary_secure.h"
 
 
 typedef struct {
 typedef struct {
 	UA_UInt32 secureChannelId;
 	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=
 UNIT_TESTS=
 check_PROGRAMS=
 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)
 TESTS += $(UNIT_TESTS)
 check_PROGRAMS += $(UNIT_TESTS)
 check_PROGRAMS += $(UNIT_TESTS)
 
 

+ 5 - 5
tests/check_namespace.c

@@ -7,7 +7,7 @@
 
 
 START_TEST(test_Namespace) {
 START_TEST(test_Namespace) {
 	Namespace *ns = UA_NULL;
 	Namespace *ns = UA_NULL;
-	Namespace_create(&ns, 512);
+	Namespace_new(&ns, 512, 99);
 	Namespace_delete(ns);
 	Namespace_delete(ns);
 }
 }
 END_TEST
 END_TEST
@@ -23,10 +23,10 @@ UA_Int32 createNode(UA_Node** p, UA_Int16 nsid, UA_Int32 id) {
 START_TEST(findNodeInNamespaceWithSingleEntry) {
 START_TEST(findNodeInNamespaceWithSingleEntry) {
 	// given
 	// given
 	Namespace *ns;
 	Namespace *ns;
-	Namespace_create(&ns, 512);
+	Namespace_new(&ns, 512, 99);
 	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
 	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
 	const UA_Node* nr = UA_NULL;
 	const UA_Node* nr = UA_NULL;
-	Namespace_Lock* nl = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
 	UA_Int32 retval;
 	UA_Int32 retval;
 	// when
 	// when
 	retval = Namespace_get(ns,&(n1->nodeId),&nr,&nl);
 	retval = Namespace_get(ns,&(n1->nodeId),&nr,&nl);
@@ -41,12 +41,12 @@ END_TEST
 START_TEST(findNodeInNamespaceWithTwoEntries) {
 START_TEST(findNodeInNamespaceWithTwoEntries) {
 	// given
 	// given
 	Namespace *ns;
 	Namespace *ns;
-	Namespace_create(&ns, 512);
+	Namespace_new(&ns, 512, 99);
 	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
 	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
 	UA_Node* n2; createNode(&n2,0,2255); Namespace_insert(ns,n2);
 	UA_Node* n2; createNode(&n2,0,2255); Namespace_insert(ns,n2);
 
 
 	const UA_Node* nr = UA_NULL;
 	const UA_Node* nr = UA_NULL;
-	Namespace_Lock* nl = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
 	UA_Int32 retval;
 	UA_Int32 retval;
 	// when
 	// when
 	retval = Namespace_get(ns,&(n2->nodeId),&nr,&nl);
 	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
  Name        : check_stack.c
- Author      :
- Version     :
+ Author      : uleon @ open62541
+ Version     : 0.1
  Copyright   : Your copyright notice
  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 <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 #include "opcua.h"
 #include "opcua.h"
 #include "ua_transport.h"
 #include "ua_transport.h"
+#include "ua_transport_binary.h"
+#include "ua_transport_binary_secure.h"
 #include "check.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
 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
 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 *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);
 	suite_add_tcase(s,tc_core);
 	return s;
 	return s;
 }
 }
-*/
-
 
 
 int main (void)
 int main (void)
 {
 {
@@ -138,27 +453,13 @@ int main (void)
 	Suite *s;
 	Suite *s;
 	SRunner *sr;
 	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);
 	sr = srunner_create(s);
 	srunner_run_all(sr,CK_NORMAL);
 	srunner_run_all(sr,CK_NORMAL);
 	number_failed += srunner_ntests_failed(sr);
 	number_failed += srunner_ntests_failed(sr);
 	srunner_free(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;
 	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-
 }
 }
 
 
 
 

+ 142 - 144
tools/generate_builtin.py

@@ -8,30 +8,24 @@ import re
 from lxml import etree
 from lxml import etree
 
 
 if len(sys.argv) != 3:
 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 
 # types that are coded manually 
 exclude_types = set(["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
 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 = []
 enum_types = []
 structured_types = []
 structured_types = []
@@ -44,36 +38,31 @@ def skipType(name):
     if re.search("NodeId$", name) != None:
     if re.search("NodeId$", name) != None:
         return True
         return True
     return False
     return False
-
+    
 def stripTypename(tn):
 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):
 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):
 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
 # StructuredType, EnumeratedType OpaqueType
 
 
-def createEnumerated(element):
+def createEnumerated(element):	
     valuemap = OrderedDict()
     valuemap = OrderedDict()
     name = "UA_" + element.get("Name")
     name = "UA_" + element.get("Name")
     enum_types.append(name)
     enum_types.append(name)
-    print("\n/** @name UA_" + name + " */", end='\n', file=fh)
     for child in element:
     for child in element:
         if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
         if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
             print("/** @brief " + child.text + " */", end='\n', file=fh)
             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_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_COPY_AS("+name+", UA_UInt32)",'\n', file=fc)  
     print("UA_TYPE_METHOD_NEW_DEFAULT("+name+")\n", end='\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
     return
     
     
 def createStructured(element):
 def createStructured(element):
@@ -100,9 +90,9 @@ def createStructured(element):
 
 
     lengthfields = set()
     lengthfields = set()
     for child in element:
     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:
     for child in element:
         if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
         if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
             print("/** @brief " + child.text + " */", end='\n', file=fh)
             print("/** @brief " + child.text + " */", end='\n', file=fh)
@@ -116,26 +106,21 @@ def createStructured(element):
             else:
             else:
                 valuemap[childname] = typename
                 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)
     print("typedef struct " + name + " {", end='\n', file=fh)
     if len(valuemap) == 0:
     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():
     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("} " + name + ";", end='\n', file=fh)
 
 
     print("UA_Int32 " + name + "_calcSize(" + name + " const* ptr);", 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 + "_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 + "_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 + "_delete("+ name + "* p);", end='\n', file=fh)
     print("UA_Int32 " + name + "_deleteMembers(" + 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)
     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\tif(ptr==UA_NULL){return sizeof("+ name +");}", end='', file=fc)
     print("\n\treturn 0", end='', file=fc)
     print("\n\treturn 0", end='', file=fc)
 
 
-    # code _calcSize
+	# code _calcSize
     for n,t in valuemap.iteritems():
     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("\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)
     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():
     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)
     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("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)
     print('\t'+name+'_init(dst);', end='\n', file=fc)
     for n,t in valuemap.iteritems():
     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)
                 print('\tCHECKED_DECODE(UA_'+t+'_decodeBinary(src,pos,&(dst->'+n+')), '+name+'_deleteMembers(dst));', end='\n', file=fc)
             elif t.find("**") != -1:
             elif t.find("**") != -1:
             	# decode size
             	# 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
 		# 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:
             elif t.find("*") != -1:
 		#allocate memory using new
 		#allocate memory using new
 		print('\tCHECKED_DECODE(UA_'+ t[0:t.find("*")] +"_new(&(dst->" + n + ")), "+name+'_deleteMembers(dst));', end='\n', file=fc)
 		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:
             else:
                 print('\tCHECKED_DECODE(UA_'+t+"_decodeBinary(src,pos,&(dst->"+n+")), "+name+'_deleteMembers(dst));', end='\n', file=fc)
                 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)
     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
     # code _delete and _deleteMembers
     print('UA_Int32 '+name+'_delete('+name+'''* p) {
     print('UA_Int32 '+name+'_delete('+name+'''* p) {
@@ -209,13 +203,13 @@ def createStructured(element):
 	retval |= '''+name+'''_deleteMembers(p);
 	retval |= '''+name+'''_deleteMembers(p);
 	retval |= UA_free(p);
 	retval |= UA_free(p);
 	return retval;
 	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)
     print("UA_Int32 "+name+"_deleteMembers(" + name + "* p) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
     for n,t in valuemap.iteritems():
     for n,t in valuemap.iteritems():
         if t not in elementary_size:
         if t not in elementary_size:
             if t.find("**") != -1:
             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:
             elif t.find("*") != -1:
 		print('\tretval |= UA_' + t[0:t.find("*")] + "_delete(p->"+n+");", end='\n', file=fc)
 		print('\tretval |= UA_' + t[0:t.find("*")] + "_delete(p->"+n+");", end='\n', file=fc)
             else:
             else:
@@ -223,26 +217,26 @@ def createStructured(element):
 		
 		
     print("\treturn retval;\n}\n", end='\n', file=fc)
     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)
     print("UA_Int32 "+name+"_init(" + name + " * p) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
     for n,t in valuemap.iteritems():
     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+'Size=0;', end='\n', file=fc)
 				print("\tp->"+n+"=UA_NULL;", 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)
 				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)
     print("\treturn retval;\n}\n", end='\n', file=fc)
 
 
-    # code _new
+	# code _new
     print("UA_TYPE_METHOD_NEW_DEFAULT(" + name + ")", end='\n', file=fc)
     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)
     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():
     for n,t in valuemap.iteritems():
         if t in elementary_size:
         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)
                 print('\tretval |= UA_'+t+'_copy(&(src->'+n+'),&(dst->'+n+'));', end='\n', file=fc)
             elif t.find("**") != -1:
             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_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:
             elif t.find("*") != -1:
                 print('\tretval |= UA_' + t[0:t.find("*")] + '_copy(src->' + n + ',dst->' + n + ');', end='\n', file=fc)
                 print('\tretval |= UA_' + t[0:t.find("*")] + '_copy(src->' + n + ',dst->' + n + ');', end='\n', file=fc)
             else:
             else:
                 print('\tretval |= UA_'+t+"_copy(&(src->"+n+"),&(dst->" + n + '));', end='\n', file=fc)
                 print('\tretval |= UA_'+t+"_copy(&(src->"+n+"),&(dst->" + n + '));', end='\n', file=fc)
     print("\treturn retval;\n}\n", end='\n', file=fc)
     print("\treturn retval;\n}\n", end='\n', file=fc)
-    
+	
 def createOpaque(element):
 def createOpaque(element):
     name = "UA_" + element.get("Name")
     name = "UA_" + element.get("Name")
     print("\n/** @name UA_" + name + " */", end='\n', file=fh)
     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_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_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_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_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_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_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_COPY_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_NEW_DEFAULT("+name+")\n", end='\n', file=fc)
     print("UA_TYPE_METHOD_NEW_DEFAULT("+name+")\n", end='\n', file=fc)
 
 
-    return
-
 ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
 ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
 tree = etree.parse(sys.argv[1])
 tree = etree.parse(sys.argv[1])
 types = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
 types = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
 
 
 fh = open(sys.argv[2] + ".hgen",'w');
 fh = open(sys.argv[2] + ".hgen",'w');
 fc = open(sys.argv[2] + ".cgen",'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]+'''
  * 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")+'''
  * 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);
 #include "''' + sys.argv[2] + '.h"', end='\n', file=fc);
 
 
 # types for which we create a vector type
 # types for which we create a vector type
 arraytypes = set()
 arraytypes = set()
 fields = tree.xpath("//opc:Field", namespaces=ns)
 fields = tree.xpath("//opc:Field", namespaces=ns)
 for field in fields:
 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()
 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
 #plugin handling
 import os
 import os
 files = [f for f in os.listdir('.') if os.path.isfile(f) and f[-3:] == ".py" and f[:7] == "plugin_"]
 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
 #end plugin handling
 
 
 for element in types:
 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():
 for name, element in deferred_types.iteritems():
 	if name in plugin_types:
 	if name in plugin_types:
@@ -364,4 +363,3 @@ for name, element in deferred_types.iteritems():
 print('#endif /* OPCUA_H_ */', end='\n', file=fh)
 print('#endif /* OPCUA_H_ */', end='\n', file=fh)
 fh.close()
 fh.close()
 fc.close()
 fc.close()
-

+ 86 - 72
tools/generate_namespace.py

@@ -2,20 +2,15 @@ from __future__ import print_function
 import sys
 import sys
 import platform
 import platform
 import getpass
 import getpass
-from collections import OrderedDict
 import time
 import time
-import re
-import csv
-from itertools import tee
 
 
 if len(sys.argv) != 3:
 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
 # 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",
 	"Image", "ImageBMP", "ImageGIF", "ImageJPG", "ImagePNG",
 	"References", "BaseVariableType", "BaseDataVariableType", 
 	"References", "BaseVariableType", "BaseDataVariableType", 
 	"PropertyType", "DataTypeDescriptionType", "DataTypeDictionaryType", "NamingRuleType",
 	"PropertyType", "DataTypeDescriptionType", "DataTypeDictionaryType", "NamingRuleType",
@@ -34,21 +29,14 @@ exclude_types = set(["Number",
 	"YArrayItemType", "XYArrayItemType", "ImageItemType", "CubeItemType", "NDimensionArrayItemType"
 	"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])
 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('''/**********************************************************
 print('''/**********************************************************
  * '''+sys.argv[2]+'''.hgen -- do not modify
  * '''+sys.argv[2]+'''.hgen -- do not modify
@@ -60,11 +48,27 @@ print('''/**********************************************************
 #ifndef OPCUA_NAMESPACE_0_H_
 #ifndef OPCUA_NAMESPACE_0_H_
 #define 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);
 UA_Int32 UA_ns0ToVTableIndex(UA_Int32 id);
 extern UA_VTable UA_[]; 
 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)
 enum UA_VTableIndex_enum {''', end='\n', file=fh)
 
 
 print('''/**********************************************************
 print('''/**********************************************************
@@ -76,77 +80,87 @@ print('''/**********************************************************
  
  
 #include "opcua.h"
 #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
 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":
     if row[0] == "BaseDataType":
     	name = "UA_Variant"
     	name = "UA_Variant"
     elif row[0] == "Structure":
     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)
     print('\tcase '+row[1]+': retval='+name.upper()+'; break; //'+row[2], file=fc)
     i = i+1
     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;
     return retval;
 }
 }
 
 
 UA_VTable UA_[] = {''', file=fc)
 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":
     if row[0] == "BaseDataType":
-    	name = "UA_Variant"
+        name = "UA_Variant"
     elif row[0] == "Structure":
     elif row[0] == "Structure":
-    	name = "UA_ExtensionObject" 
+        name = "UA_ExtensionObject"
     else:	
     else:	
 	name = "UA_" + row[0]
 	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("};", 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()
 fh.close()
 fc.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.
 # E.g. when indenting to the opening braces of an argument list.
 
 
 indent \
 indent \
---line-length160 \
+--line-length120 \
 --comment-line-length100 \
 --comment-line-length100 \
 --indent-level4 \
 --indent-level4 \
 --use-tabs \
 --use-tabs \
@@ -43,7 +43,6 @@ indent \
 --declaration-comment-column0 \
 --declaration-comment-column0 \
 --format-all-comments \
 --format-all-comments \
 --line-comments-indentation0 \
 --line-comments-indentation0 \
---blank-lines-before-block-comments \
 --space-special-semicolon \
 --space-special-semicolon \
 $@
 $@