backend_open62541_datatypes.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. from datatypes import *
  2. import datetime
  3. import re
  4. import logging
  5. logger = logging.getLogger(__name__)
  6. def generateBooleanCode(value):
  7. if value:
  8. return "true"
  9. return "false"
  10. # Strip invalid characters to create valid C identifiers (variable names etc):
  11. def makeCIdentifier(value):
  12. return re.sub(r'[^\w]', '', value)
  13. # Escape C strings:
  14. def makeCLiteral(value):
  15. return re.sub(r'(?<!\\)"', r'\\"', value.replace('\\', r'\\\\').replace('\n', r'\\n').replace('\r', r''))
  16. def splitStringLiterals(value, splitLength=500):
  17. """
  18. Split a string literal longer than splitLength into smaller literals.
  19. E.g. "Some very long text" will be split into "Some ver" "y long te" "xt"
  20. On VS2008 there is a maximum allowed length of a single string literal.
  21. """
  22. value = value.strip()
  23. if len(value) < splitLength or splitLength == 0:
  24. return "\"" + re.sub(r'(?<!\\)"', r'\\"', value) + "\""
  25. ret = ""
  26. tmp = value
  27. while len(tmp) > splitLength:
  28. ret += "\"" + tmp[:splitLength].replace('"', r'\"') + "\" "
  29. tmp = tmp[splitLength:]
  30. ret += "\"" + re.sub(r'(?<!\\)"', r'\\"', tmp) + "\" "
  31. return ret
  32. def generateStringCode(value, alloc=False):
  33. value = makeCLiteral(value)
  34. return u"UA_STRING{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value))
  35. def generateXmlElementCode(value, alloc=False):
  36. value = makeCLiteral(value)
  37. return u"UA_XMLELEMENT{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value))
  38. def generateByteStringCode(value, valueName, global_var_code):
  39. asciiarray = [ord(c) for c in value.strip()]
  40. asciiarraystr = str(asciiarray).rstrip(']').lstrip('[')
  41. global_var_code.append("static const UA_Byte {instance}_byteArray[{len}] = {{{data}}};".format(
  42. len=len(asciiarray), data=asciiarraystr, instance=valueName
  43. ))
  44. # Cast away const with '(UA_Byte *)(void*)(uintptr_t)' since we know that UA_Server_addNode_begin will copy the content
  45. return "{instance}->length = {len};\n{instance}->data = (UA_Byte *)(void*)(uintptr_t){instance}_byteArray;"\
  46. .format(len=len(asciiarray), instance=valueName)
  47. def generateLocalizedTextCode(value, alloc=False):
  48. vt = makeCLiteral(value.text)
  49. return u"UA_LOCALIZEDTEXT{}(\"{}\", {})".format("_ALLOC" if alloc else "", value.locale,
  50. splitStringLiterals(vt))
  51. def generateQualifiedNameCode(value, alloc=False,):
  52. vn = makeCLiteral(value.name)
  53. return u"UA_QUALIFIEDNAME{}(ns[{}], {})".format("_ALLOC" if alloc else "",
  54. str(value.ns), splitStringLiterals(vn))
  55. def generateNodeIdCode(value):
  56. if not value:
  57. return "UA_NODEID_NUMERIC(0, 0)"
  58. if value.i != None:
  59. return "UA_NODEID_NUMERIC(ns[%s], %s)" % (value.ns, value.i)
  60. elif value.s != None:
  61. v = makeCLiteral(value.s)
  62. return u"UA_NODEID_STRING(ns[%s], \"%s\")" % (value.ns, v)
  63. raise Exception(str(value) + " no NodeID generation for bytestring and guid..")
  64. def generateExpandedNodeIdCode(value):
  65. if value.i != None:
  66. return "UA_EXPANDEDNODEID_NUMERIC(ns[%s], %s)" % (str(value.ns), str(value.i))
  67. elif value.s != None:
  68. vs = makeCLiteral(value.s)
  69. return u"UA_EXPANDEDNODEID_STRING(ns[%s], \"%s\")" % (str(value.ns), vs)
  70. raise Exception(str(value) + " no NodeID generation for bytestring and guid..")
  71. def generateDateTimeCode(value):
  72. epoch = datetime.datetime.utcfromtimestamp(0)
  73. mSecsSinceEpoch = int((value - epoch).total_seconds() * 1000.0)
  74. return "( (UA_DateTime)(" + str(mSecsSinceEpoch) + " * UA_DATETIME_MSEC) + UA_DATETIME_UNIX_EPOCH)"
  75. def generateNodeValueCode(prepend , node, instanceName, valueName, global_var_code, asIndirect=False):
  76. if type(node) in [Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float, Double]:
  77. return prepend + "(UA_" + node.__class__.__name__ + ") " + str(node.value) + ";"
  78. elif type(node) == String:
  79. return prepend + generateStringCode(node.value, alloc=asIndirect) + ";"
  80. elif type(node) == XmlElement:
  81. return prepend + generateXmlElementCode(node.value, alloc=asIndirect) + ";"
  82. elif type(node) == ByteString:
  83. # replace whitespaces between tags and remove newlines
  84. return prepend + "UA_BYTESTRING_NULL;" if not node.value else generateByteStringCode(
  85. re.sub(r">\s*<", "><", re.sub(r"[\r\n]+", "", node.value)), valueName, global_var_code)
  86. # the replacements done here is just for the array form can be workable in C code. It doesn't couses any problem
  87. # because the core data used here is already in byte form. So, there is no way we disturb it.
  88. elif type(node) == LocalizedText:
  89. return prepend + generateLocalizedTextCode(node, alloc=asIndirect) + ";"
  90. elif type(node) == NodeId:
  91. return prepend + generateNodeIdCode(node) + ";"
  92. elif type(node) == ExpandedNodeId:
  93. return prepend + generateExpandedNodeIdCode(node) + ";"
  94. elif type(node) == DateTime:
  95. return prepend + generateDateTimeCode(node.value) + ";"
  96. elif type(node) == QualifiedName:
  97. return prepend + generateQualifiedNameCode(node.value, alloc=asIndirect) + ";"
  98. elif type(node) == StatusCode:
  99. raise Exception("generateNodeValueCode for type " + node.__class__.name + " not implemented")
  100. elif type(node) == DiagnosticInfo:
  101. raise Exception("generateNodeValueCode for type " + node.__class__.name + " not implemented")
  102. elif type(node) == Guid:
  103. raise Exception("generateNodeValueCode for type " + node.__class__.name + " not implemented")
  104. elif type(node) == ExtensionObject:
  105. if asIndirect == False:
  106. return prepend + "*" + str(instanceName) + ";"
  107. return prepend + str(instanceName) + ";"