mirror of
https://github.com/open62541/open62541.git
synced 2025-06-03 04:00:21 +00:00
commit
2b22674689
@ -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++) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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 */")
|
||||
|
@ -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):
|
||||
|
@ -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))
|
||||
|
@ -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 = []
|
||||
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']
|
||||
|
Loading…
Reference in New Issue
Block a user