소스 검색

clean up ua_types.h, fix unit tests

Julius Pfrommer 9 년 전
부모
커밋
02745117d6
8개의 변경된 파일402개의 추가작업 그리고 463개의 파일을 삭제
  1. 2 8
      examples/networklayer_tcp.c
  2. 5 3
      examples/server_readspeed.c
  3. 292 345
      include/ua_types.h
  4. 1 1
      src/server/ua_services_attribute.c
  5. 5 10
      src/ua_types.c
  6. 65 66
      src/ua_types_encoding_binary.c
  7. 9 7
      tests/check_memory.c
  8. 23 23
      tests/check_services_attributes.c

+ 2 - 8
examples/networklayer_tcp.c

@@ -200,10 +200,7 @@ static UA_StatusCode
 ServerNetworkLayerGetSendBuffer(UA_Connection *connection, size_t length, UA_ByteString *buf) {
     if(length > connection->remoteConf.recvBufferSize)
         return UA_STATUSCODE_BADCOMMUNICATIONERROR;
-    *buf = UA_ByteString_withSize(length);
-    if(buf->data == NULL)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    return UA_STATUSCODE_GOOD;
+    return UA_ByteString_allocBuffer(buf, length);
 }
 
 static void
@@ -459,10 +456,7 @@ ClientNetworkLayerGetBuffer(UA_Connection *connection, size_t length, UA_ByteStr
         return UA_STATUSCODE_BADCOMMUNICATIONERROR;
     if(connection->state == UA_CONNECTION_CLOSED)
         return UA_STATUSCODE_BADCONNECTIONCLOSED;
-    *buf = UA_ByteString_withSize(connection->remoteConf.recvBufferSize);
-    if(buf->data == NULL)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    return UA_STATUSCODE_GOOD;
+    return UA_ByteString_allocBuffer(buf, connection->remoteConf.recvBufferSize);
 }
 
 static void

+ 5 - 3
examples/server_readspeed.c

@@ -61,10 +61,12 @@ int main(int argc, char** argv) {
     request.nodesToReadSize = 1;
     request.nodesToRead = &rvi;
 
-    UA_ByteString request_msg = UA_ByteString_withSize(1000);
-    UA_ByteString response_msg = UA_ByteString_withSize(1000);
-    size_t offset = 0;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    UA_ByteString request_msg;
+    retval |= UA_ByteString_allocBuffer(&request_msg, 1000);
+    UA_ByteString response_msg;
+    retval |= UA_ByteString_allocBuffer(&response_msg, 1000);
+    size_t offset = 0;
     retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_READREQUEST], &request_msg, &offset);
     
     clock_t begin, end;

+ 292 - 345
include/ua_types.h

@@ -37,68 +37,106 @@ extern "C" {
 
 #define UA_BUILTIN_TYPES_COUNT 25
 
-/** A two-state logical value (true or false). */
+/** Boolean: A two-state logical value (true or false) */
 typedef bool UA_Boolean;
 #define UA_TRUE true
 #define UA_FALSE false
 
-/** An integer value between -128 and 127. */
+/** SByte: An integer value between -128 and 127 */
 typedef int8_t UA_SByte;
 #define UA_SBYTE_MAX 127
 #define UA_SBYTE_MIN (-128)
 
-/** An integer value between 0 and 256. */
+/** Byte: An integer value between 0 and 256 */
 typedef uint8_t UA_Byte;
 #define UA_BYTE_MAX 256
 #define UA_BYTE_MIN 0
 
-/** An integer value between -32 768 and 32 767. */
+/** Int16: An integer value between -32 768 and 32 767 */
 typedef int16_t UA_Int16;
 #define UA_INT16_MAX 32767
 #define UA_INT16_MIN (-32768)
 
-/** An integer value between 0 and 65 535. */
+/** UInt16: An integer value between 0 and 65 535 */
 typedef uint16_t UA_UInt16;
 #define UA_UINT16_MAX 65535
 #define UA_UINT16_MIN 0
 
-/** An integer value between -2 147 483 648 and 2 147 483 647. */
+/** Int32: An integer value between -2 147 483 648 and 2 147 483 647 */
 typedef int32_t UA_Int32;
 #define UA_INT32_MAX 2147483647
 #define UA_INT32_MIN (-2147483648)
 
-/** An integer value between 0 and 429 4967 295. */
+/** UInt32: An integer value between 0 and 429 4967 295 */
 typedef uint32_t UA_UInt32;
 #define UA_UINT32_MAX 4294967295
 #define UA_UINT32_MIN 0
 
-/** An integer value between -10 223 372 036 854 775 808 and 9 223 372 036 854 775 807 */
+/** Int64: An integer value between -10 223 372 036 854 775 808 and 9 223 372 036 854 775 807 */
 typedef int64_t UA_Int64;
 #define UA_INT64_MAX (int64_t)9223372036854775807
 #define UA_INT64_MIN ((int64_t)-9223372036854775808)
 
-/** An integer value between 0 and 18 446 744 073 709 551 615. */
+/** UInt64: An integer value between 0 and 18 446 744 073 709 551 615 */
 typedef uint64_t UA_UInt64;
 #define UA_UINT64_MAX (int64_t)18446744073709551615
 #define UA_UINT64_MIN (int64_t)0
 
-/** An IEEE single precision (32 bit) floating point value. */
+/** Float: An IEEE single precision (32 bit) floating point value */
 typedef float UA_Float;
 
-/** An IEEE double precision (64 bit) floating point value. */
+/** Double: An IEEE double precision (64 bit) floating point value */
 typedef double UA_Double;
 
-/** A sequence of Unicode characters. */
+/********************************************/
+/* String: A sequence of Unicode characters */
+/********************************************/
 typedef struct {
     size_t length; ///< The length of the string
     UA_Byte *data; ///< The string's content (not null-terminated)
 } UA_String;
 
-/** An instance in time. A DateTime value is encoded as a 64-bit signed integer which represents the
-    number of 100 nanosecond intervals since January 1, 1601 (UTC). */
+UA_EXPORT extern const UA_String UA_STRING_NULL;
+
+static UA_INLINE UA_String UA_STRING(char *chars) {
+    UA_String str; str.length = strlen(chars);
+    str.data   = (UA_Byte*)chars; return str; }
+
+#define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
+    
+/** Copies the content on the heap. Returns a null-string when alloc fails */
+UA_String UA_EXPORT UA_String_fromChars(char const src[]) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+UA_Boolean UA_EXPORT UA_String_equal(const UA_String *s1, const UA_String *s2);
+
+/*********************************/
+/* DateTime: An instance in time */
+/*********************************/
+/* A DateTime value is encoded as a 64-bit signed integer which represents the
+   number of 100 nanosecond intervals since January 1, 1601 (UTC). */
 typedef UA_Int64 UA_DateTime;
 
-/** A 16 byte value that can be used as a globally unique identifier. */
+UA_DateTime UA_EXPORT UA_DateTime_now(void); ///> The current time
+
+typedef struct UA_DateTimeStruct {
+    UA_UInt16 nanoSec;
+    UA_UInt16 microSec;
+    UA_UInt16 milliSec;
+    UA_UInt16 sec;
+    UA_UInt16 min;
+    UA_UInt16 hour;
+    UA_UInt16 day;
+    UA_UInt16 month;
+    UA_UInt16 year;
+} UA_DateTimeStruct;
+
+UA_DateTimeStruct UA_EXPORT UA_DateTime_toStruct(UA_DateTime time);
+
+UA_String UA_EXPORT UA_DateTime_toString(UA_DateTime time);
+
+/**************************************************************************/
+/* Guid: A 16 byte value that can be used as a globally unique identifier */
+/**************************************************************************/
 typedef struct {
     UA_UInt32 data1;
     UA_UInt16 data2;
@@ -106,12 +144,39 @@ typedef struct {
     UA_Byte   data4[8];
 } UA_Guid;
 
-/** A sequence of octets. */
+UA_Boolean UA_EXPORT UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
+
+UA_Guid UA_EXPORT UA_Guid_random(UA_UInt32 *seed);
+
+/************************************/
+/* ByteString: A sequence of octets */
+/************************************/
 typedef UA_String UA_ByteString;
 
-/** An XML element. */
+static UA_INLINE UA_Boolean UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2) {
+    return UA_String_equal((const UA_String*)string1, (const UA_String*)string2); }
+
+/* Allocates memory of size length for the bytestring. The content is not set to zero. */
+UA_StatusCode UA_EXPORT UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+UA_EXPORT extern const UA_ByteString UA_BYTESTRING_NULL;
+
+static UA_INLINE UA_ByteString UA_BYTESTRING(char *chars) {
+    UA_ByteString str; str.length = strlen(chars); str.data = (UA_Byte*)chars; return str; }
+
+static UA_INLINE UA_ByteString UA_BYTESTRING_ALLOC(const char *chars) {
+    UA_String str = UA_String_fromChars(chars); UA_ByteString bstr;
+    bstr.length = str.length; bstr.data = str.data; return bstr;
+}
+
+/******************************/
+/* XmlElement: An XML element */
+/******************************/
 typedef UA_String UA_XmlElement;
 
+/*****************************************************************************/
+/* NodeId: An identifier for a node in the address space of an OPC UA Server */
+/*****************************************************************************/
 enum UA_NodeIdType {
     UA_NODEIDTYPE_NUMERIC    = 0, ///< On the wire, this can be 0,1,2 for numeric nodeids of different sizes
     UA_NODEIDTYPE_STRING     = 3,
@@ -119,8 +184,6 @@ enum UA_NodeIdType {
     UA_NODEIDTYPE_BYTESTRING = 5
 };
 
-/** An identifier for a node in the address space of an OPC UA Server. The shortened numeric types
-    are introduced during encoding. */
 typedef struct {
     UA_UInt16 namespaceIndex;
     enum UA_NodeIdType identifierType;
@@ -132,30 +195,110 @@ typedef struct {
     } identifier;
 } UA_NodeId;
 
-/** A NodeId that allows the namespace URI to be specified instead of an index. */
+static UA_INLINE UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
+    return (p->namespaceIndex == 0 && p->identifierType == UA_NODEIDTYPE_NUMERIC &&
+            p->identifier.numeric == 0);
+}
+
+UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
+
+UA_EXPORT extern const UA_NodeId UA_NODEID_NULL;
+
+static UA_INLINE UA_NodeId UA_NODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier) {
+    UA_NodeId id; id.namespaceIndex = nsIndex; id.identifierType = UA_NODEIDTYPE_NUMERIC;
+    id.identifier.numeric = identifier; return id; }
+
+static UA_INLINE UA_NodeId UA_NODEID_STRING(UA_UInt16 nsIndex, char *chars) {
+    UA_NodeId id; id.namespaceIndex = nsIndex; id.identifierType = UA_NODEIDTYPE_STRING;
+    id.identifier.string = UA_STRING(chars); return id; }
+
+static UA_INLINE UA_NodeId UA_NODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
+    UA_NodeId id; id.namespaceIndex = nsIndex; id.identifierType = UA_NODEIDTYPE_STRING;
+    id.identifier.string = UA_STRING_ALLOC(chars); return id; }
+
+static UA_INLINE UA_NodeId UA_NODEID_GUID(UA_UInt16 nsIndex, UA_Guid guid) {
+    UA_NodeId id; id.namespaceIndex = nsIndex; id.identifierType = UA_NODEIDTYPE_GUID;
+    id.identifier.guid = guid; return id; }
+
+static UA_INLINE UA_NodeId UA_NODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars) {
+    UA_NodeId id; id.namespaceIndex = nsIndex; id.identifierType = UA_NODEIDTYPE_BYTESTRING;
+    id.identifier.byteString = UA_BYTESTRING(chars); return id; }
+
+static UA_INLINE UA_NodeId UA_NODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
+    UA_NodeId id; id.namespaceIndex = nsIndex; id.identifierType = UA_NODEIDTYPE_BYTESTRING;
+    id.identifier.byteString = UA_BYTESTRING_ALLOC(chars); return id; }
+
+/**********************************************************************************************/
+/* ExpandedNodeId: A NodeId that allows the namespace URI to be specified instead of an index */
+/**********************************************************************************************/
 typedef struct {
     UA_NodeId nodeId;
     UA_String namespaceUri;
     UA_UInt32 serverIndex;
 } UA_ExpandedNodeId;
 
