Prechádzať zdrojové kódy

simplify NodeId type (shortened nodeids only during encoding)

Julius Pfrommer 9 rokov pred
rodič
commit
3897afc744

+ 2 - 2
src/ua_application.c

@@ -13,7 +13,7 @@ Application appMockup = {
 
 UA_Node* create_node_ns0(UA_Int32 class, UA_Int32 nodeClass, UA_Int32 const id, char const * qn, char const * dn, char const * desc) {
 	UA_Node* n; UA_.types[class].new((void **)&n);
-	n->nodeId.encodingByte = UA_NODEIDTYPE_FOURBYTE;
+	n->nodeId.nodeIdType = UA_NODEIDTYPE_NUMERIC;
 	n->nodeId.namespace = 0;
 	n->nodeId.identifier.numeric = id;
 	UA_String_copycstring(qn,&(n->browseName.name));
@@ -545,7 +545,7 @@ void appMockup_init() {
 	/* v->value.arrayLength = 2; */
 	/* UA_String_copycstring("http://opcfoundation.org/UA/",&((UA_String *)((v->value).data))[0]); */
 	/* UA_String_copycstring("http://localhost:16664/open62541/",&((UA_String *)(((v)->value).data))[1]); */
-	/* v->dataType.encodingByte = UA_NODEIDTYPE_FOURBYTE; */
+	/* v->dataType.nodeIdType = UA_NODEIDTYPE_FOURBYTE; */
 	/* v->dataType.identifier.numeric = UA_STRING_NS0; */
 	/* v->valueRank = 1; */
 	/* v->minimumSamplingInterval = 1.0; */

+ 1 - 3
src/ua_namespace.c

@@ -90,9 +90,7 @@ static INLINE hash_t hash_array(const UA_Byte *data, UA_UInt32 len) {
 }
 
 static INLINE hash_t hash(const UA_NodeId *n) {
-	switch(n->encodingByte) {
-	case UA_NODEIDTYPE_TWOBYTE:
-	case UA_NODEIDTYPE_FOURBYTE:
+	switch(n->nodeIdType) {
 	case UA_NODEIDTYPE_NUMERIC:
 		/*  Knuth's multiplicative hashing */
 		return n->identifier.numeric * 2654435761;   // mod(2^32) is implicit

+ 1 - 3
src/ua_namespace_concurrent.c

@@ -77,9 +77,7 @@ static inline hash_t hash_array(const UA_Byte *data, UA_UInt32 len) {
 }
 
 static inline hash_t hash(const UA_NodeId *n) {
-	switch(n->encodingByte) {
-	case UA_NODEIDTYPE_TWOBYTE:
-	case UA_NODEIDTYPE_FOURBYTE:
+	switch(n->nodeIdType) {
 	case UA_NODEIDTYPE_NUMERIC:
 		/*  Knuth's multiplicative hashing */
 		return n->identifier.numeric * 2654435761;   // mod(2^32) is implicit

+ 1 - 1
src/ua_stack_session.c

@@ -34,7 +34,7 @@ UA_Int32 UA_Session_generateToken(UA_NodeId *newToken)
 	UA_Int32 r = 0;
 	//retval |= UA_NodeId_new(newToken);
 
-	newToken->encodingByte = 0x04; //GUID
+	newToken->nodeIdType = UA_NODEIDTYPE_GUID;
 	newToken->namespace = 0; // where else?
 	newToken->identifier.guid.data1 = rand();
 	r = rand();

+ 1 - 1
src/ua_stack_session_manager.c

@@ -23,7 +23,7 @@ static UA_SessionManager *sessionManager;
 
 UA_Int32 UA_SessionManager_generateSessionId(UA_NodeId *sessionId)
 {
-	sessionId->encodingByte = 0x00;
+	sessionId->nodeIdType = UA_NODEIDTYPE_NUMERIC;
 	sessionId->namespace = 0;
 	sessionId->identifier.numeric = sessionManager->lastSessionId++;
 	return UA_SUCCESS;

+ 2 - 4
src/ua_transport_binary_secure.c

@@ -24,15 +24,13 @@ static UA_Int32 SL_Send(SL_Channel *channel,
 	UA_TL_Connection *connection;
 	UA_AsymmetricAlgorithmSecurityHeader *asymAlgSettings = UA_NULL;
 
-	resp_nodeid.encodingByte = UA_NODEIDTYPE_FOURBYTE;
+	resp_nodeid.nodeIdType = UA_NODEIDTYPE_NUMERIC;
 	resp_nodeid.namespace = 0;
 	resp_nodeid.identifier.numeric = type + 2; // binary encoding
 
 	const UA_ByteString *response_gather[2]; // securechannel_header, seq_header, security_encryption_header, message_length (eventually + padding + size_signature);
 	UA_alloc((void ** )&response_gather[0], sizeof(UA_ByteString));
-	if (isAsym)
-	{
-
+	if (isAsym) {
 		SL_Channel_getLocalAsymAlgSettings(channel, &asymAlgSettings);
 		UA_ByteString_newMembers((UA_ByteString *) response_gather[0],
 				SIZE_SECURECHANNEL_HEADER + SIZE_SEQHEADER_HEADER

+ 31 - 72
src/ua_types.c

@@ -418,7 +418,7 @@ UA_TYPE_AS(UA_XmlElement, UA_ByteString)
 /* NodeId */
 UA_Int32 UA_NodeId_init(UA_NodeId *p) {
 	if(p == UA_NULL) return UA_ERROR;
-	p->encodingByte = UA_NODEIDTYPE_TWOBYTE;
+	p->nodeIdType = UA_NODEIDTYPE_NUMERIC;
 	p->namespace    = 0;
 	memset(&p->identifier, 0, sizeof(p->identifier));
 	return UA_SUCCESS;
@@ -427,16 +427,13 @@ UA_Int32 UA_NodeId_init(UA_NodeId *p) {
 UA_TYPE_NEW_DEFAULT(UA_NodeId)
 UA_Int32 UA_NodeId_copy(UA_NodeId const *src, UA_NodeId *dst) {
 	UA_Int32 retval = UA_SUCCESS;
-	if(src == UA_NULL || dst == UA_NULL) return UA_ERROR;
-	retval |= UA_Byte_copy(&src->encodingByte, &dst->encodingByte);
+	if(src == UA_NULL || dst == UA_NULL)
+		return UA_ERROR;
 
-	switch(src->encodingByte & UA_NODEIDTYPE_MASK) {
-	case UA_NODEIDTYPE_TWOBYTE:
-	case UA_NODEIDTYPE_FOURBYTE:
+	switch(src->nodeIdType) {
 	case UA_NODEIDTYPE_NUMERIC:
-		// nothing to do
-		retval |= UA_UInt16_copy(&src->namespace, &dst->namespace);
-		retval |= UA_UInt32_copy(&src->identifier.numeric, &dst->identifier.numeric);
+		*dst = *src;
+		return UA_SUCCESS;
 		break;
 
 	case UA_NODEIDTYPE_STRING: // Table 6, second entry
@@ -451,19 +448,22 @@ UA_Int32 UA_NodeId_copy(UA_NodeId const *src, UA_NodeId *dst) {
 		retval |= UA_ByteString_copy(&src->identifier.byteString, &dst->identifier.byteString);
 		break;
 	}
+	dst->nodeIdType = src->nodeIdType;
 	return retval;
 }
+
 UA_Boolean UA_NodeId_isBasicType(UA_NodeId const *id) {
-	return (id->namespace == 0 && id->identifier.numeric <= UA_DIAGNOSTICINFO);
+	return (id->namespace == 0 &&
+			id->nodeIdType == UA_NODEIDTYPE_NUMERIC &&
+			id->identifier.numeric <= UA_DIAGNOSTICINFO);
 }
 
 UA_TYPE_DELETE_DEFAULT(UA_NodeId)
 UA_Int32 UA_NodeId_deleteMembers(UA_NodeId *p) {
 	UA_Int32 retval = UA_SUCCESS;
 	if(p == UA_NULL) return retval;
-	switch(p->encodingByte & UA_NODEIDTYPE_MASK) {
-	case UA_NODEIDTYPE_TWOBYTE:
-	case UA_NODEIDTYPE_FOURBYTE:
+
+	switch(p->nodeIdType) {
 	case UA_NODEIDTYPE_NUMERIC:
 		// nothing to do
 		break;
@@ -485,48 +485,50 @@ UA_Int32 UA_NodeId_deleteMembers(UA_NodeId *p) {
 
 #ifdef DEBUG
 void UA_NodeId_print(const UA_NodeId *p, FILE *stream) {
-	if(p == UA_NULL || stream == UA_NULL) return;
+	if(p == UA_NULL || stream == UA_NULL)
+		return;
+
 	fprintf(stream, "(UA_NodeId){");
-	switch(p->encodingByte & UA_NODEIDTYPE_MASK) {
-	case UA_NODEIDTYPE_TWOBYTE:
-		fprintf(stream, "UA_NODEIDTYPE_TWOBYTE");
-		break;
-	case UA_NODEIDTYPE_FOURBYTE:
-		fprintf(stream, "UA_NODEIDTYPE_FOURBYTE");
-		break;
+	switch(p->nodeIdType) {
 	case UA_NODEIDTYPE_NUMERIC:
 		fprintf(stream, "UA_NODEIDTYPE_NUMERIC");
 		break;
+
 	case UA_NODEIDTYPE_STRING:
 		fprintf(stream, "UA_NODEIDTYPE_STRING");
 		break;
+
 	case UA_NODEIDTYPE_BYTESTRING:
 		fprintf(stream, "UA_NODEIDTYPE_BYTESTRING");
 		break;
+
 	case UA_NODEIDTYPE_GUID:
 		fprintf(stream, "UA_NODEIDTYPE_GUID");
 		break;
+
 	default:
 		fprintf(stream, "ERROR");
 		break;
 	}
 	fprintf(stream,",%u,", p->namespace);
-	switch(p->encodingByte & UA_NODEIDTYPE_MASK) {
-	case UA_NODEIDTYPE_TWOBYTE:
-	case UA_NODEIDTYPE_FOURBYTE:
+	switch(p->nodeIdType & UA_NODEIDTYPE_MASK) {
 	case UA_NODEIDTYPE_NUMERIC:
 		fprintf(stream, ".identifier.numeric=%u", p->identifier.numeric);
 		break;
+
 	case UA_NODEIDTYPE_STRING:
 		fprintf(stream, ".identifier.string=%.*s", p->identifier.string.length, p->identifier.string.data);
 		break;
+
 	case UA_NODEIDTYPE_BYTESTRING:
 		fprintf(stream, ".identifier.byteString=%.*s", p->identifier.byteString.length, p->identifier.byteString.data);
 		break;
+
 	case UA_NODEIDTYPE_GUID:
 		fprintf(stream, ".identifer.guid=");
 		UA_Guid_print(&p->identifier.guid, stream);
 		break;
+
 	default:
 		fprintf(stream, "ERROR");
 		break;
@@ -535,61 +537,23 @@ void UA_NodeId_print(const UA_NodeId *p, FILE *stream) {
 }
 #endif
 
-#ifdef DEBUG
-void UA_NodeId_printf(char *label, const UA_NodeId *node) {
-	UA_Int32 l;
-
-	printf("%s {encodingByte=%d, namespace=%d,", label, (int)( node->encodingByte), (int)(node->namespace));
-	switch(node->encodingByte & UA_NODEIDTYPE_MASK) {
-	case UA_NODEIDTYPE_TWOBYTE:
-	case UA_NODEIDTYPE_FOURBYTE:
-	case UA_NODEIDTYPE_NUMERIC:
-		printf("identifier=%d\n", node->identifier.numeric);
-		break;
-	case UA_NODEIDTYPE_STRING:
-		l = ( node->identifier.string.length < 0 ) ? 0 : node->identifier.string.length;
-		printf("identifier={length=%d, data=%.*s}",
-			   node->identifier.string.length, l,
-			   (char *)(node->identifier.string.data));
-		break;
-	case UA_NODEIDTYPE_BYTESTRING:
-		l = ( node->identifier.byteString.length < 0 ) ? 0 : node->identifier.byteString.length;
-		printf("identifier={Length=%d, data=%.*s}",
-			   node->identifier.byteString.length, l,
-			   (char *)(node->identifier.byteString.data));
-		break;
-	case UA_NODEIDTYPE_GUID:
-		printf(
-			   "guid={data1=%d, data2=%d, data3=%d, data4={length=%d, data=%.*s}}",
-			   node->identifier.guid.data1, node->identifier.guid.data2,
-			   node->identifier.guid.data3, 8,
-			   8,
-			   (char *)(node->identifier.guid.data4));
-		break;
-	default:
-		printf("ups! shit happens");
-		break;
-	}
-	printf("}\n");
-}
-#endif
-
 UA_Int32 UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2) {
 	if(n1 == UA_NULL || n2 == UA_NULL || n1->namespace != n2->namespace)
 		return UA_NOT_EQUAL;
 
-	switch(n1->encodingByte & UA_NODEIDTYPE_MASK) {
-	case UA_NODEIDTYPE_TWOBYTE:
-	case UA_NODEIDTYPE_FOURBYTE:
+	switch(n1->nodeIdType) {
 	case UA_NODEIDTYPE_NUMERIC:
 		if(n1->identifier.numeric == n2->identifier.numeric)
 			return UA_EQUAL;
 		else
 			return UA_NOT_EQUAL;
+
 	case UA_NODEIDTYPE_STRING:
 		return UA_String_equal(&n1->identifier.string, &n2->identifier.string);
+
 	case UA_NODEIDTYPE_GUID:
 		return UA_Guid_equal(&n1->identifier.guid, &n2->identifier.guid);
+
 	case UA_NODEIDTYPE_BYTESTRING:
 		return UA_ByteString_equal(&n1->identifier.byteString, &n2->identifier.byteString);
 	}
@@ -597,12 +561,7 @@ UA_Int32 UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2) {
 }
 
 UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
-	switch(p->encodingByte & UA_NODEIDTYPE_MASK) {
-	case UA_NODEIDTYPE_TWOBYTE:
-		if(p->identifier.numeric != 0) return UA_FALSE;
-		break;
-
-	case UA_NODEIDTYPE_FOURBYTE:
+	switch(p->nodeIdType) {
 	case UA_NODEIDTYPE_NUMERIC:
 		if(p->namespace != 0 || p->identifier.numeric != 0) return UA_FALSE;
 		break;

+ 22 - 14
src/ua_types.h

@@ -55,39 +55,46 @@
 /** @brief A two-state logical value (true or false). */
 typedef _Bool UA_Boolean;
 
-
 /** @brief An integer value between −128 and 127. */
 typedef int8_t UA_SByte;
 #define UA_SBYTE_MAX -128
 #define UA_SBYTE_MIN 127
+
 /** @brief An integer value between 0 and 256. */
 typedef uint8_t UA_Byte;
 #define UA_BYTE_MAX 256
 #define UA_BYTE_MIN 0
+
 /** @brief An integer value between −32 768 and 32 767. */
 typedef int16_t UA_Int16;
 #define UA_INT16_MAX 32767
 #define UA_INT16_MIN -32768
+
 /** @brief An integer value between 0 and 65 535. */
 typedef uint16_t UA_UInt16;
 #define UA_UINT16_MAX  65535
 #define UA_UINT16_MIN  0
+
 /** @brief 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
+
 /** @brief An integer value between 0 and 429 4967 295. */
 typedef uint32_t UA_UInt32;
 #define UA_UINT32_MAX  4294967295;
 #define UA_UINT32_MIN  0;
+
 /** @brief An integer value between −9 223 372 036 854 775 808 and 9 223 372 036 854 775 807 */
 typedef int64_t UA_Int64;
 #define UA_INT64_MAX  9223372036854775807
 #define UA_INT64_MIN  −9223372036854775808
+
 /** @brief An integer value between 0 and 18 446 744 073 709 551 615. */
 typedef uint64_t UA_UInt64;
 #define UA_UINT64_MAX = 18446744073709551615
 #define UA_UINT64_MIN = 0
+
 /** @brief An IEEE single precision (32 bit) floating point value. */
 typedef float UA_Float;
 
@@ -119,7 +126,15 @@ typedef struct UA_String UA_XmlElement;
 
 /** @brief An identifier for a node in the address space of an OPC UA Server. */
 typedef struct UA_NodeId {
-	UA_Byte encodingByte;
+	enum {
+		/* The shortened numeric types are introduced during encoding.
+		   UA_NODEIDTYPE_TWOBYTE = 0,
+		   UA_NODEIDTYPE_FOURBYTE = 1, */
+		UA_NODEIDTYPE_NUMERIC = 2,
+		UA_NODEIDTYPE_STRING = 3,
+		UA_NODEIDTYPE_GUID = 4,
+		UA_NODEIDTYPE_BYTESTRING = 5
+	} nodeIdType;
 	UA_UInt16 namespace;
 	union {
 		UA_UInt32     numeric;
@@ -129,15 +144,11 @@ typedef struct UA_NodeId {
 	} identifier;
 } UA_NodeId;
 
-#define UA_NODEIDTYPE_NAMESPACE_URI_FLAG 0x80
-#define UA_NODEIDTYPE_SERVERINDEX_FLAG 0x40
-#define UA_NODEIDTYPE_MASK (~(UA_NODEIDTYPE_NAMESPACE_URI_FLAG | UA_NODEIDTYPE_SERVERINDEX_FLAG))
-
 /** @brief A NodeId that allows the namespace URI to be specified instead of an index. */
 typedef struct UA_ExpandedNodeId {
 	UA_NodeId nodeId;
-	UA_String namespaceUri;
-	UA_UInt32 serverIndex;
+	UA_String namespaceUri; // not encoded if length=-1
+	UA_UInt32 serverIndex; // not encoded if 0
 } UA_ExpandedNodeId;
 
 /** @brief A numeric identifier for a error or condition that is associated with a value or an operation. */
@@ -335,14 +346,11 @@ void UA_ByteString_printx_hex(char *label, const UA_ByteString *string);
 
 /* NodeId */
 UA_Int32 UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
-#ifdef DEBUG
-void UA_NodeId_printf(char *label, const UA_NodeId *node);
-#endif
 UA_Boolean UA_NodeId_isNull(const UA_NodeId *p);
 UA_Boolean UA_NodeId_isBasicType(UA_NodeId const *id);
 
 #define NS0NODEID(NUMERIC_ID) \
-	(UA_NodeId){ .encodingByte = 0 /*UA_NODEIDTYPE_TWOBYTE*/, .namespace = 0, .identifier.numeric = NUMERIC_ID }
+	(UA_NodeId){ .nodeIdType = UA_NODEIDTYPE_NUMERIC, .namespace = 0, .identifier.numeric = NUMERIC_ID }
 
 /* ExpandedNodeId */
 UA_Boolean UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
@@ -353,7 +361,7 @@ UA_Boolean UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
 	VARIABLE.serverIndex = 0; } while(0)
 
 /* QualifiedName */
-#define UA_QUALIFIEDNAME_STATIC(VARIABLE, STRING) do {\
+#define UA_QUALIFIEDNAME_STATIC(VARIABLE, STRING) do { \
 	VARIABLE.namespaceIndex = 0; \
 	UA_STRING_STATIC(VARIABLE.name, STRING); } while (0)
 #ifdef DEBUG
@@ -361,7 +369,7 @@ void UA_QualifiedName_printf(char const *label, const UA_QualifiedName *qn);
 #endif
 
 /* LocalizedText */
-#define UA_LOCALIZEDTEXT_STATIC(VARIABLE, STRING) do {\
+#define UA_LOCALIZEDTEXT_STATIC(VARIABLE, STRING) do { \
 	UA_STRING_STATIC(VARIABLE.locale, "end"); \
 	UA_STRING_STATIC(VARIABLE.text, STRING); } while (0)
 

+ 88 - 48
src/ua_types_encoding_binary.c

@@ -377,38 +377,40 @@ UA_TYPE_BINARY_ENCODING_AS(UA_ByteString, UA_String)
 UA_TYPE_BINARY_ENCODING_AS(UA_XmlElement, UA_String)
 
 /* NodeId */
+
+/* The shortened numeric nodeid types. */
+#define UA_NODEIDTYPE_TWOBYTE 0
+#define UA_NODEIDTYPE_FOURBYTE 1
+
 UA_Int32 UA_NodeId_calcSizeBinary(UA_NodeId const *p) {
 	UA_Int32 length = 0;
 	if(p == UA_NULL)
 		length = sizeof(UA_NodeId);
 	else {
-		switch(p->encodingByte & UA_NODEIDTYPE_MASK) {
-		case UA_NODEIDTYPE_TWOBYTE:
-			length = 2;
-			break;
-
-		case UA_NODEIDTYPE_FOURBYTE:
-			length = 4;
-			break;
-
+		switch(p->nodeIdType) {
 		case UA_NODEIDTYPE_NUMERIC:
-			length += sizeof(UA_Byte) + sizeof(UA_UInt16) + sizeof(UA_UInt32);
+			if(p->identifier.numeric > UA_UINT16_MAX || p->namespace > UA_BYTE_MAX)
+				length = sizeof(UA_Byte) + sizeof(UA_UInt16) + sizeof(UA_UInt32);
+			else if(p->identifier.numeric > UA_BYTE_MAX || p->namespace > 0)
+				length = 4; /* UA_NODEIDTYPE_FOURBYTE */
+			else
+				length = 2; /* UA_NODEIDTYPE_TWOBYTE*/
 			break;
 
 		case UA_NODEIDTYPE_STRING:
-			length += sizeof(UA_Byte) + sizeof(UA_UInt16) + UA_String_calcSizeBinary(&p->identifier.string);
+			length = sizeof(UA_Byte) + sizeof(UA_UInt16) + UA_String_calcSizeBinary(&p->identifier.string);
 			break;
 
 		case UA_NODEIDTYPE_GUID:
-			length += sizeof(UA_Byte) + sizeof(UA_UInt16) + UA_Guid_calcSizeBinary(&p->identifier.guid);
+			length = sizeof(UA_Byte) + sizeof(UA_UInt16) + UA_Guid_calcSizeBinary(&p->identifier.guid);
 			break;
 
 		case UA_NODEIDTYPE_BYTESTRING:
-			length += sizeof(UA_Byte) + sizeof(UA_UInt16) + UA_ByteString_calcSizeBinary(&p->identifier.byteString);
+			length = sizeof(UA_Byte) + sizeof(UA_UInt16) + UA_ByteString_calcSizeBinary(&p->identifier.byteString);
 			break;
 
 		default:
-			break;
+			break; // calcSize does not return errors. But the encoding function will.
 		}
 	}
 	return length;
@@ -420,58 +422,74 @@ UA_TYPE_ENCODEBINARY(UA_NodeId,
                      UA_UInt16 srcUInt16;
 
                      UA_Int32 retval = UA_SUCCESS;
-                     retval |= UA_Byte_encodeBinary(&src->encodingByte, dst, offset);
-                     switch(src->encodingByte & UA_NODEIDTYPE_MASK) {
-					 case UA_NODEIDTYPE_TWOBYTE:
-						 srcByte = src->identifier.numeric;
-						 retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
-						 break;
-
-					 case UA_NODEIDTYPE_FOURBYTE:
-						 srcByte = src->namespace;
-						 srcUInt16 = src->identifier.numeric;
-						 retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
-						 retval |= UA_UInt16_encodeBinary(&srcUInt16, dst, offset);
-						 break;
-
+                     switch(src->nodeIdType) {
 					 case UA_NODEIDTYPE_NUMERIC:
-						 retval |= UA_UInt16_encodeBinary(&src->namespace, dst, offset);
-						 retval |= UA_UInt32_encodeBinary(&src->identifier.numeric, dst, offset);
+						 if(src->identifier.numeric > UA_UINT16_MAX || src->namespace > UA_BYTE_MAX) {
+							 srcByte = UA_NODEIDTYPE_NUMERIC;
+							 retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
+							 retval |= UA_UInt16_encodeBinary(&src->namespace, dst, offset);
+							 retval |= UA_UInt32_encodeBinary(&src->identifier.numeric, dst, offset);
+						 } else if(src->identifier.numeric > UA_BYTE_MAX || src->namespace > 0) { /* UA_NODEIDTYPE_FOURBYTE */
+							 srcByte = UA_NODEIDTYPE_FOURBYTE;
+							 retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
+							 srcByte = src->namespace;
+							 srcUInt16 = src->identifier.numeric;
+							 retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
+							 retval |= UA_UInt16_encodeBinary(&srcUInt16, dst, offset);
+						 } else { /* UA_NODEIDTYPE_TWOBYTE */
+							 srcByte = UA_NODEIDTYPE_TWOBYTE;
+							 retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
+							 srcByte = src->identifier.numeric;
+							 retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
+						 }
 						 break;
 
 					 case UA_NODEIDTYPE_STRING:
+						 srcByte = UA_NODEIDTYPE_STRING;
+						 retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
 						 retval |= UA_UInt16_encodeBinary(&src->namespace, dst, offset);
 						 retval |= UA_String_encodeBinary(&src->identifier.string, dst, offset);
 						 break;
 
 					 case UA_NODEIDTYPE_GUID:
+						 srcByte = UA_NODEIDTYPE_GUID;
+						 retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
 						 retval |= UA_UInt16_encodeBinary(&src->namespace, dst, offset);
 						 retval |= UA_Guid_encodeBinary(&src->identifier.guid, dst, offset);
 						 break;
 
 					 case UA_NODEIDTYPE_BYTESTRING:
+						 srcByte = UA_NODEIDTYPE_BYTESTRING;
+						 retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
 						 retval |= UA_UInt16_encodeBinary(&src->namespace, dst, offset);
 						 retval |= UA_ByteString_encodeBinary(&src->identifier.byteString, dst, offset);
 						 break;
+
+					 default:
+						 retval = UA_ERROR;
 					 }
                      )
 
 UA_Int32 UA_NodeId_decodeBinary(UA_ByteString const *src, UA_UInt32 *offset, UA_NodeId *dst) {
 	UA_Int32 retval = UA_SUCCESS;
 	UA_NodeId_init(dst);
+
 	// temporary variables to overcome decoder's non-endian-saveness for datatypes with different length
-	UA_Byte   dstByte   = 0;
-	UA_UInt16 dstUInt16 = 0;
+	UA_Byte   dstByte;
+	UA_UInt16 dstUInt16;
 
-	CHECKED_DECODE(UA_Byte_decodeBinary(src, offset, &dst->encodingByte),; );
-	switch(dst->encodingByte & UA_NODEIDTYPE_MASK) {
+	UA_Byte encodingByte;
+	CHECKED_DECODE(UA_Byte_decodeBinary(src, offset, &encodingByte),; );
+	switch(encodingByte) {
 	case UA_NODEIDTYPE_TWOBYTE: // Table 7
+		dst->nodeIdType = UA_NODEIDTYPE_NUMERIC;
 		CHECKED_DECODE(UA_Byte_decodeBinary(src, offset, &dstByte),; );
 		dst->identifier.numeric = dstByte;
 		dst->namespace = 0; // default namespace
 		break;
 
 	case UA_NODEIDTYPE_FOURBYTE: // Table 8
+		dst->nodeIdType = UA_NODEIDTYPE_NUMERIC;
 		CHECKED_DECODE(UA_Byte_decodeBinary(src, offset, &dstByte),; );
 		dst->namespace = dstByte;
 		CHECKED_DECODE(UA_UInt16_decodeBinary(src, offset, &dstUInt16),; );
@@ -479,24 +497,31 @@ UA_Int32 UA_NodeId_decodeBinary(UA_ByteString const *src, UA_UInt32 *offset, UA_
 		break;
 
 	case UA_NODEIDTYPE_NUMERIC: // Table 6, first entry
+		dst->nodeIdType = UA_NODEIDTYPE_NUMERIC;
 		CHECKED_DECODE(UA_UInt16_decodeBinary(src, offset, &dst->namespace),; );
 		CHECKED_DECODE(UA_UInt32_decodeBinary(src, offset, &dst->identifier.numeric),; );
 		break;
 
 	case UA_NODEIDTYPE_STRING: // Table 6, second entry
+		dst->nodeIdType = UA_NODEIDTYPE_STRING;
 		CHECKED_DECODE(UA_UInt16_decodeBinary(src, offset, &dst->namespace),; );
 		CHECKED_DECODE(UA_String_decodeBinary(src, offset, &dst->identifier.string),; );
 		break;
 
 	case UA_NODEIDTYPE_GUID: // Table 6, third entry
+		dst->nodeIdType = UA_NODEIDTYPE_GUID;
 		CHECKED_DECODE(UA_UInt16_decodeBinary(src, offset, &dst->namespace),; );
 		CHECKED_DECODE(UA_Guid_decodeBinary(src, offset, &dst->identifier.guid),; );
 		break;
 
 	case UA_NODEIDTYPE_BYTESTRING: // Table 6, "OPAQUE"
+		dst->nodeIdType = UA_NODEIDTYPE_BYTESTRING;
 		CHECKED_DECODE(UA_UInt16_decodeBinary(src, offset, &dst->namespace),; );
 		CHECKED_DECODE(UA_ByteString_decodeBinary(src, offset, &dst->identifier.byteString),; );
 		break;
+
+	default:
+		retval = UA_ERROR;
 	}
 	return retval;
 }
@@ -508,35 +533,50 @@ UA_Int32 UA_ExpandedNodeId_calcSizeBinary(UA_ExpandedNodeId const *p) {
 		length = sizeof(UA_ExpandedNodeId);
 	else {
 		length = UA_NodeId_calcSizeBinary(&p->nodeId);
-		if(p->nodeId.encodingByte & UA_NODEIDTYPE_NAMESPACE_URI_FLAG)
-			length += UA_String_calcSizeBinary(&p->namespaceUri);  //p->namespaceUri
-		if(p->nodeId.encodingByte & UA_NODEIDTYPE_SERVERINDEX_FLAG)
-			length += sizeof(UA_UInt32);                    //p->serverIndex
+		if(p->namespaceUri.length > 0)
+			length += UA_String_calcSizeBinary(&p->namespaceUri);
+		if(p->serverIndex > 0)
+			length += sizeof(UA_UInt32);
 	}
 	return length;
 }
 
-UA_String UA_String_null = { -1, UA_NULL };
+#define UA_EXPANDEDNODEID_NAMESPACEURI_FLAG 0x80
+#define UA_EXPANDEDNODEID_SERVERINDEX_FLAG 0x40
+
 UA_TYPE_ENCODEBINARY(UA_ExpandedNodeId,
+					 UA_Byte flags = 0;
+					 UA_UInt32 start = *offset;
                      retval |= UA_NodeId_encodeBinary(&src->nodeId, dst, offset);
-                     if(src->nodeId.encodingByte & UA_NODEIDTYPE_NAMESPACE_URI_FLAG)
+                     if(src->namespaceUri.length > 0) {
+						 // TODO: Set namespaceIndex to 0 in the nodeid as the namespaceUri takes precedence
 						 retval |= UA_String_encodeBinary(&src->namespaceUri, dst, offset);
-                     if(src->nodeId.encodingByte & UA_NODEIDTYPE_SERVERINDEX_FLAG)
+						 flags |= UA_EXPANDEDNODEID_NAMESPACEURI_FLAG;
+					 }
+                     if(src->serverIndex > 0) {
 						 retval |= UA_UInt32_encodeBinary(&src->serverIndex, dst, offset);
+						 flags |= UA_EXPANDEDNODEID_SERVERINDEX_FLAG;
+					 }
+					 if(flags != 0)
+						 dst->data[start] |= flags;
                      )
 
 UA_Int32 UA_ExpandedNodeId_decodeBinary(UA_ByteString const *src, UA_UInt32 *offset, UA_ExpandedNodeId *dst) {
 	UA_UInt32 retval = UA_SUCCESS;
 	UA_ExpandedNodeId_init(dst);
+
+	// get encodingflags and leave a "clean" nodeidtype
+	if((UA_Int32)*offset >= src->length)
+		return UA_ERROR;
+	UA_Byte encodingByte = src->data[*offset];
+	src->data[*offset] = encodingByte & ~(UA_EXPANDEDNODEID_NAMESPACEURI_FLAG | UA_EXPANDEDNODEID_SERVERINDEX_FLAG);
+	
 	CHECKED_DECODE(UA_NodeId_decodeBinary(src, offset, &dst->nodeId), UA_ExpandedNodeId_deleteMembers(dst));
-	if(dst->nodeId.encodingByte & UA_NODEIDTYPE_NAMESPACE_URI_FLAG) {
+	if(encodingByte & UA_EXPANDEDNODEID_NAMESPACEURI_FLAG) {
 		dst->nodeId.namespace = 0;
 		CHECKED_DECODE(UA_String_decodeBinary(src, offset, &dst->namespaceUri), UA_ExpandedNodeId_deleteMembers(dst));
-	} else {
-	CHECKED_DECODE(UA_String_copy(&UA_String_null, &dst->namespaceUri), UA_ExpandedNodeId_deleteMembers(dst));
 	}
-
-	if(dst->nodeId.encodingByte & UA_NODEIDTYPE_SERVERINDEX_FLAG)
+	if(encodingByte & UA_EXPANDEDNODEID_SERVERINDEX_FLAG)
 		CHECKED_DECODE(UA_UInt32_decodeBinary(src, offset, &dst->serverIndex), UA_ExpandedNodeId_deleteMembers(dst));
 	return retval;
 }
@@ -648,7 +688,7 @@ UA_Int32 UA_ExtensionObject_decodeBinary(UA_ByteString const *src, UA_UInt32 *of
 	UA_ExtensionObject_init(dst);
 	CHECKED_DECODE(UA_NodeId_decodeBinary(src, offset, &dst->typeId), UA_ExtensionObject_deleteMembers(dst));
 	CHECKED_DECODE(UA_Byte_decodeBinary(src, offset, &dst->encoding), UA_ExtensionObject_deleteMembers(dst));
-	CHECKED_DECODE(UA_String_copy(&UA_String_null, (UA_String *)&dst->body), UA_ExtensionObject_deleteMembers(dst));
+	CHECKED_DECODE(UA_String_copy(&UA_STRING_NULL, (UA_String *)&dst->body), UA_ExtensionObject_deleteMembers(dst));
 	switch(dst->encoding) {
 	case UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED:
 		break;
@@ -838,7 +878,7 @@ UA_Int32 UA_Variant_decodeBinary(UA_ByteString const *src, UA_UInt32 *offset, UA
 	UA_Boolean isArray = encodingByte & (0x01 << 7);                             // Bit 7
 	UA_Boolean hasDimensions = isArray && (encodingByte & (0x01 << 6));            // Bit 6
 
-	UA_NodeId typeid = { .encodingByte = (UA_Byte)UA_NODEIDTYPE_FOURBYTE, .namespace= 0,
+	UA_NodeId typeid = { .nodeIdType = UA_NODEIDTYPE_NUMERIC, .namespace= 0,
 						 .identifier.numeric = encodingByte & 0x3F };
 	UA_Int32 typeNs0Id = UA_ns0ToVTableIndex(&typeid );
 	dst->vt = &UA_.types[typeNs0Id];

+ 22 - 15
tests/check_builtin.c

@@ -214,7 +214,7 @@ START_TEST(UA_ExtensionObject_calcSizeShallWorkOnExample) {
 
 	// empty ExtensionObject, handcoded
 	// when
-	extensionObject.typeId.encodingByte = UA_NODEIDTYPE_TWOBYTE;
+	extensionObject.typeId.nodeIdType = UA_NODEIDTYPE_NUMERIC;
 	extensionObject.typeId.identifier.numeric = 0;
 	extensionObject.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED;
 	// then
@@ -337,7 +337,9 @@ END_TEST
 START_TEST(UA_NodeId_calcSizeEncodingTwoByteShallReturnEncodingSize) {
 	// given
 	UA_NodeId arg;
-	arg.encodingByte = UA_NODEIDTYPE_TWOBYTE;
+	arg.nodeIdType = UA_NODEIDTYPE_NUMERIC;
+	arg.namespace = 0;
+	arg.identifier.numeric = 1;
 	// when
 	UA_UInt32 encodingSize = UA_NodeId_calcSizeBinary(&arg);
 	// then
@@ -347,7 +349,9 @@ END_TEST
 START_TEST(UA_NodeId_calcSizeEncodingFourByteShallReturnEncodingSize) {
 	// given
 	UA_NodeId arg;
-	arg.encodingByte = UA_NODEIDTYPE_FOURBYTE;
+	arg.nodeIdType = UA_NODEIDTYPE_NUMERIC;
+	arg.namespace = 1;
+	arg.identifier.numeric = 1;
 	// when
 	UA_UInt32 encodingSize = UA_NodeId_calcSizeBinary(&arg);
 	// then
@@ -357,7 +361,7 @@ END_TEST
 START_TEST(UA_NodeId_calcSizeEncodingStringShallReturnEncodingSize) {
 	// given
 	UA_NodeId arg;
-	arg.encodingByte = UA_NODEIDTYPE_STRING;
+	arg.nodeIdType = UA_NODEIDTYPE_STRING;
 	arg.identifier.string.length = 3;
 	arg.identifier.string.data   = (UA_Byte *)"PLT";
 	// when
@@ -369,7 +373,7 @@ END_TEST
 START_TEST(UA_NodeId_calcSizeEncodingStringNegativLengthShallReturnEncodingSize) {
 	// given
 	UA_NodeId arg;
-	arg.encodingByte = UA_NODEIDTYPE_STRING;
+	arg.nodeIdType = UA_NODEIDTYPE_STRING;
 	arg.identifier.string.length = -1;
 	// when
 	UA_UInt32 encodingSize = UA_NodeId_calcSizeBinary(&arg);
@@ -380,7 +384,7 @@ END_TEST
 START_TEST(UA_NodeId_calcSizeEncodingStringZeroLengthShallReturnEncodingSize) {
 	// given
 	UA_NodeId arg;
-	arg.encodingByte = UA_NODEIDTYPE_STRING;
+	arg.nodeIdType = UA_NODEIDTYPE_STRING;
 	arg.identifier.string.length = 0;
 	// when
 	UA_UInt32 encodingSize = UA_NodeId_calcSizeBinary(&arg);
@@ -391,7 +395,9 @@ END_TEST
 START_TEST(UA_ExpandedNodeId_calcSizeEncodingStringAndServerIndexShallReturnEncodingSize) {
 	// given
 	UA_ExpandedNodeId arg;
-	arg.nodeId.encodingByte = UA_NODEIDTYPE_STRING | UA_NODEIDTYPE_SERVERINDEX_FLAG;
+	UA_ExpandedNodeId_init(&arg);
+	arg.nodeId.nodeIdType = UA_NODEIDTYPE_STRING;
+	arg.serverIndex = 1;
 	arg.nodeId.identifier.string.length = 3;
 	// when
 	UA_UInt32 encodingSize = UA_ExpandedNodeId_calcSizeBinary(&arg);
@@ -402,7 +408,8 @@ END_TEST
 START_TEST(UA_ExpandedNodeId_calcSizeEncodingStringAndNamespaceUriShallReturnEncodingSize) {
 	// given
 	UA_ExpandedNodeId arg;
-	arg.nodeId.encodingByte = UA_NODEIDTYPE_STRING | UA_NODEIDTYPE_NAMESPACE_URI_FLAG;
+	UA_ExpandedNodeId_init(&arg);
+	arg.nodeId.nodeIdType = UA_NODEIDTYPE_STRING;
 	arg.nodeId.identifier.string.length = 3;
 	arg.namespaceUri.length = 7;
 	// when
@@ -793,7 +800,7 @@ END_TEST
 START_TEST(UA_NodeId_decodeTwoByteShallReadTwoBytesAndSetNamespaceToZero) {
 	// given
 	UA_UInt32     pos    = 0;
-	UA_Byte       data[] = { UA_NODEIDTYPE_TWOBYTE, 0x10 };
+	UA_Byte       data[] = { 0 /* UA_NODEIDTYPE_TWOBYTE */, 0x10 };
 	UA_ByteString src    = { 2, data };
 
 	UA_NodeId     dst;
@@ -802,7 +809,7 @@ START_TEST(UA_NodeId_decodeTwoByteShallReadTwoBytesAndSetNamespaceToZero) {
 	// then
 	ck_assert_int_eq(retval, UA_SUCCESS);
 	ck_assert_int_eq(pos, 2);
-	ck_assert_int_eq(dst.encodingByte, UA_NODEIDTYPE_TWOBYTE);
+	ck_assert_int_eq(dst.nodeIdType, UA_NODEIDTYPE_NUMERIC);
 	ck_assert_int_eq(dst.identifier.numeric, 16);
 	ck_assert_int_eq(dst.namespace, 0);
 }
@@ -810,7 +817,7 @@ END_TEST
 START_TEST(UA_NodeId_decodeFourByteShallReadFourBytesAndRespectNamespace) {
 	// given
 	UA_UInt32     pos    = 0;
-	UA_Byte       data[] = { UA_NODEIDTYPE_FOURBYTE, 0x01, 0x00, 0x01 };
+	UA_Byte       data[] = { 1 /* UA_NODEIDTYPE_FOURBYTE */, 0x01, 0x00, 0x01 };
 	UA_ByteString src    = { 4, data };
 
 	UA_NodeId     dst;
@@ -819,7 +826,7 @@ START_TEST(UA_NodeId_decodeFourByteShallReadFourBytesAndRespectNamespace) {
 	// then
 	ck_assert_int_eq(retval, UA_SUCCESS);
 	ck_assert_int_eq(pos, 4);
-	ck_assert_int_eq(dst.encodingByte, UA_NODEIDTYPE_FOURBYTE);
+	ck_assert_int_eq(dst.nodeIdType, UA_NODEIDTYPE_NUMERIC);
 	ck_assert_int_eq(dst.identifier.numeric, 256);
 	ck_assert_int_eq(dst.namespace, 1);
 }
@@ -836,7 +843,7 @@ START_TEST(UA_NodeId_decodeStringShallAllocateMemory) {
 	// then
 	ck_assert_int_eq(retval, UA_SUCCESS);
 	ck_assert_int_eq(pos, 10);
-	ck_assert_int_eq(dst.encodingByte, UA_NODEIDTYPE_STRING);
+	ck_assert_int_eq(dst.nodeIdType, UA_NODEIDTYPE_STRING);
 	ck_assert_int_eq(dst.namespace, 1);
 	ck_assert_int_eq(dst.identifier.string.length, 3);
 	ck_assert_ptr_eq(dst.identifier.string.data, UA_alloc_lastptr);
@@ -1383,7 +1390,7 @@ START_TEST(UA_ExtensionObject_copyShallWorkOnExample) {
 	UA_ExtensionObject_init(&value);
 	UA_ExtensionObject_init(&valueCopied);
 
-	value.typeId.encodingByte = UA_NODEIDTYPE_TWOBYTE;
+	value.typeId.nodeIdType = UA_NODEIDTYPE_NUMERIC;
 	value.typeId.identifier.numeric = UA_BYTE;
 	value.encoding    = UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED;
 	value.encoding    = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
@@ -1397,7 +1404,7 @@ START_TEST(UA_ExtensionObject_copyShallWorkOnExample) {
 		ck_assert_int_eq(valueCopied.body.data[i], value.body.data[i]);
 
 	ck_assert_int_eq(valueCopied.encoding, value.encoding);
-	ck_assert_int_eq(valueCopied.typeId.encodingByte, value.typeId.encodingByte);
+	ck_assert_int_eq(valueCopied.typeId.nodeIdType, value.typeId.nodeIdType);
 	ck_assert_int_eq(valueCopied.typeId.identifier.numeric, value.typeId.identifier.numeric);
 
 	//finally

+ 1 - 1
tests/check_namespace.c

@@ -31,7 +31,7 @@ END_TEST
 
 UA_Int32 createNode(UA_Node** p, UA_Int16 nsid, UA_Int32 id) {
 	UA_VariableNode_new((UA_VariableNode **)p);
-	(*p)->nodeId.encodingByte = UA_NODEIDTYPE_FOURBYTE;
+	(*p)->nodeId.nodeIdType = UA_NODEIDTYPE_NUMERIC;
 	(*p)->nodeId.namespace = nsid;
 	(*p)->nodeId.identifier.numeric = id;
 	(*p)->nodeClass = UA_NODECLASS_VARIABLE;

+ 3 - 0
tools/generate_builtin.py

@@ -39,6 +39,9 @@ existing_types = set(["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "U
                       "QualifiedName", "LocalizedText", "ExtensionObject", "DataValue",
                       "Variant", "DiagnosticInfo"])
 
+# some types are omitted (pretend they exist already)
+existing_types.add("NodeIdType")
+
 fixed_size = set(["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_Guid", "UA_StatusCode"])

+ 1 - 1
tools/generate_namespace.py

@@ -158,7 +158,7 @@ for row in rows:
 	i=i+1
     printh('#define '+name.upper()+'_NS0 '+row[1])
 
-    printc("\t{.typeId={.encodingByte = UA_NODEIDTYPE_TWOBYTE, .namespace = 0,.identifier.numeric=" + row[1] + "}" + 
+    printc("\t{.typeId={.nodeIdType = UA_NODEIDTYPE_NUMERIC, .namespace = 0,.identifier.numeric=" + row[1] + "}" + 
           ",\n.name=(UA_Byte*)&\"%(name)s\"" +
           ",\n.new=(UA_Int32(*)(void **))%(name)s_new" +
           ",\n.init=(UA_Int32(*)(void *))%(name)s_init"+