qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

dbusparser.py (14665B)


      1 # Based from "GDBus - GLib D-Bus Library":
      2 #
      3 # Copyright (C) 2008-2011 Red Hat, Inc.
      4 #
      5 # This library is free software; you can redistribute it and/or
      6 # modify it under the terms of the GNU Lesser General Public
      7 # License as published by the Free Software Foundation; either
      8 # version 2.1 of the License, or (at your option) any later version.
      9 #
     10 # This library is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13 # Lesser General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU Lesser General
     16 # Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
     17 #
     18 # Author: David Zeuthen <davidz@redhat.com>
     19 
     20 import xml.parsers.expat
     21 
     22 
     23 class Annotation:
     24     def __init__(self, key, value):
     25         self.key = key
     26         self.value = value
     27         self.annotations = []
     28         self.since = ""
     29 
     30 
     31 class Arg:
     32     def __init__(self, name, signature):
     33         self.name = name
     34         self.signature = signature
     35         self.annotations = []
     36         self.doc_string = ""
     37         self.since = ""
     38 
     39 
     40 class Method:
     41     def __init__(self, name, h_type_implies_unix_fd=True):
     42         self.name = name
     43         self.h_type_implies_unix_fd = h_type_implies_unix_fd
     44         self.in_args = []
     45         self.out_args = []
     46         self.annotations = []
     47         self.doc_string = ""
     48         self.since = ""
     49         self.deprecated = False
     50         self.unix_fd = False
     51 
     52 
     53 class Signal:
     54     def __init__(self, name):
     55         self.name = name
     56         self.args = []
     57         self.annotations = []
     58         self.doc_string = ""
     59         self.since = ""
     60         self.deprecated = False
     61 
     62 
     63 class Property:
     64     def __init__(self, name, signature, access):
     65         self.name = name
     66         self.signature = signature
     67         self.access = access
     68         self.annotations = []
     69         self.arg = Arg("value", self.signature)
     70         self.arg.annotations = self.annotations
     71         self.readable = False
     72         self.writable = False
     73         if self.access == "readwrite":
     74             self.readable = True
     75             self.writable = True
     76         elif self.access == "read":
     77             self.readable = True
     78         elif self.access == "write":
     79             self.writable = True
     80         else:
     81             raise ValueError('Invalid access type "{}"'.format(self.access))
     82         self.doc_string = ""
     83         self.since = ""
     84         self.deprecated = False
     85         self.emits_changed_signal = True
     86 
     87 
     88 class Interface:
     89     def __init__(self, name):
     90         self.name = name
     91         self.methods = []
     92         self.signals = []
     93         self.properties = []
     94         self.annotations = []
     95         self.doc_string = ""
     96         self.doc_string_brief = ""
     97         self.since = ""
     98         self.deprecated = False
     99 
    100 
    101 class DBusXMLParser:
    102     STATE_TOP = "top"
    103     STATE_NODE = "node"
    104     STATE_INTERFACE = "interface"
    105     STATE_METHOD = "method"
    106     STATE_SIGNAL = "signal"
    107     STATE_PROPERTY = "property"
    108     STATE_ARG = "arg"
    109     STATE_ANNOTATION = "annotation"
    110     STATE_IGNORED = "ignored"
    111 
    112     def __init__(self, xml_data, h_type_implies_unix_fd=True):
    113         self._parser = xml.parsers.expat.ParserCreate()
    114         self._parser.CommentHandler = self.handle_comment
    115         self._parser.CharacterDataHandler = self.handle_char_data
    116         self._parser.StartElementHandler = self.handle_start_element
    117         self._parser.EndElementHandler = self.handle_end_element
    118 
    119         self.parsed_interfaces = []
    120         self._cur_object = None
    121 
    122         self.state = DBusXMLParser.STATE_TOP
    123         self.state_stack = []
    124         self._cur_object = None
    125         self._cur_object_stack = []
    126 
    127         self.doc_comment_last_symbol = ""
    128 
    129         self._h_type_implies_unix_fd = h_type_implies_unix_fd
    130 
    131         self._parser.Parse(xml_data)
    132 
    133     COMMENT_STATE_BEGIN = "begin"
    134     COMMENT_STATE_PARAMS = "params"
    135     COMMENT_STATE_BODY = "body"
    136     COMMENT_STATE_SKIP = "skip"
    137 
    138     def handle_comment(self, data):
    139         comment_state = DBusXMLParser.COMMENT_STATE_BEGIN
    140         lines = data.split("\n")
    141         symbol = ""
    142         body = ""
    143         in_para = False
    144         params = {}
    145         for line in lines:
    146             orig_line = line
    147             line = line.lstrip()
    148             if comment_state == DBusXMLParser.COMMENT_STATE_BEGIN:
    149                 if len(line) > 0:
    150                     colon_index = line.find(": ")
    151                     if colon_index == -1:
    152                         if line.endswith(":"):
    153                             symbol = line[0 : len(line) - 1]
    154                             comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
    155                         else:
    156                             comment_state = DBusXMLParser.COMMENT_STATE_SKIP
    157                     else:
    158                         symbol = line[0:colon_index]
    159                         rest_of_line = line[colon_index + 2 :].strip()
    160                         if len(rest_of_line) > 0:
    161                             body += rest_of_line + "\n"
    162                         comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
    163             elif comment_state == DBusXMLParser.COMMENT_STATE_PARAMS:
    164                 if line.startswith("@"):
    165                     colon_index = line.find(": ")
    166                     if colon_index == -1:
    167                         comment_state = DBusXMLParser.COMMENT_STATE_BODY
    168                         if not in_para:
    169                             in_para = True
    170                         body += orig_line + "\n"
    171                     else:
    172                         param = line[1:colon_index]
    173                         docs = line[colon_index + 2 :]
    174                         params[param] = docs
    175                 else:
    176                     comment_state = DBusXMLParser.COMMENT_STATE_BODY
    177                     if len(line) > 0:
    178                         if not in_para:
    179                             in_para = True
    180                         body += orig_line + "\n"
    181             elif comment_state == DBusXMLParser.COMMENT_STATE_BODY:
    182                 if len(line) > 0:
    183                     if not in_para:
    184                         in_para = True
    185                     body += orig_line + "\n"
    186                 else:
    187                     if in_para:
    188                         body += "\n"
    189                         in_para = False
    190         if in_para:
    191             body += "\n"
    192 
    193         if symbol != "":
    194             self.doc_comment_last_symbol = symbol
    195             self.doc_comment_params = params
    196             self.doc_comment_body = body
    197 
    198     def handle_char_data(self, data):
    199         # print 'char_data=%s'%data
    200         pass
    201 
    202     def handle_start_element(self, name, attrs):
    203         old_state = self.state
    204         old_cur_object = self._cur_object
    205         if self.state == DBusXMLParser.STATE_IGNORED:
    206             self.state = DBusXMLParser.STATE_IGNORED
    207         elif self.state == DBusXMLParser.STATE_TOP:
    208             if name == DBusXMLParser.STATE_NODE:
    209                 self.state = DBusXMLParser.STATE_NODE
    210             else:
    211                 self.state = DBusXMLParser.STATE_IGNORED
    212         elif self.state == DBusXMLParser.STATE_NODE:
    213             if name == DBusXMLParser.STATE_INTERFACE:
    214                 self.state = DBusXMLParser.STATE_INTERFACE
    215                 iface = Interface(attrs["name"])
    216                 self._cur_object = iface
    217                 self.parsed_interfaces.append(iface)
    218             elif name == DBusXMLParser.STATE_ANNOTATION:
    219                 self.state = DBusXMLParser.STATE_ANNOTATION
    220                 anno = Annotation(attrs["name"], attrs["value"])
    221                 self._cur_object.annotations.append(anno)
    222                 self._cur_object = anno
    223             else:
    224                 self.state = DBusXMLParser.STATE_IGNORED
    225 
    226             # assign docs, if any
    227             if "name" in attrs and self.doc_comment_last_symbol == attrs["name"]:
    228                 self._cur_object.doc_string = self.doc_comment_body
    229                 if "short_description" in self.doc_comment_params:
    230                     short_description = self.doc_comment_params["short_description"]
    231                     self._cur_object.doc_string_brief = short_description
    232                 if "since" in self.doc_comment_params:
    233                     self._cur_object.since = self.doc_comment_params["since"].strip()
    234 
    235         elif self.state == DBusXMLParser.STATE_INTERFACE:
    236             if name == DBusXMLParser.STATE_METHOD:
    237                 self.state = DBusXMLParser.STATE_METHOD
    238                 method = Method(
    239                     attrs["name"], h_type_implies_unix_fd=self._h_type_implies_unix_fd
    240                 )
    241                 self._cur_object.methods.append(method)
    242                 self._cur_object = method
    243             elif name == DBusXMLParser.STATE_SIGNAL:
    244                 self.state = DBusXMLParser.STATE_SIGNAL
    245                 signal = Signal(attrs["name"])
    246                 self._cur_object.signals.append(signal)
    247                 self._cur_object = signal
    248             elif name == DBusXMLParser.STATE_PROPERTY:
    249                 self.state = DBusXMLParser.STATE_PROPERTY
    250                 prop = Property(attrs["name"], attrs["type"], attrs["access"])
    251                 self._cur_object.properties.append(prop)
    252                 self._cur_object = prop
    253             elif name == DBusXMLParser.STATE_ANNOTATION:
    254                 self.state = DBusXMLParser.STATE_ANNOTATION
    255                 anno = Annotation(attrs["name"], attrs["value"])
    256                 self._cur_object.annotations.append(anno)
    257                 self._cur_object = anno
    258             else:
    259                 self.state = DBusXMLParser.STATE_IGNORED
    260 
    261             # assign docs, if any
    262             if "name" in attrs and self.doc_comment_last_symbol == attrs["name"]:
    263                 self._cur_object.doc_string = self.doc_comment_body
    264                 if "since" in self.doc_comment_params:
    265                     self._cur_object.since = self.doc_comment_params["since"].strip()
    266 
    267         elif self.state == DBusXMLParser.STATE_METHOD:
    268             if name == DBusXMLParser.STATE_ARG:
    269                 self.state = DBusXMLParser.STATE_ARG
    270                 arg_name = None
    271                 if "name" in attrs:
    272                     arg_name = attrs["name"]
    273                 arg = Arg(arg_name, attrs["type"])
    274                 direction = attrs.get("direction", "in")
    275                 if direction == "in":
    276                     self._cur_object.in_args.append(arg)
    277                 elif direction == "out":
    278                     self._cur_object.out_args.append(arg)
    279                 else:
    280                     raise ValueError('Invalid direction "{}"'.format(direction))
    281                 self._cur_object = arg
    282             elif name == DBusXMLParser.STATE_ANNOTATION:
    283                 self.state = DBusXMLParser.STATE_ANNOTATION
    284                 anno = Annotation(attrs["name"], attrs["value"])
    285                 self._cur_object.annotations.append(anno)
    286                 self._cur_object = anno
    287             else:
    288                 self.state = DBusXMLParser.STATE_IGNORED
    289 
    290             # assign docs, if any
    291             if self.doc_comment_last_symbol == old_cur_object.name:
    292                 if "name" in attrs and attrs["name"] in self.doc_comment_params:
    293                     doc_string = self.doc_comment_params[attrs["name"]]
    294                     if doc_string is not None:
    295                         self._cur_object.doc_string = doc_string
    296                     if "since" in self.doc_comment_params:
    297                         self._cur_object.since = self.doc_comment_params[
    298                             "since"
    299                         ].strip()
    300 
    301         elif self.state == DBusXMLParser.STATE_SIGNAL:
    302             if name == DBusXMLParser.STATE_ARG:
    303                 self.state = DBusXMLParser.STATE_ARG
    304                 arg_name = None
    305                 if "name" in attrs:
    306                     arg_name = attrs["name"]
    307                 arg = Arg(arg_name, attrs["type"])
    308                 self._cur_object.args.append(arg)
    309                 self._cur_object = arg
    310             elif name == DBusXMLParser.STATE_ANNOTATION:
    311                 self.state = DBusXMLParser.STATE_ANNOTATION
    312                 anno = Annotation(attrs["name"], attrs["value"])
    313                 self._cur_object.annotations.append(anno)
    314                 self._cur_object = anno
    315             else:
    316                 self.state = DBusXMLParser.STATE_IGNORED
    317 
    318             # assign docs, if any
    319             if self.doc_comment_last_symbol == old_cur_object.name:
    320                 if "name" in attrs and attrs["name"] in self.doc_comment_params:
    321                     doc_string = self.doc_comment_params[attrs["name"]]
    322                     if doc_string is not None:
    323                         self._cur_object.doc_string = doc_string
    324                     if "since" in self.doc_comment_params:
    325                         self._cur_object.since = self.doc_comment_params[
    326                             "since"
    327                         ].strip()
    328 
    329         elif self.state == DBusXMLParser.STATE_PROPERTY:
    330             if name == DBusXMLParser.STATE_ANNOTATION:
    331                 self.state = DBusXMLParser.STATE_ANNOTATION
    332                 anno = Annotation(attrs["name"], attrs["value"])
    333                 self._cur_object.annotations.append(anno)
    334                 self._cur_object = anno
    335             else:
    336                 self.state = DBusXMLParser.STATE_IGNORED
    337 
    338         elif self.state == DBusXMLParser.STATE_ARG:
    339             if name == DBusXMLParser.STATE_ANNOTATION:
    340                 self.state = DBusXMLParser.STATE_ANNOTATION
    341                 anno = Annotation(attrs["name"], attrs["value"])
    342                 self._cur_object.annotations.append(anno)
    343                 self._cur_object = anno
    344             else:
    345                 self.state = DBusXMLParser.STATE_IGNORED
    346 
    347         elif self.state == DBusXMLParser.STATE_ANNOTATION:
    348             if name == DBusXMLParser.STATE_ANNOTATION:
    349                 self.state = DBusXMLParser.STATE_ANNOTATION
    350                 anno = Annotation(attrs["name"], attrs["value"])
    351                 self._cur_object.annotations.append(anno)
    352                 self._cur_object = anno
    353             else:
    354                 self.state = DBusXMLParser.STATE_IGNORED
    355 
    356         else:
    357             raise ValueError(
    358                 'Unhandled state "{}" while entering element with name "{}"'.format(
    359                     self.state, name
    360                 )
    361             )
    362 
    363         self.state_stack.append(old_state)
    364         self._cur_object_stack.append(old_cur_object)
    365 
    366     def handle_end_element(self, name):
    367         self.state = self.state_stack.pop()
    368         self._cur_object = self._cur_object_stack.pop()
    369 
    370 
    371 def parse_dbus_xml(xml_data):
    372     parser = DBusXMLParser(xml_data, True)
    373     return parser.parsed_interfaces