-/** A name qualified by a namespace. */
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier) {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_NUMERIC(nsIndex, identifier);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; }
+
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING(UA_UInt16 nsIndex, char *chars) {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_STRING(nsIndex, chars);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; }
+
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_STRING_ALLOC(nsIndex, chars);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; }
+
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING_GUID(UA_UInt16 nsIndex, UA_Guid guid) {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_GUID(nsIndex, guid);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; }
+
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars) {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_BYTESTRING(nsIndex, chars);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; }
+
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
+    UA_ExpandedNodeId id; id.nodeId = UA_NODEID_BYTESTRING_ALLOC(nsIndex, chars);
+    id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; }
+
+/**************************************************/
+/* QualifiedName: A name qualified by a namespace */
+/**************************************************/
 typedef struct {
     UA_UInt16 namespaceIndex; ///< The namespace index
     UA_String name; ///< The actual name
 } UA_QualifiedName;
 
-/** Human readable text with an optional locale identifier. */
+static UA_INLINE UA_QualifiedName UA_QUALIFIEDNAME(UA_UInt16 nsIndex, char *chars) {
+    UA_QualifiedName qn; qn.namespaceIndex = nsIndex; qn.name = UA_STRING(chars); return qn; }
+
+static UA_INLINE UA_QualifiedName UA_QUALIFIEDNAME_ALLOC(UA_UInt16 nsIndex, const char *chars) {
+    UA_QualifiedName qn; qn.namespaceIndex = nsIndex; qn.name = UA_STRING_ALLOC(chars); return qn; }
+
+/*************************************************************************/
+/* LocalizedText: Human readable text with an optional locale identifier */
+/*************************************************************************/
 typedef struct {
     UA_String locale; ///< The locale (e.g. "en-US")
     UA_String text; ///< The actual text
 } UA_LocalizedText;
 
+static UA_INLINE UA_LocalizedText UA_LOCALIZEDTEXT(char *locale, char *text) {
+    UA_LocalizedText lt; lt.locale = UA_STRING(locale);
+    lt.text = UA_STRING(text); return lt; }
+
+static UA_INLINE UA_LocalizedText UA_LOCALIZEDTEXT_ALLOC(const char *locale, const char *text) {
+    UA_LocalizedText lt; lt.locale = UA_STRING_ALLOC(locale);
+    lt.text = UA_STRING_ALLOC(text); return lt; }
+
 /* Forward Declaration of UA_DataType */
 struct UA_DataType;
 typedef struct UA_DataType UA_DataType; 
 
