Browse Source

squash commit of the better_variant branch.
most of this is coming from @stasik

Julius Pfrommer 10 years ago
parent
commit
9d1a7de054

+ 3 - 3
examples/server_datasource.c

@@ -36,7 +36,7 @@ static UA_StatusCode readTimeData(const void *handle, UA_Boolean sourceTimeStamp
 		return UA_STATUSCODE_BADOUTOFMEMORY;
 	*currentTime = UA_DateTime_now();
 	value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
-	value->value.arrayLength = 1;
+	value->value.arrayLength = -1;
 	value->value.dataPtr = currentTime;
 	value->value.arrayDimensionsSize = -1;
 	value->value.arrayDimensions = NULL;
@@ -73,7 +73,7 @@ static UA_StatusCode readTemperature(const void *handle, UA_Boolean sourceTimeSt
 	*currentTemperature /= 1000.0;
 
 	value->value.type = &UA_TYPES[UA_TYPES_DOUBLE];
-	value->value.arrayLength = 1;
+	value->value.arrayLength = -1;
 	value->value.dataPtr = currentTemperature;
 	value->value.arrayDimensionsSize = -1;
 	value->value.arrayDimensions = NULL;
@@ -102,7 +102,7 @@ static UA_StatusCode readLedStatus(const void *handle, UA_Boolean sourceTimeStam
 	pthread_rwlock_rdlock(&writeLock);
 #endif
 	value->value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
-	value->value.arrayLength = 1;
+	value->value.arrayLength = -1;
 	value->value.dataPtr = &ledStatus;
 	value->value.arrayDimensionsSize = -1;
 	value->value.arrayDimensions = NULL;

+ 9 - 22
src/server/ua_server.c

@@ -103,7 +103,7 @@ static UA_StatusCode readStatus(const void *handle, UA_Boolean sourceTimeStamp,
     status->buildInfo.buildDate = ((const UA_Server*)handle)->buildDate;
     status->secondsTillShutdown = 0;
     value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
-	value->value.arrayLength = 1;
+	value->value.arrayLength = -1;
     value->value.dataPtr = status;
     value->value.arrayDimensionsSize = -1;
     value->value.arrayDimensions = UA_NULL;
@@ -125,7 +125,7 @@ static UA_StatusCode readCurrentTime(const void *handle, UA_Boolean sourceTimeSt
 		return UA_STATUSCODE_BADOUTOFMEMORY;
 	*currentTime = UA_DateTime_now();
 	value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
-	value->value.arrayLength = 1;
+	value->value.arrayLength = -1;
 	value->value.dataPtr = currentTime;
 	value->value.arrayDimensionsSize = -1;
 	value->value.arrayDimensions = NULL;
@@ -695,7 +695,7 @@ UA_Server * UA_Server_new(void) {
    state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
    state->variableType = UA_VARIABLENODETYPE_VARIANT;
    state->variable.variant.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
-   state->variable.variant.arrayLength = 1;
+   state->variable.variant.arrayLength = -1;
    state->variable.variant.dataPtr = stateEnum; // points into the other object.
    UA_NodeStore_insert(server->nodestore, (UA_Node*)state, UA_NULL);
    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS), UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT),
@@ -761,25 +761,12 @@ UA_Server * UA_Server_new(void) {
 	                              &UA_NODEID_STATIC(1, SCALARID),
 	                              &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
 
-   	   //add an array node for every built-in type
-	   UA_VariableNode *arraynode = UA_VariableNode_new();
-	   copyNames((UA_Node*)arraynode, name);
-	   arraynode->nodeId = UA_NODEID_STATIC(1, ++id);
-	   arraynode->variableType = UA_VARIABLENODETYPE_VARIANT;
-	   arraynode->variable.variant.arrayLength = type;
-	   arraynode->variable.variant.dataPtr = UA_Array_new(&UA_TYPES[type], arraynode->variable.variant.arrayLength);
-	   char* initPointer = (char* )arraynode->variable.variant.dataPtr;
-	   for(UA_Int32 i=0;i<arraynode->variable.variant.arrayLength;i++) {
-		   UA_init(initPointer, &UA_TYPES[type]);
-		   initPointer += UA_TYPES[type].memSize;
-	   }
-	   arraynode->variable.variant.type = &UA_TYPES[type];
-	   arraynode->valueRank = 1;
-	   arraynode->minimumSamplingInterval = 1.0;
-	   arraynode->historizing = UA_FALSE;
-	   UA_Server_addNode(server, (UA_Node*)arraynode,
-			   &UA_EXPANDEDNODEID_STATIC(1, ARRAYID),
-			   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+        //add an array node for every built-in type
+        UA_Variant *arrayvar = UA_Variant_new();
+        UA_Variant_setArray(arrayvar, UA_Array_new(&UA_TYPES[type], 10), 10, &UA_TYPES[type]);
+        UA_Server_addVariableNode(server, arrayvar, &UA_NODEID_STATIC(1, ++id), &myIntegerName,
+                                  &UA_NODEID_STATIC(1, ARRAYID),
+                                  &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
    }
 #endif
 

+ 1 - 2
src/server/ua_services_attribute.c

@@ -201,7 +201,6 @@ static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         {
         	//TODO: handle indexRange
-
         	if(node->nodeClass == UA_NODECLASS_VARIABLE){
 				const UA_VariableNode *vn = (const UA_VariableNode *)node;
 				if(vn->variableType == UA_VARIABLENODETYPE_VARIANT) {
@@ -226,7 +225,7 @@ static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
 													 val.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
 					vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
 				}
-        	}else{
+        	} else {
         		retval = UA_STATUSCODE_GOOD;
         	}
         }

+ 12 - 6
src/ua_types.c

@@ -581,6 +581,8 @@ UA_TYPE_DELETE_DEFAULT(UA_Variant)
 void UA_Variant_deleteMembers(UA_Variant *p) {
     if(p->storageType == UA_VARIANT_DATA) {
         if(p->dataPtr) {
+            if(p->arrayLength == -1)
+                p->arrayLength = 1;
             UA_Array_delete(p->dataPtr, p->type, p->arrayLength);
             p->dataPtr = UA_NULL;
             p->arrayLength = -1;
@@ -594,15 +596,18 @@ void UA_Variant_deleteMembers(UA_Variant *p) {
 
 UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
     UA_Variant_init(dst);
-    dst->type = src->type;
-    dst->storageType = UA_VARIANT_DATA;
-    UA_StatusCode retval = UA_Array_copy(src->dataPtr, &dst->dataPtr, src->type, src->arrayLength);
+    UA_Int32 tmp = src->arrayLength;
+    if(src->arrayLength == -1 && src->dataPtr)
+        tmp = 1;
+    UA_StatusCode retval = UA_Array_copy(src->dataPtr, &dst->dataPtr, src->type, tmp);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Variant_deleteMembers(dst);
         UA_Variant_init(dst);
         return retval;
     }
     dst->arrayLength = src->arrayLength;
+    dst->type = src->type;
+    dst->storageType = UA_VARIANT_DATA;
 
     if(src->arrayDimensions) {
         retval |= UA_Array_copy(src->arrayDimensions, (void **)&dst->arrayDimensions,
@@ -610,15 +615,16 @@ UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
         if(retval != UA_STATUSCODE_GOOD) {
             UA_Variant_deleteMembers(dst);
             UA_Variant_init(dst);
+            return retval;
         }
+        dst->arrayDimensionsSize = src->arrayDimensionsSize;
     }
-    dst->arrayDimensionsSize = src->arrayDimensionsSize;
 
     return retval;
 }
 
 UA_StatusCode UA_Variant_setValue(UA_Variant *v, void *p, const UA_DataType *type) {
-    return UA_Variant_setArray(v, p, 1, type);
+    return UA_Variant_setArray(v, p, -1, type);
 }
 
 UA_StatusCode UA_Variant_copySetValue(UA_Variant *v, const void *p, const UA_DataType *type) {
@@ -630,7 +636,7 @@ UA_StatusCode UA_Variant_copySetValue(UA_Variant *v, const void *p, const UA_Dat
 		UA_delete(new, type);
 		return retval;
 	}
-    return UA_Variant_setArray(v, new, 1, type);
+    return UA_Variant_setArray(v, new, -1, type);
 }
 
 UA_StatusCode UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 noElements,

+ 31 - 27
src/ua_types_encoding_binary.c

@@ -681,22 +681,25 @@ enum UA_VARIANT_ENCODINGMASKTYPE_enum {
 };
 
 size_t UA_Variant_calcSizeBinary(UA_Variant const *p) {
+    UA_Boolean isArray = p->arrayLength != -1 || !p->dataPtr;  // a single element is not an array
+    UA_Boolean hasDimensions = isArray && p->arrayDimensions != UA_NULL;
+    UA_Boolean isBuiltin = p->type->namespaceZero && UA_IS_BUILTIN(p->type->typeIndex);
     size_t length = sizeof(UA_Byte); //p->encodingMask
     UA_Int32 arrayLength = p->arrayLength;
-    if(arrayLength <= 0 || p->dataPtr == UA_NULL) {
-        length += 4;
-        arrayLength = 0; // for adding the extensionobject overhead...
-    }
-    else if(arrayLength == 1)
+    if(!isArray) {
+    	arrayLength = 1;
         length += UA_calcSizeBinary(p->dataPtr, p->type);
+    }
     else
         length += UA_Array_calcSizeBinary(p->dataPtr, arrayLength, p->type);
         
     // if the type is not builtin, we encode it as an extensionobject
-    if(!UA_IS_BUILTIN(p->type->typeIndex) || !p->type->namespaceZero)
-        length += 9 * arrayLength;  // overhead for extensionobjects: 4 byte nodeid + 1 byte
-                                    // encoding + 4 byte bytestring length
-    if(arrayLength != 1 && p->arrayDimensions != UA_NULL)
+    if(!isBuiltin) {
+        if(arrayLength > 0)
+            length += 9 * arrayLength;  // overhead for extensionobjects: 4 byte nodeid + 1 byte
+                                        // encoding + 4 byte bytestring length
+    }
+    if(hasDimensions)
         length += UA_Array_calcSizeBinary(p->arrayDimensions, p->arrayDimensionsSize,
                                           &UA_TYPES[UA_TYPES_INT32]);
     return length;
@@ -704,7 +707,7 @@ size_t UA_Variant_calcSizeBinary(UA_Variant const *p) {
 
 UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst, size_t *offset) {
     UA_Byte encodingByte = 0;
-    UA_Boolean isArray = src->arrayLength != 1;  // a single element is not an array
+    UA_Boolean isArray = src->arrayLength != -1 || !src->dataPtr;  // a single element is not an array
     UA_Boolean hasDimensions = isArray && src->arrayDimensions != UA_NULL;
     UA_Boolean isBuiltin = src->type->namespaceZero && UA_IS_BUILTIN(src->type->typeIndex);
 
@@ -722,11 +725,14 @@ UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst,
 
     UA_StatusCode retval = UA_Byte_encodeBinary(&encodingByte, dst, offset);
 
-    if(src->arrayLength != 1)
+    if(isArray)
         retval |= UA_Int32_encodeBinary(&src->arrayLength, dst, offset);
     uintptr_t ptr = (uintptr_t)src->dataPtr;
     ptrdiff_t memSize = src->type->memSize;
-    for(UA_Int32 i=0;i<src->arrayLength;i++) {
+    UA_Int32 numToEncode = src->arrayLength;
+    if(!isArray)
+        numToEncode = 1;
+    for(UA_Int32 i=0;i<numToEncode;i++) {
         if(!isBuiltin) {
             /* The type is wrapped inside an extensionobject*/
             // todo: offest holds only for namespace 0
@@ -739,7 +745,6 @@ UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst,
         retval |= UA_encodeBinary((void*)ptr, src->type, dst, offset);
         ptr += memSize;
     }
-
     if(hasDimensions)
         retval |= UA_Array_encodeBinary(src->arrayDimensions, src->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32], dst, offset);
     return retval;
@@ -755,17 +760,13 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset,
         return retval;
 
     UA_Boolean isArray = encodingByte & UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
-    /* The datatype in the encodingByte is always builtin. Structures are encoded inside an extensionobject */
     size_t typeIndex = (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) - 1;
-    if(typeIndex > 24)
+    if(typeIndex > 24) /* must be builtin */
         return UA_STATUSCODE_BADDECODINGERROR;
 
-    /* Arrays of extensionobjects may contain different types in every element. So we don't
-       transparently decode the content. */
-    const UA_DataType *dataType = UA_NULL;
     if(isArray || typeIndex != UA_TYPES_EXTENSIONOBJECT) {
-        /* array or builtin */
-        dataType = &UA_TYPES[typeIndex];
+        /* an array or a single builtin */
+        const UA_DataType *dataType = &UA_TYPES[typeIndex];
         UA_Int32 arraySize = 1;
         if(isArray) {
             retval |= UA_Int32_decodeBinary(src, offset, &arraySize);
@@ -778,7 +779,7 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset,
         dst->arrayLength = arraySize; // for deleteMembers
         dst->type = dataType;
     } else {
-        /* single extensionobject */
+        /* a single extensionobject */
         size_t oldoffset = *offset;
         UA_NodeId typeId;
         if((retval |= UA_NodeId_decodeBinary(src, offset, &typeId)) != UA_STATUSCODE_GOOD)
@@ -788,7 +789,8 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset,
             UA_NodeId_deleteMembers(&typeId);
             return retval;
         }
-        if(typeId.namespaceIndex == 0 && EOencodingByte == UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISXML) {
+        const UA_DataType *dataType = UA_NULL;
+        if(typeId.namespaceIndex == 0 && EOencodingByte == UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING) {
             for(typeIndex = 0;typeIndex < UA_TYPES_COUNT; typeIndex++) {
                 if(UA_NodeId_equal(&typeId, &UA_TYPES[typeIndex].typeId)) {
                     dataType = &UA_TYPES[typeIndex];
@@ -804,17 +806,17 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset,
         if((retval |= UA_decodeBinary(src, offset, dst->dataPtr, dataType)) != UA_STATUSCODE_GOOD)
             return retval;
         dst->type = dataType;
-        dst->arrayLength = 1;
+        dst->arrayLength = -1;
     }
     
-    UA_Boolean hasDimensions = isArray && (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS);
-    if(hasDimensions) {
+    /* array dimensions */
+    if(isArray && (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS)) {
         retval |= UA_Int32_decodeBinary(src, offset, &dst->arrayDimensionsSize);
         if(retval == UA_STATUSCODE_GOOD)
             retval |= UA_Array_decodeBinary(src, offset, dst->arrayDimensionsSize,
                                             &dst->dataPtr, &UA_TYPES[UA_TYPES_INT32]);
         if(retval != UA_STATUSCODE_GOOD) {
-            dst->arrayDimensionsSize = -1; // for deleteMembers
+            dst->arrayDimensionsSize = -1;
             UA_Variant_deleteMembers(dst);
             return retval;
         }
@@ -1247,7 +1249,9 @@ UA_StatusCode UA_Array_decodeBinary(const UA_ByteString *src, size_t *offset, UA
         retval = UA_decodeBinary(src, offset, (void*)ptr, dataType);
         ptr += dataType->memSize;
     }
-    if(retval != UA_STATUSCODE_GOOD)
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_Array_delete(*dst, dataType, i);
+        *dst = UA_NULL;
+    }
     return retval;
 }

+ 2 - 2
tests/check_builtin.c

@@ -1151,7 +1151,7 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithVariant) {
     src.hasVariant = UA_TRUE;
     src.hasServerTimestamp = UA_TRUE;
 	src.value.type = &UA_TYPES[UA_TYPES_INT32];
-	src.value.arrayLength  = 1; // one element (encoded as not an array)
+	src.value.arrayLength  = -1; // one element (encoded as not an array)
 	UA_Int32  vdata  = 45;
 	src.value.dataPtr = (void *)&vdata;
 
@@ -1619,7 +1619,7 @@ START_TEST(UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject) {
 	UA_Variant_init(&varAttr.value);
 	varAttr.value.type = &UA_TYPES[UA_TYPES_INT32];
 	varAttr.value.dataPtr = &val;
-	varAttr.value.arrayLength = 1;
+	varAttr.value.arrayLength = -1;
 	varAttr.userWriteMask = 41;
 	varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DATATYPE;
 	varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUE;