Merge pull request #5002 from open62541/1.3

Merge 1.3 to master
This commit is contained in:
Julius Pfrommer 2022-03-11 07:38:47 +01:00 committed by GitHub
commit 2b22674689
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 188 additions and 31 deletions

View File

@ -1955,8 +1955,8 @@ DECODE_JSON(String) {
/* No escaping */
if(*p != '\\') {
/* In the ASCII range, but not a printable character */
if(*p < 32 || *p == 127)
goto cleanup;
/* if(*p < 32 || *p == 127) */
/* goto cleanup; */
*(pos++) = *(p++);
continue;
@ -2084,21 +2084,27 @@ lookAheadForKey(const char *key, CtxJson *ctx,
parseCtx->index++; /* Move to the first key */
while(parseCtx->index < parseCtx->tokenCount &&
parseCtx->tokenArray[parseCtx->index].start < end) {
UA_assert(getJsmnType(parseCtx) == JSMN_STRING); /* Key must be a string */
/* Key must be a string (TODO: Make this an assert after replacing jsmn) */
if(getJsmnType(parseCtx) != JSMN_STRING)
return UA_STATUSCODE_BADDECODINGERROR;
parseCtx->index++; /* Move to the value already */
UA_assert(parseCtx->index < parseCtx->tokenCount); /* Key followed by a value */
/* Move index to the value */
parseCtx->index++;
/* Compare the key */
/* Value for the key must exist (TODO: Make this an assert after replacing jsmn) */
if(parseCtx->index >= parseCtx->tokenCount)
return UA_STATUSCODE_BADDECODINGERROR;
/* Compare the key (previous index) */
if(jsoneq((char*)ctx->pos, &parseCtx->tokenArray[parseCtx->index-1], key) == 0) {
*resultIndex = parseCtx->index; /* Point to the value */
*resultIndex = parseCtx->index; /* Point result to the current index */
ret = UA_STATUSCODE_GOOD;
break;
}
skipObject(parseCtx);
skipObject(parseCtx); /* Jump over the value (can also be an array or object) */
}
parseCtx->index = oldIndex; /* Restore index */
parseCtx->index = oldIndex; /* Restore the old index */
return ret;
}
@ -2360,6 +2366,7 @@ DECODE_JSON(DateTime) {
denom *= 0.1;
pos++;
}
frac += 0.00000005; /* Correct rounding when converting to integer */
dt += (UA_DateTime)(frac * UA_DATETIME_SEC);
}
@ -2771,7 +2778,9 @@ decodeFields(CtxJson *ctx, ParseCtx *parseCtx,
for(size_t currObj = 0; currObj < objectCount &&
parseCtx->index < parseCtx->tokenCount; currObj++) {
UA_assert(getJsmnType(parseCtx) == JSMN_STRING); /* Key must be a string */
/* Key must be a string (TODO: Convert to assert when jsmn is replaced) */
if(getJsmnType(parseCtx) != JSMN_STRING)
return UA_STATUSCODE_BADDECODINGERROR;
/* Start searching at the index of currObj */
for(size_t i = currObj; i < entryCount + currObj; i++) {

View File

@ -175,6 +175,50 @@ START_TEST(checkInputArguments) {
}
END_TEST
START_TEST(checkGuid) {
UA_Variant out;
UA_Variant_init(&out);
UA_StatusCode status = UA_Server_readValue(server, UA_NODEID_NUMERIC(testNamespaceIndex, 7051), &out);
ck_assert(status == UA_STATUSCODE_GOOD);
ck_assert(out.type == &UA_TYPES[UA_TYPES_GUID]);
UA_Guid *scalarData = (UA_Guid *)out.data;
UA_Guid scalarGuidVal = UA_GUID("7822a391-de79-4a59-b08d-b70bc63fecec");
ck_assert(UA_Guid_equal(scalarData, &scalarGuidVal));
UA_Variant_clear(&out);
status = UA_Server_readValue(server, UA_NODEID_NUMERIC(testNamespaceIndex, 7052), &out);
ck_assert(status == UA_STATUSCODE_GOOD);
ck_assert(out.type == &UA_TYPES[UA_TYPES_GUID]);
ck_assert(out.arrayLength == 3);
UA_Guid *ArrayData = (UA_Guid *)out.data;
UA_Guid ArrayGuidVal[3] = {UA_GUID("7822a391-1111-4a59-b08d-b70bc63fecec"),
UA_GUID("7822a391-2222-4a59-b08d-b70bc63fecec"),
UA_GUID("7822a391-3333-4a59-b08d-b70bc63fecec")};
ck_assert(UA_Guid_equal(&ArrayData[0], &ArrayGuidVal[0]));
ck_assert(UA_Guid_equal(&ArrayData[1], &ArrayGuidVal[1]));
ck_assert(UA_Guid_equal(&ArrayData[2], &ArrayGuidVal[2]));
UA_Variant_clear(&out);
}
END_TEST
START_TEST(checkDataSetMetaData) {
UA_Variant out;
UA_Variant_init(&out);
UA_StatusCode status = UA_Server_readValue(server, UA_NODEID_NUMERIC(testNamespaceIndex, 6021), &out);
ck_assert(status == UA_STATUSCODE_GOOD);
ck_assert(out.type == &UA_TYPES[UA_TYPES_DATASETMETADATATYPE]);
UA_DataSetMetaDataType *p = (UA_DataSetMetaDataType *)out.data;
UA_String dataSetName = UA_STRING("DataSetName");
ck_assert(UA_String_equal(&p->name, &dataSetName) == UA_TRUE);
ck_assert(p->fieldsSize == 1);
UA_String fieldName = UA_STRING("FieldName");
ck_assert(UA_String_equal(&p->fields[0].name, &fieldName) == UA_TRUE);
UA_Guid guid = UA_GUID("10000000-2000-3000-4000-500000000000");
ck_assert(UA_Guid_equal(&p->dataSetClassId, &guid) == UA_TRUE);
UA_Variant_clear(&out);
}
END_TEST
static Suite *testSuite_Client(void) {
Suite *s = suite_create("Server Nodeset Compiler");
TCase *tc_server = tcase_create("Server Testnodeset");
@ -186,6 +230,8 @@ static Suite *testSuite_Client(void) {
tcase_add_test(tc_server, readValueRank);
tcase_add_test(tc_server, checkFrameValues);
tcase_add_test(tc_server, checkInputArguments);
tcase_add_test(tc_server, checkGuid);
tcase_add_test(tc_server, checkDataSetMetaData);
suite_add_tcase(s, tc_server);
return s;
}

View File

@ -8,6 +8,7 @@
<Alias Alias="Int32">i=6</Alias>
<Alias Alias="UInt32">i=7</Alias>
<Alias Alias="Double">i=11</Alias>
<Alias Alias="Guid">i=14</Alias>
<Alias Alias="Organizes">i=35</Alias>
<Alias Alias="HasModellingRule">i=37</Alias>
<Alias Alias="HasEncoding">i=38</Alias>
@ -21,6 +22,7 @@
<Alias Alias="SelfContainingUnion">ns=1;i=4002</Alias>
<Alias Alias="TestDataType">ns=1;i=3006</Alias>
<Alias Alias="TestObjectType">ns=1;i=1003</Alias>
<Alias Alias="DataSetMetaDataType">i=14523</Alias>
</Aliases>
<Extensions>
<Extension>
@ -600,4 +602,87 @@
</Field>
</Definition>
</UADataType>
<UAVariable DataType="Guid" ParentNodeId="ns=1;i=5100" NodeId="ns=1;i=7051" BrowseName="1:TestGuidScalar" AccessLevel="3">
<DisplayName>TestGuidScalar</DisplayName>
<References>
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5100</Reference>
</References>
<Value>
<uax:Guid>
<uax:String>7822a391-de79-4a59-b08d-b70bc63fecec</uax:String>
</uax:Guid>
</Value>
</UAVariable>
<UAVariable DataType="Guid" ParentNodeId="ns=1;i=5100" ValueRank="1" NodeId="ns=1;i=7052" ArrayDimensions="0" BrowseName="1:TestGuidArray" AccessLevel="3">
<DisplayName>TestGuidArray</DisplayName>
<References>
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5100</Reference>
</References>
<Value>
<uax:ListOfString>
<uax:Guid>
<uax:String>7822a391-1111-4a59-b08d-b70bc63fecec</uax:String>
</uax:Guid>
<uax:Guid>
<uax:String>7822a391-2222-4a59-b08d-b70bc63fecec</uax:String>
</uax:Guid>
<uax:Guid>
<uax:String>7822a391-3333-4a59-b08d-b70bc63fecec</uax:String>
</uax:Guid>
</uax:ListOfString>
</Value>
</UAVariable>
<UAVariable DataType="DataSetMetaDataType" ParentNodeId="ns=1;i=5001" NodeId="ns=1;i=6021" BrowseName="TestDataSetMetaData">
<DisplayName>TestDataSetMetaData</DisplayName>
<References>
<Reference ReferenceType="HasProperty" IsForward="false">ns=1;i=5001</Reference>
<Reference ReferenceType="HasTypeDefinition">i=68</Reference>
</References>
<Value>
<uax:ExtensionObject>
<uax:TypeId>
<uax:Identifier>i=14794</uax:Identifier>
</uax:TypeId>
<uax:Body>
<DataSetMetaDataType xmlns="http://opcfoundation.org/UA/2008/02/Types.xsd">
<Namespaces>
<String></String>
</Namespaces>
<StructureDataTypes/>
<EnumDataTypes/>
<SimpleDataTypes/>
<Name>DataSetName</Name>
<Description/>
<Fields>
<FieldMetaData>
<Name>FieldName</Name>
<Description/>
<FieldFlags>0</FieldFlags>
<BuiltInType>10</BuiltInType>
<DataType>
<Identifier>i=10</Identifier>
</DataType>
<ValueRank>-1</ValueRank>
<ArrayDimensions/>
<MaxStringLength>0</MaxStringLength>
<DataSetFieldId>
<String>10000000-2000-3000-4000-500000000000</String>
</DataSetFieldId>
<Properties/>
</FieldMetaData>
</Fields>
<DataSetClassId>
<String>10000000-2000-3000-4000-500000000000</String>
</DataSetClassId>
<ConfigurationVersion>
<MajorVersion>1</MajorVersion>
<MinorVersion>1</MinorVersion>
</ConfigurationVersion>
</DataSetMetaDataType>
</uax:Body>
</uax:ExtensionObject>
</Value>
</UAVariable>
</UANodeSet>

View File

@ -238,7 +238,7 @@ _UA_END_DECLS
writec("\n".join(code_global))
writec("\n")
writec("\nstatic UA_StatusCode function_" + outfilebase + "_" + str(functionNumber) + "_begin(UA_Server *server, UA_UInt16* ns) {")
if isinstance(node, MethodNode):
if isinstance(node, MethodNode) or isinstance(node.parent, MethodNode):
writec("#ifdef UA_ENABLE_METHODCALLS")
writec(code)
@ -259,7 +259,7 @@ _UA_END_DECLS
writec("return retVal;")
if isinstance(node, MethodNode):
if isinstance(node, MethodNode) or isinstance(node.parent, MethodNode):
writec("#else")
writec("return UA_STATUSCODE_GOOD;")
writec("#endif /* UA_ENABLE_METHODCALLS */")
@ -267,10 +267,10 @@ _UA_END_DECLS
writec("\nstatic UA_StatusCode function_" + outfilebase + "_" + str(functionNumber) + "_finish(UA_Server *server, UA_UInt16* ns) {")
if isinstance(node, MethodNode):
if isinstance(node, MethodNode) or isinstance(node.parent, MethodNode):
writec("#ifdef UA_ENABLE_METHODCALLS")
writec("return " + generateNodeCode_finish(node))
if isinstance(node, MethodNode):
if isinstance(node, MethodNode) or isinstance(node.parent, MethodNode):
writec("#else")
writec("return UA_STATUSCODE_GOOD;")
writec("#endif /* UA_ENABLE_METHODCALLS */")

View File

@ -85,6 +85,12 @@ def generateQualifiedNameCode(value, alloc=False,):
return u"UA_QUALIFIEDNAME{}(ns[{}], {})".format("_ALLOC" if alloc else "",
str(value.ns), splitStringLiterals(vn))
def generateGuidCode(value):
if not value or len(value) != 5:
return "UA_GUID_NULL"
else:
return "UA_GUID(\"{}\")".format('-'.join(value))
def generateNodeIdCode(value):
if not value:
return "UA_NODEID_NUMERIC(0, 0)"
@ -154,7 +160,7 @@ def generateNodeValueCode(prepend , node, instanceName, valueName, global_var_co
elif isinstance(node, DiagnosticInfo):
raise Exception("generateNodeValueCode for type " + node.__class__.name + " not implemented")
elif isinstance(node, Guid):
raise Exception("generateNodeValueCode for type " + node.__class__.name + " not implemented")
return prepend + " = " + generateGuidCode(node.value) + ";"
elif isinstance(node, ExtensionObject):
if asIndirect == False:
return prepend + " = *" + str(instanceName) + ";"
@ -163,6 +169,8 @@ def generateNodeValueCode(prepend , node, instanceName, valueName, global_var_co
code = []
if idxList is None:
raise Exception("No index was passed and the code generation cannot generate the array element")
if len(node) == 0:
return "\n".join(code)
# Code generation for structure arrays with fields of type Buildin.
# Example:
# Structure []
@ -174,6 +182,10 @@ def generateNodeValueCode(prepend , node, instanceName, valueName, global_var_co
typeOfArray = encRule.member_type.name
arrayName = encRule.name
code.append("UA_STACKARRAY(UA_" + typeOfArray + ", " + arrayName+", {0});".format(len(node)))
# memset is used here instead of UA_Init. Finding the dataType nodeID (to get the type array)
# would require searching whole nodeset to match the type name
code.append("memset({arrayName}, 0, sizeof(UA_{typeOfArray}) * {arrayLength});".format(arrayName=arrayName, typeOfArray=typeOfArray,
arrayLength=len(node)))
for idx,subv in enumerate(node):
code.append(generateNodeValueCode(arrayName + "[" + str(idx) + "]", subv, instanceName, valueName, global_var_code, asIndirect, encRule=encRule, idxList=idx))
code.append(prepend + "Size = {0};".format(len(node)))
@ -201,6 +213,10 @@ def generateNodeValueCode(prepend , node, instanceName, valueName, global_var_co
typeOfArray = encRule.member_type.name
arrayName = encRule.name
code.append("UA_STACKARRAY(UA_" + typeOfArray + ", " + arrayName+", {0});".format(len(node.value)))
# memset is used here instead of UA_Init. Finding the dataType nodeID (to get the type array)
# would require searching whole nodeset to match the type name
code.append("memset({arrayName}, 0, sizeof(UA_{typeOfArray}) * {arrayLength});".format(arrayName=arrayName, typeOfArray=typeOfArray,
arrayLength=len(node.value)))
# Values is a list of lists
# The current index must be passed so that the code path for evaluating lists has the current index value and can generate the code correctly.
for idx,subv in enumerate(node.value):

View File

@ -12,7 +12,7 @@
### Copyright 2018 (c) Jannis Volker
### Copyright 2018 (c) Ralph Lange
from datatypes import ExtensionObject, NodeId, StatusCode, DiagnosticInfo, Guid, Value
from datatypes import ExtensionObject, NodeId, StatusCode, DiagnosticInfo, Value
from nodes import ReferenceTypeNode, ObjectNode, VariableNode, VariableTypeNode, MethodNode, ObjectTypeNode, DataTypeNode, ViewNode
from backend_open62541_datatypes import makeCIdentifier, generateLocalizedTextCode, generateQualifiedNameCode, generateNodeIdCode, \
generateExpandedNodeIdCode, generateNodeValueCode
@ -394,9 +394,7 @@ def generateValueCode(node, parentNode, nodeset, bootstrapping=True):
if isArrayVariableNode(node, parentNode):
# User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
if isinstance(node.value[0], Guid):
logger.warn("Don't know how to print array of GUID in node " + str(parentNode.id))
elif isinstance(node.value[0], DiagnosticInfo):
if isinstance(node.value[0], DiagnosticInfo):
logger.warn("Don't know how to print array of DiagnosticInfo in node " + str(parentNode.id))
elif isinstance(node.value[0], StatusCode):
logger.warn("Don't know how to print array of StatusCode in node " + str(parentNode.id))
@ -423,9 +421,7 @@ def generateValueCode(node, parentNode, nodeset, bootstrapping=True):
#scalar value
else:
# User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
if isinstance(node.value[0], Guid):
logger.warn("Don't know how to print scalar GUID in node " + str(parentNode.id))
elif isinstance(node.value[0], DiagnosticInfo):
if isinstance(node.value[0], DiagnosticInfo):
logger.warn("Don't know how to print scalar DiagnosticInfo in node " + str(parentNode.id))
elif isinstance(node.value[0], StatusCode):
logger.warn("Don't know how to print scalar StatusCode in node " + str(parentNode.id))

View File

@ -347,7 +347,7 @@ class Value(object):
childValue = ebodypart.firstChild
if not childValue == ebodypart.ELEMENT_NODE:
if not childValue.nodeType == ebodypart.ELEMENT_NODE:
childValue = getNextElementNode(childValue)
for e in members:
if isinstance(e, StructMember):
@ -355,7 +355,7 @@ class Value(object):
if isinstance(e.member_type, BuiltinType):
if e.is_array:
values = []
for el in ebodypart.childNodes:
for el in childValue.childNodes:
if not el.nodeType == el.ELEMENT_NODE:
continue
t = self.getTypeByString(e.member_type.name, None)
@ -375,12 +375,13 @@ class Value(object):
structure = Structure()
structure.alias = e.name
structure.value = []
structure.__parseXMLSingleValue(childValue, parentDataTypeNode, parent, parser, alias=None, encodingPart=e.member_type)
if not len(childValue.childNodes) == 0:
structure.__parseXMLSingleValue(childValue, parentDataTypeNode, parent, parser, alias=None, encodingPart=e.member_type)
self.value.append(structure)
return structure
elif isinstance(e.member_type, EnumerationType):
t = self.getTypeByString("Int32", None)
t.parseXML(ebodypart)
t.parseXML(childValue)
t.alias = e.name
self.value.append(t)
else:
@ -846,10 +847,15 @@ class Guid(Value):
def parseXML(self, xmlvalue):
self.checkXML(xmlvalue)
val = getXmlTextTrimmed(xmlvalue.firstChild)
# Support GUID in format:
# <Guid>
# <String>01234567-89AB-CDEF-ABCD-0123456789AB</String>
# </Guid>
if len(xmlvalue.getElementsByTagName("String")) != 0:
val = getXmlTextTrimmed(xmlvalue.getElementsByTagName("String")[0].firstChild)
if val is None:
self.value = [0, 0, 0, 0] # Catch XML <Guid /> by setting the value to a default
self.value = ['00000000', '0000', '0000', '0000', '000000000000'] # Catch XML <Guid /> by setting the value to a default
else:
self.value = val
self.value = self.value.replace("{", "")
@ -862,9 +868,8 @@ class Guid(Value):
except Exception:
logger.error("Invalid formatting of Guid. Expected {01234567-89AB-CDEF-ABCD-0123456789AB}, got " + \
unicode(xmlvalue.firstChild.data))
tmp = [0, 0, 0, 0, 0]
self.value = ['00000000', '0000', '0000', '0000', '000000000000']
if len(tmp) != 5:
logger.error("Invalid formatting of Guid. Expected {01234567-89AB-CDEF-ABCD-0123456789AB}, got " + \
unicode(xmlvalue.firstChild.data))
tmp = [0, 0, 0, 0]
self.value = tmp
self.value = ['00000000', '0000', '0000', '0000', '000000000000']