-/** A structure that contains an application specific data type that may not be recognized by the receiver. */
+/********************************************************************************/
+/* ExtensionObject: A structure that contains an application specific data type */
+/* that may not be recognized by the receiver                                   */
+/********************************************************************************/
 typedef struct {
     enum {
         UA_EXTENSIONOBJECT_ENCODED_NOBODY     = 0,
@@ -176,28 +319,18 @@ typedef struct {
     } content;
 } UA_ExtensionObject;
 
-/* NumericRanges are used select a subset in a (multidimensional) variant array.
- * NumericRange has no official type structure in the standard. On the wire, it
- * only exists as an encoded string, such as "1:2,0:3,5". The colon separates
- * min/max index and the comma separates dimensions. A single value indicates a
- * range with a single element (min==max). */
-typedef struct {
-    size_t dimensionsSize;
-    struct UA_NumericRangeDimension {
-        UA_UInt32 min;
-        UA_UInt32 max;
-    } *dimensions;
-} UA_NumericRange;
-
- /** Variants store (arrays of) any data type. Either they provide a pointer to the data in
- *   memory, or functions from which the data can be accessed. Variants are replaced together with
- *   the data they store (exception: use a data source).
- *
- * Variant semantics:
- *  - arrayLength == 0 && data == NULL: no existing data
- *  - arrayLength == 0 && data == 0x01: array of length 0
- *  - arrayLength == 0 && data > 0x01: scalar value
- *  - arrayLength > 0: array of the given length
+/*********************************************/
+/* Variant: Stores (arrays of) any data type */
+/*********************************************/
+ /* Variants either they provide a pointer to the data in memory, or functions
+    from which the data can be accessed. Variants are replaced together with
+    the data they store (exception: use a data source).
+
+    Variant semantics:
+    - arrayLength == 0 && data == NULL: no existing data
+    - arrayLength == 0 && data == 0x01: array of length 0
+    - arrayLength == 0 && data > 0x01: scalar value
+    - arrayLength > 0: array of the given length
  */
 typedef struct {
     const UA_DataType *type; ///< The nodeid of the datatype
@@ -214,7 +347,116 @@ typedef struct {
     UA_UInt32 *arrayDimensions; ///< the length of each dimension of the data-array
 } UA_Variant;
 
-/** A data value with an associated status code and timestamps. */
+/**
+ * Returns true if the variant contains a scalar value. Note that empty variants contain an array of
+ * length -1 (undefined).
+ *
+ * @param v The variant
+ * @return Does the variant contain a scalar value.
+ */
+static UA_INLINE UA_Boolean UA_Variant_isScalar(const UA_Variant *v) {
+    return (v->arrayLength == 0 && v->data >= UA_EMPTY_ARRAY_SENTINEL); }
+    
+/**
+ * Set the variant to a scalar value that already resides in memory. The value takes on the
+ * lifecycle of the variant and is deleted with it.
+ *
+ * @param v The variant
+ * @param p A pointer to the value data
+ * @param type The datatype of the value in question
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, const UA_DataType *type);
+
+/**
+ * Set the variant to a scalar value that is copied from an existing variable.
+ *
+ * @param v The variant
+ * @param p A pointer to the value data
+ * @param type The datatype of the value
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_Variant_setScalarCopy(UA_Variant *v, const void *p, const UA_DataType *type);
+
+/**
+ * Set the variant to an array that already resides in memory. The array takes on the lifecycle of
+ * the variant and is deleted with it.
+ *
+ * @param v The variant
+ * @param array A pointer to the array data
+ * @param arraySize The size of the array
+ * @param type The datatype of the array
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT
+UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, const UA_DataType *type);
+
+/**
+ * Set the variant to an array that is copied from an existing array.
+ *
+ * @param v The variant
+ * @param array A pointer to the array data
+ * @param arraySize The size of the array
+ * @param type The datatype of the array
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT
+UA_Variant_setArrayCopy(UA_Variant *v, const void *array, size_t arraySize, const UA_DataType *type);
+
+/* NumericRanges are used select a subset in a (multidimensional) variant array.
+ * NumericRange has no official type structure in the standard. On the wire, it
+ * only exists as an encoded string, such as "1:2,0:3,5". The colon separates
+ * min/max index and the comma separates dimensions. A single value indicates a
+ * range with a single element (min==max). */
+typedef struct {
+    size_t dimensionsSize;
+    struct UA_NumericRangeDimension {
+        UA_UInt32 min;
+        UA_UInt32 max;
+    } *dimensions;
+} UA_NumericRange;
+
+/**
+ * Copy the variant, but use only a subset of the (multidimensional) array into a variant. Returns
+ * an error code if the variant is not an array or if the indicated range does not fit.
+ *
+ * @param src The source variant
+ * @param dst The target variant
+ * @param range The range of the copied data
+ * @return Returns UA_STATUSCODE_GOOD or an error code
+ */
+UA_StatusCode UA_EXPORT
+UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRange range);
+
+/**
+ * Insert a range of data into an existing variant. The data array can't be reused afterwards if it
+ * contains types without a fixed size (e.g. strings) since the members are moved into the variant
+ * and take on its lifecycle.
+ *
+ * @param v The variant
+ * @param dataArray The data array. The type must match the variant
+ * @param dataArraySize The length of the data array. This is checked to match the range size.
+ * @param range The range of where the new data is inserted
+ * @return Returns UA_STATUSCODE_GOOD or an error code
+ */
+UA_StatusCode UA_EXPORT
+UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, const UA_NumericRange range);
+
+/**
+ * Deep-copy a range of data into an existing variant.
+ *
+ * @param v The variant
+ * @param dataArray The data array. The type must match the variant
+ * @param dataArraySize The length of the data array. This is checked to match the range size.
+ * @param range The range of where the new data is inserted
+ * @return Returns UA_STATUSCODE_GOOD or an error code
+ */
+UA_StatusCode UA_EXPORT
+UA_Variant_setRangeCopy(UA_Variant *v, const void *array, size_t arraySize, const UA_NumericRange range);
+
+/**************************************************************************/
+/* DataValue: A data value with an associated status code and timestamps. */
+/**************************************************************************/
 typedef struct {
     UA_Boolean    hasValue             : 1;
     UA_Boolean    hasStatus            : 1;
@@ -230,7 +472,10 @@ typedef struct {
     UA_Int16      serverPicoseconds;
 } UA_DataValue;
 
-/** A structure that contains detailed error and diagnostic information associated with a StatusCode. */
+/***************************************************************************/
+/* DiagnosticInfo: A structure that contains detailed error and diagnostic */
+/* information associated with a StatusCode.                               */
+/***************************************************************************/
 typedef struct UA_DiagnosticInfo {
     UA_Boolean    hasSymbolicId          : 1;
     UA_Boolean    hasNamespaceUri        : 1;
@@ -366,304 +611,6 @@ UA_Array_copy(const void *src, size_t src_size, void **dst,
  */
 void UA_EXPORT UA_Array_delete(void *p, size_t size, const UA_DataType *type);
 
-
-/**********/
-/* String */
-/**********/
-UA_EXPORT extern const UA_String UA_STRING_NULL;
-
-static UA_INLINE UA_String UA_STRING(char *chars) {
-    UA_String str;
-    str.length = strlen(chars);
-    str.data   = (UA_Byte*)chars;
-    return str; }
-
-#define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
-    
-/** Copies the content on the heap. Returns a null-string when alloc fails */
-UA_String UA_EXPORT UA_String_fromChars(char const src[]);
-
-UA_Boolean UA_EXPORT UA_String_equal(const UA_String *s1, const UA_String *s2);
-
-/************/
-/* DateTime */
-/************/
-UA_DateTime UA_EXPORT UA_DateTime_now(void); ///> The current time
-
-typedef struct UA_DateTimeStruct {
-    UA_UInt16 nanoSec;
-    UA_UInt16 microSec;
-    UA_UInt16 milliSec;
-    UA_UInt16 sec;
-    UA_UInt16 min;
-    UA_UInt16 hour;
-    UA_UInt16 day;
-    UA_UInt16 month;
-    UA_UInt16 year;
-} UA_DateTimeStruct;
-
-UA_DateTimeStruct UA_EXPORT UA_DateTime_toStruct(UA_DateTime time);
-
-UA_String UA_EXPORT UA_DateTime_toString(UA_DateTime time);
-
-/********/
-/* Guid */
-/********/
-UA_Boolean UA_EXPORT UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
-
-UA_Guid UA_EXPORT UA_Guid_random(UA_UInt32 *seed);
-
-/**************/
-/* ByteString */
-/**************/
-static UA_INLINE UA_Boolean UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2) {
-    return UA_String_equal((const UA_String*)string1, (const UA_String*)string2); }
-
-/* Allocates memory of size length for the bytestring. The content is not set to zero. */
-UA_ByteString UA_EXPORT UA_ByteString_withSize(size_t length);
-
-UA_EXPORT extern const UA_ByteString UA_BYTESTRING_NULL;
-
-static UA_INLINE UA_ByteString UA_BYTESTRING(char *chars) {
-    UA_ByteString str;
-    str.length = strlen(chars);
-    str.data   = (UA_Byte*)chars;
-    return str; }
-
-static UA_INLINE UA_ByteString UA_BYTESTRING_ALLOC(const char *chars) {
-    UA_String str = UA_String_fromChars(chars);
-    UA_ByteString bstr;
-    bstr.length = str.length;
-    bstr.data   = str.data;
-    return bstr;
-}
-
-/**********/
-/* NodeId */
-/**********/
-static UA_INLINE UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
-    return (p->namespaceIndex == 0 && p->identifierType == UA_NODEIDTYPE_NUMERIC &&
-            p->identifier.numeric == 0);
-}
-
-UA_EXPORT extern const UA_NodeId UA_NODEID_NULL;
-
-UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
-
-static UA_INLINE UA_NodeId UA_NODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier) {
-    UA_NodeId id;
-    id.namespaceIndex = nsIndex;
-    id.identifierType = UA_NODEIDTYPE_NUMERIC;
-    id.identifier.numeric = identifier;
-    return id; }
-
-static UA_INLINE UA_NodeId UA_NODEID_STRING(UA_UInt16 nsIndex, char *chars) {
-    UA_NodeId id;
-    id.namespaceIndex = nsIndex;
-    id.identifierType = UA_NODEIDTYPE_STRING;
-    id.identifier.string = UA_STRING(chars);
-    return id; }
-
-static UA_INLINE UA_NodeId UA_NODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
-    UA_NodeId id;
-    id.namespaceIndex = nsIndex;
-    id.identifierType = UA_NODEIDTYPE_STRING;
-    id.identifier.string = UA_STRING_ALLOC(chars);
-    return id; }
-
-static UA_INLINE UA_NodeId UA_NODEID_GUID(UA_UInt16 nsIndex, UA_Guid guid) {
-    UA_NodeId id;
-    id.namespaceIndex = nsIndex;
-    id.identifierType = UA_NODEIDTYPE_GUID;
-    id.identifier.guid = guid;
-    return id; }
-
-static UA_INLINE UA_NodeId UA_NODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars) {
-    UA_NodeId id;
-    id.namespaceIndex = nsIndex;
-    id.identifierType = UA_NODEIDTYPE_BYTESTRING;
-    id.identifier.byteString = UA_BYTESTRING(chars);
-    return id; }
-
-static UA_INLINE UA_NodeId UA_NODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
-    UA_NodeId id;
-    id.namespaceIndex = nsIndex;
-    id.identifierType = UA_NODEIDTYPE_BYTESTRING;
-    id.identifier.byteString = UA_BYTESTRING_ALLOC(chars);
-    return id; }
-
-/******************/
-/* ExpandedNodeId */
-/******************/
-static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier) {
-    UA_ExpandedNodeId id;
-    id.nodeId       = UA_NODEID_NUMERIC(nsIndex, identifier);
-    id.serverIndex  = 0;
-    id.namespaceUri = UA_STRING_NULL;
-    return id; }
-
-static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING(UA_UInt16 nsIndex, char *chars) {
-    UA_ExpandedNodeId id;
-    id.nodeId       = UA_NODEID_STRING(nsIndex, chars);
-    id.serverIndex  = 0;
-    id.namespaceUri = UA_STRING_NULL;
-    return id; }
-
-static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
-    UA_ExpandedNodeId id;
-    id.nodeId       = UA_NODEID_STRING_ALLOC(nsIndex, chars);
-    id.serverIndex  = 0;
-    id.namespaceUri = UA_STRING_NULL;
-    return id; }
-
-static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING_GUID(UA_UInt16 nsIndex, UA_Guid guid) {
-    UA_ExpandedNodeId id;
-    id.nodeId       = UA_NODEID_GUID(nsIndex, guid);
-    id.serverIndex  = 0;
-    id.namespaceUri = UA_STRING_NULL;
-    return id; }
-
-static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars) {
-    UA_ExpandedNodeId id;
-    id.nodeId       = UA_NODEID_BYTESTRING(nsIndex, chars);
-    id.serverIndex  = 0;
-    id.namespaceUri = UA_STRING_NULL;
-    return id; }
-
-static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
-    UA_ExpandedNodeId id;
-    id.nodeId       = UA_NODEID_BYTESTRING_ALLOC(nsIndex, chars);
-    id.serverIndex  = 0;
-    id.namespaceUri = UA_STRING_NULL;
-    return id; }
-
-/*****************/
-/* QualifiedName */
-/*****************/
-static UA_INLINE UA_QualifiedName UA_QUALIFIEDNAME(UA_UInt16 nsIndex, char *chars) {
-    UA_QualifiedName qn;
-    qn.namespaceIndex = nsIndex;
-    qn.name           = UA_STRING(chars);
-    return qn; }
-
-static UA_INLINE UA_QualifiedName UA_QUALIFIEDNAME_ALLOC(UA_UInt16 nsIndex, const char *chars) {
-    UA_QualifiedName qn;
-    qn.namespaceIndex = nsIndex;
-    qn.name           = UA_STRING_ALLOC(chars);
-    return qn; }
-
-/*****************/
-/* LocalizedText */
-/*****************/
-static UA_INLINE UA_LocalizedText UA_LOCALIZEDTEXT(char *locale, char *text) {
-    UA_LocalizedText lt;
-    lt.locale = UA_STRING(locale);
-    lt.text   = UA_STRING(text);
-    return lt; }
-
-static UA_INLINE UA_LocalizedText UA_LOCALIZEDTEXT_ALLOC(const char *locale, const char *text) {
-    UA_LocalizedText lt;
-    lt.locale = UA_STRING_ALLOC(locale);
-    lt.text   = UA_STRING_ALLOC(text);
-    return lt; }
-
-/***********/
-/* Variant */
-/***********/
-/**
- * Returns true if the variant contains a scalar value. Note that empty variants contain an array of
- * length -1 (undefined).
- *
- * @param v The variant
- * @return Does the variant contain a scalar value.
- */
-static UA_INLINE UA_Boolean UA_Variant_isScalar(const UA_Variant *v) {
-    return (v->arrayLength == 0 && v->data >= UA_EMPTY_ARRAY_SENTINEL); }
-    
-/**
- * Set the variant to a scalar value that already resides in memory. The value takes on the
- * lifecycle of the variant and is deleted with it.
- *
- * @param v The variant
- * @param p A pointer to the value data
- * @param type The datatype of the value in question
- * @return Indicates whether the operation succeeded or returns an error code
- */
-UA_StatusCode UA_EXPORT UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, const UA_DataType *type);
-
-/**
- * Set the variant to a scalar value that is copied from an existing variable.
- *
- * @param v The variant
- * @param p A pointer to the value data
- * @param type The datatype of the value
- * @return Indicates whether the operation succeeded or returns an error code
- */
-UA_StatusCode UA_EXPORT UA_Variant_setScalarCopy(UA_Variant *v, const void *p, const UA_DataType *type);
-
-/**
- * Set the variant to an array that already resides in memory. The array takes on the lifecycle of
- * the variant and is deleted with it.
- *
- * @param v The variant
- * @param array A pointer to the array data
- * @param arraySize The size of the array
- * @param type The datatype of the array
- * @return Indicates whether the operation succeeded or returns an error code
- */
-UA_StatusCode UA_EXPORT
-UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, const UA_DataType *type);
-
-/**
- * Set the variant to an array that is copied from an existing array.
- *
- * @param v The variant
- * @param array A pointer to the array data
- * @param arraySize The size of the array
- * @param type The datatype of the array
- * @return Indicates whether the operation succeeded or returns an error code
- */
-UA_StatusCode UA_EXPORT
-UA_Variant_setArrayCopy(UA_Variant *v, const void *array, size_t arraySize, const UA_DataType *type);
-
-/**
- * Copy the variant, but use only a subset of the (multidimensional) array into a variant. Returns
- * an error code if the variant is not an array or if the indicated range does not fit.
- *
- * @param src The source variant
- * @param dst The target variant
- * @param range The range of the copied data
- * @return Returns UA_STATUSCODE_GOOD or an error code
- */
-UA_StatusCode UA_EXPORT
-UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRange range);
-
-/**
- * Insert a range of data into an existing variant. The data array can't be reused afterwards if it
- * contains types without a fixed size (e.g. strings) since the members are moved into the variant
- * and take on its lifecycle.
- *
- * @param v The variant
- * @param dataArray The data array. The type must match the variant
- * @param dataArraySize The length of the data array. This is checked to match the range size.
- * @param range The range of where the new data is inserted
- * @return Returns UA_STATUSCODE_GOOD or an error code
- */
-UA_StatusCode UA_EXPORT
-UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, const UA_NumericRange range);
-
-/**
- * Deep-copy a range of data into an existing variant.
- *
- * @param v The variant
- * @param dataArray The data array. The type must match the variant
- * @param dataArraySize The length of the data array. This is checked to match the range size.
- * @param range The range of where the new data is inserted
- * @return Returns UA_STATUSCODE_GOOD or an error code
- */
-UA_StatusCode UA_EXPORT
-UA_Variant_setRangeCopy(UA_Variant *v, const void *array, size_t arraySize, const UA_NumericRange range);
-
 /**********************/
 /* Node Attribute Ids */
 /**********************/

