소스 검색

Overlayable (#582)

* use overlayable information for all types

* move travis scripts into own directory
Julius Pfrommer 9 년 전
부모
커밋
f45d6faf85

+ 7 - 7
.travis.yml

@@ -90,17 +90,17 @@ before_install:
 - export CHECK_INCLUDE_DIRS=$LOCAL_PKG/include/
 - export CHECK_LIBRARIES=$LOCAL_PKG/lib/
 
-- if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis_linux_before_install.sh; fi
-- if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis_osx_before_install.sh; fi
+- if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis/travis_linux_before_install.sh; fi
+- if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis/travis_osx_before_install.sh; fi
 
 script:
-- if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis_linux_script.sh; fi
-- if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis_osx_script.sh; fi
+- if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis/travis_linux_script.sh; fi
+- if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis/travis_osx_script.sh; fi
 
 after_success:
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master" && ${TRAVIS_PULL_REQUEST} == "false" ) ]]; then sh ./tools/travis_push_doc.sh; fi
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master" && ${TRAVIS_PULL_REQUEST} == "false" ) ]]; then sh ./tools/travis_push_coverity.sh; fi
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" ) ]]; then sh ./tools/travis_push_release.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master" && ${TRAVIS_PULL_REQUEST} == "false" ) ]]; then sh ./tools/travis/travis_push_doc.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master" && ${TRAVIS_PULL_REQUEST} == "false" ) ]]; then sh ./tools/travis/travis_push_coverity.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" ) ]]; then sh ./tools/travis/travis_push_release.sh; fi
 
 before_deploy:
 - rm build -rf && mkdir -p build && cd build

+ 4 - 11
CMakeLists.txt

@@ -235,11 +235,6 @@ else()
   list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore.c)
 endif()
 
-set(generate_typeintrospection "")
-if(UA_ENABLE_TYPENAMES)
-  set(generate_typeintrospection "--typeintrospection")
-endif()
-
 set(generate_subscriptiontypes "")
 if(UA_ENABLE_SUBSCRIPTIONS)
   list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_services_subscription.c
@@ -268,10 +263,8 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                    PRE_BUILD
                    COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
-                                                ${generate_subscriptiontypes}
-                                                ${generate_typeintrospection}
                                                 --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv
-                                                0
+                                                --selected_types=${PROJECT_SOURCE_DIR}/tools/schema/datatypes_minimal.txt
                                                 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
                                                 ${PROJECT_BINARY_DIR}/src_generated/ua_types
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
@@ -284,9 +277,9 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_transport_gener
                           ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h
                    PRE_BUILD
                    COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
-                                                ${generate_typeintrospection}
-                                                --ns0-types-xml ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
-                                                1
+                                                --namespace=1
+                                                --selected_types=${PROJECT_SOURCE_DIR}/tools/schema/datatypes_transport.txt
+                                                ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
                                                 ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd
                                                 ${PROJECT_BINARY_DIR}/src_generated/ua_transport
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py

+ 61 - 63
include/ua_config.h.in

@@ -82,84 +82,82 @@
 /**
  * Integer Endianness
  * ------------------ */
-#if defined(_WIN32) || (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) \
-                        && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
-# define htole16(x) (x)
-# define htole32(x) (x)
-# define htole64(x) (x)
-# define le16toh(x) (x)
-# define le32toh(x) (x)
-# define le64toh(x) (x)
-#else
-# if defined(__ANDROID__)
-#  include <endian.h>
-#  define le16toh(x) letoh16(x)
-#  define le32toh(x) letoh32(x)
-#  define le64toh(x) letoh64(x)
-# elif defined(__linux__)
-#  include <endian.h>
-# elif defined(__OpenBSD__)
-#  include <sys/endian.h>
-# elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
-#  include <sys/endian.h>
-#  define le16toh(x) letoh16(x)
-#  define le32toh(x) letoh32(x)
-#  define le64toh(x) letoh64(x)
-# elif defined(__APPLE__)
-#  include <libkern/OSByteOrder.h>
-#  define htole16(x) OSSwapHostToLittleInt16(x)
-#  define htole32(x) OSSwapHostToLittleInt32(x)
-#  define htole64(x) OSSwapHostToLittleInt64(x)
-#  define le16toh(x) OSSwapLittleToHostInt16(x)
-#  define le32toh(x) OSSwapLittleToHostInt32(x)
-#  define le64toh(x) OSSwapLittleToHostInt64(x)
-# elif defined(__QNX__) || defined(__QNXNTO__)
-#  include <gulliver.h>
-#  define htole16(x) ENDIAN_LE16(x)
-#  define htole32(x) ENDIAN_LE32(x)
-#  define htole64(x) ENDIAN_LE64(x)
-#  define le16toh(x) ENDIAN_LE16(x)
-#  define le32toh(x) ENDIAN_LE32(x)
-#  define le64toh(x) ENDIAN_LE64(x)
-# else
-#  define UA_ENCODING_INTEGER_GENERIC
-#  warning No native function for endianness conversion available. Use a slow generic conversion.
+#if defined(_WIN32) || (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
+                        (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) /* little endian detected */
+# define UA_BINARY_OVERLAYABLE_INTEGER true
+#elif defined(__ANDROID__) /* Andoid */
+# include <endian.h>
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define UA_BINARY_OVERLAYABLE_INTEGER true
+# endif
+#elif defined(__linux__) /* Linux */
+# include <endian.h>
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define UA_BINARY_OVERLAYABLE_INTEGER true
+# endif
+# if __FLOAT_BYTE_ORDER == __LITTLE_ENDIAN
+#  define UA_BINARY_OVERLAYABLE_FLOAT true
+# endif
+#elif defined(__OpenBSD__) /* OpenBSD */
+# include <sys/endian.h>
+# if BYTE_ORDER == LITTLE_ENDIAN
+#  define UA_BINARY_OVERLAYABLE_INTEGER true
+# endif
+#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) /* Other BSD */
+# include <sys/endian.h>
+# if _BYTE_ORDER == _LITTLE_ENDIAN
+#  define UA_BINARY_OVERLAYABLE_INTEGER true
+# endif
+#elif defined(__APPLE__) /* Apple (MacOS, iOS) */
+# include <libkern/OSByteOrder.h>
+# if defined(__LITTLE_ENDIAN__)
+#  define UA_BINARY_OVERLAYABLE_INTEGER true
+# endif
+#elif defined(__QNX__) || defined(__QNXNTO__) /* QNX */
+# include <gulliver.h>
+# if defined(__LITTLEENDIAN__)
+#  define UA_BINARY_OVERLAYABLE_INTEGER true
 # endif
 #endif
 
 /**
  * Float Endianness
  * ---------------- */
+#if defined(_WIN32)
+# define UA_BINARY_OVERLAYABLE_FLOAT true
+#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
+    (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) /* Defined only in GCC */
+# define UA_BINARY_OVERLAYABLE_FLOAT true
+#endif
+
+/**
+ * Binary Encoding Overlays
+ * ------------------------
+ * Some data types have the same layout in memory as on the binary data stream.
+ * This can be used to speed up the decoding. If we could not detect
+ * little-endianness of integers and floats, this is not possible for types that
+ * contain integers or floats respectively. See the definition of the
+ * overlayable flag defined in `UA_DataType`. */
 
 /* Demote error to a warning on clang. There is no robust way to detect float
  * endianness here. On x86/x86-64, floats are always in the right IEEE 754
- * format. Then, the "Unknown float representation warning" can be ignored or
- * disabled and the UA_ENCODING_FLOAT_GENERIC definition removed to get faster
- * speed. */
+ * format. So floats are overlayable is the architecture is little-endian. */
 #if defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic warning "-W#warnings"
+# pragma GCC diagnostic push
+# pragma GCC diagnostic warning "-W#warnings"
 #endif
 
