qemu

Форк
0
/
dbusparser.py 
373 строки · 14.3 Кб
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
374

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.