+ 1 - 1
src/server/ua_services_attribute.c

@@ -181,7 +181,7 @@ static const UA_String binEncoding = {sizeof("DefaultBinary")-1, (UA_Byte*)"Defa
 /** Reads a single attribute from a node in the nodestore. */
 void Service_Read_single(UA_Server *server, UA_Session *session, const UA_TimestampsToReturn timestamps,
                          const UA_ReadValueId *id, UA_DataValue *v) {
-	if(!UA_String_equal(&binEncoding, &id->dataEncoding.name)) {
+	if(id->dataEncoding.name.length > 0 && !UA_String_equal(&binEncoding, &id->dataEncoding.name)) {
            v->hasStatus = UA_TRUE;
            v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
            return;

+ 5 - 10
src/ua_types.c

@@ -169,16 +169,11 @@ UA_Guid UA_Guid_random(UA_UInt32 *seed) {
 }
 
 /* ByteString */
-UA_ByteString UA_ByteString_withSize(size_t length) {
-    UA_ByteString bs = UA_BYTESTRING_NULL;
-    if(length == 0) {
-        bs.data = UA_EMPTY_ARRAY_SENTINEL;
-        return bs;
-    }
-    if(!(bs.data = UA_malloc((UA_UInt32)length)))
-        return bs;
-    bs.length = length;
-    return bs;
+UA_StatusCode UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length) {
+    if(!(bs->data = UA_malloc(length)))
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    bs->length = length;
+    return UA_STATUSCODE_GOOD;
 }
 
 /* NodeId */

+ 65 - 66
src/ua_types_encoding_binary.c

@@ -3,13 +3,23 @@
 #include "ua_statuscodes.h"
 #include "ua_types_generated.h"
 
+/* All de- and encoding functions have the same signature (up to the pointer type).
+   So we can use a jump-table to switch into member types.
+   The builtin types don't use the pointer to the data type. */
+
+typedef UA_StatusCode (*UA_encodeBinarySignature)(const void *src, const UA_DataType *type,
+                                                  UA_ByteString *dst, size_t *UA_RESTRICT offset);
+
+typedef UA_StatusCode (*UA_decodeBinarySignature) (const UA_ByteString *src, size_t *UA_RESTRICT offset,
+                                                   void *dst, const UA_DataType*);
+
 /*****************/
 /* Integer Types */
 /*****************/
 
 /* Boolean */
 static UA_StatusCode
-Boolean_encodeBinary(const UA_Boolean *src, const UA_DataType *dummy,
+Boolean_encodeBinary(const UA_Boolean *src, const UA_DataType *_,
                      UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_Boolean) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
@@ -20,7 +30,7 @@ Boolean_encodeBinary(const UA_Boolean *src, const UA_DataType *dummy,
 
 static UA_StatusCode
 Boolean_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                     UA_Boolean *dst, const UA_DataType *dummy) {
+                     UA_Boolean *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_Boolean) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
     *dst = (src->data[*offset] > 0) ? UA_TRUE : UA_FALSE;
@@ -30,7 +40,7 @@ Boolean_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 
 /* Byte */
 static UA_StatusCode
-Byte_encodeBinary(const UA_Byte *src, const UA_DataType *dummy,
+Byte_encodeBinary(const UA_Byte *src, const UA_DataType *_,
                   UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_Byte) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
@@ -41,7 +51,7 @@ Byte_encodeBinary(const UA_Byte *src, const UA_DataType *dummy,
 
 static UA_StatusCode
 Byte_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                  UA_Byte *dst, const UA_DataType *dummy) {
+                  UA_Byte *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_Byte) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
     *dst = src->data[*offset];
@@ -51,7 +61,7 @@ Byte_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 
 /* UInt16 */
 static UA_StatusCode
-UInt16_encodeBinary(UA_UInt16 const *src, const UA_DataType *dummy,
+UInt16_encodeBinary(UA_UInt16 const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_UInt16) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
@@ -72,13 +82,13 @@ UInt16_encodeBinary(UA_UInt16 const *src, const UA_DataType *dummy,
 }
 
 static UA_INLINE UA_StatusCode
-Int16_encodeBinary(UA_Int16 const *src, const UA_DataType *dummy,
+Int16_encodeBinary(UA_Int16 const *src, const UA_DataType *_,
                    UA_ByteString *dst, size_t *UA_RESTRICT offset) {
-    return UInt16_encodeBinary((const UA_UInt16*)src, dummy, dst, offset); }
+    return UInt16_encodeBinary((const UA_UInt16*)src, _, dst, offset); }
 
 static UA_StatusCode
 UInt16_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                    UA_UInt16 *dst, const UA_DataType *dummy) {
+                    UA_UInt16 *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_UInt16) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
 
@@ -98,12 +108,12 @@ UInt16_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 
 static UA_INLINE UA_StatusCode
 Int16_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                    UA_Int16 *dst, const UA_DataType *dummy) {
-    return UInt16_decodeBinary(src, offset, (UA_UInt16*)dst, dummy); }
+                    UA_Int16 *dst, const UA_DataType *_) {
+    return UInt16_decodeBinary(src, offset, (UA_UInt16*)dst, _); }
 
 /* UInt32 */
 static UA_StatusCode
-UInt32_encodeBinary(UA_UInt32 const *src, const UA_DataType *dummy,
+UInt32_encodeBinary(UA_UInt32 const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_UInt32) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
@@ -126,18 +136,18 @@ UInt32_encodeBinary(UA_UInt32 const *src, const UA_DataType *dummy,
 }
 
 static UA_INLINE UA_StatusCode
-Int32_encodeBinary(UA_Int32 const *src, const UA_DataType *dummy,
+Int32_encodeBinary(UA_Int32 const *src, const UA_DataType *_,
                    UA_ByteString *dst, size_t *UA_RESTRICT offset) {
-    return UInt32_encodeBinary((const UA_UInt32*)src, dummy, dst, offset); }
+    return UInt32_encodeBinary((const UA_UInt32*)src, _, dst, offset); }
 
 static UA_INLINE UA_StatusCode
-StatusCode_encodeBinary(UA_StatusCode const *src, const UA_DataType *dummy,
+StatusCode_encodeBinary(UA_StatusCode const *src, const UA_DataType *_,
                         UA_ByteString *dst, size_t *UA_RESTRICT offset) {
-    return UInt32_encodeBinary((const UA_UInt32*)src, dummy, dst, offset); }
+    return UInt32_encodeBinary((const UA_UInt32*)src, _, dst, offset); }
 
 static UA_StatusCode
 UInt32_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                    UA_UInt32 *dst, const UA_DataType *dummy) {
+                    UA_UInt32 *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_UInt32) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
 
@@ -159,18 +169,18 @@ UInt32_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 
 static UA_INLINE UA_StatusCode
 Int32_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                    UA_Int32 *dst, const UA_DataType *dummy) {
-    return UInt32_decodeBinary(src, offset, (UA_UInt32*)dst, dummy); }
+                    UA_Int32 *dst, const UA_DataType *_) {
+    return UInt32_decodeBinary(src, offset, (UA_UInt32*)dst, _); }
 
 static UA_INLINE UA_StatusCode
 StatusCode_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                        UA_StatusCode *dst, const UA_DataType *dummy) {
-    return UInt32_decodeBinary(src, offset, (UA_UInt32*)dst, dummy); }
+                        UA_StatusCode *dst, const UA_DataType *_) {
+    return UInt32_decodeBinary(src, offset, (UA_UInt32*)dst, _); }
 
 
 /* UInt64 */
 static UA_StatusCode
