00001 """
00002 Generate address space c++ code from xml file specification
00003 """
00004 import sys
00005 from copy import copy
00006
00007 import xml.etree.ElementTree as ET
00008
00009
00010
00011 NeedOverride = []
00012 NeedConstructor = []
00013 IgnoredEnums = []
00014
00015 IgnoredStructs = []
00016
00017 NoSplitStruct = ["GetEndpointsResponse", "CloseSessionRequest", "AddNodesResponse", "DeleteNodesResponse", "BrowseResponse", "HistoryReadResponse", "HistoryUpdateResponse", "RegisterServerResponse", "CloseSecureChannelRequest", "CloseSecureChannelResponse", "CloseSessionRequest", "CloseSessionResponse", "UnregisterNodesResponse", "MonitoredItemModifyRequest", "MonitoredItemsCreateRequest", "ReadResponse", "WriteResponse", "TranslateBrowsePathsToNodeIdsResponse", "DeleteSubscriptionsResponse", "DeleteMonitoredItemsResponse", "CreateMonitoredItemsResponse", "ServiceFault", "AddReferencesRequest", "AddReferencesResponse", "ModifyMonitoredItemsResponse", "RepublishResponse", "CallResponse", "FindServersResponse", "RegisterServerRequest", "RegisterServer2Response"]
00018
00019 NotRequest = ["MonitoredItemCreateRequest", "MonitoredItemModifyRequest", "CallMethodRequest"]
00020 OverrideTypes = {}
00021 OverrideNames = {}
00022
00023
00024
00025
00026
00027
00028 class Bit(object):
00029 def __init__(self):
00030 self.name = None
00031 self.idx = None
00032 self.container = None
00033 self.length = 1
00034
00035 def __str__(self):
00036 return "(Bit: {0}, container:{1}, idx:{2})".format(self.name, self.container, self.idx)
00037 __repr__ = __str__
00038
00039 class Struct(object):
00040 def __init__(self):
00041 self.name = None
00042 self.basetype = None
00043 self.doc = ""
00044 self.fields = []
00045 self.bits = {}
00046 self.needconstructor = None
00047 self.needoverride = False
00048 self.children = []
00049 self.parents = []
00050 self.extensionobject = False
00051
00052 def get_field(self, name):
00053 for f in self.fields:
00054 if f.name == name:
00055 return f
00056 raise Exception("field not found: " + name)
00057
00058 def __str__(self):
00059 return "Struct {0}:{1}".format(self.name, self.basetype)
00060
00061 __repr__ = __str__
00062
00063
00064 class Field(object):
00065 def __init__(self):
00066 self.name = None
00067 self.uatype = None
00068 self.length = None
00069 self.sourcetype = None
00070 self.switchfield = None
00071 self.switchvalue = None
00072 self.bitlength = 1
00073
00074 def __str__(self):
00075 return "Field {0}({1})".format(self.name, self.uatype)
00076
00077 __repr__ = __str__
00078
00079 def is_native_type(self):
00080 if self.uatype in ("Char", "SByte", "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Boolean", "Double", "Float", "Byte", "String", "CharArray", "ByteString", "DateTime"):
00081 return True
00082 return False
00083
00084 def get_ctype(self):
00085 if self.uatype == "String":
00086 ty = "std::string"
00087 elif self.uatype == "CharArray":
00088 ty = "std::string"
00089 elif self.uatype == "Char":
00090 ty = "char"
00091 elif self.uatype == "SByte":
00092 ty = "char"
00093 elif self.uatype == "Int8":
00094 ty = "int8_t"
00095 elif self.uatype == "Int16":
00096 ty = "int16_t"
00097 elif self.uatype == "Int32":
00098 ty = "int32_t"
00099 elif self.uatype == "Int64":
00100 ty = "int64_t"
00101 elif self.uatype == "UInt8":
00102 ty = "uint8_t"
00103 elif self.uatype == "UInt16":
00104 ty = "uint16_t"
00105 elif self.uatype == "UInt32":
00106 ty = "uint32_t"
00107 elif self.uatype == "UInt64":
00108 ty = "uint64_t"
00109 elif self.uatype == "DateTime":
00110 ty = "OpcUa::DateTime"
00111 elif self.uatype == "Boolean":
00112 ty = "bool"
00113 elif self.uatype == "Double":
00114 ty = "double"
00115 elif self.uatype == "Float":
00116 ty = "float"
00117 elif self.uatype == "ByteString":
00118 ty = "OpcUa::ByteString"
00119 elif self.uatype == "Byte":
00120 ty = "uint8_t"
00121 else:
00122 ty = "OpcUa::" + self.uatype
00123 if self.length:
00124 ty = "std::vector<{0}>".format(ty)
00125 return ty
00126
00127 class Enum(object):
00128 def __init__(self):
00129 self.name = None
00130 self.uatype = None
00131 self.values = []
00132 self.doc = ""
00133
00134 def get_ctype(self):
00135 return "uint{0}_t".format(self.uatype)
00136
00137 class EnumValue(object):
00138 def __init__(self):
00139 self.name = None
00140 self.value = None
00141
00142 class Model(object):
00143 def __init__(self):
00144 self.structs = []
00145 self.enums = []
00146 self.struct_list = []
00147 self.enum_list = []
00148
00149 def get_struct(self, name):
00150 for struct in self.structs:
00151 if name == struct.name:
00152 return struct
00153 raise Exception("No struct named: " + str(name))
00154
00155 def get_enum(self, name):
00156 for s in self.enums:
00157 if name == s.name:
00158 return s
00159 raise Exception("No enum named: " + str(name))
00160
00161
00162
00163
00164 def reorder_structs(model):
00165 types = IgnoredStructs + IgnoredEnums + ["Bit", "Char", "CharArray", "Guid", "SByte", "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "DateTime", "Boolean", "Double", "Float", "ByteString", "Byte", "StatusCode", "DiagnosticInfo", "String", "AttributeID"] + [enum.name for enum in model.enums] + ["VariableAccessLevel"]
00166 waiting = {}
00167 newstructs = []
00168 for s in model.structs:
00169 types.append(s.name)
00170 s.waitingfor = []
00171 ok = True
00172 for f in s.fields:
00173 if f.uatype not in types:
00174 if f.uatype in waiting.keys():
00175 waiting[f.uatype].append(s)
00176 s.waitingfor.append(f.uatype)
00177 else:
00178 waiting[f.uatype] = [s]
00179 s.waitingfor.append(f.uatype)
00180 ok = False
00181 if ok:
00182 newstructs.append(s)
00183 waitings = waiting.pop(s.name, None)
00184 if waitings:
00185 for s2 in waitings:
00186 s2.waitingfor.remove(s.name)
00187 if not s2.waitingfor:
00188 newstructs.append(s2)
00189 if len(model.structs) != len(newstructs):
00190 print("Error while reordering structs, some structs could not be reinserted, had {0} structs, we now have {1} structs".format(len(model.structs), len(newstructs)))
00191 s1 = set(model.structs)
00192 s2 = set(newstructs)
00193 rest = s1 -s2
00194 print("Variant" in types)
00195 for s in s1-s2:
00196 print("{0} is waiting for: {1}".format(s, s.waitingfor))
00197
00198
00199 model.structs = newstructs
00200
00201 def override_types(model):
00202 for struct in model.structs:
00203 for field in struct.fields:
00204 if field.name in OverrideTypes.keys():
00205 field.uatype = OverrideTypes[field.name]
00206
00207 def remove_duplicates(model):
00208 for struct in model.structs:
00209 fields = []
00210 names = []
00211 for field in struct.fields:
00212 if field.name not in names:
00213 names.append(field.name)
00214 fields.append(field)
00215 struct.fields = fields
00216
00217 def add_encoding_field(model):
00218 for struct in model.structs:
00219 newfields = []
00220 container = None
00221 idx = 0
00222 for field in struct.fields:
00223 if field.uatype in ("UInt6", "NodeIdType"):
00224 container = field.name
00225 b = Bit()
00226 b.name = field.name
00227 b.idx = 0
00228 b.container = container
00229 b.length = 6
00230 idx = b.length
00231 struct.bits[b.name] = b
00232
00233 if field.uatype == "Bit":
00234 if not container or idx > 7:
00235 container = "Encoding"
00236 idx = 0
00237 f = Field()
00238 f.sourcetype = field.sourcetype
00239 f.name = "Encoding"
00240 f.uatype = "UInt8"
00241 newfields.append(f)
00242
00243 b = Bit()
00244 b.name = field.name
00245 b.idx = idx
00246 b.container = container
00247 b.length = field.bitlength
00248 idx += field.bitlength
00249 struct.bits[b.name] = b
00250 else:
00251 newfields.append(field)
00252 struct.fields = newfields
00253
00254 def remove_vector_length(model):
00255 for struct in model.structs:
00256 new = []
00257 for field in struct.fields:
00258 if not field.name.startswith("NoOf"):
00259 new.append(field)
00260 struct.fields = new
00261
00262 def remove_body_length(model):
00263 for struct in model.structs:
00264 new = []
00265 for field in struct.fields:
00266 if not field.name == "BodyLength":
00267 new.append(field)
00268 struct.fields = new
00269
00270
00271
00272
00273
00274
00275 def split_requests(model):
00276 structs = []
00277 for struct in model.structs:
00278 structtype = None
00279 if struct.name.endswith("Request") and not struct.name in NotRequest:
00280 structtype = "Request"
00281 elif struct.name.endswith("Response") or struct.name == "ServiceFault":
00282 structtype = "Response"
00283 if structtype:
00284
00285
00286
00287
00288
00289
00290
00291
00292 struct.needconstructor = True
00293 field = Field()
00294 field.name = "TypeId"
00295 field.uatype = "NodeId"
00296 struct.fields.insert(0, field)
00297
00298 if structtype and not struct.name in NoSplitStruct:
00299 paramstruct = Struct()
00300 if structtype == "Request":
00301 basename = struct.name.replace("Request", "") + "Parameters"
00302 paramstruct.name = basename
00303 else:
00304 basename = struct.name.replace("Response", "") + "Result"
00305 paramstruct.name = basename
00306 paramstruct.fields = struct.fields[2:]
00307 paramstruct.bits = struct.bits
00308
00309 struct.fields = struct.fields[:2]
00310
00311 structs.append(paramstruct)
00312
00313 typeid = Field()
00314 typeid.name = "Parameters"
00315 typeid.uatype = paramstruct.name
00316 struct.fields.append(typeid)
00317 structs.append(struct)
00318 model.structs = structs
00319
00320
00321 class Parser(object):
00322 def __init__(self, path):
00323 self.path = path
00324 self.model = None
00325
00326 def parse(self):
00327 print("Parsing: ", self.path)
00328 self.model = Model()
00329 tree = ET.parse(self.path)
00330 root = tree.getroot()
00331 self.add_extension_object()
00332 for child in root:
00333 tag = child.tag[40:]
00334 if tag == "StructuredType":
00335 struct = self.parse_struct(child)
00336 if struct.name != "ExtensionObject":
00337 self.model.structs.append(struct)
00338 self.model.struct_list.append(struct.name)
00339 elif tag == "EnumeratedType":
00340 enum = self.parse_enum(child)
00341 self.model.enums.append(enum)
00342 self.model.enum_list.append(enum.name)
00343
00344
00345 return self.model
00346
00347 def add_extension_object(self):
00348 obj = Struct()
00349 obj.name = "ExtensionObject"
00350 f = Field()
00351 f.name = "TypeId"
00352 f.uatype = "NodeId"
00353 obj.fields.append(f)
00354 f = Field()
00355 f.name = "BinaryBody"
00356 f.uatype = "Bit"
00357 obj.fields.append(f)
00358 f = Field()
00359 f.name = "XmlBody"
00360 f.uatype = "Bit"
00361 obj.fields.append(f)
00362 f = Field()
00363 f.name = "Body"
00364 f.uatype = "ByteString"
00365 f.switchfield = "BinaryBody"
00366 obj.fields.append(f)
00367 self.model.struct_list.append(obj.name)
00368
00369 self.model.structs.append(obj)
00370
00371 def parse_struct(self, child):
00372 tag = child.tag[40:]
00373 struct = Struct()
00374 for key, val in child.attrib.items():
00375 if key == "Name":
00376 struct.name = val
00377 elif key == "BaseType":
00378 if ":" in val:
00379 prefix, val = val.split(":")
00380 struct.basetype = val
00381 tmp = struct
00382 while tmp.basetype:
00383 struct.parents.append(tmp.basetype)
00384 tmp = self.model.get_struct(tmp.basetype)
00385 else:
00386 print("Error unknown key: ", key)
00387 for el in child:
00388 tag = el.tag[40:]
00389 if tag == "Field":
00390 field = Field()
00391 for key, val in el.attrib.items():
00392 if key == "Name":
00393 field.name = val
00394 elif key == "TypeName":
00395 field.uatype = val.split(":")[1]
00396 elif key == "LengthField":
00397 field.length = val
00398 elif key == "SourceType":
00399 field.sourcetype = val
00400 elif key == "SwitchField":
00401 field.switchfield = val
00402 elif key == "SwitchValue":
00403 field.switchvalue = val
00404 elif key == "Length":
00405 field.bitlength = int(val)
00406 else:
00407 print("Unknown field item: ", struct.name, key)
00408
00409 struct.fields.append(field)
00410 elif tag == "Documentation":
00411 struct.doc = el.text
00412 else:
00413 print("Unknown tag: ", tag)
00414
00415 return struct
00416
00417 def parse_enum(self, child):
00418 tag = child.tag[40:]
00419 enum = Enum()
00420 for k, v in child.items():
00421 if k == "Name":
00422 enum.name = v
00423 elif k == "LengthInBits":
00424 enum.uatype = "UInt" + v
00425 else:
00426 print("Unknown attr for enum: ", k)
00427 for el in child:
00428 tag = el.tag[40:]
00429 if tag == "EnumeratedValue":
00430 ev = EnumValue()
00431 for k, v in el.attrib.items():
00432 if k == "Name":
00433 ev.name = v
00434 elif k == "Value":
00435 ev.value = v
00436 else:
00437 print("Unknown field attrib: ", k)
00438 enum.values.append(ev)
00439 elif tag == "Documentation":
00440 enum.doc = el.text
00441 else:
00442 print("Unknown enum tag: ", tag)
00443 return enum
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453 def add_basetype_members(model):
00454 for struct in model.structs:
00455 if not struct.basetype:
00456 continue
00457 emptystruct = False
00458 if len(struct.fields) == 0:
00459 emptystruct = True
00460 if struct.basetype in ("ExtensionObject"):
00461 struct.basetype = None
00462 continue
00463 base = model.get_struct(struct.basetype)
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 for name, bit in base.bits.items():
00475 struct.bits[name] = bit
00476 for idx, field in enumerate(base.fields):
00477 field = copy(field)
00478 if field.name == "Body" and not emptystruct:
00479
00480 struct.extensionobject = True
00481 field.name = "BodyLength"
00482 field.uatype = "Int32"
00483 field.length = None
00484 field.switchfield = None
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 if not field.sourcetype:
00497 field.sourcetype = base.name
00498 struct.fields.insert(idx, field)
00499
00500
00501
00502
00503