-#if !defined(_WIN32)
-# if !defined(__FLOAT_WORD_ORDER__) || !defined(__BYTE_ORDER__) || \
-     !defined(__ORDER_LITTLE_ENDIAN__) || !defined(__ORDER_BIG_ENDIAN__)
-#  define UA_ENCODING_FLOAT_GENERIC
-#  warning Unknown float representation. Use a slow manual IEEE 754 conversion.
-/* Replace UA_ENCODING_FLOAT_GENERIC with the following section (and adjust
-   accordingly to your archtecture) if little-endian IEEE 754 can be achieved
-   with a simple byte-swap. For example for middle-endian encoding on some
-   ARM CPUs. */
-/* #define UA_ENCODING_FLOAT_SWAP */
-/* #define UA_swap32(u32) ((u32 >> 24) | ((u32 << 8) & 0x00FF0000) | ((u32 >> 8) & 0x0000FF00) | (u32 << 24)) */
-/* #define UA_swap64(u64) ((u64 >> 56) | ((u64 << 40) & 0x00FF000000000000) | ((u64 << 24) & 0x0000FF0000000000) | \ */
-/*                        ((u64 << 8) & 0x000000FF00000000) | ((u64 >> 8) & 0x00000000FF000000) |                 \ */
-/*                        ((u64 >> 24) & 0x0000000000FF0000) | ((u64 >> 40) & 0x000000000000FF00) | (u64 << 56)) */
-# endif
+#ifndef UA_BINARY_OVERLAYABLE_INTEGER
+# define UA_BINARY_OVERLAYABLE_INTEGER false
+# warning Slow Integer Encoding
+#endif
+#ifndef UA_BINARY_OVERLAYABLE_FLOAT
+# define UA_BINARY_OVERLAYABLE_FLOAT false
+# warning Slow Float Encoding
 #endif
 
 #if defined(__clang__)
-#pragma GCC diagnostic pop
+# pragma GCC diagnostic pop
 #endif
 
 /**

+ 2 - 2
include/ua_types.h

@@ -709,8 +709,8 @@ struct UA_DataType {
     UA_Boolean builtin      : 1; /* The type is "builtin" and has dedicated de- and
                                     encoding functions */
     UA_Boolean fixedSize    : 1; /* The type (and its members) contains no pointers */
-    UA_Boolean zeroCopyable : 1; /* The type can be copied directly off the stream (given
-                                     that the endianness matches) */
+    UA_Boolean overlayable  : 1; /* The type has the identical memory layout in
+                                    memory and on the binary stream. */
     UA_DataTypeMember *members;
 };
 

+ 17 - 2
src/server/ua_server_binary.c

@@ -505,17 +505,32 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
     }
 
     /* Test if the session is valid */
-    if(!session->activated && requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST) {
+    if(!session->activated &&
+       requestType->typeIndex != UA_TYPES_CREATESESSIONREQUEST &&
+       requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST &&
+       requestType->typeIndex != UA_TYPES_FINDSERVERSREQUEST &&
+       requestType->typeIndex != UA_TYPES_GETENDPOINTSREQUEST &&
+       requestType->typeIndex != UA_TYPES_OPENSECURECHANNELREQUEST) {
         UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
                     "Client tries to call a service with a non-activated session");
         sendError(channel, &bytes, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
         return;
     }
+
 #ifndef UA_ENABLE_NONSTANDARD_STATELESS
     if(session == &anonymousSession &&
-       requestType->typeIndex > UA_TYPES_ACTIVATESESSIONREQUEST) {
+       requestType->typeIndex != UA_TYPES_CREATESESSIONREQUEST &&
+       requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST &&
+       requestType->typeIndex != UA_TYPES_FINDSERVERSREQUEST &&
+       requestType->typeIndex != UA_TYPES_GETENDPOINTSREQUEST &&
+       requestType->typeIndex != UA_TYPES_OPENSECURECHANNELREQUEST) {
+#ifdef UA_ENABLE_TYPENAMES
+        UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                    "Client sent a %s without a session", requestType->typeName);
+#else
         UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
                     "Client tries to call a service without a session");
+#endif
         sendError(channel, &bytes, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONIDINVALID);
         return;
     }

+ 13 - 65
src/ua_types_encoding_binary.c

@@ -23,7 +23,6 @@ UA_THREAD_LOCAL const UA_DataType *type; // used to pass the datatype into the j
 /* Integer Types */
 /*****************/
 
-#ifdef UA_ENCODING_INTEGER_GENERIC
 static void UA_encode16(const UA_UInt16 v, UA_Byte buf[2]) {
     buf[0] = (UA_Byte)v; buf[1] = (UA_Byte)(v >> 8);
 }
@@ -50,7 +49,6 @@ static void UA_decode64(const UA_Byte buf[4], UA_UInt64 *v) {
                     (((UA_UInt64)buf[4]) << 32) + (((UA_UInt64)buf[5]) << 40) +
                     (((UA_UInt64)buf[6]) << 48) + (((UA_UInt64)buf[7]) << 56));
 }
-#endif
 
 /* Boolean */
 static UA_StatusCode