-UInt64_encodeBinary(UA_UInt64 const *src, const UA_DataType *dummy,
+UInt64_encodeBinary(UA_UInt64 const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_UInt64) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
@@ -197,18 +207,18 @@ UInt64_encodeBinary(UA_UInt64 const *src, const UA_DataType *dummy,
 }
 
 static UA_INLINE UA_StatusCode
-Int64_encodeBinary(UA_Int64 const *src, const UA_DataType *dummy,
+Int64_encodeBinary(UA_Int64 const *src, const UA_DataType *_,
                    UA_ByteString *dst, size_t *UA_RESTRICT offset) {
-    return UInt64_encodeBinary((const UA_UInt64*)src, dummy, dst, offset); }
+    return UInt64_encodeBinary((const UA_UInt64*)src, _, dst, offset); }
 
 static UA_INLINE UA_StatusCode
-DateTime_encodeBinary(UA_DateTime const *src, const UA_DataType *dummy,
+DateTime_encodeBinary(UA_DateTime const *src, const UA_DataType *_,
                       UA_ByteString *dst, size_t *UA_RESTRICT offset) {
-    return UInt64_encodeBinary((const UA_UInt64*)src, dummy, dst, offset); }
+    return UInt64_encodeBinary((const UA_UInt64*)src, _, dst, offset); }
 
 static UA_StatusCode
 UInt64_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                    UA_UInt64 *dst, const UA_DataType *dummy) {
+                    UA_UInt64 *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_UInt64) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
 
