static void adjustValue(UA_Server *server, UA_Variant *value, const UA_NodeId *targetDataTypeId) { const UA_DataType *targetDataType = UA_findDataType(targetDataTypeId); if(!targetDataType) return; /* A string is written to a byte array. the valuerank and array dimensions * are checked later */ if(targetDataType == &UA_TYPES[UA_TYPES_BYTE] && value->type == &UA_TYPES[UA_TYPES_BYTESTRING] && UA_Variant_isScalar(value)) { UA_ByteString *str = (UA_ByteString*)value->data; value->type = &UA_TYPES[UA_TYPES_BYTE]; value->arrayLength = str->length; value->data = str->data; return; } /* An enum was sent as an int32, or an opaque type as a bytestring. This * is detected with the typeIndex indicating the "true" datatype. */ enum type_equivalence te1 = typeEquivalence(targetDataType); enum type_equivalence te2 = typeEquivalence(value->type); if(te1 != TYPE_EQUIVALENCE_NONE && te1 == te2) { value->type = targetDataType; return; } /* No more possible equivalencies */ }
static UA_StatusCode CopyValueIntoNode(UA_VariableNode *node, const UA_WriteValue *wvalue) { UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE); UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || node->nodeClass == UA_NODECLASS_VARIABLETYPE); UA_assert(node->valueSource == UA_VALUESOURCE_VARIANT); /* Parse the range */ UA_NumericRange range; UA_NumericRange *rangeptr = NULL; UA_StatusCode retval = UA_STATUSCODE_GOOD; if(wvalue->indexRange.length > 0) { retval = parse_numericrange(&wvalue->indexRange, &range); if(retval != UA_STATUSCODE_GOOD) return retval; rangeptr = ⦥ } /* The nodeid on the wire may be != the nodeid in the node: opaque types, enums and bytestrings. nodeV contains the correct type definition. */ const UA_Variant *newV = &wvalue->value.value; UA_Variant *oldV = &node->value.variant.value; UA_Variant cast_v; if (oldV->type != NULL) { // Don't run NodeId_equal on a NULL pointer (happens if the variable never held a variant) if(!UA_NodeId_equal(&oldV->type->typeId, &newV->type->typeId)) { cast_v = wvalue->value.value; newV = &cast_v; enum type_equivalence te1 = typeEquivalence(oldV->type); enum type_equivalence te2 = typeEquivalence(newV->type); if(te1 != TYPE_EQUIVALENCE_NONE && te1 == te2) { /* An enum was sent as an int32, or an opaque type as a bytestring. This is detected with the typeIndex indicated the "true" datatype. */ cast_v.type = oldV->type; } else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] && !UA_Variant_isScalar(oldV) && newV->type == &UA_TYPES[UA_TYPES_BYTESTRING] && UA_Variant_isScalar(newV)) { /* a string is written to a byte array */ UA_ByteString *str = (UA_ByteString*) newV->data; cast_v.arrayLength = str->length; cast_v.data = str->data; cast_v.type = &UA_TYPES[UA_TYPES_BYTE]; } else { if(rangeptr) UA_free(range.dimensions); return UA_STATUSCODE_BADTYPEMISMATCH; } } } if(!rangeptr) { UA_Variant_deleteMembers(&node->value.variant.value); UA_Variant_copy(newV, &node->value.variant.value); } else retval = UA_Variant_setRangeCopy(&node->value.variant.value, newV->data, newV->arrayLength, range); if(node->value.variant.callback.onWrite) node->value.variant.callback.onWrite(node->value.variant.callback.handle, node->nodeId, &node->value.variant.value, rangeptr); if(rangeptr) UA_free(range.dimensions); return retval; }