@@ -95,9 +93,8 @@ static UA_StatusCode
 UInt16_encodeBinary(UA_UInt16 const *src, bufpos pos, bufend end) {
     if(*pos + sizeof(UA_UInt16) > end)
         return UA_STATUSCODE_BADENCODINGERROR;
-#ifndef UA_ENCODING_INTEGER_GENERIC
-    UA_UInt16 le_uint16 = htole16(*src);
-    memcpy(*pos, &le_uint16, sizeof(UA_UInt16));
+#if UA_BINARY_OVERLAYABLE_INTEGER
+    memcpy(*pos, src, sizeof(UA_UInt16));
 #else
     UA_encode16(*src, *pos);
 #endif
@@ -114,9 +111,8 @@ static UA_StatusCode
 UInt16_decodeBinary(bufpos pos, bufend end, UA_UInt16 *dst) {
     if(*pos + sizeof(UA_UInt16) > end)
         return UA_STATUSCODE_BADDECODINGERROR;
-#ifndef UA_ENCODING_INTEGER_GENERIC
+#if UA_BINARY_OVERLAYABLE_INTEGER
     memcpy(dst, *pos, sizeof(UA_UInt16));
-    *dst = le16toh(*dst);
 #else
     UA_decode16(*pos, dst);
 #endif
@@ -134,9 +130,8 @@ static UA_StatusCode
 UInt32_encodeBinary(UA_UInt32 const *src, bufpos pos, bufend end) {
     if(*pos + sizeof(UA_UInt32) > end)
         return UA_STATUSCODE_BADENCODINGERROR;
-#ifndef UA_ENCODING_INTEGER_GENERIC
-    UA_UInt32 le_uint32 = htole32(*src);
-    memcpy(*pos, &le_uint32, sizeof(UA_UInt32));
+#if UA_BINARY_OVERLAYABLE_INTEGER
+    memcpy(*pos, src, sizeof(UA_UInt32));
 #else
     UA_encode32(*src, *pos);
 #endif
@@ -158,9 +153,8 @@ static UA_StatusCode
 UInt32_decodeBinary(bufpos pos, bufend end, UA_UInt32 *dst) {
     if(*pos + sizeof(UA_UInt32) > end)
         return UA_STATUSCODE_BADDECODINGERROR;
-#ifndef UA_ENCODING_INTEGER_GENERIC
+#if UA_BINARY_OVERLAYABLE_INTEGER
     memcpy(dst, *pos, sizeof(UA_UInt32));
-    *dst = le32toh(*dst);
 #else
     UA_decode32(*pos, dst);
 #endif
@@ -183,9 +177,8 @@ static UA_StatusCode
 UInt64_encodeBinary(UA_UInt64 const *src, bufpos pos, bufend end) {
     if(*pos + sizeof(UA_UInt64) > end)
         return UA_STATUSCODE_BADENCODINGERROR;
-#ifndef UA_ENCODING_INTEGER_GENERIC
-    UA_UInt64 le_uint64 = htole64(*src);
-    memcpy(*pos, &le_uint64, sizeof(UA_UInt64));
+#if UA_BINARY_OVERLAYABLE_INTEGER
+    memcpy(*pos, src, sizeof(UA_UInt64));
 #else
     UA_encode64(*src, *pos);
 #endif
@@ -207,9 +200,8 @@ static UA_StatusCode
 UInt64_decodeBinary(bufpos pos, bufend end, UA_UInt64 *dst) {
     if(*pos + sizeof(UA_UInt64) > end)
         return UA_STATUSCODE_BADDECODINGERROR;
-#ifndef UA_ENCODING_INTEGER_GENERIC
+#if UA_BINARY_OVERLAYABLE_INTEGER
     memcpy(dst, *pos, sizeof(UA_UInt64));
-    *dst = le64toh(*dst);
 #else
     UA_decode64(*pos, dst);
 #endif
@@ -231,52 +223,13 @@ DateTime_decodeBinary(bufpos pos, bufend end, UA_DateTime *dst) {
 /* Floating Point Types */
 /************************/
 
-#if !defined(UA_ENCODING_FLOAT_SWAP) && !defined(UA_ENCODING_FLOAT_GENERIC)
-/* Encode natively */
+#if UA_BINARY_OVERLAYABLE_FLOAT
 # define Float_encodeBinary UInt32_encodeBinary
 # define Float_decodeBinary UInt32_decodeBinary
 # define Double_encodeBinary UInt64_encodeBinary
 # define Double_decodeBinary UInt64_decodeBinary
 #else
 
-#ifdef UA_ENCODING_FLOAT_SWAP
-
-static UA_StatusCode
-Float_encodeBinary(UA_Float const *src, bufpos pos, bufend end) {
-    const UA_UInt32 *f = (const UA_UInt32*)src;
-    UA_UInt32 encoded = UA_swap32(*f);
-    return UInt32_encodeBinary(&encoded, pos, end);
-}
-
-static UA_StatusCode Float_decodeBinary(bufpos pos, bufend end, UA_Float *dst) {
-    UA_UInt32 decoded;
-    UA_StatusCode retval = UInt32_decodeBinary(pos, end, &decoded);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-    decoded = UA_swap32(decoded);
-    *dst = *(UA_Float*)decoded;
-    return UA_STATUSCODE_GOOD;
-}
-
-static UA_StatusCode
-Double_encodeBinary(UA_Double const *src, bufpos pos, bufend end) {
-    const UA_UInt64 *f = (const UA_UInt64*)src;
-    UA_UInt64 encoded = UA_swap64(*f);
-    return UInt64_encodeBinary(&encoded, pos, end);
-}
-
-static UA_StatusCode Double_decodeBinary(bufpos pos, bufend end, UA_Double *dst) {
-    UA_UInt64 decoded;
-    UA_StatusCode retval = UInt64_decodeBinary(pos, end, &decoded);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-    decoded = UA_swap64(decoded);
-    *dst = *(UA_Double*)decoded;
-    return UA_STATUSCODE_GOOD;
-}
-
-#else /* UA_ENCODING_FLOAT_GENERIC */
-
 #include <math.h>
 
 /* Handling of IEEE754 floating point values was taken from Beej's Guide to
@@ -376,7 +329,6 @@ Double_decodeBinary(bufpos pos, bufend end, UA_Double *dst) {
     return UA_STATUSCODE_GOOD;
 }
 
-#endif
 #endif
 
 /******************/
@@ -396,15 +348,13 @@ Array_encodeBinary(const void *src, size_t length, const UA_DataType *contenttyp
     if(retval != UA_STATUSCODE_GOOD || length == 0)
         return retval;
 
-#ifndef UA_NON_LITTLEENDIAN_ARCHITECTURE
-    if(contenttype->zeroCopyable) {
+    if(contenttype->overlayable) {
         if(end < *pos + (contenttype->memSize * length))
             return UA_STATUSCODE_BADENCODINGERROR;
         memcpy(*pos, src, contenttype->memSize * length);
         (*pos) += contenttype->memSize * length;
         return retval;
     }
-#endif
 
     uintptr_t ptr = (uintptr_t)src;
     size_t encode_index = contenttype->builtin ? contenttype->typeIndex : UA_BUILTIN_TYPES_COUNT;
@@ -437,8 +387,7 @@ Array_decodeBinary(bufpos pos, bufend end, UA_Int32 signed_length, void *UA_REST
     if(!*dst)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
-#ifndef UA_NON_LITTLEENDIAN_ARCHITECTURE
-    if(contenttype->zeroCopyable) {
+    if(contenttype->overlayable) {
         if(end < *pos + (contenttype->memSize * length))
             return UA_STATUSCODE_BADDECODINGERROR;
         memcpy(*dst, *pos, contenttype->memSize * length);
@@ -446,7 +395,6 @@ Array_decodeBinary(bufpos pos, bufend end, UA_Int32 signed_length, void *UA_REST
         *out_length = length;
         return UA_STATUSCODE_GOOD;
     }
-#endif
 
     uintptr_t ptr = (uintptr_t)*dst;
     size_t decode_index = contenttype->builtin ? contenttype->typeIndex : UA_BUILTIN_TYPES_COUNT;
@@ -1266,7 +1214,7 @@ UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst, const UA_Da
 static size_t
 Array_calcSizeBinary(const void *src, size_t length, const UA_DataType *contenttype) {
     size_t s = 4; // length
-    if(contenttype->zeroCopyable) {
+    if(contenttype->overlayable) {
         s += contenttype->memSize * length;
         return s;
     }

+ 1 - 1
tests/check_memory.c

@@ -107,8 +107,8 @@ START_TEST(decodeShallFailWithTruncatedBufferButSurvive) {
     }
 	// when
 	void *obj2 = UA_new(&UA_TYPES[_i]);
-	pos = 0;
 	msg1.length = pos / 2;
+	pos = 0;
 	//fprintf(stderr,"testing %s with half buffer\n",UA_TYPES[_i].name);
 	retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i]);
 	ck_assert_int_ne(retval, UA_STATUSCODE_GOOD);

+ 345 - 442
tools/generate_datatypes.py

@@ -10,463 +10,353 @@ import itertools
 import argparse
 from pprint import pprint
 
-fixed_size = {"UA_Boolean": 1, "UA_SByte": 1, "UA_Byte": 1, "UA_Int16": 2, "UA_UInt16": 2,
-              "UA_Int32": 4, "UA_UInt32": 4, "UA_Int64": 8, "UA_UInt64": 8, "UA_Float": 4,
-              "UA_Double": 8, "UA_DateTime": 8, "UA_Guid": 16, "UA_StatusCode": 4}
-
-zero_copy = ["UA_Boolean", "UA_SByte", "UA_Byte", "UA_Int16", "UA_UInt16", "UA_Int32", "UA_UInt32",
-             "UA_Int64", "UA_UInt64", "UA_Float", "UA_Double", "UA_DateTime", "UA_StatusCode"]
-
-# The order of the builtin-types is not as in the standard. We put all the
-# fixed_size types in the front, so they can be distinguished by a simple geq
-# comparison. That's ok, since we use the type-index only internally!!
-builtin_types = ["UA_Boolean", "UA_SByte", "UA_Byte", "UA_Int16", "UA_UInt16",
-                 "UA_Int32", "UA_UInt32", "UA_Int64", "UA_UInt64", "UA_Float",
-                 "UA_Double", "UA_String", "UA_DateTime", "UA_Guid", "UA_ByteString",
-                 "UA_XmlElement", "UA_NodeId", "UA_ExpandedNodeId", "UA_StatusCode",
-                 "UA_QualifiedName", "UA_LocalizedText", "UA_ExtensionObject", "UA_DataValue",
-                 "UA_Variant", "UA_DiagnosticInfo"]
-
-excluded_types = ["UA_NodeIdType", "UA_InstanceNode", "UA_TypeNode", "UA_Node", "UA_ObjectNode",
-                  "UA_ObjectTypeNode", "UA_VariableNode", "UA_VariableTypeNode", "UA_ReferenceTypeNode",
-                  "UA_MethodNode", "UA_ViewNode", "UA_DataTypeNode", "UA_ServerDiagnosticsSummaryDataType",
-                  "UA_SamplingIntervalDiagnosticsDataType", "UA_SessionSecurityDiagnosticsDataType",
-                  "UA_SubscriptionDiagnosticsDataType", "UA_SessionDiagnosticsDataType"]
-
-minimal_types = ["InvalidType", "Node", "NodeClass", "ReferenceNode", "ApplicationDescription", "ApplicationType",
-                 "ChannelSecurityToken", "OpenSecureChannelRequest", "OpenSecureChannelResponse",
-                 "CloseSecureChannelRequest", "CloseSecureChannelResponse", "RequestHeader", "ResponseHeader",
-                 "SecurityTokenRequestType", "MessageSecurityMode", "CloseSessionResponse", "CloseSessionRquest",
-                 "ActivateSessionRequest", "ActivateSessionResponse", "SignatureData", "SignedSoftwareCertificate",
-                 "CreateSessionResponse", "CreateSessionRequest", "EndpointDescription", "UserTokenPolicy", "UserTokenType",
-                 "GetEndpointsRequest", "GetEndpointsResponse", "PublishRequest", "PublishResponse", "FindServersRequest",
-                 "FindServersResponse", "SetPublishingModeResponse", "SubscriptionAcknowledgement", "NotificationMessage",
-                 "ExtensionObject", "Structure", "ReadRequest", "ReadResponse", "ReadValueId", "TimestampsToReturn", "WriteRequest",
-                 "WriteResponse", "WriteValue", "SetPublishingModeRequest", "CreateMonitoredItemsResponse",
-                 "MonitoredItemCreateResult", "CreateMonitoredItemsRequest", "MonitoredItemCreateRequest",
-                 "MonitoringMode", "MonitoringParameters", "TranslateBrowsePathsToNodeIdsRequest",
-                 "TranslateBrowsePathsToNodeIdsResponse", "BrowsePath", "BrowsePathResult", "RelativePath",
-                 "BrowsePathTarget", "RelativePathElement", "CreateSubscriptionRequest", "CreateSubscriptionResponse",
-                 "BrowseResponse", "BrowseResult", "ReferenceDescription", "BrowseRequest", "ViewDescription",
-                 "BrowseNextRequest", "BrowseNextResponse", "DeleteSubscriptionsRequest", "DeleteSubscriptionsResponse",
-                 "BrowseDescription", "BrowseDirection", "CloseSessionRequest", "AddNodesRequest", "AddNodesResponse",
-                 "AddNodesItem", "AddNodesResult", "DeleteNodesItem","AddReferencesRequest", "AddReferencesResponse",
-                 "AddReferencesItem","DeleteReferencesItem", "VariableNode", "MethodNode", "VariableTypeNode",
-                 "ViewNode", "ReferenceTypeNode", "BrowseResultMask", "ServerState", "ServerStatusDataType", "BuildInfo",
-                 "ObjectNode", "DataTypeNode", "ObjectTypeNode", "IdType", "NodeAttributes",
-                 "VariableAttributes", "ObjectAttributes", "ReferenceTypeAttributes", "ViewAttributes", "MethodAttributes",
-                 "ObjectTypeAttributes", "VariableTypeAttributes", "DataTypeAttributes", "NodeAttributesMask",
-                 "DeleteNodesItem", "DeleteNodesRequest", "DeleteNodesResponse",
-                 "DeleteReferencesItem", "DeleteReferencesRequest", "DeleteReferencesResponse",
-                 "RegisterNodesRequest", "RegisterNodesResponse", "UnregisterNodesRequest", "UnregisterNodesResponse", 
-                 "UserIdentityToken", "UserNameIdentityToken", "AnonymousIdentityToken", "ServiceFault",
-                 "CallMethodRequest", "CallMethodResult", "CallResponse", "CallRequest", "Argument",
-                 "FilterOperator", "ContentFilterElement", "ContentFilter", "QueryDataDescription",
-                 "NodeTypeDescription", "QueryFirstRequest", "QueryDataSet", "ParsingResult",
-                 "ContentFilterElementResult", "ContentFilterResult", "QueryFirstResponse",
-                 "QueryNextRequest", "QueryNextResponse"]
-
-subscription_types = ["CreateSubscriptionRequest", "CreateSubscriptionResponse",
-                      "DeleteMonitoredItemsRequest", "DeleteMonitoredItemsResponse", "NotificationMessage",
-                      "MonitoredItemNotification", "DataChangeNotification", "ModifySubscriptionRequest",
-                      "ModifySubscriptionResponse", "RepublishRequest", "RepublishResponse"]
+types = OrderedDict() # contains types that were already parsed
+typedescriptions = {} # contains type nodeids
+
+excluded_types = ["NodeIdType", "InstanceNode", "TypeNode", "Node", "ObjectNode",
+                  "ObjectTypeNode", "VariableNode", "VariableTypeNode", "ReferenceTypeNode",
+                  "MethodNode", "ViewNode", "DataTypeNode",
+                  "UA_ServerDiagnosticsSummaryDataType", "UA_SamplingIntervalDiagnosticsDataType",
+                  "UA_SessionSecurityDiagnosticsDataType", "UA_SubscriptionDiagnosticsDataType",
+                  "UA_SessionDiagnosticsDataType"]
+
+builtin_types = ["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"]
+
+# If the type does not contain pointers, it can be copied with memcpy
+# (internally, not into the protocol message). This dict contains the sizes of
+# fixed-size types. Parsed types are added if they apply.
+builtin_fixed_size = ["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
+                      "Int64", "UInt64", "Float", "Double", "DateTime", "Guid", "StatusCode"]
+
+# Some types can be memcpy'd off the binary stream. That's especially important
+# for arrays. But we need to check if they contain padding and whether the
+# endianness is correct. This dict gives the C-statement that must be true for the
+# type to be overlayable. Parsed types are added if they apply.
+builtin_overlayable = {"Boolean": "true", "SByte": "true", "Byte": "true",
+                       "Int16": "UA_BINARY_OVERLAYABLE_INTEGER", "UInt16": "UA_BINARY_OVERLAYABLE_INTEGER",
+                       "Int32": "UA_BINARY_OVERLAYABLE_INTEGER", "UInt32": "UA_BINARY_OVERLAYABLE_INTEGER",
+                       "Int64": "UA_BINARY_OVERLAYABLE_INTEGER", "UInt64": "UA_BINARY_OVERLAYABLE_INTEGER",
+                       "Float": "UA_BINARY_OVERLAYABLE_FLOAT", "Double": "UA_BINARY_OVERLAYABLE_FLOAT",
+                       "DateTime": "UA_BINARY_OVERLAYABLE_INTEGER", "StatusCode": "UA_BINARY_OVERLAYABLE_INTEGER",
+                       "Guid": "(UA_BINARY_OVERLAYABLE_INTEGER && offsetof(UA_Guid, data2) == sizeof(UA_UInt32) && " + \
+                       "offsetof(UA_Guid, data3) == (sizeof(UA_UInt16) + sizeof(UA_UInt32)) && " + \
+                       "offsetof(UA_Guid, data4) == (2*sizeof(UA_UInt32)))"}
+
+################
+# Type Classes #
+################
 
-class TypeDescription(object):
-    def __init__(self, name, nodeid, namespaceid):
-        self.name = name # without the UA_ prefix
-        self.nodeid = nodeid
-        self.namespaceid = namespaceid
-
-def parseTypeDescriptions(filename, namespaceid):
-    definitions = {}
-    f = open(filename[0])
-    input_str = f.read()
-    f.close()
-    input_str = input_str.replace('\r','')
-    rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
-    for index, row in enumerate(rows):
-        if len(row) < 3:
-            continue
-        if row[2] != "DataType":
-            continue
-        if row[0] == "BaseDataType":
-            definitions["UA_Variant"] = TypeDescription(row[0], row[1], namespaceid)
-        elif row[0] == "Structure":
-            definitions["UA_ExtensionObject"] = TypeDescription(row[0], row[1], namespaceid)
-        else:
-            definitions["UA_" + row[0]] = TypeDescription(row[0], row[1], namespaceid)
-    return definitions
-
-class Type(object):
-    def __init__(self, name, description = ""):
+class StructMember(object):
+    def __init__(self, name, memberType, isArray):
         self.name = name
-        self.description = description
-
-    def fixed_size(self):
-        return self.name in fixed_size
+        self.memberType = memberType
+        self.isArray = isArray
 
-    def mem_size(self):
-        return fixed_size[self.name]
+class Type(object):
+    def __init__(self, outname, xml):
+        self.name = xml.get("Name")
+        self.ns0 = ("true" if outname == "ua_types" else "false")
+        self.typeIndex = outname.upper() + "_" + self.name.upper()
+        self.outname = outname
+        self.description = ""
+        self.fixed_size = "false"
+        self.overlayable = "false"
+        if self.name in builtin_types:
+            self.builtin = "true"
+        else:
+            self.builtin = "false"
+        self.members = [StructMember("", self, False)] # Returns one member: itself. Overwritten by some types.
+        for child in xml:
+            if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
+                self.description = child.text
+                break
 
-    def zero_copy(self):
-        return self.name in zero_copy
+    def datatype_c(self):
+        if self.name in typedescriptions:
+            description = typedescriptions[self.name]
+            typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}" % (description.namespaceid, description.nodeid)
+        else:
+            typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}"
+        return "{ .typeId = " + typeid + \
+            ",\n  .typeIndex = " + self.typeIndex + \
+            ",\n#ifdef UA_ENABLE_TYPENAMES\n  .typeName = \"%s\",\n#endif\n" % self.name + \
+            "  .memSize = sizeof(UA_" + self.name + ")" + \
+            ",\n  .builtin = " + self.builtin + \
+            ",\n  .fixedSize = " + self.fixed_size + \
+            ",\n  .overlayable = " + self.overlayable + \
+            ",\n  .membersSize = " + str(len(self.members)) + \
+            ",\n  .members = %s_members" % self.name + " }"
+
+    def members_c(self):
+        members = "static UA_DataTypeMember %s_members[%s] = {" % (self.name, len(self.members))
+        before = None
+        for index, member in enumerate(self.members):
+            m = "\n  { .memberTypeIndex = %s_%s,\n" % (member.memberType.outname.upper(), member.memberType.name.upper())
+            m += "#ifdef UA_ENABLE_TYPENAMES\n    .memberName = \"%s\",\n#endif\n" % member.name
+            m += "    .namespaceZero = %s,\n" % member.memberType.ns0
+            m += "    .padding = "
+            if not before:
+                m += "0,\n"
+            else:
+                if member.isArray:
+                    m += "offsetof(UA_%s, %sSize)" % (self.name, member.name)
+                else:
+                    m += "offsetof(UA_%s, %s)" % (self.name, member.name)
+                m += " - offsetof(UA_%s, %s)" % (self.name, before.name)
+                if before.isArray:
+                    m += " - sizeof(void*),\n"
+                else:
+                    m += " - sizeof(UA_%s),\n" % before.memberType.name
+            m += "    .isArray = " + ("true" if member.isArray else "false")
+            members += m + "\n  },"
+            before = member
+        return members + "};"
+
+    def datatype_ptr(self):
+        return "&" + self.outname.upper() + "[" + self.outname.upper() + "_" + self.name.upper() + "]"
+        
+    def functions_c(self):
+        funcs = "static UA_INLINE void UA_%s_init(UA_%s *p) { memset(p, 0, sizeof(UA_%s)); }\n" % (self.name, self.name, self.name)
+        funcs += "static UA_INLINE UA_%s * UA_%s_new(void) { return (UA_%s*) UA_new(%s); }\n" % (self.name, self.name, self.name, self.datatype_ptr())
+        if self.fixed_size == "true":
+            funcs += "static UA_INLINE UA_StatusCode UA_%s_copy(const UA_%s *src, UA_%s *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }\n" % (self.name, self.name, self.name)
+            funcs += "static UA_INLINE void UA_%s_deleteMembers(UA_%s *p) { }\n" % (self.name, self.name)
+        else:
+            funcs += "static UA_INLINE UA_StatusCode UA_%s_copy(const UA_%s *src, UA_%s *dst) { return UA_copy(src, dst, %s); }\n" % (self.name, self.name, self.name, self.datatype_ptr())
+            funcs += "static UA_INLINE void UA_%s_deleteMembers(UA_%s *p) { UA_deleteMembers(p, %s); }\n" % (self.name, self.name, self.datatype_ptr())
+        funcs += "static UA_INLINE void UA_%s_delete(UA_%s *p) { UA_delete(p, %s); }" % (self.name, self.name, self.datatype_ptr())
+        return funcs
 
-    def typedef_c(self):
-        pass
-    
-    def functions_c(self, typeTableName):
-        return ('''static UA_INLINE void %s_init(%s *p) { memset(p, 0, sizeof(%s)); }
-static UA_INLINE void %s_delete(%s *p) { UA_delete(p, %s); }
-static UA_INLINE void %s_deleteMembers(%s *p) { ''' + ("UA_deleteMembers(p, &"+typeTableName+"["+typeTableName+"_"+self.name[3:].upper()+"]);" if not self.fixed_size() else "") + ''' }
-static UA_INLINE %s * %s_new(void) { return (%s*) UA_new(%s); }
-static UA_INLINE UA_StatusCode %s_copy(const %s *src, %s *dst) { ''' + \
-                ("*dst = *src; return UA_STATUSCODE_GOOD;" if self.fixed_size() else "return UA_copy(src, dst, &" + typeTableName+"["+typeTableName+"_"+self.name[3:].upper() + "]);") +" }") % \
-    tuple([self.name, self.name, self.name] +
-          [self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"] +
-          [self.name, self.name] + 
-          [self.name, self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"] +
-          [self.name, self.name, self.name]) 
-
-    def encoding_h(self, typeTableName):
-        return '''static UA_INLINE UA_StatusCode %s_encodeBinary(const %s *src, UA_ByteString *dst, size_t *offset) { return UA_encodeBinary(src, %s, dst, offset); }
-static UA_INLINE UA_StatusCode %s_decodeBinary(const UA_ByteString *src, size_t *offset, %s *dst) { return UA_decodeBinary(src, offset, dst, %s); }''' % \
-    tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 2))))
+    def encoding_h(self):
+        enc = "static UA_INLINE UA_StatusCode UA_%s_encodeBinary(const UA_%s *src, UA_ByteString *dst, size_t *offset) { return UA_encodeBinary(src, %s, dst, offset); }\n"
+        enc += "static UA_INLINE UA_StatusCode UA_%s_decodeBinary(const UA_ByteString *src, size_t *offset, UA_%s *dst) { return UA_decodeBinary(src, offset, dst, %s); }"
+        return enc % tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, self.datatype_ptr()], 2))))
 
 class BuiltinType(Type):
-    "Generic type without members. Used for builtin types."
-    def typelayout_c(self, namespace_0, description, outname):
-        if description == None:
-            typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
+    def __init__(self, name):
+        self.name = name
+        self.ns0 = "true"
+        self.typeIndex = "UA_TYPES_" + self.name.upper()
+        self.outname = "ua_types"
+        self.description = ""
+        self.fixed_size = "false"
+        if self.name in builtin_fixed_size:
+            self.fixed_size = "true"
+        self.overlayable = "false"
+        if name in builtin_overlayable:
+            self.overlayable = builtin_overlayable[name]
+        self.builtin = "true"
+        if self.name == "QualifiedName":
+            self.members = [StructMember("namespaceIndex", types["Int16"], False), StructMember("name", types["String"], False)]
+        elif self.name in ["String", "ByteString", "XmlElement"]:
+            self.members = [StructMember("", types["Byte"], True)]
         else:
-            typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % \
-                     (description.namespaceid, description.nodeid)
-        if self.name in ["UA_String", "UA_ByteString", "UA_XmlElement"]:
-            return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-                ".memSize = sizeof(" + self.name + "), " + \
-                ".builtin = true, .fixedSize = false, .zeroCopyable = false, " + \
-                ".membersSize = 1,\n\t.members = (UA_DataTypeMember[]){{.memberTypeIndex = UA_TYPES_BYTE, .namespaceZero = true, " + \
-                (".memberName = \"\", " if typeintrospection else "") + \
-                ".padding = 0, .isArray = true }}, " + \
-                ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
-
-        if self.name == "UA_QualifiedName":
-            return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-                ".memSize = sizeof(UA_QualifiedName), " + \
-                ".builtin = true, .fixedSize = false, .zeroCopyable = false, " + \
-                ".membersSize = 2, .members = (UA_DataTypeMember[]){" + \
-                "\n\t{.memberTypeIndex = UA_TYPES_UINT16, .namespaceZero = true, " + \
-                (".memberName = \"namespaceIndex\", " if typeintrospection else "") + \
-                ".padding = 0, .isArray = false }," + \
-                "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = true, " + \
-                (".memberName = \"name\", " if typeintrospection else "") + \
-                ".padding = offsetof(UA_QualifiedName, name)-sizeof(UA_UInt16), .isArray = false }},\n" + \
-                ".typeIndex = UA_TYPES_QUALIFIEDNAME }"
-
-        return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-            ".memSize = sizeof(" + self.name + "), " + \
-            ".builtin = true, .fixedSize = " + ("true" if self.fixed_size() else "false") + \
-            ", .zeroCopyable = " + ("true" if self.zero_copy() else "false") + \
-            ", .membersSize = 1, .members = (UA_DataTypeMember[]){" + \
-            "\n\t{.memberTypeIndex = UA_TYPES_" + self.name[3:].upper() + " , .namespaceZero = true, " + \
-            (".memberName = \"\", " if typeintrospection else "") + \
-            ".padding = 0, .isArray = false }},\n" + \
-            ".typeIndex = UA_TYPES_" + self.name[3:].upper() + " }"
+            self.members = [StructMember("", self, False)]
 
 class EnumerationType(Type):
-    def __init__(self, name, description = "", elements = OrderedDict()):
-        self.name = name
-        self.description = description
-        self.elements = elements # maps a name to an integer value
-
-    def append_enum(name, value):
-        self.elements[name] = value
-
-    def fixed_size(self):
-        return True
-
-    def mem_size(self):
-        return 4
-
-    def zero_copy(self):
-        return True
-
-    def typedef_c(self):
+    def __init__(self, outname, xml):
+        Type.__init__(self, outname, xml)
+        self.fixed_size = "true"
+        self.overlayable = "UA_BINARY_OVERLAYABLE_INTEGER"
+        self.members = [StructMember("", types["Int32"], False)] # encoded as uint32
+        self.elements = OrderedDict()
+        for child in xml:
+            if child.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedValue":
+                self.elements[child.get("Name")] = child.get("Value")
+    
+    def typedef_h(self):
         if sys.version_info[0] < 3:
             values = self.elements.iteritems()
         else:
             values = self.elements.items()
-        return "typedef enum { \n    " + \
-            ",\n    ".join(map(lambda kv : kv[0].upper() + " = " + kv[1], values)) + \
-            "\n} " + self.name + ";"
-
-    def typelayout_c(self, namespace_0, description, outname):
-        if description == None:
-            typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
-        else:
-            typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
-        return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-            ".memSize = sizeof(" + self.name + "), .builtin = true, " + \
-            ".fixedSize = true, .zeroCopyable = true, " + \
-            ".membersSize = 1,\n\t.members = (UA_DataTypeMember[]){{.memberTypeIndex = UA_TYPES_INT32, " + \
-            (".memberName = \"\", " if typeintrospection else "") + \
-            ".namespaceZero = true, .padding = 0, .isArray = false }}, .typeIndex = UA_TYPES_INT32 }"
+        return "typedef enum { \n    " + ",\n    ".join(map(lambda kv : "UA_" + self.name.upper() + "_" + kv[0].upper() + \
+                                                            " = " + kv[1], values)) + "\n} UA_%s;" % self.name
 
 class OpaqueType(Type):
-    def fixed_size(self):
-        return False
-
-    def zero_copy(self):
-        return False
-
-    def typedef_c(self):
-        return "typedef UA_ByteString " + self.name + ";"
-
-    def typelayout_c(self, namespace_0, description, outname):
-        if description == None:
-            typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
-        else:
-            typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
-        return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-            ".memSize = sizeof(" + self.name + "), .fixedSize = false, .zeroCopyable = false, " + \
-            ".builtin = false, .membersSize = 1,\n\t.members = (UA_DataTypeMember[]){{.memberTypeIndex = UA_TYPES_BYTE," + \
-            (".memberName = \"\", " if typeintrospection else "") + \
-            ".namespaceZero = true, .padding = 0, .isArray = true }}, .typeIndex = %s}" % (outname.upper() + "_" + self.name[3:].upper())
+    def __init__(self, outname, xml):
+        Type.__init__(self, outname, xml)
+        self.members = [StructMember("", types["ByteString"], False)] # encoded as string
 
-class StructMember(object):
-    def __init__(self, name, memberType, isArray):
-        self.name = name
-        self.memberType = memberType
-        self.isArray = isArray
+    def typedef_h(self):
+        return "typedef UA_ByteString UA_%s;" % self.name
 
 class StructType(Type):
-    def __init__(self, name, description, members = OrderedDict()):
-        self.name = name
-        self.description = description
-        self.members = members # maps a name to a member definition
-
-    def fixed_size(self):
-        for m in self.members.values():
-            if m.isArray or not m.memberType.fixed_size():
-                return False
-        return True
-
-    def mem_size(self):
-        total = 0
-        for m in self.members.values():
-            if m.isArray:
-                raise Exception("Arrays have no fixed size!")
+    def __init__(self, outname, xml):
+        Type.__init__(self, outname, xml)
+        self.members = []
+        lengthfields = [] # lengthfields of arrays are not included as members
+        for child in xml:
+            if child.get("LengthField"):
+                lengthfields.append(child.get("LengthField"))
+        for child in xml:
+            if not child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
+                continue
+            if child.get("Name") in lengthfields:
+                continue
+            memberName = child.get("Name")
+            memberName = memberName[:1].lower() + memberName[1:]
+            memberTypeName = child.get("TypeName")
+            memberType = types[memberTypeName[memberTypeName.find(":")+1:]]
+            isArray = True if child.get("LengthField") else False
+            self.members.append(StructMember(memberName, memberType, isArray))
+
+        self.fixed_size = "true"
+        self.overlayable = "true"
+        before = None
+        for m in self.members:
+            if m.isArray or m.memberType.fixed_size != "true":
+                self.fixed_size = "false"
+                self.overlayable = "false"
             else:
-                total += m.memberType.mem_size()
-        return total
-
-    def zero_copy(self):
-        for m in self.members.values():
-            if m.isArray or not m.memberType.zero_copy():
-                return False
-        return True
-
-    def typedef_c(self):
+                self.overlayable += " && " + m.memberType.overlayable
+                if before:
+                    self.overlayable += " && offsetof(UA_%s, %s) == (offsetof(UA_%s, %s) + sizeof(UA_%s))" % \
+                                        (self.name, m.name, self.name, before.name, before.memberType.name)
+            if "false" in self.overlayable:
+                self.overlayable = "false"
+            before = m
+
+    def typedef_h(self):
         if len(self.members) == 0:
-            return "typedef void * " + self.name + ";"
+            return "typedef void * UA_%s;" % self.name
         returnstr =  "typedef struct {\n"
-        if sys.version_info[0] < 3:
-            values = self.members.iteritems()
-        else:
-            values = self.members.items()
-        for name, member in values:
+        for member in self.members:
             if member.isArray:
-                returnstr += "    size_t " + name + "Size;\n"
-                returnstr += "    " + member.memberType.name + " *" +name + ";\n"
+                returnstr += "    size_t %sSize;\n" % member.name
+                returnstr += "    UA_%s *%s;\n" % (member.memberType.name, member.name)
             else:
-                returnstr += "    " + member.memberType.name + " " +name + ";\n"
-        return returnstr + "} " + self.name + ";"
+                returnstr += "    UA_%s %s;\n" % (member.memberType.name, member.name)
+        return returnstr + "} UA_%s;" % self.name
 
-    def typelayout_c(self, namespace_0, description, outname):
-        if description == None:
-            typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
-        else:
-            typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
-        layout = (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-                 ".memSize = sizeof(" + self.name + "), "+ \
-                 ".builtin = false" + \
-                 ", .fixedSize = " + ("true" if self.fixed_size() else "false") + \
-                 ", .zeroCopyable = " + ("sizeof(" + self.name + ") == " + str(self.mem_size()) if self.zero_copy() \
-                                         else "false") + \
-                 ", .typeIndex = " + outname.upper() + "_" + self.name[3:].upper() + \
-                 ", .membersSize = " + str(len(self.members)) + ","
-        if len(self.members) > 0:
-            layout += "\n\t.members=(UA_DataTypeMember[]){"
-            for index, member in enumerate(self.members.values()):
-                layout += "\n\t{" + \
-                          ((".memberName = \"" + member.name + "\", ") if typeintrospection else "") + \
-                          ".memberTypeIndex = " + ("UA_TYPES_" + member.memberType.name[3:].upper() if args.namespace_id == 0 or member.memberType.name in existing_types else \
-                                                   outname.upper() + "_" + member.memberType.name[3:].upper()) + ", " + \
-                          ".namespaceZero = "+ \
-                          ("true, " if args.namespace_id == 0 or member.memberType.name in existing_types else "false, ") + \
-                          ".padding = "
-
-                if not member.isArray:
-                    thispos = "offsetof(%s, %s)" % (self.name, member.name)
-                else:
-                    thispos = "offsetof(%s, %sSize)" % (self.name, member.name)
-                before_endpos = "0"
-                if index > 0:
-                    if sys.version_info[0] < 3:
-                        before = self.members.values()[index-1]
-                    else:
-                        before = list(self.members.values())[index-1]
-                    before_endpos = "(offsetof(%s, %s)" % (self.name, before.name)
-                    if before.isArray:
-                        before_endpos += " + sizeof(void*))"
-                    else:
-                        before_endpos += " + sizeof(%s))" % before.memberType.name
-                layout += "%s - %s" % (thispos, before_endpos)
-
-                layout += ", .isArray = " + ("true" if member.isArray else "false") + " }, "
-            layout += "}"
-        return layout + "}"
-
-def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
-    '''Returns an ordered dict that maps names to types. The order is such that
-       every type depends only on known types. '''
+#########################
+# Parse Typedefinitions #
+#########################
+
+def parseTypeDefinitions(outname, xmlDescription):
     ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
     tree = etree.parse(xmlDescription)
     typeSnippets = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
-    types = OrderedDict(existing_types.items())
 
-    # types we do not want to autogenerate
+    def typeReady(element):
+        "Are all member types defined?"
+        for child in element:
+            if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
+                childname = child.get("TypeName")
+                if childname[childname.find(":")+1:] not in types:
+                    return False
+        return True
+
     def skipType(name):
-        if name in builtin_types:
-            return True
         if name in excluded_types:
             return True
-        if outname == "ua_types" and not name[3:] in minimal_types:
-            return True
         if "Test" in name: # skip all test types
             return True
         if re.search("NodeId$", name) != None:
             return True
         return False
 
-    def stripTypename(tn):
-        return tn[tn.find(":")+1:]
-
-    def camlCase2CCase(item):
-        "Member names begin with a lower case character"
-        return item[:1].lower() + item[1:] if item else ''
-
-    def typeReady(element):
-        "Do we have the member types yet?"
-        for child in element:
-            if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
-                if stripTypename(child.get("TypeName")) not in types:
-                    return False
-        return True
-
-    def parseEnumeration(typeXml):	
-        name = "UA_" + typeXml.get("Name")
-        description = ""
-        elements = OrderedDict()
-        for child in typeXml:
-            if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
-                description = child.text
-            if child.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedValue":
-                elements[name + "_" + child.get("Name")] = child.get("Value")
-        return EnumerationType(name, description, elements)
+    snippets = {}
+    for typeXml in typeSnippets:
+        name = typeXml.get("Name")
+        snippets[name] = typeXml
 
-    def parseOpaque(typeXml):
-        name = "UA_" + typeXml.get("Name")
-        description = ""
-        for child in typeXml:
-            if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
-                description = child.text
-        return OpaqueType(name, description)
-
-    def parseStructured(typeXml):
-        "Returns None if we miss member descriptions"
-        name = "UA_" + typeXml.get("Name")
-        description = ""
-        for child in typeXml:
-            if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
-                description = child.text
-        # ignore lengthfields, just tag the array-members as an array
-        lengthfields = []
-        for child in typeXml:
-            if child.get("LengthField"):
-                lengthfields.append(child.get("LengthField"))
-        members = OrderedDict()
-        for child in typeXml:
-            if not child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
-                continue
-            if child.get("Name") in lengthfields:
-                continue
-            memberTypeName = "UA_" + stripTypename(child.get("TypeName"))
-            if not memberTypeName in types:
-                return None
-            memberType = types[memberTypeName]
-            memberName = camlCase2CCase(child.get("Name"))
-            isArray = True if child.get("LengthField") else False
-            members[memberName] = StructMember(memberName, memberType, isArray)
-        return StructType(name, description, members)
-
-    finished = False
-    while(not finished):
-        finished = True
-        for typeXml in typeSnippets:
-            name = "UA_" + typeXml.get("Name")
+    while(len(snippets) > 0):
+        for name, typeXml in snippets.items():
             if name in types or skipType(name):
+                del snippets[name]
+                continue
+            if not typeReady(typeXml):
                 continue
-            if typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
-                t = parseEnumeration(typeXml)
-                types[t.name] = t
+            if name in builtin_types:
+                types[name] = BuiltinType(name)
+            elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
+                types[name] = EnumerationType(outname, typeXml)
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
-                t = parseOpaque(typeXml)
-                types[t.name] = t
+                types[name] = OpaqueType(outname, typeXml)
             elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
-                t = parseStructured(typeXml)
-                if t == None:
-                    finished = False
-                else:
-                    types[t.name] = t
+                types[name] = StructType(outname, typeXml)
+            else:
+                raise Exception("Type not known")
+            del snippets[name]
+
+##########################
+# Parse TypeDescriptions #
+##########################
 
-    # remove the existing types
-    for k in existing_types.keys():
-        types.pop(k)
-    return types
+class TypeDescription(object):
+    def __init__(self, name, nodeid, namespaceid):
+        self.name = name
+        self.nodeid = nodeid
+        self.namespaceid = namespaceid
+
+def parseTypeDescriptions(filename, namespaceid):
+    definitions = {}
+    with open(filename) as f:
+        input_str = f.read()
+    input_str = input_str.replace('\r','')
+    rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
+    for index, row in enumerate(rows):
+        if len(row) < 3:
+            continue
+        if row[2] != "DataType":
+            continue
+        if row[0] == "BaseDataType":
+            definitions["Variant"] = TypeDescription(row[0], row[1], namespaceid)
+        elif row[0] == "Structure":
+            definitions["ExtensionObject"] = TypeDescription(row[0], row[1], namespaceid)
+        elif row[0] not in types:
+            continue
+        elif type(types[row[0]]) == EnumerationType:
+            definitions[row[0]] = TypeDescription(row[0], "6", namespaceid) # enumerations look like int32 on the wire
+        else:
+            definitions[row[0]] = TypeDescription(row[0], row[1], namespaceid)
+    return definitions
+
+###############################
+# Parse the Command Line Input#
+###############################
 
 parser = argparse.ArgumentParser()
-parser.add_argument('--ns0-types-xml', nargs=1, help='xml-definition of the ns0 types that are assumed to already exist')
-parser.add_argument('--enable-subscription-types', nargs=1, help='Generate datatypes necessary for Montoring and Subscriptions.')
-parser.add_argument('--typedescriptions', nargs=1, help='csv file with type descriptions')
-parser.add_argument('--typeintrospection', help='add the type and member names to the idatatype structures', action='store_true')
-parser.add_argument('namespace_id', type=int, help='the id of the target namespace')
-parser.add_argument('types_xml', help='path/to/Opc.Ua.Types.bsd')
+parser.add_argument('--typedescriptions', help='csv file with type descriptions')
+parser.add_argument('--namespace', type=int, default=0, help='namespace id of the generated type nodeids (defaults to 0)')
+parser.add_argument('--selected_types', help='file with list of types (among those parsed) to be generated')
+parser.add_argument('typexml_ns0', help='path/to/Opc.Ua.Types.bsd ...')
+parser.add_argument('typexml_additional', nargs='*', help='path/to/Opc.Ua.Types.bsd ...')
 parser.add_argument('outfile', help='output file w/o extension')
-
 args = parser.parse_args()
+
 outname = args.outfile.split("/")[-1] 
-inname = args.types_xml.split("/")[-1]
-typeintrospection = args.typeintrospection
-existing_types = OrderedDict()
-if args.enable_subscription_types:
-    minimal_types = minimal_types + subscription_types
-if args.namespace_id == 0 or args.ns0_types_xml:
-    existing_types = OrderedDict([(t, BuiltinType(t)) for t in builtin_types])
-if args.ns0_types_xml:
-    if sys.version_info[0] < 3:
-        OrderedDict(existing_types.items() + parseTypeDefinitions(args.ns0_types_xml[0], existing_types).items())
-    else:
-        OrderedDict(list(existing_types.items()) + list(parseTypeDefinitions(args.ns0_types_xml[0], existing_types).items()))
-types = parseTypeDefinitions(args.types_xml, existing_types)
-if args.namespace_id == 0:
-    if sys.version_info[0] < 3:
-        types = OrderedDict(existing_types.items() + types.items())
-    else:
-        types = OrderedDict(list(existing_types.items()) + list(types.items()))
+inname = ', '.join([args.typexml_ns0.split("/")[-1]] + map(lambda x:x.split("/")[-1], args.typexml_additional))
+
+################
+# Create Types #
+################
+
+for builtin in builtin_types:
+    types[builtin] = BuiltinType(builtin)
+
+with open(args.typexml_ns0) as f:
+    parseTypeDefinitions("ua_types", f)
+for typexml in args.typexml_additional:
+    with open(typexml) as f:
+        parseTypeDefinitions(outname, f)
 
 typedescriptions = {}
 if args.typedescriptions:
-    typedescriptions = parseTypeDescriptions(args.typedescriptions, args.namespace_id)
+    typedescriptions = parseTypeDescriptions(args.typedescriptions, args.namespace)
+
+selected_types = types.keys()
+if args.selected_types:
+    with open(args.selected_types) as f:
+        selected_types = filter(len, [line.strip() for line in f])
+
+#############################
+# Write out the Definitions #
+#############################
 
 fh = open(args.outfile + "_generated.h",'w')
 fe = open(args.outfile + "_generated_encoding_binary.h",'w')
@@ -479,7 +369,8 @@ def printc(string):
     print(string, end='\n', file=fc)
 
 printh('''/* Generated from ''' + inname + ''' 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 ''' + outname.upper() + '''_GENERATED_H_
 #define ''' + outname.upper() + '''_GENERATED_H_
@@ -491,24 +382,56 @@ extern "C" {
 #include "ua_types.h"
 #ifdef UA_INTERNAL
 #include "ua_types_encoding_binary.h"
-#endif'''
- + ('\n#include "ua_types_generated.h"\n' if args.namespace_id != 0 else '') + '''
+#endif''' + ('\n#include "ua_types_generated.h"\n' if outname != "ua_types" else '') + '''
 
 /**
  * Additional Data Type Definitions
  * ================================
  */
 ''')
-printh("#define " + outname.upper() + "_COUNT %s" % (str(len(types))))
+
+printh("#define " + outname.upper() + "_COUNT %s" % (str(len(selected_types))))
 printh("extern UA_EXPORT const UA_DataType " + outname.upper() + "[" + outname.upper() + "_COUNT];")
 
-i = 0
+printc('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
+ * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + \
+       ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
+ 
+#include "stddef.h"
+#include "ua_types.h"
+#include "''' + outname + '''_generated.h"''')
+
+printe('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
+ * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + \
+       ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
+ 
+#include "ua_types_encoding_binary.h"
+#include "''' + outname + '''_generated.h"''')
+
 if sys.version_info[0] < 3:
     values = types.itervalues()
 else:
     values = types.values()
 
+# Datatype members
 for t in values:
+    if not t.name in selected_types:
+        continue
+    printc("")
+    printc("/* " + t.name + " */")
+    printc(t.members_c())
+printc("const UA_DataType %s[%s_COUNT] = {" % (outname.upper(), outname.upper()))
+
+if sys.version_info[0] < 3:
+    values = types.itervalues()
+else:
+    values = types.values()
+
+i = 0
+for t in values:
+    if not t.name in selected_types:
+        continue
+    # Header
     printh("\n/**\n * " +  t.name)
     printh(" * " + "-" * len(t.name))
     if t.description == "":
@@ -516,10 +439,18 @@ for t in values:
     else:
         printh(" * " + t.description + " */")
     if type(t) != BuiltinType:
-        printh(t.typedef_c() + "\n")
-    printh("#define " + outname.upper() + "_" + t.name[3:].upper() + " " + str(i))
-    printh(t.functions_c(outname.upper()))
+        printh(t.typedef_h() + "\n")
+    printh("#define " + outname.upper() + "_" + t.name.upper() + " " + str(i))
+    printh(t.functions_c())
     i += 1
+    # Datatype
+    printc("")
+    printc("/* " + t.name + " */")
+    printc(t.datatype_c() + ",")
+    # Encoding
+    printe("")
+    printe("/* " + t.name + " */")
+    printe(t.encoding_h())
 
 printh('''
 #ifdef __cplusplus
@@ -527,36 +458,8 @@ printh('''
 #endif\n
 #endif /* %s_GENERATED_H_ */''' % outname.upper())
 
-printe('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
- * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
- 
-#include "ua_types_encoding_binary.h"
-#include "''' + outname + '''_generated.h"''')
-
-printc('''/* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
- * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + ''' */
- 
-#include "stddef.h"
-#include "ua_types.h"
-#include "''' + outname + '''_generated.h"\n
-const UA_DataType ''' + outname.upper() + '''[] = {''')
-if sys.version_info[0] < 3:
-    values = types.itervalues()
-else:
-    values = types.values()
-for t in values:
-    printc("")
-    printc("/* " + t.name + " */")
-    if args.typedescriptions:
-        td = typedescriptions[t.name]
-    else:
-        td = None
-    printc(t.typelayout_c(args.namespace_id == 0, td, outname) + ",")
-    printe("")
-    printe("/* " + t.name + " */")
-    printe(t.encoding_h(outname.upper()))
 printc("};\n")
 
 fh.close()
-fe.close()
 fc.close()
+fe.close()

+ 154 - 0
tools/schema/datatypes_minimal.txt

@@ -0,0 +1,154 @@
+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
+NodeClass
+ReferenceNode
+ApplicationDescription
+ApplicationType
+ChannelSecurityToken
+OpenSecureChannelRequest
+OpenSecureChannelResponse
+CloseSecureChannelRequest
+CloseSecureChannelResponse
+RequestHeader
+ResponseHeader
+SecurityTokenRequestType
+MessageSecurityMode
+CloseSessionResponse
+CloseSessionRequest
+ActivateSessionRequest
+ActivateSessionResponse
+SignatureData
+SignedSoftwareCertificate
+CreateSessionResponse
+CreateSessionRequest
+EndpointDescription
+UserTokenPolicy
+UserTokenType
+GetEndpointsRequest
+GetEndpointsResponse
+PublishRequest
+PublishResponse
+FindServersRequest
+FindServersResponse
+SetPublishingModeResponse
+SubscriptionAcknowledgement
+ReadRequest
+ReadResponse
+ReadValueId
+TimestampsToReturn
+WriteRequest
+WriteResponse
+WriteValue
+SetPublishingModeRequest
+CreateMonitoredItemsResponse
+MonitoredItemCreateResult
+CreateMonitoredItemsRequest
+MonitoredItemCreateRequest
+MonitoringMode
+MonitoringParameters
+TranslateBrowsePathsToNodeIdsRequest
+TranslateBrowsePathsToNodeIdsResponse
+BrowsePath
+BrowsePathResult
+RelativePath
+BrowsePathTarget
+RelativePathElement
+BrowseResponse
+BrowseResult
+ReferenceDescription
+BrowseRequest
+ViewDescription
+BrowseNextRequest
+BrowseNextResponse
+DeleteSubscriptionsRequest
+DeleteSubscriptionsResponse
+BrowseDescription
+BrowseDirection
+AddNodesRequest
+AddNodesResponse
+AddNodesItem
+AddNodesResult
+AddReferencesRequest
+AddReferencesResponse
+AddReferencesItem
+BrowseResultMask
+ServerState
+ServerStatusDataType
+BuildInfo
+IdType
+NodeAttributes
+VariableAttributes
+ObjectAttributes
+ReferenceTypeAttributes
+ViewAttributes
+MethodAttributes
+ObjectTypeAttributes
+VariableTypeAttributes
+DataTypeAttributes
+NodeAttributesMask
+DeleteNodesItem
+DeleteNodesRequest
+DeleteNodesResponse
+DeleteReferencesItem
+DeleteReferencesRequest
+DeleteReferencesResponse
+RegisterNodesRequest
+RegisterNodesResponse
+UnregisterNodesRequest
+UnregisterNodesResponse
+UserIdentityToken
+UserNameIdentityToken
+AnonymousIdentityToken
+ServiceFault
+CallMethodRequest
+CallMethodResult
+CallResponse
+CallRequest
+Argument
+FilterOperator
+ContentFilterElement
+ContentFilter
+QueryDataDescription
+NodeTypeDescription
+QueryFirstRequest
+QueryDataSet
+ParsingResult
+ContentFilterElementResult
+ContentFilterResult
+QueryFirstResponse
+QueryNextRequest
+QueryNextResponse
+CreateSubscriptionRequest
+CreateSubscriptionResponse
+DeleteMonitoredItemsRequest
+DeleteMonitoredItemsResponse
+NotificationMessage
+MonitoredItemNotification
+DataChangeNotification
+ModifySubscriptionRequest
+ModifySubscriptionResponse
+RepublishRequest
+RepublishResponse

+ 10 - 0
tools/schema/datatypes_transport.txt

@@ -0,0 +1,10 @@
+MessageTypeAndFinal
+TcpMessageHeader
+TcpHelloMessage
+TcpAcknowledgeMessage
+SecureConversationMessageHeader
+AsymmetricAlgorithmSecurityHeader
+SymmetricAlgorithmSecurityHeader
+SequenceHeader
+SecureConversationMessageFooter
+SecureConversationMessageAbortBody

tools/travis_linux_before_install.sh → tools/travis/travis_linux_before_install.sh


tools/travis_linux_script.sh → tools/travis/travis_linux_script.sh


tools/travis_osx_before_install.sh → tools/travis/travis_osx_before_install.sh


tools/travis_osx_script.sh → tools/travis/travis_osx_script.sh


tools/travis_push_coverity.sh → tools/travis/travis_push_coverity.sh


tools/travis_push_doc.sh → tools/travis/travis_push_doc.sh


tools/travis_push_release.sh → tools/travis/travis_push_release.sh