@@ -234,13 +244,13 @@ UInt64_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 
 static UA_INLINE UA_StatusCode
 Int64_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                   UA_Int64 *dst, const UA_DataType *dummy) {
-    return UInt64_decodeBinary(src, offset, (UA_UInt64*)dst, dummy); }
+                   UA_Int64 *dst, const UA_DataType *_) {
+    return UInt64_decodeBinary(src, offset, (UA_UInt64*)dst, _); }
 
 static UA_INLINE UA_StatusCode
 DateTime_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                      UA_DateTime *dst, const UA_DataType *dummy) {
-    return UInt64_decodeBinary(src, offset, (UA_UInt64*)dst, dummy); }
+                      UA_DateTime *dst, const UA_DataType *_) {
+    return UInt64_decodeBinary(src, offset, (UA_UInt64*)dst, _); }
 
 #ifndef UA_MIXED_ENDIAN
 # define Float_encodeBinary UInt32_encodeBinary
@@ -251,8 +261,7 @@ DateTime_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 /* Float */
 UA_Byte UA_FLOAT_ZERO[] = { 0x00, 0x00, 0x00, 0x00 };
 static UA_StatusCode
-Float_decodeBinary(UA_ByteString const *src, size_t *offset,
-                   UA_Float *dst, const UA_DataType *dummy) {
+Float_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Float *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_Float) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
     UA_Float mantissa;
@@ -276,8 +285,7 @@ Float_decodeBinary(UA_ByteString const *src, size_t *offset,
 }
 
 static UA_StatusCode
-Float_encodeBinary(UA_Float const *src, const UA_DataType *dummy,
-                   UA_ByteString *dst, size_t *UA_RESTRICT offset) {
+Float_encodeBinary(UA_Float const *src, const UA_DataType *_, UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_Float) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
     UA_Float srcFloat = *src;
@@ -292,7 +300,7 @@ Float_encodeBinary(UA_Float const *src, const UA_DataType *dummy,
 UA_Byte UA_DOUBLE_ZERO[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 static UA_StatusCode
 Double_decodeBinary(UA_ByteString const *src, size_t *offset,
-                    UA_Double *dst, const UA_DataType *dummy) {
+                    UA_Double *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_Double) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
 
@@ -337,7 +345,7 @@ Double_decodeBinary(UA_ByteString const *src, size_t *offset,
 
 /* Expecting double in ieee754 format */
 static UA_StatusCode
-Double_encodeBinary(UA_Double const *src, const UA_DataType *dummy,
+Double_encodeBinary(UA_Double const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_Double) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
@@ -445,7 +453,7 @@ Array_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset, UA_Int3
 /*****************/
 
 static UA_StatusCode
-String_encodeBinary(UA_String const *src, const UA_DataType *dummy,
+String_encodeBinary(UA_String const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + src->length > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
@@ -466,7 +474,7 @@ String_encodeBinary(UA_String const *src, const UA_DataType *dummy,
 
 static UA_StatusCode
 String_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                    UA_String *dst, const UA_DataType *dummy) {
+                    UA_String *dst, const UA_DataType *_) {
     UA_String_init(dst);
     UA_Int32 signed_length;
     UA_StatusCode retval = Int32_decodeBinary(src, offset, &signed_length, NULL);
@@ -491,7 +499,7 @@ String_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 
 /* Guid */
 static UA_StatusCode
-Guid_encodeBinary(UA_Guid const *src, const UA_DataType *dummy,
+Guid_encodeBinary(UA_Guid const *src, const UA_DataType *_,
                   UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     UA_StatusCode retval = UInt32_encodeBinary(&src->data1, NULL, dst, offset);
     retval |= UInt16_encodeBinary(&src->data2, NULL, dst, offset);
@@ -503,7 +511,7 @@ Guid_encodeBinary(UA_Guid const *src, const UA_DataType *dummy,
 
 static UA_StatusCode
 Guid_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                  UA_Guid *dst, const UA_DataType *dummy) {
+                  UA_Guid *dst, const UA_DataType *_) {
     // This could be done with a single memcpy (if the compiler does no fancy
     // realigning of structs)
     UA_StatusCode retval = UInt32_decodeBinary(src, offset, &dst->data1, NULL);
@@ -522,7 +530,7 @@ Guid_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 #define UA_NODEIDTYPE_NUMERIC_COMPLETE 2
 
 static UA_StatusCode
-NodeId_encodeBinary(UA_NodeId const *src, const UA_DataType *dummy,
+NodeId_encodeBinary(UA_NodeId const *src, const UA_DataType *_,
                     UA_ByteString * dst, size_t *UA_RESTRICT offset) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     // temporary variables for endian-save code
@@ -577,15 +585,14 @@ NodeId_encodeBinary(UA_NodeId const *src, const UA_DataType *dummy,
 
 static UA_StatusCode
 NodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                    UA_NodeId *dst, const UA_DataType *dummy) {
+                    UA_NodeId *dst, const UA_DataType *_) {
     UA_NodeId_init(dst);
-    /* temporary variables to overcome decoder's non-endian-saveness for
-       datatypes with different length */
     UA_Byte dstByte = 0, encodingByte = 0;
     UA_UInt16 dstUInt16 = 0;
     UA_StatusCode retval = Byte_decodeBinary(src, offset, &encodingByte, NULL);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
+
     switch (encodingByte) {
     case UA_NODEIDTYPE_NUMERIC_TWOBYTE:
         dst->identifierType = UA_NODEIDTYPE_NUMERIC;
@@ -635,13 +642,12 @@ NodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 #define UA_EXPANDEDNODEID_SERVERINDEX_FLAG 0x40
 
 static UA_StatusCode
-ExpandedNodeId_encodeBinary(UA_ExpandedNodeId const *src, const UA_DataType *dummy,
+ExpandedNodeId_encodeBinary(UA_ExpandedNodeId const *src, const UA_DataType *_,
                             UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     UA_Byte flags = 0;
     UA_UInt32 start = *offset;
     UA_StatusCode retval = NodeId_encodeBinary(&src->nodeId, NULL, dst, offset);
     if(src->namespaceUri.length > 0) {
-        // TODO: Set namespaceIndex to 0 in the nodeid as the namespaceUri takes precedence
         retval |= UA_encodeBinary(&src->namespaceUri, &UA_TYPES[UA_TYPES_STRING], dst, offset);
         flags |= UA_EXPANDEDNODEID_NAMESPACEURI_FLAG;
     }
@@ -656,7 +662,7 @@ ExpandedNodeId_encodeBinary(UA_ExpandedNodeId const *src, const UA_DataType *dum
 
 static UA_StatusCode
 ExpandedNodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                            UA_ExpandedNodeId *dst, const UA_DataType *dummy) {
+                            UA_ExpandedNodeId *dst, const UA_DataType *_) {
     UA_ExpandedNodeId_init(dst);
     if(*offset >= src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
@@ -680,7 +686,7 @@ ExpandedNodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset
 #define UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT 0x02
 
 static UA_StatusCode
-LocalizedText_encodeBinary(UA_LocalizedText const *src, const UA_DataType *dummy,
+LocalizedText_encodeBinary(UA_LocalizedText const *src, const UA_DataType *_,
                            UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     UA_Byte encodingMask = 0;
     if(src->locale.data != NULL)
@@ -699,7 +705,7 @@ LocalizedText_encodeBinary(UA_LocalizedText const *src, const UA_DataType *dummy
 
 static UA_StatusCode
 LocalizedText_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                           UA_LocalizedText *dst, const UA_DataType *dummy) {
+                           UA_LocalizedText *dst, const UA_DataType *_) {
     UA_LocalizedText_init(dst);
     UA_Byte encodingMask = 0;
     UA_StatusCode retval = Byte_decodeBinary(src, offset, &encodingMask, NULL);
@@ -714,7 +720,7 @@ LocalizedText_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 
 /* ExtensionObject */
 static UA_StatusCode
-ExtensionObject_encodeBinary(UA_ExtensionObject const *src, const UA_DataType *dummy,
+ExtensionObject_encodeBinary(UA_ExtensionObject const *src, const UA_DataType *_,
                              UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     UA_StatusCode retval;
     UA_Byte encoding = src->encoding;
@@ -744,7 +750,7 @@ ExtensionObject_encodeBinary(UA_ExtensionObject const *src, const UA_DataType *d
 
 static UA_StatusCode
 ExtensionObject_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                             UA_ExtensionObject *dst, const UA_DataType *dummy) {
+                             UA_ExtensionObject *dst, const UA_DataType *_) {
     UA_ExtensionObject_init(dst);
     UA_Byte encoding = 0;
     UA_NodeId typeId;
@@ -803,7 +809,7 @@ enum UA_VARIANT_ENCODINGMASKTYPE {
 };
 
 static UA_StatusCode
-Variant_encodeBinary(UA_Variant const *src, const UA_DataType *dummy,
+Variant_encodeBinary(UA_Variant const *src, const UA_DataType *_,
                      UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(!src->type)
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -876,7 +882,7 @@ Variant_encodeBinary(UA_Variant const *src, const UA_DataType *dummy,
  we only support ns0 types (todo: attach typedescriptions to datatypenodes) */
 static UA_StatusCode
 Variant_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                     UA_Variant *dst, const UA_DataType *dummy) {
+                     UA_Variant *dst, const UA_DataType *_) {
     UA_Variant_init(dst);
     UA_Byte encodingByte;
     UA_StatusCode retval = Byte_decodeBinary(src, offset, &encodingByte, NULL);
@@ -953,7 +959,7 @@ Variant_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 
 /* DataValue */
 static UA_StatusCode
-DataValue_encodeBinary(UA_DataValue const *src, const UA_DataType *dummy,
+DataValue_encodeBinary(UA_DataValue const *src, const UA_DataType *_,
                        UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     UA_StatusCode retval = Byte_encodeBinary((const UA_Byte*) src, NULL, dst, offset);
     if(src->hasValue)
@@ -974,7 +980,7 @@ DataValue_encodeBinary(UA_DataValue const *src, const UA_DataType *dummy,
 #define MAX_PICO_SECONDS 1000
 static UA_StatusCode
 DataValue_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                       UA_DataValue *dst, const UA_DataType *dummy) {
+                       UA_DataValue *dst, const UA_DataType *_) {
     UA_DataValue_init(dst);
     UA_StatusCode retval = Byte_decodeBinary(src, offset, (UA_Byte*) dst, NULL);
     if(retval != UA_STATUSCODE_GOOD)
@@ -1004,7 +1010,7 @@ DataValue_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 
 /* DiagnosticInfo */
 static UA_StatusCode
-DiagnosticInfo_encodeBinary(const UA_DiagnosticInfo *src, const UA_DataType *dummy,
+DiagnosticInfo_encodeBinary(const UA_DiagnosticInfo *src, const UA_DataType *_,
                             UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     UA_StatusCode retval = Byte_encodeBinary((const UA_Byte *) src, NULL, dst, offset);
     if(src->hasSymbolicId)
@@ -1026,7 +1032,7 @@ DiagnosticInfo_encodeBinary(const UA_DiagnosticInfo *src, const UA_DataType *dum
 
 static UA_StatusCode
 DiagnosticInfo_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
-                            UA_DiagnosticInfo *dst, const UA_DataType *dummy) {
+                            UA_DiagnosticInfo *dst, const UA_DataType *_) {
     UA_DiagnosticInfo_init(dst);
     UA_StatusCode retval = Byte_decodeBinary(src, offset, (UA_Byte*) dst, NULL);
     if(!retval)
@@ -1063,9 +1069,6 @@ DiagnosticInfo_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset
 /********************/
 /* Structured Types */
 /********************/
-
-typedef UA_StatusCode (*UA_encodeBinarySignature)(const void *src, const UA_DataType *type,
-                                                  UA_ByteString *dst, size_t *UA_RESTRICT offset);
 static const UA_encodeBinarySignature encodeBinaryJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = {
     (UA_encodeBinarySignature)Boolean_encodeBinary, 
     (UA_encodeBinarySignature)Byte_encodeBinary, // SByte
@@ -1096,8 +1099,7 @@ static const UA_encodeBinarySignature encodeBinaryJumpTable[UA_BUILTIN_TYPES_COU
 };
 
 UA_StatusCode
-UA_encodeBinary(const void *src, const UA_DataType *type,
-                UA_ByteString *dst, size_t *UA_RESTRICT offset) {
+UA_encodeBinary(const void *src, const UA_DataType *type, UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     uintptr_t ptr = (uintptr_t)src;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Byte membersSize = type->membersSize;
@@ -1121,8 +1123,6 @@ UA_encodeBinary(const void *src, const UA_DataType *type,
     return retval;
 }
 
-typedef UA_StatusCode (*UA_decodeBinarySignature) (const UA_ByteString *src, size_t *UA_RESTRICT offset,
-                                                   void *dst, const UA_DataType*);
 static const UA_decodeBinarySignature decodeBinaryJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = {
     (UA_decodeBinarySignature)Boolean_decodeBinary, 
     (UA_decodeBinarySignature)Byte_decodeBinary, // SByte
@@ -1153,8 +1153,7 @@ static const UA_decodeBinarySignature decodeBinaryJumpTable[UA_BUILTIN_TYPES_COU
 };
 
 UA_StatusCode
-UA_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset,
-                void *dst, const UA_DataType *type) {
+UA_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset, void *dst, const UA_DataType *type) {
     uintptr_t ptr = (uintptr_t)dst;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Byte membersSize = type->membersSize;

+ 9 - 7
tests/check_memory.c

@@ -51,10 +51,11 @@ START_TEST(encodeShallYieldDecode) {
 	UA_ByteString msg1, msg2;
 	size_t pos = 0;
 	void *obj1 = UA_new(&UA_TYPES[_i]);
-	msg1 = UA_ByteString_withSize(65000); // fixed buf size
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&msg1, 65000); // fixed buf size
+	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     printf("%i\n", _i);
     fflush(stdout);
-    UA_StatusCode retval = UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
+    retval = UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
     msg1.length = pos;
 	if(retval != UA_STATUSCODE_GOOD) {
 		UA_delete(obj1, &UA_TYPES[_i]);
@@ -68,7 +69,8 @@ START_TEST(encodeShallYieldDecode) {
 	ck_assert_msg(retval == UA_STATUSCODE_GOOD, "could not decode idx=%d,nodeid=%i", _i, UA_TYPES[_i].typeId.identifier.numeric);
 	ck_assert(!memcmp(obj1, obj2, UA_TYPES[_i].memSize)); // bit identical decoding
     assert(!memcmp(obj1, obj2, UA_TYPES[_i].memSize));
-	msg2 = UA_ByteString_withSize(65000);
+	retval = UA_ByteString_allocBuffer(&msg2, 65000);
+	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	pos = 0; retval = UA_encodeBinary(obj2, &UA_TYPES[_i], &msg2, &pos);
     msg2.length = pos;
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
@@ -90,8 +92,8 @@ START_TEST(decodeShallFailWithTruncatedBufferButSurvive) {
 	UA_ByteString msg1;
 	void *obj1 = UA_new(&UA_TYPES[_i]);
 	size_t pos = 0;
-	msg1 = UA_ByteString_withSize(65000); // fixed buf size
-    UA_StatusCode retval = UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&msg1, 65000); // fixed buf size
+    retval |= UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
 	UA_delete(obj1, &UA_TYPES[_i]);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_ByteString_deleteMembers(&msg1);
@@ -120,7 +122,7 @@ START_TEST(decodeScalarBasicTypeFromRandomBufferShallSucceed) {
 	UA_ByteString msg1;
 	UA_Int32 retval = UA_STATUSCODE_GOOD;
 	UA_Int32 buflen = 256;
-	msg1 = UA_ByteString_withSize(buflen); // fixed size
+	retval = UA_ByteString_allocBuffer(&msg1, buflen); // fixed size
 #ifdef _WIN32
 	srand(42);
 #else
@@ -153,7 +155,7 @@ START_TEST(decodeComplexTypeFromRandomBufferShallSurvive) {
 	UA_ByteString msg1;
 	UA_Int32 retval = UA_STATUSCODE_GOOD;
 	UA_Int32 buflen = 256;
-	msg1 = UA_ByteString_withSize(buflen); // fixed size
+	retval = UA_ByteString_allocBuffer(&msg1, buflen); // fixed size
 #ifdef _WIN32
 	srand(42);
 #else

+ 23 - 23
tests/check_services_attributes.c

@@ -68,7 +68,7 @@ static UA_Server* makeTestSequence(void) {
                             UA_NODEID_NUMERIC(0, 3),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                             UA_QUALIFIEDNAME_ALLOC(0, "Methodtest"), ma,
-                            NULL, NULL, -1, NULL, -1, NULL, NULL);
+                            NULL, NULL, 0, NULL, 0, NULL, NULL);
 #endif
 
 	return server;
@@ -106,7 +106,7 @@ START_TEST(ReadSingleAttributeValueWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
     ck_assert_int_eq(42, *(UA_Int32* )resp.value.data);
     UA_Server_delete(server);
@@ -126,7 +126,7 @@ START_TEST(ReadSingleAttributeNodeIdWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_NODEID;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_NODEID], resp.value.type);
     UA_NodeId* respval = (UA_NodeId*) resp.value.data;
     ck_assert_int_eq(1, respval->namespaceIndex);
@@ -147,7 +147,7 @@ START_TEST(ReadSingleAttributeNodeClassWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_NODECLASS;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32],resp.value.type);
     ck_assert_int_eq(*(UA_Int32*)resp.value.data,UA_NODECLASS_VARIABLE);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -168,7 +168,7 @@ START_TEST(ReadSingleAttributeBrowseNameWithoutTimestamp) {
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_QualifiedName* respval = (UA_QualifiedName*) resp.value.data;
     const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_QUALIFIEDNAME], resp.value.type);
     ck_assert_int_eq(1, respval->namespaceIndex);
     ck_assert(UA_String_equal(&myIntegerName.name, &respval->name));
@@ -191,7 +191,7 @@ START_TEST(ReadSingleAttributeDisplayNameWithoutTimestamp) {
     UA_LocalizedText* respval = (UA_LocalizedText*) resp.value.data;
     const UA_LocalizedText comp = UA_LOCALIZEDTEXT("locale", "the answer");
     UA_VariableNode* compNode = makeCompareSequence();
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_LOCALIZEDTEXT], resp.value.type);
     ck_assert(UA_String_equal(&comp.text, &respval->text));
     ck_assert(UA_String_equal(&compNode->displayName.locale, &respval->locale));
@@ -214,7 +214,7 @@ START_TEST(ReadSingleAttributeDescriptionWithoutTimestamp) {
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_LocalizedText* respval = (UA_LocalizedText*) resp.value.data;
     UA_VariableNode* compNode = makeCompareSequence();
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_LOCALIZEDTEXT], resp.value.type);
     ck_assert(UA_String_equal(&compNode->description.locale, &respval->locale));
     ck_assert(UA_String_equal(&compNode->description.text, &respval->text));
@@ -236,7 +236,7 @@ START_TEST(ReadSingleAttributeWriteMaskWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_WRITEMASK;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_UInt32* respval = (UA_UInt32*) resp.value.data;
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_UINT32], resp.value.type);
     ck_assert_int_eq(0,*respval);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -256,7 +256,7 @@ START_TEST(ReadSingleAttributeUserWriteMaskWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_USERWRITEMASK;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_UInt32* respval = (UA_UInt32*) resp.value.data;
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_UINT32], resp.value.type);
     ck_assert_int_eq(0,*respval);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -275,7 +275,7 @@ START_TEST(ReadSingleAttributeIsAbstractWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_ISABSTRACT;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean* )resp.value.data==UA_FALSE);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -294,7 +294,7 @@ START_TEST(ReadSingleAttributeSymmetricWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_SYMMETRIC;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean* )resp.value.data==UA_FALSE);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -315,7 +315,7 @@ START_TEST(ReadSingleAttributeInverseNameWithoutTimestamp) {
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_LocalizedText* respval = (UA_LocalizedText*) resp.value.data;
     const UA_LocalizedText comp = UA_LOCALIZEDTEXT("en_US", "OrganizedBy");
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_LOCALIZEDTEXT],resp.value.type);
     ck_assert(UA_String_equal(&comp.text, &respval->text));
     ck_assert(UA_String_equal(&comp.locale, &respval->locale));
@@ -335,7 +335,7 @@ START_TEST(ReadSingleAttributeContainsNoLoopsWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_VIEWNODE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_CONTAINSNOLOOPS;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean* )resp.value.data==UA_FALSE);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -355,7 +355,7 @@ START_TEST(ReadSingleAttributeEventNotifierWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_EVENTNOTIFIER;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     ck_assert_int_eq(UA_STATUSCODE_GOOD, resp.status);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE],resp.value.type);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, 0);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -375,7 +375,7 @@ START_TEST(ReadSingleAttributeDataTypeWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_DATATYPE;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_NodeId* respval = (UA_NodeId*) resp.value.data;
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_NODEID], resp.value.type);
     ck_assert_int_eq(respval->namespaceIndex,0);
     ck_assert_int_eq(respval->identifier.numeric,UA_NS0ID_INT32);
@@ -395,7 +395,7 @@ START_TEST(ReadSingleAttributeValueRankWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUERANK;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
     ck_assert_int_eq(-2, *(UA_Int32* )resp.value.data);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -414,7 +414,7 @@ START_TEST(ReadSingleAttributeArrayDimensionsWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
     Service_Read_single(server, &adminSession,  UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
     ck_assert_ptr_eq((UA_Int32*)resp.value.data,0);
     UA_DataValue_deleteMembers(&resp);
@@ -433,7 +433,7 @@ START_TEST(ReadSingleAttributeAccessLevelWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_ACCESSLEVEL;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE], resp.value.type);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, 0);
     UA_DataValue_deleteMembers(&resp);
@@ -453,7 +453,7 @@ START_TEST(ReadSingleAttributeUserAccessLevelWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_USERACCESSLEVEL;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_VariableNode* compNode = makeCompareSequence();
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE], resp.value.type);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, compNode->userAccessLevel);
     UA_Server_delete(server);
@@ -476,7 +476,7 @@ START_TEST(ReadSingleAttributeMinimumSamplingIntervalWithoutTimestamp) {
     UA_Double* respval = (UA_Double*) resp.value.data;
     UA_VariableNode *compNode = makeCompareSequence();
     UA_Double comp = (UA_Double) compNode->minimumSamplingInterval;
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_DOUBLE], resp.value.type);
     ck_assert(*respval == comp);
     UA_DataValue_deleteMembers(&resp);
@@ -496,7 +496,7 @@ START_TEST(ReadSingleAttributeHistorizingWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_HISTORIZING;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean*)resp.value.data==UA_FALSE);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -516,7 +516,7 @@ START_TEST(ReadSingleAttributeExecutableWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_METHODNODE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_EXECUTABLE;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean*)resp.value.data==UA_FALSE);
     UA_DataValue_deleteMembers(&resp);
@@ -537,7 +537,7 @@ START_TEST(ReadSingleAttributeUserExecutableWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_METHODNODE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_USEREXECUTABLE;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean*)resp.value.data==UA_FALSE);
     UA_DataValue_deleteMembers(&resp);